X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fchan_utils.rs;h=9f98cd03b28af31ec86b58f154bf582942ccf849;hb=073afbb24471a2e1bd50b88dc7a5e4d7cd4e0dd6;hp=f86c53bc3bc7b01584ba9720014ec23b23330263;hpb=414e62230e8bcca5c841222b21a00fe60609ee03;p=rust-lightning diff --git a/lightning/src/ln/chan_utils.rs b/lightning/src/ln/chan_utils.rs index f86c53bc..9f98cd03 100644 --- a/lightning/src/ln/chan_utils.rs +++ b/lightning/src/ln/chan_utils.rs @@ -8,8 +8,7 @@ // licenses. //! Various utilities for building scripts and deriving keys related to channels. These are -//! largely of interest for those implementing chain::keysinterface::ChannelKeys message signing -//! by hand. +//! largely of interest for those implementing chain::keysinterface::Sign message signing by hand. use bitcoin::blockdata::script::{Script,Builder}; use bitcoin::blockdata::opcodes; @@ -21,9 +20,9 @@ use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::hashes::ripemd160::Hash as Ripemd160; use bitcoin::hash_types::{Txid, PubkeyHash}; -use ln::channelmanager::{PaymentHash, PaymentPreimage}; +use ln::{PaymentHash, PaymentPreimage}; use ln::msgs::DecodeError; -use util::ser::{Readable, Writeable, Writer, MAX_BUF_SIZE}; +use util::ser::{Readable, Writeable, Writer}; use util::byte_utils; use bitcoin::hash_types::WPubkeyHash; @@ -32,21 +31,16 @@ use bitcoin::secp256k1::{Secp256k1, Signature, Message}; use bitcoin::secp256k1::Error as SecpError; use bitcoin::secp256k1; -use std::cmp; +use prelude::*; +use core::cmp; use ln::chan_utils; use util::transaction_utils::sort_outputs; use ln::channel::INITIAL_COMMITMENT_NUMBER; -use std::io::Read; -use std::ops::Deref; +use core::ops::Deref; use chain; -const HTLC_OUTPUT_IN_COMMITMENT_SIZE: usize = 1 + 8 + 4 + 32 + 5; - pub(crate) const MAX_HTLCS: u16 = 483; -// This checks that the buffer size is greater than the maximum possible size for serialized HTLCS -const _EXCESS_BUFFER_SIZE: usize = MAX_BUF_SIZE - MAX_HTLCS as usize * HTLC_OUTPUT_IN_COMMITMENT_SIZE; - pub(super) const HTLC_SUCCESS_TX_WEIGHT: u64 = 703; pub(super) const HTLC_TIMEOUT_TX_WEIGHT: u64 = 663; @@ -178,6 +172,7 @@ impl Writeable for CounterpartyCommitmentSecrets { writer.write_all(secret)?; writer.write_all(&byte_utils::be64_to_array(*idx))?; } + write_tlv_fields!(writer, {}, {}); Ok(()) } } @@ -188,7 +183,7 @@ impl Readable for CounterpartyCommitmentSecrets { *secret = Readable::read(reader)?; *idx = Readable::read(reader)?; } - + read_tlv_fields!(reader, {}, {}); Ok(Self { old_secrets }) } } @@ -321,8 +316,14 @@ pub struct TxCreationKeys { /// Broadcaster's Payment Key (which isn't allowed to be spent from for some delay) pub broadcaster_delayed_payment_key: PublicKey, } -impl_writeable!(TxCreationKeys, 33*6, - { per_commitment_point, revocation_key, broadcaster_htlc_key, countersignatory_htlc_key, broadcaster_delayed_payment_key }); + +impl_writeable_tlv_based!(TxCreationKeys, { + (0, per_commitment_point), + (2, revocation_key), + (4, broadcaster_htlc_key), + (6, countersignatory_htlc_key), + (8, broadcaster_delayed_payment_key), +}, {}, {}); /// One counterparty's public keys which do not change over the life of a channel. #[derive(Clone, PartialEq)] @@ -348,14 +349,13 @@ pub struct ChannelPublicKeys { pub htlc_basepoint: PublicKey, } -impl_writeable!(ChannelPublicKeys, 33*5, { - funding_pubkey, - revocation_basepoint, - payment_point, - delayed_payment_basepoint, - htlc_basepoint -}); - +impl_writeable_tlv_based!(ChannelPublicKeys, { + (0, funding_pubkey), + (2, revocation_basepoint), + (4, payment_point), + (6, delayed_payment_basepoint), + (8, htlc_basepoint), +}, {}, {}); impl TxCreationKeys { /// Create per-state keys from channel base points and the per-commitment point. @@ -428,13 +428,14 @@ pub struct HTLCOutputInCommitment { pub transaction_output_index: Option, } -impl_writeable!(HTLCOutputInCommitment, HTLC_OUTPUT_IN_COMMITMENT_SIZE, { - offered, - amount_msat, - cltv_expiry, - payment_hash, - transaction_output_index -}); +impl_writeable_tlv_based!(HTLCOutputInCommitment, { + (0, offered), + (2, amount_msat), + (4, cltv_expiry), + (6, payment_hash), +}, { + (8, transaction_output_index) +}, {}); #[inline] pub(crate) fn get_htlc_redeemscript_with_explicit_keys(htlc: &HTLCOutputInCommitment, broadcaster_htlc_key: &PublicKey, countersignatory_htlc_key: &PublicKey, revocation_key: &PublicKey) -> Script { @@ -524,12 +525,18 @@ pub fn make_funding_redeemscript(broadcaster: &PublicKey, countersignatory: &Pub }.push_opcode(opcodes::all::OP_PUSHNUM_2).push_opcode(opcodes::all::OP_CHECKMULTISIG).into_script() } -/// panics if htlc.transaction_output_index.is_none()! -pub fn build_htlc_transaction(prev_hash: &Txid, feerate_per_kw: u32, contest_delay: u16, htlc: &HTLCOutputInCommitment, broadcaster_delayed_payment_key: &PublicKey, revocation_key: &PublicKey) -> Transaction { +/// Builds an unsigned HTLC-Success or HTLC-Timeout transaction from the given channel and HTLC +/// parameters. This is used by [`TrustedCommitmentTransaction::get_htlc_sigs`] to fetch the +/// transaction which needs signing, and can be used to construct an HTLC transaction which is +/// broadcastable given a counterparty HTLC signature. +/// +/// 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 { let mut txins: Vec = Vec::new(); txins.push(TxIn { previous_output: OutPoint { - txid: prev_hash.clone(), + txid: commitment_txid.clone(), vout: htlc.transaction_output_index.expect("Can't build an HTLC transaction for a dust output"), }, script_sig: Script::new(), @@ -618,18 +625,19 @@ impl ChannelTransactionParameters { } } -impl_writeable!(CounterpartyChannelTransactionParameters, 0, { - pubkeys, - selected_contest_delay -}); +impl_writeable_tlv_based!(CounterpartyChannelTransactionParameters, { + (0, pubkeys), + (2, selected_contest_delay), +}, {}, {}); -impl_writeable!(ChannelTransactionParameters, 0, { - holder_pubkeys, - holder_selected_contest_delay, - is_outbound_from_holder, - counterparty_parameters, - funding_outpoint -}); +impl_writeable_tlv_based!(ChannelTransactionParameters, { + (0, holder_pubkeys), + (2, holder_selected_contest_delay), + (4, is_outbound_from_holder), +}, { + (6, counterparty_parameters), + (8, funding_outpoint), +}, {}); /// Static channel fields used to build transactions given per-commitment fields, organized by /// broadcaster/countersignatory. @@ -711,8 +719,12 @@ impl PartialEq for HolderCommitmentTransaction { } } -impl_writeable!(HolderCommitmentTransaction, 0, { - inner, counterparty_sig, counterparty_htlc_sigs, holder_sig_first +impl_writeable_tlv_based!(HolderCommitmentTransaction, { + (0, inner), + (2, counterparty_sig), + (4, holder_sig_first), +}, {}, { + (6, counterparty_htlc_sigs), }); impl HolderCommitmentTransaction { @@ -796,7 +808,10 @@ pub struct BuiltCommitmentTransaction { pub txid: Txid, } -impl_writeable!(BuiltCommitmentTransaction, 0, { transaction, txid }); +impl_writeable_tlv_based!(BuiltCommitmentTransaction, { + (0, transaction), + (2, txid) +}, {}, {}); impl BuiltCommitmentTransaction { /// Get the SIGHASH_ALL sighash value of the transaction. @@ -850,43 +865,15 @@ impl PartialEq for CommitmentTransaction { } } -/// (C-not exported) as users never need to call this directly -impl Writeable for Vec { - #[inline] - fn write(&self, w: &mut W) -> Result<(), ::std::io::Error> { - (self.len() as u16).write(w)?; - for e in self.iter() { - e.write(w)?; - } - Ok(()) - } -} - -/// (C-not exported) as users never need to call this directly -impl Readable for Vec { - #[inline] - fn read(r: &mut R) -> Result { - let len: u16 = Readable::read(r)?; - let byte_size = (len as usize) - .checked_mul(HTLC_OUTPUT_IN_COMMITMENT_SIZE) - .ok_or(DecodeError::BadLengthDescriptor)?; - if byte_size > MAX_BUF_SIZE { - return Err(DecodeError::BadLengthDescriptor); - } - let mut ret = Vec::with_capacity(len as usize); - for _ in 0..len { ret.push(HTLCOutputInCommitment::read(r)?); } - Ok(ret) - } -} - -impl_writeable!(CommitmentTransaction, 0, { - commitment_number, - to_broadcaster_value_sat, - to_countersignatory_value_sat, - feerate_per_kw, - htlcs, - keys, - built +impl_writeable_tlv_based!(CommitmentTransaction, { + (0, commitment_number), + (2, to_broadcaster_value_sat), + (4, to_countersignatory_value_sat), + (6, feerate_per_kw), + (8, keys), + (10, built), +}, {}, { + (12, htlcs), }); impl CommitmentTransaction { @@ -1196,7 +1183,12 @@ impl<'a> TrustedCommitmentTransaction<'a> { } } -/// Get the transaction number obscure factor +/// Commitment transaction numbers which appear in the transactions themselves are XOR'd with a +/// shared secret first. This prevents on-chain observers from discovering how many commitment +/// transactions occurred in a channel before it was closed. +/// +/// This function gets the shared secret from relevant channel public keys and can be used to +/// "decrypt" the commitment transaction number given a commitment transaction on-chain. pub fn get_commitment_transaction_number_obscure_factor( broadcaster_payment_basepoint: &PublicKey, countersignatory_payment_basepoint: &PublicKey, @@ -1231,6 +1223,7 @@ fn script_for_p2wpkh(key: &PublicKey) -> Script { mod tests { use super::CounterpartyCommitmentSecrets; use hex; + use prelude::*; #[test] fn test_per_commitment_storage() {