lightning_signer/util/
transaction_utils.rs

1use crate::io_extras::sink;
2use crate::prelude::*;
3use crate::tx::script::ANCHOR_OUTPUT_VALUE_SATOSHI;
4use anyhow::anyhow;
5use bitcoin::address::Payload;
6use bitcoin::consensus::Encodable;
7use bitcoin::secp256k1::ecdsa::Signature;
8use bitcoin::secp256k1::{All, PublicKey, Secp256k1};
9use bitcoin::sighash::EcdsaSighashType;
10use bitcoin::{PublicKey as BitcoinPublicKey, ScriptBuf, Sequence, TxIn, Witness};
11use bitcoin::{Transaction, TxOut, VarInt};
12use lightning::ln::chan_utils::{
13    get_commitment_transaction_number_obscure_factor, get_revokeable_redeemscript,
14    get_to_countersignatory_with_anchors_redeemscript, make_funding_redeemscript,
15    ChannelTransactionParameters, TxCreationKeys,
16};
17use lightning::sign::{
18    DelayedPaymentOutputDescriptor, SpendableOutputDescriptor, StaticPaymentOutputDescriptor,
19};
20
21/// The maximum value of an input or output in milli satoshi
22pub const MAX_VALUE_MSAT: u64 = 21_000_000_0000_0000_000;
23
24/// The minimum value of the dust limit in satoshis - for p2wsh outputs
25/// (such as anchors)
26pub const MIN_DUST_LIMIT_SATOSHIS: u64 = 330;
27/// The minimum value of the dust limit in satoshis - for segwit in general
28/// This is also the minimum negotiated dust limit
29pub const MIN_CHAN_DUST_LIMIT_SATOSHIS: u64 = 354;
30
31/// The expected weight of a commitment transaction
32pub(crate) fn expected_commitment_tx_weight(opt_anchors: bool, num_untrimmed_htlc: usize) -> usize {
33    const COMMITMENT_TX_BASE_WEIGHT: usize = 724;
34    const COMMITMENT_TX_BASE_ANCHOR_WEIGHT: usize = 1124;
35    const COMMITMENT_TX_WEIGHT_PER_HTLC: usize = 172;
36    let base_weight =
37        if opt_anchors { COMMITMENT_TX_BASE_ANCHOR_WEIGHT } else { COMMITMENT_TX_BASE_WEIGHT };
38    base_weight + num_untrimmed_htlc * COMMITMENT_TX_WEIGHT_PER_HTLC
39}
40
41/// The weight of a mutual close transaction.
42pub(crate) fn mutual_close_tx_weight(unsigned_tx: &Transaction) -> usize {
43    // NOTE related to issue 165 - we use 72 here because we might as well assume low-S
44    // for the signature, and some node implementations use that.
45    // However, nodes may use 73 to be consistent with BOLT-3.
46    // That's OK because we will be more lenient on the fee.
47    const EXPECTED_MUTUAL_CLOSE_WITNESS_WEIGHT: usize = //
48        2 + 1 + 4 + // witness-marker-and-flag witness-element-count 4-element-lengths
49        72 + 72 + // <signature_for_pubkey1> <signature_for_pubkey2>
50        1 + 1 + 33 + 1 + 33 + 1 + 1; // 2 <pubkey1> <pubkey2> 2 OP_CHECKMULTISIG
51    unsigned_tx.weight().to_wu() as usize + EXPECTED_MUTUAL_CLOSE_WITNESS_WEIGHT
52}
53
54/// Possibly adds a change output to the given transaction, always doing so if there are excess
55/// funds available beyond the requested feerate.
56/// Assumes at least one input will have a witness (ie spends a segwit output).
57/// Returns an Err(()) if the requested feerate cannot be met.
58pub fn maybe_add_change_output(
59    tx: &mut Transaction,
60    input_value: u64,
61    witness_max_weight: u64,
62    feerate_sat_per_1000_weight: u32,
63    change_destination_script: ScriptBuf,
64) -> Result<(), ()> {
65    if input_value > MAX_VALUE_MSAT / 1000 {
66        //bail!("Input value is greater than max satoshis");
67        return Err(());
68    }
69
70    let mut output_value = 0;
71    for output in tx.output.iter() {
72        output_value += output.value;
73        if output_value >= input_value {
74            // bail!("Ouput value equals or exceeds input value");
75            return Err(());
76        }
77    }
78
79    let dust_value = change_destination_script.dust_value();
80    let mut change_output = TxOut { script_pubkey: change_destination_script, value: 0 };
81    let change_len = change_output.consensus_encode(&mut sink()).map_err(|_| ())?;
82    let mut weight_with_change: i64 =
83        tx.weight().to_wu() as i64 + 2 + witness_max_weight as i64 + change_len as i64 * 4;
84    // Include any extra bytes required to push an extra output.
85    weight_with_change += (VarInt(tx.output.len() as u64 + 1).len()
86        - VarInt(tx.output.len() as u64).len()) as i64
87        * 4;
88    // When calculating weight, add two for the flag bytes
89    let change_value: i64 = (input_value - output_value) as i64
90        - weight_with_change * feerate_sat_per_1000_weight as i64 / 1000;
91    if change_value >= dust_value.to_sat() as i64 {
92        change_output.value = change_value as u64;
93        tx.output.push(change_output);
94    } else if (input_value - output_value) as i64
95        - (tx.weight().to_wu() as i64 + 2 + witness_max_weight as i64)
96            * feerate_sat_per_1000_weight as i64
97            / 1000
98        < 0
99    {
100        // bail!("Requested fee rate cannot be met");
101        return Err(());
102    }
103
104    Ok(())
105}
106
107/// Estimate the feerate for an HTLC transaction
108pub(crate) fn estimate_feerate_per_kw(total_fee: u64, weight: u64) -> u32 {
109    // we want the highest feerate that can give rise to this total fee
110    (((total_fee * 1000) + 999) / weight) as u32
111}
112
113pub(crate) fn add_holder_sig(
114    tx: &mut Transaction,
115    holder_sig: Signature,
116    counterparty_sig: Signature,
117    holder_funding_key: &PublicKey,
118    counterparty_funding_key: &PublicKey,
119) {
120    let funding_redeemscript =
121        make_funding_redeemscript(&holder_funding_key, &counterparty_funding_key);
122
123    tx.input[0].witness.push(Vec::new());
124    let mut ser_holder_sig = holder_sig.serialize_der().to_vec();
125    ser_holder_sig.push(EcdsaSighashType::All as u8);
126    let mut ser_cp_sig = counterparty_sig.serialize_der().to_vec();
127    ser_cp_sig.push(EcdsaSighashType::All as u8);
128
129    let holder_sig_first =
130        holder_funding_key.serialize()[..] < counterparty_funding_key.serialize()[..];
131
132    if holder_sig_first {
133        tx.input[0].witness.push(ser_holder_sig);
134        tx.input[0].witness.push(ser_cp_sig);
135    } else {
136        tx.input[0].witness.push(ser_cp_sig);
137        tx.input[0].witness.push(ser_holder_sig);
138    }
139
140    tx.input[0].witness.push(funding_redeemscript.as_bytes().to_vec());
141}
142
143pub(crate) fn is_tx_non_malleable(tx: &Transaction, segwit_flags: &[bool]) -> bool {
144    assert_eq!(tx.input.len(), segwit_flags.len(), "tx and segwit_flags must have same length");
145    segwit_flags.iter().all(|flag| *flag)
146}
147
148/// Decode a commitment transaction and return the outputs that we need to watch.
149/// Our main output index and any HTLC output indexes are returned.
150///
151/// `cp_per_commitment_point` is filled in if known, otherwise None.  It might
152/// not be known if the signer is old, before we started collecting counterparty secrets.
153/// If it is None, then we won't be able to tell the difference between a counterparty
154/// to-self output and an HTLC output.
155///
156/// The counterparty parameters must be populated.
157pub fn decode_commitment_tx(
158    tx: &Transaction,
159    holder_per_commitment_point: &PublicKey,
160    cp_per_commitment_point: &Option<PublicKey>,
161    params: &ChannelTransactionParameters,
162    secp_ctx: &Secp256k1<All>,
163) -> (Option<u32>, Vec<u32>) {
164    let cp_params = params.counterparty_parameters.as_ref().unwrap();
165
166    let opt_anchors = params.channel_type_features.supports_anchors_nonzero_fee_htlc_tx()
167        || params.channel_type_features.supports_anchors_zero_fee_htlc_tx();
168    let holder_pubkeys = &params.holder_pubkeys;
169    let cp_pubkeys = &cp_params.pubkeys;
170
171    let holder_non_delayed_script = if opt_anchors {
172        get_to_countersignatory_with_anchors_redeemscript(&holder_pubkeys.payment_point)
173            .to_v0_p2wsh()
174    } else {
175        Payload::p2wpkh(&BitcoinPublicKey::new(holder_pubkeys.payment_point))
176            .unwrap()
177            .script_pubkey()
178    };
179
180    // compute the transaction keys we would have used if this is a holder commitment
181    let holder_tx_keys = TxCreationKeys::derive_new(
182        secp_ctx,
183        &holder_per_commitment_point,
184        &holder_pubkeys.delayed_payment_basepoint,
185        &holder_pubkeys.htlc_basepoint,
186        &cp_pubkeys.revocation_basepoint,
187        &cp_pubkeys.htlc_basepoint,
188    );
189
190    let holder_delayed_redeem_script = get_revokeable_redeemscript(
191        &holder_tx_keys.revocation_key,
192        cp_params.selected_contest_delay,
193        &holder_tx_keys.broadcaster_delayed_payment_key,
194    );
195
196    let holder_delayed_script = holder_delayed_redeem_script.to_v0_p2wsh();
197
198    let cp_delayed_script = if let Some(cp_per_commitment_point) = cp_per_commitment_point {
199        // compute the transaction keys we would have used if this is a holder commitment
200        let cp_tx_keys = TxCreationKeys::derive_new(
201            secp_ctx,
202            &cp_per_commitment_point,
203            &cp_pubkeys.delayed_payment_basepoint,
204            &cp_pubkeys.htlc_basepoint,
205            &holder_pubkeys.revocation_basepoint,
206            &holder_pubkeys.htlc_basepoint,
207        );
208
209        let cp_delayed_redeem_script = get_revokeable_redeemscript(
210            &cp_tx_keys.revocation_key,
211            params.holder_selected_contest_delay,
212            &cp_tx_keys.broadcaster_delayed_payment_key,
213        );
214
215        Some(cp_delayed_redeem_script.to_v0_p2wsh())
216    } else {
217        None
218    };
219
220    let mut htlcs = Vec::new();
221    let mut main_output_index = None;
222
223    // find the output that pays to us, if any
224    for (idx, output) in tx.output.iter().enumerate() {
225        // we don't track anchors
226        if output.value == ANCHOR_OUTPUT_VALUE_SATOSHI {
227            continue;
228        }
229
230        if Some(&output.script_pubkey) == cp_delayed_script.as_ref() {
231            continue;
232        }
233
234        // look for our main output, either when broadcast by us or by our counterparty
235        if output.script_pubkey == holder_non_delayed_script
236            || output.script_pubkey == holder_delayed_script
237        {
238            main_output_index = Some(idx as u32);
239        } else if output.script_pubkey.is_v0_p2wsh() {
240            htlcs.push(idx as u32);
241        }
242    }
243
244    (main_output_index, htlcs)
245}
246
247/// Decode a commitment transaction and return the commitment number if it is a commitment tx
248pub fn decode_commitment_number(
249    tx: &Transaction,
250    params: &ChannelTransactionParameters,
251) -> Option<u64> {
252    let holder_pubkeys = &params.holder_pubkeys;
253    let cp_params = params.counterparty_parameters.as_ref().unwrap();
254    let cp_pubkeys = &cp_params.pubkeys;
255
256    let obscure_factor = get_commitment_transaction_number_obscure_factor(
257        &holder_pubkeys.payment_point,
258        &cp_pubkeys.payment_point,
259        params.is_outbound_from_holder,
260    );
261
262    // if the tx has more than one input, it's not a standard closing tx,
263    // so we bail
264    if tx.input.len() != 1 {
265        return None;
266    }
267
268    // check if the input sequence and locktime are set to standard commitment tx values
269    if (tx.input[0].sequence.0 >> 8 * 3) as u8 != 0x80
270        || (tx.lock_time.to_consensus_u32() >> 8 * 3) as u8 != 0x20
271    {
272        return None;
273    }
274
275    // forward counting
276    let commitment_number = (((tx.input[0].sequence.0 as u64 & 0xffffff) << 3 * 8)
277        | (tx.lock_time.to_consensus_u32() as u64 & 0xffffff))
278        ^ obscure_factor;
279    Some(commitment_number)
280}
281
282/// Create a spending transaction, helper function used in [`KeysManagerClient::spend_spendable_outputs`].
283///
284/// [`KeysManagerClient::spend_spendable_outputsspend_spendable_outputs`] vls_protocol_client::KeysManagerClient::spend_spendable_outputsspend_spendable_outputs
285pub fn create_spending_transaction(
286    descriptors: &[&SpendableOutputDescriptor],
287    outputs: Vec<TxOut>,
288    change_destination_script: ScriptBuf,
289    feerate_sats_per_1000_weight: u32,
290) -> anyhow::Result<Transaction> {
291    let mut input = Vec::new();
292    let mut input_value = 0;
293    let mut witness_weight = 0;
294    let mut output_set = UnorderedSet::with_capacity(descriptors.len());
295    for outp in descriptors {
296        match outp {
297            SpendableOutputDescriptor::StaticPaymentOutput(descriptor) => {
298                input.push(TxIn {
299                    previous_output: descriptor.outpoint.into_bitcoin_outpoint(),
300                    script_sig: ScriptBuf::new(),
301                    sequence: Sequence(1),
302                    witness: Witness::new(),
303                });
304                witness_weight += StaticPaymentOutputDescriptor::max_witness_length(descriptor);
305                input_value += descriptor.output.value;
306                if !output_set.insert(descriptor.outpoint) {
307                    return Err(anyhow!("duplicate"));
308                }
309            }
310            SpendableOutputDescriptor::DelayedPaymentOutput(descriptor) => {
311                input.push(TxIn {
312                    previous_output: descriptor.outpoint.into_bitcoin_outpoint(),
313                    script_sig: ScriptBuf::new(),
314                    sequence: Sequence(descriptor.to_self_delay as u32),
315                    witness: Witness::new(),
316                });
317                witness_weight += DelayedPaymentOutputDescriptor::MAX_WITNESS_LENGTH;
318                input_value += descriptor.output.value;
319                if !output_set.insert(descriptor.outpoint) {
320                    return Err(anyhow!("duplicate"));
321                }
322            }
323
324            SpendableOutputDescriptor::StaticOutput {
325                ref outpoint,
326                ref output,
327                channel_keys_id: _,
328            } => {
329                input.push(TxIn {
330                    previous_output: outpoint.into_bitcoin_outpoint(),
331                    script_sig: ScriptBuf::new(),
332                    sequence: Sequence::ZERO,
333                    witness: Witness::default(),
334                });
335                witness_weight += 1 + 73 + 34;
336                input_value += output.value;
337                if !output_set.insert(*outpoint) {
338                    return Err(anyhow!("duplicate"));
339                }
340            }
341        }
342
343        if input_value > MAX_VALUE_MSAT / 1000 {
344            return Err(anyhow!("overflow"));
345        }
346    }
347
348    let mut spend_tx = Transaction {
349        version: 2,
350        lock_time: bitcoin::absolute::LockTime::ZERO,
351        input,
352        output: outputs,
353    };
354    maybe_add_change_output(
355        &mut spend_tx,
356        input_value,
357        witness_weight,
358        feerate_sats_per_1000_weight,
359        change_destination_script,
360    )
361    .map_err(|()| anyhow!("could not add or change"))?;
362    Ok(spend_tx)
363}
364
365#[cfg(test)]
366mod tests {
367    use super::*;
368    use crate::channel::ChannelBase;
369    use crate::util::test_utils::{
370        init_node_and_channel, make_test_channel_setup, TEST_NODE_CONFIG, TEST_SEED,
371    };
372    use bitcoin::consensus::deserialize;
373    use bitcoin::hashes::hex::FromHex;
374    use bitcoin::secp256k1::SecretKey;
375    use bitcoin::Transaction;
376    use lightning::ln::chan_utils::{htlc_success_tx_weight, htlc_timeout_tx_weight};
377    use lightning::ln::features::ChannelTypeFeatures;
378
379    #[test]
380    fn test_parse_closing_tx_holder() {
381        let secp_ctx = Secp256k1::new();
382        let commitment_number = 0;
383        let (node, channel_id) =
384            init_node_and_channel(TEST_NODE_CONFIG, TEST_SEED[0], make_test_channel_setup());
385        let params = node
386            .with_channel(&channel_id, |channel| Ok(channel.make_channel_parameters()))
387            .unwrap();
388
389        let (holder_commitment, per_commitment_point) = node
390            .with_channel(&channel_id, |channel| {
391                let per_commitment_point =
392                    channel.get_per_commitment_point(commitment_number).unwrap();
393                let keys = channel.make_holder_tx_keys(&per_commitment_point);
394                let per_commitment_point = channel.get_per_commitment_point(commitment_number)?;
395                Ok((
396                    channel.make_holder_commitment_tx(
397                        commitment_number,
398                        &keys,
399                        123,
400                        1000,
401                        100,
402                        Vec::new(),
403                    ),
404                    per_commitment_point,
405                ))
406            })
407            .unwrap();
408        let holder_tx = holder_commitment.trust().built_transaction().transaction.clone();
409        let parsed_commitment_number = decode_commitment_number(&holder_tx, &params).unwrap();
410        assert_eq!(parsed_commitment_number, commitment_number);
411        let (parsed_main, htlcs) =
412            decode_commitment_tx(&holder_tx, &per_commitment_point, &None, &params, &secp_ctx);
413        let our_main =
414            holder_tx.output.iter().position(|txout| txout.script_pubkey.is_v0_p2wsh()).unwrap();
415        assert_eq!(parsed_main, Some(our_main as u32));
416        assert!(htlcs.is_empty());
417    }
418
419    #[test]
420    fn test_parse_closing_tx_counterparty() {
421        let secp_ctx = Secp256k1::new();
422        let commitment_number = 0;
423        let (node, channel_id) =
424            init_node_and_channel(TEST_NODE_CONFIG, TEST_SEED[0], make_test_channel_setup());
425        let params = node
426            .with_channel(&channel_id, |channel| Ok(channel.make_channel_parameters()))
427            .unwrap();
428
429        let cp_per_commitment_secret = SecretKey::from_slice(&[2; 32]).unwrap();
430        let cp_per_commitment_point =
431            PublicKey::from_secret_key(&secp_ctx, &cp_per_commitment_secret);
432        let (cp_commitment, holder_per_commitment_point) = node
433            .with_channel(&channel_id, |channel| {
434                // this is not used in the test because we are parsing a counterparty commitment,
435                // but we need to set it to something different than the counterparty one
436                let holder_per_commitment_point =
437                    channel.get_per_commitment_point(commitment_number)?;
438                Ok((
439                    channel.make_counterparty_commitment_tx(
440                        &cp_per_commitment_point,
441                        commitment_number,
442                        123,
443                        1000,
444                        100,
445                        Vec::new(),
446                    ),
447                    holder_per_commitment_point,
448                ))
449            })
450            .unwrap();
451        let cp_tx = cp_commitment.trust().built_transaction().transaction.clone();
452        let parsed_commit_number = decode_commitment_number(&cp_tx, &params).unwrap();
453        assert_eq!(parsed_commit_number, commitment_number);
454        let (parsed_main, htlcs) = decode_commitment_tx(
455            &cp_tx,
456            &holder_per_commitment_point,
457            &Some(cp_per_commitment_point),
458            &params,
459            &secp_ctx,
460        );
461        let our_main =
462            cp_tx.output.iter().position(|txout| txout.script_pubkey.is_v0_p2wpkh()).unwrap();
463        assert_eq!(parsed_main, Some(our_main as u32));
464        println!("htlcs: {:?}", htlcs);
465        assert!(htlcs.is_empty());
466    }
467
468    #[test]
469    fn test_estimate_feerate() {
470        let non_anchor_features = ChannelTypeFeatures::empty();
471        let mut anchor_features = ChannelTypeFeatures::empty();
472        anchor_features.set_anchors_zero_fee_htlc_tx_optional();
473        let weights = vec![
474            htlc_timeout_tx_weight(&non_anchor_features),
475            htlc_timeout_tx_weight(&anchor_features),
476            htlc_success_tx_weight(&non_anchor_features),
477            htlc_success_tx_weight(&anchor_features),
478        ];
479
480        // make sure the feerate is not lower than 253 at the low end,
481        // so as not to fail policy check
482        let feerate = 253;
483        for weight in &weights {
484            let total_fee = (feerate as u64 * *weight) / 1000;
485            let estimated_feerate = super::estimate_feerate_per_kw(total_fee, *weight);
486            assert!(estimated_feerate >= 253);
487        }
488
489        // make sure that the total tx fee stays the same after estimating the rate and recomputing the fee
490        // so as to recreate an identical transaction
491        for feerate in (300..5000).step_by(10) {
492            for weight in &weights {
493                let total_fee = (feerate as u64 * *weight) / 1000;
494                let estimated_feerate = super::estimate_feerate_per_kw(total_fee, *weight);
495                let recovered_total_fee = (estimated_feerate as u64 * *weight) / 1000;
496                assert_eq!(total_fee, recovered_total_fee);
497            }
498        }
499    }
500
501    #[test]
502    fn test_issue_165() {
503        let tx: Transaction = deserialize(&Vec::from_hex("0200000001b78e0523c17f8ac709eec54654cc849529c05584bfda6e04c92a3b670476f2a20000000000ffffffff017d4417000000000016001476168b09afc66bd3956efb25cd8b83650bda0c5f00000000").unwrap()).unwrap();
504        let tx_weight = tx.weight();
505        let spk = tx.output[0].script_pubkey.len();
506        let weight = super::mutual_close_tx_weight(&tx);
507        let fee = 1524999 - tx.output[0].value;
508        let estimated_feerate = super::estimate_feerate_per_kw(fee, weight as u64);
509        let expected_tx_weight = (4 +                                           // version
510            1 +                                           // input count
511            36 +                                          // prevout
512            1 +                                           // script length (0)
513            4 +                                           // sequence
514            1 +                                           // output count
515            4                                             // lock time
516        )*4 +                                         // * 4 for non-witness parts
517            ((8+1) +                            // output values and script length
518                spk as u64) * 4; // scriptpubkey and witness multiplier
519        assert_eq!(expected_tx_weight, tx_weight.to_wu());
520        // CLN was actually missing the pubkey length byte, so the feerate is genuinely too low
521        assert_eq!(estimated_feerate, 252);
522    }
523}