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(),
946 do_state_transition!(self, sent_tx_add_input, &msg)?;
947 Ok(InteractiveTxMessageSend::TxAddInput(msg))
948 } else if let Some((serial_id, output)) = self.outputs_to_contribute.pop() {
949 let msg = msgs::TxAddOutput {
950 channel_id: self.channel_id,
952 sats: output.value.to_sat(),
953 script: output.script_pubkey,
955 do_state_transition!(self, sent_tx_add_output, &msg)?;
956 Ok(InteractiveTxMessageSend::TxAddOutput(msg))
958 let msg = msgs::TxComplete { channel_id: self.channel_id };
959 do_state_transition!(self, sent_tx_complete, &msg)?;
960 Ok(InteractiveTxMessageSend::TxComplete(msg))
964 pub fn handle_tx_add_input(
965 &mut self, msg: &msgs::TxAddInput,
966 ) -> Result<InteractiveTxMessageSend, AbortReason> {
967 do_state_transition!(self, received_tx_add_input, msg)?;
968 self.maybe_send_message()
971 pub fn handle_tx_remove_input(
972 &mut self, msg: &msgs::TxRemoveInput,
973 ) -> Result<InteractiveTxMessageSend, AbortReason> {
974 do_state_transition!(self, received_tx_remove_input, msg)?;
975 self.maybe_send_message()
978 pub fn handle_tx_add_output(
979 &mut self, msg: &msgs::TxAddOutput,
980 ) -> Result<InteractiveTxMessageSend, AbortReason> {
981 do_state_transition!(self, received_tx_add_output, msg)?;
982 self.maybe_send_message()
985 pub fn handle_tx_remove_output(
986 &mut self, msg: &msgs::TxRemoveOutput,
987 ) -> Result<InteractiveTxMessageSend, AbortReason> {
988 do_state_transition!(self, received_tx_remove_output, msg)?;
989 self.maybe_send_message()
992 pub fn handle_tx_complete(
993 &mut self, msg: &msgs::TxComplete,
994 ) -> Result<HandleTxCompleteValue, AbortReason> {
995 do_state_transition!(self, received_tx_complete, msg)?;
996 match &self.state_machine {
997 StateMachine::ReceivedTxComplete(_) => {
998 let msg_send = self.maybe_send_message()?;
999 match &self.state_machine {
1000 StateMachine::NegotiationComplete(s) => {
1001 Ok(HandleTxCompleteValue::SendTxComplete(msg_send, s.0.clone()))
1003 StateMachine::SentChangeMsg(_) => {
1004 Ok(HandleTxCompleteValue::SendTxMessage(msg_send))
1005 }, // We either had an input or output to contribute.
1007 debug_assert!(false, "We cannot transition to any other states after receiving `tx_complete` and responding");
1008 Err(AbortReason::InvalidStateTransition)
1012 StateMachine::NegotiationComplete(s) => {
1013 Ok(HandleTxCompleteValue::NegotiationComplete(s.0.clone()))
1018 "We cannot transition to any other states after receiving `tx_complete`"
1020 Err(AbortReason::InvalidStateTransition)
1028 use crate::chain::chaininterface::{fee_for_weight, FEERATE_FLOOR_SATS_PER_KW};
1029 use crate::ln::channel::TOTAL_BITCOIN_SUPPLY_SATOSHIS;
1030 use crate::ln::interactivetxs::{
1031 generate_holder_serial_id, AbortReason, HandleTxCompleteValue, InteractiveTxConstructor,
1032 InteractiveTxMessageSend, MAX_INPUTS_OUTPUTS_COUNT, MAX_RECEIVED_TX_ADD_INPUT_COUNT,
1033 MAX_RECEIVED_TX_ADD_OUTPUT_COUNT,
1035 use crate::ln::types::ChannelId;
1036 use crate::sign::EntropySource;
1037 use crate::util::atomic_counter::AtomicCounter;
1038 use crate::util::ser::TransactionU16LenLimited;
1039 use bitcoin::amount::Amount;
1040 use bitcoin::blockdata::opcodes;
1041 use bitcoin::blockdata::script::Builder;
1042 use bitcoin::hashes::Hash;
1043 use bitcoin::key::UntweakedPublicKey;
1044 use bitcoin::secp256k1::{Keypair, Secp256k1};
1045 use bitcoin::transaction::Version;
1047 absolute::LockTime as AbsoluteLockTime, OutPoint, Sequence, Transaction, TxIn, TxOut,
1049 use bitcoin::{PubkeyHash, ScriptBuf, WPubkeyHash, WScriptHash};
1050 use core::ops::Deref;
1053 get_output_weight, P2TR_INPUT_WEIGHT_LOWER_BOUND, P2WPKH_INPUT_WEIGHT_LOWER_BOUND,
1054 P2WSH_INPUT_WEIGHT_LOWER_BOUND, TX_COMMON_FIELDS_WEIGHT,
1057 const TEST_FEERATE_SATS_PER_KW: u32 = FEERATE_FLOOR_SATS_PER_KW * 10;
1059 // A simple entropy source that works based on an atomic counter.
1060 struct TestEntropySource(AtomicCounter);
1061 impl EntropySource for TestEntropySource {
1062 fn get_secure_random_bytes(&self) -> [u8; 32] {
1063 let mut res = [0u8; 32];
1064 let increment = self.0.get_increment();
1066 // Rotate the increment value by 'i' bits to the right, to avoid clashes
1067 // when `generate_local_serial_id` does a parity flip on consecutive calls for the
1069 let rotated_increment = increment.rotate_right(i as u32);
1070 res[i] = (rotated_increment & 0xff) as u8;
1076 // An entropy source that deliberately returns you the same seed every time. We use this
1077 // to test if the constructor would catch inputs/outputs that are attempting to be added
1078 // with duplicate serial ids.
1079 struct DuplicateEntropySource;
1080 impl EntropySource for DuplicateEntropySource {
1081 fn get_secure_random_bytes(&self) -> [u8; 32] {
1082 let mut res = [0u8; 32];
1084 res[0..8].copy_from_slice(&count.to_be_bytes());
1089 #[derive(Debug, PartialEq, Eq)]
1093 // Some error values are only checked at the end of the negotiation and are not easy to attribute
1094 // to a particular party. Both parties would indicate an `AbortReason` in this case.
1095 // e.g. Exceeded max inputs and outputs after negotiation.
1099 struct TestSession {
1100 description: &'static str,
1101 inputs_a: Vec<(TxIn, TransactionU16LenLimited)>,
1102 outputs_a: Vec<TxOut>,
1103 inputs_b: Vec<(TxIn, TransactionU16LenLimited)>,
1104 outputs_b: Vec<TxOut>,
1105 expect_error: Option<(AbortReason, ErrorCulprit)>,
1108 fn do_test_interactive_tx_constructor(session: TestSession) {
1109 let entropy_source = TestEntropySource(AtomicCounter::new());
1110 do_test_interactive_tx_constructor_internal(session, &&entropy_source);
1113 fn do_test_interactive_tx_constructor_with_entropy_source<ES: Deref>(
1114 session: TestSession, entropy_source: ES,
1116 ES::Target: EntropySource,
1118 do_test_interactive_tx_constructor_internal(session, &entropy_source);
1121 fn do_test_interactive_tx_constructor_internal<ES: Deref>(
1122 session: TestSession, entropy_source: &ES,
1124 ES::Target: EntropySource,
1126 let channel_id = ChannelId(entropy_source.get_secure_random_bytes());
1127 let tx_locktime = AbsoluteLockTime::from_height(1337).unwrap();
1129 let (mut constructor_a, first_message_a) = InteractiveTxConstructor::new(
1132 TEST_FEERATE_SATS_PER_KW,
1138 let (mut constructor_b, first_message_b) = InteractiveTxConstructor::new(
1141 TEST_FEERATE_SATS_PER_KW,
1148 let handle_message_send =
1149 |msg: InteractiveTxMessageSend, for_constructor: &mut InteractiveTxConstructor| {
1151 InteractiveTxMessageSend::TxAddInput(msg) => for_constructor
1152 .handle_tx_add_input(&msg)
1153 .map(|msg_send| (Some(msg_send), None)),
1154 InteractiveTxMessageSend::TxAddOutput(msg) => for_constructor
1155 .handle_tx_add_output(&msg)
1156 .map(|msg_send| (Some(msg_send), None)),
1157 InteractiveTxMessageSend::TxComplete(msg) => {
1158 for_constructor.handle_tx_complete(&msg).map(|value| match value {
1159 HandleTxCompleteValue::SendTxMessage(msg_send) => {
1160 (Some(msg_send), None)
1162 HandleTxCompleteValue::SendTxComplete(msg_send, tx) => {
1163 (Some(msg_send), Some(tx))
1165 HandleTxCompleteValue::NegotiationComplete(tx) => (None, Some(tx)),
1171 assert!(first_message_b.is_none());
1172 let mut message_send_a = first_message_a;
1173 let mut message_send_b = None;
1174 let mut final_tx_a = None;
1175 let mut final_tx_b = None;
1176 while final_tx_a.is_none() || final_tx_b.is_none() {
1177 if let Some(message_send_a) = message_send_a.take() {
1178 match handle_message_send(message_send_a, &mut constructor_b) {
1179 Ok((msg_send, final_tx)) => {
1180 message_send_b = msg_send;
1181 final_tx_b = final_tx;
1183 Err(abort_reason) => {
1184 let error_culprit = match abort_reason {
1185 AbortReason::ExceededNumberOfInputsOrOutputs => {
1186 ErrorCulprit::Indeterminate
1188 _ => ErrorCulprit::NodeA,
1191 Some((abort_reason, error_culprit)),
1192 session.expect_error,
1196 assert!(message_send_b.is_none());
1201 if let Some(message_send_b) = message_send_b.take() {
1202 match handle_message_send(message_send_b, &mut constructor_a) {
1203 Ok((msg_send, final_tx)) => {
1204 message_send_a = msg_send;
1205 final_tx_a = final_tx;
1207 Err(abort_reason) => {
1208 let error_culprit = match abort_reason {
1209 AbortReason::ExceededNumberOfInputsOrOutputs => {
1210 ErrorCulprit::Indeterminate
1212 _ => ErrorCulprit::NodeB,
1215 Some((abort_reason, error_culprit)),
1216 session.expect_error,
1220 assert!(message_send_a.is_none());
1226 assert!(message_send_a.is_none());
1227 assert!(message_send_b.is_none());
1228 assert_eq!(final_tx_a.unwrap().into_unsigned_tx(), final_tx_b.unwrap().into_unsigned_tx());
1229 assert!(session.expect_error.is_none(), "Test: {}", session.description);
1232 #[derive(Debug, Clone, Copy)]
1237 // Non-witness type to test rejection.
1241 fn generate_tx(outputs: &[TestOutput]) -> Transaction {
1242 generate_tx_with_locktime(outputs, 1337)
1245 fn generate_txout(output: &TestOutput) -> TxOut {
1246 let secp_ctx = Secp256k1::new();
1247 let (value, script_pubkey) = match output {
1248 TestOutput::P2WPKH(value) => {
1249 (*value, ScriptBuf::new_p2wpkh(&WPubkeyHash::from_slice(&[1; 20]).unwrap()))
1251 TestOutput::P2WSH(value) => {
1252 (*value, ScriptBuf::new_p2wsh(&WScriptHash::from_slice(&[2; 32]).unwrap()))
1254 TestOutput::P2TR(value) => (
1256 ScriptBuf::new_p2tr(
1258 UntweakedPublicKey::from_keypair(
1259 &Keypair::from_seckey_slice(&secp_ctx, &[3; 32]).unwrap(),
1265 TestOutput::P2PKH(value) => {
1266 (*value, ScriptBuf::new_p2pkh(&PubkeyHash::from_slice(&[4; 20]).unwrap()))
1270 TxOut { value: Amount::from_sat(value), script_pubkey }
1273 fn generate_tx_with_locktime(outputs: &[TestOutput], locktime: u32) -> Transaction {
1275 version: Version::TWO,
1276 lock_time: AbsoluteLockTime::from_height(locktime).unwrap(),
1277 input: vec![TxIn { ..Default::default() }],
1278 output: outputs.iter().map(generate_txout).collect(),
1282 fn generate_inputs(outputs: &[TestOutput]) -> Vec<(TxIn, TransactionU16LenLimited)> {
1283 let tx = generate_tx(outputs);
1284 let txid = tx.txid();
1290 previous_output: OutPoint { txid, vout: idx as u32 },
1291 script_sig: Default::default(),
1292 sequence: Sequence::ENABLE_RBF_NO_LOCKTIME,
1293 witness: Default::default(),
1295 (input, TransactionU16LenLimited::new(tx.clone()).unwrap())
1300 fn generate_p2wsh_script_pubkey() -> ScriptBuf {
1301 Builder::new().push_opcode(opcodes::OP_TRUE).into_script().to_p2wsh()
1304 fn generate_p2wpkh_script_pubkey() -> ScriptBuf {
1305 ScriptBuf::new_p2wpkh(&WPubkeyHash::from_slice(&[1; 20]).unwrap())
1308 fn generate_outputs(outputs: &[TestOutput]) -> Vec<TxOut> {
1309 outputs.iter().map(generate_txout).collect()
1312 fn generate_fixed_number_of_inputs(count: u16) -> Vec<(TxIn, TransactionU16LenLimited)> {
1313 // Generate transactions with a total `count` number of outputs such that no transaction has a
1314 // serialized length greater than u16::MAX.
1315 let max_outputs_per_prevtx = 1_500;
1316 let mut remaining = count;
1317 let mut inputs: Vec<(TxIn, TransactionU16LenLimited)> = Vec::with_capacity(count as usize);
1319 while remaining > 0 {
1320 let tx_output_count = remaining.min(max_outputs_per_prevtx);
1321 remaining -= tx_output_count;
1323 // Use unique locktime for each tx so outpoints are different across transactions
1324 let tx = generate_tx_with_locktime(
1325 &vec![TestOutput::P2WPKH(1_000_000); tx_output_count as usize],
1326 (1337 + remaining).into(),
1328 let txid = tx.txid();
1330 let mut temp: Vec<(TxIn, TransactionU16LenLimited)> = tx
1336 previous_output: OutPoint { txid, vout: idx as u32 },
1337 script_sig: Default::default(),
1338 sequence: Sequence::ENABLE_RBF_NO_LOCKTIME,
1339 witness: Default::default(),
1341 (input, TransactionU16LenLimited::new(tx.clone()).unwrap())
1345 inputs.append(&mut temp);
1351 fn generate_fixed_number_of_outputs(count: u16) -> Vec<TxOut> {
1352 // Set a constant value for each TxOut
1353 generate_outputs(&vec![TestOutput::P2WPKH(1_000_000); count as usize])
1356 fn generate_p2sh_script_pubkey() -> ScriptBuf {
1357 Builder::new().push_opcode(opcodes::OP_TRUE).into_script().to_p2sh()
1360 fn generate_non_witness_output(value: u64) -> TxOut {
1361 TxOut { value: Amount::from_sat(value), script_pubkey: generate_p2sh_script_pubkey() }
1365 fn test_interactive_tx_constructor() {
1366 do_test_interactive_tx_constructor(TestSession {
1367 description: "No contributions",
1372 expect_error: Some((AbortReason::InsufficientFees, ErrorCulprit::NodeA)),
1374 do_test_interactive_tx_constructor(TestSession {
1375 description: "Single contribution, no initiator inputs",
1377 outputs_a: generate_outputs(&[TestOutput::P2WPKH(1_000_000)]),
1380 expect_error: Some((AbortReason::OutputsValueExceedsInputsValue, ErrorCulprit::NodeA)),
1382 do_test_interactive_tx_constructor(TestSession {
1383 description: "Single contribution, no initiator outputs",
1384 inputs_a: generate_inputs(&[TestOutput::P2WPKH(1_000_000)]),
1390 do_test_interactive_tx_constructor(TestSession {
1391 description: "Single contribution, no fees",
1392 inputs_a: generate_inputs(&[TestOutput::P2WPKH(1_000_000)]),
1393 outputs_a: generate_outputs(&[TestOutput::P2WPKH(1_000_000)]),
1396 expect_error: Some((AbortReason::InsufficientFees, ErrorCulprit::NodeA)),
1398 let p2wpkh_fee = fee_for_weight(TEST_FEERATE_SATS_PER_KW, P2WPKH_INPUT_WEIGHT_LOWER_BOUND);
1399 let outputs_fee = fee_for_weight(
1400 TEST_FEERATE_SATS_PER_KW,
1401 get_output_weight(&generate_p2wpkh_script_pubkey()).to_wu(),
1403 let tx_common_fields_fee =
1404 fee_for_weight(TEST_FEERATE_SATS_PER_KW, TX_COMMON_FIELDS_WEIGHT);
1405 do_test_interactive_tx_constructor(TestSession {
1406 description: "Single contribution, with P2WPKH input, insufficient fees",
1407 inputs_a: generate_inputs(&[TestOutput::P2WPKH(1_000_000)]),
1408 outputs_a: generate_outputs(&[TestOutput::P2WPKH(
1409 1_000_000 - p2wpkh_fee - outputs_fee - tx_common_fields_fee + 1, /* makes fees insuffcient for initiator */
1413 expect_error: Some((AbortReason::InsufficientFees, ErrorCulprit::NodeA)),
1415 do_test_interactive_tx_constructor(TestSession {
1416 description: "Single contribution with P2WPKH input, sufficient fees",
1417 inputs_a: generate_inputs(&[TestOutput::P2WPKH(1_000_000)]),
1418 outputs_a: generate_outputs(&[TestOutput::P2WPKH(
1419 1_000_000 - p2wpkh_fee - outputs_fee - tx_common_fields_fee,
1425 let p2wsh_fee = fee_for_weight(TEST_FEERATE_SATS_PER_KW, P2WSH_INPUT_WEIGHT_LOWER_BOUND);
1426 do_test_interactive_tx_constructor(TestSession {
1427 description: "Single contribution, with P2WSH input, insufficient fees",
1428 inputs_a: generate_inputs(&[TestOutput::P2WSH(1_000_000)]),
1429 outputs_a: generate_outputs(&[TestOutput::P2WPKH(
1430 1_000_000 - p2wsh_fee - outputs_fee - tx_common_fields_fee + 1, /* makes fees insuffcient for initiator */
1434 expect_error: Some((AbortReason::InsufficientFees, ErrorCulprit::NodeA)),
1436 do_test_interactive_tx_constructor(TestSession {
1437 description: "Single contribution with P2WSH input, sufficient fees",
1438 inputs_a: generate_inputs(&[TestOutput::P2WSH(1_000_000)]),
1439 outputs_a: generate_outputs(&[TestOutput::P2WPKH(
1440 1_000_000 - p2wsh_fee - outputs_fee - tx_common_fields_fee,
1446 let p2tr_fee = fee_for_weight(TEST_FEERATE_SATS_PER_KW, P2TR_INPUT_WEIGHT_LOWER_BOUND);
1447 do_test_interactive_tx_constructor(TestSession {
1448 description: "Single contribution, with P2TR input, insufficient fees",
1449 inputs_a: generate_inputs(&[TestOutput::P2TR(1_000_000)]),
1450 outputs_a: generate_outputs(&[TestOutput::P2WPKH(
1451 1_000_000 - p2tr_fee - outputs_fee - tx_common_fields_fee + 1, /* makes fees insuffcient for initiator */
1455 expect_error: Some((AbortReason::InsufficientFees, ErrorCulprit::NodeA)),
1457 do_test_interactive_tx_constructor(TestSession {
1458 description: "Single contribution with P2TR input, sufficient fees",
1459 inputs_a: generate_inputs(&[TestOutput::P2TR(1_000_000)]),
1460 outputs_a: generate_outputs(&[TestOutput::P2WPKH(
1461 1_000_000 - p2tr_fee - outputs_fee - tx_common_fields_fee,
1467 do_test_interactive_tx_constructor(TestSession {
1468 description: "Initiator contributes sufficient fees, but non-initiator does not",
1469 inputs_a: generate_inputs(&[TestOutput::P2WPKH(1_000_000)]),
1471 inputs_b: generate_inputs(&[TestOutput::P2WPKH(100_000)]),
1472 outputs_b: generate_outputs(&[TestOutput::P2WPKH(100_000)]),
1473 expect_error: Some((AbortReason::InsufficientFees, ErrorCulprit::NodeB)),
1475 do_test_interactive_tx_constructor(TestSession {
1476 description: "Multi-input-output contributions from both sides",
1477 inputs_a: generate_inputs(&[TestOutput::P2WPKH(1_000_000); 2]),
1478 outputs_a: generate_outputs(&[
1479 TestOutput::P2WPKH(1_000_000),
1480 TestOutput::P2WPKH(200_000),
1482 inputs_b: generate_inputs(&[
1483 TestOutput::P2WPKH(1_000_000),
1484 TestOutput::P2WPKH(500_000),
1486 outputs_b: generate_outputs(&[
1487 TestOutput::P2WPKH(1_000_000),
1488 TestOutput::P2WPKH(400_000),
1493 do_test_interactive_tx_constructor(TestSession {
1494 description: "Prevout from initiator is not a witness program",
1495 inputs_a: generate_inputs(&[TestOutput::P2PKH(1_000_000)]),
1499 expect_error: Some((AbortReason::PrevTxOutInvalid, ErrorCulprit::NodeA)),
1503 TransactionU16LenLimited::new(generate_tx(&[TestOutput::P2WPKH(1_000_000)])).unwrap();
1504 let invalid_sequence_input = TxIn {
1505 previous_output: OutPoint { txid: tx.as_transaction().txid(), vout: 0 },
1506 ..Default::default()
1508 do_test_interactive_tx_constructor(TestSession {
1509 description: "Invalid input sequence from initiator",
1510 inputs_a: vec![(invalid_sequence_input, tx.clone())],
1511 outputs_a: generate_outputs(&[TestOutput::P2WPKH(1_000_000)]),
1514 expect_error: Some((AbortReason::IncorrectInputSequenceValue, ErrorCulprit::NodeA)),
1516 let duplicate_input = TxIn {
1517 previous_output: OutPoint { txid: tx.as_transaction().txid(), vout: 0 },
1518 sequence: Sequence::ENABLE_RBF_NO_LOCKTIME,
1519 ..Default::default()
1521 do_test_interactive_tx_constructor(TestSession {
1522 description: "Duplicate prevout from initiator",
1523 inputs_a: vec![(duplicate_input.clone(), tx.clone()), (duplicate_input, tx.clone())],
1524 outputs_a: generate_outputs(&[TestOutput::P2WPKH(1_000_000)]),
1527 expect_error: Some((AbortReason::PrevTxOutInvalid, ErrorCulprit::NodeB)),
1529 let duplicate_input = TxIn {
1530 previous_output: OutPoint { txid: tx.as_transaction().txid(), vout: 0 },
1531 sequence: Sequence::ENABLE_RBF_NO_LOCKTIME,
1532 ..Default::default()
1534 do_test_interactive_tx_constructor(TestSession {
1535 description: "Non-initiator uses same prevout as initiator",
1536 inputs_a: vec![(duplicate_input.clone(), tx.clone())],
1537 outputs_a: generate_outputs(&[TestOutput::P2WPKH(1_000_000)]),
1538 inputs_b: vec![(duplicate_input.clone(), tx.clone())],
1540 expect_error: Some((AbortReason::PrevTxOutInvalid, ErrorCulprit::NodeA)),
1542 do_test_interactive_tx_constructor(TestSession {
1543 description: "Initiator sends too many TxAddInputs",
1544 inputs_a: generate_fixed_number_of_inputs(MAX_RECEIVED_TX_ADD_INPUT_COUNT + 1),
1548 expect_error: Some((AbortReason::ReceivedTooManyTxAddInputs, ErrorCulprit::NodeA)),
1550 do_test_interactive_tx_constructor_with_entropy_source(
1552 // We use a deliberately bad entropy source, `DuplicateEntropySource` to simulate this.
1553 description: "Attempt to queue up two inputs with duplicate serial ids",
1554 inputs_a: generate_fixed_number_of_inputs(2),
1558 expect_error: Some((AbortReason::DuplicateSerialId, ErrorCulprit::NodeA)),
1560 &DuplicateEntropySource,
1562 do_test_interactive_tx_constructor(TestSession {
1563 description: "Initiator sends too many TxAddOutputs",
1565 outputs_a: generate_fixed_number_of_outputs(MAX_RECEIVED_TX_ADD_OUTPUT_COUNT + 1),
1568 expect_error: Some((AbortReason::ReceivedTooManyTxAddOutputs, ErrorCulprit::NodeA)),
1570 do_test_interactive_tx_constructor(TestSession {
1571 description: "Initiator sends an output below dust value",
1573 outputs_a: generate_outputs(&[TestOutput::P2WSH(
1574 generate_p2wsh_script_pubkey().dust_value().to_sat() - 1,
1578 expect_error: Some((AbortReason::BelowDustLimit, ErrorCulprit::NodeA)),
1580 do_test_interactive_tx_constructor(TestSession {
1581 description: "Initiator sends an output above maximum sats allowed",
1583 outputs_a: generate_outputs(&[TestOutput::P2WPKH(TOTAL_BITCOIN_SUPPLY_SATOSHIS + 1)]),
1586 expect_error: Some((AbortReason::ExceededMaximumSatsAllowed, ErrorCulprit::NodeA)),
1588 do_test_interactive_tx_constructor(TestSession {
1589 description: "Initiator sends an output without a witness program",
1591 outputs_a: vec![generate_non_witness_output(1_000_000)],
1594 expect_error: Some((AbortReason::InvalidOutputScript, ErrorCulprit::NodeA)),
1596 do_test_interactive_tx_constructor_with_entropy_source(
1598 // We use a deliberately bad entropy source, `DuplicateEntropySource` to simulate this.
1599 description: "Attempt to queue up two outputs with duplicate serial ids",
1601 outputs_a: generate_fixed_number_of_outputs(2),
1604 expect_error: Some((AbortReason::DuplicateSerialId, ErrorCulprit::NodeA)),
1606 &DuplicateEntropySource,
1609 do_test_interactive_tx_constructor(TestSession {
1610 description: "Peer contributed more output value than inputs",
1611 inputs_a: generate_inputs(&[TestOutput::P2WPKH(100_000)]),
1612 outputs_a: generate_outputs(&[TestOutput::P2WPKH(1_000_000)]),
1615 expect_error: Some((AbortReason::OutputsValueExceedsInputsValue, ErrorCulprit::NodeA)),
1618 do_test_interactive_tx_constructor(TestSession {
1619 description: "Peer contributed more than allowed number of inputs",
1620 inputs_a: generate_fixed_number_of_inputs(MAX_INPUTS_OUTPUTS_COUNT as u16 + 1),
1624 expect_error: Some((
1625 AbortReason::ExceededNumberOfInputsOrOutputs,
1626 ErrorCulprit::Indeterminate,
1629 do_test_interactive_tx_constructor(TestSession {
1630 description: "Peer contributed more than allowed number of outputs",
1631 inputs_a: generate_inputs(&[TestOutput::P2WPKH(TOTAL_BITCOIN_SUPPLY_SATOSHIS)]),
1632 outputs_a: generate_fixed_number_of_outputs(MAX_INPUTS_OUTPUTS_COUNT as u16 + 1),
1635 expect_error: Some((
1636 AbortReason::ExceededNumberOfInputsOrOutputs,
1637 ErrorCulprit::Indeterminate,
1643 fn test_generate_local_serial_id() {
1644 let entropy_source = TestEntropySource(AtomicCounter::new());
1646 // Initiators should have even serial id, non-initiators should have odd serial id.
1647 assert_eq!(generate_holder_serial_id(&&entropy_source, true) % 2, 0);
1648 assert_eq!(generate_holder_serial_id(&&entropy_source, false) % 2, 1)