X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fchan_utils.rs;h=4690d298aedee2a7f16b18adf09ffee8ac202c4e;hb=0dfcacd22c23f69b6526c9c6507d21427a2b7ccb;hp=8037de64eb562f4ef854b511a382625b77f0e035;hpb=9c9c88147e6a8fa637dc048f764ab8ecfea200d4;p=rust-lightning diff --git a/lightning/src/ln/chan_utils.rs b/lightning/src/ln/chan_utils.rs index 8037de64..4690d298 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,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; -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 }) } } @@ -321,8 +317,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, 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)] @@ -348,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. @@ -384,11 +385,16 @@ impl TxCreationKeys { } } +/// The maximum length of a script returned by get_revokeable_redeemscript. +// Calculated as 6 bytes of opcodes, 1 byte push plus 2 bytes for contest_delay, and two public +// keys of 33 bytes (+ 1 push). +pub const REVOKEABLE_REDEEMSCRIPT_MAX_LENGTH: usize = 6 + 3 + 34*2; + /// A script either spendable by the revocation /// key or the broadcaster_delayed_payment_key and satisfying the relative-locktime OP_CSV constrain. /// Encumbering a `to_holder` output on a commitment transaction or 2nd-stage HTLC transactions. pub fn get_revokeable_redeemscript(revocation_key: &PublicKey, contest_delay: u16, broadcaster_delayed_payment_key: &PublicKey) -> Script { - Builder::new().push_opcode(opcodes::all::OP_IF) + let res = Builder::new().push_opcode(opcodes::all::OP_IF) .push_slice(&revocation_key.serialize()) .push_opcode(opcodes::all::OP_ELSE) .push_int(contest_delay as i64) @@ -397,7 +403,9 @@ pub fn get_revokeable_redeemscript(revocation_key: &PublicKey, contest_delay: u1 .push_slice(&broadcaster_delayed_payment_key.serialize()) .push_opcode(opcodes::all::OP_ENDIF) .push_opcode(opcodes::all::OP_CHECKSIG) - .into_script() + .into_script(); + debug_assert!(res.len() <= REVOKEABLE_REDEEMSCRIPT_MAX_LENGTH); + res } #[derive(Clone, PartialEq)] @@ -421,12 +429,12 @@ 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, required), + (2, amount_msat, required), + (4, cltv_expiry, required), + (6, payment_hash, required), + (8, transaction_output_index, option), }); #[inline] @@ -517,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(), @@ -611,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 @@ -704,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 { @@ -789,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. @@ -843,41 +863,14 @@ impl PartialEq for CommitmentTransaction { } } -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(()) - } -} - -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 { @@ -889,6 +882,8 @@ impl CommitmentTransaction { /// This auxiliary data is not stored in this object. /// /// Only include HTLCs that are above the dust limit for the channel. + /// + /// (C-not exported) due to the generic though we likely should expose a version without pub fn new_with_auxiliary_htlc_data(commitment_number: u64, to_broadcaster_value_sat: u64, to_countersignatory_value_sat: u64, keys: TxCreationKeys, feerate_per_kw: u32, htlcs_with_aux: &mut Vec<(HTLCOutputInCommitment, T)>, channel_parameters: &DirectedChannelTransactionParameters) -> CommitmentTransaction { // Sort outputs and populate output indices while keeping track of the auxiliary data let (outputs, htlcs) = Self::internal_build_outputs(&keys, to_broadcaster_value_sat, to_countersignatory_value_sat, htlcs_with_aux, channel_parameters).unwrap(); @@ -1056,6 +1051,9 @@ impl CommitmentTransaction { /// The non-dust HTLCs (direction, amt, height expiration, hash, transaction output index) /// which were included in this commitment transaction in output order. /// The transaction index is always populated. + /// + /// (C-not exported) as we cannot currently convert Vec references to/from C, though we should + /// expose a less effecient version which creates a Vec of references in the future. pub fn htlcs(&self) -> &Vec { &self.htlcs } @@ -1182,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, @@ -1217,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() {