@@ -1556,21 +1556,40 @@ impl<SP: Deref> Channel<SP> where
1556
1556
L::Target: Logger
1557
1557
{
1558
1558
let phase = core::mem::replace(&mut self.phase, ChannelPhase::Undefined);
1559
- let result = if let ChannelPhase::UnfundedV2(chan) = phase {
1560
- let logger = WithChannelContext::from(logger, &chan.context, None);
1561
- match chan.funding_tx_constructed(signing_session, &&logger) {
1562
- Ok((chan, commitment_signed, event)) => {
1563
- self.phase = ChannelPhase::Funded(chan);
1564
- Ok((commitment_signed, event))
1565
- },
1566
- Err((chan, e)) => {
1567
- self.phase = ChannelPhase::UnfundedV2(chan);
1568
- Err(e)
1569
- },
1559
+ let result = match phase {
1560
+ ChannelPhase::UnfundedV2(chan) => {
1561
+ let logger = WithChannelContext::from(logger, &chan.context, None);
1562
+ match chan.funding_tx_constructed(signing_session, &&logger) {
1563
+ Ok((chan, commitment_signed, event)) => {
1564
+ self.phase = ChannelPhase::Funded(chan);
1565
+ Ok((commitment_signed, event))
1566
+ },
1567
+ Err((chan, e)) => {
1568
+ // revert
1569
+ self.phase = ChannelPhase::UnfundedV2(chan);
1570
+ Err(e)
1571
+ },
1572
+ }
1573
+ }
1574
+ #[cfg(splicing)]
1575
+ ChannelPhase::RefundingV2(chan) => {
1576
+ let logger = WithChannelContext::from(logger, &chan.pre_funded.context, None);
1577
+ match chan.funding_tx_constructed(signing_session, &&logger) {
1578
+ Ok((signing_session, holder_commitment_point, commitment_signed, event)) => {
1579
+ let _res = self.phase_from_splice_to_funded(signing_session, holder_commitment_point)?;
1580
+ Ok((commitment_signed, event))
1581
+ },
1582
+ Err((chan, e)) => {
1583
+ // revert
1584
+ self.phase = ChannelPhase::RefundingV2(chan);
1585
+ Err(e)
1586
+ },
1587
+ }
1588
+ }
1589
+ _ => {
1590
+ self.phase = phase;
1591
+ Err(ChannelError::Warn("Got a tx_complete message with no interactive transaction construction expected or in-progress".to_owned()))
1570
1592
}
1571
- } else {
1572
- self.phase = phase;
1573
- Err(ChannelError::Warn("Got a tx_complete message with no interactive transaction construction expected or in-progress".to_owned()))
1574
1593
};
1575
1594
1576
1595
debug_assert!(!matches!(self.phase, ChannelPhase::Undefined));
@@ -1580,11 +1599,10 @@ impl<SP: Deref> Channel<SP> where
1580
1599
/// Transition the channel from Funded to SplicingChannel.
1581
1600
/// Done in one go, as the existing ('pre') channel is put in the new channel (alongside a new one).
1582
1601
#[cfg(splicing)]
1583
- fn phase_to_splice(&mut self, post_funding: FundingScope, dual_funding_context: DualFundingChannelContext, pending_splice_post: PendingSplicePost) -> Result<(), ChannelError>
1584
- {
1602
+ fn phase_from_funded_to_splice(&mut self, post_funding: FundingScope, dual_funding_context: DualFundingChannelContext, unfunded_context: UnfundedChannelContext, pending_splice_post: PendingSplicePost) -> Result<(), ChannelError> {
1585
1603
let phase = core::mem::replace(&mut self.phase, ChannelPhase::Undefined);
1586
1604
let result = if let ChannelPhase::Funded(prev_chan) = phase {
1587
- self.phase = ChannelPhase::RefundingV2(SplicingChannel::new(prev_chan, post_funding, dual_funding_context, pending_splice_post));
1605
+ self.phase = ChannelPhase::RefundingV2(SplicingChannel::new(prev_chan, post_funding, dual_funding_context, unfunded_context, pending_splice_post));
1588
1606
Ok(())
1589
1607
} else {
1590
1608
// revert phase
@@ -1595,6 +1613,29 @@ impl<SP: Deref> Channel<SP> where
1595
1613
result
1596
1614
}
1597
1615
1616
+ /// Transition the channel from SplicingChannel to Funded, after negotiating new funded.
1617
+ #[cfg(splicing)]
1618
+ fn phase_from_splice_to_funded(&mut self, signing_session: InteractiveTxSigningSession, holder_commitment_point: HolderCommitmentPoint) -> Result<(), ChannelError> {
1619
+ let phase = core::mem::replace(&mut self.phase, ChannelPhase::Undefined);
1620
+ let result = if let ChannelPhase::RefundingV2(chan) = phase {
1621
+ self.phase = ChannelPhase::Funded(FundedChannel {
1622
+ funding: chan.post_funding,
1623
+ context: chan.pre_funded.context,
1624
+ interactive_tx_signing_session: Some(signing_session),
1625
+ holder_commitment_point,
1626
+ pending_splice_pre: None,
1627
+ pending_splice_post: None,
1628
+ });
1629
+ Ok(())
1630
+ } else {
1631
+ // revert phase
1632
+ self.phase = phase;
1633
+ Err(ChannelError::Warn("Cannot transition away from splicing, not in splicing phase".to_owned()))
1634
+ };
1635
+ debug_assert!(!matches!(self.phase, ChannelPhase::Undefined));
1636
+ result
1637
+ }
1638
+
1598
1639
#[cfg(splicing)]
1599
1640
pub fn splice_init<ES: Deref, L: Deref>(
1600
1641
&mut self, msg: &msgs::SpliceInit, our_funding_contribution: i64,
@@ -1606,10 +1647,10 @@ impl<SP: Deref> Channel<SP> where
1606
1647
{
1607
1648
// Explicit check for Funded, not as_funded; RefundingV2 not allowed
1608
1649
if let ChannelPhase::Funded(prev_chan) = &mut self.phase {
1609
- let (pending_splice_post, post_funding, dual_funding_context) =
1650
+ let (pending_splice_post, post_funding, dual_funding_context, unfunded_context ) =
1610
1651
prev_chan.splice_init(msg, our_funding_contribution)?;
1611
1652
1612
- let _res = self.phase_to_splice (post_funding, dual_funding_context, pending_splice_post)?;
1653
+ let _res = self.phase_from_funded_to_splice (post_funding, dual_funding_context, unfunded_context , pending_splice_post)?;
1613
1654
1614
1655
if let ChannelPhase::RefundingV2(chan) = &mut self.phase {
1615
1656
let splice_ack_msg = chan.splice_init(msg, our_funding_contribution, signer_provider, entropy_source, our_node_id, logger)?;
@@ -1633,10 +1674,10 @@ impl<SP: Deref> Channel<SP> where
1633
1674
{
1634
1675
// Explicit check for Funded, not as_funded; RefundingV2 not allowed
1635
1676
if let ChannelPhase::Funded(prev_chan) = &mut self.phase {
1636
- let (pending_splice_post, post_funding, dual_funding_context, our_funding_contribution) =
1677
+ let (pending_splice_post, post_funding, dual_funding_context, unfunded_context, our_funding_contribution) =
1637
1678
prev_chan.splice_ack(msg)?;
1638
1679
1639
- let _res = self.phase_to_splice (post_funding, dual_funding_context, pending_splice_post)?;
1680
+ let _res = self.phase_from_funded_to_splice (post_funding, dual_funding_context, unfunded_context , pending_splice_post)?;
1640
1681
1641
1682
if let ChannelPhase::RefundingV2(chan) = &mut self.phase {
1642
1683
let tx_msg_opt = chan.splice_ack(msg, our_funding_contribution, signer_provider, entropy_source, our_node_id, logger)?;
@@ -1709,9 +1750,9 @@ pub(super) struct SplicingChannel<SP: Deref> where SP::Target: SignerProvider {
1709
1750
/// TODO: replace it with its fields; done with trait?
1710
1751
pub pre_funded: FundedChannel<SP>,
1711
1752
1712
- // Fields for PendingV2Channel follow, except ChannelContext
1753
+ // Fields from PendingV2Channel follow, except ChannelContext, which is reused from above
1713
1754
pub post_funding: FundingScope,
1714
- // pub unfunded_context: Option< UnfundedChannelContext> ,
1755
+ pub unfunded_context: UnfundedChannelContext,
1715
1756
/// Used when negotiating the splice transaction
1716
1757
pub dual_funding_context: DualFundingChannelContext,
1717
1758
/// The current interactive transaction construction session under negotiation.
@@ -1724,11 +1765,12 @@ pub(super) struct SplicingChannel<SP: Deref> where SP::Target: SignerProvider {
1724
1765
1725
1766
#[cfg(splicing)]
1726
1767
impl<SP: Deref> SplicingChannel<SP> where SP::Target: SignerProvider {
1727
- fn new(pre_funded: FundedChannel<SP>, post_funding: FundingScope, dual_funding_context: DualFundingChannelContext, pending_splice_post: PendingSplicePost) -> Self {
1768
+ fn new(pre_funded: FundedChannel<SP>, post_funding: FundingScope, dual_funding_context: DualFundingChannelContext, unfunded_context: UnfundedChannelContext, pending_splice_post: PendingSplicePost) -> Self {
1728
1769
Self {
1729
1770
pre_funded,
1730
1771
post_funding,
1731
1772
dual_funding_context,
1773
+ unfunded_context,
1732
1774
interactive_tx_constructor: None,
1733
1775
pending_splice_post,
1734
1776
}
@@ -1966,15 +2008,100 @@ impl<SP: Deref> SplicingChannel<SP> where SP::Target: SignerProvider {
1966
2008
HandleTxCompleteResult(Ok(tx_complete))
1967
2009
}
1968
2010
1969
- // TODO implement and use
1970
- // pub fn funding_tx_constructed<L: Deref>(
1971
- // self, signing_session: InteractiveTxSigningSession, logger: &L
1972
- // ) -> Result<(msgs::CommitmentSigned, Option<Event>), ChannelError> where L::Target: Logger {
1973
- // match self.post_pending.funding_tx_constructed(signing_session, logger) {
1974
- // Ok((_chan, msg, event)) => Ok((msg, event)),
1975
- // Err((_chan, err)) => Err(err),
1976
- // }
1977
- // }
2011
+ /// Copied from PendingV2Channel::funding_tx_constructed
2012
+ /// TODO avoid code duplication with traits
2013
+ fn funding_tx_constructed<L: Deref>(
2014
+ mut self, mut signing_session: InteractiveTxSigningSession, logger: &L
2015
+ ) -> Result<(InteractiveTxSigningSession, HolderCommitmentPoint, msgs::CommitmentSigned, Option<Event>), (SplicingChannel<SP>, ChannelError)>
2016
+ where
2017
+ L::Target: Logger
2018
+ {
2019
+ let our_funding_satoshis = self.dual_funding_context.our_funding_satoshis;
2020
+ let transaction_number = self.unfunded_context.transaction_number();
2021
+
2022
+ let mut output_index = None;
2023
+ let expected_spk = self.pre_funded.context.get_funding_redeemscript().to_p2wsh();
2024
+ for (idx, outp) in signing_session.unsigned_tx.outputs().enumerate() {
2025
+ if outp.script_pubkey() == &expected_spk && outp.value() == self.post_funding.get_value_satoshis() {
2026
+ if output_index.is_some() {
2027
+ return Err(ChannelError::Close((
2028
+ "Multiple outputs matched the expected script and value".to_owned(),
2029
+ ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) },
2030
+ ))).map_err(|e| (self, e));
2031
+ }
2032
+ output_index = Some(idx as u16);
2033
+ }
2034
+ }
2035
+ let outpoint = if let Some(output_index) = output_index {
2036
+ OutPoint { txid: signing_session.unsigned_tx.compute_txid(), index: output_index }
2037
+ } else {
2038
+ return Err(ChannelError::Close((
2039
+ "No output matched the funding script_pubkey".to_owned(),
2040
+ ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) },
2041
+ ))).map_err(|e| (self, e));
2042
+ };
2043
+ self.pre_funded.context.channel_transaction_parameters.funding_outpoint = Some(outpoint);
2044
+ self.pre_funded.context.holder_signer.as_mut().provide_channel_parameters(&self.pre_funded.context.channel_transaction_parameters);
2045
+
2046
+ self.pre_funded.context.assert_no_commitment_advancement(transaction_number, "initial commitment_signed");
2047
+ let commitment_signed = self.pre_funded.context.get_initial_commitment_signed(&self.post_funding, logger);
2048
+ let commitment_signed = match commitment_signed {
2049
+ Ok(commitment_signed) => {
2050
+ // TODO: funding tx should be in FundingContext
2051
+ self.pre_funded.context.funding_transaction = Some(signing_session.unsigned_tx.build_unsigned_tx());
2052
+ commitment_signed
2053
+ },
2054
+ Err(err) => {
2055
+ self.pre_funded.context.channel_transaction_parameters.funding_outpoint = None;
2056
+ return Err(ChannelError::Close((err.to_string(), ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) })))
2057
+ .map_err(|e| (self, e));
2058
+ },
2059
+ };
2060
+
2061
+ let funding_ready_for_sig_event = None;
2062
+ if signing_session.local_inputs_count() == 0 {
2063
+ debug_assert_eq!(our_funding_satoshis, 0);
2064
+ if signing_session.provide_holder_witnesses(self.pre_funded.context.channel_id, Vec::new()).is_err() {
2065
+ debug_assert!(
2066
+ false,
2067
+ "Zero inputs were provided & zero witnesses were provided, but a count mismatch was somehow found",
2068
+ );
2069
+ }
2070
+ } else {
2071
+ // TODO(dual_funding): Send event for signing if we've contributed funds.
2072
+ // Inform the user that SIGHASH_ALL must be used for all signatures when contributing
2073
+ // inputs/signatures.
2074
+ // Also warn the user that we don't do anything to prevent the counterparty from
2075
+ // providing non-standard witnesses which will prevent the funding transaction from
2076
+ // confirming. This warning must appear in doc comments wherever the user is contributing
2077
+ // funds, whether they are initiator or acceptor.
2078
+ //
2079
+ // The following warning can be used when the APIs allowing contributing inputs become available:
2080
+ // <div class="warning">
2081
+ // WARNING: LDK makes no attempt to prevent the counterparty from using non-standard inputs which
2082
+ // will prevent the funding transaction from being relayed on the bitcoin network and hence being
2083
+ // confirmed.
2084
+ // </div>
2085
+ }
2086
+
2087
+ self.pre_funded.context.channel_state = ChannelState::FundingNegotiated;
2088
+
2089
+ // Clear the interactive transaction constructor
2090
+ self.interactive_tx_constructor.take();
2091
+
2092
+ match self.unfunded_context.holder_commitment_point {
2093
+ Some(holder_commitment_point) => {
2094
+ Ok((signing_session, holder_commitment_point, commitment_signed, funding_ready_for_sig_event))
2095
+ },
2096
+ None => {
2097
+ let err = ChannelError::close(format!(
2098
+ "Expected to have holder commitment points available upon finishing interactive tx construction for channel {}",
2099
+ self.pre_funded.context.channel_id(),
2100
+ ));
2101
+ Err((self, err))
2102
+ },
2103
+ }
2104
+ }
1978
2105
}
1979
2106
1980
2107
/// Contains all state common to unfunded inbound/outbound channels.
@@ -9181,7 +9308,7 @@ impl<SP: Deref> FundedChannel<SP> where
9181
9308
#[cfg(splicing)]
9182
9309
fn splice_init(
9183
9310
&mut self, msg: &msgs::SpliceInit, our_funding_contribution: i64,
9184
- ) -> Result<(PendingSplicePost, FundingScope, DualFundingChannelContext), ChannelError>
9311
+ ) -> Result<(PendingSplicePost, FundingScope, DualFundingChannelContext, UnfundedChannelContext ), ChannelError>
9185
9312
{
9186
9313
let _res = self.splice_init_checks(msg)?;
9187
9314
@@ -9229,12 +9356,12 @@ impl<SP: Deref> FundedChannel<SP> where
9229
9356
funding_feerate_sat_per_1000_weight: msg.funding_feerate_per_kw,
9230
9357
our_funding_inputs: Vec::new(),
9231
9358
};
9232
- // let unfunded_context = UnfundedChannelContext {
9233
- // unfunded_channel_age_ticks: 0,
9234
- // holder_commitment_point: HolderCommitmentPoint::new(&context.holder_signer, &context.secp_ctx),
9235
- // };
9359
+ let unfunded_context = UnfundedChannelContext {
9360
+ unfunded_channel_age_ticks: 0,
9361
+ holder_commitment_point: HolderCommitmentPoint::new(&self. context.holder_signer, &self. context.secp_ctx),
9362
+ };
9236
9363
9237
- Ok((pending_splice_post, post_funding, dual_funding_context))
9364
+ Ok((pending_splice_post, post_funding, dual_funding_context, unfunded_context ))
9238
9365
}
9239
9366
9240
9367
/// Checks during handling splice_ack
@@ -9252,7 +9379,7 @@ impl<SP: Deref> FundedChannel<SP> where
9252
9379
#[cfg(splicing)]
9253
9380
fn splice_ack(
9254
9381
&mut self, msg: &msgs::SpliceAck,
9255
- ) -> Result<(PendingSplicePost, FundingScope, DualFundingChannelContext, i64), ChannelError>
9382
+ ) -> Result<(PendingSplicePost, FundingScope, DualFundingChannelContext, UnfundedChannelContext, i64), ChannelError>
9256
9383
{
9257
9384
let pending_splice = self.splice_ack_checks()?;
9258
9385
@@ -9300,12 +9427,12 @@ impl<SP: Deref> FundedChannel<SP> where
9300
9427
funding_feerate_sat_per_1000_weight: pending_splice.funding_feerate_per_kw,
9301
9428
our_funding_inputs: pending_splice.our_funding_inputs.clone(),
9302
9429
};
9303
- // let unfunded_context = UnfundedChannelContext {
9304
- // unfunded_channel_age_ticks: 0,
9305
- // holder_commitment_point: HolderCommitmentPoint::new(&context.holder_signer, &context.secp_ctx),
9306
- // };
9430
+ let unfunded_context = UnfundedChannelContext {
9431
+ unfunded_channel_age_ticks: 0,
9432
+ holder_commitment_point: HolderCommitmentPoint::new(&self. context.holder_signer, &self. context.secp_ctx),
9433
+ };
9307
9434
9308
- Ok((pending_splice_post, post_funding, dual_funding_context, pending_splice.our_funding_contribution))
9435
+ Ok((pending_splice_post, post_funding, dual_funding_context, unfunded_context, pending_splice.our_funding_contribution))
9309
9436
}
9310
9437
9311
9438
// Send stuff to our remote peers:
0 commit comments