Skip to content

Commit 6564dce

Browse files
committed
Allow InteractiveTxConstructor use in splicing
InteractiveTxConstructor was only used in PendingV2Channel methods, but for splicing those methods are needed for FundedChannel, too. Refactor the code such that each type has a method for accessing its InteractiveTxConstructor such that it can be called in either use, refactoring code out of PendingV2Channel as needed.
1 parent e49c9cc commit 6564dce

File tree

3 files changed

+307
-267
lines changed

3 files changed

+307
-267
lines changed

lightning/src/ln/channel.rs

Lines changed: 179 additions & 174 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,9 @@ use crate::ln::channelmanager::{
5656
BREAKDOWN_TIMEOUT, MAX_LOCAL_BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA,
5757
};
5858
use crate::ln::interactivetxs::{
59-
calculate_change_output_value, get_output_weight, AbortReason, HandleTxCompleteResult,
60-
InteractiveTxConstructor, InteractiveTxConstructorArgs, InteractiveTxMessageSendResult,
61-
InteractiveTxSigningSession, SharedOwnedInput, SharedOwnedOutput, TX_COMMON_FIELDS_WEIGHT,
59+
calculate_change_output_value, get_output_weight, AbortReason, InteractiveTxConstructor,
60+
InteractiveTxConstructorArgs, InteractiveTxSigningSession, SharedOwnedInput, SharedOwnedOutput,
61+
TX_COMMON_FIELDS_WEIGHT,
6262
};
6363
use crate::ln::msgs;
6464
use crate::ln::msgs::{ClosingSigned, ClosingSignedFeeRange, DecodeError, OnionErrorPacket};
@@ -1731,6 +1731,15 @@ where
17311731
}
17321732
}
17331733

1734+
pub fn interactive_tx_constructor_mut(&mut self) -> Option<&mut InteractiveTxConstructor> {
1735+
match &mut self.phase {
1736+
ChannelPhase::UnfundedV2(chan) => chan.interactive_tx_constructor.as_mut(),
1737+
#[cfg(splicing)]
1738+
ChannelPhase::Funded(chan) => chan.interactive_tx_constructor_mut(),
1739+
_ => None,
1740+
}
1741+
}
1742+
17341743
#[rustfmt::skip]
17351744
pub fn funding_signed<L: Deref>(
17361745
&mut self, msg: &msgs::FundingSigned, best_block: BestBlock, signer_provider: &SP, logger: &L
@@ -1764,16 +1773,70 @@ where
17641773
}
17651774

