@@ -2302,7 +2302,21 @@ impl<SP: Deref> InitialRemoteCommitmentReceiver<SP> for FundedChannel<SP> where
2302
2302
}
2303
2303
}
2304
2304
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
+
2306
2320
/// Prepare and start interactive transaction negotiation.
2307
2321
/// `change_destination_opt` - Optional destination for optional change; if None,
2308
2322
/// default destination address is used.
@@ -2314,11 +2328,12 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
2314
2328
) -> Result<Option<InteractiveTxMessageSend>, AbortReason>
2315
2329
where ES::Target: EntropySource
2316
2330
{
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());
2319
2333
2320
2334
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))?;
2322
2337
2323
2338
// TODO(splicing): Add prev funding tx as input, must be provided as a parameter
2324
2339
@@ -2328,15 +2343,20 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
2328
2343
let mut funding_outputs = Vec::new();
2329
2344
let mut expected_remote_shared_funding_output = None;
2330
2345
2346
+ let pending_funding = self.pending_funding()
2347
+ .map_err(|e| AbortReason::InternalError(e))?;
2348
+
2331
2349
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(),
2334
2352
};
2335
2353
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() {
2337
2357
funding_outputs.push(
2338
2358
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,
2340
2360
))
2341
2361
);
2342
2362
} else {
@@ -2348,13 +2368,13 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
2348
2368
let change_script = if let Some(script) = change_destination_opt {
2349
2369
script
2350
2370
} else {
2351
- signer_provider.get_destination_script(self.context.channel_keys_id)
2371
+ signer_provider.get_destination_script(self.context() .channel_keys_id)
2352
2372
.map_err(|_err| AbortReason::InternalError("Error getting destination script"))?
2353
2373
};
2354
2374
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,
2356
2376
&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,
2358
2378
change_script.minimal_non_dust().to_sat(),
2359
2379
)?;
2360
2380
if let Some(change_value) = change_value_opt {
@@ -2363,10 +2383,10 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
2363
2383
script_pubkey: change_script,
2364
2384
};
2365
2385
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);
2367
2387
let change_value_decreased_with_fee = change_value.saturating_sub(change_output_fee);
2368
2388
// 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 {
2370
2390
change_output.value = Amount::from_sat(change_value_decreased_with_fee);
2371
2391
funding_outputs.push(OutputOwned::Single(change_output));
2372
2392
}
@@ -2375,71 +2395,74 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
2375
2395
let constructor_args = InteractiveTxConstructorArgs {
2376
2396
entropy_source,
2377
2397
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,
2383
2403
inputs_to_contribute: funding_inputs,
2384
2404
outputs_to_contribute: funding_outputs,
2385
2405
expected_remote_shared_funding_output,
2386
2406
};
2387
2407
let mut tx_constructor = InteractiveTxConstructor::new(constructor_args)?;
2388
2408
let msg = tx_constructor.take_initiator_first_message();
2389
2409
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);
2391
2413
2392
2414
Ok(msg)
2393
2415
}
2394
2416
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(),
2401
2423
data: b"No interactive transaction negotiation in progress".to_vec()
2402
2424
}),
2403
2425
})
2404
2426
}
2405
2427
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(),
2412
2434
data: b"No interactive transaction negotiation in progress".to_vec()
2413
2435
}),
2414
2436
})
2415
2437
}
2416
2438
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(),
2423
2445
data: b"No interactive transaction negotiation in progress".to_vec()
2424
2446
}),
2425
2447
})
2426
2448
}
2427
2449
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(),
2434
2456
data: b"No interactive transaction negotiation in progress".to_vec()
2435
2457
}),
2436
2458
})
2437
2459
}
2438
2460
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(_) => {
2443
2466
let tx_abort = msgs::TxAbort {
2444
2467
channel_id: msg.channel_id,
2445
2468
data: b"No interactive transaction negotiation in progress".to_vec(),
@@ -2456,25 +2479,31 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
2456
2479
};
2457
2480
2458
2481
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());
2460
2483
};
2461
2484
2462
2485
HandleTxCompleteResult(Ok(tx_complete))
2463
2486
}
2464
2487
2465
- pub fn funding_tx_constructed<L: Deref>(
2488
+ fn funding_tx_constructed<L: Deref>(
2466
2489
&mut self, mut signing_session: InteractiveTxSigningSession, logger: &L
2467
2490
) -> Result<(msgs::CommitmentSigned, Option<Event>), ChannelError>
2468
2491
where
2469
2492
L::Target: Logger
2470
2493
{
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()))?;
2473
2502
2474
2503
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();
2476
2505
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() {
2478
2507
if output_index.is_some() {
2479
2508
return Err(ChannelError::Close(
2480
2509
(
@@ -2494,24 +2523,32 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
2494
2523
ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) },
2495
2524
)));
2496
2525
};
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);
2501
2534
let commitment_signed = match commitment_signed {
2502
2535
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());
2504
2539
commitment_signed
2505
2540
},
2506
2541
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;
2508
2545
return Err(ChannelError::Close((err.to_string(), ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) })));
2509
2546
},
2510
2547
};
2511
2548
2512
2549
let funding_ready_for_sig_event = if signing_session.local_inputs_count() == 0 {
2513
2550
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() {
2515
2552
debug_assert!(
2516
2553
false,
2517
2554
"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 {
2547
2584
)));
2548
2585
};
2549
2586
2550
- self.context .channel_state = ChannelState::FundingNegotiated;
2587
+ self.context_mut() .channel_state = ChannelState::FundingNegotiated;
2551
2588
2552
2589
// 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);
2555
2598
2556
2599
Ok((commitment_signed, funding_ready_for_sig_event))
2557
2600
}
2558
2601
}
2559
2602
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
+
2560
2662
impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
2561
2663
fn new_for_inbound_channel<'a, ES: Deref, F: Deref, L: Deref>(
2562
2664
fee_estimator: &'a LowerBoundedFeeEstimator<F>,
0 commit comments