X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fmsgs.rs;h=2e56e2fc2c0c95d2e3cb3380d1f8b50138404ead;hb=be134d11c93eaaf594c8ccb35f3d1a8bcff753aa;hp=b877565e01725bf37e402ddd8ed5985418d982e3;hpb=cfaa7f3617947d25e74fb4fcaad20c442ffd602e;p=rust-lightning diff --git a/lightning/src/ln/msgs.rs b/lightning/src/ln/msgs.rs index b877565e..2e56e2fc 100644 --- a/lightning/src/ln/msgs.rs +++ b/lightning/src/ln/msgs.rs @@ -1668,22 +1668,31 @@ pub trait OnionMessageHandler: EventsProvider { fn provided_init_features(&self, their_node_id: &PublicKey) -> InitFeatures; } +#[derive(Clone)] +#[cfg_attr(test, derive(Debug, PartialEq))] +/// Information communicated in the onion to the recipient for multi-part tracking and proof that +/// the payment is associated with an invoice. +pub struct FinalOnionHopData { + /// When sending a multi-part payment, this secret is used to identify a payment across HTLCs. + /// Because it is generated by the recipient and included in the invoice, it also provides + /// proof to the recipient that the payment was sent by someone with the generated invoice. + pub payment_secret: PaymentSecret, + /// The intended total amount that this payment is for. + /// + /// Message serialization may panic if this value is more than 21 million Bitcoin. + pub total_msat: u64, +} + 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::ln::features::BlindedHopFeatures; + use super::FinalOnionHopData; // These types aren't intended to be pub, but are exposed for direct fuzzing (as we deserialize // them from untrusted input): - #[derive(Clone)] - pub struct FinalOnionHopData { - pub payment_secret: PaymentSecret, - /// The total value, in msat, of the payment as received by the ultimate recipient. - /// Message serialization may panic if this value is more than 21 million Bitcoin. - pub total_msat: u64, - } pub enum InboundOnionPayload { Forward { @@ -1713,7 +1722,7 @@ mod fuzzy_internal_msgs { outgoing_cltv_value: u32, payment_secret: PaymentSecret, payment_constraints: PaymentConstraints, - intro_node_blinding_point: PublicKey, + intro_node_blinding_point: Option, } } @@ -2319,8 +2328,10 @@ impl Writeable for OutboundOnionPayload { } } -impl ReadableArgs<&NS> for InboundOnionPayload where NS::Target: NodeSigner { - fn read(r: &mut R, node_signer: &NS) -> Result { +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; + let mut amt = None; let mut cltv_value = None; let mut short_id: Option = None; @@ -2354,9 +2365,14 @@ impl ReadableArgs<&NS> for InboundOnionPayload where NS::Target: Node }); if amt.unwrap_or(0) > MAX_VALUE_MSAT { return Err(DecodeError::InvalidValue) } + if intro_node_blinding_point.is_some() && update_add_blinding_point.is_some() { + return Err(DecodeError::InvalidValue) + } - if let Some(blinding_point) = intro_node_blinding_point { - if short_id.is_some() || payment_data.is_some() || payment_metadata.is_some() { + if let Some(blinding_point) = intro_node_blinding_point.or(update_add_blinding_point) { + if short_id.is_some() || payment_data.is_some() || payment_metadata.is_some() || + keysend_preimage.is_some() + { return Err(DecodeError::InvalidValue) } let enc_tlvs = encrypted_tlvs_opt.ok_or(DecodeError::InvalidValue)?.0; @@ -2377,7 +2393,7 @@ impl ReadableArgs<&NS> for InboundOnionPayload where NS::Target: Node payment_relay, payment_constraints, features, - intro_node_blinding_point: blinding_point, + intro_node_blinding_point: intro_node_blinding_point.ok_or(DecodeError::InvalidValue)?, }) }, ChaChaPolyReadAdapter { readable: BlindedPaymentTlvs::Receive(ReceiveTlvs { @@ -2390,7 +2406,7 @@ impl ReadableArgs<&NS> for InboundOnionPayload where NS::Target: Node outgoing_cltv_value: cltv_value.ok_or(DecodeError::InvalidValue)?, payment_secret, payment_constraints, - intro_node_blinding_point: blinding_point, + intro_node_blinding_point, }) }, } @@ -3987,7 +4003,7 @@ mod tests { assert_eq!(encoded_value, target_value); let node_signer = test_utils::TestKeysInterface::new(&[42; 32], Network::Testnet); - let inbound_msg = ReadableArgs::read(&mut Cursor::new(&target_value[..]), &&node_signer).unwrap(); + let inbound_msg = ReadableArgs::read(&mut Cursor::new(&target_value[..]), (None, &&node_signer)).unwrap(); if let msgs::InboundOnionPayload::Forward { short_channel_id, amt_to_forward, outgoing_cltv_value } = inbound_msg { @@ -4012,7 +4028,7 @@ mod tests { assert_eq!(encoded_value, target_value); let node_signer = test_utils::TestKeysInterface::new(&[42; 32], Network::Testnet); - let inbound_msg = ReadableArgs::read(&mut Cursor::new(&target_value[..]), &&node_signer).unwrap(); + let inbound_msg = ReadableArgs::read(&mut Cursor::new(&target_value[..]), (None, &&node_signer)).unwrap(); if let msgs::InboundOnionPayload::Receive { payment_data: None, amt_msat, outgoing_cltv_value, .. } = inbound_msg { @@ -4040,7 +4056,7 @@ mod tests { assert_eq!(encoded_value, target_value); let node_signer = test_utils::TestKeysInterface::new(&[42; 32], Network::Testnet); - let inbound_msg = ReadableArgs::read(&mut Cursor::new(&target_value[..]), &&node_signer).unwrap(); + let inbound_msg = ReadableArgs::read(&mut Cursor::new(&target_value[..]), (None, &&node_signer)).unwrap(); if let msgs::InboundOnionPayload::Receive { payment_data: Some(FinalOnionHopData { payment_secret, @@ -4076,7 +4092,7 @@ mod tests { }; let encoded_value = msg.encode(); let node_signer = test_utils::TestKeysInterface::new(&[42; 32], Network::Testnet); - assert!(msgs::InboundOnionPayload::read(&mut Cursor::new(&encoded_value[..]), &&node_signer).is_err()); + assert!(msgs::InboundOnionPayload::read(&mut Cursor::new(&encoded_value[..]), (None, &&node_signer)).is_err()); let good_type_range_tlvs = vec![ ((1 << 16) - 3, vec![42]), ((1 << 16) - 1, vec![42; 32]), @@ -4085,7 +4101,7 @@ mod tests { *custom_tlvs = good_type_range_tlvs.clone(); } let encoded_value = msg.encode(); - let inbound_msg = ReadableArgs::read(&mut Cursor::new(&encoded_value[..]), &&node_signer).unwrap(); + let inbound_msg = ReadableArgs::read(&mut Cursor::new(&encoded_value[..]), (None, &&node_signer)).unwrap(); match inbound_msg { msgs::InboundOnionPayload::Receive { custom_tlvs, .. } => assert!(custom_tlvs.is_empty()), _ => panic!(), @@ -4110,7 +4126,7 @@ mod tests { let target_value = >::from_hex("2e02080badf00d010203040404ffffffffff0000000146c6616b021234ff0000000146c6616f084242424242424242").unwrap(); assert_eq!(encoded_value, target_value); let node_signer = test_utils::TestKeysInterface::new(&[42; 32], Network::Testnet); - let inbound_msg: msgs::InboundOnionPayload = ReadableArgs::read(&mut Cursor::new(&target_value[..]), &&node_signer).unwrap(); + let inbound_msg: msgs::InboundOnionPayload = ReadableArgs::read(&mut Cursor::new(&target_value[..]), (None, &&node_signer)).unwrap(); if let msgs::InboundOnionPayload::Receive { payment_data: None, payment_metadata: None, @@ -4275,8 +4291,8 @@ mod tests { let mut rd = Cursor::new(&big_payload[..]); let node_signer = test_utils::TestKeysInterface::new(&[42; 32], Network::Testnet); - > - ::read(&mut rd, &&node_signer).unwrap(); + , &&test_utils::TestKeysInterface)>> + ::read(&mut rd, (None, &&node_signer)).unwrap(); } // see above test, needs to be a separate method for use of the serialization macros. fn encode_big_payload() -> Result, io::Error> {