17661775
pub fn funding_tx_constructed<L: Deref>(
1767-
&mut self, signing_session: InteractiveTxSigningSession, logger: &L,
1776+
&mut self, logger: &L,
17681777
) -> Result<(msgs::CommitmentSigned, Option<Event>), ChannelError>
17691778
where
17701779
L::Target: Logger,
17711780
{
1772-
if let ChannelPhase::UnfundedV2(chan) = &mut self.phase {
1773-
let logger = WithChannelContext::from(logger, &chan.context, None);
1774-
chan.funding_tx_constructed(signing_session, &&logger)
1775-
} else {
1776-
Err(ChannelError::Warn("Got a tx_complete message with no interactive transaction construction expected or in-progress".to_owned()))
1781+
let logger = WithChannelContext::from(logger, self.context(), None);
1782+
match &mut self.phase {
1783+
ChannelPhase::UnfundedV2(chan) => {
1784+
let mut signing_session =
1785+
chan.interactive_tx_constructor.take().expect("TODO").into_signing_session();
1786+
let result = chan.context.funding_tx_constructed(
1787+
&mut chan.funding,
1788+
&mut signing_session,
1789+
false,
1790+
chan.unfunded_context.transaction_number(),
1791+
&&logger,
1792+
);
1793+
1794+
// FIXME: Should this remain None if result is an Err?
1795+
chan.interactive_tx_signing_session = Some(signing_session);
1796+
1797+
return result;
1798+
},
1799+
#[cfg(splicing)]
1800+
ChannelPhase::Funded(chan) => {
1801+
if let Some(pending_splice) = chan.pending_splice.as_mut() {
1802+
if let Some(funding_negotiation) = pending_splice.funding_negotiation.take() {
1803+
if let FundingNegotiation::Pending(
1804+
mut funding,
1805+
interactive_tx_constructor,
1806+
) = funding_negotiation
1807+
{
1808+
let mut signing_session =
1809+
interactive_tx_constructor.into_signing_session();
1810+
let result = chan.context.funding_tx_constructed(
1811+
&mut funding,
1812+
&mut signing_session,
1813+
true,
1814+
chan.holder_commitment_point.transaction_number(),
1815+
&&logger,
1816+
);
1817+
1818+
// FIXME: Should these remain None if result is an Err?
1819+
chan.interactive_tx_signing_session = Some(signing_session);
1820+
pending_splice.funding_negotiation =
1821+
Some(FundingNegotiation::AwaitingSignatures(funding));
1822+
1823+
return result;
1824+
} else {
1825+
// Replace the taken state
1826+
pending_splice.funding_negotiation = Some(funding_negotiation);
1827+
}
1828+
}
1829+
}
1830+
1831+
return Err(ChannelError::Warn(
1832+
"Got a transaction negotiation message in an invalid state".to_owned(),
1833+
));
1834+
},
1835+
_ => {
1836+
return Err(ChannelError::Warn(
1837+
"Got a transaction negotiation message in an invalid phase".to_owned(),
1838+
))
1839+
},
17771840
}
17781841
}
17791842

@@ -2772,171 +2835,6 @@ where
27722835
}
27732836
}
27742837

