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::blockdata::constants::WITNESS_SCALE_FACTOR;
15 use bitcoin::consensus::Encodable;
16 use bitcoin::policy::MAX_STANDARD_TX_WEIGHT;
18 absolute::LockTime as AbsoluteLockTime, OutPoint, ScriptBuf, Sequence, Transaction, TxIn,
22 use crate::chain::chaininterface::fee_for_weight;
23 use crate::events::bump_transaction::{BASE_INPUT_WEIGHT, EMPTY_SCRIPT_SIG_WEIGHT};
24 use crate::ln::channel::TOTAL_BITCOIN_SUPPLY_SATOSHIS;
26 use crate::ln::msgs::SerialId;
27 use crate::ln::types::ChannelId;
28 use crate::sign::{EntropySource, P2TR_KEY_PATH_WITNESS_WEIGHT, P2WPKH_WITNESS_WEIGHT};
29 use crate::util::ser::TransactionU16LenLimited;
31 /// The number of received `tx_add_input` messages during a negotiation at which point the
32 /// negotiation MUST be failed.
33 const MAX_RECEIVED_TX_ADD_INPUT_COUNT: u16 = 4096;
35 /// The number of received `tx_add_output` messages during a negotiation at which point the
36 /// negotiation MUST be failed.
37 const MAX_RECEIVED_TX_ADD_OUTPUT_COUNT: u16 = 4096;
39 /// The number of inputs or outputs that the state machine can have, before it MUST fail the
41 const MAX_INPUTS_OUTPUTS_COUNT: usize = 252;
43 /// The total weight of the common fields whose fee is paid by the initiator of the interactive
44 /// transaction construction protocol.
45 const TX_COMMON_FIELDS_WEIGHT: u64 = (4 /* version */ + 4 /* locktime */ + 1 /* input count */ +
46 1 /* output count */) * WITNESS_SCALE_FACTOR as u64 + 2 /* segwit marker + flag */;
48 // BOLT 3 - Lower bounds for input weights
50 /// Lower bound for P2WPKH input weight
51 pub(crate) const P2WPKH_INPUT_WEIGHT_LOWER_BOUND: u64 =
52 BASE_INPUT_WEIGHT + EMPTY_SCRIPT_SIG_WEIGHT + P2WPKH_WITNESS_WEIGHT;
54 /// Lower bound for P2WSH input weight is chosen as same as P2WPKH input weight in BOLT 3
55 pub(crate) const P2WSH_INPUT_WEIGHT_LOWER_BOUND: u64 = P2WPKH_INPUT_WEIGHT_LOWER_BOUND;
57 /// Lower bound for P2TR input weight is chosen as the key spend path.
58 /// Not specified in BOLT 3, but a reasonable lower bound.
59 pub(crate) const P2TR_INPUT_WEIGHT_LOWER_BOUND: u64 =
60 BASE_INPUT_WEIGHT + EMPTY_SCRIPT_SIG_WEIGHT + P2TR_KEY_PATH_WITNESS_WEIGHT;
62 /// Lower bound for unknown segwit version input weight is chosen the same as P2WPKH in BOLT 3
63 pub(crate) const UNKNOWN_SEGWIT_VERSION_INPUT_WEIGHT_LOWER_BOUND: u64 =
64 P2WPKH_INPUT_WEIGHT_LOWER_BOUND;
67 fn is_for_initiator(&self) -> bool;
68 fn is_for_non_initiator(&self) -> bool;
71 impl SerialIdExt for SerialId {
72 fn is_for_initiator(&self) -> bool {
76 fn is_for_non_initiator(&self) -> bool {
77 !self.is_for_initiator()
81 #[derive(Debug, Clone, PartialEq)]
82 pub(crate) enum AbortReason {
83 InvalidStateTransition,
84 UnexpectedCounterpartyMessage,
85 ReceivedTooManyTxAddInputs,
86 ReceivedTooManyTxAddOutputs,
87 IncorrectInputSequenceValue,
88 IncorrectSerialIdParity,
92 ExceededMaximumSatsAllowed,
93 ExceededNumberOfInputsOrOutputs,
98 OutputsValueExceedsInputsValue,
102 #[derive(Debug, Clone, PartialEq, Eq)]
103 pub(crate) struct InteractiveTxInput {
109 #[derive(Debug, Clone, PartialEq, Eq)]
110 pub(crate) struct InteractiveTxOutput {
115 #[derive(Debug, Clone, PartialEq, Eq)]
116 pub(crate) struct ConstructedTransaction {
117 holder_is_initiator: bool,
119 inputs: Vec<InteractiveTxInput>,
120 outputs: Vec<InteractiveTxOutput>,
122 local_inputs_value_satoshis: u64,
123 local_outputs_value_satoshis: u64,
125 remote_inputs_value_satoshis: u64,
126 remote_outputs_value_satoshis: u64,
128 lock_time: AbsoluteLockTime,
131 impl ConstructedTransaction {
132 fn new(context: NegotiationContext) -> Self {
133 let local_inputs_value_satoshis = context
136 .filter(|(serial_id, _)| {
137 !is_serial_id_valid_for_counterparty(context.holder_is_initiator, serial_id)
139 .fold(0u64, |value, (_, input)| value.saturating_add(input.prev_output.value));
141 let local_outputs_value_satoshis = context
144 .filter(|(serial_id, _)| {
145 !is_serial_id_valid_for_counterparty(context.holder_is_initiator, serial_id)
147 .fold(0u64, |value, (_, output)| value.saturating_add(output.tx_out.value));
150 holder_is_initiator: context.holder_is_initiator,
152 local_inputs_value_satoshis,
153 local_outputs_value_satoshis,
155 remote_inputs_value_satoshis: context.remote_inputs_value(),
156 remote_outputs_value_satoshis: context.remote_outputs_value(),
158 inputs: context.inputs.into_values().collect(),
159 outputs: context.outputs.into_values().collect(),
161 lock_time: context.tx_locktime,
165 pub fn weight(&self) -> Weight {
166 let inputs_weight = self.inputs.iter().fold(
168 |weight, InteractiveTxInput { prev_output, .. }| {
169 weight.checked_add(estimate_input_weight(prev_output)).unwrap_or(Weight::MAX)
172 let outputs_weight = self.outputs.iter().fold(
174 |weight, InteractiveTxOutput { tx_out, .. }| {
175 weight.checked_add(get_output_weight(&tx_out.script_pubkey)).unwrap_or(Weight::MAX)
178 Weight::from_wu(TX_COMMON_FIELDS_WEIGHT)
179 .checked_add(inputs_weight)
180 .and_then(|weight| weight.checked_add(outputs_weight))
181 .unwrap_or(Weight::MAX)
184 pub fn into_unsigned_tx(self) -> Transaction {
185 // Inputs and outputs must be sorted by serial_id
186 let ConstructedTransaction { mut inputs, mut outputs, .. } = self;
188 inputs.sort_unstable_by_key(|InteractiveTxInput { serial_id, .. }| *serial_id);
189 outputs.sort_unstable_by_key(|InteractiveTxOutput { serial_id, .. }| *serial_id);
191 let input: Vec<TxIn> =
192 inputs.into_iter().map(|InteractiveTxInput { input, .. }| input).collect();
193 let output: Vec<TxOut> =
194 outputs.into_iter().map(|InteractiveTxOutput { tx_out, .. }| tx_out).collect();
196 Transaction { version: 2, lock_time: self.lock_time, input, output }
201 struct NegotiationContext {
202 holder_is_initiator: bool,
203 received_tx_add_input_count: u16,
204 received_tx_add_output_count: u16,
205 inputs: HashMap<SerialId, InteractiveTxInput>,
206 prevtx_outpoints: HashSet<OutPoint>,
207 outputs: HashMap<SerialId, InteractiveTxOutput>,
208 tx_locktime: AbsoluteLockTime,
209 feerate_sat_per_kw: u32,
212 pub(crate) fn estimate_input_weight(prev_output: &TxOut) -> Weight {
213 Weight::from_wu(if prev_output.script_pubkey.is_v0_p2wpkh() {
214 P2WPKH_INPUT_WEIGHT_LOWER_BOUND
215 } else if prev_output.script_pubkey.is_v0_p2wsh() {
216 P2WSH_INPUT_WEIGHT_LOWER_BOUND
217 } else if prev_output.script_pubkey.is_v1_p2tr() {
218 P2TR_INPUT_WEIGHT_LOWER_BOUND
220 UNKNOWN_SEGWIT_VERSION_INPUT_WEIGHT_LOWER_BOUND
224 pub(crate) fn get_output_weight(script_pubkey: &ScriptBuf) -> Weight {
226 (8 /* value */ + script_pubkey.consensus_encode(&mut sink()).unwrap() as u64)
227 * WITNESS_SCALE_FACTOR as u64,
231 fn is_serial_id_valid_for_counterparty(holder_is_initiator: bool, serial_id: &SerialId) -> bool {
232 // A received `SerialId`'s parity must match the role of the counterparty.
233 holder_is_initiator == serial_id.is_for_non_initiator()
236 impl NegotiationContext {
237 fn is_serial_id_valid_for_counterparty(&self, serial_id: &SerialId) -> bool {
238 is_serial_id_valid_for_counterparty(self.holder_is_initiator, serial_id)
241 fn remote_inputs_value(&self) -> u64 {
244 .filter(|(serial_id, _)| self.is_serial_id_valid_for_counterparty(serial_id))
245 .fold(0u64, |acc, (_, InteractiveTxInput { prev_output, .. })| {
246 acc.saturating_add(prev_output.value)
250 fn remote_outputs_value(&self) -> u64 {
253 .filter(|(serial_id, _)| self.is_serial_id_valid_for_counterparty(serial_id))
254 .fold(0u64, |acc, (_, InteractiveTxOutput { tx_out, .. })| {
255 acc.saturating_add(tx_out.value)
259 fn remote_inputs_weight(&self) -> Weight {
263 .filter(|(serial_id, _)| self.is_serial_id_valid_for_counterparty(serial_id))
264 .fold(0u64, |weight, (_, InteractiveTxInput { prev_output, .. })| {
265 weight.saturating_add(estimate_input_weight(prev_output).to_wu())
270 fn remote_outputs_weight(&self) -> Weight {
274 .filter(|(serial_id, _)| self.is_serial_id_valid_for_counterparty(serial_id))
275 .fold(0u64, |weight, (_, InteractiveTxOutput { tx_out, .. })| {
276 weight.saturating_add(get_output_weight(&tx_out.script_pubkey).to_wu())
281 fn received_tx_add_input(&mut self, msg: &msgs::TxAddInput) -> Result<(), AbortReason> {
282 // The interactive-txs spec calls for us to fail negotiation if the `prevtx` we receive is
283 // invalid. However, we would not need to account for this explicit negotiation failure
284 // mode here since `PeerManager` would already disconnect the peer if the `prevtx` is
285 // invalid; implicitly ending the negotiation.
287 if !self.is_serial_id_valid_for_counterparty(&msg.serial_id) {
288 // The receiving node:
289 // - MUST fail the negotiation if:
290 // - the `serial_id` has the wrong parity
291 return Err(AbortReason::IncorrectSerialIdParity);
294 self.received_tx_add_input_count += 1;
295 if self.received_tx_add_input_count > MAX_RECEIVED_TX_ADD_INPUT_COUNT {
296 // The receiving node:
297 // - MUST fail the negotiation if:
298 // - if has received 4096 `tx_add_input` messages during this negotiation
299 return Err(AbortReason::ReceivedTooManyTxAddInputs);
302 if msg.sequence >= 0xFFFFFFFE {
303 // The receiving node:
304 // - MUST fail the negotiation if:
305 // - `sequence` is set to `0xFFFFFFFE` or `0xFFFFFFFF`
306 return Err(AbortReason::IncorrectInputSequenceValue);
309 let transaction = msg.prevtx.as_transaction();
310 let txid = transaction.txid();
312 if let Some(tx_out) = transaction.output.get(msg.prevtx_out as usize) {
313 if !tx_out.script_pubkey.is_witness_program() {
314 // The receiving node:
315 // - MUST fail the negotiation if:
316 // - the `scriptPubKey` is not a witness program
317 return Err(AbortReason::PrevTxOutInvalid);
320 if !self.prevtx_outpoints.insert(OutPoint { txid, vout: msg.prevtx_out }) {
321 // The receiving node:
322 // - MUST fail the negotiation if:
323 // - the `prevtx` and `prevtx_vout` are identical to a previously added
324 // (and not removed) input's
325 return Err(AbortReason::PrevTxOutInvalid);
328 // The receiving node:
329 // - MUST fail the negotiation if:
330 // - `prevtx_vout` is greater or equal to the number of outputs on `prevtx`
331 return Err(AbortReason::PrevTxOutInvalid);
334 let prev_out = if let Some(prev_out) = transaction.output.get(msg.prevtx_out as usize) {
337 return Err(AbortReason::PrevTxOutInvalid);
339 match self.inputs.entry(msg.serial_id) {
340 hash_map::Entry::Occupied(_) => {
341 // The receiving node:
342 // - MUST fail the negotiation if:
343 // - the `serial_id` is already included in the transaction
344 Err(AbortReason::DuplicateSerialId)
346 hash_map::Entry::Vacant(entry) => {
347 let prev_outpoint = OutPoint { txid, vout: msg.prevtx_out };
348 entry.insert(InteractiveTxInput {
349 serial_id: msg.serial_id,
351 previous_output: prev_outpoint,
352 sequence: Sequence(msg.sequence),
355 prev_output: prev_out,
357 self.prevtx_outpoints.insert(prev_outpoint);
363 fn received_tx_remove_input(&mut self, msg: &msgs::TxRemoveInput) -> Result<(), AbortReason> {
364 if !self.is_serial_id_valid_for_counterparty(&msg.serial_id) {
365 return Err(AbortReason::IncorrectSerialIdParity);
369 .remove(&msg.serial_id)
370 // The receiving node:
371 // - MUST fail the negotiation if:
372 // - the input or output identified by the `serial_id` was not added by the sender
373 // - the `serial_id` does not correspond to a currently added input
374 .ok_or(AbortReason::SerialIdUnknown)
378 fn received_tx_add_output(&mut self, msg: &msgs::TxAddOutput) -> Result<(), AbortReason> {
379 // The receiving node:
380 // - MUST fail the negotiation if:
381 // - the serial_id has the wrong parity
382 if !self.is_serial_id_valid_for_counterparty(&msg.serial_id) {
383 return Err(AbortReason::IncorrectSerialIdParity);
386 self.received_tx_add_output_count += 1;
387 if self.received_tx_add_output_count > MAX_RECEIVED_TX_ADD_OUTPUT_COUNT {
388 // The receiving node:
389 // - MUST fail the negotiation if:
390 // - if has received 4096 `tx_add_output` messages during this negotiation
391 return Err(AbortReason::ReceivedTooManyTxAddOutputs);
394 if msg.sats < msg.script.dust_value().to_sat() {
395 // The receiving node:
396 // - MUST fail the negotiation if:
397 // - the sats amount is less than the dust_limit
398 return Err(AbortReason::BelowDustLimit);
401 // Check that adding this output would not cause the total output value to exceed the total
403 let mut outputs_value: u64 = 0;
404 for output in self.outputs.iter() {
405 outputs_value = outputs_value.saturating_add(output.1.tx_out.value);
407 if outputs_value.saturating_add(msg.sats) > TOTAL_BITCOIN_SUPPLY_SATOSHIS {
408 // The receiving node:
409 // - MUST fail the negotiation if:
410 // - the sats amount is greater than 2,100,000,000,000,000 (TOTAL_BITCOIN_SUPPLY_SATOSHIS)
411 return Err(AbortReason::ExceededMaximumSatsAllowed);
414 // The receiving node:
415 // - MUST accept P2WSH, P2WPKH, P2TR scripts
416 // - MAY fail the negotiation if script is non-standard
418 // We can actually be a bit looser than the above as only witness version 0 has special
419 // length-based standardness constraints to match similar consensus rules. All witness scripts
420 // with witness versions V1 and up are always considered standard. Yes, the scripts can be
421 // anyone-can-spend-able, but if our counterparty wants to add an output like that then it's none
422 // of our concern really ¯\_(ツ)_/¯
424 // TODO: The last check would be simplified when https://github.com/rust-bitcoin/rust-bitcoin/commit/1656e1a09a1959230e20af90d20789a4a8f0a31b
425 // hits the next release of rust-bitcoin.
426 if !(msg.script.is_v0_p2wpkh()
427 || msg.script.is_v0_p2wsh()
428 || (msg.script.is_witness_program()
429 && msg.script.witness_version().map(|v| v.to_num() >= 1).unwrap_or(false)))
431 return Err(AbortReason::InvalidOutputScript);
434 match self.outputs.entry(msg.serial_id) {
435 hash_map::Entry::Occupied(_) => {
436 // The receiving node:
437 // - MUST fail the negotiation if:
438 // - the `serial_id` is already included in the transaction
439 Err(AbortReason::DuplicateSerialId)
441 hash_map::Entry::Vacant(entry) => {
442 entry.insert(InteractiveTxOutput {
443 serial_id: msg.serial_id,
444 tx_out: TxOut { value: msg.sats, script_pubkey: msg.script.clone() },
451 fn received_tx_remove_output(&mut self, msg: &msgs::TxRemoveOutput) -> Result<(), AbortReason> {
452 if !self.is_serial_id_valid_for_counterparty(&msg.serial_id) {
453 return Err(AbortReason::IncorrectSerialIdParity);
455 if self.outputs.remove(&msg.serial_id).is_some() {
458 // The receiving node:
459 // - MUST fail the negotiation if:
460 // - the input or output identified by the `serial_id` was not added by the sender
461 // - the `serial_id` does not correspond to a currently added input
462 Err(AbortReason::SerialIdUnknown)
466 fn sent_tx_add_input(&mut self, msg: &msgs::TxAddInput) -> Result<(), AbortReason> {
467 let tx = msg.prevtx.as_transaction();
469 previous_output: OutPoint { txid: tx.txid(), vout: msg.prevtx_out },
470 sequence: Sequence(msg.sequence),
474 tx.output.get(msg.prevtx_out as usize).ok_or(AbortReason::PrevTxOutInvalid)?.clone();
475 if !self.prevtx_outpoints.insert(input.previous_output) {
476 // We have added an input that already exists
477 return Err(AbortReason::PrevTxOutInvalid);
481 InteractiveTxInput { serial_id: msg.serial_id, input, prev_output },
486 fn sent_tx_add_output(&mut self, msg: &msgs::TxAddOutput) -> Result<(), AbortReason> {
489 InteractiveTxOutput {
490 serial_id: msg.serial_id,
491 tx_out: TxOut { value: msg.sats, script_pubkey: msg.script.clone() },
497 fn sent_tx_remove_input(&mut self, msg: &msgs::TxRemoveInput) -> Result<(), AbortReason> {
498 self.inputs.remove(&msg.serial_id);
502 fn sent_tx_remove_output(&mut self, msg: &msgs::TxRemoveOutput) -> Result<(), AbortReason> {
503 self.outputs.remove(&msg.serial_id);
507 fn check_counterparty_fees(
508 &self, counterparty_fees_contributed: u64,
509 ) -> Result<(), AbortReason> {
510 let counterparty_weight_contributed = self
511 .remote_inputs_weight()
513 .saturating_add(self.remote_outputs_weight().to_wu());
514 let mut required_counterparty_contribution_fee =
515 fee_for_weight(self.feerate_sat_per_kw, counterparty_weight_contributed);
516 if !self.holder_is_initiator {
517 // if is the non-initiator:
518 // - the initiator's fees do not cover the common fields (version, segwit marker + flag,
519 // input count, output count, locktime)
520 let tx_common_fields_fee =
521 fee_for_weight(self.feerate_sat_per_kw, TX_COMMON_FIELDS_WEIGHT);
522 required_counterparty_contribution_fee += tx_common_fields_fee;
524 if counterparty_fees_contributed < required_counterparty_contribution_fee {
525 return Err(AbortReason::InsufficientFees);
530 fn validate_tx(self) -> Result<ConstructedTransaction, AbortReason> {
531 // The receiving node:
532 // MUST fail the negotiation if:
534 // - the peer's total input satoshis is less than their outputs
535 let remote_inputs_value = self.remote_inputs_value();
536 let remote_outputs_value = self.remote_outputs_value();
537 if remote_inputs_value < remote_outputs_value {
538 return Err(AbortReason::OutputsValueExceedsInputsValue);
541 // - there are more than 252 inputs
542 // - there are more than 252 outputs
543 if self.inputs.len() > MAX_INPUTS_OUTPUTS_COUNT
544 || self.outputs.len() > MAX_INPUTS_OUTPUTS_COUNT
546 return Err(AbortReason::ExceededNumberOfInputsOrOutputs);
549 // - the peer's paid feerate does not meet or exceed the agreed feerate (based on the minimum fee).
550 self.check_counterparty_fees(remote_inputs_value.saturating_sub(remote_outputs_value))?;
552 let constructed_tx = ConstructedTransaction::new(self);
554 if constructed_tx.weight().to_wu() > MAX_STANDARD_TX_WEIGHT as u64 {
555 return Err(AbortReason::TransactionTooLarge);
562 // The interactive transaction construction protocol allows two peers to collaboratively build a
563 // transaction for broadcast.
565 // The protocol is turn-based, so we define different states here that we store depending on whose
566 // turn it is to send the next message. The states are defined so that their types ensure we only
567 // perform actions (only send messages) via defined state transitions that do not violate the
570 // An example of a full negotiation and associated states follows:
572 // +------------+ +------------------+---- Holder state after message sent/received ----+
573 // | |--(1)- tx_add_input ---->| | SentChangeMsg +
574 // | |<-(2)- tx_complete ------| | ReceivedTxComplete +
575 // | |--(3)- tx_add_output --->| | SentChangeMsg +
576 // | |<-(4)- tx_complete ------| | ReceivedTxComplete +
577 // | |--(5)- tx_add_input ---->| | SentChangeMsg +
578 // | Holder |<-(6)- tx_add_input -----| Counterparty | ReceivedChangeMsg +
579 // | |--(7)- tx_remove_output >| | SentChangeMsg +
580 // | |<-(8)- tx_add_output ----| | ReceivedChangeMsg +
581 // | |--(9)- tx_complete ----->| | SentTxComplete +
582 // | |<-(10) tx_complete ------| | NegotiationComplete +
583 // +------------+ +------------------+--------------------------------------------------+
585 /// Negotiation states that can send & receive `tx_(add|remove)_(input|output)` and `tx_complete`
588 /// Category of states where we have sent some message to the counterparty, and we are waiting for
590 trait SentMsgState: State {
591 fn into_negotiation_context(self) -> NegotiationContext;
594 /// Category of states that our counterparty has put us in after we receive a message from them.
595 trait ReceivedMsgState: State {
596 fn into_negotiation_context(self) -> NegotiationContext;
599 // This macro is a helper for implementing the above state traits for various states subsequently
600 // defined below the macro.
601 macro_rules! define_state {
602 (SENT_MSG_STATE, $state: ident, $doc: expr) => {
603 define_state!($state, NegotiationContext, $doc);
604 impl SentMsgState for $state {
605 fn into_negotiation_context(self) -> NegotiationContext {
610 (RECEIVED_MSG_STATE, $state: ident, $doc: expr) => {
611 define_state!($state, NegotiationContext, $doc);
612 impl ReceivedMsgState for $state {
613 fn into_negotiation_context(self) -> NegotiationContext {
618 ($state: ident, $inner: ident, $doc: expr) => {
621 struct $state($inner);
622 impl State for $state {}
629 "We have sent a message to the counterparty that has affected our negotiation state."
634 "We have sent a `tx_complete` message and are awaiting the counterparty's."
639 "We have received a message from the counterparty that has affected our negotiation state."
644 "We have received a `tx_complete` message and the counterparty is awaiting ours."
646 define_state!(NegotiationComplete, ConstructedTransaction, "We have exchanged consecutive `tx_complete` messages with the counterparty and the transaction negotiation is complete.");
650 "The negotiation has failed and cannot be continued."
653 type StateTransitionResult<S> = Result<S, AbortReason>;
655 trait StateTransition<NewState: State, TransitionData> {
656 fn transition(self, data: TransitionData) -> StateTransitionResult<NewState>;
659 // This macro helps define the legal transitions between the states above by implementing
660 // the `StateTransition` trait for each of the states that follow this declaration.
661 macro_rules! define_state_transitions {
662 (SENT_MSG_STATE, [$(DATA $data: ty, TRANSITION $transition: ident),+]) => {
664 impl<S: SentMsgState> StateTransition<ReceivedChangeMsg, $data> for S {
665 fn transition(self, data: $data) -> StateTransitionResult<ReceivedChangeMsg> {
666 let mut context = self.into_negotiation_context();
667 context.$transition(data)?;
668 Ok(ReceivedChangeMsg(context))
673 (RECEIVED_MSG_STATE, [$(DATA $data: ty, TRANSITION $transition: ident),+]) => {
675 impl<S: ReceivedMsgState> StateTransition<SentChangeMsg, $data> for S {
676 fn transition(self, data: $data) -> StateTransitionResult<SentChangeMsg> {
677 let mut context = self.into_negotiation_context();
678 context.$transition(data)?;
679 Ok(SentChangeMsg(context))
684 (TX_COMPLETE, $from_state: ident, $tx_complete_state: ident) => {
685 impl StateTransition<NegotiationComplete, &msgs::TxComplete> for $tx_complete_state {
686 fn transition(self, _data: &msgs::TxComplete) -> StateTransitionResult<NegotiationComplete> {
687 let context = self.into_negotiation_context();
688 let tx = context.validate_tx()?;
689 Ok(NegotiationComplete(tx))
693 impl StateTransition<$tx_complete_state, &msgs::TxComplete> for $from_state {
694 fn transition(self, _data: &msgs::TxComplete) -> StateTransitionResult<$tx_complete_state> {
695 Ok($tx_complete_state(self.into_negotiation_context()))
701 // State transitions when we have sent our counterparty some messages and are waiting for them
703 define_state_transitions!(SENT_MSG_STATE, [
704 DATA &msgs::TxAddInput, TRANSITION received_tx_add_input,
705 DATA &msgs::TxRemoveInput, TRANSITION received_tx_remove_input,
706 DATA &msgs::TxAddOutput, TRANSITION received_tx_add_output,
707 DATA &msgs::TxRemoveOutput, TRANSITION received_tx_remove_output
709 // State transitions when we have received some messages from our counterparty and we should
711 define_state_transitions!(RECEIVED_MSG_STATE, [
712 DATA &msgs::TxAddInput, TRANSITION sent_tx_add_input,
713 DATA &msgs::TxRemoveInput, TRANSITION sent_tx_remove_input,
714 DATA &msgs::TxAddOutput, TRANSITION sent_tx_add_output,
715 DATA &msgs::TxRemoveOutput, TRANSITION sent_tx_remove_output
717 define_state_transitions!(TX_COMPLETE, SentChangeMsg, ReceivedTxComplete);
718 define_state_transitions!(TX_COMPLETE, ReceivedChangeMsg, SentTxComplete);
723 SentChangeMsg(SentChangeMsg),
724 ReceivedChangeMsg(ReceivedChangeMsg),
725 SentTxComplete(SentTxComplete),
726 ReceivedTxComplete(ReceivedTxComplete),
727 NegotiationComplete(NegotiationComplete),
728 NegotiationAborted(NegotiationAborted),
731 impl Default for StateMachine {
732 fn default() -> Self {
737 // The `StateMachine` internally executes the actual transition between two states and keeps
738 // track of the current state. This macro defines _how_ those state transitions happen to
739 // update the internal state.
740 macro_rules! define_state_machine_transitions {
741 ($transition: ident, $msg: ty, [$(FROM $from_state: ident, TO $to_state: ident),+]) => {
742 fn $transition(self, msg: $msg) -> StateMachine {
745 Self::$from_state(s) => match s.transition(msg) {
746 Ok(new_state) => StateMachine::$to_state(new_state),
747 Err(abort_reason) => StateMachine::NegotiationAborted(NegotiationAborted(abort_reason)),
750 _ => StateMachine::NegotiationAborted(NegotiationAborted(AbortReason::UnexpectedCounterpartyMessage)),
757 fn new(feerate_sat_per_kw: u32, is_initiator: bool, tx_locktime: AbsoluteLockTime) -> Self {
758 let context = NegotiationContext {
760 holder_is_initiator: is_initiator,
761 received_tx_add_input_count: 0,
762 received_tx_add_output_count: 0,
763 inputs: new_hash_map(),
764 prevtx_outpoints: new_hash_set(),
765 outputs: new_hash_map(),
769 Self::ReceivedChangeMsg(ReceivedChangeMsg(context))
771 Self::SentChangeMsg(SentChangeMsg(context))
776 define_state_machine_transitions!(sent_tx_add_input, &msgs::TxAddInput, [
777 FROM ReceivedChangeMsg, TO SentChangeMsg,
778 FROM ReceivedTxComplete, TO SentChangeMsg
780 define_state_machine_transitions!(received_tx_add_input, &msgs::TxAddInput, [
781 FROM SentChangeMsg, TO ReceivedChangeMsg,
782 FROM SentTxComplete, TO ReceivedChangeMsg
786 define_state_machine_transitions!(sent_tx_add_output, &msgs::TxAddOutput, [
787 FROM ReceivedChangeMsg, TO SentChangeMsg,
788 FROM ReceivedTxComplete, TO SentChangeMsg
790 define_state_machine_transitions!(received_tx_add_output, &msgs::TxAddOutput, [
791 FROM SentChangeMsg, TO ReceivedChangeMsg,
792 FROM SentTxComplete, TO ReceivedChangeMsg
796 define_state_machine_transitions!(sent_tx_remove_input, &msgs::TxRemoveInput, [
797 FROM ReceivedChangeMsg, TO SentChangeMsg,
798 FROM ReceivedTxComplete, TO SentChangeMsg
800 define_state_machine_transitions!(received_tx_remove_input, &msgs::TxRemoveInput, [
801 FROM SentChangeMsg, TO ReceivedChangeMsg,
802 FROM SentTxComplete, TO ReceivedChangeMsg
806 define_state_machine_transitions!(sent_tx_remove_output, &msgs::TxRemoveOutput, [
807 FROM ReceivedChangeMsg, TO SentChangeMsg,
808 FROM ReceivedTxComplete, TO SentChangeMsg
810 define_state_machine_transitions!(received_tx_remove_output, &msgs::TxRemoveOutput, [
811 FROM SentChangeMsg, TO ReceivedChangeMsg,
812 FROM SentTxComplete, TO ReceivedChangeMsg
816 define_state_machine_transitions!(sent_tx_complete, &msgs::TxComplete, [
817 FROM ReceivedChangeMsg, TO SentTxComplete,
818 FROM ReceivedTxComplete, TO NegotiationComplete
820 define_state_machine_transitions!(received_tx_complete, &msgs::TxComplete, [
821 FROM SentChangeMsg, TO ReceivedTxComplete,
822 FROM SentTxComplete, TO NegotiationComplete
826 pub(crate) struct InteractiveTxConstructor {
827 state_machine: StateMachine,
828 channel_id: ChannelId,
829 inputs_to_contribute: Vec<(SerialId, TxIn, TransactionU16LenLimited)>,
830 outputs_to_contribute: Vec<(SerialId, TxOut)>,
833 pub(crate) enum InteractiveTxMessageSend {
834 TxAddInput(msgs::TxAddInput),
835 TxAddOutput(msgs::TxAddOutput),
836 TxComplete(msgs::TxComplete),
839 // This macro executes a state machine transition based on a provided action.
840 macro_rules! do_state_transition {
841 ($self: ident, $transition: ident, $msg: expr) => {{
842 let state_machine = core::mem::take(&mut $self.state_machine);
843 $self.state_machine = state_machine.$transition($msg);
844 match &$self.state_machine {
845 StateMachine::NegotiationAborted(state) => Err(state.0.clone()),
851 fn generate_holder_serial_id<ES: Deref>(entropy_source: &ES, is_initiator: bool) -> SerialId
853 ES::Target: EntropySource,
855 let rand_bytes = entropy_source.get_secure_random_bytes();
856 let mut serial_id_bytes = [0u8; 8];
857 serial_id_bytes.copy_from_slice(&rand_bytes[..8]);
858 let mut serial_id = u64::from_be_bytes(serial_id_bytes);
859 if serial_id.is_for_initiator() != is_initiator {
865 pub(crate) enum HandleTxCompleteValue {
866 SendTxMessage(InteractiveTxMessageSend),
867 SendTxComplete(InteractiveTxMessageSend, ConstructedTransaction),
868 NegotiationComplete(ConstructedTransaction),
871 impl InteractiveTxConstructor {
872 /// Instantiates a new `InteractiveTxConstructor`.
874 /// A tuple is returned containing the newly instantiate `InteractiveTxConstructor` and optionally
875 /// an initial wrapped `Tx_` message which the holder needs to send to the counterparty.
876 pub fn new<ES: Deref>(
877 entropy_source: &ES, channel_id: ChannelId, feerate_sat_per_kw: u32, is_initiator: bool,
878 funding_tx_locktime: AbsoluteLockTime,
879 inputs_to_contribute: Vec<(TxIn, TransactionU16LenLimited)>,
880 outputs_to_contribute: Vec<TxOut>,
881 ) -> (Self, Option<InteractiveTxMessageSend>)
883 ES::Target: EntropySource,
886 StateMachine::new(feerate_sat_per_kw, is_initiator, funding_tx_locktime);
887 let mut inputs_to_contribute: Vec<(SerialId, TxIn, TransactionU16LenLimited)> =
891 let serial_id = generate_holder_serial_id(entropy_source, is_initiator);
892 (serial_id, input, tx)
895 // We'll sort by the randomly generated serial IDs, effectively shuffling the order of the inputs
896 // as the user passed them to us to avoid leaking any potential categorization of transactions
897 // before we pass any of the inputs to the counterparty.
898 inputs_to_contribute.sort_unstable_by_key(|(serial_id, _, _)| *serial_id);
899 let mut outputs_to_contribute: Vec<(SerialId, TxOut)> = outputs_to_contribute
902 let serial_id = generate_holder_serial_id(entropy_source, is_initiator);
906 // In the same manner and for the same rationale as the inputs above, we'll shuffle the outputs.
907 outputs_to_contribute.sort_unstable_by_key(|(serial_id, _)| *serial_id);
908 let mut constructor =
909 Self { state_machine, channel_id, inputs_to_contribute, outputs_to_contribute };
910 let message_send = if is_initiator {
911 match constructor.maybe_send_message() {
912 Ok(msg_send) => Some(msg_send),
916 "We should always be able to start our state machine successfully"
924 (constructor, message_send)
927 fn maybe_send_message(&mut self) -> Result<InteractiveTxMessageSend, AbortReason> {
928 // We first attempt to send inputs we want to add, then outputs. Once we are done sending
929 // them both, then we always send tx_complete.
930 if let Some((serial_id, input, prevtx)) = self.inputs_to_contribute.pop() {
931 let msg = msgs::TxAddInput {
932 channel_id: self.channel_id,
935 prevtx_out: input.previous_output.vout,
936 sequence: input.sequence.to_consensus_u32(),
938 do_state_transition!(self, sent_tx_add_input, &msg)?;
939 Ok(InteractiveTxMessageSend::TxAddInput(msg))
940 } else if let Some((serial_id, output)) = self.outputs_to_contribute.pop() {
941 let msg = msgs::TxAddOutput {
942 channel_id: self.channel_id,
945 script: output.script_pubkey,
947 do_state_transition!(self, sent_tx_add_output, &msg)?;
948 Ok(InteractiveTxMessageSend::TxAddOutput(msg))
950 let msg = msgs::TxComplete { channel_id: self.channel_id };
951 do_state_transition!(self, sent_tx_complete, &msg)?;
952 Ok(InteractiveTxMessageSend::TxComplete(msg))
956 pub fn handle_tx_add_input(
957 &mut self, msg: &msgs::TxAddInput,
958 ) -> Result<InteractiveTxMessageSend, AbortReason> {
959 do_state_transition!(self, received_tx_add_input, msg)?;
960 self.maybe_send_message()
963 pub fn handle_tx_remove_input(
964 &mut self, msg: &msgs::TxRemoveInput,
965 ) -> Result<InteractiveTxMessageSend, AbortReason> {
966 do_state_transition!(self, received_tx_remove_input, msg)?;
967 self.maybe_send_message()
970 pub fn handle_tx_add_output(
971 &mut self, msg: &msgs::TxAddOutput,
972 ) -> Result<InteractiveTxMessageSend, AbortReason> {
973 do_state_transition!(self, received_tx_add_output, msg)?;
974 self.maybe_send_message()
977 pub fn handle_tx_remove_output(
978 &mut self, msg: &msgs::TxRemoveOutput,
979 ) -> Result<InteractiveTxMessageSend, AbortReason> {
980 do_state_transition!(self, received_tx_remove_output, msg)?;
981 self.maybe_send_message()
984 pub fn handle_tx_complete(
985 &mut self, msg: &msgs::TxComplete,
986 ) -> Result<HandleTxCompleteValue, AbortReason> {
987 do_state_transition!(self, received_tx_complete, msg)?;
988 match &self.state_machine {
989 StateMachine::ReceivedTxComplete(_) => {
990 let msg_send = self.maybe_send_message()?;
991 match &self.state_machine {
992 StateMachine::NegotiationComplete(s) => {
993 Ok(HandleTxCompleteValue::SendTxComplete(msg_send, s.0.clone()))
995 StateMachine::SentChangeMsg(_) => {
996 Ok(HandleTxCompleteValue::SendTxMessage(msg_send))
997 }, // We either had an input or output to contribute.
999 debug_assert!(false, "We cannot transition to any other states after receiving `tx_complete` and responding");
1000 Err(AbortReason::InvalidStateTransition)
1004 StateMachine::NegotiationComplete(s) => {
1005 Ok(HandleTxCompleteValue::NegotiationComplete(s.0.clone()))
1010 "We cannot transition to any other states after receiving `tx_complete`"
1012 Err(AbortReason::InvalidStateTransition)
1020 use crate::chain::chaininterface::{fee_for_weight, FEERATE_FLOOR_SATS_PER_KW};
1021 use crate::ln::channel::TOTAL_BITCOIN_SUPPLY_SATOSHIS;
1022 use crate::ln::interactivetxs::{
1023 generate_holder_serial_id, AbortReason, HandleTxCompleteValue, InteractiveTxConstructor,
1024 InteractiveTxMessageSend, MAX_INPUTS_OUTPUTS_COUNT, MAX_RECEIVED_TX_ADD_INPUT_COUNT,
1025 MAX_RECEIVED_TX_ADD_OUTPUT_COUNT,
1027 use crate::ln::types::ChannelId;
1028 use crate::sign::EntropySource;
1029 use crate::util::atomic_counter::AtomicCounter;
1030 use crate::util::ser::TransactionU16LenLimited;
1031 use bitcoin::blockdata::opcodes;
1032 use bitcoin::blockdata::script::Builder;
1033 use bitcoin::hashes::Hash;
1034 use bitcoin::key::UntweakedPublicKey;
1035 use bitcoin::secp256k1::{KeyPair, Secp256k1};
1037 absolute::LockTime as AbsoluteLockTime, OutPoint, Sequence, Transaction, TxIn, TxOut,
1039 use bitcoin::{PubkeyHash, ScriptBuf, WPubkeyHash, WScriptHash};
1040 use core::ops::Deref;
1043 get_output_weight, P2TR_INPUT_WEIGHT_LOWER_BOUND, P2WPKH_INPUT_WEIGHT_LOWER_BOUND,
1044 P2WSH_INPUT_WEIGHT_LOWER_BOUND, TX_COMMON_FIELDS_WEIGHT,
1047 const TEST_FEERATE_SATS_PER_KW: u32 = FEERATE_FLOOR_SATS_PER_KW * 10;
1049 // A simple entropy source that works based on an atomic counter.
1050 struct TestEntropySource(AtomicCounter);
1051 impl EntropySource for TestEntropySource {
1052 fn get_secure_random_bytes(&self) -> [u8; 32] {
1053 let mut res = [0u8; 32];
1054 let increment = self.0.get_increment();
1056 // Rotate the increment value by 'i' bits to the right, to avoid clashes
1057 // when `generate_local_serial_id` does a parity flip on consecutive calls for the
1059 let rotated_increment = increment.rotate_right(i as u32);
1060 res[i] = (rotated_increment & 0xff) as u8;
1066 // An entropy source that deliberately returns you the same seed every time. We use this
1067 // to test if the constructor would catch inputs/outputs that are attempting to be added
1068 // with duplicate serial ids.
1069 struct DuplicateEntropySource;
1070 impl EntropySource for DuplicateEntropySource {
1071 fn get_secure_random_bytes(&self) -> [u8; 32] {
1072 let mut res = [0u8; 32];
1074 res[0..8].copy_from_slice(&count.to_be_bytes());
1079 #[derive(Debug, PartialEq, Eq)]
1083 // Some error values are only checked at the end of the negotiation and are not easy to attribute
1084 // to a particular party. Both parties would indicate an `AbortReason` in this case.
1085 // e.g. Exceeded max inputs and outputs after negotiation.
1089 struct TestSession {
1090 description: &'static str,
1091 inputs_a: Vec<(TxIn, TransactionU16LenLimited)>,
1092 outputs_a: Vec<TxOut>,
1093 inputs_b: Vec<(TxIn, TransactionU16LenLimited)>,
1094 outputs_b: Vec<TxOut>,
1095 expect_error: Option<(AbortReason, ErrorCulprit)>,
1098 fn do_test_interactive_tx_constructor(session: TestSession) {
1099 let entropy_source = TestEntropySource(AtomicCounter::new());
1100 do_test_interactive_tx_constructor_internal(session, &&entropy_source);
1103 fn do_test_interactive_tx_constructor_with_entropy_source<ES: Deref>(
1104 session: TestSession, entropy_source: ES,
1106 ES::Target: EntropySource,
1108 do_test_interactive_tx_constructor_internal(session, &entropy_source);
1111 fn do_test_interactive_tx_constructor_internal<ES: Deref>(
1112 session: TestSession, entropy_source: &ES,
1114 ES::Target: EntropySource,
1116 let channel_id = ChannelId(entropy_source.get_secure_random_bytes());
1117 let tx_locktime = AbsoluteLockTime::from_height(1337).unwrap();
1119 let (mut constructor_a, first_message_a) = InteractiveTxConstructor::new(
1122 TEST_FEERATE_SATS_PER_KW,
1128 let (mut constructor_b, first_message_b) = InteractiveTxConstructor::new(
1131 TEST_FEERATE_SATS_PER_KW,
1138 let handle_message_send =
1139 |msg: InteractiveTxMessageSend, for_constructor: &mut InteractiveTxConstructor| {
1141 InteractiveTxMessageSend::TxAddInput(msg) => for_constructor
1142 .handle_tx_add_input(&msg)
1143 .map(|msg_send| (Some(msg_send), None)),
1144 InteractiveTxMessageSend::TxAddOutput(msg) => for_constructor
1145 .handle_tx_add_output(&msg)
1146 .map(|msg_send| (Some(msg_send), None)),
1147 InteractiveTxMessageSend::TxComplete(msg) => {
1148 for_constructor.handle_tx_complete(&msg).map(|value| match value {
1149 HandleTxCompleteValue::SendTxMessage(msg_send) => {
1150 (Some(msg_send), None)
1152 HandleTxCompleteValue::SendTxComplete(msg_send, tx) => {
1153 (Some(msg_send), Some(tx))
1155 HandleTxCompleteValue::NegotiationComplete(tx) => (None, Some(tx)),
1161 assert!(first_message_b.is_none());
1162 let mut message_send_a = first_message_a;
1163 let mut message_send_b = None;
1164 let mut final_tx_a = None;
1165 let mut final_tx_b = None;
1166 while final_tx_a.is_none() || final_tx_b.is_none() {
1167 if let Some(message_send_a) = message_send_a.take() {
1168 match handle_message_send(message_send_a, &mut constructor_b) {
1169 Ok((msg_send, final_tx)) => {
1170 message_send_b = msg_send;
1171 final_tx_b = final_tx;
1173 Err(abort_reason) => {
1174 let error_culprit = match abort_reason {
1175 AbortReason::ExceededNumberOfInputsOrOutputs => {
1176 ErrorCulprit::Indeterminate
1178 _ => ErrorCulprit::NodeA,
1181 Some((abort_reason, error_culprit)),
1182 session.expect_error,
1186 assert!(message_send_b.is_none());
1191 if let Some(message_send_b) = message_send_b.take() {
1192 match handle_message_send(message_send_b, &mut constructor_a) {
1193 Ok((msg_send, final_tx)) => {
1194 message_send_a = msg_send;
1195 final_tx_a = final_tx;
1197 Err(abort_reason) => {
1198 let error_culprit = match abort_reason {
1199 AbortReason::ExceededNumberOfInputsOrOutputs => {
1200 ErrorCulprit::Indeterminate
1202 _ => ErrorCulprit::NodeB,
1205 Some((abort_reason, error_culprit)),
1206 session.expect_error,
1210 assert!(message_send_a.is_none());
1216 assert!(message_send_a.is_none());
1217 assert!(message_send_b.is_none());
1218 assert_eq!(final_tx_a.unwrap().into_unsigned_tx(), final_tx_b.unwrap().into_unsigned_tx());
1219 assert!(session.expect_error.is_none(), "Test: {}", session.description);
1222 #[derive(Debug, Clone, Copy)]
1227 // Non-witness type to test rejection.
1231 fn generate_tx(outputs: &[TestOutput]) -> Transaction {
1232 generate_tx_with_locktime(outputs, 1337)
1235 fn generate_txout(output: &TestOutput) -> TxOut {
1236 let secp_ctx = Secp256k1::new();
1237 let (value, script_pubkey) = match output {
1238 TestOutput::P2WPKH(value) => {
1239 (*value, ScriptBuf::new_v0_p2wpkh(&WPubkeyHash::from_slice(&[1; 20]).unwrap()))
1241 TestOutput::P2WSH(value) => {
1242 (*value, ScriptBuf::new_v0_p2wsh(&WScriptHash::from_slice(&[2; 32]).unwrap()))
1244 TestOutput::P2TR(value) => (
1246 ScriptBuf::new_v1_p2tr(
1248 UntweakedPublicKey::from_keypair(
1249 &KeyPair::from_seckey_slice(&secp_ctx, &[3; 32]).unwrap(),
1255 TestOutput::P2PKH(value) => {
1256 (*value, ScriptBuf::new_p2pkh(&PubkeyHash::from_slice(&[4; 20]).unwrap()))
1260 TxOut { value, script_pubkey }
1263 fn generate_tx_with_locktime(outputs: &[TestOutput], locktime: u32) -> Transaction {
1266 lock_time: AbsoluteLockTime::from_height(locktime).unwrap(),
1267 input: vec![TxIn { ..Default::default() }],
1268 output: outputs.iter().map(generate_txout).collect(),
1272 fn generate_inputs(outputs: &[TestOutput]) -> Vec<(TxIn, TransactionU16LenLimited)> {
1273 let tx = generate_tx(outputs);
1274 let txid = tx.txid();
1280 previous_output: OutPoint { txid, vout: idx as u32 },
1281 script_sig: Default::default(),
1282 sequence: Sequence::ENABLE_RBF_NO_LOCKTIME,
1283 witness: Default::default(),
1285 (input, TransactionU16LenLimited::new(tx.clone()).unwrap())
1290 fn generate_p2wsh_script_pubkey() -> ScriptBuf {
1291 Builder::new().push_opcode(opcodes::OP_TRUE).into_script().to_v0_p2wsh()
1294 fn generate_p2wpkh_script_pubkey() -> ScriptBuf {
1295 ScriptBuf::new_v0_p2wpkh(&WPubkeyHash::from_slice(&[1; 20]).unwrap())
1298 fn generate_outputs(outputs: &[TestOutput]) -> Vec<TxOut> {
1299 outputs.iter().map(generate_txout).collect()
1302 fn generate_fixed_number_of_inputs(count: u16) -> Vec<(TxIn, TransactionU16LenLimited)> {
1303 // Generate transactions with a total `count` number of outputs such that no transaction has a
1304 // serialized length greater than u16::MAX.
1305 let max_outputs_per_prevtx = 1_500;
1306 let mut remaining = count;
1307 let mut inputs: Vec<(TxIn, TransactionU16LenLimited)> = Vec::with_capacity(count as usize);
1309 while remaining > 0 {
1310 let tx_output_count = remaining.min(max_outputs_per_prevtx);
1311 remaining -= tx_output_count;
1313 // Use unique locktime for each tx so outpoints are different across transactions
1314 let tx = generate_tx_with_locktime(
1315 &vec![TestOutput::P2WPKH(1_000_000); tx_output_count as usize],
1316 (1337 + remaining).into(),
1318 let txid = tx.txid();
1320 let mut temp: Vec<(TxIn, TransactionU16LenLimited)> = tx
1326 previous_output: OutPoint { txid, vout: idx as u32 },
1327 script_sig: Default::default(),
1328 sequence: Sequence::ENABLE_RBF_NO_LOCKTIME,
1329 witness: Default::default(),
1331 (input, TransactionU16LenLimited::new(tx.clone()).unwrap())
1335 inputs.append(&mut temp);
1341 fn generate_fixed_number_of_outputs(count: u16) -> Vec<TxOut> {
1342 // Set a constant value for each TxOut
1343 generate_outputs(&vec![TestOutput::P2WPKH(1_000_000); count as usize])
1346 fn generate_p2sh_script_pubkey() -> ScriptBuf {
1347 Builder::new().push_opcode(opcodes::OP_TRUE).into_script().to_p2sh()
1350 fn generate_non_witness_output(value: u64) -> TxOut {
1351 TxOut { value, script_pubkey: generate_p2sh_script_pubkey() }
1355 fn test_interactive_tx_constructor() {
1356 do_test_interactive_tx_constructor(TestSession {
1357 description: "No contributions",
1362 expect_error: Some((AbortReason::InsufficientFees, ErrorCulprit::NodeA)),
1364 do_test_interactive_tx_constructor(TestSession {
1365 description: "Single contribution, no initiator inputs",
1367 outputs_a: generate_outputs(&[TestOutput::P2WPKH(1_000_000)]),
1370 expect_error: Some((AbortReason::OutputsValueExceedsInputsValue, ErrorCulprit::NodeA)),
1372 do_test_interactive_tx_constructor(TestSession {
1373 description: "Single contribution, no initiator outputs",
1374 inputs_a: generate_inputs(&[TestOutput::P2WPKH(1_000_000)]),
1380 do_test_interactive_tx_constructor(TestSession {
1381 description: "Single contribution, no fees",
1382 inputs_a: generate_inputs(&[TestOutput::P2WPKH(1_000_000)]),
1383 outputs_a: generate_outputs(&[TestOutput::P2WPKH(1_000_000)]),
1386 expect_error: Some((AbortReason::InsufficientFees, ErrorCulprit::NodeA)),
1388 let p2wpkh_fee = fee_for_weight(TEST_FEERATE_SATS_PER_KW, P2WPKH_INPUT_WEIGHT_LOWER_BOUND);
1389 let outputs_fee = fee_for_weight(
1390 TEST_FEERATE_SATS_PER_KW,
1391 get_output_weight(&generate_p2wpkh_script_pubkey()).to_wu(),
1393 let tx_common_fields_fee =
1394 fee_for_weight(TEST_FEERATE_SATS_PER_KW, TX_COMMON_FIELDS_WEIGHT);
1395 do_test_interactive_tx_constructor(TestSession {
1396 description: "Single contribution, with P2WPKH input, insufficient fees",
1397 inputs_a: generate_inputs(&[TestOutput::P2WPKH(1_000_000)]),
1398 outputs_a: generate_outputs(&[TestOutput::P2WPKH(
1399 1_000_000 - p2wpkh_fee - outputs_fee - tx_common_fields_fee + 1, /* makes fees insuffcient for initiator */
1403 expect_error: Some((AbortReason::InsufficientFees, ErrorCulprit::NodeA)),
1405 do_test_interactive_tx_constructor(TestSession {
1406 description: "Single contribution with P2WPKH input, sufficient 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,
1415 let p2wsh_fee = fee_for_weight(TEST_FEERATE_SATS_PER_KW, P2WSH_INPUT_WEIGHT_LOWER_BOUND);
1416 do_test_interactive_tx_constructor(TestSession {
1417 description: "Single contribution, with P2WSH input, insufficient fees",
1418 inputs_a: generate_inputs(&[TestOutput::P2WSH(1_000_000)]),
1419 outputs_a: generate_outputs(&[TestOutput::P2WPKH(
1420 1_000_000 - p2wsh_fee - outputs_fee - tx_common_fields_fee + 1, /* makes fees insuffcient for initiator */
1424 expect_error: Some((AbortReason::InsufficientFees, ErrorCulprit::NodeA)),
1426 do_test_interactive_tx_constructor(TestSession {
1427 description: "Single contribution with P2WSH input, sufficient 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,
1436 let p2tr_fee = fee_for_weight(TEST_FEERATE_SATS_PER_KW, P2TR_INPUT_WEIGHT_LOWER_BOUND);
1437 do_test_interactive_tx_constructor(TestSession {
1438 description: "Single contribution, with P2TR input, insufficient fees",
1439 inputs_a: generate_inputs(&[TestOutput::P2TR(1_000_000)]),
1440 outputs_a: generate_outputs(&[TestOutput::P2WPKH(
1441 1_000_000 - p2tr_fee - outputs_fee - tx_common_fields_fee + 1, /* makes fees insuffcient for initiator */
1445 expect_error: Some((AbortReason::InsufficientFees, ErrorCulprit::NodeA)),
1447 do_test_interactive_tx_constructor(TestSession {
1448 description: "Single contribution with P2TR input, sufficient 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,
1457 do_test_interactive_tx_constructor(TestSession {
1458 description: "Initiator contributes sufficient fees, but non-initiator does not",
1459 inputs_a: generate_inputs(&[TestOutput::P2WPKH(1_000_000)]),
1461 inputs_b: generate_inputs(&[TestOutput::P2WPKH(100_000)]),
1462 outputs_b: generate_outputs(&[TestOutput::P2WPKH(100_000)]),
1463 expect_error: Some((AbortReason::InsufficientFees, ErrorCulprit::NodeB)),
1465 do_test_interactive_tx_constructor(TestSession {
1466 description: "Multi-input-output contributions from both sides",
1467 inputs_a: generate_inputs(&[TestOutput::P2WPKH(1_000_000); 2]),
1468 outputs_a: generate_outputs(&[
1469 TestOutput::P2WPKH(1_000_000),
1470 TestOutput::P2WPKH(200_000),
1472 inputs_b: generate_inputs(&[
1473 TestOutput::P2WPKH(1_000_000),
1474 TestOutput::P2WPKH(500_000),
1476 outputs_b: generate_outputs(&[
1477 TestOutput::P2WPKH(1_000_000),
1478 TestOutput::P2WPKH(400_000),
1483 do_test_interactive_tx_constructor(TestSession {
1484 description: "Prevout from initiator is not a witness program",
1485 inputs_a: generate_inputs(&[TestOutput::P2PKH(1_000_000)]),
1489 expect_error: Some((AbortReason::PrevTxOutInvalid, ErrorCulprit::NodeA)),
1493 TransactionU16LenLimited::new(generate_tx(&[TestOutput::P2WPKH(1_000_000)])).unwrap();
1494 let invalid_sequence_input = TxIn {
1495 previous_output: OutPoint { txid: tx.as_transaction().txid(), vout: 0 },
1496 ..Default::default()
1498 do_test_interactive_tx_constructor(TestSession {
1499 description: "Invalid input sequence from initiator",
1500 inputs_a: vec![(invalid_sequence_input, tx.clone())],
1501 outputs_a: generate_outputs(&[TestOutput::P2WPKH(1_000_000)]),
1504 expect_error: Some((AbortReason::IncorrectInputSequenceValue, ErrorCulprit::NodeA)),
1506 let duplicate_input = TxIn {
1507 previous_output: OutPoint { txid: tx.as_transaction().txid(), vout: 0 },
1508 sequence: Sequence::ENABLE_RBF_NO_LOCKTIME,
1509 ..Default::default()
1511 do_test_interactive_tx_constructor(TestSession {
1512 description: "Duplicate prevout from initiator",
1513 inputs_a: vec![(duplicate_input.clone(), tx.clone()), (duplicate_input, tx.clone())],
1514 outputs_a: generate_outputs(&[TestOutput::P2WPKH(1_000_000)]),
1517 expect_error: Some((AbortReason::PrevTxOutInvalid, ErrorCulprit::NodeB)),
1519 let duplicate_input = TxIn {
1520 previous_output: OutPoint { txid: tx.as_transaction().txid(), vout: 0 },
1521 sequence: Sequence::ENABLE_RBF_NO_LOCKTIME,
1522 ..Default::default()
1524 do_test_interactive_tx_constructor(TestSession {
1525 description: "Non-initiator uses same prevout as initiator",
1526 inputs_a: vec![(duplicate_input.clone(), tx.clone())],
1527 outputs_a: generate_outputs(&[TestOutput::P2WPKH(1_000_000)]),
1528 inputs_b: vec![(duplicate_input.clone(), tx.clone())],
1530 expect_error: Some((AbortReason::PrevTxOutInvalid, ErrorCulprit::NodeA)),
1532 do_test_interactive_tx_constructor(TestSession {
1533 description: "Initiator sends too many TxAddInputs",
1534 inputs_a: generate_fixed_number_of_inputs(MAX_RECEIVED_TX_ADD_INPUT_COUNT + 1),
1538 expect_error: Some((AbortReason::ReceivedTooManyTxAddInputs, ErrorCulprit::NodeA)),
1540 do_test_interactive_tx_constructor_with_entropy_source(
1542 // We use a deliberately bad entropy source, `DuplicateEntropySource` to simulate this.
1543 description: "Attempt to queue up two inputs with duplicate serial ids",
1544 inputs_a: generate_fixed_number_of_inputs(2),
1548 expect_error: Some((AbortReason::DuplicateSerialId, ErrorCulprit::NodeA)),
1550 &DuplicateEntropySource,
1552 do_test_interactive_tx_constructor(TestSession {
1553 description: "Initiator sends too many TxAddOutputs",
1555 outputs_a: generate_fixed_number_of_outputs(MAX_RECEIVED_TX_ADD_OUTPUT_COUNT + 1),
1558 expect_error: Some((AbortReason::ReceivedTooManyTxAddOutputs, ErrorCulprit::NodeA)),
1560 do_test_interactive_tx_constructor(TestSession {
1561 description: "Initiator sends an output below dust value",
1563 outputs_a: generate_outputs(&[TestOutput::P2WSH(
1564 generate_p2wsh_script_pubkey().dust_value().to_sat() - 1,
1568 expect_error: Some((AbortReason::BelowDustLimit, ErrorCulprit::NodeA)),
1570 do_test_interactive_tx_constructor(TestSession {
1571 description: "Initiator sends an output above maximum sats allowed",
1573 outputs_a: generate_outputs(&[TestOutput::P2WPKH(TOTAL_BITCOIN_SUPPLY_SATOSHIS + 1)]),
1576 expect_error: Some((AbortReason::ExceededMaximumSatsAllowed, ErrorCulprit::NodeA)),
1578 do_test_interactive_tx_constructor(TestSession {
1579 description: "Initiator sends an output without a witness program",
1581 outputs_a: vec![generate_non_witness_output(1_000_000)],
1584 expect_error: Some((AbortReason::InvalidOutputScript, ErrorCulprit::NodeA)),
1586 do_test_interactive_tx_constructor_with_entropy_source(
1588 // We use a deliberately bad entropy source, `DuplicateEntropySource` to simulate this.
1589 description: "Attempt to queue up two outputs with duplicate serial ids",
1591 outputs_a: generate_fixed_number_of_outputs(2),
1594 expect_error: Some((AbortReason::DuplicateSerialId, ErrorCulprit::NodeA)),
1596 &DuplicateEntropySource,
1599 do_test_interactive_tx_constructor(TestSession {
1600 description: "Peer contributed more output value than inputs",
1601 inputs_a: generate_inputs(&[TestOutput::P2WPKH(100_000)]),
1602 outputs_a: generate_outputs(&[TestOutput::P2WPKH(1_000_000)]),
1605 expect_error: Some((AbortReason::OutputsValueExceedsInputsValue, ErrorCulprit::NodeA)),
1608 do_test_interactive_tx_constructor(TestSession {
1609 description: "Peer contributed more than allowed number of inputs",
1610 inputs_a: generate_fixed_number_of_inputs(MAX_INPUTS_OUTPUTS_COUNT as u16 + 1),
1614 expect_error: Some((
1615 AbortReason::ExceededNumberOfInputsOrOutputs,
1616 ErrorCulprit::Indeterminate,
1619 do_test_interactive_tx_constructor(TestSession {
1620 description: "Peer contributed more than allowed number of outputs",
1621 inputs_a: generate_inputs(&[TestOutput::P2WPKH(TOTAL_BITCOIN_SUPPLY_SATOSHIS)]),
1622 outputs_a: generate_fixed_number_of_outputs(MAX_INPUTS_OUTPUTS_COUNT as u16 + 1),
1625 expect_error: Some((
1626 AbortReason::ExceededNumberOfInputsOrOutputs,
1627 ErrorCulprit::Indeterminate,
1633 fn test_generate_local_serial_id() {
1634 let entropy_source = TestEntropySource(AtomicCounter::new());
1636 // Initiators should have even serial id, non-initiators should have odd serial id.
1637 assert_eq!(generate_holder_serial_id(&&entropy_source, true) % 2, 0);
1638 assert_eq!(generate_holder_serial_id(&&entropy_source, false) % 2, 1)