X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fchan_utils.rs;h=4690d298aedee2a7f16b18adf09ffee8ac202c4e;hb=0dfcacd22c23f69b6526c9c6507d21427a2b7ccb;hp=4438579657eecc74e6cf1cb9458b339c2db82292;hpb=3b67be235a46d8f9a9a6faf7ca7c5872ffbd8646;p=rust-lightning diff --git a/lightning/src/ln/chan_utils.rs b/lightning/src/ln/chan_utils.rs index 44385796..4690d298 100644 --- a/lightning/src/ln/chan_utils.rs +++ b/lightning/src/ln/chan_utils.rs @@ -22,7 +22,7 @@ use bitcoin::hash_types::{Txid, PubkeyHash}; 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; @@ -31,22 +31,17 @@ use bitcoin::secp256k1::{Secp256k1, Signature, Message}; use bitcoin::secp256k1::Error as SecpError; use bitcoin::secp256k1; -use std::cmp; +use io; +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; -// Maximum size of a serialized HTLCOutputInCommitment -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; @@ -173,22 +168,23 @@ impl CounterpartyCommitmentSecrets { } impl Writeable for CounterpartyCommitmentSecrets { - fn write(&self, writer: &mut W) -> Result<(), ::std::io::Error> { + 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))?; } + write_tlv_fields!(writer, {}); Ok(()) } } impl Readable for CounterpartyCommitmentSecrets { - fn read(reader: &mut R) -> Result { + fn read(reader: &mut R) -> Result { let mut old_secrets = [([0; 32], 1 << 48); 49]; for &mut (ref mut secret, ref mut idx) in old_secrets.iter_mut() { *secret = Readable::read(reader)?; *idx = Readable::read(reader)?; } - + read_tlv_fields!(reader, {}); Ok(Self { old_secrets }) } } @@ -322,8 +318,13 @@ pub struct TxCreationKeys { pub broadcaster_delayed_payment_key: PublicKey, } -impl_writeable!(TxCreationKeys, 33*5, - { per_commitment_point, revocation_key, broadcaster_htlc_key, countersignatory_htlc_key, broadcaster_delayed_payment_key }); +impl_writeable_tlv_based!(TxCreationKeys, { + (0, per_commitment_point, required), + (2, revocation_key, required), + (4, broadcaster_htlc_key, required), + (6, countersignatory_htlc_key, required), + (8, broadcaster_delayed_payment_key, required), +}); /// One counterparty's public keys which do not change over the life of a channel. #[derive(Clone, PartialEq)] @@ -349,15 +350,14 @@ 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, required), + (2, revocation_basepoint, required), + (4, payment_point, required), + (6, delayed_payment_basepoint, required), + (8, htlc_basepoint, required), }); - impl TxCreationKeys { /// Create per-state keys from channel base points and the per-commitment point. /// Key set is asymmetric and can't be used as part of counter-signatory set of transactions. @@ -429,15 +429,12 @@ pub struct HTLCOutputInCommitment { pub transaction_output_index: Option, } -impl_writeable_len_match!(HTLCOutputInCommitment, { - { HTLCOutputInCommitment { transaction_output_index: None, .. }, HTLC_OUTPUT_IN_COMMITMENT_SIZE - 4 }, - { _, HTLC_OUTPUT_IN_COMMITMENT_SIZE } - }, { - offered, - amount_msat, - cltv_expiry, - payment_hash, - transaction_output_index +impl_writeable_tlv_based!(HTLCOutputInCommitment, { + (0, offered, required), + (2, amount_msat, required), + (4, cltv_expiry, required), + (6, payment_hash, required), + (8, transaction_output_index, option), }); #[inline] @@ -528,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(), @@ -622,17 +625,17 @@ impl ChannelTransactionParameters { } } -impl_writeable!(CounterpartyChannelTransactionParameters, 0, { - pubkeys, - selected_contest_delay +impl_writeable_tlv_based!(CounterpartyChannelTransactionParameters, { + (0, pubkeys, required), + (2, selected_contest_delay, required), }); -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, required), + (2, holder_selected_contest_delay, required), + (4, is_outbound_from_holder, required), + (6, counterparty_parameters, option), + (8, funding_outpoint, option), }); /// Static channel fields used to build transactions given per-commitment fields, organized by @@ -715,8 +718,11 @@ impl PartialEq for HolderCommitmentTransaction { } } -impl_writeable!(HolderCommitmentTransaction, 0, { - inner, counterparty_sig, counterparty_htlc_sigs, holder_sig_first +impl_writeable_tlv_based!(HolderCommitmentTransaction, { + (0, inner, required), + (2, counterparty_sig, required), + (4, holder_sig_first, required), + (6, counterparty_htlc_sigs, vec_type), }); impl HolderCommitmentTransaction { @@ -800,7 +806,10 @@ pub struct BuiltCommitmentTransaction { pub txid: Txid, } -impl_writeable!(BuiltCommitmentTransaction, 0, { transaction, txid }); +impl_writeable_tlv_based!(BuiltCommitmentTransaction, { + (0, transaction, required), + (2, txid, required), +}); impl BuiltCommitmentTransaction { /// Get the SIGHASH_ALL sighash value of the transaction. @@ -854,43 +863,14 @@ 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, required), + (2, to_broadcaster_value_sat, required), + (4, to_countersignatory_value_sat, required), + (6, feerate_per_kw, required), + (8, keys, required), + (10, built, required), + (12, htlcs, vec_type), }); impl CommitmentTransaction { @@ -1200,7 +1180,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, @@ -1235,6 +1220,7 @@ fn script_for_p2wpkh(key: &PublicKey) -> Script { mod tests { use super::CounterpartyCommitmentSecrets; use hex; + use prelude::*; #[test] fn test_per_commitment_storage() {