@@ -15,18 +15,21 @@ use bitcoin::amount::Amount;
1515use bitcoin:: consensus:: Encodable ;
1616use bitcoin:: constants:: WITNESS_SCALE_FACTOR ;
1717use bitcoin:: policy:: MAX_STANDARD_TX_WEIGHT ;
18+ use bitcoin:: secp256k1:: PublicKey ;
1819use bitcoin:: transaction:: Version ;
1920use bitcoin:: { OutPoint , ScriptBuf , Sequence , Transaction , TxIn , TxOut , Weight } ;
2021
2122use crate :: chain:: chaininterface:: fee_for_weight;
2223use crate :: events:: bump_transaction:: { BASE_INPUT_WEIGHT , EMPTY_SCRIPT_SIG_WEIGHT } ;
24+ use crate :: events:: MessageSendEvent ;
2325use crate :: ln:: channel:: TOTAL_BITCOIN_SUPPLY_SATOSHIS ;
2426use crate :: ln:: msgs;
2527use crate :: ln:: msgs:: SerialId ;
2628use crate :: ln:: types:: ChannelId ;
2729use crate :: sign:: { EntropySource , P2TR_KEY_PATH_WITNESS_WEIGHT , P2WPKH_WITNESS_WEIGHT } ;
2830use crate :: util:: ser:: TransactionU16LenLimited ;
2931
32+ use core:: fmt:: Display ;
3033use core:: ops:: Deref ;
3134
3235/// The number of received `tx_add_input` messages during a negotiation at which point the
@@ -43,7 +46,7 @@ const MAX_INPUTS_OUTPUTS_COUNT: usize = 252;
4346
4447/// The total weight of the common fields whose fee is paid by the initiator of the interactive
4548/// transaction construction protocol.
46- const TX_COMMON_FIELDS_WEIGHT : u64 = ( 4 /* version */ + 4 /* locktime */ + 1 /* input count */ +
49+ pub ( crate ) const TX_COMMON_FIELDS_WEIGHT : u64 = ( 4 /* version */ + 4 /* locktime */ + 1 /* input count */ +
4750 1 /* output count */ ) * WITNESS_SCALE_FACTOR as u64 + 2 /* segwit marker + flag */ ;
4851
4952// BOLT 3 - Lower bounds for input weights
@@ -108,6 +111,47 @@ pub(crate) enum AbortReason {
108111 InvalidLowFundingOutputValue ,
109112}
110113
114+ impl AbortReason {
115+ pub fn into_tx_abort_msg ( self , channel_id : ChannelId ) -> msgs:: TxAbort {
116+ msgs:: TxAbort { channel_id, data : self . to_string ( ) . into_bytes ( ) }
117+ }
118+ }
119+
120+ impl Display for AbortReason {
121+ fn fmt ( & self , f : & mut core:: fmt:: Formatter < ' _ > ) -> core:: fmt:: Result {
122+ f. write_str ( match self {
123+ AbortReason :: InvalidStateTransition => "State transition was invalid" ,
124+ AbortReason :: UnexpectedCounterpartyMessage => "Unexpected message" ,
125+ AbortReason :: ReceivedTooManyTxAddInputs => "Too many `tx_add_input`s received" ,
126+ AbortReason :: ReceivedTooManyTxAddOutputs => "Too many `tx_add_output`s received" ,
127+ AbortReason :: IncorrectInputSequenceValue => {
128+ "Input has a sequence value greater than 0xFFFFFFFD"
129+ } ,
130+ AbortReason :: IncorrectSerialIdParity => "Parity for `serial_id` was incorrect" ,
131+ AbortReason :: SerialIdUnknown => "The `serial_id` is unknown" ,
132+ AbortReason :: DuplicateSerialId => "The `serial_id` already exists" ,
133+ AbortReason :: PrevTxOutInvalid => "Invalid previous transaction output" ,
134+ AbortReason :: ExceededMaximumSatsAllowed => {
135+ "Output amount exceeded total bitcoin supply"
136+ } ,
137+ AbortReason :: ExceededNumberOfInputsOrOutputs => "Too many inputs or outputs" ,
138+ AbortReason :: TransactionTooLarge => "Transaction weight is too large" ,
139+ AbortReason :: BelowDustLimit => "Output amount is below the dust limit" ,
140+ AbortReason :: InvalidOutputScript => "The output script is non-standard" ,
141+ AbortReason :: InsufficientFees => "Insufficient fees paid" ,
142+ AbortReason :: OutputsValueExceedsInputsValue => {
143+ "Total value of outputs exceeds total value of inputs"
144+ } ,
145+ AbortReason :: InvalidTx => "The transaction is invalid" ,
146+ AbortReason :: MissingFundingOutput => "No shared funding output found" ,
147+ AbortReason :: DuplicateFundingOutput => "More than one funding output found" ,
148+ AbortReason :: InvalidLowFundingOutputValue => {
149+ "Local part of funding output value is greater than the funding output value"
150+ } ,
151+ } )
152+ }
153+ }
154+
111155#[ derive( Debug , Clone , PartialEq , Eq ) ]
112156pub ( crate ) struct ConstructedTransaction {
113157 holder_is_initiator : bool ,
@@ -1048,8 +1092,9 @@ impl InteractiveTxInput {
10481092 }
10491093}
10501094
1051- pub ( crate ) struct InteractiveTxConstructor {
1095+ pub ( super ) struct InteractiveTxConstructor {
10521096 state_machine : StateMachine ,
1097+ initiator_first_message : Option < InteractiveTxMessageSend > ,
10531098 channel_id : ChannelId ,
10541099 inputs_to_contribute : Vec < ( SerialId , TxIn , TransactionU16LenLimited ) > ,
10551100 outputs_to_contribute : Vec < ( SerialId , OutputOwned ) > ,
@@ -1062,6 +1107,39 @@ pub(crate) enum InteractiveTxMessageSend {
10621107 TxComplete ( msgs:: TxComplete ) ,
10631108}
10641109
1110+ impl InteractiveTxMessageSend {
1111+ pub fn into_msg_send_event ( self , counterparty_node_id : PublicKey ) -> MessageSendEvent {
1112+ match self {
1113+ InteractiveTxMessageSend :: TxAddInput ( msg) => {
1114+ MessageSendEvent :: SendTxAddInput { node_id : counterparty_node_id, msg }
1115+ } ,
1116+ InteractiveTxMessageSend :: TxAddOutput ( msg) => {
1117+ MessageSendEvent :: SendTxAddOutput { node_id : counterparty_node_id, msg }
1118+ } ,
1119+ InteractiveTxMessageSend :: TxComplete ( msg) => {
1120+ MessageSendEvent :: SendTxComplete { node_id : counterparty_node_id, msg }
1121+ } ,
1122+ }
1123+ }
1124+ }
1125+
1126+ pub ( super ) struct InteractiveTxMessageSendResult (
1127+ pub Result < InteractiveTxMessageSend , msgs:: TxAbort > ,
1128+ ) ;
1129+
1130+ impl InteractiveTxMessageSendResult {
1131+ pub fn into_msg_send_event ( self , counterparty_node_id : PublicKey ) -> MessageSendEvent {
1132+ match self . 0 {
1133+ Ok ( interactive_tx_msg_send) => {
1134+ interactive_tx_msg_send. into_msg_send_event ( counterparty_node_id)
1135+ } ,
1136+ Err ( tx_abort_msg) => {
1137+ MessageSendEvent :: SendTxAbort { node_id : counterparty_node_id, msg : tx_abort_msg }
1138+ } ,
1139+ }
1140+ }
1141+ }
1142+
10651143// This macro executes a state machine transition based on a provided action.
10661144macro_rules! do_state_transition {
10671145 ( $self: ident, $transition: ident, $msg: expr) => { {
@@ -1094,6 +1172,22 @@ pub(crate) enum HandleTxCompleteValue {
10941172 NegotiationComplete ( ConstructedTransaction ) ,
10951173}
10961174
1175+ pub ( super ) struct HandleTxCompleteResult ( pub Result < HandleTxCompleteValue , msgs:: TxAbort > ) ;
1176+
1177+ pub ( super ) struct InteractiveTxConstructorArgs < ' a , ES : Deref >
1178+ where
1179+ ES :: Target : EntropySource ,
1180+ {
1181+ pub entropy_source : & ' a ES ,
1182+ pub channel_id : ChannelId ,
1183+ pub feerate_sat_per_kw : u32 ,
1184+ pub is_initiator : bool ,
1185+ pub funding_tx_locktime : AbsoluteLockTime ,
1186+ pub inputs_to_contribute : Vec < ( TxIn , TransactionU16LenLimited ) > ,
1187+ pub outputs_to_contribute : Vec < OutputOwned > ,
1188+ pub expected_remote_shared_funding_output : Option < ( ScriptBuf , u64 ) > ,
1189+ }
1190+
10971191impl InteractiveTxConstructor {
10981192 /// Instantiates a new `InteractiveTxConstructor`.
10991193 ///
@@ -1103,20 +1197,24 @@ impl InteractiveTxConstructor {
11031197 /// and its (local) contribution from the shared output:
11041198 /// 0 when the whole value belongs to the remote node, or
11051199 /// positive if owned also by local.
1106- /// Note: The local value cannot be larger that the actual shared output.
1200+ /// Note: The local value cannot be larger than the actual shared output.
11071201 ///
1108- /// A tuple is returned containing the newly instantiate `InteractiveTxConstructor` and optionally
1109- /// an initial wrapped `Tx_` message which the holder needs to send to the counterparty.
1110- pub fn new < ES : Deref > (
1111- entropy_source : & ES , channel_id : ChannelId , feerate_sat_per_kw : u32 , is_initiator : bool ,
1112- funding_tx_locktime : AbsoluteLockTime ,
1113- inputs_to_contribute : Vec < ( TxIn , TransactionU16LenLimited ) > ,
1114- outputs_to_contribute : Vec < OutputOwned > ,
1115- expected_remote_shared_funding_output : Option < ( ScriptBuf , u64 ) > ,
1116- ) -> Result < ( Self , Option < InteractiveTxMessageSend > ) , AbortReason >
1202+ /// If the holder is the initiator, they need to send the first message which is a `TxAddInput`
1203+ /// message.
1204+ pub fn new < ES : Deref > ( args : InteractiveTxConstructorArgs < ES > ) -> Result < Self , AbortReason >
11171205 where
11181206 ES :: Target : EntropySource ,
11191207 {
1208+ let InteractiveTxConstructorArgs {
1209+ entropy_source,
1210+ channel_id,
1211+ feerate_sat_per_kw,
1212+ is_initiator,
1213+ funding_tx_locktime,
1214+ inputs_to_contribute,
1215+ outputs_to_contribute,
1216+ expected_remote_shared_funding_output,
1217+ } = args;
11201218 // Sanity check: There can be at most one shared output, local-added or remote-added
11211219 let mut expected_shared_funding_output: Option < ( ScriptBuf , u64 ) > = None ;
11221220 for output in & outputs_to_contribute {
@@ -1175,28 +1273,27 @@ impl InteractiveTxConstructor {
11751273 . collect ( ) ;
11761274 // In the same manner and for the same rationale as the inputs above, we'll shuffle the outputs.
11771275 outputs_to_contribute. sort_unstable_by_key ( |( serial_id, _) | * serial_id) ;
1178- let mut constructor =
1179- Self { state_machine, channel_id, inputs_to_contribute, outputs_to_contribute } ;
1180- let message_send = if is_initiator {
1181- match constructor. maybe_send_message ( ) {
1182- Ok ( msg_send) => Some ( msg_send) ,
1183- Err ( _) => {
1184- debug_assert ! (
1185- false ,
1186- "We should always be able to start our state machine successfully"
1187- ) ;
1188- None
1189- } ,
1190- }
1191- } else {
1192- None
1276+ let mut constructor = Self {
1277+ state_machine,
1278+ initiator_first_message : None ,
1279+ channel_id,
1280+ inputs_to_contribute,
1281+ outputs_to_contribute,
11931282 } ;
1194- Ok ( ( constructor, message_send) )
1283+ // We'll store the first message for the initiator.
1284+ if is_initiator {
1285+ constructor. initiator_first_message = Some ( constructor. maybe_send_message ( ) ?) ;
1286+ }
1287+ Ok ( constructor)
11951288 } else {
11961289 Err ( AbortReason :: MissingFundingOutput )
11971290 }
11981291 }
11991292
1293+ pub fn take_initiator_first_message ( & mut self ) -> Option < InteractiveTxMessageSend > {
1294+ self . initiator_first_message . take ( )
1295+ }
1296+
12001297 fn maybe_send_message ( & mut self ) -> Result < InteractiveTxMessageSend , AbortReason > {
12011298 // We first attempt to send inputs we want to add, then outputs. Once we are done sending
12021299 // them both, then we always send tx_complete.
@@ -1295,8 +1392,8 @@ mod tests {
12951392 use crate :: ln:: channel:: TOTAL_BITCOIN_SUPPLY_SATOSHIS ;
12961393 use crate :: ln:: interactivetxs:: {
12971394 generate_holder_serial_id, AbortReason , HandleTxCompleteValue , InteractiveTxConstructor ,
1298- InteractiveTxMessageSend , MAX_INPUTS_OUTPUTS_COUNT , MAX_RECEIVED_TX_ADD_INPUT_COUNT ,
1299- MAX_RECEIVED_TX_ADD_OUTPUT_COUNT ,
1395+ InteractiveTxConstructorArgs , InteractiveTxMessageSend , MAX_INPUTS_OUTPUTS_COUNT ,
1396+ MAX_RECEIVED_TX_ADD_INPUT_COUNT , MAX_RECEIVED_TX_ADD_OUTPUT_COUNT ,
13001397 } ;
13011398 use crate :: ln:: types:: ChannelId ;
13021399 use crate :: sign:: EntropySource ;
@@ -1395,7 +1492,7 @@ mod tests {
13951492 ES :: Target : EntropySource ,
13961493 {
13971494 let channel_id = ChannelId ( entropy_source. get_secure_random_bytes ( ) ) ;
1398- let tx_locktime = AbsoluteLockTime :: from_height ( 1337 ) . unwrap ( ) ;
1495+ let funding_tx_locktime = AbsoluteLockTime :: from_height ( 1337 ) . unwrap ( ) ;
13991496
14001497 // funding output sanity check
14011498 let shared_outputs_by_a: Vec < _ > =
@@ -1448,16 +1545,16 @@ mod tests {
14481545 }
14491546 }
14501547
1451- let ( mut constructor_a, first_message_a ) = match InteractiveTxConstructor :: new (
1548+ let mut constructor_a = match InteractiveTxConstructor :: new ( InteractiveTxConstructorArgs {
14521549 entropy_source,
14531550 channel_id,
1454- TEST_FEERATE_SATS_PER_KW ,
1455- true ,
1456- tx_locktime ,
1457- session. inputs_a ,
1458- session. outputs_a . to_vec ( ) ,
1459- session. a_expected_remote_shared_output ,
1460- ) {
1551+ feerate_sat_per_kw : TEST_FEERATE_SATS_PER_KW ,
1552+ is_initiator : true ,
1553+ funding_tx_locktime ,
1554+ inputs_to_contribute : session. inputs_a ,
1555+ outputs_to_contribute : session. outputs_a . to_vec ( ) ,
1556+ expected_remote_shared_funding_output : session. a_expected_remote_shared_output ,
1557+ } ) {
14611558 Ok ( r) => r,
14621559 Err ( abort_reason) => {
14631560 assert_eq ! (
@@ -1469,16 +1566,16 @@ mod tests {
14691566 return ;
14701567 } ,
14711568 } ;
1472- let ( mut constructor_b, first_message_b ) = match InteractiveTxConstructor :: new (
1569+ let mut constructor_b = match InteractiveTxConstructor :: new ( InteractiveTxConstructorArgs {
14731570 entropy_source,
14741571 channel_id,
1475- TEST_FEERATE_SATS_PER_KW ,
1476- false ,
1477- tx_locktime ,
1478- session. inputs_b ,
1479- session. outputs_b . to_vec ( ) ,
1480- session. b_expected_remote_shared_output ,
1481- ) {
1572+ feerate_sat_per_kw : TEST_FEERATE_SATS_PER_KW ,
1573+ is_initiator : false ,
1574+ funding_tx_locktime ,
1575+ inputs_to_contribute : session. inputs_b ,
1576+ outputs_to_contribute : session. outputs_b . to_vec ( ) ,
1577+ expected_remote_shared_funding_output : session. b_expected_remote_shared_output ,
1578+ } ) {
14821579 Ok ( r) => r,
14831580 Err ( abort_reason) => {
14841581 assert_eq ! (
@@ -1514,8 +1611,7 @@ mod tests {
15141611 }
15151612 } ;
15161613
1517- assert ! ( first_message_b. is_none( ) ) ;
1518- let mut message_send_a = first_message_a;
1614+ let mut message_send_a = constructor_a. take_initiator_first_message ( ) ;
15191615 let mut message_send_b = None ;
15201616 let mut final_tx_a = None ;
15211617 let mut final_tx_b = None ;
0 commit comments