lightning/ln/
funding.rs

1// This file is Copyright its original authors, visible in version control
2// history.
3//
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
8// licenses.
9
10//! Types pertaining to funding channels.
11
12use alloc::vec::Vec;
13
14use bitcoin::{Amount, ScriptBuf, SignedAmount, TxOut};
15use bitcoin::{Script, Sequence, Transaction, Weight};
16
17use crate::events::bump_transaction::Utxo;
18use crate::ln::chan_utils::EMPTY_SCRIPT_SIG_WEIGHT;
19use crate::sign::{P2TR_KEY_PATH_WITNESS_WEIGHT, P2WPKH_WITNESS_WEIGHT};
20
21/// The components of a splice's funding transaction that are contributed by one party.
22#[derive(Debug, Clone)]
23pub enum SpliceContribution {
24	/// When funds are added to a channel.
25	SpliceIn {
26		/// The amount to contribute to the splice.
27		value: Amount,
28
29		/// The inputs included in the splice's funding transaction to meet the contributed amount
30		/// plus fees. Any excess amount will be sent to a change output.
31		inputs: Vec<FundingTxInput>,
32
33		/// An optional change output script. This will be used if needed or, when not set,
34		/// generated using [`SignerProvider::get_destination_script`].
35		///
36		/// [`SignerProvider::get_destination_script`]: crate::sign::SignerProvider::get_destination_script
37		change_script: Option<ScriptBuf>,
38	},
39	/// When funds are removed from a channel.
40	SpliceOut {
41		/// The outputs to include in the splice's funding transaction. The total value of all
42		/// outputs plus fees will be the amount that is removed.
43		outputs: Vec<TxOut>,
44	},
45}
46
47impl SpliceContribution {
48	pub(super) fn value(&self) -> SignedAmount {
49		match self {
50			SpliceContribution::SpliceIn { value, .. } => {
51				value.to_signed().unwrap_or(SignedAmount::MAX)
52			},
53			SpliceContribution::SpliceOut { outputs } => {
54				let value_removed = outputs
55					.iter()
56					.map(|txout| txout.value)
57					.sum::<Amount>()
58					.to_signed()
59					.unwrap_or(SignedAmount::MAX);
60				-value_removed
61			},
62		}
63	}
64
65	pub(super) fn inputs(&self) -> &[FundingTxInput] {
66		match self {
67			SpliceContribution::SpliceIn { inputs, .. } => &inputs[..],
68			SpliceContribution::SpliceOut { .. } => &[],
69		}
70	}
71
72	pub(super) fn outputs(&self) -> &[TxOut] {
73		match self {
74			SpliceContribution::SpliceIn { .. } => &[],
75			SpliceContribution::SpliceOut { outputs } => &outputs[..],
76		}
77	}
78
79	pub(super) fn into_tx_parts(self) -> (Vec<FundingTxInput>, Vec<TxOut>, Option<ScriptBuf>) {
80		match self {
81			SpliceContribution::SpliceIn { inputs, change_script, .. } => {
82				(inputs, vec![], change_script)
83			},
84			SpliceContribution::SpliceOut { outputs } => (vec![], outputs, None),
85		}
86	}
87}
88
89/// An input to contribute to a channel's funding transaction either when using the v2 channel
90/// establishment protocol or when splicing.
91#[derive(Debug, Clone)]
92pub struct FundingTxInput {
93	/// The unspent [`TxOut`] that the input spends.
94	///
95	/// [`TxOut`]: bitcoin::TxOut
96	pub(super) utxo: Utxo,
97
98	/// The sequence number to use in the [`TxIn`].
99	///
100	/// [`TxIn`]: bitcoin::TxIn
101	pub(super) sequence: Sequence,
102
103	/// The transaction containing the unspent [`TxOut`] referenced by [`utxo`].
104	///
105	/// [`TxOut`]: bitcoin::TxOut
106	/// [`utxo`]: Self::utxo
107	pub(super) prevtx: Transaction,
108}
109
110impl_writeable_tlv_based!(FundingTxInput, {
111	(1, utxo, required),
112	(3, sequence, required),
113	(5, prevtx, required),
114});
115
116impl FundingTxInput {
117	fn new<F: FnOnce(&bitcoin::Script) -> bool>(
118		prevtx: Transaction, vout: u32, witness_weight: Weight, script_filter: F,
119	) -> Result<Self, ()> {
120		Ok(FundingTxInput {
121			utxo: Utxo {
122				outpoint: bitcoin::OutPoint { txid: prevtx.compute_txid(), vout },
123				output: prevtx
124					.output
125					.get(vout as usize)
126					.filter(|output| script_filter(&output.script_pubkey))
127					.ok_or(())?
128					.clone(),
129				satisfaction_weight: EMPTY_SCRIPT_SIG_WEIGHT + witness_weight.to_wu(),
130			},
131			sequence: Sequence::ENABLE_RBF_NO_LOCKTIME,
132			prevtx,
133		})
134	}
135
136	/// Creates an input spending a P2WPKH output from the given `prevtx` at index `vout`.
137	///
138	/// Uses [`Sequence::ENABLE_RBF_NO_LOCKTIME`] as the [`TxIn::sequence`], which can be overridden
139	/// by [`set_sequence`].
140	///
141	/// Returns `Err` if no such output exists in `prevtx` at index `vout`.
142	///
143	/// [`TxIn::sequence`]: bitcoin::TxIn::sequence
144	/// [`set_sequence`]: Self::set_sequence
145	pub fn new_p2wpkh(prevtx: Transaction, vout: u32) -> Result<Self, ()> {
146		let witness_weight = Weight::from_wu(P2WPKH_WITNESS_WEIGHT)
147			- if cfg!(feature = "grind_signatures") {
148				// Guarantees a low R signature
149				Weight::from_wu(1)
150			} else {
151				Weight::ZERO
152			};
153		FundingTxInput::new(prevtx, vout, witness_weight, Script::is_p2wpkh)
154	}
155
156	/// Creates an input spending a P2WSH output from the given `prevtx` at index `vout`.
157	///
158	/// Requires passing the weight of witness needed to satisfy the output's script.
159	///
160	/// Uses [`Sequence::ENABLE_RBF_NO_LOCKTIME`] as the [`TxIn::sequence`], which can be overridden
161	/// by [`set_sequence`].
162	///
163	/// Returns `Err` if no such output exists in `prevtx` at index `vout`.
164	///
165	/// [`TxIn::sequence`]: bitcoin::TxIn::sequence
166	/// [`set_sequence`]: Self::set_sequence
167	pub fn new_p2wsh(prevtx: Transaction, vout: u32, witness_weight: Weight) -> Result<Self, ()> {
168		FundingTxInput::new(prevtx, vout, witness_weight, Script::is_p2wsh)
169	}
170
171	/// Creates an input spending a P2TR output from the given `prevtx` at index `vout`.
172	///
173	/// This is meant for inputs spending a taproot output using the key path. See
174	/// [`new_p2tr_script_spend`] for when spending using a script path.
175	///
176	/// Uses [`Sequence::ENABLE_RBF_NO_LOCKTIME`] as the [`TxIn::sequence`], which can be overridden
177	/// by [`set_sequence`].
178	///
179	/// Returns `Err` if no such output exists in `prevtx` at index `vout`.
180	///
181	/// [`new_p2tr_script_spend`]: Self::new_p2tr_script_spend
182	///
183	/// [`TxIn::sequence`]: bitcoin::TxIn::sequence
184	/// [`set_sequence`]: Self::set_sequence
185	pub fn new_p2tr_key_spend(prevtx: Transaction, vout: u32) -> Result<Self, ()> {
186		let witness_weight = Weight::from_wu(P2TR_KEY_PATH_WITNESS_WEIGHT);
187		FundingTxInput::new(prevtx, vout, witness_weight, Script::is_p2tr)
188	}
189
190	/// Creates an input spending a P2TR output from the given `prevtx` at index `vout`.
191	///
192	/// Requires passing the weight of witness needed to satisfy a script path of the taproot
193	/// output. See [`new_p2tr_key_spend`] for when spending using the key path.
194	///
195	/// Uses [`Sequence::ENABLE_RBF_NO_LOCKTIME`] as the [`TxIn::sequence`], which can be overridden
196	/// by [`set_sequence`].
197	///
198	/// Returns `Err` if no such output exists in `prevtx` at index `vout`.
199	///
200	/// [`new_p2tr_key_spend`]: Self::new_p2tr_key_spend
201	///
202	/// [`TxIn::sequence`]: bitcoin::TxIn::sequence
203	/// [`set_sequence`]: Self::set_sequence
204	pub fn new_p2tr_script_spend(
205		prevtx: Transaction, vout: u32, witness_weight: Weight,
206	) -> Result<Self, ()> {
207		FundingTxInput::new(prevtx, vout, witness_weight, Script::is_p2tr)
208	}
209
210	#[cfg(test)]
211	pub(crate) fn new_p2pkh(prevtx: Transaction, vout: u32) -> Result<Self, ()> {
212		FundingTxInput::new(prevtx, vout, Weight::ZERO, Script::is_p2pkh)
213	}
214
215	/// The outpoint of the UTXO being spent.
216	pub fn outpoint(&self) -> bitcoin::OutPoint {
217		self.utxo.outpoint
218	}
219
220	/// The sequence number to use in the [`TxIn`].
221	///
222	/// [`TxIn`]: bitcoin::TxIn
223	pub fn sequence(&self) -> Sequence {
224		self.sequence
225	}
226
227	/// Sets the sequence number to use in the [`TxIn`].
228	///
229	/// [`TxIn`]: bitcoin::TxIn
230	pub fn set_sequence(&mut self, sequence: Sequence) {
231		self.sequence = sequence;
232	}
233
234	/// Converts the [`FundingTxInput`] into a [`Utxo`] for coin selection.
235	pub fn into_utxo(self) -> Utxo {
236		self.utxo
237	}
238}