Skip to content

Commit 3e999f8

Browse files
committed
Put V2 transaction negotiation behind a trait
PendingV2Channel struct can do transaction negotiation operations, but now behind a trait, so that FundingChannel is also do that, and inherit some common logic.
1 parent a88bf56 commit 3e999f8

File tree

2 files changed

+166
-64
lines changed

2 files changed

+166
-64
lines changed

lightning/src/ln/channel.rs

Lines changed: 165 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -2302,7 +2302,21 @@ impl<SP: Deref> InitialRemoteCommitmentReceiver<SP> for FundedChannel<SP> where
23022302
}
23032303
}
23042304

2305-
impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
2305+
/// A channel struct implementing this trait can perform V2 transaction negotiation,
2306+
/// either at channel open or during splicing.
2307+
/// Accessors return a Result, because [`FundedChannel`] can act like a TX constructor,
2308+
/// but not always (only during splicing).
2309+
pub(super) trait FundingTxConstructorV2<SP: Deref>: ChannelContextProvider<SP> where SP::Target: SignerProvider {
2310+
fn pending_funding(&self) -> Result<&FundingScope, &'static str>;
2311+
fn pending_funding_mut(&mut self) -> Result<&mut FundingScope, &'static str>;
2312+
fn pending_funding_and_context_mut(&mut self) -> Result<(&FundingScope, &mut ChannelContext<SP>), &'static str>;
2313+
fn dual_funding_context(&self) -> Result<&DualFundingChannelContext, &'static str>;
2314+
fn swap_out_dual_funding_context_inputs(&mut self, funding_inputs: &mut Vec<(TxIn, TransactionU16LenLimited)>) -> Result<(), &'static str>;
2315+
fn unfunded_context(&self) -> Result<&UnfundedChannelContext, &'static str>;
2316+
fn interactive_tx_constructor(&self) -> Result<Option<&InteractiveTxConstructor>, &'static str>;
2317+
fn interactive_tx_constructor_mut(&mut self) -> Result<&mut Option<InteractiveTxConstructor>, &'static str>;
2318+
fn interactive_tx_signing_session_mut(&mut self) -> Result<&mut Option<InteractiveTxSigningSession>, &'static str>;
2319+
23062320
/// Prepare and start interactive transaction negotiation.
23072321
/// `change_destination_opt` - Optional destination for optional change; if None,
23082322
/// default destination address is used.
@@ -2314,11 +2328,12 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
23142328
) -> Result<Option<InteractiveTxMessageSend>, AbortReason>
23152329
where ES::Target: EntropySource
23162330
{
2317-
debug_assert!(matches!(self.context.channel_state, ChannelState::NegotiatingFunding(_)));
2318-
debug_assert!(self.interactive_tx_constructor.is_none());
2331+
debug_assert!(matches!(self.context().channel_state, ChannelState::NegotiatingFunding(_)));
2332+
debug_assert!(self.interactive_tx_constructor().unwrap_or(None).is_none());
23192333

23202334
let mut funding_inputs = Vec::new();
2321-
mem::swap(&mut self.dual_funding_context.our_funding_inputs, &mut funding_inputs);
2335+
self.swap_out_dual_funding_context_inputs(&mut funding_inputs)
2336+
.map_err(|e| AbortReason::InternalError(e))?;
23222337

23232338
// TODO(splicing): Add prev funding tx as input, must be provided as a parameter
23242339

@@ -2328,15 +2343,20 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
23282343
let mut funding_outputs = Vec::new();
23292344
let mut expected_remote_shared_funding_output = None;
23302345

2346+
let pending_funding = self.pending_funding()
2347+
.map_err(|e| AbortReason::InternalError(e))?;
2348+
23312349
let shared_funding_output = TxOut {
2332-
value: Amount::from_sat(self.funding.get_value_satoshis()),
2333-
script_pubkey: self.funding.get_funding_redeemscript().to_p2wsh(),
2350+
value: Amount::from_sat(pending_funding.get_value_satoshis()),
2351+
script_pubkey: pending_funding.get_funding_redeemscript().to_p2wsh(),
23342352
};
23352353

2336-
if self.funding.is_outbound() {
2354+
let dual_funding_context = &self.dual_funding_context()
2355+
.map_err(|e| AbortReason::InternalError(e))?;
2356+
if pending_funding.is_outbound() {
23372357
funding_outputs.push(
23382358
OutputOwned::Shared(SharedOwnedOutput::new(
2339-
shared_funding_output, self.dual_funding_context.our_funding_satoshis,
2359+
shared_funding_output, dual_funding_context.our_funding_satoshis,
23402360
))
23412361
);
23422362
} else {
@@ -2348,13 +2368,13 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
23482368
let change_script = if let Some(script) = change_destination_opt {
23492369
script
23502370
} else {
2351-
signer_provider.get_destination_script(self.context.channel_keys_id)
2371+
signer_provider.get_destination_script(self.context().channel_keys_id)
23522372
.map_err(|_err| AbortReason::InternalError("Error getting destination script"))?
23532373
};
23542374
let change_value_opt = calculate_change_output_value(
2355-
self.funding.is_outbound(), self.dual_funding_context.our_funding_satoshis,
2375+
pending_funding.is_outbound(), dual_funding_context.our_funding_satoshis,
23562376
&funding_inputs, &funding_outputs,
2357-
self.dual_funding_context.funding_feerate_sat_per_1000_weight,
2377+
dual_funding_context.funding_feerate_sat_per_1000_weight,
23582378
change_script.minimal_non_dust().to_sat(),
23592379
)?;
23602380
if let Some(change_value) = change_value_opt {
@@ -2363,10 +2383,10 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
23632383
script_pubkey: change_script,
23642384
};
23652385
let change_output_weight = get_output_weight(&change_output.script_pubkey).to_wu();
2366-
let change_output_fee = fee_for_weight(self.dual_funding_context.funding_feerate_sat_per_1000_weight, change_output_weight);
2386+
let change_output_fee = fee_for_weight(dual_funding_context.funding_feerate_sat_per_1000_weight, change_output_weight);
23672387
let change_value_decreased_with_fee = change_value.saturating_sub(change_output_fee);
23682388
// Check dust limit again
2369-
if change_value_decreased_with_fee > self.context.holder_dust_limit_satoshis {
2389+
if change_value_decreased_with_fee > self.context().holder_dust_limit_satoshis {
23702390
change_output.value = Amount::from_sat(change_value_decreased_with_fee);
23712391
funding_outputs.push(OutputOwned::Single(change_output));
23722392
}
@@ -2375,71 +2395,74 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
23752395
let constructor_args = InteractiveTxConstructorArgs {
23762396
entropy_source,
23772397
holder_node_id,
2378-
counterparty_node_id: self.context.counterparty_node_id,
2379-
channel_id: self.context.channel_id(),
2380-
feerate_sat_per_kw: self.dual_funding_context.funding_feerate_sat_per_1000_weight,
2381-
is_initiator: self.funding.is_outbound(),
2382-
funding_tx_locktime: self.dual_funding_context.funding_tx_locktime,
2398+
counterparty_node_id: self.context().counterparty_node_id,
2399+
channel_id: self.context().channel_id(),
2400+
feerate_sat_per_kw: dual_funding_context.funding_feerate_sat_per_1000_weight,
2401+
is_initiator: pending_funding.is_outbound(),
2402+
funding_tx_locktime: dual_funding_context.funding_tx_locktime,
23832403
inputs_to_contribute: funding_inputs,
23842404
outputs_to_contribute: funding_outputs,
23852405
expected_remote_shared_funding_output,
23862406
};
23872407
let mut tx_constructor = InteractiveTxConstructor::new(constructor_args)?;
23882408
let msg = tx_constructor.take_initiator_first_message();
23892409

2390-
self.interactive_tx_constructor = Some(tx_constructor);
2410+
*(
2411+
self.interactive_tx_constructor_mut().map_err(|e| AbortReason::InternalError(e))?
2412+
) = Some(tx_constructor);
23912413

23922414
Ok(msg)
23932415
}
23942416

2395-
pub fn tx_add_input(&mut self, msg: &msgs::TxAddInput) -> InteractiveTxMessageSendResult {
2396-
InteractiveTxMessageSendResult(match &mut self.interactive_tx_constructor {
2397-
Some(ref mut tx_constructor) => tx_constructor.handle_tx_add_input(msg).map_err(
2398-
|reason| reason.into_tx_abort_msg(self.context.channel_id())),
2399-
None => Err(msgs::TxAbort {
2400-
channel_id: self.context.channel_id(),
2417+
fn tx_add_input(&mut self, msg: &msgs::TxAddInput) -> InteractiveTxMessageSendResult {
2418+
InteractiveTxMessageSendResult(match self.interactive_tx_constructor_mut() {
2419+
Ok(Some(ref mut tx_constructor)) => tx_constructor.handle_tx_add_input(msg).map_err(
2420+
|reason| reason.into_tx_abort_msg(self.context().channel_id())),
2421+
Ok(None) | Err(_) => Err(msgs::TxAbort {
2422+
channel_id: self.context().channel_id(),
24012423
data: b"No interactive transaction negotiation in progress".to_vec()
24022424
}),
24032425
})
24042426
}
24052427

2406-
pub fn tx_add_output(&mut self, msg: &msgs::TxAddOutput)-> InteractiveTxMessageSendResult {
2407-
InteractiveTxMessageSendResult(match &mut self.interactive_tx_constructor {
2408-
Some(ref mut tx_constructor) => tx_constructor.handle_tx_add_output(msg).map_err(
2409-
|reason| reason.into_tx_abort_msg(self.context.channel_id())),
2410-
None => Err(msgs::TxAbort {
2411-
channel_id: self.context.channel_id(),
2428+
fn tx_add_output(&mut self, msg: &msgs::TxAddOutput)-> InteractiveTxMessageSendResult {
2429+
InteractiveTxMessageSendResult(match self.interactive_tx_constructor_mut() {
2430+
Ok(Some(ref mut tx_constructor)) => tx_constructor.handle_tx_add_output(msg).map_err(
2431+
|reason| reason.into_tx_abort_msg(self.context().channel_id())),
2432+
Ok(None) | Err(_) => Err(msgs::TxAbort {
2433+
channel_id: self.context().channel_id(),
24122434
data: b"No interactive transaction negotiation in progress".to_vec()
24132435
}),
24142436
})
24152437
}
24162438

2417-
pub fn tx_remove_input(&mut self, msg: &msgs::TxRemoveInput)-> InteractiveTxMessageSendResult {
2418-
InteractiveTxMessageSendResult(match &mut self.interactive_tx_constructor {
2419-
Some(ref mut tx_constructor) => tx_constructor.handle_tx_remove_input(msg).map_err(
2420-
|reason| reason.into_tx_abort_msg(self.context.channel_id())),
2421-
None => Err(msgs::TxAbort {
2422-
channel_id: self.context.channel_id(),
2439+
fn tx_remove_input(&mut self, msg: &msgs::TxRemoveInput)-> InteractiveTxMessageSendResult {
2440+
InteractiveTxMessageSendResult(match self.interactive_tx_constructor_mut() {
2441+
Ok(Some(ref mut tx_constructor)) => tx_constructor.handle_tx_remove_input(msg).map_err(
2442+
|reason| reason.into_tx_abort_msg(self.context().channel_id())),
2443+
Ok(None) | Err(_) => Err(msgs::TxAbort {
2444+
channel_id: self.context().channel_id(),
24232445
data: b"No interactive transaction negotiation in progress".to_vec()
24242446
}),
24252447
})
24262448
}
24272449

2428-
pub fn tx_remove_output(&mut self, msg: &msgs::TxRemoveOutput)-> InteractiveTxMessageSendResult {
2429-
InteractiveTxMessageSendResult(match &mut self.interactive_tx_constructor {
2430-
Some(ref mut tx_constructor) => tx_constructor.handle_tx_remove_output(msg).map_err(
2431-
|reason| reason.into_tx_abort_msg(self.context.channel_id())),
2432-
None => Err(msgs::TxAbort {
2433-
channel_id: self.context.channel_id(),
2450+
fn tx_remove_output(&mut self, msg: &msgs::TxRemoveOutput)-> InteractiveTxMessageSendResult {
2451+
InteractiveTxMessageSendResult(match self.interactive_tx_constructor_mut() {
2452+
Ok(Some(ref mut tx_constructor)) => tx_constructor.handle_tx_remove_output(msg).map_err(
2453+
|reason| reason.into_tx_abort_msg(self.context().channel_id())),
2454+
Ok(None) | Err(_) => Err(msgs::TxAbort {
2455+
channel_id: self.context().channel_id(),
24342456
data: b"No interactive transaction negotiation in progress".to_vec()
24352457
}),
24362458
})
24372459
}
24382460

2439-
pub fn tx_complete(&mut self, msg: &msgs::TxComplete) -> HandleTxCompleteResult {
2440-
let tx_constructor = match &mut self.interactive_tx_constructor {
2441-
Some(ref mut tx_constructor) => tx_constructor,
2442-
None => {
2461+
fn tx_complete(&mut self, msg: &msgs::TxComplete) -> HandleTxCompleteResult {
2462+
let interactive_tx_constructor = self.interactive_tx_constructor_mut();
2463+
let tx_constructor = match interactive_tx_constructor {
2464+
Ok(Some(tx_constructor)) => tx_constructor,
2465+
Ok(None) | Err(_) => {
24432466
let tx_abort = msgs::TxAbort {
24442467
channel_id: msg.channel_id,
24452468
data: b"No interactive transaction negotiation in progress".to_vec(),
@@ -2456,25 +2479,31 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
24562479
};
24572480

24582481
if let HandleTxCompleteValue::SendTxComplete(_, ref signing_session) = tx_complete {
2459-
self.context.next_funding_txid = Some(signing_session.unsigned_tx.compute_txid());
2482+
self.context_mut().next_funding_txid = Some(signing_session.unsigned_tx.compute_txid());
24602483
};
24612484

24622485
HandleTxCompleteResult(Ok(tx_complete))
24632486
}
24642487

2465-
pub fn funding_tx_constructed<L: Deref>(
2488+
fn funding_tx_constructed<L: Deref>(
24662489
&mut self, mut signing_session: InteractiveTxSigningSession, logger: &L
24672490
) -> Result<(msgs::CommitmentSigned, Option<Event>), ChannelError>
24682491
where
24692492
L::Target: Logger
24702493
{
2471-
let our_funding_satoshis = self.dual_funding_context.our_funding_satoshis;
2472-
let transaction_number = self.unfunded_context.transaction_number();
2494+
let our_funding_satoshis = self.dual_funding_context()
2495+
.map_err(|e| ChannelError::close(e.to_owned()))?
2496+
.our_funding_satoshis;
2497+
let transaction_number = self.unfunded_context()
2498+
.map_err(|e| ChannelError::close(e.to_owned()))?
2499+
.transaction_number();
2500+
let pending_funding = self.pending_funding()
2501+
.map_err(|e| ChannelError::close(e.to_owned()))?;
24732502

24742503
let mut output_index = None;
2475-
let expected_spk = self.funding.get_funding_redeemscript().to_p2wsh();
2504+
let expected_spk = pending_funding.get_funding_redeemscript().to_p2wsh();
24762505
for (idx, outp) in signing_session.unsigned_tx.outputs().enumerate() {
2477-
if outp.script_pubkey() == &expected_spk && outp.value() == self.funding.get_value_satoshis() {
2506+
if outp.script_pubkey() == &expected_spk && outp.value() == pending_funding.get_value_satoshis() {
24782507
if output_index.is_some() {
24792508
return Err(ChannelError::Close(
24802509
(
@@ -2494,24 +2523,32 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
24942523
ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) },
24952524
)));
24962525
};
2497-
self.funding.channel_transaction_parameters.funding_outpoint = Some(outpoint);
2498-
2499-
self.context.assert_no_commitment_advancement(transaction_number, "initial commitment_signed");
2500-
let commitment_signed = self.context.get_initial_commitment_signed(&self.funding, logger);
2526+
self.pending_funding_mut()
2527+
.map_err(|e| ChannelError::close(e.to_owned()))?
2528+
.channel_transaction_parameters.funding_outpoint = Some(outpoint);
2529+
2530+
self.context().assert_no_commitment_advancement(transaction_number, "initial commitment_signed");
2531+
let (funding, context_mut) = self.pending_funding_and_context_mut()
2532+
.map_err(|e| ChannelError::close(e.to_owned()))?;
2533+
let commitment_signed = context_mut.get_initial_commitment_signed(&funding, logger);
25012534
let commitment_signed = match commitment_signed {
25022535
Ok(commitment_signed) => {
2503-
self.funding.funding_transaction = Some(signing_session.unsigned_tx.build_unsigned_tx());
2536+
self.pending_funding_mut()
2537+
.map_err(|e| ChannelError::close(e.to_owned()))?
2538+
.funding_transaction = Some(signing_session.unsigned_tx.build_unsigned_tx());
25042539
commitment_signed
25052540
},
25062541
Err(err) => {
2507-
self.funding.channel_transaction_parameters.funding_outpoint = None;
2542+
self.pending_funding_mut()
2543+
.map_err(|e| ChannelError::close(e.to_owned()))?
2544+
.channel_transaction_parameters.funding_outpoint = None;
25082545
return Err(ChannelError::Close((err.to_string(), ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) })));
25092546
},
25102547
};
25112548

25122549
let funding_ready_for_sig_event = if signing_session.local_inputs_count() == 0 {
25132550
debug_assert_eq!(our_funding_satoshis, 0);
2514-
if signing_session.provide_holder_witnesses(self.context.channel_id, Vec::new()).is_err() {
2551+
if signing_session.provide_holder_witnesses(self.context().channel_id, Vec::new()).is_err() {
25152552
debug_assert!(
25162553
false,
25172554
"Zero inputs were provided & zero witnesses were provided, but a count mismatch was somehow found",
@@ -2547,16 +2584,81 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
25472584
)));
25482585
};
25492586

2550-
self.context.channel_state = ChannelState::FundingNegotiated;
2587+
self.context_mut().channel_state = ChannelState::FundingNegotiated;
25512588

25522589
// Clear the interactive transaction constructor
2553-
self.interactive_tx_constructor.take();
2554-
self.interactive_tx_signing_session = Some(signing_session);
2590+
*(
2591+
self.interactive_tx_constructor_mut()
2592+
.map_err(|e| ChannelError::close(e.to_owned()))?
2593+
) = None;
2594+
*(
2595+
self.interactive_tx_signing_session_mut()
2596+
.map_err(|e| ChannelError::close(e.to_owned()))?
2597+
) = Some(signing_session);
25552598

25562599
Ok((commitment_signed, funding_ready_for_sig_event))
25572600
}
25582601
}
25592602

2603+
impl<SP: Deref> ChannelContextProvider<SP> for PendingV2Channel<SP> where SP::Target: SignerProvider {
2604+
#[inline]
2605+
fn context(&self) -> &ChannelContext<SP> {
2606+
&self.context
2607+
}
2608+
2609+
#[inline]
2610+
fn context_mut(&mut self) -> &mut ChannelContext<SP> {
2611+
&mut self.context
2612+
}
2613+
}
2614+
2615+
impl<SP: Deref> FundingTxConstructorV2<SP> for PendingV2Channel<SP> where SP::Target: SignerProvider {
2616+
#[inline]
2617+
fn pending_funding(&self) -> Result<&FundingScope, &'static str> {
2618+
Ok(&self.funding)
2619+
}
2620+
2621+
#[inline]
2622+
fn pending_funding_mut(&mut self) -> Result<&mut FundingScope, &'static str> {
2623+
Ok(&mut self.funding)
2624+
}
2625+
2626+
#[inline]
2627+
fn pending_funding_and_context_mut(&mut self) -> Result<(&FundingScope, &mut ChannelContext<SP>), &'static str> {
2628+
Ok((&self.funding, &mut self.context))
2629+
}
2630+
2631+
#[inline]
2632+
fn dual_funding_context(&self) -> Result<&DualFundingChannelContext, &'static str> {
2633+
Ok(&self.dual_funding_context)
2634+
}
2635+
2636+
fn swap_out_dual_funding_context_inputs(&mut self, funding_inputs: &mut Vec<(TxIn, TransactionU16LenLimited)>) -> Result<(), &'static str> {
2637+
mem::swap(&mut self.dual_funding_context.our_funding_inputs, funding_inputs);
2638+
Ok(())
2639+
}
2640+
2641+
#[inline]
2642+
fn unfunded_context(&self) -> Result<&UnfundedChannelContext, &'static str> {
2643+
Ok(&self.unfunded_context)
2644+
}
2645+
2646+
#[inline]
2647+
fn interactive_tx_constructor(&self) -> Result<Option<&InteractiveTxConstructor>, &'static str> {
2648+
Ok(self.interactive_tx_constructor.as_ref())
2649+
}
2650+
2651+
#[inline]
2652+
fn interactive_tx_constructor_mut(&mut self) -> Result<&mut Option<InteractiveTxConstructor>, &'static str> {
2653+
Ok(&mut self.interactive_tx_constructor)
2654+
}
2655+
2656+
#[inline]
2657+
fn interactive_tx_signing_session_mut(&mut self) -> Result<&mut Option<InteractiveTxSigningSession>, &'static str> {
2658+
Ok(&mut self.interactive_tx_signing_session)
2659+
}
2660+
}
2661+
25602662
impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
25612663
fn new_for_inbound_channel<'a, ES: Deref, F: Deref, L: Deref>(
25622664
fee_estimator: &'a LowerBoundedFeeEstimator<F>,

lightning/src/ln/channelmanager.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ use crate::ln::inbound_payment;
5151
use crate::ln::types::ChannelId;
5252
use crate::types::payment::{PaymentHash, PaymentPreimage, PaymentSecret};
5353
use crate::ln::channel::{self, Channel, ChannelError, ChannelUpdateStatus, FundedChannel, ShutdownResult, UpdateFulfillCommitFetch, OutboundV1Channel, ReconnectionMsg, InboundV1Channel, WithChannelContext};
54-
use crate::ln::channel::PendingV2Channel;
54+
use crate::ln::channel::{FundingTxConstructorV2, PendingV2Channel};
5555
use crate::ln::channel_state::ChannelDetails;
5656
use crate::types::features::{Bolt12InvoiceFeatures, ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures};
5757
#[cfg(any(feature = "_test_utils", test))]

0 commit comments

Comments
 (0)