1 // This file is Copyright its original authors, visible in version control
4 // This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
5 // or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
7 // You may not use this file except in accordance with one or both of these
10 use crate::io_extras::sink;
11 use crate::prelude::*;
14 use bitcoin::amount::Amount;
15 use bitcoin::blockdata::constants::WITNESS_SCALE_FACTOR;
16 use bitcoin::consensus::Encodable;
17 use bitcoin::policy::MAX_STANDARD_TX_WEIGHT;
18 use bitcoin::transaction::Version;
20 absolute::LockTime as AbsoluteLockTime, OutPoint, ScriptBuf, Sequence, Transaction, TxIn,
24 use crate::chain::chaininterface::fee_for_weight;
25 use crate::events::bump_transaction::{BASE_INPUT_WEIGHT, EMPTY_SCRIPT_SIG_WEIGHT};
26 use crate::ln::channel::TOTAL_BITCOIN_SUPPLY_SATOSHIS;
28 use crate::ln::msgs::SerialId;
29 use crate::ln::types::ChannelId;
30 use crate::sign::{EntropySource, P2TR_KEY_PATH_WITNESS_WEIGHT, P2WPKH_WITNESS_WEIGHT};
31 use crate::util::ser::TransactionU16LenLimited;
33 /// The number of received `tx_add_input` messages during a negotiation at which point the
34 /// negotiation MUST be failed.
35 const MAX_RECEIVED_TX_ADD_INPUT_COUNT: u16 = 4096;
37 /// The number of received `tx_add_output` messages during a negotiation at which point the
38 /// negotiation MUST be failed.
39 const MAX_RECEIVED_TX_ADD_OUTPUT_COUNT: u16 = 4096;
41 /// The number of inputs or outputs that the state machine can have, before it MUST fail the
43 const MAX_INPUTS_OUTPUTS_COUNT: usize = 252;
45 /// The total weight of the common fields whose fee is paid by the initiator of the interactive
46 /// transaction construction protocol.
47 const TX_COMMON_FIELDS_WEIGHT: u64 = (4 /* version */ + 4 /* locktime */ + 1 /* input count */ +
48 1 /* output count */) * WITNESS_SCALE_FACTOR as u64 + 2 /* segwit marker + flag */;
50 // BOLT 3 - Lower bounds for input weights
52 /// Lower bound for P2WPKH input weight
53 pub(crate) const P2WPKH_INPUT_WEIGHT_LOWER_BOUND: u64 =
54 BASE_INPUT_WEIGHT + EMPTY_SCRIPT_SIG_WEIGHT + P2WPKH_WITNESS_WEIGHT;
56 /// Lower bound for P2WSH input weight is chosen as same as P2WPKH input weight in BOLT 3
57 pub(crate) const P2WSH_INPUT_WEIGHT_LOWER_BOUND: u64 = P2WPKH_INPUT_WEIGHT_LOWER_BOUND;
59 /// Lower bound for P2TR input weight is chosen as the key spend path.
60 /// Not specified in BOLT 3, but a reasonable lower bound.
61 pub(crate) const P2TR_INPUT_WEIGHT_LOWER_BOUND: u64 =
62 BASE_INPUT_WEIGHT + EMPTY_SCRIPT_SIG_WEIGHT + P2TR_KEY_PATH_WITNESS_WEIGHT;
64 /// Lower bound for unknown segwit version input weight is chosen the same as P2WPKH in BOLT 3
65 pub(crate) const UNKNOWN_SEGWIT_VERSION_INPUT_WEIGHT_LOWER_BOUND: u64 =
66 P2WPKH_INPUT_WEIGHT_LOWER_BOUND;
69 fn is_for_initiator(&self) -> bool;
70 fn is_for_non_initiator(&self) -> bool;
73 impl SerialIdExt for SerialId {
74 fn is_for_initiator(&self) -> bool {
78 fn is_for_non_initiator(&self) -> bool {
79 !self.is_for_initiator()
83 #[derive(Debug, Clone, PartialEq)]
84 pub(crate) enum AbortReason {
85 InvalidStateTransition,
86 UnexpectedCounterpartyMessage,
87 ReceivedTooManyTxAddInputs,
88 ReceivedTooManyTxAddOutputs,
89 IncorrectInputSequenceValue,
90 IncorrectSerialIdParity,
94 ExceededMaximumSatsAllowed,
95 ExceededNumberOfInputsOrOutputs,
100 OutputsValueExceedsInputsValue,
104 #[derive(Debug, Clone, PartialEq, Eq)]
105 pub(crate) struct InteractiveTxInput {
111 #[derive(Debug, Clone, PartialEq, Eq)]
112 pub(crate) struct InteractiveTxOutput {
117 #[derive(Debug, Clone, PartialEq, Eq)]
118 pub(crate) struct ConstructedTransaction {
119 holder_is_initiator: bool,
121 inputs: Vec<InteractiveTxInput>,
122 outputs: Vec<InteractiveTxOutput>,
124 local_inputs_value_satoshis: u64,
125 local_outputs_value_satoshis: u64,
127 remote_inputs_value_satoshis: u64,
128 remote_outputs_value_satoshis: u64,
130 lock_time: AbsoluteLockTime,
133 impl ConstructedTransaction {
134 fn new(context: NegotiationContext) -> Self {
135 let local_inputs_value_satoshis = context
138 .filter(|(serial_id, _)| {
139 !is_serial_id_valid_for_counterparty(context.holder_is_initiator, serial_id)
141 .fold(0u64, |value, (_, input)| value.saturating_add(input.prev_output.value.to_sat()));
143 let local_outputs_value_satoshis = context
146 .filter(|(serial_id, _)| {
147 !is_serial_id_valid_for_counterparty(context.holder_is_initiator, serial_id)
149 .fold(0u64, |value, (_, output)| value.saturating_add(output.tx_out.value.to_sat()));
152 holder_is_initiator: context.holder_is_initiator,
154 local_inputs_value_satoshis,
155 local_outputs_value_satoshis,
157 remote_inputs_value_satoshis: context.remote_inputs_value(),
158 remote_outputs_value_satoshis: context.remote_outputs_value(),
160 inputs: context.inputs.into_values().collect(),
161 outputs: context.outputs.into_values().collect(),
163 lock_time: context.tx_locktime,
167 pub fn weight(&self) -> Weight {
168 let inputs_weight = self.inputs.iter().fold(
170 |weight, InteractiveTxInput { prev_output, .. }| {
171 weight.checked_add(estimate_input_weight(prev_output)).unwrap_or(Weight::MAX)
174 let outputs_weight = self.outputs.iter().fold(
176 |weight, InteractiveTxOutput { tx_out, .. }| {
177 weight.checked_add(get_output_weight(&tx_out.script_pubkey)).unwrap_or(Weight::MAX)
180 Weight::from_wu(TX_COMMON_FIELDS_WEIGHT)
181 .checked_add(inputs_weight)
182 .and_then(|weight| weight.checked_add(outputs_weight))
183 .unwrap_or(Weight::MAX)
186 pub fn into_unsigned_tx(self) -> Transaction {
187 // Inputs and outputs must be sorted by serial_id
188 let ConstructedTransaction { mut inputs, mut outputs, .. } = self;
190 inputs.sort_unstable_by_key(|InteractiveTxInput { serial_id, .. }| *serial_id);
191 outputs.sort_unstable_by_key(|InteractiveTxOutput { serial_id, .. }| *serial_id);
193 let input: Vec<TxIn> =
194 inputs.into_iter().map(|InteractiveTxInput { input, .. }| input).collect();
195 let output: Vec<TxOut> =
196 outputs.into_iter().map(|InteractiveTxOutput { tx_out, .. }| tx_out).collect();
198 Transaction { version: Version::TWO, lock_time: self.lock_time, input, output }
203 struct NegotiationContext {
204 holder_is_initiator: bool,
205 received_tx_add_input_count: u16,
206 received_tx_add_output_count: u16,
207 inputs: HashMap<SerialId, InteractiveTxInput>,
208 prevtx_outpoints: HashSet<OutPoint>,
209 outputs: HashMap<SerialId, InteractiveTxOutput>,
210 tx_locktime: AbsoluteLockTime,
211 feerate_sat_per_kw: u32,
214 pub(crate) fn estimate_input_weight(prev_output: &TxOut) -> Weight {
215 Weight::from_wu(if prev_output.script_pubkey.is_p2wpkh() {
216 P2WPKH_INPUT_WEIGHT_LOWER_BOUND
217 } else if prev_output.script_pubkey.is_p2wsh() {
218 P2WSH_INPUT_WEIGHT_LOWER_BOUND
219 } else if prev_output.script_pubkey.is_p2tr() {
220 P2TR_INPUT_WEIGHT_LOWER_BOUND
222 UNKNOWN_SEGWIT_VERSION_INPUT_WEIGHT_LOWER_BOUND
226 pub(crate) fn get_output_weight(script_pubkey: &ScriptBuf) -> Weight {
228 (8 /* value */ + script_pubkey.consensus_encode(&mut sink()).unwrap() as u64)
229 * WITNESS_SCALE_FACTOR as u64,
233 fn is_serial_id_valid_for_counterparty(holder_is_initiator: bool, serial_id: &SerialId) -> bool {
234 // A received `SerialId`'s parity must match the role of the counterparty.
235 holder_is_initiator == serial_id.is_for_non_initiator()
238 impl NegotiationContext {
239 fn is_serial_id_valid_for_counterparty(&self, serial_id: &SerialId) -> bool {
240 is_serial_id_valid_for_counterparty(self.holder_is_initiator, serial_id)
243 fn remote_inputs_value(&self) -> u64 {
246 .filter(|(serial_id, _)| self.is_serial_id_valid_for_counterparty(serial_id))
247 .fold(0u64, |acc, (_, InteractiveTxInput { prev_output, .. })| {
248 acc.saturating_add(prev_output.value.to_sat())
252 fn remote_outputs_value(&self) -> u64 {
255 .filter(|(serial_id, _)| self.is_serial_id_valid_for_counterparty(serial_id))
256 .fold(0u64, |acc, (_, InteractiveTxOutput { tx_out, .. })| {
257 acc.saturating_add(tx_out.value.to_sat())
261 fn remote_inputs_weight(&self) -> Weight {
265 .filter(|(serial_id, _)| self.is_serial_id_valid_for_counterparty(serial_id))
266 .fold(0u64, |weight, (_, InteractiveTxInput { prev_output, .. })| {
267 weight.saturating_add(estimate_input_weight(prev_output).to_wu())
272 fn remote_outputs_weight(&self) -> Weight {
276 .filter(|(serial_id, _)| self.is_serial_id_valid_for_counterparty(serial_id))
277 .fold(0u64, |weight, (_, InteractiveTxOutput { tx_out, .. })| {
278 weight.saturating_add(get_output_weight(&tx_out.script_pubkey).to_wu())
283 fn received_tx_add_input(&mut self, msg: &msgs::TxAddInput) -> Result<(), AbortReason> {
284 // The interactive-txs spec calls for us to fail negotiation if the `prevtx` we receive is
285 // invalid. However, we would not need to account for this explicit negotiation failure
286 // mode here since `PeerManager` would already disconnect the peer if the `prevtx` is
287 // invalid; implicitly ending the negotiation.
289 if !self.is_serial_id_valid_for_counterparty(&msg.serial_id) {
290 // The receiving node:
291 // - MUST fail the negotiation if:
292 // - the `serial_id` has the wrong parity
293 return Err(AbortReason::IncorrectSerialIdParity);
296 self.received_tx_add_input_count += 1;
297 if self.received_tx_add_input_count > MAX_RECEIVED_TX_ADD_INPUT_COUNT {
298 // The receiving node:
299 // - MUST fail the negotiation if:
300 // - if has received 4096 `tx_add_input` messages during this negotiation
301 return Err(AbortReason::ReceivedTooManyTxAddInputs);
304 if msg.sequence >= 0xFFFFFFFE {
305 // The receiving node:
306 // - MUST fail the negotiation if:
307 // - `sequence` is set to `0xFFFFFFFE` or `0xFFFFFFFF`
308 return Err(AbortReason::IncorrectInputSequenceValue);
311 let transaction = msg.prevtx.as_transaction();
312 let txid = transaction.txid();
314 if let Some(tx_out) = transaction.output.get(msg.prevtx_out as usize) {
315 if !tx_out.script_pubkey.is_witness_program() {
316 // The receiving node:
317 // - MUST fail the negotiation if:
318 // - the `scriptPubKey` is not a witness program
319 return Err(AbortReason::PrevTxOutInvalid);
322 if !self.prevtx_outpoints.insert(OutPoint { txid, vout: msg.prevtx_out }) {
323 // The receiving node:
324 // - MUST fail the negotiation if:
325 // - the `prevtx` and `prevtx_vout` are identical to a previously added
326 // (and not removed) input's
327 return Err(AbortReason::PrevTxOutInvalid);
330 // The receiving node:
331 // - MUST fail the negotiation if:
332 // - `prevtx_vout` is greater or equal to the number of outputs on `prevtx`
333 return Err(AbortReason::PrevTxOutInvalid);
336 let prev_out = if let Some(prev_out) = transaction.output.get(msg.prevtx_out as usize) {
339 return Err(AbortReason::PrevTxOutInvalid);
341 match self.inputs.entry(msg.serial_id) {
342 hash_map::Entry::Occupied(_) => {
343 // The receiving node:
344 // - MUST fail the negotiation if:
345 // - the `serial_id` is already included in the transaction
346 Err(AbortReason::DuplicateSerialId)
348 hash_map::Entry::Vacant(entry) => {
349 let prev_outpoint = OutPoint { txid, vout: msg.prevtx_out };
350 entry.insert(InteractiveTxInput {
351 serial_id: msg.serial_id,
353 previous_output: prev_outpoint,
354 sequence: Sequence(msg.sequence),
357 prev_output: prev_out,
359 self.prevtx_outpoints.insert(prev_outpoint);
365 fn received_tx_remove_input(&mut self, msg: &msgs::TxRemoveInput) -> Result<(), AbortReason> {
366 if !self.is_serial_id_valid_for_counterparty(&msg.serial_id) {
367 return Err(AbortReason::IncorrectSerialIdParity);
371 .remove(&msg.serial_id)
372 // The receiving node:
373 // - MUST fail the negotiation if:
374 // - the input or output identified by the `serial_id` was not added by the sender
375 // - the `serial_id` does not correspond to a currently added input
376 .ok_or(AbortReason::SerialIdUnknown)
380 fn received_tx_add_output(&mut self, msg: &msgs::TxAddOutput) -> Result<(), AbortReason> {
381 // The receiving node:
382 // - MUST fail the negotiation if:
383 // - the serial_id has the wrong parity
384 if !self.is_serial_id_valid_for_counterparty(&msg.serial_id) {
385 return Err(AbortReason::IncorrectSerialIdParity);
388 self.received_tx_add_output_count += 1;
389 if self.received_tx_add_output_count > MAX_RECEIVED_TX_ADD_OUTPUT_COUNT {
390 // The receiving node:
391 // - MUST fail the negotiation if:
392 // - if has received 4096 `tx_add_output` messages during this negotiation
393 return Err(AbortReason::ReceivedTooManyTxAddOutputs);
396 if msg.sats < msg.script.dust_value().to_sat() {
397 // The receiving node:
398 // - MUST fail the negotiation if:
399 // - the sats amount is less than the dust_limit
400 return Err(AbortReason::BelowDustLimit);
403 // Check that adding this output would not cause the total output value to exceed the total
405 let mut outputs_value: u64 = 0;
406 for output in self.outputs.iter() {
407 outputs_value = outputs_value.saturating_add(output.1.tx_out.value.to_sat());
409 if outputs_value.saturating_add(msg.sats) > TOTAL_BITCOIN_SUPPLY_SATOSHIS {
410 // The receiving node:
411 // - MUST fail the negotiation if:
412 // - the sats amount is greater than 2,100,000,000,000,000 (TOTAL_BITCOIN_SUPPLY_SATOSHIS)
413 return Err(AbortReason::ExceededMaximumSatsAllowed);
416 // The receiving node:
417 // - MUST accept P2WSH, P2WPKH, P2TR scripts
418 // - MAY fail the negotiation if script is non-standard
420 // We can actually be a bit looser than the above as only witness version 0 has special
421 // length-based standardness constraints to match similar consensus rules. All witness scripts
422 // with witness versions V1 and up are always considered standard. Yes, the scripts can be
423 // anyone-can-spend-able, but if our counterparty wants to add an output like that then it's none
424 // of our concern really ¯\_(ツ)_/¯
426 // TODO: The last check would be simplified when https://github.com/rust-bitcoin/rust-bitcoin/commit/1656e1a09a1959230e20af90d20789a4a8f0a31b
427 // hits the next release of rust-bitcoin.
428 if !(msg.script.is_p2wpkh()
429 || msg.script.is_p2wsh()
430 || (msg.script.is_witness_program()
431 && msg.script.witness_version().map(|v| v.to_num() >= 1).unwrap_or(false)))
433 return Err(AbortReason::InvalidOutputScript);
436 match self.outputs.entry(msg.serial_id) {
437 hash_map::Entry::Occupied(_) => {
438 // The receiving node:
439 // - MUST fail the negotiation if:
440 // - the `serial_id` is already included in the transaction
441 Err(AbortReason::DuplicateSerialId)
443 hash_map::Entry::Vacant(entry) => {
444 entry.insert(InteractiveTxOutput {
445 serial_id: msg.serial_id,
447 value: Amount::from_sat(msg.sats),
448 script_pubkey: msg.script.clone(),
456 fn received_tx_remove_output(&mut self, msg: &msgs::TxRemoveOutput) -> Result<(), AbortReason> {
457 if !self.is_serial_id_valid_for_counterparty(&msg.serial_id) {
458 return Err(AbortReason::IncorrectSerialIdParity);
460 if self.outputs.remove(&msg.serial_id).is_some() {
463 // The receiving node:
464 // - MUST fail the negotiation if:
465 // - the input or output identified by the `serial_id` was not added by the sender
466 // - the `serial_id` does not correspond to a currently added input
467 Err(AbortReason::SerialIdUnknown)
471 fn sent_tx_add_input(&mut self, msg: &msgs::TxAddInput) -> Result<(), AbortReason> {
472 let tx = msg.prevtx.as_transaction();
474 previous_output: OutPoint { txid: tx.txid(), vout: msg.prevtx_out },
475 sequence: Sequence(msg.sequence),
479 tx.output.get(msg.prevtx_out as usize).ok_or(AbortReason::PrevTxOutInvalid)?.clone();
480 if !self.prevtx_outpoints.insert(input.previous_output) {
481 // We have added an input that already exists
482 return Err(AbortReason::PrevTxOutInvalid);
486 InteractiveTxInput { serial_id: msg.serial_id, input, prev_output },
491 fn sent_tx_add_output(&mut self, msg: &msgs::TxAddOutput) -> Result<(), AbortReason> {
494 InteractiveTxOutput {
495 serial_id: msg.serial_id,
497 value: Amount::from_sat(msg.sats),
498 script_pubkey: msg.script.clone(),
505 fn sent_tx_remove_input(&mut self, msg: &msgs::TxRemoveInput) -> Result<(), AbortReason> {
506 self.inputs.remove(&msg.serial_id);
510 fn sent_tx_remove_output(&mut self, msg: &msgs::TxRemoveOutput) -> Result<(), AbortReason> {
511 self.outputs.remove(&msg.serial_id);
515 fn check_counterparty_fees(
516 &self, counterparty_fees_contributed: u64,
517 ) -> Result<(), AbortReason> {
518 let counterparty_weight_contributed = self
519 .remote_inputs_weight()
521 .saturating_add(self.remote_outputs_weight().to_wu());
522 let mut required_counterparty_contribution_fee =
523 fee_for_weight(self.feerate_sat_per_kw, counterparty_weight_contributed);
524 if !self.holder_is_initiator {
525 // if is the non-initiator:
526 // - the initiator's fees do not cover the common fields (version, segwit marker + flag,
527 // input count, output count, locktime)
528 let tx_common_fields_fee =
529 fee_for_weight(self.feerate_sat_per_kw, TX_COMMON_FIELDS_WEIGHT);
530 required_counterparty_contribution_fee += tx_common_fields_fee;
532 if counterparty_fees_contributed < required_counterparty_contribution_fee {
533 return Err(AbortReason::InsufficientFees);
538 fn validate_tx(self) -> Result<ConstructedTransaction, AbortReason> {
539 // The receiving node:
540 // MUST fail the negotiation if:
542 // - the peer's total input satoshis is less than their outputs
543 let remote_inputs_value = self.remote_inputs_value();
544 let remote_outputs_value = self.remote_outputs_value();
545 if remote_inputs_value < remote_outputs_value {
546 return Err(AbortReason::OutputsValueExceedsInputsValue);
549 // - there are more than 252 inputs
550 // - there are more than 252 outputs
551 if self.inputs.len() > MAX_INPUTS_OUTPUTS_COUNT
552 || self.outputs.len() > MAX_INPUTS_OUTPUTS_COUNT
554 return Err(AbortReason::ExceededNumberOfInputsOrOutputs);
557 // - the peer's paid feerate does not meet or exceed the agreed feerate (based on the minimum fee).
558 self.check_counterparty_fees(remote_inputs_value.saturating_sub(remote_outputs_value))?;
560 let constructed_tx = ConstructedTransaction::new(self);
562 if constructed_tx.weight().to_wu() > MAX_STANDARD_TX_WEIGHT as u64 {
563 return Err(AbortReason::TransactionTooLarge);
570 // The interactive transaction construction protocol allows two peers to collaboratively build a
571 // transaction for broadcast.
573 // The protocol is turn-based, so we define different states here that we store depending on whose
574 // turn it is to send the next message. The states are defined so that their types ensure we only
575 // perform actions (only send messages) via defined state transitions that do not violate the
578 // An example of a full negotiation and associated states follows:
580 // +------------+ +------------------+---- Holder state after message sent/received ----+
581 // | |--(1)- tx_add_input ---->| | SentChangeMsg +
582 // | |<-(2)- tx_complete ------| | ReceivedTxComplete +
583 // | |--(3)- tx_add_output --->| | SentChangeMsg +
584 // | |<-(4)- tx_complete ------| | ReceivedTxComplete +
585 // | |--(5)- tx_add_input ---->| | SentChangeMsg +
586 // | Holder |<-(6)- tx_add_input -----| Counterparty | ReceivedChangeMsg +
587 // | |--(7)- tx_remove_output >| | SentChangeMsg +
588 // | |<-(8)- tx_add_output ----| | ReceivedChangeMsg +
589 // | |--(9)- tx_complete ----->| | SentTxComplete +
590 // | |<-(10) tx_complete ------| | NegotiationComplete +
591 // +------------+ +------------------+--------------------------------------------------+
593 /// Negotiation states that can send & receive `tx_(add|remove)_(input|output)` and `tx_complete`
596 /// Category of states where we have sent some message to the counterparty, and we are waiting for
598 trait SentMsgState: State {
599 fn into_negotiation_context(self) -> NegotiationContext;
602 /// Category of states that our counterparty has put us in after we receive a message from them.
603 trait ReceivedMsgState: State {
604 fn into_negotiation_context(self) -> NegotiationContext;
607 // This macro is a helper for implementing the above state traits for various states subsequently
608 // defined below the macro.
609 macro_rules! define_state {
610 (SENT_MSG_STATE, $state: ident, $doc: expr) => {
611 define_state!($state, NegotiationContext, $doc);
612 impl SentMsgState for $state {
613 fn into_negotiation_context(self) -> NegotiationContext {
618 (RECEIVED_MSG_STATE, $state: ident, $doc: expr) => {
619 define_state!($state, NegotiationContext, $doc);
620 impl ReceivedMsgState for $state {
621 fn into_negotiation_context(self) -> NegotiationContext {
626 ($state: ident, $inner: ident, $doc: expr) => {
629 struct $state($inner);
630 impl State for $state {}
637 "We have sent a message to the counterparty that has affected our negotiation state."
642 "We have sent a `tx_complete` message and are awaiting the counterparty's."
647 "We have received a message from the counterparty that has affected our negotiation state."
652 "We have received a `tx_complete` message and the counterparty is awaiting ours."
654 define_state!(NegotiationComplete, ConstructedTransaction, "We have exchanged consecutive `tx_complete` messages with the counterparty and the transaction negotiation is complete.");
658 "The negotiation has failed and cannot be continued."
661 type StateTransitionResult<S> = Result<S, AbortReason>;
663 trait StateTransition<NewState: State, TransitionData> {
664 fn transition(self, data: TransitionData) -> StateTransitionResult<NewState>;
667 // This macro helps define the legal transitions between the states above by implementing
668 // the `StateTransition` trait for each of the states that follow this declaration.
669 macro_rules! define_state_transitions {
670 (SENT_MSG_STATE, [$(DATA $data: ty, TRANSITION $transition: ident),+]) => {
672 impl<S: SentMsgState> StateTransition<ReceivedChangeMsg, $data> for S {
673 fn transition(self, data: $data) -> StateTransitionResult<ReceivedChangeMsg> {
674 let mut context = self.into_negotiation_context();
675 context.$transition(data)?;
676 Ok(ReceivedChangeMsg(context))
681 (RECEIVED_MSG_STATE, [$(DATA $data: ty, TRANSITION $transition: ident),+]) => {
683 impl<S: ReceivedMsgState> StateTransition<SentChangeMsg, $data> for S {
684 fn transition(self, data: $data) -> StateTransitionResult<SentChangeMsg> {
685 let mut context = self.into_negotiation_context();
686 context.$transition(data)?;
687 Ok(SentChangeMsg(context))
692 (TX_COMPLETE, $from_state: ident, $tx_complete_state: ident) => {
693 impl StateTransition<NegotiationComplete, &msgs::TxComplete> for $tx_complete_state {
694 fn transition(self, _data: &msgs::TxComplete) -> StateTransitionResult<NegotiationComplete> {
695 let context = self.into_negotiation_context();
696 let tx = context.validate_tx()?;
697 Ok(NegotiationComplete(tx))
701 impl StateTransition<$tx_complete_state, &msgs::TxComplete> for $from_state {
702 fn transition(self, _data: &msgs::TxComplete) -> StateTransitionResult<$tx_complete_state> {
703 Ok($tx_complete_state(self.into_negotiation_context()))
709 // State transitions when we have sent our counterparty some messages and are waiting for them
711 define_state_transitions!(SENT_MSG_STATE, [
712 DATA &msgs::TxAddInput, TRANSITION received_tx_add_input,
713 DATA &msgs::TxRemoveInput, TRANSITION received_tx_remove_input,
714 DATA &msgs::TxAddOutput, TRANSITION received_tx_add_output,
715 DATA &msgs::TxRemoveOutput, TRANSITION received_tx_remove_output
717 // State transitions when we have received some messages from our counterparty and we should
719 define_state_transitions!(RECEIVED_MSG_STATE, [
720 DATA &msgs::TxAddInput, TRANSITION sent_tx_add_input,
721 DATA &msgs::TxRemoveInput, TRANSITION sent_tx_remove_input,
722 DATA &msgs::TxAddOutput, TRANSITION sent_tx_add_output,
723 DATA &msgs::TxRemoveOutput, TRANSITION sent_tx_remove_output
725 define_state_transitions!(TX_COMPLETE, SentChangeMsg, ReceivedTxComplete);
726 define_state_transitions!(TX_COMPLETE, ReceivedChangeMsg, SentTxComplete);
731 SentChangeMsg(SentChangeMsg),
732 ReceivedChangeMsg(ReceivedChangeMsg),
733 SentTxComplete(SentTxComplete),
734 ReceivedTxComplete(ReceivedTxComplete),
735 NegotiationComplete(NegotiationComplete),
736 NegotiationAborted(NegotiationAborted),
739 impl Default for StateMachine {
740 fn default() -> Self {
745 // The `StateMachine` internally executes the actual transition between two states and keeps
746 // track of the current state. This macro defines _how_ those state transitions happen to
747 // update the internal state.
748 macro_rules! define_state_machine_transitions {
749 ($transition: ident, $msg: ty, [$(FROM $from_state: ident, TO $to_state: ident),+]) => {
750 fn $transition(self, msg: $msg) -> StateMachine {
753 Self::$from_state(s) => match s.transition(msg) {
754 Ok(new_state) => StateMachine::$to_state(new_state),
755 Err(abort_reason) => StateMachine::NegotiationAborted(NegotiationAborted(abort_reason)),
758 _ => StateMachine::NegotiationAborted(NegotiationAborted(AbortReason::UnexpectedCounterpartyMessage)),
765 fn new(feerate_sat_per_kw: u32, is_initiator: bool, tx_locktime: AbsoluteLockTime) -> Self {
766 let context = NegotiationContext {
768 holder_is_initiator: is_initiator,
769 received_tx_add_input_count: 0,
770 received_tx_add_output_count: 0,
771 inputs: new_hash_map(),
772 prevtx_outpoints: new_hash_set(),
773 outputs: new_hash_map(),
777 Self::ReceivedChangeMsg(ReceivedChangeMsg(context))
779 Self::SentChangeMsg(SentChangeMsg(context))
784 define_state_machine_transitions!(sent_tx_add_input, &msgs::TxAddInput, [
785 FROM ReceivedChangeMsg, TO SentChangeMsg,
786 FROM ReceivedTxComplete, TO SentChangeMsg
788 define_state_machine_transitions!(received_tx_add_input, &msgs::TxAddInput, [
789 FROM SentChangeMsg, TO ReceivedChangeMsg,
790 FROM SentTxComplete, TO ReceivedChangeMsg
794 define_state_machine_transitions!(sent_tx_add_output, &msgs::TxAddOutput, [
795 FROM ReceivedChangeMsg, TO SentChangeMsg,
796 FROM ReceivedTxComplete, TO SentChangeMsg
798 define_state_machine_transitions!(received_tx_add_output, &msgs::TxAddOutput, [
799 FROM SentChangeMsg, TO ReceivedChangeMsg,
800 FROM SentTxComplete, TO ReceivedChangeMsg
804 define_state_machine_transitions!(sent_tx_remove_input, &msgs::TxRemoveInput, [
805 FROM ReceivedChangeMsg, TO SentChangeMsg,
806 FROM ReceivedTxComplete, TO SentChangeMsg
808 define_state_machine_transitions!(received_tx_remove_input, &msgs::TxRemoveInput, [
809 FROM SentChangeMsg, TO ReceivedChangeMsg,
810 FROM SentTxComplete, TO ReceivedChangeMsg
814 define_state_machine_transitions!(sent_tx_remove_output, &msgs::TxRemoveOutput, [
815 FROM ReceivedChangeMsg, TO SentChangeMsg,
816 FROM ReceivedTxComplete, TO SentChangeMsg
818 define_state_machine_transitions!(received_tx_remove_output, &msgs::TxRemoveOutput, [
819 FROM SentChangeMsg, TO ReceivedChangeMsg,
820 FROM SentTxComplete, TO ReceivedChangeMsg
824 define_state_machine_transitions!(sent_tx_complete, &msgs::TxComplete, [
825 FROM ReceivedChangeMsg, TO SentTxComplete,
826 FROM ReceivedTxComplete, TO NegotiationComplete
828 define_state_machine_transitions!(received_tx_complete, &msgs::TxComplete, [
829 FROM SentChangeMsg, TO ReceivedTxComplete,
830 FROM SentTxComplete, TO NegotiationComplete
834 pub(crate) struct InteractiveTxConstructor {
835 state_machine: StateMachine,
836 channel_id: ChannelId,
837 inputs_to_contribute: Vec<(SerialId, TxIn, TransactionU16LenLimited)>,
838 outputs_to_contribute: Vec<(SerialId, TxOut)>,
841 pub(crate) enum InteractiveTxMessageSend {
842 TxAddInput(msgs::TxAddInput),
843 TxAddOutput(msgs::TxAddOutput),
844 TxComplete(msgs::TxComplete),
847 // This macro executes a state machine transition based on a provided action.
848 macro_rules! do_state_transition {
849 ($self: ident, $transition: ident, $msg: expr) => {{
850 let state_machine = core::mem::take(&mut $self.state_machine);
851 $self.state_machine = state_machine.$transition($msg);
852 match &$self.state_machine {
853 StateMachine::NegotiationAborted(state) => Err(state.0.clone()),
859 fn generate_holder_serial_id<ES: Deref>(entropy_source: &ES, is_initiator: bool) -> SerialId
861 ES::Target: EntropySource,
863 let rand_bytes = entropy_source.get_secure_random_bytes();
864 let mut serial_id_bytes = [0u8; 8];
865 serial_id_bytes.copy_from_slice(&rand_bytes[..8]);
866 let mut serial_id = u64::from_be_bytes(serial_id_bytes);
867 if serial_id.is_for_initiator() != is_initiator {
873 pub(crate) enum HandleTxCompleteValue {
874 SendTxMessage(InteractiveTxMessageSend),
875 SendTxComplete(InteractiveTxMessageSend, ConstructedTransaction),
876 NegotiationComplete(ConstructedTransaction),
879 impl InteractiveTxConstructor {
880 /// Instantiates a new `InteractiveTxConstructor`.
882 /// A tuple is returned containing the newly instantiate `InteractiveTxConstructor` and optionally
883 /// an initial wrapped `Tx_` message which the holder needs to send to the counterparty.
884 pub fn new<ES: Deref>(
885 entropy_source: &ES, channel_id: ChannelId, feerate_sat_per_kw: u32, is_initiator: bool,
886 funding_tx_locktime: AbsoluteLockTime,
887 inputs_to_contribute: Vec<(TxIn, TransactionU16LenLimited)>,
888 outputs_to_contribute: Vec<TxOut>,
889 ) -> (Self, Option<InteractiveTxMessageSend>)
891 ES::Target: EntropySource,
894 StateMachine::new(feerate_sat_per_kw, is_initiator, funding_tx_locktime);
895 let mut inputs_to_contribute: Vec<(SerialId, TxIn, TransactionU16LenLimited)> =
899 let serial_id = generate_holder_serial_id(entropy_source, is_initiator);
900 (serial_id, input, tx)
903 // We'll sort by the randomly generated serial IDs, effectively shuffling the order of the inputs
904 // as the user passed them to us to avoid leaking any potential categorization of transactions
905 // before we pass any of the inputs to the counterparty.
906 inputs_to_contribute.sort_unstable_by_key(|(serial_id, _, _)| *serial_id);
907 let mut outputs_to_contribute: Vec<(SerialId, TxOut)> = outputs_to_contribute
910 let serial_id = generate_holder_serial_id(entropy_source, is_initiator);
914 // In the same manner and for the same rationale as the inputs above, we'll shuffle the outputs.
915 outputs_to_contribute.sort_unstable_by_key(|(serial_id, _)| *serial_id);
916 let mut constructor =
917 Self { state_machine, channel_id, inputs_to_contribute, outputs_to_contribute };
918 let message_send = if is_initiator {
919 match constructor.maybe_send_message() {
920 Ok(msg_send) => Some(msg_send),
924 "We should always be able to start our state machine successfully"
932 (constructor, message_send)
935 fn maybe_send_message(&mut self) -> Result<InteractiveTxMessageSend, AbortReason> {
936 // We first attempt to send inputs we want to add, then outputs. Once we are done sending
937 // them both, then we always send tx_complete.
938 if let Some((serial_id, input, prevtx)) = self.inputs_to_contribute.pop() {
939 let msg = msgs::TxAddInput {
940 channel_id: self.channel_id,
943 prevtx_out: input.previous_output.vout,
944 sequence: input.sequence.to_consensus_u32(),
945 shared_input_txid: None,
947 do_state_transition!(self, sent_tx_add_input, &msg)?;
948 Ok(InteractiveTxMessageSend::TxAddInput(msg))
949 } else if let Some((serial_id, output)) = self.outputs_to_contribute.pop() {
950 let msg = msgs::TxAddOutput {
951 channel_id: self.channel_id,
953 sats: output.value.to_sat(),
954 script: output.script_pubkey,
956 do_state_transition!(self, sent_tx_add_output, &msg)?;
957 Ok(InteractiveTxMessageSend::TxAddOutput(msg))
959 let msg = msgs::TxComplete { channel_id: self.channel_id };
960 do_state_transition!(self, sent_tx_complete, &msg)?;
961 Ok(InteractiveTxMessageSend::TxComplete(msg))
965 pub fn handle_tx_add_input(
966 &mut self, msg: &msgs::TxAddInput,
967 ) -> Result<InteractiveTxMessageSend, AbortReason> {
968 do_state_transition!(self, received_tx_add_input, msg)?;
969 self.maybe_send_message()
972 pub fn handle_tx_remove_input(
973 &mut self, msg: &msgs::TxRemoveInput,
974 ) -> Result<InteractiveTxMessageSend, AbortReason> {
975 do_state_transition!(self, received_tx_remove_input, msg)?;
976 self.maybe_send_message()
979 pub fn handle_tx_add_output(
980 &mut self, msg: &msgs::TxAddOutput,
981 ) -> Result<InteractiveTxMessageSend, AbortReason> {
982 do_state_transition!(self, received_tx_add_output, msg)?;
983 self.maybe_send_message()
986 pub fn handle_tx_remove_output(
987 &mut self, msg: &msgs::TxRemoveOutput,
988 ) -> Result<InteractiveTxMessageSend, AbortReason> {
989 do_state_transition!(self, received_tx_remove_output, msg)?;
990 self.maybe_send_message()
993 pub fn handle_tx_complete(
994 &mut self, msg: &msgs::TxComplete,
995 ) -> Result<HandleTxCompleteValue, AbortReason> {
996 do_state_transition!(self, received_tx_complete, msg)?;
997 match &self.state_machine {
998 StateMachine::ReceivedTxComplete(_) => {
999 let msg_send = self.maybe_send_message()?;
1000 match &self.state_machine {
1001 StateMachine::NegotiationComplete(s) => {
1002 Ok(HandleTxCompleteValue::SendTxComplete(msg_send, s.0.clone()))
1004 StateMachine::SentChangeMsg(_) => {
1005 Ok(HandleTxCompleteValue::SendTxMessage(msg_send))
1006 }, // We either had an input or output to contribute.
1008 debug_assert!(false, "We cannot transition to any other states after receiving `tx_complete` and responding");
1009 Err(AbortReason::InvalidStateTransition)
1013 StateMachine::NegotiationComplete(s) => {
1014 Ok(HandleTxCompleteValue::NegotiationComplete(s.0.clone()))
1019 "We cannot transition to any other states after receiving `tx_complete`"
1021 Err(AbortReason::InvalidStateTransition)
1029 use crate::chain::chaininterface::{fee_for_weight, FEERATE_FLOOR_SATS_PER_KW};
1030 use crate::ln::channel::TOTAL_BITCOIN_SUPPLY_SATOSHIS;
1031 use crate::ln::interactivetxs::{
1032 generate_holder_serial_id, AbortReason, HandleTxCompleteValue, InteractiveTxConstructor,
1033 InteractiveTxMessageSend, MAX_INPUTS_OUTPUTS_COUNT, MAX_RECEIVED_TX_ADD_INPUT_COUNT,
1034 MAX_RECEIVED_TX_ADD_OUTPUT_COUNT,
1036 use crate::ln::types::ChannelId;
1037 use crate::sign::EntropySource;
1038 use crate::util::atomic_counter::AtomicCounter;
1039 use crate::util::ser::TransactionU16LenLimited;
1040 use bitcoin::amount::Amount;
1041 use bitcoin::blockdata::opcodes;
1042 use bitcoin::blockdata::script::Builder;
1043 use bitcoin::hashes::Hash;
1044 use bitcoin::key::UntweakedPublicKey;
1045 use bitcoin::secp256k1::{Keypair, Secp256k1};
1046 use bitcoin::transaction::Version;
1048 absolute::LockTime as AbsoluteLockTime, OutPoint, Sequence, Transaction, TxIn, TxOut,
1050 use bitcoin::{PubkeyHash, ScriptBuf, WPubkeyHash, WScriptHash};
1051 use core::ops::Deref;
1054 get_output_weight, P2TR_INPUT_WEIGHT_LOWER_BOUND, P2WPKH_INPUT_WEIGHT_LOWER_BOUND,
1055 P2WSH_INPUT_WEIGHT_LOWER_BOUND, TX_COMMON_FIELDS_WEIGHT,
1058 const TEST_FEERATE_SATS_PER_KW: u32 = FEERATE_FLOOR_SATS_PER_KW * 10;
1060 // A simple entropy source that works based on an atomic counter.
1061 struct TestEntropySource(AtomicCounter);
1062 impl EntropySource for TestEntropySource {
1063 fn get_secure_random_bytes(&self) -> [u8; 32] {
1064 let mut res = [0u8; 32];
1065 let increment = self.0.get_increment();
1067 // Rotate the increment value by 'i' bits to the right, to avoid clashes
1068 // when `generate_local_serial_id` does a parity flip on consecutive calls for the
1070 let rotated_increment = increment.rotate_right(i as u32);
1071 res[i] = (rotated_increment & 0xff) as u8;
1077 // An entropy source that deliberately returns you the same seed every time. We use this
1078 // to test if the constructor would catch inputs/outputs that are attempting to be added
1079 // with duplicate serial ids.
1080 struct DuplicateEntropySource;
1081 impl EntropySource for DuplicateEntropySource {
1082 fn get_secure_random_bytes(&self) -> [u8; 32] {
1083 let mut res = [0u8; 32];
1085 res[0..8].copy_from_slice(&count.to_be_bytes());
1090 #[derive(Debug, PartialEq, Eq)]
1094 // Some error values are only checked at the end of the negotiation and are not easy to attribute
1095 // to a particular party. Both parties would indicate an `AbortReason` in this case.
1096 // e.g. Exceeded max inputs and outputs after negotiation.
1100 struct TestSession {
1101 description: &'static str,
1102 inputs_a: Vec<(TxIn, TransactionU16LenLimited)>,
1103 outputs_a: Vec<TxOut>,
1104 inputs_b: Vec<(TxIn, TransactionU16LenLimited)>,
1105 outputs_b: Vec<TxOut>,
1106 expect_error: Option<(AbortReason, ErrorCulprit)>,
1109 fn do_test_interactive_tx_constructor(session: TestSession) {
1110 let entropy_source = TestEntropySource(AtomicCounter::new());
1111 do_test_interactive_tx_constructor_internal(session, &&entropy_source);
1114 fn do_test_interactive_tx_constructor_with_entropy_source<ES: Deref>(
1115 session: TestSession, entropy_source: ES,
1117 ES::Target: EntropySource,
1119 do_test_interactive_tx_constructor_internal(session, &entropy_source);
1122 fn do_test_interactive_tx_constructor_internal<ES: Deref>(
1123 session: TestSession, entropy_source: &ES,
1125 ES::Target: EntropySource,
1127 let channel_id = ChannelId(entropy_source.get_secure_random_bytes());
1128 let tx_locktime = AbsoluteLockTime::from_height(1337).unwrap();
1130 let (mut constructor_a, first_message_a) = InteractiveTxConstructor::new(
1133 TEST_FEERATE_SATS_PER_KW,
1139 let (mut constructor_b, first_message_b) = InteractiveTxConstructor::new(
1142 TEST_FEERATE_SATS_PER_KW,
1149 let handle_message_send =
1150 |msg: InteractiveTxMessageSend, for_constructor: &mut InteractiveTxConstructor| {
1152 InteractiveTxMessageSend::TxAddInput(msg) => for_constructor
1153 .handle_tx_add_input(&msg)
1154 .map(|msg_send| (Some(msg_send), None)),
1155 InteractiveTxMessageSend::TxAddOutput(msg) => for_constructor
1156 .handle_tx_add_output(&msg)
1157 .map(|msg_send| (Some(msg_send), None)),
1158 InteractiveTxMessageSend::TxComplete(msg) => {
1159 for_constructor.handle_tx_complete(&msg).map(|value| match value {
1160 HandleTxCompleteValue::SendTxMessage(msg_send) => {
1161 (Some(msg_send), None)
1163 HandleTxCompleteValue::SendTxComplete(msg_send, tx) => {
1164 (Some(msg_send), Some(tx))
1166 HandleTxCompleteValue::NegotiationComplete(tx) => (None, Some(tx)),
1172 assert!(first_message_b.is_none());
1173 let mut message_send_a = first_message_a;
1174 let mut message_send_b = None;
1175 let mut final_tx_a = None;
1176 let mut final_tx_b = None;
1177 while final_tx_a.is_none() || final_tx_b.is_none() {
1178 if let Some(message_send_a) = message_send_a.take() {
1179 match handle_message_send(message_send_a, &mut constructor_b) {
1180 Ok((msg_send, final_tx)) => {
1181 message_send_b = msg_send;
1182 final_tx_b = final_tx;
1184 Err(abort_reason) => {
1185 let error_culprit = match abort_reason {
1186 AbortReason::ExceededNumberOfInputsOrOutputs => {
1187 ErrorCulprit::Indeterminate
1189 _ => ErrorCulprit::NodeA,
1192 Some((abort_reason, error_culprit)),
1193 session.expect_error,
1197 assert!(message_send_b.is_none());
1202 if let Some(message_send_b) = message_send_b.take() {
1203 match handle_message_send(message_send_b, &mut constructor_a) {
1204 Ok((msg_send, final_tx)) => {
1205 message_send_a = msg_send;
1206 final_tx_a = final_tx;
1208 Err(abort_reason) => {
1209 let error_culprit = match abort_reason {
1210 AbortReason::ExceededNumberOfInputsOrOutputs => {
1211 ErrorCulprit::Indeterminate
1213 _ => ErrorCulprit::NodeB,
1216 Some((abort_reason, error_culprit)),
1217 session.expect_error,
1221 assert!(message_send_a.is_none());
1227 assert!(message_send_a.is_none());
1228 assert!(message_send_b.is_none());
1229 assert_eq!(final_tx_a.unwrap().into_unsigned_tx(), final_tx_b.unwrap().into_unsigned_tx());
1230 assert!(session.expect_error.is_none(), "Test: {}", session.description);
1233 #[derive(Debug, Clone, Copy)]
1238 // Non-witness type to test rejection.
1242 fn generate_tx(outputs: &[TestOutput]) -> Transaction {
1243 generate_tx_with_locktime(outputs, 1337)
1246 fn generate_txout(output: &TestOutput) -> TxOut {
1247 let secp_ctx = Secp256k1::new();
1248 let (value, script_pubkey) = match output {
1249 TestOutput::P2WPKH(value) => {
1250 (*value, ScriptBuf::new_p2wpkh(&WPubkeyHash::from_slice(&[1; 20]).unwrap()))
1252 TestOutput::P2WSH(value) => {
1253 (*value, ScriptBuf::new_p2wsh(&WScriptHash::from_slice(&[2; 32]).unwrap()))
1255 TestOutput::P2TR(value) => (
1257 ScriptBuf::new_p2tr(
1259 UntweakedPublicKey::from_keypair(
1260 &Keypair::from_seckey_slice(&secp_ctx, &[3; 32]).unwrap(),
1266 TestOutput::P2PKH(value) => {
1267 (*value, ScriptBuf::new_p2pkh(&PubkeyHash::from_slice(&[4; 20]).unwrap()))
1271 TxOut { value: Amount::from_sat(value), script_pubkey }
1274 fn generate_tx_with_locktime(outputs: &[TestOutput], locktime: u32) -> Transaction {
1276 version: Version::TWO,
1277 lock_time: AbsoluteLockTime::from_height(locktime).unwrap(),
1278 input: vec![TxIn { ..Default::default() }],
1279 output: outputs.iter().map(generate_txout).collect(),
1283 fn generate_inputs(outputs: &[TestOutput]) -> Vec<(TxIn, TransactionU16LenLimited)> {
1284 let tx = generate_tx(outputs);
1285 let txid = tx.txid();
1291 previous_output: OutPoint { txid, vout: idx as u32 },
1292 script_sig: Default::default(),
1293 sequence: Sequence::ENABLE_RBF_NO_LOCKTIME,
1294 witness: Default::default(),
1296 (input, TransactionU16LenLimited::new(tx.clone()).unwrap())
1301 fn generate_p2wsh_script_pubkey() -> ScriptBuf {
1302 Builder::new().push_opcode(opcodes::OP_TRUE).into_script().to_p2wsh()
1305 fn generate_p2wpkh_script_pubkey() -> ScriptBuf {
1306 ScriptBuf::new_p2wpkh(&WPubkeyHash::from_slice(&[1; 20]).unwrap())
1309 fn generate_outputs(outputs: &[TestOutput]) -> Vec<TxOut> {
1310 outputs.iter().map(generate_txout).collect()
1313 fn generate_fixed_number_of_inputs(count: u16) -> Vec<(TxIn, TransactionU16LenLimited)> {
1314 // Generate transactions with a total `count` number of outputs such that no transaction has a
1315 // serialized length greater than u16::MAX.
1316 let max_outputs_per_prevtx = 1_500;
1317 let mut remaining = count;
1318 let mut inputs: Vec<(TxIn, TransactionU16LenLimited)> = Vec::with_capacity(count as usize);
1320 while remaining > 0 {
1321 let tx_output_count = remaining.min(max_outputs_per_prevtx);
1322 remaining -= tx_output_count;
1324 // Use unique locktime for each tx so outpoints are different across transactions
1325 let tx = generate_tx_with_locktime(
1326 &vec![TestOutput::P2WPKH(1_000_000); tx_output_count as usize],
1327 (1337 + remaining).into(),
1329 let txid = tx.txid();
1331 let mut temp: Vec<(TxIn, TransactionU16LenLimited)> = tx
1337 previous_output: OutPoint { txid, vout: idx as u32 },
1338 script_sig: Default::default(),
1339 sequence: Sequence::ENABLE_RBF_NO_LOCKTIME,
1340 witness: Default::default(),
1342 (input, TransactionU16LenLimited::new(tx.clone()).unwrap())
1346 inputs.append(&mut temp);
1352 fn generate_fixed_number_of_outputs(count: u16) -> Vec<TxOut> {
1353 // Set a constant value for each TxOut
1354 generate_outputs(&vec![TestOutput::P2WPKH(1_000_000); count as usize])
1357 fn generate_p2sh_script_pubkey() -> ScriptBuf {
1358 Builder::new().push_opcode(opcodes::OP_TRUE).into_script().to_p2sh()
1361 fn generate_non_witness_output(value: u64) -> TxOut {
1362 TxOut { value: Amount::from_sat(value), script_pubkey: generate_p2sh_script_pubkey() }
1366 fn test_interactive_tx_constructor() {
1367 do_test_interactive_tx_constructor(TestSession {
1368 description: "No contributions",
1373 expect_error: Some((AbortReason::InsufficientFees, ErrorCulprit::NodeA)),
1375 do_test_interactive_tx_constructor(TestSession {
1376 description: "Single contribution, no initiator inputs",
1378 outputs_a: generate_outputs(&[TestOutput::P2WPKH(1_000_000)]),
1381 expect_error: Some((AbortReason::OutputsValueExceedsInputsValue, ErrorCulprit::NodeA)),
1383 do_test_interactive_tx_constructor(TestSession {
1384 description: "Single contribution, no initiator outputs",
1385 inputs_a: generate_inputs(&[TestOutput::P2WPKH(1_000_000)]),
1391 do_test_interactive_tx_constructor(TestSession {
1392 description: "Single contribution, no fees",
1393 inputs_a: generate_inputs(&[TestOutput::P2WPKH(1_000_000)]),
1394 outputs_a: generate_outputs(&[TestOutput::P2WPKH(1_000_000)]),
1397 expect_error: Some((AbortReason::InsufficientFees, ErrorCulprit::NodeA)),
1399 let p2wpkh_fee = fee_for_weight(TEST_FEERATE_SATS_PER_KW, P2WPKH_INPUT_WEIGHT_LOWER_BOUND);
1400 let outputs_fee = fee_for_weight(
1401 TEST_FEERATE_SATS_PER_KW,
1402 get_output_weight(&generate_p2wpkh_script_pubkey()).to_wu(),
1404 let tx_common_fields_fee =
1405 fee_for_weight(TEST_FEERATE_SATS_PER_KW, TX_COMMON_FIELDS_WEIGHT);
1406 do_test_interactive_tx_constructor(TestSession {
1407 description: "Single contribution, with P2WPKH input, insufficient fees",
1408 inputs_a: generate_inputs(&[TestOutput::P2WPKH(1_000_000)]),
1409 outputs_a: generate_outputs(&[TestOutput::P2WPKH(
1410 1_000_000 - p2wpkh_fee - outputs_fee - tx_common_fields_fee + 1, /* makes fees insuffcient for initiator */
1414 expect_error: Some((AbortReason::InsufficientFees, ErrorCulprit::NodeA)),
1416 do_test_interactive_tx_constructor(TestSession {
1417 description: "Single contribution with P2WPKH input, sufficient fees",
1418 inputs_a: generate_inputs(&[TestOutput::P2WPKH(1_000_000)]),
1419 outputs_a: generate_outputs(&[TestOutput::P2WPKH(
1420 1_000_000 - p2wpkh_fee - outputs_fee - tx_common_fields_fee,
1426 let p2wsh_fee = fee_for_weight(TEST_FEERATE_SATS_PER_KW, P2WSH_INPUT_WEIGHT_LOWER_BOUND);
1427 do_test_interactive_tx_constructor(TestSession {
1428 description: "Single contribution, with P2WSH input, insufficient fees",
1429 inputs_a: generate_inputs(&[TestOutput::P2WSH(1_000_000)]),
1430 outputs_a: generate_outputs(&[TestOutput::P2WPKH(
1431 1_000_000 - p2wsh_fee - outputs_fee - tx_common_fields_fee + 1, /* makes fees insuffcient for initiator */
1435 expect_error: Some((AbortReason::InsufficientFees, ErrorCulprit::NodeA)),
1437 do_test_interactive_tx_constructor(TestSession {
1438 description: "Single contribution with P2WSH input, sufficient fees",
1439 inputs_a: generate_inputs(&[TestOutput::P2WSH(1_000_000)]),
1440 outputs_a: generate_outputs(&[TestOutput::P2WPKH(
1441 1_000_000 - p2wsh_fee - outputs_fee - tx_common_fields_fee,
1447 let p2tr_fee = fee_for_weight(TEST_FEERATE_SATS_PER_KW, P2TR_INPUT_WEIGHT_LOWER_BOUND);
1448 do_test_interactive_tx_constructor(TestSession {
1449 description: "Single contribution, with P2TR input, insufficient fees",
1450 inputs_a: generate_inputs(&[TestOutput::P2TR(1_000_000)]),
1451 outputs_a: generate_outputs(&[TestOutput::P2WPKH(
1452 1_000_000 - p2tr_fee - outputs_fee - tx_common_fields_fee + 1, /* makes fees insuffcient for initiator */
1456 expect_error: Some((AbortReason::InsufficientFees, ErrorCulprit::NodeA)),
1458 do_test_interactive_tx_constructor(TestSession {
1459 description: "Single contribution with P2TR input, sufficient fees",
1460 inputs_a: generate_inputs(&[TestOutput::P2TR(1_000_000)]),
1461 outputs_a: generate_outputs(&[TestOutput::P2WPKH(
1462 1_000_000 - p2tr_fee - outputs_fee - tx_common_fields_fee,
1468 do_test_interactive_tx_constructor(TestSession {
1469 description: "Initiator contributes sufficient fees, but non-initiator does not",
1470 inputs_a: generate_inputs(&[TestOutput::P2WPKH(1_000_000)]),
1472 inputs_b: generate_inputs(&[TestOutput::P2WPKH(100_000)]),
1473 outputs_b: generate_outputs(&[TestOutput::P2WPKH(100_000)]),
1474 expect_error: Some((AbortReason::InsufficientFees, ErrorCulprit::NodeB)),
1476 do_test_interactive_tx_constructor(TestSession {
1477 description: "Multi-input-output contributions from both sides",
1478 inputs_a: generate_inputs(&[TestOutput::P2WPKH(1_000_000); 2]),
1479 outputs_a: generate_outputs(&[
1480 TestOutput::P2WPKH(1_000_000),
1481 TestOutput::P2WPKH(200_000),
1483 inputs_b: generate_inputs(&[
1484 TestOutput::P2WPKH(1_000_000),
1485 TestOutput::P2WPKH(500_000),
1487 outputs_b: generate_outputs(&[
1488 TestOutput::P2WPKH(1_000_000),
1489 TestOutput::P2WPKH(400_000),
1494 do_test_interactive_tx_constructor(TestSession {
1495 description: "Prevout from initiator is not a witness program",
1496 inputs_a: generate_inputs(&[TestOutput::P2PKH(1_000_000)]),
1500 expect_error: Some((AbortReason::PrevTxOutInvalid, ErrorCulprit::NodeA)),
1504 TransactionU16LenLimited::new(generate_tx(&[TestOutput::P2WPKH(1_000_000)])).unwrap();
1505 let invalid_sequence_input = TxIn {
1506 previous_output: OutPoint { txid: tx.as_transaction().txid(), vout: 0 },
1507 ..Default::default()
1509 do_test_interactive_tx_constructor(TestSession {
1510 description: "Invalid input sequence from initiator",
1511 inputs_a: vec![(invalid_sequence_input, tx.clone())],
1512 outputs_a: generate_outputs(&[TestOutput::P2WPKH(1_000_000)]),
1515 expect_error: Some((AbortReason::IncorrectInputSequenceValue, ErrorCulprit::NodeA)),
1517 let duplicate_input = TxIn {
1518 previous_output: OutPoint { txid: tx.as_transaction().txid(), vout: 0 },
1519 sequence: Sequence::ENABLE_RBF_NO_LOCKTIME,
1520 ..Default::default()
1522 do_test_interactive_tx_constructor(TestSession {
1523 description: "Duplicate prevout from initiator",
1524 inputs_a: vec![(duplicate_input.clone(), tx.clone()), (duplicate_input, tx.clone())],
1525 outputs_a: generate_outputs(&[TestOutput::P2WPKH(1_000_000)]),
1528 expect_error: Some((AbortReason::PrevTxOutInvalid, ErrorCulprit::NodeB)),
1530 let duplicate_input = TxIn {
1531 previous_output: OutPoint { txid: tx.as_transaction().txid(), vout: 0 },
1532 sequence: Sequence::ENABLE_RBF_NO_LOCKTIME,
1533 ..Default::default()
1535 do_test_interactive_tx_constructor(TestSession {
1536 description: "Non-initiator uses same prevout as initiator",
1537 inputs_a: vec![(duplicate_input.clone(), tx.clone())],
1538 outputs_a: generate_outputs(&[TestOutput::P2WPKH(1_000_000)]),
1539 inputs_b: vec![(duplicate_input.clone(), tx.clone())],
1541 expect_error: Some((AbortReason::PrevTxOutInvalid, ErrorCulprit::NodeA)),
1543 do_test_interactive_tx_constructor(TestSession {
1544 description: "Initiator sends too many TxAddInputs",
1545 inputs_a: generate_fixed_number_of_inputs(MAX_RECEIVED_TX_ADD_INPUT_COUNT + 1),
1549 expect_error: Some((AbortReason::ReceivedTooManyTxAddInputs, ErrorCulprit::NodeA)),
1551 do_test_interactive_tx_constructor_with_entropy_source(
1553 // We use a deliberately bad entropy source, `DuplicateEntropySource` to simulate this.
1554 description: "Attempt to queue up two inputs with duplicate serial ids",
1555 inputs_a: generate_fixed_number_of_inputs(2),
1559 expect_error: Some((AbortReason::DuplicateSerialId, ErrorCulprit::NodeA)),
1561 &DuplicateEntropySource,
1563 do_test_interactive_tx_constructor(TestSession {
1564 description: "Initiator sends too many TxAddOutputs",
1566 outputs_a: generate_fixed_number_of_outputs(MAX_RECEIVED_TX_ADD_OUTPUT_COUNT + 1),
1569 expect_error: Some((AbortReason::ReceivedTooManyTxAddOutputs, ErrorCulprit::NodeA)),
1571 do_test_interactive_tx_constructor(TestSession {
1572 description: "Initiator sends an output below dust value",
1574 outputs_a: generate_outputs(&[TestOutput::P2WSH(
1575 generate_p2wsh_script_pubkey().dust_value().to_sat() - 1,
1579 expect_error: Some((AbortReason::BelowDustLimit, ErrorCulprit::NodeA)),
1581 do_test_interactive_tx_constructor(TestSession {
1582 description: "Initiator sends an output above maximum sats allowed",
1584 outputs_a: generate_outputs(&[TestOutput::P2WPKH(TOTAL_BITCOIN_SUPPLY_SATOSHIS + 1)]),
1587 expect_error: Some((AbortReason::ExceededMaximumSatsAllowed, ErrorCulprit::NodeA)),
1589 do_test_interactive_tx_constructor(TestSession {
1590 description: "Initiator sends an output without a witness program",
1592 outputs_a: vec![generate_non_witness_output(1_000_000)],
1595 expect_error: Some((AbortReason::InvalidOutputScript, ErrorCulprit::NodeA)),
1597 do_test_interactive_tx_constructor_with_entropy_source(
1599 // We use a deliberately bad entropy source, `DuplicateEntropySource` to simulate this.
1600 description: "Attempt to queue up two outputs with duplicate serial ids",
1602 outputs_a: generate_fixed_number_of_outputs(2),
1605 expect_error: Some((AbortReason::DuplicateSerialId, ErrorCulprit::NodeA)),
1607 &DuplicateEntropySource,
1610 do_test_interactive_tx_constructor(TestSession {
1611 description: "Peer contributed more output value than inputs",
1612 inputs_a: generate_inputs(&[TestOutput::P2WPKH(100_000)]),
1613 outputs_a: generate_outputs(&[TestOutput::P2WPKH(1_000_000)]),
1616 expect_error: Some((AbortReason::OutputsValueExceedsInputsValue, ErrorCulprit::NodeA)),
1619 do_test_interactive_tx_constructor(TestSession {
1620 description: "Peer contributed more than allowed number of inputs",
1621 inputs_a: generate_fixed_number_of_inputs(MAX_INPUTS_OUTPUTS_COUNT as u16 + 1),
1625 expect_error: Some((
1626 AbortReason::ExceededNumberOfInputsOrOutputs,
1627 ErrorCulprit::Indeterminate,
1630 do_test_interactive_tx_constructor(TestSession {
1631 description: "Peer contributed more than allowed number of outputs",
1632 inputs_a: generate_inputs(&[TestOutput::P2WPKH(TOTAL_BITCOIN_SUPPLY_SATOSHIS)]),
1633 outputs_a: generate_fixed_number_of_outputs(MAX_INPUTS_OUTPUTS_COUNT as u16 + 1),
1636 expect_error: Some((
1637 AbortReason::ExceededNumberOfInputsOrOutputs,
1638 ErrorCulprit::Indeterminate,
1644 fn test_generate_local_serial_id() {
1645 let entropy_source = TestEntropySource(AtomicCounter::new());
1647 // Initiators should have even serial id, non-initiators should have odd serial id.
1648 assert_eq!(generate_holder_serial_id(&&entropy_source, true) % 2, 0);
1649 assert_eq!(generate_holder_serial_id(&&entropy_source, false) % 2, 1)