X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fchan_utils.rs;h=31881d05dfa1c1883e066f526d76dca20037df99;hb=6b49af1563ffdd2533900059922bd655c1f90a8d;hp=b5b9d2ee77f97c36280cdbbbf6825b838d2ed8db;hpb=2cfc1dbb44ef2b764f4f14abbc70d6757d4b12a4;p=rust-lightning diff --git a/lightning/src/ln/chan_utils.rs b/lightning/src/ln/chan_utils.rs index b5b9d2ee..31881d05 100644 --- a/lightning/src/ln/chan_utils.rs +++ b/lightning/src/ln/chan_utils.rs @@ -14,6 +14,7 @@ use bitcoin::blockdata::script::{Script,Builder}; use bitcoin::blockdata::opcodes; use bitcoin::blockdata::transaction::{TxIn,TxOut,OutPoint,Transaction, EcdsaSighashType}; use bitcoin::util::sighash; +use bitcoin::util::address::Payload; use bitcoin::hashes::{Hash, HashEngine}; use bitcoin::hashes::sha256::Hash as Sha256; @@ -23,12 +24,12 @@ use bitcoin::hash_types::{Txid, PubkeyHash}; use crate::ln::{PaymentHash, PaymentPreimage}; use crate::ln::msgs::DecodeError; use crate::util::ser::{Readable, Writeable, Writer}; -use crate::util::{byte_utils, transaction_utils}; +use crate::util::transaction_utils; -use bitcoin::hash_types::WPubkeyHash; use bitcoin::secp256k1::{SecretKey, PublicKey, Scalar}; use bitcoin::secp256k1::{Secp256k1, ecdsa::Signature, Message}; use bitcoin::{PackedLockTime, secp256k1, Sequence, Witness}; +use bitcoin::PublicKey as BitcoinPublicKey; use crate::io; use crate::prelude::*; @@ -40,13 +41,20 @@ use core::ops::Deref; use crate::chain; use crate::util::crypto::sign; -pub(crate) const MAX_HTLCS: u16 = 483; -pub(crate) const OFFERED_HTLC_SCRIPT_WEIGHT: usize = 133; -pub(crate) const OFFERED_HTLC_SCRIPT_WEIGHT_ANCHORS: usize = 136; -// The weight of `accepted_htlc_script` can vary in function of its CLTV argument value. We define a -// range that encompasses both its non-anchors and anchors variants. +/// Maximum number of one-way in-flight HTLC (protocol-level value). +pub const MAX_HTLCS: u16 = 483; +/// The weight of a BIP141 witnessScript for a BOLT3's "offered HTLC output" on a commitment transaction, non-anchor variant. +pub const OFFERED_HTLC_SCRIPT_WEIGHT: usize = 133; +/// The weight of a BIP141 witnessScript for a BOLT3's "offered HTLC output" on a commitment transaction, anchor variant. +pub const OFFERED_HTLC_SCRIPT_WEIGHT_ANCHORS: usize = 136; + +/// The weight of a BIP141 witnessScript for a BOLT3's "received HTLC output" can vary in function of its CLTV argument value. +/// We define a range that encompasses both its non-anchors and anchors variants. pub(crate) const MIN_ACCEPTED_HTLC_SCRIPT_WEIGHT: usize = 136; -pub(crate) const MAX_ACCEPTED_HTLC_SCRIPT_WEIGHT: usize = 143; +/// The weight of a BIP141 witnessScript for a BOLT3's "received HTLC output" can vary in function of its CLTV argument value. +/// We define a range that encompasses both its non-anchors and anchors variants. +/// This is the maximum post-anchor value. +pub const MAX_ACCEPTED_HTLC_SCRIPT_WEIGHT: usize = 143; /// Gets the weight for an HTLC-Success transaction. #[inline] @@ -64,18 +72,24 @@ pub fn htlc_timeout_tx_weight(opt_anchors: bool) -> u64 { if opt_anchors { HTLC_TIMEOUT_ANCHOR_TX_WEIGHT } else { HTLC_TIMEOUT_TX_WEIGHT } } +/// Describes the type of HTLC claim as determined by analyzing the witness. #[derive(PartialEq, Eq)] -pub(crate) enum HTLCClaim { +pub enum HTLCClaim { + /// Claims an offered output on a commitment transaction through the timeout path. OfferedTimeout, + /// Claims an offered output on a commitment transaction through the success path. OfferedPreimage, + /// Claims an accepted output on a commitment transaction through the timeout path. AcceptedTimeout, + /// Claims an accepted output on a commitment transaction through the success path. AcceptedPreimage, + /// Claims an offered/accepted output on a commitment transaction through the revocation path. Revocation, } impl HTLCClaim { /// Check if a given input witness attempts to claim a HTLC. - pub(crate) fn from_witness(witness: &Witness) -> Option { + pub fn from_witness(witness: &Witness) -> Option { debug_assert_eq!(OFFERED_HTLC_SCRIPT_WEIGHT_ANCHORS, MIN_ACCEPTED_HTLC_SCRIPT_WEIGHT); if witness.len() < 2 { return None; @@ -295,7 +309,7 @@ impl Writeable for CounterpartyCommitmentSecrets { fn write(&self, writer: &mut W) -> Result<(), io::Error> { for &(ref secret, ref idx) in self.old_secrets.iter() { writer.write_all(secret)?; - writer.write_all(&byte_utils::be64_to_array(*idx))?; + writer.write_all(&idx.to_be_bytes())?; } write_tlv_fields!(writer, {}); Ok(()) @@ -448,7 +462,7 @@ impl_writeable_tlv_based!(TxCreationKeys, { }); /// One counterparty's public keys which do not change over the life of a channel. -#[derive(Clone, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct ChannelPublicKeys { /// The public key which is used to sign all commitment transactions, as it appears in the /// on-chain channel lock-in 2-of-2 multisig output. @@ -665,7 +679,24 @@ pub fn make_funding_redeemscript(broadcaster: &PublicKey, countersignatory: &Pub /// commitment transaction). pub fn build_htlc_transaction(commitment_txid: &Txid, feerate_per_kw: u32, contest_delay: u16, htlc: &HTLCOutputInCommitment, opt_anchors: bool, use_non_zero_fee_anchors: bool, broadcaster_delayed_payment_key: &PublicKey, revocation_key: &PublicKey) -> Transaction { let mut txins: Vec = Vec::new(); - txins.push(TxIn { + txins.push(build_htlc_input(commitment_txid, htlc, opt_anchors)); + + let mut txouts: Vec = Vec::new(); + txouts.push(build_htlc_output( + feerate_per_kw, contest_delay, htlc, opt_anchors, use_non_zero_fee_anchors, + broadcaster_delayed_payment_key, revocation_key + )); + + Transaction { + version: 2, + lock_time: PackedLockTime(if htlc.offered { htlc.cltv_expiry } else { 0 }), + input: txins, + output: txouts, + } +} + +pub(crate) fn build_htlc_input(commitment_txid: &Txid, htlc: &HTLCOutputInCommitment, opt_anchors: bool) -> TxIn { + TxIn { previous_output: OutPoint { txid: commitment_txid.clone(), vout: htlc.transaction_output_index.expect("Can't build an HTLC transaction for a dust output"), @@ -673,8 +704,13 @@ pub fn build_htlc_transaction(commitment_txid: &Txid, feerate_per_kw: u32, conte script_sig: Script::new(), sequence: Sequence(if opt_anchors { 1 } else { 0 }), witness: Witness::new(), - }); + } +} +pub(crate) fn build_htlc_output( + feerate_per_kw: u32, contest_delay: u16, htlc: &HTLCOutputInCommitment, opt_anchors: bool, + use_non_zero_fee_anchors: bool, broadcaster_delayed_payment_key: &PublicKey, revocation_key: &PublicKey +) -> TxOut { let weight = if htlc.offered { htlc_timeout_tx_weight(opt_anchors) } else { @@ -687,23 +723,41 @@ pub fn build_htlc_transaction(commitment_txid: &Txid, feerate_per_kw: u32, conte htlc.amount_msat / 1000 - total_fee }; - let mut txouts: Vec = Vec::new(); - txouts.push(TxOut { + TxOut { script_pubkey: get_revokeable_redeemscript(revocation_key, contest_delay, broadcaster_delayed_payment_key).to_v0_p2wsh(), value: output_value, - }); + } +} - Transaction { - version: 2, - lock_time: PackedLockTime(if htlc.offered { htlc.cltv_expiry } else { 0 }), - input: txins, - output: txouts, +/// Returns the witness required to satisfy and spend a HTLC input. +pub fn build_htlc_input_witness( + local_sig: &Signature, remote_sig: &Signature, preimage: &Option, + redeem_script: &Script, opt_anchors: bool, +) -> Witness { + let remote_sighash_type = if opt_anchors { + EcdsaSighashType::SinglePlusAnyoneCanPay + } else { + EcdsaSighashType::All + }; + + let mut witness = Witness::new(); + // First push the multisig dummy, note that due to BIP147 (NULLDUMMY) it must be a zero-length element. + witness.push(vec![]); + witness.push_bitcoin_signature(&remote_sig.serialize_der(), remote_sighash_type); + witness.push_bitcoin_signature(&local_sig.serialize_der(), EcdsaSighashType::All); + if let Some(preimage) = preimage { + witness.push(preimage.0.to_vec()); + } else { + // Due to BIP146 (MINIMALIF) this must be a zero-length element to relay. + witness.push(vec![]); } + witness.push(redeem_script.to_bytes()); + witness } /// Gets the witnessScript for the to_remote output when anchors are enabled. #[inline] -pub(crate) fn get_to_countersignatory_with_anchors_redeemscript(payment_point: &PublicKey) -> Script { +pub fn get_to_countersignatory_with_anchors_redeemscript(payment_point: &PublicKey) -> Script { Builder::new() .push_slice(&payment_point.serialize()[..]) .push_opcode(opcodes::all::OP_CHECKSIGVERIFY) @@ -742,9 +796,10 @@ pub(crate) fn get_anchor_output<'a>(commitment_tx: &'a Transaction, funding_pubk /// Returns the witness required to satisfy and spend an anchor input. pub fn build_anchor_input_witness(funding_key: &PublicKey, funding_sig: &Signature) -> Witness { let anchor_redeem_script = chan_utils::get_anchor_redeemscript(funding_key); - let mut funding_sig = funding_sig.serialize_der().to_vec(); - funding_sig.push(EcdsaSighashType::All as u8); - Witness::from_vec(vec![funding_sig, anchor_redeem_script.to_bytes()]) + let mut ret = Witness::new(); + ret.push_bitcoin_signature(&funding_sig.serialize_der(), EcdsaSighashType::All); + ret.push(anchor_redeem_script.as_bytes()); + ret } /// Per-channel data used to build transactions in conjunction with the per-commitment data (CommitmentTransaction). @@ -752,7 +807,7 @@ pub fn build_anchor_input_witness(funding_key: &PublicKey, funding_sig: &Signatu /// /// Normally, this is converted to the broadcaster/countersignatory-organized DirectedChannelTransactionParameters /// before use, via the as_holder_broadcastable and as_counterparty_broadcastable functions. -#[derive(Clone)] +#[derive(Clone, Debug, PartialEq)] pub struct ChannelTransactionParameters { /// Holder public keys pub holder_pubkeys: ChannelPublicKeys, @@ -776,7 +831,7 @@ pub struct ChannelTransactionParameters { } /// Late-bound per-channel counterparty data used to build transactions. -#[derive(Clone)] +#[derive(Clone, Debug, PartialEq)] pub struct CounterpartyChannelTransactionParameters { /// Counter-party public keys pub pubkeys: ChannelPublicKeys, @@ -978,17 +1033,13 @@ impl HolderCommitmentTransaction { // First push the multisig dummy, note that due to BIP147 (NULLDUMMY) it must be a zero-length element. let mut tx = self.inner.built.transaction.clone(); tx.input[0].witness.push(Vec::new()); - let mut ser_holder_sig = holder_sig.serialize_der().to_vec(); - ser_holder_sig.push(EcdsaSighashType::All as u8); - let mut ser_cp_sig = self.counterparty_sig.serialize_der().to_vec(); - ser_cp_sig.push(EcdsaSighashType::All as u8); if self.holder_sig_first { - tx.input[0].witness.push(ser_holder_sig); - tx.input[0].witness.push(ser_cp_sig); + tx.input[0].witness.push_bitcoin_signature(&holder_sig.serialize_der(), EcdsaSighashType::All); + tx.input[0].witness.push_bitcoin_signature(&self.counterparty_sig.serialize_der(), EcdsaSighashType::All); } else { - tx.input[0].witness.push(ser_cp_sig); - tx.input[0].witness.push(ser_holder_sig); + tx.input[0].witness.push_bitcoin_signature(&self.counterparty_sig.serialize_der(), EcdsaSighashType::All); + tx.input[0].witness.push_bitcoin_signature(&holder_sig.serialize_der(), EcdsaSighashType::All); } tx.input[0].witness.push(funding_redeemscript.as_bytes().to_vec()); @@ -1287,7 +1338,7 @@ impl CommitmentTransaction { let script = if opt_anchors { get_to_countersignatory_with_anchors_redeemscript(&countersignatory_pubkeys.payment_point).to_v0_p2wsh() } else { - get_p2wpkh_redeemscript(&countersignatory_pubkeys.payment_point) + Payload::p2wpkh(&BitcoinPublicKey::new(countersignatory_pubkeys.payment_point)).unwrap().script_pubkey() }; txouts.push(( TxOut { @@ -1539,26 +1590,9 @@ impl<'a> TrustedCommitmentTransaction<'a> { 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() { EcdsaSighashType::SinglePlusAnyoneCanPay } else { EcdsaSighashType::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()); - - let mut cp_sig_ser = counterparty_signature.serialize_der().to_vec(); - cp_sig_ser.push(sighashtype as u8); - htlc_tx.input[0].witness.push(cp_sig_ser); - let mut holder_sig_ser = signature.serialize_der().to_vec(); - holder_sig_ser.push(EcdsaSighashType::All as u8); - htlc_tx.input[0].witness.push(holder_sig_ser); - - if this_htlc.offered { - // Due to BIP146 (MINIMALIF) this must be a zero-length element to relay. - htlc_tx.input[0].witness.push(Vec::new()); - } else { - htlc_tx.input[0].witness.push(preimage.unwrap().0.to_vec()); - } - - htlc_tx.input[0].witness.push(htlc_redeemscript.as_bytes().to_vec()); + htlc_tx.input[0].witness = chan_utils::build_htlc_input_witness( + signature, counterparty_signature, preimage, &htlc_redeemscript, self.opt_anchors(), + ); htlc_tx } } @@ -1593,25 +1627,21 @@ pub fn get_commitment_transaction_number_obscure_factor( | ((res[31] as u64) << 0 * 8) } -fn get_p2wpkh_redeemscript(key: &PublicKey) -> Script { - Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0) - .push_slice(&WPubkeyHash::hash(&key.serialize())[..]) - .into_script() -} - #[cfg(test)] mod tests { use super::CounterpartyCommitmentSecrets; use crate::{hex, chain}; use crate::prelude::*; - use crate::ln::chan_utils::{get_htlc_redeemscript, get_to_countersignatory_with_anchors_redeemscript, get_p2wpkh_redeemscript, CommitmentTransaction, TxCreationKeys, ChannelTransactionParameters, CounterpartyChannelTransactionParameters, HTLCOutputInCommitment}; + use crate::ln::chan_utils::{get_htlc_redeemscript, get_to_countersignatory_with_anchors_redeemscript, CommitmentTransaction, TxCreationKeys, ChannelTransactionParameters, CounterpartyChannelTransactionParameters, HTLCOutputInCommitment}; use bitcoin::secp256k1::{PublicKey, SecretKey, Secp256k1}; use crate::util::test_utils; - use crate::chain::keysinterface::{KeysInterface, BaseSign}; + use crate::chain::keysinterface::{ChannelSigner, SignerProvider}; use bitcoin::{Network, Txid}; use bitcoin::hashes::Hash; use crate::ln::PaymentHash; use bitcoin::hashes::hex::ToHex; + use bitcoin::util::address::Payload; + use bitcoin::PublicKey as BitcoinPublicKey; #[test] fn test_anchors() { @@ -1620,8 +1650,8 @@ mod tests { let seed = [42; 32]; let network = Network::Testnet; let keys_provider = test_utils::TestKeysInterface::new(&seed, network); - let signer = keys_provider.get_channel_signer(false, 3000); - let counterparty_signer = keys_provider.get_channel_signer(false, 3000); + let signer = keys_provider.derive_channel_signer(3000, keys_provider.generate_channel_keys_id(false, 1_000_000, 0)); + let counterparty_signer = keys_provider.derive_channel_signer(3000, keys_provider.generate_channel_keys_id(true, 1_000_000, 1)); let delayed_payment_base = &signer.pubkeys().delayed_payment_basepoint; let per_commitment_secret = SecretKey::from_slice(&hex::decode("1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100").unwrap()[..]).unwrap(); let per_commitment_point = PublicKey::from_secret_key(&secp_ctx, &per_commitment_secret); @@ -1651,7 +1681,7 @@ mod tests { &mut htlcs_with_aux, &channel_parameters.as_holder_broadcastable() ); assert_eq!(tx.built.transaction.output.len(), 2); - assert_eq!(tx.built.transaction.output[1].script_pubkey, get_p2wpkh_redeemscript(&counterparty_pubkeys.payment_point)); + assert_eq!(tx.built.transaction.output[1].script_pubkey, Payload::p2wpkh(&BitcoinPublicKey::new(counterparty_pubkeys.payment_point)).unwrap().script_pubkey()); // Generate broadcaster and counterparty outputs as well as two anchors let tx = CommitmentTransaction::new_with_auxiliary_htlc_data( @@ -1717,9 +1747,9 @@ mod tests { 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"); + "0020e43a7c068553003fe68fcae424fb7b28ec5ce48cd8b6744b3945631389bad2fb"); assert_eq!(get_htlc_redeemscript(&offered_htlc, false, &keys).to_v0_p2wsh().to_hex(), - "002049f0736bb335c61a04d2623a24df878a7592a3c51fa7258d41b2c85318265e73"); + "0020215d61bba56b19e9eadb6107f5a85d7f99c40f65992443f69229c290165bc00d"); // Generate broadcaster output and received and offered HTLC outputs, with anchors channel_parameters.opt_anchors = Some(()); @@ -1736,9 +1766,9 @@ mod tests { 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"); + "0020b70d0649c72b38756885c7a30908d912a7898dd5d79457a7280b8e9a20f3f2bc"); assert_eq!(get_htlc_redeemscript(&offered_htlc, true, &keys).to_v0_p2wsh().to_hex(), - "0020a06e3b0d4fcf704f2b9c41e16a70099e39989466c3142b8573a1154542f28f57"); + "002087a3faeb1950a469c0e2db4a79b093a41b9526e5a6fc6ef5cb949bde3be379c7"); } #[test]