]> git.bitcoin.ninja Git - rust-lightning/commitdiff
Add anchor support to commitment HTLC outputs
authorKen Sedgwick <ken@bonsai.com>
Tue, 16 Nov 2021 02:03:46 +0000 (18:03 -0800)
committerKen Sedgwick <ken@bonsai.com>
Tue, 23 Nov 2021 16:00:42 +0000 (08:00 -0800)
lightning/src/chain/channelmonitor.rs
lightning/src/chain/keysinterface.rs
lightning/src/chain/onchaintx.rs
lightning/src/chain/package.rs
lightning/src/ln/chan_utils.rs
lightning/src/ln/channel.rs
lightning/src/util/enforcing_trait_impls.rs

index d5664e453d42e7c7ae7d4268f12acba6b2e8c265..1699e4827236c89ba6e1dc6fef6b7ff726db6366 100644 (file)
@@ -3381,6 +3381,7 @@ mod tests {
                                selected_contest_delay: 67,
                        }),
                        funding_outpoint: Some(funding_outpoint),
+                       opt_anchors: None,
                };
                // Prune with one old state and a holder commitment tx holding a few overlaps with the
                // old state.
@@ -3446,7 +3447,7 @@ mod tests {
                let mut sum_actual_sigs = 0;
 
                macro_rules! sign_input {
-                       ($sighash_parts: expr, $idx: expr, $amount: expr, $weight: expr, $sum_actual_sigs: expr) => {
+                       ($sighash_parts: expr, $idx: expr, $amount: expr, $weight: expr, $sum_actual_sigs: expr, $opt_anchors: expr) => {
                                let htlc = HTLCOutputInCommitment {
                                        offered: if *$weight == WEIGHT_REVOKED_OFFERED_HTLC || *$weight == WEIGHT_OFFERED_HTLC { true } else { false },
                                        amount_msat: 0,
@@ -3454,7 +3455,7 @@ mod tests {
                                        payment_hash: PaymentHash([1; 32]),
                                        transaction_output_index: Some($idx as u32),
                                };
-                               let redeem_script = if *$weight == WEIGHT_REVOKED_OUTPUT { chan_utils::get_revokeable_redeemscript(&pubkey, 256, &pubkey) } else { chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, &pubkey, &pubkey, &pubkey) };
+                               let redeem_script = if *$weight == WEIGHT_REVOKED_OUTPUT { chan_utils::get_revokeable_redeemscript(&pubkey, 256, &pubkey) } else { chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, $opt_anchors, &pubkey, &pubkey, &pubkey) };
                                let sighash = hash_to_message!(&$sighash_parts.signature_hash($idx, &redeem_script, $amount, SigHashType::All)[..]);
                                let sig = secp_ctx.sign(&sighash, &privkey);
                                $sighash_parts.access_witness($idx).push(sig.serialize_der().to_vec());
@@ -3502,7 +3503,7 @@ mod tests {
                {
                        let mut sighash_parts = bip143::SigHashCache::new(&mut claim_tx);
                        for (idx, inp) in inputs_weight.iter().enumerate() {
-                               sign_input!(sighash_parts, idx, 0, inp, sum_actual_sigs);
+                               sign_input!(sighash_parts, idx, 0, inp, sum_actual_sigs, false);
                                inputs_total_weight += inp;
                        }
                }
@@ -3528,7 +3529,7 @@ mod tests {
                {
                        let mut sighash_parts = bip143::SigHashCache::new(&mut claim_tx);
                        for (idx, inp) in inputs_weight.iter().enumerate() {
-                               sign_input!(sighash_parts, idx, 0, inp, sum_actual_sigs);
+                               sign_input!(sighash_parts, idx, 0, inp, sum_actual_sigs, false);
                                inputs_total_weight += inp;
                        }
                }
@@ -3552,7 +3553,7 @@ mod tests {
                {
                        let mut sighash_parts = bip143::SigHashCache::new(&mut claim_tx);
                        for (idx, inp) in inputs_weight.iter().enumerate() {
-                               sign_input!(sighash_parts, idx, 0, inp, sum_actual_sigs);
+                               sign_input!(sighash_parts, idx, 0, inp, sum_actual_sigs, false);
                                inputs_total_weight += inp;
                        }
                }
index b36694eb126cded8b5048dd1a2f28461eb5c25f6..4b1d172f4e9104bcd7cf7fbb512135f79715ac63 100644 (file)
@@ -505,6 +505,12 @@ impl InMemorySigner {
                self.channel_parameters.as_ref().unwrap()
        }
 
+       /// Whether anchors should be used.
+       /// Will panic if ready_channel wasn't called.
+       pub fn opt_anchors(&self) -> bool {
+               self.get_channel_parameters().opt_anchors.is_some()
+       }
+
        /// Sign the single input of spend_tx at index `input_idx` which spends the output
        /// described by descriptor, returning the witness stack for the input.
        ///
@@ -594,7 +600,7 @@ impl BaseSign for InMemorySigner {
                let mut htlc_sigs = Vec::with_capacity(commitment_tx.htlcs().len());
                for htlc in commitment_tx.htlcs() {
                        let htlc_tx = chan_utils::build_htlc_transaction(&commitment_txid, commitment_tx.feerate_per_kw(), self.holder_selected_contest_delay(), htlc, &keys.broadcaster_delayed_payment_key, &keys.revocation_key);
-                       let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &keys);
+                       let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, self.opt_anchors(), &keys);
                        let htlc_sighash = hash_to_message!(&bip143::SigHashCache::new(&htlc_tx).signature_hash(0, &htlc_redeemscript, htlc.amount_msat / 1000, SigHashType::All)[..]);
                        let holder_htlc_key = chan_utils::derive_private_key(&secp_ctx, &keys.per_commitment_point, &self.htlc_base_key).map_err(|_| ())?;
                        htlc_sigs.push(secp_ctx.sign(&htlc_sighash, &holder_htlc_key));
@@ -648,7 +654,7 @@ impl BaseSign for InMemorySigner {
                let witness_script = {
                        let counterparty_htlcpubkey = chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &self.counterparty_pubkeys().htlc_basepoint).map_err(|_| ())?;
                        let holder_htlcpubkey = chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &self.pubkeys().htlc_basepoint).map_err(|_| ())?;
-                       chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, &counterparty_htlcpubkey, &holder_htlcpubkey, &revocation_pubkey)
+                       chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, self.opt_anchors(), &counterparty_htlcpubkey, &holder_htlcpubkey, &revocation_pubkey)
                };
                let mut sighash_parts = bip143::SigHashCache::new(justice_tx);
                let sighash = hash_to_message!(&sighash_parts.signature_hash(input, &witness_script, amount, SigHashType::All)[..]);
@@ -660,7 +666,7 @@ impl BaseSign for InMemorySigner {
                        let witness_script = if let Ok(revocation_pubkey) = chan_utils::derive_public_revocation_key(&secp_ctx, &per_commitment_point, &self.pubkeys().revocation_basepoint) {
                                if let Ok(counterparty_htlcpubkey) = chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &self.counterparty_pubkeys().htlc_basepoint) {
                                        if let Ok(htlcpubkey) = chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &self.pubkeys().htlc_basepoint) {
-                                               chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, &counterparty_htlcpubkey, &htlcpubkey, &revocation_pubkey)
+                                               chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, self.opt_anchors(), &counterparty_htlcpubkey, &htlcpubkey, &revocation_pubkey)
                                        } else { return Err(()) }
                                } else { return Err(()) }
                        } else { return Err(()) };