2775-
impl<SP: Deref> PendingV2Channel<SP>
2776-
where
2777-
SP::Target: SignerProvider,
2778-
{
2779-
pub fn tx_add_input(&mut self, msg: &msgs::TxAddInput) -> InteractiveTxMessageSendResult {
2780-
InteractiveTxMessageSendResult(match &mut self.interactive_tx_constructor {
2781-
Some(ref mut tx_constructor) => tx_constructor
2782-
.handle_tx_add_input(msg)
2783-
.map_err(|reason| reason.into_tx_abort_msg(self.context.channel_id())),
2784-
None => Err(msgs::TxAbort {
2785-
channel_id: self.context.channel_id(),
2786-
data: b"No interactive transaction negotiation in progress".to_vec(),
2787-
}),
2788-
})
2789-
}
2790-
2791-
pub fn tx_add_output(&mut self, msg: &msgs::TxAddOutput) -> InteractiveTxMessageSendResult {
2792-
InteractiveTxMessageSendResult(match &mut self.interactive_tx_constructor {
2793-
Some(ref mut tx_constructor) => tx_constructor
2794-
.handle_tx_add_output(msg)
2795-
.map_err(|reason| reason.into_tx_abort_msg(self.context.channel_id())),
2796-
None => Err(msgs::TxAbort {
2797-
channel_id: self.context.channel_id(),
2798-
data: b"No interactive transaction negotiation in progress".to_vec(),
2799-
}),
2800-
})
2801-
}
2802-
2803-
pub fn tx_remove_input(&mut self, msg: &msgs::TxRemoveInput) -> InteractiveTxMessageSendResult {
2804-
InteractiveTxMessageSendResult(match &mut self.interactive_tx_constructor {
2805-
Some(ref mut tx_constructor) => tx_constructor
2806-
.handle_tx_remove_input(msg)
2807-
.map_err(|reason| reason.into_tx_abort_msg(self.context.channel_id())),
2808-
None => Err(msgs::TxAbort {
2809-
channel_id: self.context.channel_id(),
2810-
data: b"No interactive transaction negotiation in progress".to_vec(),
2811-
}),
2812-
})
2813-
}
2814-
2815-
pub fn tx_remove_output(
2816-
&mut self, msg: &msgs::TxRemoveOutput,
2817-
) -> InteractiveTxMessageSendResult {
2818-
InteractiveTxMessageSendResult(match &mut self.interactive_tx_constructor {
2819-
Some(ref mut tx_constructor) => tx_constructor
2820-
.handle_tx_remove_output(msg)
2821-
.map_err(|reason| reason.into_tx_abort_msg(self.context.channel_id())),
2822-
None => Err(msgs::TxAbort {
2823-
channel_id: self.context.channel_id(),
2824-
data: b"No interactive transaction negotiation in progress".to_vec(),
2825-
}),
2826-
})
2827-
}
2828-
2829-
pub fn tx_complete(&mut self, msg: &msgs::TxComplete) -> HandleTxCompleteResult {
2830-
let tx_constructor = match &mut self.interactive_tx_constructor {
2831-
Some(ref mut tx_constructor) => tx_constructor,
2832-
None => {
2833-
let tx_abort = msgs::TxAbort {
2834-
channel_id: msg.channel_id,
2835-
data: b"No interactive transaction negotiation in progress".to_vec(),
2836-
};
2837-
return HandleTxCompleteResult(Err(tx_abort));
2838-
},
2839-
};
2840-
2841-
let tx_complete = match tx_constructor.handle_tx_complete(msg) {
2842-
Ok(tx_complete) => tx_complete,
2843-
Err(reason) => {
2844-
return HandleTxCompleteResult(Err(reason.into_tx_abort_msg(msg.channel_id)))
2845-
},
2846-
};
2847-
2848-
HandleTxCompleteResult(Ok(tx_complete))
2849-
}
2850-
2851-
#[rustfmt::skip]
2852-
pub fn funding_tx_constructed<L: Deref>(
2853-
&mut self, mut signing_session: InteractiveTxSigningSession, logger: &L
2854-
) -> Result<(msgs::CommitmentSigned, Option<Event>), ChannelError>
2855-
where
2856-
L::Target: Logger
2857-
{
2858-
let our_funding_satoshis = self.funding_negotiation_context.our_funding_contribution_satoshis;
2859-
let transaction_number = self.unfunded_context.transaction_number();
2860-
2861-
let mut output_index = None;
2862-
let expected_spk = self.funding.get_funding_redeemscript().to_p2wsh();
2863-
for (idx, outp) in signing_session.unsigned_tx().outputs().enumerate() {
2864-
if outp.script_pubkey() == &expected_spk && outp.value() == self.funding.get_value_satoshis() {
2865-
if output_index.is_some() {
2866-
let msg = "Multiple outputs matched the expected script and value";
2867-
let reason = ClosureReason::ProcessingError { err: msg.to_owned() };
2868-
return Err(ChannelError::Close((msg.to_owned(), reason)));
2869-
}
2870-
output_index = Some(idx as u16);
2871-
}
2872-
}
2873-
let outpoint = if let Some(output_index) = output_index {
2874-
OutPoint { txid: signing_session.unsigned_tx().compute_txid(), index: output_index }
2875-
} else {
2876-
let msg = "No output matched the funding script_pubkey";
2877-
let reason = ClosureReason::ProcessingError { err: msg.to_owned() };
2878-
return Err(ChannelError::Close((msg.to_owned(), reason)));
2879-
};
2880-
self.funding.channel_transaction_parameters.funding_outpoint = Some(outpoint);
2881-
2882-
self.context.assert_no_commitment_advancement(transaction_number, "initial commitment_signed");
2883-
let commitment_signed = self.context.get_initial_commitment_signed(&self.funding, logger);
2884-
let commitment_signed = match commitment_signed {
2885-
Ok(commitment_signed) => commitment_signed,
2886-
Err(e) => {
2887-
self.funding.channel_transaction_parameters.funding_outpoint = None;
2888-
return Err(e)
2889-
},
2890-
};
2891-
2892-
let funding_ready_for_sig_event = if signing_session.local_inputs_count() == 0 {
2893-
debug_assert_eq!(our_funding_satoshis, 0);
2894-
if signing_session.provide_holder_witnesses(self.context.channel_id, Vec::new()).is_err() {
2895-
debug_assert!(
2896-
false,
2897-
"Zero inputs were provided & zero witnesses were provided, but a count mismatch was somehow found",
2898-
);
2899-
let msg = "V2 channel rejected due to sender error";
2900-
let reason = ClosureReason::ProcessingError { err: msg.to_owned() };
2901-
return Err(ChannelError::Close((msg.to_owned(), reason)));
2902-
}
2903-
None
2904-
} else {
2905-
// TODO(dual_funding): Send event for signing if we've contributed funds.
2906-
// Inform the user that SIGHASH_ALL must be used for all signatures when contributing
2907-
// inputs/signatures.
2908-
// Also warn the user that we don't do anything to prevent the counterparty from
2909-
// providing non-standard witnesses which will prevent the funding transaction from
2910-
// confirming. This warning must appear in doc comments wherever the user is contributing
2911-
// funds, whether they are initiator or acceptor.
2912-
//
2913-
// The following warning can be used when the APIs allowing contributing inputs become available:
2914-
// <div class="warning">
2915-
// WARNING: LDK makes no attempt to prevent the counterparty from using non-standard inputs which
2916-
// will prevent the funding transaction from being relayed on the bitcoin network and hence being
2917-
// confirmed.
2918-
// </div>
2919-
debug_assert!(
2920-
false,
2921-
"We don't support users providing inputs but somehow we had more than zero inputs",
2922-
);
2923-
let msg = "V2 channel rejected due to sender error";
2924-
let reason = ClosureReason::ProcessingError { err: msg.to_owned() };
2925-
return Err(ChannelError::Close((msg.to_owned(), reason)));
2926-
};
2927-
2928-
let mut channel_state = ChannelState::FundingNegotiated(FundingNegotiatedFlags::new());
2929-
channel_state.set_interactive_signing();
2930-
self.context.channel_state = channel_state;
2931-
2932-
// Clear the interactive transaction constructor
2933-
self.interactive_tx_constructor.take();
2934-
self.interactive_tx_signing_session = Some(signing_session);
2935-
2936-
Ok((commitment_signed, funding_ready_for_sig_event))
2937-
}
2938-
}
2939-
29402838
impl<SP: Deref> ChannelContext<SP>
29412839
where
29422840
SP::Target: SignerProvider,
@@ -5403,6 +5301,97 @@ where
54035301
Ok(())
54045302
}
54055303

