Merge pull request #1352 from TheBlueMatt/2022-03-debug-rwlock
[rust-lightning] / lightning / src / ln / chan_utils.rs
index 80dd872a9de9cec9e6e3277cf0ccab8c4b2d9705..6dc05c2ef3c09e2fcd5fc16ad8a2ebe2427343d3 100644 (file)
@@ -42,8 +42,21 @@ use chain;
 
 pub(crate) const MAX_HTLCS: u16 = 483;
 
-pub(super) const HTLC_SUCCESS_TX_WEIGHT: u64 = 703;
-pub(super) const HTLC_TIMEOUT_TX_WEIGHT: u64 = 663;
+/// Gets the weight for an HTLC-Success transaction.
+#[inline]
+pub fn htlc_success_tx_weight(opt_anchors: bool) -> u64 {
+       const HTLC_SUCCESS_TX_WEIGHT: u64 = 703;
+       const HTLC_SUCCESS_ANCHOR_TX_WEIGHT: u64 = 706;
+       if opt_anchors { HTLC_SUCCESS_ANCHOR_TX_WEIGHT } else { HTLC_SUCCESS_TX_WEIGHT }
+}
+
+/// Gets the weight for an HTLC-Timeout transaction.
+#[inline]
+pub fn htlc_timeout_tx_weight(opt_anchors: bool) -> u64 {
+       const HTLC_TIMEOUT_TX_WEIGHT: u64 = 663;
+       const HTLC_TIMEOUT_ANCHOR_TX_WEIGHT: u64 = 666;
+       if opt_anchors { HTLC_TIMEOUT_ANCHOR_TX_WEIGHT } else { HTLC_TIMEOUT_TX_WEIGHT }
+}
 
 #[derive(PartialEq)]
 pub(crate) enum HTLCType {
@@ -127,10 +140,10 @@ pub fn build_closing_transaction(to_holder_value_sat: u64, to_counterparty_value
 /// Implements the per-commitment secret storage scheme from
 /// [BOLT 3](https://github.com/lightningnetwork/lightning-rfc/blob/dcbf8583976df087c79c3ce0b535311212e6812d/03-transactions.md#efficient-per-commitment-secret-storage).
 ///
-/// Allows us to keep track of all of the revocation secrets of counterarties in just 50*32 bytes
+/// Allows us to keep track of all of the revocation secrets of our counterparty in just 50*32 bytes
 /// or so.
 #[derive(Clone)]
-pub(crate) struct CounterpartyCommitmentSecrets {
+pub struct CounterpartyCommitmentSecrets {
        old_secrets: [([u8; 32], u64); 49],
 }
 
@@ -146,7 +159,8 @@ impl PartialEq for CounterpartyCommitmentSecrets {
 }
 
 impl CounterpartyCommitmentSecrets {
-       pub(crate) fn new() -> Self {
+       /// Creates a new empty `CounterpartyCommitmentSecrets` structure.
+       pub fn new() -> Self {
                Self { old_secrets: [([0; 32], 1 << 48); 49], }
        }
 
@@ -160,7 +174,9 @@ impl CounterpartyCommitmentSecrets {
                48
        }
 
-       pub(crate) fn get_min_seen_secret(&self) -> u64 {
+       /// Returns the minimum index of all stored secrets. Note that indexes start
+       /// at 1 << 48 and get decremented by one for each new secret.
+       pub fn get_min_seen_secret(&self) -> u64 {
                //TODO This can be optimized?
                let mut min = 1 << 48;
                for &(_, idx) in self.old_secrets.iter() {
@@ -184,7 +200,9 @@ impl CounterpartyCommitmentSecrets {
                res
        }
 
-       pub(crate) fn provide_secret(&mut self, idx: u64, secret: [u8; 32]) -> Result<(), ()> {
+       /// Inserts the `secret` at `idx`. Returns `Ok(())` if the secret
+       /// was generated in accordance with BOLT 3 and is consistent with previous secrets.
+       pub fn provide_secret(&mut self, idx: u64, secret: [u8; 32]) -> Result<(), ()> {
                let pos = Self::place_secret(idx);
                for i in 0..pos {
                        let (old_secret, old_idx) = self.old_secrets[i as usize];
@@ -199,8 +217,9 @@ impl CounterpartyCommitmentSecrets {
                Ok(())
        }
 
-       /// Can only fail if idx is < get_min_seen_secret
-       pub(crate) fn get_secret(&self, idx: u64) -> Option<[u8; 32]> {
+       /// Returns the secret at `idx`.
+       /// Returns `None` if `idx` is < [`CounterpartyCommitmentSecrets::get_min_seen_secret`].
+       pub fn get_secret(&self, idx: u64) -> Option<[u8; 32]> {
                for i in 0..self.old_secrets.len() {
                        if (idx & (!((1 << i) - 1))) == self.old_secrets[i].1 {
                                return Some(Self::derive_secret(self.old_secrets[i].0, i as u8, idx))
@@ -586,7 +605,7 @@ pub fn make_funding_redeemscript(broadcaster: &PublicKey, countersignatory: &Pub
 ///
 /// Panics if htlc.transaction_output_index.is_none() (as such HTLCs do not appear in the
 /// commitment transaction).
-pub fn build_htlc_transaction(commitment_txid: &Txid, feerate_per_kw: u32, contest_delay: u16, htlc: &HTLCOutputInCommitment, broadcaster_delayed_payment_key: &PublicKey, revocation_key: &PublicKey) -> Transaction {
+pub fn build_htlc_transaction(commitment_txid: &Txid, feerate_per_kw: u32, contest_delay: u16, htlc: &HTLCOutputInCommitment, opt_anchors: bool, broadcaster_delayed_payment_key: &PublicKey, revocation_key: &PublicKey) -> Transaction {
        let mut txins: Vec<TxIn> = Vec::new();
        txins.push(TxIn {
                previous_output: OutPoint {
@@ -594,15 +613,16 @@ pub fn build_htlc_transaction(commitment_txid: &Txid, feerate_per_kw: u32, conte
                        vout: htlc.transaction_output_index.expect("Can't build an HTLC transaction for a dust output"),
                },
                script_sig: Script::new(),
-               sequence: 0,
+               sequence: if opt_anchors { 1 } else { 0 },
                witness: Vec::new(),
        });
 
-       let total_fee = if htlc.offered {
-                       feerate_per_kw as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000
-               } else {
-                       feerate_per_kw as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000
-               };
+       let weight = if htlc.offered {
+               htlc_timeout_tx_weight(opt_anchors)
+       } else {
+               htlc_success_tx_weight(opt_anchors)
+       };
+       let total_fee = feerate_per_kw as u64 * weight / 1000;
 
        let mut txouts: Vec<TxOut> = Vec::new();
        txouts.push(TxOut {
@@ -636,7 +656,7 @@ pub(crate) fn get_to_countersignatory_with_anchors_redeemscript(payment_point: &
 /// <>
 /// (empty vector required to satisfy compliance with MINIMALIF-standard rule)
 #[inline]
-pub(crate) fn get_anchor_redeemscript(funding_pubkey: &PublicKey) -> Script {
+pub fn get_anchor_redeemscript(funding_pubkey: &PublicKey) -> Script {
        Builder::new().push_slice(&funding_pubkey.serialize()[..])
                .push_opcode(opcodes::all::OP_CHECKSIG)
                .push_opcode(opcodes::all::OP_IFDUP)
@@ -774,6 +794,11 @@ impl<'a> DirectedChannelTransactionParameters<'a> {
        pub fn funding_outpoint(&self) -> OutPoint {
                self.inner.funding_outpoint.unwrap().into_bitcoin_outpoint()
        }
+
+       /// Whether to use anchors for this channel
+       pub fn opt_anchors(&self) -> bool {
+               self.inner.opt_anchors.is_some()
+       }
 }
 
 /// Information needed to build and sign a holder's commitment transaction.
@@ -920,6 +945,7 @@ impl BuiltCommitmentTransaction {
 ///
 /// This class can be used inside a signer implementation to generate a signature given the relevant
 /// secret key.
+#[derive(Clone, Hash, PartialEq)]
 pub struct ClosingTransaction {
        to_holder_value_sat: u64,
        to_counterparty_value_sat: u64,
@@ -1225,7 +1251,7 @@ impl CommitmentTransaction {
                                if let &Some(ref b_htlcout) = b {
                                        a_htlcout.cltv_expiry.cmp(&b_htlcout.cltv_expiry)
                                                // Note that due to hash collisions, we have to have a fallback comparison
-                                               // here for fuzztarget mode (otherwise at least chanmon_fail_consistency
+                                               // here for fuzzing mode (otherwise at least chanmon_fail_consistency
                                                // may fail)!
                                                .then(a_htlcout.payment_hash.0.cmp(&b_htlcout.payment_hash.0))
                                // For non-HTLC outputs, if they're copying our SPK we don't really care if we
@@ -1373,6 +1399,8 @@ impl<'a> TrustedCommitmentTransaction<'a> {
        /// which HTLCOutputInCommitment::transaction_output_index.is_some()).
        ///
        /// The returned Vec has one entry for each HTLC, and in the same order.
+       ///
+       /// This function is only valid in the holder commitment context, it always uses SigHashType::All.
        pub fn get_htlc_sigs<T: secp256k1::Signing>(&self, htlc_base_key: &SecretKey, channel_parameters: &DirectedChannelTransactionParameters, secp_ctx: &Secp256k1<T>) -> Result<Vec<Signature>, ()> {
                let inner = self.inner;
                let keys = &inner.keys;
@@ -1382,7 +1410,7 @@ impl<'a> TrustedCommitmentTransaction<'a> {
 
                for this_htlc in inner.htlcs.iter() {
                        assert!(this_htlc.transaction_output_index.is_some());
-                       let htlc_tx = build_htlc_transaction(&txid, inner.feerate_per_kw, channel_parameters.contest_delay(), &this_htlc, &keys.broadcaster_delayed_payment_key, &keys.revocation_key);
+                       let htlc_tx = build_htlc_transaction(&txid, inner.feerate_per_kw, channel_parameters.contest_delay(), &this_htlc, self.opt_anchors(), &keys.broadcaster_delayed_payment_key, &keys.revocation_key);
 
                        let htlc_redeemscript = get_htlc_redeemscript_with_explicit_keys(&this_htlc, self.opt_anchors(), &keys.broadcaster_htlc_key, &keys.countersignatory_htlc_key, &keys.revocation_key);
 
@@ -1404,16 +1432,18 @@ impl<'a> TrustedCommitmentTransaction<'a> {
                // Further, we should never be provided the preimage for an HTLC-Timeout transaction.
                if  this_htlc.offered && preimage.is_some() { unreachable!(); }
 
-               let mut htlc_tx = build_htlc_transaction(&txid, inner.feerate_per_kw, channel_parameters.contest_delay(), &this_htlc, &keys.broadcaster_delayed_payment_key, &keys.revocation_key);
+               let mut htlc_tx = build_htlc_transaction(&txid, inner.feerate_per_kw, channel_parameters.contest_delay(), &this_htlc, self.opt_anchors(), &keys.broadcaster_delayed_payment_key, &keys.revocation_key);
 
                let htlc_redeemscript = get_htlc_redeemscript_with_explicit_keys(&this_htlc, self.opt_anchors(), &keys.broadcaster_htlc_key, &keys.countersignatory_htlc_key, &keys.revocation_key);
 
+               let sighashtype = if self.opt_anchors() { SigHashType::SinglePlusAnyoneCanPay } else { SigHashType::All };
+
                // First push the multisig dummy, note that due to BIP147 (NULLDUMMY) it must be a zero-length element.
                htlc_tx.input[0].witness.push(Vec::new());
 
                htlc_tx.input[0].witness.push(counterparty_signature.serialize_der().to_vec());
                htlc_tx.input[0].witness.push(signature.serialize_der().to_vec());
-               htlc_tx.input[0].witness[1].push(SigHashType::All as u8);
+               htlc_tx.input[0].witness[1].push(sighashtype as u8);
                htlc_tx.input[0].witness[2].push(SigHashType::All as u8);
 
                if this_htlc.offered {
@@ -1475,6 +1505,7 @@ mod tests {
        use chain::keysinterface::{KeysInterface, BaseSign};
        use bitcoin::Network;
        use ln::PaymentHash;
+       use bitcoin::hashes::hex::ToHex;
 
        #[test]
        fn test_anchors() {
@@ -1578,6 +1609,10 @@ mod tests {
                assert_eq!(tx.built.transaction.output.len(), 3);
                assert_eq!(tx.built.transaction.output[0].script_pubkey, get_htlc_redeemscript(&received_htlc, false, &keys).to_v0_p2wsh());
                assert_eq!(tx.built.transaction.output[1].script_pubkey, get_htlc_redeemscript(&offered_htlc, false, &keys).to_v0_p2wsh());
+               assert_eq!(get_htlc_redeemscript(&received_htlc, false, &keys).to_v0_p2wsh().to_hex(),
+                                  "002085cf52e41ba7c099a39df504e7b61f6de122971ceb53b06731876eaeb85e8dc5");
+               assert_eq!(get_htlc_redeemscript(&offered_htlc, false, &keys).to_v0_p2wsh().to_hex(),
+                                  "002049f0736bb335c61a04d2623a24df878a7592a3c51fa7258d41b2c85318265e73");
 
                // Generate broadcaster output and received and offered HTLC outputs,  with anchors
                channel_parameters.opt_anchors = Some(());
@@ -1593,6 +1628,10 @@ mod tests {
                assert_eq!(tx.built.transaction.output.len(), 5);
                assert_eq!(tx.built.transaction.output[2].script_pubkey, get_htlc_redeemscript(&received_htlc, true, &keys).to_v0_p2wsh());
                assert_eq!(tx.built.transaction.output[3].script_pubkey, get_htlc_redeemscript(&offered_htlc, true, &keys).to_v0_p2wsh());
+               assert_eq!(get_htlc_redeemscript(&received_htlc, true, &keys).to_v0_p2wsh().to_hex(),
+                                  "002067114123af3f95405bae4fd930fc95de03e3c86baaee8b2dd29b43dd26cf613c");
+               assert_eq!(get_htlc_redeemscript(&offered_htlc, true, &keys).to_v0_p2wsh().to_hex(),
+                                  "0020a06e3b0d4fcf704f2b9c41e16a70099e39989466c3142b8573a1154542f28f57");
        }
 
        #[test]