index 765a9c091815379104b42c05578bda5b9622f7a5..6f64f3eec56210b3e383dd0a15b87368946a2201 100644 (file)
@@ -786,6 +786,10 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
                htlc_tx
        }
 
+       pub(crate) fn opt_anchors(&self) -> bool {
+               self.channel_transaction_parameters.opt_anchors.is_some()
+       }
+
        #[cfg(any(test,feature = "unsafe_revoked_tx_signing"))]
        pub(crate) fn unsafe_get_fully_signed_htlc_tx(&mut self, outp: &::bitcoin::OutPoint, preimage: &Option<PaymentPreimage>) -> Option<Transaction> {
                let latest_had_sigs = self.holder_htlc_sigs.is_some();
index 8a17f726cf030a23b3fbda31248b791cf5b51b28..6af41506fb36ed458ca149b0fa66ec901d09a47b 100644 (file)
@@ -341,7 +341,7 @@ impl PackageSolvingData {
                        },
                        PackageSolvingData::RevokedHTLCOutput(ref outp) => {
                                if let Ok(chan_keys) = TxCreationKeys::derive_new(&onchain_handler.secp_ctx, &outp.per_commitment_point, &outp.counterparty_delayed_payment_base_key, &outp.counterparty_htlc_base_key, &onchain_handler.signer.pubkeys().revocation_basepoint, &onchain_handler.signer.pubkeys().htlc_basepoint) {
-                                       let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&outp.htlc, &chan_keys.broadcaster_htlc_key, &chan_keys.countersignatory_htlc_key, &chan_keys.revocation_key);
+                                       let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&outp.htlc, onchain_handler.opt_anchors(), &chan_keys.broadcaster_htlc_key, &chan_keys.countersignatory_htlc_key, &chan_keys.revocation_key);
                                        //TODO: should we panic on signer failure ?
                                        if let Ok(sig) = onchain_handler.signer.sign_justice_revoked_htlc(&bumped_tx, i, outp.amount, &outp.per_commitment_key, &outp.htlc, &onchain_handler.secp_ctx) {
                                                bumped_tx.input[i].witness.push(sig.serialize_der().to_vec());
@@ -353,7 +353,7 @@ impl PackageSolvingData {
                        },
                        PackageSolvingData::CounterpartyOfferedHTLCOutput(ref outp) => {
                                if let Ok(chan_keys) = TxCreationKeys::derive_new(&onchain_handler.secp_ctx, &outp.per_commitment_point, &outp.counterparty_delayed_payment_base_key, &outp.counterparty_htlc_base_key, &onchain_handler.signer.pubkeys().revocation_basepoint, &onchain_handler.signer.pubkeys().htlc_basepoint) {
-                                       let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&outp.htlc, &chan_keys.broadcaster_htlc_key, &chan_keys.countersignatory_htlc_key, &chan_keys.revocation_key);
+                                       let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&outp.htlc, onchain_handler.opt_anchors(), &chan_keys.broadcaster_htlc_key, &chan_keys.countersignatory_htlc_key, &chan_keys.revocation_key);
 
                                        if let Ok(sig) = onchain_handler.signer.sign_counterparty_htlc_transaction(&bumped_tx, i, &outp.htlc.amount_msat / 1000, &outp.per_commitment_point, &outp.htlc, &onchain_handler.secp_ctx) {
                                                bumped_tx.input[i].witness.push(sig.serialize_der().to_vec());
@@ -365,7 +365,7 @@ impl PackageSolvingData {
                        },
                        PackageSolvingData::CounterpartyReceivedHTLCOutput(ref outp) => {
                                if let Ok(chan_keys) = TxCreationKeys::derive_new(&onchain_handler.secp_ctx, &outp.per_commitment_point, &outp.counterparty_delayed_payment_base_key, &outp.counterparty_htlc_base_key, &onchain_handler.signer.pubkeys().revocation_basepoint, &onchain_handler.signer.pubkeys().htlc_basepoint) {
-                                       let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&outp.htlc, &chan_keys.broadcaster_htlc_key, &chan_keys.countersignatory_htlc_key, &chan_keys.revocation_key);
+                                       let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&outp.htlc, onchain_handler.opt_anchors(), &chan_keys.broadcaster_htlc_key, &chan_keys.countersignatory_htlc_key, &chan_keys.revocation_key);
 
                                        bumped_tx.lock_time = outp.htlc.cltv_expiry; // Right now we don't aggregate time-locked transaction, if we do we should set lock_time before to avoid breaking hash computation
                                        if let Ok(sig) = onchain_handler.signer.sign_counterparty_htlc_transaction(&bumped_tx, i, &outp.htlc.amount_msat / 1000, &outp.per_commitment_point, &outp.htlc, &onchain_handler.secp_ctx) {
index 9be58a9cc894e2ec04500e6a75518b6ee92dbe1e..80dd872a9de9cec9e6e3277cf0ccab8c4b2d9705 100644 (file)
@@ -482,10 +482,10 @@ impl_writeable_tlv_based!(HTLCOutputInCommitment, {
 });
 
 #[inline]
-pub(crate) fn get_htlc_redeemscript_with_explicit_keys(htlc: &HTLCOutputInCommitment, broadcaster_htlc_key: &PublicKey, countersignatory_htlc_key: &PublicKey, revocation_key: &PublicKey) -> Script {
+pub(crate) fn get_htlc_redeemscript_with_explicit_keys(htlc: &HTLCOutputInCommitment, opt_anchors: bool, broadcaster_htlc_key: &PublicKey, countersignatory_htlc_key: &PublicKey, revocation_key: &PublicKey) -> Script {
        let payment_hash160 = Ripemd160::hash(&htlc.payment_hash.0[..]).into_inner();
        if htlc.offered {
-               Builder::new().push_opcode(opcodes::all::OP_DUP)
+               let mut bldr = Builder::new().push_opcode(opcodes::all::OP_DUP)
                              .push_opcode(opcodes::all::OP_HASH160)
                              .push_slice(&PubkeyHash::hash(&revocation_key.serialize())[..])
                              .push_opcode(opcodes::all::OP_EQUAL)
@@ -509,11 +509,16 @@ pub(crate) fn get_htlc_redeemscript_with_explicit_keys(htlc: &HTLCOutputInCommit
                              .push_slice(&payment_hash160)
                              .push_opcode(opcodes::all::OP_EQUALVERIFY)
                              .push_opcode(opcodes::all::OP_CHECKSIG)
-                             .push_opcode(opcodes::all::OP_ENDIF)
-                             .push_opcode(opcodes::all::OP_ENDIF)
-                             .into_script()
+                             .push_opcode(opcodes::all::OP_ENDIF);
+               if opt_anchors {
+                       bldr = bldr.push_opcode(opcodes::all::OP_PUSHNUM_1)
+                               .push_opcode(opcodes::all::OP_CSV)
+                               .push_opcode(opcodes::all::OP_DROP);
+               }
+               bldr.push_opcode(opcodes::all::OP_ENDIF)
+                       .into_script()
        } else {
-               Builder::new().push_opcode(opcodes::all::OP_DUP)
+                       let mut bldr = Builder::new().push_opcode(opcodes::all::OP_DUP)
                              .push_opcode(opcodes::all::OP_HASH160)
                              .push_slice(&PubkeyHash::hash(&revocation_key.serialize())[..])
                              .push_opcode(opcodes::all::OP_EQUAL)
@@ -540,17 +545,22 @@ pub(crate) fn get_htlc_redeemscript_with_explicit_keys(htlc: &HTLCOutputInCommit
                              .push_opcode(opcodes::all::OP_CLTV)
                              .push_opcode(opcodes::all::OP_DROP)
                              .push_opcode(opcodes::all::OP_CHECKSIG)
-                             .push_opcode(opcodes::all::OP_ENDIF)
-                             .push_opcode(opcodes::all::OP_ENDIF)
-                             .into_script()
+                             .push_opcode(opcodes::all::OP_ENDIF);
+               if opt_anchors {
+                       bldr = bldr.push_opcode(opcodes::all::OP_PUSHNUM_1)
+                               .push_opcode(opcodes::all::OP_CSV)
+                               .push_opcode(opcodes::all::OP_DROP);
+               }
+               bldr.push_opcode(opcodes::all::OP_ENDIF)
+                       .into_script()
        }
 }
 
 /// Gets the witness redeemscript for an HTLC output in a commitment transaction. Note that htlc
 /// does not need to have its previous_output_index filled.
 #[inline]
-pub fn get_htlc_redeemscript(htlc: &HTLCOutputInCommitment, keys: &TxCreationKeys) -> Script {
-       get_htlc_redeemscript_with_explicit_keys(htlc, &keys.broadcaster_htlc_key, &keys.countersignatory_htlc_key, &keys.revocation_key)
+pub fn get_htlc_redeemscript(htlc: &HTLCOutputInCommitment, opt_anchors: bool, keys: &TxCreationKeys) -> Script {
+       get_htlc_redeemscript_with_explicit_keys(htlc, opt_anchors, &keys.broadcaster_htlc_key, &keys.countersignatory_htlc_key, &keys.revocation_key)
 }
 
 /// Gets the redeemscript for a funding output from the two funding public keys.
@@ -656,6 +666,8 @@ pub struct ChannelTransactionParameters {
        pub counterparty_parameters: Option<CounterpartyChannelTransactionParameters>,
        /// The late-bound funding outpoint
        pub funding_outpoint: Option<chain::transaction::OutPoint>,
+       /// Are anchors used for this channel.  Boolean is serialization backwards-compatible
+       pub opt_anchors: Option<()>
 }
 
 /// Late-bound per-channel counterparty data used to build transactions.
@@ -709,6 +721,7 @@ impl_writeable_tlv_based!(ChannelTransactionParameters, {
        (4, is_outbound_from_holder, required),
        (6, counterparty_parameters, option),
        (8, funding_outpoint, option),
+       (10, opt_anchors, option),
 });
 
 /// Static channel fields used to build transactions given per-commitment fields, organized by
@@ -824,7 +837,8 @@ impl HolderCommitmentTransaction {
                        holder_selected_contest_delay: 0,
                        is_outbound_from_holder: false,
                        counterparty_parameters: Some(CounterpartyChannelTransactionParameters { pubkeys: channel_pubkeys.clone(), selected_contest_delay: 0 }),
-                       funding_outpoint: Some(chain::transaction::OutPoint { txid: Default::default(), index: 0 })
+                       funding_outpoint: Some(chain::transaction::OutPoint { txid: Default::default(), index: 0 }),
+                       opt_anchors: None
                };
                let mut htlcs_with_aux: Vec<(_, ())> = Vec::new();
                let inner = CommitmentTransaction::new_with_auxiliary_htlc_data(0, 0, 0, false, dummy_key.clone(), dummy_key.clone(), keys, 0, &mut htlcs_with_aux, &channel_parameters.as_counterparty_broadcastable());
@@ -1196,7 +1210,7 @@ impl CommitmentTransaction {
 
                let mut htlcs = Vec::with_capacity(htlcs_with_aux.len());
                for (htlc, _) in htlcs_with_aux {
-                       let script = chan_utils::get_htlc_redeemscript(&htlc, &keys);
+                       let script = chan_utils::get_htlc_redeemscript(&htlc, opt_anchors, &keys);
                        let txout = TxOut {
                                script_pubkey: script.to_v0_p2wsh(),
                                value: htlc.amount_msat / 1000,
@@ -1350,6 +1364,11 @@ impl<'a> TrustedCommitmentTransaction<'a> {
                &self.inner.keys
        }
 
+       /// Should anchors be used.
+       pub fn opt_anchors(&self) -> bool {
+               self.opt_anchors.is_some()
+       }
+
        /// Get a signature for each HTLC which was included in the commitment transaction (ie for
        /// which HTLCOutputInCommitment::transaction_output_index.is_some()).
        ///
@@ -1365,7 +1384,7 @@ impl<'a> TrustedCommitmentTransaction<'a> {
                        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_redeemscript = get_htlc_redeemscript_with_explicit_keys(&this_htlc, &keys.broadcaster_htlc_key, &keys.countersignatory_htlc_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 sighash = hash_to_message!(&bip143::SigHashCache::new(&htlc_tx).signature_hash(0, &htlc_redeemscript, this_htlc.amount_msat / 1000, SigHashType::All)[..]);
                        ret.push(secp_ctx.sign(&sighash, &holder_htlc_key));
@@ -1387,7 +1406,7 @@ impl<'a> TrustedCommitmentTransaction<'a> {
 
                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 htlc_redeemscript = get_htlc_redeemscript_with_explicit_keys(&this_htlc, &keys.broadcaster_htlc_key, &keys.countersignatory_htlc_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);
 
                // 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());
@@ -1450,7 +1469,7 @@ mod tests {
        use super::CounterpartyCommitmentSecrets;
        use ::{hex, chain};
        use prelude::*;
-       use ln::chan_utils::{get_to_countersignatory_with_anchors_redeemscript, get_p2wpkh_redeemscript, CommitmentTransaction, TxCreationKeys, ChannelTransactionParameters, CounterpartyChannelTransactionParameters, HTLCOutputInCommitment};
+       use ln::chan_utils::{get_htlc_redeemscript, get_to_countersignatory_with_anchors_redeemscript, get_p2wpkh_redeemscript, CommitmentTransaction, TxCreationKeys, ChannelTransactionParameters, CounterpartyChannelTransactionParameters, HTLCOutputInCommitment};
        use bitcoin::secp256k1::{PublicKey, SecretKey, Secp256k1};
        use util::test_utils;
        use chain::keysinterface::{KeysInterface, BaseSign};
@@ -1473,12 +1492,13 @@ mod tests {
                let holder_pubkeys = signer.pubkeys();
                let counterparty_pubkeys = counterparty_signer.pubkeys();
                let keys = TxCreationKeys::derive_new(&secp_ctx, &per_commitment_point, delayed_payment_base, htlc_basepoint, &counterparty_pubkeys.revocation_basepoint, &counterparty_pubkeys.htlc_basepoint).unwrap();
-               let channel_parameters = ChannelTransactionParameters {
+               let mut channel_parameters = ChannelTransactionParameters {
                        holder_pubkeys: holder_pubkeys.clone(),
                        holder_selected_contest_delay: 0,
                        is_outbound_from_holder: false,
                        counterparty_parameters: Some(CounterpartyChannelTransactionParameters { pubkeys: counterparty_pubkeys.clone(), selected_contest_delay: 0 }),
-                       funding_outpoint: Some(chain::transaction::OutPoint { txid: Default::default(), index: 0 })
+                       funding_outpoint: Some(chain::transaction::OutPoint { txid: Default::default(), index: 0 }),
+                       opt_anchors: None
                };
 
                let mut htlcs_with_aux: Vec<(_, ())> = Vec::new();
@@ -1529,25 +1549,50 @@ mod tests {
                );
                assert_eq!(tx.built.transaction.output.len(), 2);
 
-               // Generate broadcaster output, an HTLC output and two anchors
-               let payment_hash = PaymentHash([42; 32]);
-               let htlc_info = HTLCOutputInCommitment {
+               let received_htlc = HTLCOutputInCommitment {
                        offered: false,
-                       amount_msat: 1000000,
+                       amount_msat: 400000,
+                       cltv_expiry: 100,
+                       payment_hash: PaymentHash([42; 32]),
+                       transaction_output_index: None,
+               };
+
+               let offered_htlc = HTLCOutputInCommitment {
+                       offered: true,
+                       amount_msat: 600000,
                        cltv_expiry: 100,
-                       payment_hash,
+                       payment_hash: PaymentHash([43; 32]),
                        transaction_output_index: None,
                };
 
+               // Generate broadcaster output and received and offered HTLC outputs,  w/o anchors
+               let tx = CommitmentTransaction::new_with_auxiliary_htlc_data(
+                       0, 3000, 0,
+                       false,
+                       holder_pubkeys.funding_pubkey,
+                       counterparty_pubkeys.funding_pubkey,
+                       keys.clone(), 1,
+                       &mut vec![(received_htlc.clone(), ()), (offered_htlc.clone(), ())],
+                       &channel_parameters.as_holder_broadcastable()
+               );
+               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());
+
+               // Generate broadcaster output and received and offered HTLC outputs,  with anchors
+               channel_parameters.opt_anchors = Some(());
                let tx = CommitmentTransaction::new_with_auxiliary_htlc_data(
                        0, 3000, 0,
                        true,
                        holder_pubkeys.funding_pubkey,
                        counterparty_pubkeys.funding_pubkey,
                        keys.clone(), 1,
-                       &mut vec![(htlc_info, ())], &channel_parameters.as_holder_broadcastable()
+                       &mut vec![(received_htlc.clone(), ()), (offered_htlc.clone(), ())],
+                       &channel_parameters.as_holder_broadcastable()
                );
-               assert_eq!(tx.built.transaction.output.len(), 4);
+               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());
        }
 
        #[test]
index 35aac0471ea2790f6517ab3d8e6f1797651fc8a0..64f52288c6f363e90a215a853eb20bd04d72e97e 100644 (file)
@@ -679,6 +679,10 @@ impl<Signer: Sign> Channel<Signer> {
                cmp::min(channel_value_satoshis, cmp::max(q, 1000)) //TODO
        }
 
+       pub(crate) fn opt_anchors(&self) -> bool {
+               self.channel_transaction_parameters.opt_anchors.is_some()
+       }
+
        // Constructors:
        pub fn new_outbound<K: Deref, F: Deref>(
                fee_estimator: &F, keys_provider: &K, counterparty_node_id: PublicKey, their_features: &InitFeatures,
@@ -790,7 +794,8 @@ impl<Signer: Sign> Channel<Signer> {
                                holder_selected_contest_delay: config.own_channel_config.our_to_self_delay,
                                is_outbound_from_holder: true,
                                counterparty_parameters: None,
-                               funding_outpoint: None
+                               funding_outpoint: None,
+                               opt_anchors: None,
                        },
                        funding_transaction: None,
 
@@ -1084,7 +1089,8 @@ impl<Signer: Sign> Channel<Signer> {
                                        selected_contest_delay: msg.to_self_delay,
                                        pubkeys: counterparty_pubkeys,
                                }),
-                               funding_outpoint: None
+                               funding_outpoint: None,
+                               opt_anchors: None
                        },
                        funding_transaction: None,
 
@@ -1311,7 +1317,7 @@ impl<Signer: Sign> Channel<Signer> {
                let tx = CommitmentTransaction::new_with_auxiliary_htlc_data(commitment_number,
                                                                             value_to_a as u64,
                                                                             value_to_b as u64,
-                                                                            false,
+                                                                            self.channel_transaction_parameters.opt_anchors.is_some(),
                                                                             funding_pubkey_a,
                                                                             funding_pubkey_b,
                                                                             keys.clone(),
@@ -2578,7 +2584,7 @@ impl<Signer: Sign> Channel<Signer> {
                                        self.get_counterparty_selected_contest_delay().unwrap(), &htlc,
                                        &keys.broadcaster_delayed_payment_key, &keys.revocation_key);
 
-                               let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &keys);
+                               let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, self.opt_anchors(), &keys);
                                let htlc_sighash = hash_to_message!(&bip143::SigHashCache::new(&htlc_tx).signature_hash(0, &htlc_redeemscript, htlc.amount_msat / 1000, SigHashType::All)[..]);
                                log_trace!(logger, "Checking HTLC tx signature {} by key {} against tx {} (sighash {}) with redeemscript {} in channel {}.",
                                        log_bytes!(msg.htlc_signatures[idx].serialize_compact()[..]), log_bytes!(keys.countersignatory_htlc_key.serialize()),
@@ -4922,7 +4928,7 @@ impl<Signer: Sign> Channel<Signer> {
                        for (ref htlc_sig, ref htlc) in htlc_signatures.iter().zip(htlcs) {
                                log_trace!(logger, "Signed remote HTLC tx {} with redeemscript {} with pubkey {} -> {} in channel {}",
                                        encode::serialize_hex(&chan_utils::build_htlc_transaction(&counterparty_commitment_txid, commitment_stats.feerate_per_kw, self.get_holder_selected_contest_delay(), htlc, &counterparty_keys.broadcaster_delayed_payment_key, &counterparty_keys.revocation_key)),
-                                       encode::serialize_hex(&chan_utils::get_htlc_redeemscript(&htlc, &counterparty_keys)),
+                                       encode::serialize_hex(&chan_utils::get_htlc_redeemscript(&htlc, self.opt_anchors(), &counterparty_keys)),
                                        log_bytes!(counterparty_keys.broadcaster_htlc_key.serialize()),
                                        log_bytes!(htlc_sig.serialize_compact()[..]), log_bytes!(self.channel_id()));
                        }
@@ -5626,6 +5632,11 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel<Signer>
                        return Err(DecodeError::UnknownRequiredFeature);
                }
 
+               if channel_parameters.opt_anchors.is_some() {
+                       // Relax this check when ChannelTypeFeatures supports anchors.
+                       return Err(DecodeError::InvalidValue);
+               }
+
                let mut secp_ctx = Secp256k1::new();
                secp_ctx.seeded_randomize(&keys_source.get_secure_random_bytes());
 
@@ -6215,7 +6226,8 @@ mod tests {
                                        let htlc_tx = chan_utils::build_htlc_transaction(&unsigned_tx.txid, chan.feerate_per_kw,
                                                chan.get_counterparty_selected_contest_delay().unwrap(),
                                                &htlc, &keys.broadcaster_delayed_payment_key, &keys.revocation_key);
-                                       let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &keys);
+                                       let opt_anchors = false;
+                                       let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, opt_anchors, &keys);
                                        let htlc_sighash = Message::from_slice(&bip143::SigHashCache::new(&htlc_tx).signature_hash(0, &htlc_redeemscript, htlc.amount_msat / 1000, SigHashType::All)[..]).unwrap();
                                        secp_ctx.verify(&htlc_sighash, &remote_signature, &keys.countersignatory_htlc_key).unwrap();
 
index b905665c98918bbb8f1fd9306174badb51752724..ba11718e9aa8ecefa888efdc31c799b219d82c79 100644 (file)
@@ -79,6 +79,8 @@ impl EnforcingSigner {
                }
        }
 
+       pub fn opt_anchors(&self) -> bool { self.inner.opt_anchors() }
+
        #[cfg(test)]
        pub fn get_enforcement_state(&self) -> MutexGuard<EnforcementState> {
                self.state.lock().unwrap()
@@ -156,7 +158,7 @@ impl BaseSign for EnforcingSigner {
                        let keys = trusted_tx.keys();
                        let htlc_tx = chan_utils::build_htlc_transaction(&commitment_txid, trusted_tx.feerate_per_kw(), holder_csv, &this_htlc, &keys.broadcaster_delayed_payment_key, &keys.revocation_key);
 
-                       let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&this_htlc, &keys);
+                       let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&this_htlc, self.opt_anchors(), &keys);
 
                        let sighash = hash_to_message!(&bip143::SigHashCache::new(&htlc_tx).signature_hash(0, &htlc_redeemscript, this_htlc.amount_msat / 1000, SigHashType::All)[..]);
                        secp_ctx.verify(&sighash, sig, &keys.countersignatory_htlc_key).unwrap();