5304+
#[rustfmt::skip]
5305+
fn funding_tx_constructed<L: Deref>(
5306+
&mut self, funding: &mut FundingScope, signing_session: &mut InteractiveTxSigningSession,
5307+
is_splice: bool, holder_commitment_transaction_number: u64, logger: &L
5308+
) -> Result<(msgs::CommitmentSigned, Option<Event>), ChannelError>
5309+
where
5310+
L::Target: Logger
5311+
{
5312+
let mut output_index = None;
5313+
let expected_spk = funding.get_funding_redeemscript().to_p2wsh();
5314+
for (idx, outp) in signing_session.unsigned_tx().outputs().enumerate() {
5315+
if outp.script_pubkey() == &expected_spk && outp.value() == funding.get_value_satoshis() {
5316+
if output_index.is_some() {
5317+
let msg = "Multiple outputs matched the expected script and value";
5318+
let reason = ClosureReason::ProcessingError { err: msg.to_owned() };
5319+
return Err(ChannelError::Close((msg.to_owned(), reason)));
5320+
}
5321+
output_index = Some(idx as u16);
5322+
}
5323+
}
5324+
let outpoint = if let Some(output_index) = output_index {
5325+
OutPoint { txid: signing_session.unsigned_tx().compute_txid(), index: output_index }
5326+
} else {
5327+
let msg = "No output matched the funding script_pubkey";
5328+
let reason = ClosureReason::ProcessingError { err: msg.to_owned() };
5329+
return Err(ChannelError::Close((msg.to_owned(), reason)));
5330+
};
5331+
funding
5332+
.channel_transaction_parameters.funding_outpoint = Some(outpoint);
5333+
5334+
if is_splice {
5335+
let message = "TODO Forced error, incomplete implementation".to_owned();
5336+
// TODO(splicing) Forced error, as the use case is not complete
5337+
return Err(ChannelError::Close((
5338+
message.clone(),
5339+
ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false), message }
5340+
)));
5341+
}
5342+
5343+
self.assert_no_commitment_advancement(holder_commitment_transaction_number, "initial commitment_signed");
5344+
let commitment_signed = self.get_initial_commitment_signed(&funding, logger);
5345+
let commitment_signed = match commitment_signed {
5346+
Ok(commitment_signed) => commitment_signed,
5347+
Err(e) => {
5348+
funding.channel_transaction_parameters.funding_outpoint = None;
5349+
return Err(e)
5350+
},
5351+
};
5352+
5353+
let funding_ready_for_sig_event = if signing_session.local_inputs_count() == 0 {
5354+
if signing_session.provide_holder_witnesses(self.channel_id, Vec::new()).is_err() {
5355+
debug_assert!(
5356+
false,
5357+
"Zero inputs were provided & zero witnesses were provided, but a count mismatch was somehow found",
5358+
);
5359+
let msg = "V2 channel rejected due to sender error";
5360+
let reason = ClosureReason::ProcessingError { err: msg.to_owned() };
5361+
return Err(ChannelError::Close((msg.to_owned(), reason)));
5362+
}
5363+
None
5364+
} else {
5365+
// TODO(dual_funding): Send event for signing if we've contributed funds.
5366+
// Inform the user that SIGHASH_ALL must be used for all signatures when contributing
5367+
// inputs/signatures.
5368+
// Also warn the user that we don't do anything to prevent the counterparty from
5369+
// providing non-standard witnesses which will prevent the funding transaction from
5370+
// confirming. This warning must appear in doc comments wherever the user is contributing
5371+
// funds, whether they are initiator or acceptor.
5372+
//
5373+
// The following warning can be used when the APIs allowing contributing inputs become available:
5374+
// <div class="warning">
5375+
// WARNING: LDK makes no attempt to prevent the counterparty from using non-standard inputs which
5376+
// will prevent the funding transaction from being relayed on the bitcoin network and hence being
5377+
// confirmed.
5378+
// </div>
5379+
debug_assert!(
5380+
false,
5381+
"We don't support users providing inputs but somehow we had more than zero inputs",
5382+
);
5383+
let msg = "V2 channel rejected due to sender error";
5384+
let reason = ClosureReason::ProcessingError { err: msg.to_owned() };
5385+
return Err(ChannelError::Close((msg.to_owned(), reason)));
5386+
};
5387+
5388+
let mut channel_state = ChannelState::FundingNegotiated(FundingNegotiatedFlags::new());
5389+
channel_state.set_interactive_signing();
5390+
self.channel_state = channel_state;
5391+
5392+
Ok((commitment_signed, funding_ready_for_sig_event))
5393+
}
5394+
54065395
/// Asserts that the commitment tx numbers have not advanced from their initial number.
54075396
#[rustfmt::skip]
54085397
fn assert_no_commitment_advancement(&self, holder_commitment_transaction_number: u64, msg_name: &str) {
@@ -6003,6 +5992,22 @@ where
60035992
self.context.force_shutdown(&self.funding, closure_reason)
60045993
}
60055994

5995+
#[cfg(splicing)]
5996+
fn interactive_tx_constructor_mut(&mut self) -> Option<&mut InteractiveTxConstructor> {
5997+
self.pending_splice
5998+
.as_mut()
5999+
.and_then(|pending_splice| pending_splice.funding_negotiation.as_mut())
6000+
.and_then(|funding_negotiation| {
6001+
if let FundingNegotiation::Pending(_, interactive_tx_constructor) =
6002+
funding_negotiation
6003+
{
6004+
Some(interactive_tx_constructor)
6005+
} else {
6006+
None
6007+
}
6008+
})
6009+
}
6010+
60066011
#[rustfmt::skip]
60076012
fn check_remote_fee<F: Deref, L: Deref>(
60086013
channel_type: &ChannelTypeFeatures, fee_estimator: &LowerBoundedFeeEstimator<F>,

0 commit comments

Comments
 (0)