@@ -2012,7 +2012,6 @@ pub(super) struct InteractiveTxConstructorArgs<'a, ES: EntropySource> {
20122012 pub counterparty_node_id : PublicKey ,
20132013 pub channel_id : ChannelId ,
20142014 pub feerate_sat_per_kw : u32 ,
2015- pub is_initiator : bool ,
20162015 pub funding_tx_locktime : AbsoluteLockTime ,
20172016 pub inputs_to_contribute : Vec < FundingTxInput > ,
20182017 pub shared_funding_input : Option < SharedOwnedInput > ,
@@ -2023,18 +2022,15 @@ pub(super) struct InteractiveTxConstructorArgs<'a, ES: EntropySource> {
20232022impl InteractiveTxConstructor {
20242023 /// Instantiates a new `InteractiveTxConstructor`.
20252024 ///
2026- /// If the holder is the initiator, they need to send the first message which is a `TxAddInput`
2027- /// message.
2028- pub fn new < ES : EntropySource > (
2029- args : InteractiveTxConstructorArgs < ES > ,
2030- ) -> Result < Self , NegotiationError > {
2025+ /// Use [`Self::new_for_outbound`] or [`Self::new_for_inbound`] instead to also prepare the
2026+ /// first message for the initiator.
2027+ fn new < ES : EntropySource > ( args : InteractiveTxConstructorArgs < ES > , is_initiator : bool ) -> Self {
20312028 let InteractiveTxConstructorArgs {
20322029 entropy_source,
20332030 holder_node_id,
20342031 counterparty_node_id,
20352032 channel_id,
20362033 feerate_sat_per_kw,
2037- is_initiator,
20382034 funding_tx_locktime,
20392035 inputs_to_contribute,
20402036 shared_funding_input,
@@ -2104,7 +2100,7 @@ impl InteractiveTxConstructor {
21042100 let next_input_index = ( !inputs_to_contribute. is_empty ( ) ) . then_some ( 0 ) ;
21052101 let next_output_index = ( !outputs_to_contribute. is_empty ( ) ) . then_some ( 0 ) ;
21062102
2107- let mut constructor = Self {
2103+ Self {
21082104 state_machine,
21092105 is_initiator,
21102106 initiator_first_message : None ,
@@ -2113,19 +2109,32 @@ impl InteractiveTxConstructor {
21132109 outputs_to_contribute,
21142110 next_input_index,
21152111 next_output_index,
2116- } ;
2117- // We'll store the first message for the initiator.
2118- if is_initiator {
2119- match constructor. maybe_send_message ( ) {
2120- Ok ( message) => {
2121- constructor. initiator_first_message = Some ( message) ;
2122- } ,
2123- Err ( reason) => {
2124- return Err ( constructor. into_negotiation_error ( reason) ) ;
2125- } ,
2126- }
21272112 }
2128- Ok ( constructor)
2113+ }
2114+
2115+ /// Instantiates a new `InteractiveTxConstructor` for the initiator (outbound splice).
2116+ ///
2117+ /// The initiator always has the shared funding output added internally, so preparing the
2118+ /// first message should never fail. Debug asserts verify this invariant.
2119+ pub fn new_for_outbound < ES : EntropySource > ( args : InteractiveTxConstructorArgs < ES > ) -> Self {
2120+ let mut constructor = Self :: new ( args, true ) ;
2121+ match constructor. maybe_send_message ( ) {
2122+ Ok ( message) => constructor. initiator_first_message = Some ( message) ,
2123+ Err ( reason) => {
2124+ debug_assert ! (
2125+ false ,
2126+ "Outbound constructor should always have inputs: {:?}" ,
2127+ reason
2128+ ) ;
2129+ } ,
2130+ }
2131+ constructor
2132+ }
2133+
2134+ /// Instantiates a new `InteractiveTxConstructor` for the non-initiator (inbound splice or
2135+ /// dual-funded channel acceptor).
2136+ pub fn new_for_inbound < ES : EntropySource > ( args : InteractiveTxConstructorArgs < ES > ) -> Self {
2137+ Self :: new ( args, false )
21292138 }
21302139
21312140 fn into_negotiation_error ( self , reason : AbortReason ) -> NegotiationError {
@@ -2428,84 +2437,62 @@ mod tests {
24282437 & SecretKey :: from_slice ( & [ 43 ; 32 ] ) . unwrap ( ) ,
24292438 ) ;
24302439
2431- let mut constructor_a = match InteractiveTxConstructor :: new ( InteractiveTxConstructorArgs {
2432- entropy_source,
2433- channel_id,
2434- feerate_sat_per_kw : TEST_FEERATE_SATS_PER_KW ,
2435- holder_node_id,
2436- counterparty_node_id,
2437- is_initiator : true ,
2438- funding_tx_locktime,
2439- inputs_to_contribute : session. inputs_a ,
2440- shared_funding_input : session. a_shared_input . map ( |( op, prev_output, lo) | {
2441- SharedOwnedInput :: new (
2442- TxIn {
2443- previous_output : op,
2444- sequence : Sequence :: ENABLE_RBF_NO_LOCKTIME ,
2445- ..Default :: default ( )
2446- } ,
2447- prev_output,
2448- lo,
2449- true , // holder_sig_first
2450- generate_funding_script_pubkey ( ) , // witness_script for test
2451- )
2452- } ) ,
2453- shared_funding_output : SharedOwnedOutput :: new (
2454- session. shared_output_a . 0 ,
2455- session. shared_output_a . 1 ,
2456- ) ,
2457- outputs_to_contribute : session. outputs_a ,
2458- } ) {
2459- Ok ( r) => Some ( r) ,
2460- Err ( e) => {
2461- assert_eq ! (
2462- Some ( ( e. reason, ErrorCulprit :: NodeA ) ) ,
2463- session. expect_error,
2464- "Test: {}" ,
2465- session. description
2466- ) ;
2467- return ;
2468- } ,
2469- } ;
2470- let mut constructor_b = match InteractiveTxConstructor :: new ( InteractiveTxConstructorArgs {
2471- entropy_source,
2472- holder_node_id,
2473- counterparty_node_id,
2474- channel_id,
2475- feerate_sat_per_kw : TEST_FEERATE_SATS_PER_KW ,
2476- is_initiator : false ,
2477- funding_tx_locktime,
2478- inputs_to_contribute : session. inputs_b ,
2479- shared_funding_input : session. b_shared_input . map ( |( op, prev_output, lo) | {
2480- SharedOwnedInput :: new (
2481- TxIn {
2482- previous_output : op,
2483- sequence : Sequence :: ENABLE_RBF_NO_LOCKTIME ,
2484- ..Default :: default ( )
2485- } ,
2486- prev_output,
2487- lo,
2488- false , // holder_sig_first
2489- generate_funding_script_pubkey ( ) , // witness_script for test
2490- )
2491- } ) ,
2492- shared_funding_output : SharedOwnedOutput :: new (
2493- session. shared_output_b . 0 ,
2494- session. shared_output_b . 1 ,
2495- ) ,
2496- outputs_to_contribute : session. outputs_b ,
2497- } ) {
2498- Ok ( r) => Some ( r) ,
2499- Err ( e) => {
2500- assert_eq ! (
2501- Some ( ( e. reason, ErrorCulprit :: NodeB ) ) ,
2502- session. expect_error,
2503- "Test: {}" ,
2504- session. description
2505- ) ;
2506- return ;
2507- } ,
2508- } ;
2440+ let mut constructor_a =
2441+ Some ( InteractiveTxConstructor :: new_for_outbound ( InteractiveTxConstructorArgs {
2442+ entropy_source,
2443+ channel_id,
2444+ feerate_sat_per_kw : TEST_FEERATE_SATS_PER_KW ,
2445+ holder_node_id,
2446+ counterparty_node_id,
2447+ funding_tx_locktime,
2448+ inputs_to_contribute : session. inputs_a ,
2449+ shared_funding_input : session. a_shared_input . map ( |( op, prev_output, lo) | {
2450+ SharedOwnedInput :: new (
2451+ TxIn {
2452+ previous_output : op,
2453+ sequence : Sequence :: ENABLE_RBF_NO_LOCKTIME ,
2454+ ..Default :: default ( )
2455+ } ,
2456+ prev_output,
2457+ lo,
2458+ true , // holder_sig_first
2459+ generate_funding_script_pubkey ( ) , // witness_script for test
2460+ )
2461+ } ) ,
2462+ shared_funding_output : SharedOwnedOutput :: new (
2463+ session. shared_output_a . 0 ,
2464+ session. shared_output_a . 1 ,
2465+ ) ,
2466+ outputs_to_contribute : session. outputs_a ,
2467+ } ) ) ;
2468+ let mut constructor_b =
2469+ Some ( InteractiveTxConstructor :: new_for_inbound ( InteractiveTxConstructorArgs {
2470+ entropy_source,
2471+ holder_node_id,
2472+ counterparty_node_id,
2473+ channel_id,
2474+ feerate_sat_per_kw : TEST_FEERATE_SATS_PER_KW ,
2475+ funding_tx_locktime,
2476+ inputs_to_contribute : session. inputs_b ,
2477+ shared_funding_input : session. b_shared_input . map ( |( op, prev_output, lo) | {
2478+ SharedOwnedInput :: new (
2479+ TxIn {
2480+ previous_output : op,
2481+ sequence : Sequence :: ENABLE_RBF_NO_LOCKTIME ,
2482+ ..Default :: default ( )
2483+ } ,
2484+ prev_output,
2485+ lo,
2486+ false , // holder_sig_first
2487+ generate_funding_script_pubkey ( ) , // witness_script for test
2488+ )
2489+ } ) ,
2490+ shared_funding_output : SharedOwnedOutput :: new (
2491+ session. shared_output_b . 0 ,
2492+ session. shared_output_b . 1 ,
2493+ ) ,
2494+ outputs_to_contribute : session. outputs_b ,
2495+ } ) ) ;
25092496
25102497 let handle_message_send =
25112498 |msg : InteractiveTxMessageSend , for_constructor : & mut InteractiveTxConstructor | {
0 commit comments