X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fmsgs.rs;h=3e0627aac233036361bda62971f704d6ea2718d6;hb=refs%2Fheads%2Fupstream%2Fmain;hp=2efc3c1c051798eebcad6fc800502d85ab683659;hpb=6d1111111ccafedec6b2050e76ce91eb59c993b4;p=rust-lightning diff --git a/lightning/src/ln/msgs.rs b/lightning/src/ln/msgs.rs index 2efc3c1c..e7b43ded 100644 --- a/lightning/src/ln/msgs.rs +++ b/lightning/src/ln/msgs.rs @@ -32,15 +32,15 @@ use bitcoin::blockdata::script::ScriptBuf; use bitcoin::hash_types::Txid; use crate::blinded_path::payment::{BlindedPaymentTlvs, ForwardTlvs, ReceiveTlvs}; -use crate::ln::{ChannelId, PaymentPreimage, PaymentHash, PaymentSecret}; +use crate::ln::types::{ChannelId, PaymentPreimage, PaymentHash, PaymentSecret}; use crate::ln::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures}; use crate::ln::onion_utils; use crate::onion_message; use crate::sign::{NodeSigner, Recipient}; +#[allow(unused_imports)] use crate::prelude::*; -#[cfg(feature = "std")] -use core::convert::TryFrom; + use core::fmt; use core::fmt::Debug; use core::ops::Deref; @@ -52,10 +52,10 @@ use core::fmt::Display; use crate::io::{self, Cursor, Read}; use crate::io_extras::read_to_end; -use crate::events::{EventsProvider, MessageSendEventsProvider}; +use crate::events::MessageSendEventsProvider; use crate::crypto::streams::ChaChaPolyReadAdapter; use crate::util::logger; -use crate::util::ser::{LengthReadable, LengthReadableArgs, Readable, ReadableArgs, Writeable, Writer, WithoutLength, FixedLengthReader, HighZeroBytesDroppedBigSize, Hostname, TransactionU16LenLimited, BigSize}; +use crate::util::ser::{BigSize, FixedLengthReader, HighZeroBytesDroppedBigSize, Hostname, LengthRead, LengthReadable, LengthReadableArgs, Readable, ReadableArgs, TransactionU16LenLimited, WithoutLength, Writeable, Writer}; use crate::util::base32; use crate::routing::gossip::{NodeAlias, NodeId}; @@ -91,6 +91,16 @@ pub enum DecodeError { Io(io::ErrorKind), /// The message included zlib-compressed values, which we don't support. UnsupportedCompression, + /// Value is validly encoded but is dangerous to use. + /// + /// This is used for things like [`ChannelManager`] deserialization where we want to ensure + /// that we don't use a [`ChannelManager`] which is in out of sync with the [`ChannelMonitor`]. + /// This indicates that there is a critical implementation flaw in the storage implementation + /// and it's unsafe to continue. + /// + /// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager + /// [`ChannelMonitor`]: crate::chain::channelmonitor::ChannelMonitor + DangerousValue, } /// An [`init`] message to be sent to or received from a peer. @@ -400,8 +410,9 @@ pub struct ChannelReady { /// construction. pub type SerialId = u64; -/// An stfu (quiescence) message to be sent by or received from the stfu initiator. -// TODO(splicing): Add spec link for `stfu`; still in draft, using from https://github.com/lightning/bolts/pull/863 +/// An `stfu` (quiescence) message to be sent by or received from the stfu initiator. +/// +// TODO(splicing): Add spec link for `stfu`; still in draft, using from https://github.com/lightning/bolts/pull/1160 #[derive(Clone, Debug, PartialEq, Eq)] pub struct Stfu { /// The channel ID where quiescence is intended @@ -410,48 +421,51 @@ pub struct Stfu { pub initiator: u8, } -/// A splice message to be sent by or received from the stfu initiator (splice initiator). -// TODO(splicing): Add spec link for `splice`; still in draft, using from https://github.com/lightning/bolts/pull/863 +/// A `splice_init` message to be sent by or received from the stfu initiator (splice initiator). +/// +// TODO(splicing): Add spec link for `splice_init`; still in draft, using from https://github.com/lightning/bolts/pull/1160 #[derive(Clone, Debug, PartialEq, Eq)] -pub struct Splice { +pub struct SpliceInit { /// The channel ID where splicing is intended pub channel_id: ChannelId, - /// The genesis hash of the blockchain where the channel is intended to be spliced - pub chain_hash: ChainHash, - /// The intended change in channel capacity: the amount to be added (positive value) - /// or removed (negative value) by the sender (splice initiator) by splicing into/from the channel. - pub relative_satoshis: i64, + /// The amount the splice initiator is intending to add to its channel balance (splice-in) + /// or remove from its channel balance (splice-out). + pub funding_contribution_satoshis: i64, /// The feerate for the new funding transaction, set by the splice initiator pub funding_feerate_perkw: u32, /// The locktime for the new funding transaction pub locktime: u32, /// The key of the sender (splice initiator) controlling the new funding transaction pub funding_pubkey: PublicKey, + /// If set, only confirmed inputs added (by the splice acceptor) will be accepted + pub require_confirmed_inputs: Option<()>, } -/// A splice_ack message to be received by or sent to the splice initiator. +/// A `splice_ack` message to be received by or sent to the splice initiator. /// -// TODO(splicing): Add spec link for `splice_ack`; still in draft, using from https://github.com/lightning/bolts/pull/863 +// TODO(splicing): Add spec link for `splice_ack`; still in draft, using from https://github.com/lightning/bolts/pull/1160 #[derive(Clone, Debug, PartialEq, Eq)] pub struct SpliceAck { /// The channel ID where splicing is intended pub channel_id: ChannelId, - /// The genesis hash of the blockchain where the channel is intended to be spliced - pub chain_hash: ChainHash, - /// The intended change in channel capacity: the amount to be added (positive value) - /// or removed (negative value) by the sender (splice acceptor) by splicing into/from the channel. - pub relative_satoshis: i64, + /// The amount the splice acceptor is intending to add to its channel balance (splice-in) + /// or remove from its channel balance (splice-out). + pub funding_contribution_satoshis: i64, /// The key of the sender (splice acceptor) controlling the new funding transaction pub funding_pubkey: PublicKey, + /// If set, only confirmed inputs added (by the splice initiator) will be accepted + pub require_confirmed_inputs: Option<()>, } -/// A splice_locked message to be sent to or received from a peer. +/// A `splice_locked` message to be sent to or received from a peer. /// -// TODO(splicing): Add spec link for `splice_locked`; still in draft, using from https://github.com/lightning/bolts/pull/863 +// TODO(splicing): Add spec link for `splice_locked`; still in draft, using from https://github.com/lightning/bolts/pull/1160 #[derive(Clone, Debug, PartialEq, Eq)] pub struct SpliceLocked { /// The channel ID pub channel_id: ChannelId, + /// The ID of the new funding transaction that has been locked + pub splice_txid: Txid, } /// A tx_add_input message for adding an input during interactive transaction construction @@ -471,6 +485,8 @@ pub struct TxAddInput { pub prevtx_out: u32, /// The sequence number of this input pub sequence: u32, + /// The ID of the previous funding transaction, when it is being added as an input during splicing + pub shared_input_txid: Option, } /// A tx_add_output message for adding an output during interactive transaction construction. @@ -533,6 +549,8 @@ pub struct TxSignatures { pub tx_hash: Txid, /// The list of witnesses pub witnesses: Vec, + /// Optional signature for the shared input -- the previous funding outpoint -- signed by both peers + pub shared_input_signature: Option, } /// A tx_init_rbf message which initiates a replacement of the transaction after it's been @@ -696,6 +714,15 @@ pub struct UpdateFailMalformedHTLC { pub failure_code: u16, } +/// Optional batch parameters for `commitment_signed` message. +#[derive(Clone, Debug, Hash, PartialEq, Eq)] +pub struct CommitmentSignedBatch { + /// Batch size N: all N `commitment_signed` messages must be received before being processed + pub batch_size: u16, + /// The funding transaction, to discriminate among multiple pending funding transactions (e.g. in case of splicing) + pub funding_txid: Txid, +} + /// A [`commitment_signed`] message to be sent to or received from a peer. /// /// [`commitment_signed`]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#committing-updates-so-far-commitment_signed @@ -707,6 +734,8 @@ pub struct CommitmentSigned { pub signature: Signature, /// Signatures on the HTLC transactions pub htlc_signatures: Vec, + /// Optional batch size and other parameters + pub batch: Option, #[cfg(taproot)] /// The partial Taproot signature on the commitment transaction pub partial_signature_with_nonce: Option, @@ -1215,8 +1244,11 @@ pub struct UnsignedChannelUpdate { pub short_channel_id: u64, /// A strictly monotonic announcement counter, with gaps allowed, specific to this channel pub timestamp: u32, - /// Channel flags - pub flags: u8, + /// Flags pertaining to this message. + pub message_flags: u8, + /// Flags pertaining to the channel, including to which direction in the channel this update + /// applies and whether the direction is currently able to forward HTLCs. + pub channel_flags: u8, /// The number of blocks such that if: /// `incoming_htlc.cltv_expiry < outgoing_htlc.cltv_expiry + cltv_expiry_delta` /// then we need to fail the HTLC backwards. When forwarding an HTLC, `cltv_expiry_delta` determines @@ -1449,11 +1481,14 @@ pub trait ChannelMessageHandler : MessageSendEventsProvider { fn handle_stfu(&self, their_node_id: &PublicKey, msg: &Stfu); // Splicing - /// Handle an incoming `splice` message from the given peer. - fn handle_splice(&self, their_node_id: &PublicKey, msg: &Splice); + /// Handle an incoming `splice_init` message from the given peer. + #[cfg(splicing)] + fn handle_splice_init(&self, their_node_id: &PublicKey, msg: &SpliceInit); /// Handle an incoming `splice_ack` message from the given peer. + #[cfg(splicing)] fn handle_splice_ack(&self, their_node_id: &PublicKey, msg: &SpliceAck); /// Handle an incoming `splice_locked` message from the given peer. + #[cfg(splicing)] fn handle_splice_locked(&self, their_node_id: &PublicKey, msg: &SpliceLocked); // Interactive channel construction @@ -1608,7 +1643,7 @@ pub trait RoutingMessageHandler : MessageSendEventsProvider { } /// A handler for received [`OnionMessage`]s and for providing generated ones to send. -pub trait OnionMessageHandler: EventsProvider { +pub trait OnionMessageHandler { /// Handle an incoming `onion_message` message from the given peer. fn handle_onion_message(&self, peer_node_id: &PublicKey, msg: &OnionMessage); @@ -1662,12 +1697,14 @@ pub struct FinalOnionHopData { mod fuzzy_internal_msgs { use bitcoin::secp256k1::PublicKey; - use crate::blinded_path::payment::{PaymentConstraints, PaymentRelay}; - use crate::prelude::*; - use crate::ln::{PaymentPreimage, PaymentSecret}; + use crate::blinded_path::payment::{PaymentConstraints, PaymentContext, PaymentRelay}; + use crate::ln::types::{PaymentPreimage, PaymentSecret}; use crate::ln::features::BlindedHopFeatures; use super::{FinalOnionHopData, TrampolineOnionPacket}; + #[allow(unused_imports)] + use crate::prelude::*; + // These types aren't intended to be pub, but are exposed for direct fuzzing (as we deserialize // them from untrusted input): @@ -1699,12 +1736,14 @@ mod fuzzy_internal_msgs { cltv_expiry_height: u32, payment_secret: PaymentSecret, payment_constraints: PaymentConstraints, + payment_context: PaymentContext, intro_node_blinding_point: Option, keysend_preimage: Option, + custom_tlvs: Vec<(u64, Vec)>, } } - pub(crate) enum OutboundOnionPayload { + pub(crate) enum OutboundOnionPayload<'a> { Forward { short_channel_id: u64, /// The value, in msat, of the payment after this hop's fee is deducted. @@ -1720,23 +1759,35 @@ mod fuzzy_internal_msgs { }, Receive { payment_data: Option, - payment_metadata: Option>, + payment_metadata: Option<&'a Vec>, keysend_preimage: Option, - custom_tlvs: Vec<(u64, Vec)>, + custom_tlvs: &'a Vec<(u64, Vec)>, sender_intended_htlc_amt_msat: u64, cltv_expiry_height: u32, }, BlindedForward { - encrypted_tlvs: Vec, + encrypted_tlvs: &'a Vec, intro_node_blinding_point: Option, }, BlindedReceive { sender_intended_htlc_amt_msat: u64, total_msat: u64, cltv_expiry_height: u32, - encrypted_tlvs: Vec, + encrypted_tlvs: &'a Vec, intro_node_blinding_point: Option, // Set if the introduction node of the blinded path is the final node keysend_preimage: Option, + custom_tlvs: &'a Vec<(u64, Vec)>, + } + } + + pub(crate) enum OutboundTrampolinePayload { + #[allow(unused)] + Forward { + /// The value, in msat, of the payment after this hop's fee is deducted. + amt_to_forward: u64, + outgoing_cltv_value: u32, + /// The node id to which the trampoline node must find a route + outgoing_node_id: PublicKey, } } @@ -1798,7 +1849,7 @@ pub struct TrampolineOnionPacket { // Unlike the onion packets used for payments, Trampoline onion packets have to be shorter than // 1300 bytes. The expected default is 650 bytes. // TODO: if 650 ends up being the most common size, optimize this to be: - // enum { ThirteenHundred([u8; 650]), VarLen(Vec) } + // enum { SixFifty([u8; 650]), VarLen(Vec) } pub hop_data: Vec, /// HMAC to verify the integrity of hop_data pub hmac: [u8; 32], @@ -1826,6 +1877,26 @@ impl Writeable for TrampolineOnionPacket { } } +impl LengthReadable for TrampolineOnionPacket { + fn read(r: &mut R) -> Result { + let version = Readable::read(r)?; + let public_key = Readable::read(r)?; + + let hop_data_len = r.total_bytes().saturating_sub(66); // 1 (version) + 33 (pubkey) + 32 (HMAC) = 66 + let mut rd = FixedLengthReader::new(r, hop_data_len); + let hop_data = WithoutLength::>::read(&mut rd)?.0; + + let hmac = Readable::read(r)?; + + Ok(TrampolineOnionPacket { + version, + public_key, + hop_data, + hmac, + }) + } +} + impl Debug for TrampolineOnionPacket { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_fmt(format_args!("TrampolineOnionPacket version {} with hmac {:?}", self.version, &self.hmac[..])) @@ -1849,6 +1920,7 @@ impl fmt::Display for DecodeError { DecodeError::BadLengthDescriptor => f.write_str("A length descriptor in the packet didn't describe the later data correctly"), DecodeError::Io(ref e) => fmt::Debug::fmt(e, f), DecodeError::UnsupportedCompression => f.write_str("We don't support receiving messages with zlib-compressed fields"), + DecodeError::DangerousValue => f.write_str("Value would be dangerous to continue execution with"), } } } @@ -2036,24 +2108,27 @@ impl_writeable_msg!(Stfu, { initiator, }, {}); -impl_writeable_msg!(Splice, { +impl_writeable_msg!(SpliceInit, { channel_id, - chain_hash, - relative_satoshis, + funding_contribution_satoshis, funding_feerate_perkw, locktime, funding_pubkey, -}, {}); +}, { + (2, require_confirmed_inputs, option), // `splice_init_tlvs` +}); impl_writeable_msg!(SpliceAck, { channel_id, - chain_hash, - relative_satoshis, + funding_contribution_satoshis, funding_pubkey, -}, {}); +}, { + (2, require_confirmed_inputs, option), // `splice_ack_tlvs` +}); impl_writeable_msg!(SpliceLocked, { channel_id, + splice_txid, }, {}); impl_writeable_msg!(TxAddInput, { @@ -2062,7 +2137,9 @@ impl_writeable_msg!(TxAddInput, { prevtx, prevtx_out, sequence, -}, {}); +}, { + (0, shared_input_txid, option), // `funding_txid` +}); impl_writeable_msg!(TxAddOutput, { channel_id, @@ -2089,7 +2166,9 @@ impl_writeable_msg!(TxSignatures, { channel_id, tx_hash, witnesses, -}, {}); +}, { + (0, shared_input_signature, option), // `signature` +}); impl_writeable_msg!(TxInitRbf, { channel_id, @@ -2137,12 +2216,19 @@ impl_writeable!(ClosingSignedFeeRange, { max_fee_satoshis }); +impl_writeable_msg!(CommitmentSignedBatch, { + batch_size, + funding_txid, +}, {}); + #[cfg(not(taproot))] impl_writeable_msg!(CommitmentSigned, { channel_id, signature, htlc_signatures -}, {}); +}, { + (0, batch, option), +}); #[cfg(taproot)] impl_writeable_msg!(CommitmentSigned, { @@ -2150,7 +2236,8 @@ impl_writeable_msg!(CommitmentSigned, { signature, htlc_signatures }, { - (2, partial_signature_with_nonce, option) + (0, batch, option), + (2, partial_signature_with_nonce, option), }); impl_writeable!(DecodedOnionErrorPacket, { @@ -2535,7 +2622,7 @@ impl Readable for FinalOnionHopData { } } -impl Writeable for OutboundOnionPayload { +impl<'a> Writeable for OutboundOnionPayload<'a> { fn write(&self, w: &mut W) -> Result<(), io::Error> { match self { Self::Forward { short_channel_id, amt_to_forward, outgoing_cltv_value } => { @@ -2570,33 +2657,54 @@ impl Writeable for OutboundOnionPayload { (2, HighZeroBytesDroppedBigSize(*sender_intended_htlc_amt_msat), required), (4, HighZeroBytesDroppedBigSize(*cltv_expiry_height), required), (8, payment_data, option), - (16, payment_metadata.as_ref().map(|m| WithoutLength(m)), option) + (16, payment_metadata.map(|m| WithoutLength(m)), option) }, custom_tlvs.iter()); }, Self::BlindedForward { encrypted_tlvs, intro_node_blinding_point } => { _encode_varint_length_prefixed_tlv!(w, { - (10, *encrypted_tlvs, required_vec), + (10, **encrypted_tlvs, required_vec), (12, intro_node_blinding_point, option) }); }, Self::BlindedReceive { sender_intended_htlc_amt_msat, total_msat, cltv_expiry_height, encrypted_tlvs, - intro_node_blinding_point, keysend_preimage, + intro_node_blinding_point, keysend_preimage, ref custom_tlvs, } => { + // We need to update [`ln::outbound_payment::RecipientOnionFields::with_custom_tlvs`] + // to reject any reserved types in the experimental range if new ones are ever + // standardized. + let keysend_tlv = keysend_preimage.map(|preimage| (5482373484, preimage.encode())); + let mut custom_tlvs: Vec<&(u64, Vec)> = custom_tlvs.iter().chain(keysend_tlv.iter()).collect(); + custom_tlvs.sort_unstable_by_key(|(typ, _)| *typ); _encode_varint_length_prefixed_tlv!(w, { (2, HighZeroBytesDroppedBigSize(*sender_intended_htlc_amt_msat), required), (4, HighZeroBytesDroppedBigSize(*cltv_expiry_height), required), - (10, *encrypted_tlvs, required_vec), + (10, **encrypted_tlvs, required_vec), (12, intro_node_blinding_point, option), - (18, HighZeroBytesDroppedBigSize(*total_msat), required), - (5482373484, keysend_preimage, option) - }); + (18, HighZeroBytesDroppedBigSize(*total_msat), required) + }, custom_tlvs.iter()); }, } Ok(()) } } +impl Writeable for OutboundTrampolinePayload { + fn write(&self, w: &mut W) -> Result<(), io::Error> { + match self { + Self::Forward { amt_to_forward, outgoing_cltv_value, outgoing_node_id } => { + _encode_varint_length_prefixed_tlv!(w, { + (2, HighZeroBytesDroppedBigSize(*amt_to_forward), required), + (4, HighZeroBytesDroppedBigSize(*outgoing_cltv_value), required), + (14, outgoing_node_id, required) + }); + } + } + Ok(()) + } +} + + impl ReadableArgs<(Option, &NS)> for InboundOnionPayload where NS::Target: NodeSigner { fn read(r: &mut R, args: (Option, &NS)) -> Result { let (update_add_blinding_point, node_signer) = args; @@ -2666,7 +2774,7 @@ impl ReadableArgs<(Option, &NS)> for InboundOnionPayload w }) }, ChaChaPolyReadAdapter { readable: BlindedPaymentTlvs::Receive(ReceiveTlvs { - payment_secret, payment_constraints + payment_secret, payment_constraints, payment_context })} => { if total_msat.unwrap_or(0) > MAX_VALUE_MSAT { return Err(DecodeError::InvalidValue) } Ok(Self::BlindedReceive { @@ -2675,8 +2783,10 @@ impl ReadableArgs<(Option, &NS)> for InboundOnionPayload w cltv_expiry_height: cltv_value.ok_or(DecodeError::InvalidValue)?, payment_secret, payment_constraints, + payment_context, intro_node_blinding_point, keysend_preimage, + custom_tlvs, }) }, } @@ -2789,13 +2899,13 @@ impl_writeable!(ChannelAnnouncement, { impl Writeable for UnsignedChannelUpdate { fn write(&self, w: &mut W) -> Result<(), io::Error> { - // `message_flags` used to indicate presence of `htlc_maximum_msat`, but was deprecated in the spec. - const MESSAGE_FLAGS: u8 = 1; self.chain_hash.write(w)?; self.short_channel_id.write(w)?; self.timestamp.write(w)?; - let all_flags = self.flags as u16 | ((MESSAGE_FLAGS as u16) << 8); - all_flags.write(w)?; + // The low bit of message_flags used to indicate the presence of `htlc_maximum_msat`, and + // now must be set + (self.message_flags | 1).write(w)?; + self.channel_flags.write(w)?; self.cltv_expiry_delta.write(w)?; self.htlc_minimum_msat.write(w)?; self.fee_base_msat.write(w)?; @@ -2808,22 +2918,26 @@ impl Writeable for UnsignedChannelUpdate { impl Readable for UnsignedChannelUpdate { fn read(r: &mut R) -> Result { - Ok(Self { + let res = Self { chain_hash: Readable::read(r)?, short_channel_id: Readable::read(r)?, timestamp: Readable::read(r)?, - flags: { - let flags: u16 = Readable::read(r)?; - // Note: we ignore the `message_flags` for now, since it was deprecated by the spec. - flags as u8 - }, + message_flags: Readable::read(r)?, + channel_flags: Readable::read(r)?, cltv_expiry_delta: Readable::read(r)?, htlc_minimum_msat: Readable::read(r)?, fee_base_msat: Readable::read(r)?, fee_proportional_millionths: Readable::read(r)?, htlc_maximum_msat: Readable::read(r)?, excess_data: read_to_end(r)?, - }) + }; + if res.message_flags & 1 != 1 { + // The `must_be_one` flag should be set (historically it indicated the presence of the + // `htlc_maximum_msat` field, which is now required). + Err(DecodeError::InvalidValue) + } else { + Ok(res) + } } } @@ -3117,26 +3231,25 @@ impl_writeable_msg!(GossipTimestampFilter, { #[cfg(test)] mod tests { - use std::convert::TryFrom; - use bitcoin::{Transaction, TxIn, ScriptBuf, Sequence, Witness, TxOut}; + use bitcoin::{Amount, Transaction, TxIn, ScriptBuf, Sequence, Witness, TxOut}; use hex::DisplayHex; - use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret}; - use crate::ln::ChannelId; + use crate::ln::types::{ChannelId, PaymentPreimage, PaymentHash, PaymentSecret}; use crate::ln::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures}; use crate::ln::msgs::{self, FinalOnionHopData, OnionErrorPacket, CommonOpenChannelFields, CommonAcceptChannelFields, TrampolineOnionPacket}; use crate::ln::msgs::SocketAddress; use crate::routing::gossip::{NodeAlias, NodeId}; - use crate::util::ser::{BigSize, Hostname, Readable, ReadableArgs, TransactionU16LenLimited, Writeable}; + use crate::util::ser::{BigSize, FixedLengthReader, Hostname, LengthReadable, Readable, ReadableArgs, TransactionU16LenLimited, Writeable}; use crate::util::test_utils; use bitcoin::hashes::hex::FromHex; use bitcoin::address::Address; - use bitcoin::network::constants::Network; + use bitcoin::network::Network; use bitcoin::blockdata::constants::ChainHash; use bitcoin::blockdata::script::Builder; use bitcoin::blockdata::opcodes; use bitcoin::hash_types::Txid; use bitcoin::locktime::absolute::LockTime; + use bitcoin::transaction::Version; use bitcoin::secp256k1::{PublicKey,SecretKey}; use bitcoin::secp256k1::{Secp256k1, Message}; @@ -3227,7 +3340,7 @@ mod tests { macro_rules! get_sig_on { ($privkey: expr, $ctx: expr, $string: expr) => { { - let sighash = Message::from_slice(&$string.into_bytes()[..]).unwrap(); + let sighash = Message::from_digest_slice(&$string.into_bytes()[..]).unwrap(); $ctx.sign_ecdsa(&sighash, &$privkey) } } @@ -3420,7 +3533,8 @@ mod tests { chain_hash: ChainHash::using_genesis_block(Network::Bitcoin), short_channel_id: 2316138423780173, timestamp: 20190119, - flags: if direction { 1 } else { 0 } | if disable { 1 << 1 } else { 0 }, + message_flags: 1, // Only must_be_one + channel_flags: if direction { 1 } else { 0 } | if disable { 1 << 1 } else { 0 }, cltv_expiry_delta: 144, htlc_minimum_msat: 1000000, htlc_maximum_msat: 131355275467161, @@ -3775,19 +3889,19 @@ mod tests { } #[test] - fn encoding_splice() { + fn encoding_splice_init() { let secp_ctx = Secp256k1::new(); let (_, pubkey_1,) = get_keys_from!("0101010101010101010101010101010101010101010101010101010101010101", secp_ctx); - let splice = msgs::Splice { - chain_hash: ChainHash::from_hex("6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000").unwrap(), + let splice_init = msgs::SpliceInit { channel_id: ChannelId::from_bytes([2; 32]), - relative_satoshis: 123456, + funding_contribution_satoshis: -123456, funding_feerate_perkw: 2000, locktime: 0, funding_pubkey: pubkey_1, + require_confirmed_inputs: Some(()), }; - let encoded_value = splice.encode(); - assert_eq!(encoded_value.as_hex().to_string(), "02020202020202020202020202020202020202020202020202020202020202026fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000000000000001e240000007d000000000031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f"); + let encoded_value = splice_init.encode(); + assert_eq!(encoded_value.as_hex().to_string(), "0202020202020202020202020202020202020202020202020202020202020202fffffffffffe1dc0000007d000000000031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f0200"); } #[test] @@ -3804,23 +3918,24 @@ mod tests { fn encoding_splice_ack() { let secp_ctx = Secp256k1::new(); let (_, pubkey_1,) = get_keys_from!("0101010101010101010101010101010101010101010101010101010101010101", secp_ctx); - let splice = msgs::SpliceAck { - chain_hash: ChainHash::from_hex("6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000").unwrap(), + let splice_ack = msgs::SpliceAck { channel_id: ChannelId::from_bytes([2; 32]), - relative_satoshis: 123456, + funding_contribution_satoshis: -123456, funding_pubkey: pubkey_1, + require_confirmed_inputs: Some(()), }; - let encoded_value = splice.encode(); - assert_eq!(encoded_value.as_hex().to_string(), "02020202020202020202020202020202020202020202020202020202020202026fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000000000000001e240031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f"); + let encoded_value = splice_ack.encode(); + assert_eq!(encoded_value.as_hex().to_string(), "0202020202020202020202020202020202020202020202020202020202020202fffffffffffe1dc0031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f0200"); } #[test] fn encoding_splice_locked() { - let splice = msgs::SpliceLocked { + let splice_locked = msgs::SpliceLocked { channel_id: ChannelId::from_bytes([2; 32]), + splice_txid: Txid::from_str("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap(), }; - let encoded_value = splice.encode(); - assert_eq!(encoded_value.as_hex().to_string(), "0202020202020202020202020202020202020202020202020202020202020202"); + let encoded_value = splice_locked.encode(); + assert_eq!(encoded_value.as_hex().to_string(), "02020202020202020202020202020202020202020202020202020202020202026e96fe9f8b0ddcd729ba03cfafa5a27b050b39d354dd980814268dfa9a44d4c2"); } #[test] @@ -3829,7 +3944,7 @@ mod tests { channel_id: ChannelId::from_bytes([2; 32]), serial_id: 4886718345, prevtx: TransactionU16LenLimited::new(Transaction { - version: 2, + version: Version::TWO, lock_time: LockTime::ZERO, input: vec![TxIn { previous_output: OutPoint { txid: Txid::from_str("305bab643ee297b8b6b76b320792c8223d55082122cb606bf89382146ced9c77").unwrap(), index: 2 }.into_bitcoin_outpoint(), @@ -3841,21 +3956,22 @@ mod tests { }], output: vec![ TxOut { - value: 12704566, - script_pubkey: Address::from_str("bc1qzlffunw52jav8vwdu5x3jfk6sr8u22rmq3xzw2").unwrap().payload.script_pubkey(), + value: Amount::from_sat(12704566), + script_pubkey: Address::from_str("bc1qzlffunw52jav8vwdu5x3jfk6sr8u22rmq3xzw2").unwrap().payload().script_pubkey(), }, TxOut { - value: 245148, - script_pubkey: Address::from_str("bc1qxmk834g5marzm227dgqvynd23y2nvt2ztwcw2z").unwrap().payload.script_pubkey(), + value: Amount::from_sat(245148), + script_pubkey: Address::from_str("bc1qxmk834g5marzm227dgqvynd23y2nvt2ztwcw2z").unwrap().payload().script_pubkey(), }, ], }).unwrap(), prevtx_out: 305419896, sequence: 305419896, + shared_input_txid: Some(Txid::from_str("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap()), }; let encoded_value = tx_add_input.encode(); - let target_value = >::from_hex("0202020202020202020202020202020202020202020202020202020202020202000000012345678900de02000000000101779ced6c148293f86b60cb222108553d22c89207326bb7b6b897e23e64ab5b300200000000fdffffff0236dbc1000000000016001417d29e4dd454bac3b1cde50d1926da80cfc5287b9cbd03000000000016001436ec78d514df462da95e6a00c24daa8915362d420247304402206af85b7dd67450ad12c979302fac49dfacbc6a8620f49c5da2b5721cf9565ca502207002b32fed9ce1bf095f57aeb10c36928ac60b12e723d97d2964a54640ceefa701210301ab7dc16488303549bfcdd80f6ae5ee4c20bf97ab5410bbd6b1bfa85dcd6944000000001234567812345678").unwrap(); - assert_eq!(encoded_value, target_value); + let target_value = "0202020202020202020202020202020202020202020202020202020202020202000000012345678900de02000000000101779ced6c148293f86b60cb222108553d22c89207326bb7b6b897e23e64ab5b300200000000fdffffff0236dbc1000000000016001417d29e4dd454bac3b1cde50d1926da80cfc5287b9cbd03000000000016001436ec78d514df462da95e6a00c24daa8915362d420247304402206af85b7dd67450ad12c979302fac49dfacbc6a8620f49c5da2b5721cf9565ca502207002b32fed9ce1bf095f57aeb10c36928ac60b12e723d97d2964a54640ceefa701210301ab7dc16488303549bfcdd80f6ae5ee4c20bf97ab5410bbd6b1bfa85dcd694400000000123456781234567800206e96fe9f8b0ddcd729ba03cfafa5a27b050b39d354dd980814268dfa9a44d4c2"; + assert_eq!(encoded_value.as_hex().to_string(), target_value); } #[test] @@ -3864,7 +3980,7 @@ mod tests { channel_id: ChannelId::from_bytes([2; 32]), serial_id: 4886718345, sats: 4886718345, - script: Address::from_str("bc1qxmk834g5marzm227dgqvynd23y2nvt2ztwcw2z").unwrap().payload.script_pubkey(), + script: Address::from_str("bc1qxmk834g5marzm227dgqvynd23y2nvt2ztwcw2z").unwrap().payload().script_pubkey(), }; let encoded_value = tx_add_output.encode(); let target_value = >::from_hex("0202020202020202020202020202020202020202020202020202020202020202000000012345678900000001234567890016001436ec78d514df462da95e6a00c24daa8915362d42").unwrap(); @@ -3905,6 +4021,10 @@ mod tests { #[test] fn encoding_tx_signatures() { + let secp_ctx = Secp256k1::new(); + let (privkey_1, _) = get_keys_from!("0101010101010101010101010101010101010101010101010101010101010101", secp_ctx); + let sig_1 = get_sig_on!(privkey_1, secp_ctx, String::from("01010101010101010101010101010101")); + let tx_signatures = msgs::TxSignatures { channel_id: ChannelId::from_bytes([2; 32]), tx_hash: Txid::from_str("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap(), @@ -3916,6 +4036,7 @@ mod tests { >::from_hex("3045022100ee00dbf4a862463e837d7c08509de814d620e4d9830fa84818713e0fa358f145022021c3c7060c4d53fe84fd165d60208451108a778c13b92ca4c6bad439236126cc01").unwrap(), >::from_hex("028fbbf0b16f5ba5bcb5dd37cd4047ce6f726a21c06682f9ec2f52b057de1dbdb5").unwrap()]), ], + shared_input_signature: Some(sig_1), }; let encoded_value = tx_signatures.encode(); let mut target_value = >::from_hex("0202020202020202020202020202020202020202020202020202020202020202").unwrap(); // channel_id @@ -3935,6 +4056,8 @@ mod tests { target_value.append(&mut >::from_hex("3045022100ee00dbf4a862463e837d7c08509de814d620e4d9830fa84818713e0fa358f145022021c3c7060c4d53fe84fd165d60208451108a778c13b92ca4c6bad439236126cc01").unwrap()); target_value.append(&mut >::from_hex("21").unwrap()); // len of witness element data (VarInt) target_value.append(&mut >::from_hex("028fbbf0b16f5ba5bcb5dd37cd4047ce6f726a21c06682f9ec2f52b057de1dbdb5").unwrap()); + target_value.append(&mut >::from_hex("0040").unwrap()); // type and len (64) + target_value.append(&mut >::from_hex("d977cb9b53d93a6ff64bb5f1e158b4094b66e798fb12911168a3ccdf80a83096340a6a95da0ae8d9f776528eecdbb747eb6b545495a4319ed5378e35b21e073a").unwrap()); assert_eq!(encoded_value, target_value); } @@ -4142,17 +4265,19 @@ mod tests { channel_id: ChannelId::from_bytes([2; 32]), signature: sig_1, htlc_signatures: if htlcs { vec![sig_2, sig_3, sig_4] } else { Vec::new() }, + batch: Some(msgs::CommitmentSignedBatch { batch_size: 3, funding_txid: Txid::from_str("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap() }), #[cfg(taproot)] partial_signature_with_nonce: None, }; let encoded_value = commitment_signed.encode(); - let mut target_value = >::from_hex("0202020202020202020202020202020202020202020202020202020202020202d977cb9b53d93a6ff64bb5f1e158b4094b66e798fb12911168a3ccdf80a83096340a6a95da0ae8d9f776528eecdbb747eb6b545495a4319ed5378e35b21e073a").unwrap(); + let mut target_value = "0202020202020202020202020202020202020202020202020202020202020202d977cb9b53d93a6ff64bb5f1e158b4094b66e798fb12911168a3ccdf80a83096340a6a95da0ae8d9f776528eecdbb747eb6b545495a4319ed5378e35b21e073a".to_string(); if htlcs { - target_value.append(&mut >::from_hex("00031735b6a427e80d5fe7cd90a2f4ee08dc9c27cda7c35a4172e5d85b12c49d4232537e98f9b1f3c5e6989a8b9644e90e8918127680dbd0d4043510840fc0f1e11a216c280b5395a2546e7e4b2663e04f811622f15a4f91e83aa2e92ba2a573c139142c54ae63072a1ec1ee7dc0c04bde5c847806172aa05c92c22ae8e308d1d2692b12cc195ce0a2d1bda6a88befa19fa07f51caa75ce83837f28965600b8aacab0855ffb0e741ec5f7c41421e9829a9d48611c8c831f71be5ea73e66594977ffd").unwrap()); + target_value += "00031735b6a427e80d5fe7cd90a2f4ee08dc9c27cda7c35a4172e5d85b12c49d4232537e98f9b1f3c5e6989a8b9644e90e8918127680dbd0d4043510840fc0f1e11a216c280b5395a2546e7e4b2663e04f811622f15a4f91e83aa2e92ba2a573c139142c54ae63072a1ec1ee7dc0c04bde5c847806172aa05c92c22ae8e308d1d2692b12cc195ce0a2d1bda6a88befa19fa07f51caa75ce83837f28965600b8aacab0855ffb0e741ec5f7c41421e9829a9d48611c8c831f71be5ea73e66594977ffd"; } else { - target_value.append(&mut >::from_hex("0000").unwrap()); + target_value += "0000"; } - assert_eq!(encoded_value, target_value); + target_value += "002200036e96fe9f8b0ddcd729ba03cfafa5a27b050b39d354dd980814268dfa9a44d4c2"; // batch + assert_eq!(encoded_value.as_hex().to_string(), target_value); } #[test] @@ -4297,7 +4422,7 @@ mod tests { keysend_preimage: None, sender_intended_htlc_amt_msat: 0x0badf00d01020304, cltv_expiry_height: 0xffffffff, - custom_tlvs: vec![], + custom_tlvs: &vec![], }; let encoded_value = outbound_msg.encode(); let target_value = >::from_hex("1002080badf00d010203040404ffffffff").unwrap(); @@ -4325,7 +4450,7 @@ mod tests { keysend_preimage: None, sender_intended_htlc_amt_msat: 0x0badf00d01020304, cltv_expiry_height: 0xffffffff, - custom_tlvs: vec![], + custom_tlvs: &vec![], }; let encoded_value = outbound_msg.encode(); let target_value = >::from_hex("3602080badf00d010203040404ffffffff082442424242424242424242424242424242424242424242424242424242424242421badca1f").unwrap(); @@ -4362,7 +4487,7 @@ mod tests { payment_data: None, payment_metadata: None, keysend_preimage: None, - custom_tlvs: bad_type_range_tlvs, + custom_tlvs: &bad_type_range_tlvs, sender_intended_htlc_amt_msat: 0x0badf00d01020304, cltv_expiry_height: 0xffffffff, }; @@ -4374,7 +4499,7 @@ mod tests { ((1 << 16) - 1, vec![42; 32]), ]; if let msgs::OutboundOnionPayload::Receive { ref mut custom_tlvs, .. } = msg { - *custom_tlvs = good_type_range_tlvs.clone(); + *custom_tlvs = &good_type_range_tlvs; } let encoded_value = msg.encode(); let inbound_msg = ReadableArgs::read(&mut Cursor::new(&encoded_value[..]), (None, &&node_signer)).unwrap(); @@ -4394,7 +4519,7 @@ mod tests { payment_data: None, payment_metadata: None, keysend_preimage: None, - custom_tlvs: expected_custom_tlvs.clone(), + custom_tlvs: &expected_custom_tlvs, sender_intended_htlc_amt_msat: 0x0badf00d01020304, cltv_expiry_height: 0xffffffff, }; @@ -4435,6 +4560,13 @@ mod tests { let encoded_trampoline_packet = trampoline_packet.encode(); assert_eq!(encoded_trampoline_packet.len(), 716); + { // verify that a codec round trip works + let mut reader = Cursor::new(&encoded_trampoline_packet); + let mut trampoline_packet_reader = FixedLengthReader::new(&mut reader, encoded_trampoline_packet.len() as u64); + let decoded_trampoline_packet: TrampolineOnionPacket = ::read(&mut trampoline_packet_reader).unwrap(); + assert_eq!(decoded_trampoline_packet.encode(), encoded_trampoline_packet); + } + let msg = msgs::OutboundOnionPayload::TrampolineEntrypoint { multipath_trampoline_data: None, amt_to_forward: 0x0badf00d01020304,