Skip to content

Commit 7dba1df

Browse files
committed
WIP, Implement funding_tx_constructed()
1 parent 1ef4df0 commit 7dba1df

File tree

2 files changed

+187
-41
lines changed

2 files changed

+187
-41
lines changed

lightning/src/ln/channel.rs

+183-40
Original file line numberDiff line numberDiff line change
@@ -1335,6 +1335,7 @@ impl<SP: Deref> Channel<SP> where
13351335
}
13361336
}
13371337

1338+
#[cfg(splicing)]
13381339
fn as_splicing_mut(&mut self) -> Option<&mut SplicingChannel<SP>> {
13391340
if let ChannelPhase::RefundingV2(channel) = &mut self.phase {
13401341
Some(channel)
@@ -1481,6 +1482,7 @@ impl<SP: Deref> Channel<SP> where
14811482
if let Some(unfunded) = self.as_unfunded_v2_mut() {
14821483
return unfunded.tx_add_input(msg);
14831484
}
1485+
#[cfg(splicing)]
14841486
if let Some(splicing) = self.as_splicing_mut() {
14851487
return splicing.tx_add_input(msg);
14861488
}
@@ -1492,6 +1494,7 @@ impl<SP: Deref> Channel<SP> where
14921494
if let Some(unfunded) = self.as_unfunded_v2_mut() {
14931495
return unfunded.tx_add_output(msg);
14941496
}
1497+
#[cfg(splicing)]
14951498
if let Some(splicing) = self.as_splicing_mut() {
14961499
return splicing.tx_add_output(msg);
14971500
}
@@ -1503,6 +1506,7 @@ impl<SP: Deref> Channel<SP> where
15031506
if let Some(unfunded) = self.as_unfunded_v2_mut() {
15041507
return unfunded.tx_complete(msg);
15051508
}
1509+
#[cfg(splicing)]
15061510
if let Some(splicing) = self.as_splicing_mut() {
15071511
return splicing.tx_complete(msg);
15081512
}
@@ -1546,22 +1550,55 @@ impl<SP: Deref> Channel<SP> where
15461550
where
15471551
L::Target: Logger
15481552
{
1549-
if let ChannelPhase::UnfundedV2(chan) = &mut self.phase {
1550-
let logger = WithChannelContext::from(logger, &chan.context, None);
1551-
chan.funding_tx_constructed(signing_session, &&logger)
1552-
} else {
1553-
Err(ChannelError::Warn("Got a tx_complete message with no interactive transaction construction expected or in-progress".to_owned()))
1554-
}
1553+
let phase = core::mem::replace(&mut self.phase, ChannelPhase::Undefined);
1554+
let result = match phase {
1555+
ChannelPhase::UnfundedV2(mut chan) => {
1556+
let logger = WithChannelContext::from(logger, &chan.context, None);
1557+
match chan.funding_tx_constructed(signing_session, &&logger) {
1558+
Ok((commitment_signed, event)) => {
1559+
// TODO: Transition to Funded ? Which chan? // self.phase = ChannelPhase::Funded(chan);
1560+
self.phase = ChannelPhase::UnfundedV2(chan);
1561+
Ok((commitment_signed, event))
1562+
},
1563+
Err(e) => {
1564+
// revert
1565+
self.phase = ChannelPhase::UnfundedV2(chan);
1566+
Err(e)
1567+
},
1568+
}
1569+
}
1570+
#[cfg(splicing)]
1571+
ChannelPhase::RefundingV2(chan) => {
1572+
let logger = WithChannelContext::from(logger, &chan.pre_funded.context, None);
1573+
match chan.funding_tx_constructed(signing_session, &&logger) {
1574+
Ok((signing_session, holder_commitment_point, commitment_signed, event)) => {
1575+
let _res = self.phase_from_splice_to_funded(signing_session, holder_commitment_point)?;
1576+
Ok((commitment_signed, event))
1577+
},
1578+
Err((chan, e)) => {
1579+
// revert
1580+
self.phase = ChannelPhase::RefundingV2(chan);
1581+
Err(e)
1582+
},
1583+
}
1584+
}
1585+
_ => {
1586+
self.phase = phase;
1587+
Err(ChannelError::Warn("Got a tx_complete message with no interactive transaction construction expected or in-progress".to_owned()))
1588+
}
1589+
};
1590+
1591+
debug_assert!(!matches!(self.phase, ChannelPhase::Undefined));
1592+
result
15551593
}
15561594

15571595
/// Transition the channel from Funded to SplicingChannel.
15581596
/// Done in one go, as the existing ('pre') channel is put in the new channel (alongside a new one).
15591597
#[cfg(splicing)]
1560-
fn phase_to_splice(&mut self, post_funding: FundingScope, dual_funding_context: DualFundingChannelContext, pending_splice_post: PendingSplicePost) -> Result<(), ChannelError>
1561-
{
1598+
fn phase_from_funded_to_splice(&mut self, post_funding: FundingScope, dual_funding_context: DualFundingChannelContext, unfunded_context: UnfundedChannelContext, pending_splice_post: PendingSplicePost) -> Result<(), ChannelError> {
15621599
let phase = core::mem::replace(&mut self.phase, ChannelPhase::Undefined);
15631600
let result = if let ChannelPhase::Funded(prev_chan) = phase {
1564-
self.phase = ChannelPhase::RefundingV2(SplicingChannel::new(prev_chan, post_funding, dual_funding_context, pending_splice_post));
1601+
self.phase = ChannelPhase::RefundingV2(SplicingChannel::new(prev_chan, post_funding, dual_funding_context, unfunded_context, pending_splice_post));
15651602
Ok(())
15661603
} else {
15671604
// revert phase
@@ -1572,6 +1609,30 @@ impl<SP: Deref> Channel<SP> where
15721609
result
15731610
}
15741611

1612+
/// Transition the channel from SplicingChannel to Funded, after negotiating new funded.
1613+
#[cfg(splicing)]
1614+
fn phase_from_splice_to_funded(&mut self, signing_session: InteractiveTxSigningSession, holder_commitment_point: HolderCommitmentPoint) -> Result<(), ChannelError> {
1615+
let phase = core::mem::replace(&mut self.phase, ChannelPhase::Undefined);
1616+
let result = if let ChannelPhase::RefundingV2(chan) = phase {
1617+
self.phase = ChannelPhase::Funded(FundedChannel {
1618+
funding: chan.post_funding,
1619+
context: chan.pre_funded.context,
1620+
interactive_tx_signing_session: Some(signing_session),
1621+
holder_commitment_point,
1622+
is_v2_established: true,
1623+
pending_splice_pre: None,
1624+
pending_splice_post: None,
1625+
});
1626+
Ok(())
1627+
} else {
1628+
// revert phase
1629+
self.phase = phase;
1630+
Err(ChannelError::Warn("Cannot transition away from splicing, not in splicing phase".to_owned()))
1631+
};
1632+
debug_assert!(!matches!(self.phase, ChannelPhase::Undefined));
1633+
result
1634+
}
1635+
15751636
#[cfg(splicing)]
15761637
pub fn splice_init<ES: Deref, L: Deref>(
15771638
&mut self, msg: &msgs::SpliceInit, our_funding_contribution: i64,
@@ -1583,10 +1644,10 @@ impl<SP: Deref> Channel<SP> where
15831644
{
15841645
// Explicit check for Funded, not as_funded; RefundingV2 not allowed
15851646
if let ChannelPhase::Funded(prev_chan) = &mut self.phase {
1586-
let (pending_splice_post, post_funding, dual_funding_context) =
1647+
let (pending_splice_post, post_funding, dual_funding_context, unfunded_context) =
15871648
prev_chan.splice_init(msg, our_funding_contribution)?;
15881649

1589-
let _res = self.phase_to_splice(post_funding, dual_funding_context, pending_splice_post)?;
1650+
let _res = self.phase_from_funded_to_splice(post_funding, dual_funding_context, unfunded_context, pending_splice_post)?;
15901651

15911652
if let ChannelPhase::RefundingV2(chan) = &mut self.phase {
15921653
let splice_ack_msg = chan.splice_init(msg, our_funding_contribution, signer_provider, entropy_source, our_node_id, logger)?;
@@ -1610,10 +1671,10 @@ impl<SP: Deref> Channel<SP> where
16101671
{
16111672
// Explicit check for Funded, not as_funded; RefundingV2 not allowed
16121673
if let ChannelPhase::Funded(prev_chan) = &mut self.phase {
1613-
let (pending_splice_post, post_funding, dual_funding_context, our_funding_contribution) =
1674+
let (pending_splice_post, post_funding, dual_funding_context, unfunded_context, our_funding_contribution) =
16141675
prev_chan.splice_ack(msg)?;
16151676

1616-
let _res = self.phase_to_splice(post_funding, dual_funding_context, pending_splice_post)?;
1677+
let _res = self.phase_from_funded_to_splice(post_funding, dual_funding_context, unfunded_context, pending_splice_post)?;
16171678

16181679
if let ChannelPhase::RefundingV2(chan) = &mut self.phase {
16191680
let tx_msg_opt = chan.splice_ack(msg, our_funding_contribution, signer_provider, entropy_source, our_node_id, logger)?;
@@ -1740,9 +1801,9 @@ pub(super) struct SplicingChannel<SP: Deref> where SP::Target: SignerProvider {
17401801
/// TODO: replace it with its fields; done with trait?
17411802
pub pre_funded: FundedChannel<SP>,
17421803

1743-
// Fields for PendingV2Channel follow, except ChannelContext
1804+
// Fields from PendingV2Channel follow, except ChannelContext, which is reused from above
17441805
pub post_funding: FundingScope,
1745-
// pub unfunded_context: Option<UnfundedChannelContext>,
1806+
pub unfunded_context: UnfundedChannelContext,
17461807
/// Used when negotiating the splice transaction
17471808
pub dual_funding_context: DualFundingChannelContext,
17481809
/// The current interactive transaction construction session under negotiation.
@@ -1755,18 +1816,18 @@ pub(super) struct SplicingChannel<SP: Deref> where SP::Target: SignerProvider {
17551816

17561817
#[cfg(splicing)]
17571818
impl<SP: Deref> SplicingChannel<SP> where SP::Target: SignerProvider {
1758-
fn new(pre_funded: FundedChannel<SP>, post_funding: FundingScope, dual_funding_context: DualFundingChannelContext, pending_splice_post: PendingSplicePost) -> Self {
1819+
fn new(pre_funded: FundedChannel<SP>, post_funding: FundingScope, dual_funding_context: DualFundingChannelContext, unfunded_context: UnfundedChannelContext, pending_splice_post: PendingSplicePost) -> Self {
17591820
Self {
17601821
pre_funded,
17611822
post_funding,
17621823
dual_funding_context,
1824+
unfunded_context,
17631825
interactive_tx_constructor: None,
17641826
pending_splice_post,
17651827
}
17661828
}
17671829

17681830
/// Handle splice_init
1769-
#[cfg(splicing)]
17701831
pub fn splice_init<ES: Deref, L: Deref>(
17711832
&mut self, _msg: &msgs::SpliceInit, our_funding_contribution: i64,
17721833
signer_provider: &SP, entropy_source: &ES, holder_node_id: &PublicKey, logger: &L,
@@ -1788,7 +1849,6 @@ impl<SP: Deref> SplicingChannel<SP> where SP::Target: SignerProvider {
17881849
}
17891850

17901851
/// Handle splice_ack
1791-
#[cfg(splicing)]
17921852
pub fn splice_ack<ES: Deref, L: Deref>(
17931853
&mut self, msg: &msgs::SpliceAck, our_funding_contribution: i64,
17941854
signer_provider: &SP, entropy_source: &ES, holder_node_id: &PublicKey, logger: &L,
@@ -1824,7 +1884,6 @@ impl<SP: Deref> SplicingChannel<SP> where SP::Target: SignerProvider {
18241884
}
18251885

18261886
/// Splice process starting; update state, log, etc.
1827-
#[cfg(splicing)]
18281887
pub(crate) fn splice_start<L: Deref>(&mut self, is_outgoing: bool, logger: &L) where L::Target: Logger {
18291888
// Set state, by this point splice_init/splice_ack handshake is complete
18301889
// TODO(splicing)
@@ -1997,15 +2056,99 @@ impl<SP: Deref> SplicingChannel<SP> where SP::Target: SignerProvider {
19972056
HandleTxCompleteResult(Ok(tx_complete))
19982057
}
19992058

2000-
// TODO implement and use
2001-
// pub fn funding_tx_constructed<L: Deref>(
2002-
// self, signing_session: InteractiveTxSigningSession, logger: &L
2003-
// ) -> Result<(msgs::CommitmentSigned, Option<Event>), ChannelError> where L::Target: Logger {
2004-
// match self.post_pending.funding_tx_constructed(signing_session, logger) {
2005-
// Ok((_chan, msg, event)) => Ok((msg, event)),
2006-
// Err((_chan, err)) => Err(err),
2007-
// }
2008-
// }
2059+
/// Copied from PendingV2Channel::funding_tx_constructed
2060+
/// TODO avoid code duplication with traits
2061+
fn funding_tx_constructed<L: Deref>(
2062+
mut self, mut signing_session: InteractiveTxSigningSession, logger: &L
2063+
) -> Result<(InteractiveTxSigningSession, HolderCommitmentPoint, msgs::CommitmentSigned, Option<Event>), (SplicingChannel<SP>, ChannelError)>
2064+
where
2065+
L::Target: Logger
2066+
{
2067+
let our_funding_satoshis = self.dual_funding_context.our_funding_satoshis;
2068+
let transaction_number = self.unfunded_context.transaction_number();
2069+
2070+
let mut output_index = None;
2071+
let expected_spk = self.pre_funded.funding.get_funding_redeemscript().to_p2wsh();
2072+
for (idx, outp) in signing_session.unsigned_tx.outputs().enumerate() {
2073+
if outp.script_pubkey() == &expected_spk && outp.value() == self.post_funding.get_value_satoshis() {
2074+
if output_index.is_some() {
2075+
return Err(ChannelError::Close((
2076+
"Multiple outputs matched the expected script and value".to_owned(),
2077+
ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) },
2078+
))).map_err(|e| (self, e));
2079+
}
2080+
output_index = Some(idx as u16);
2081+
}
2082+
}
2083+
let outpoint = if let Some(output_index) = output_index {
2084+
OutPoint { txid: signing_session.unsigned_tx.compute_txid(), index: output_index }
2085+
} else {
2086+
return Err(ChannelError::Close((
2087+
"No output matched the funding script_pubkey".to_owned(),
2088+
ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) },
2089+
))).map_err(|e| (self, e));
2090+
};
2091+
self.pre_funded.funding.channel_transaction_parameters.funding_outpoint = Some(outpoint);
2092+
// self.pre_funded.context.holder_signer.as_mut_ecdsa().provide_channel_parameters(&self.pre_funded.funding.channel_transaction_parameters);
2093+
2094+
self.pre_funded.context.assert_no_commitment_advancement(transaction_number, "initial commitment_signed");
2095+
let commitment_signed = self.pre_funded.context.get_initial_commitment_signed(&self.post_funding, logger);
2096+
let commitment_signed = match commitment_signed {
2097+
Ok(commitment_signed) => {
2098+
self.pre_funded.funding.funding_transaction = Some(signing_session.unsigned_tx.build_unsigned_tx());
2099+
commitment_signed
2100+
},
2101+
Err(err) => {
2102+
self.pre_funded.funding.channel_transaction_parameters.funding_outpoint = None;
2103+
return Err(ChannelError::Close((err.to_string(), ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) })))
2104+
.map_err(|e| (self, e));
2105+
},
2106+
};
2107+
2108+
let funding_ready_for_sig_event = None;
2109+
if signing_session.local_inputs_count() == 0 {
2110+
debug_assert_eq!(our_funding_satoshis, 0);
2111+
if signing_session.provide_holder_witnesses(self.pre_funded.context.channel_id, Vec::new()).is_err() {
2112+
debug_assert!(
2113+
false,
2114+
"Zero inputs were provided & zero witnesses were provided, but a count mismatch was somehow found",
2115+
);
2116+
}
2117+
} else {
2118+
// TODO(dual_funding): Send event for signing if we've contributed funds.
2119+
// Inform the user that SIGHASH_ALL must be used for all signatures when contributing
2120+
// inputs/signatures.
2121+
// Also warn the user that we don't do anything to prevent the counterparty from
2122+
// providing non-standard witnesses which will prevent the funding transaction from
2123+
// confirming. This warning must appear in doc comments wherever the user is contributing
2124+
// funds, whether they are initiator or acceptor.
2125+
//
2126+
// The following warning can be used when the APIs allowing contributing inputs become available:
2127+
// <div class="warning">
2128+
// WARNING: LDK makes no attempt to prevent the counterparty from using non-standard inputs which
2129+
// will prevent the funding transaction from being relayed on the bitcoin network and hence being
2130+
// confirmed.
2131+
// </div>
2132+
}
2133+
2134+
self.pre_funded.context.channel_state = ChannelState::FundingNegotiated;
2135+
2136+
// Clear the interactive transaction constructor
2137+
self.interactive_tx_constructor.take();
2138+
2139+
match self.unfunded_context.holder_commitment_point {
2140+
Some(holder_commitment_point) => {
2141+
Ok((signing_session, holder_commitment_point, commitment_signed, funding_ready_for_sig_event))
2142+
},
2143+
None => {
2144+
let err = ChannelError::close(format!(
2145+
"Expected to have holder commitment points available upon finishing interactive tx construction for channel {}",
2146+
self.pre_funded.context.channel_id(),
2147+
));
2148+
Err((self, err))
2149+
},
2150+
}
2151+
}
20092152
}
20102153

20112154
/// Contains all state common to unfunded inbound/outbound channels.
@@ -9213,7 +9356,7 @@ impl<SP: Deref> FundedChannel<SP> where
92139356
#[cfg(splicing)]
92149357
fn splice_init(
92159358
&mut self, msg: &msgs::SpliceInit, our_funding_contribution: i64,
9216-
) -> Result<(PendingSplicePost, FundingScope, DualFundingChannelContext), ChannelError>
9359+
) -> Result<(PendingSplicePost, FundingScope, DualFundingChannelContext, UnfundedChannelContext), ChannelError>
92179360
{
92189361
let _res = self.splice_init_checks(msg)?;
92199362

@@ -9264,12 +9407,12 @@ impl<SP: Deref> FundedChannel<SP> where
92649407
funding_feerate_sat_per_1000_weight: msg.funding_feerate_per_kw,
92659408
our_funding_inputs: Vec::new(),
92669409
};
9267-
// let unfunded_context = UnfundedChannelContext {
9268-
// unfunded_channel_age_ticks: 0,
9269-
// holder_commitment_point: HolderCommitmentPoint::new(&context.holder_signer, &context.secp_ctx),
9270-
// };
9410+
let unfunded_context = UnfundedChannelContext {
9411+
unfunded_channel_age_ticks: 0,
9412+
holder_commitment_point: HolderCommitmentPoint::new(&self.context.holder_signer, &self.context.secp_ctx),
9413+
};
92719414

9272-
Ok((pending_splice_post, post_funding, dual_funding_context))
9415+
Ok((pending_splice_post, post_funding, dual_funding_context, unfunded_context))
92739416
}
92749417

92759418
/// Get the splice_ack message that can be sent in response to splice initiation.
@@ -9301,7 +9444,7 @@ impl<SP: Deref> FundedChannel<SP> where
93019444
#[cfg(splicing)]
93029445
fn splice_ack(
93039446
&mut self, msg: &msgs::SpliceAck,
9304-
) -> Result<(PendingSplicePost, FundingScope, DualFundingChannelContext, i64), ChannelError>
9447+
) -> Result<(PendingSplicePost, FundingScope, DualFundingChannelContext, UnfundedChannelContext, i64), ChannelError>
93059448
{
93069449
let pending_splice = self.splice_ack_checks()?;
93079450

@@ -9352,12 +9495,12 @@ impl<SP: Deref> FundedChannel<SP> where
93529495
funding_feerate_sat_per_1000_weight: pending_splice.funding_feerate_per_kw,
93539496
our_funding_inputs: pending_splice.our_funding_inputs.clone(),
93549497
};
9355-
// let unfunded_context = UnfundedChannelContext {
9356-
// unfunded_channel_age_ticks: 0,
9357-
// holder_commitment_point: HolderCommitmentPoint::new(&context.holder_signer, &context.secp_ctx),
9358-
// };
9498+
let unfunded_context = UnfundedChannelContext {
9499+
unfunded_channel_age_ticks: 0,
9500+
holder_commitment_point: HolderCommitmentPoint::new(&self.context.holder_signer, &self.context.secp_ctx),
9501+
};
93599502

9360-
Ok((pending_splice_post, post_funding, dual_funding_context, pending_splice.our_funding_contribution))
9503+
Ok((pending_splice_post, post_funding, dual_funding_context, unfunded_context, pending_splice.our_funding_contribution))
93619504
}
93629505

93639506
// Send stuff to our remote peers:

lightning/src/ln/channelmanager.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -8548,7 +8548,9 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
85488548
if let Some(msg_send_event) = msg_send_event_opt {
85498549
peer_state.pending_msg_events.push(msg_send_event);
85508550
};
8551-
if let Some(signing_session) = signing_session_opt {
8551+
if let Some(_signing_session) = signing_session_opt {
8552+
panic!("TODO Fix commitment handling, execution should get to here");
8553+
/*
85528554
let (commitment_signed, funding_ready_for_sig_event_opt) = chan_entry
85538555
.get_mut()
85548556
.funding_tx_constructed(signing_session, &self.logger)
@@ -8568,6 +8570,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
85688570
update_fee: None,
85698571
},
85708572
});
8573+
*/
85718574
}
85728575
Ok(())
85738576
},

0 commit comments

Comments
 (0)