use crate::io_extras::read_to_end;
use crate::events::{EventsProvider, MessageSendEventsProvider};
-use crate::util::chacha20poly1305rfc::ChaChaPolyReadAdapter;
+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::base32;
/// Used in decrypting the onion packet's payload.
pub blinding_point: PublicKey,
/// The full onion packet including hop data, pubkey, and hmac
- pub onion_routing_packet: onion_message::Packet,
+ pub onion_routing_packet: onion_message::packet::Packet,
}
/// An [`update_fulfill_htlc`] message to be sent to or received from a peer.
}
/// Represents the set of gossip messages that require a signature from a node's identity key.
-pub enum UnsignedGossipMessage<'a> {
+#[derive(Clone)]
+pub enum UnsignedGossipMessage {
/// An unsigned channel announcement.
- ChannelAnnouncement(&'a UnsignedChannelAnnouncement),
+ ChannelAnnouncement(UnsignedChannelAnnouncement),
/// An unsigned channel update.
- ChannelUpdate(&'a UnsignedChannelUpdate),
+ ChannelUpdate(UnsignedChannelUpdate),
/// An unsigned node announcement.
- NodeAnnouncement(&'a UnsignedNodeAnnouncement)
+ NodeAnnouncement(UnsignedNodeAnnouncement)
}
-impl<'a> Writeable for UnsignedGossipMessage<'a> {
+impl Writeable for UnsignedGossipMessage {
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
match self {
UnsignedGossipMessage::ChannelAnnouncement(ref msg) => msg.write(writer),
}
/// A handler for received [`OnionMessage`]s and for providing generated ones to send.
-pub trait OnionMessageHandler: EventsProvider {
+pub trait OnionMessageHandler {
+ /// Because much of the lightning network does not yet support forwarding onion messages, we
+ /// may need to directly connect to a node which will forward a message for us. In such a case,
+ /// this method will return the set of nodes which need connection by node_id and the
+ /// corresponding socket addresses where they may accept incoming connections.
+ ///
+ /// Thus, this method should be polled regularly to detect messages await such a direct
+ /// connection.
+ fn get_and_clear_connections_needed(&self) -> Vec<(PublicKey, Vec<SocketAddress>)>;
+
/// Handle an incoming `onion_message` message from the given peer.
fn handle_onion_message(&self, peer_node_id: &PublicKey, msg: &OnionMessage);
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 {
payment_metadata: Option<Vec<u8>>,
keysend_preimage: Option<PaymentPreimage>,
custom_tlvs: Vec<(u64, Vec<u8>)>,
- amt_msat: u64,
- outgoing_cltv_value: u32,
+ sender_intended_htlc_amt_msat: u64,
+ cltv_expiry_height: u32,
},
BlindedForward {
short_channel_id: u64,
payment_relay: PaymentRelay,
payment_constraints: PaymentConstraints,
features: BlindedHopFeatures,
- intro_node_blinding_point: PublicKey,
+ intro_node_blinding_point: Option<PublicKey>,
},
BlindedReceive {
- amt_msat: u64,
+ sender_intended_htlc_amt_msat: u64,
total_msat: u64,
- outgoing_cltv_value: u32,
+ cltv_expiry_height: u32,
payment_secret: PaymentSecret,
payment_constraints: PaymentConstraints,
- intro_node_blinding_point: PublicKey,
+ intro_node_blinding_point: Option<PublicKey>,
}
}
payment_metadata: Option<Vec<u8>>,
keysend_preimage: Option<PaymentPreimage>,
custom_tlvs: Vec<(u64, Vec<u8>)>,
- amt_msat: u64,
- outgoing_cltv_value: u32,
+ sender_intended_htlc_amt_msat: u64,
+ cltv_expiry_height: u32,
},
BlindedForward {
encrypted_tlvs: Vec<u8>,
intro_node_blinding_point: Option<PublicKey>,
},
BlindedReceive {
- amt_msat: u64,
+ sender_intended_htlc_amt_msat: u64,
total_msat: u64,
- outgoing_cltv_value: u32,
+ cltv_expiry_height: u32,
encrypted_tlvs: Vec<u8>,
intro_node_blinding_point: Option<PublicKey>, // Set if the introduction node of the blinded path is the final node
}
let blinding_point: PublicKey = Readable::read(r)?;
let len: u16 = Readable::read(r)?;
let mut packet_reader = FixedLengthReader::new(r, len as u64);
- let onion_routing_packet: onion_message::Packet = <onion_message::Packet as LengthReadable>::read(&mut packet_reader)?;
+ let onion_routing_packet: onion_message::packet::Packet =
+ <onion_message::packet::Packet as LengthReadable>::read(&mut packet_reader)?;
Ok(Self {
blinding_point,
onion_routing_packet,
});
},
Self::Receive {
- ref payment_data, ref payment_metadata, ref keysend_preimage, amt_msat,
- outgoing_cltv_value, ref custom_tlvs,
+ ref payment_data, ref payment_metadata, ref keysend_preimage, sender_intended_htlc_amt_msat,
+ cltv_expiry_height, 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
let mut custom_tlvs: Vec<&(u64, Vec<u8>)> = custom_tlvs.iter().chain(keysend_tlv.iter()).collect();
custom_tlvs.sort_unstable_by_key(|(typ, _)| *typ);
_encode_varint_length_prefixed_tlv!(w, {
- (2, HighZeroBytesDroppedBigSize(*amt_msat), required),
- (4, HighZeroBytesDroppedBigSize(*outgoing_cltv_value), required),
+ (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)
}, custom_tlvs.iter());
});
},
Self::BlindedReceive {
- amt_msat, total_msat, outgoing_cltv_value, encrypted_tlvs,
+ sender_intended_htlc_amt_msat, total_msat, cltv_expiry_height, encrypted_tlvs,
intro_node_blinding_point,
} => {
_encode_varint_length_prefixed_tlv!(w, {
- (2, HighZeroBytesDroppedBigSize(*amt_msat), required),
- (4, HighZeroBytesDroppedBigSize(*outgoing_cltv_value), required),
+ (2, HighZeroBytesDroppedBigSize(*sender_intended_htlc_amt_msat), required),
+ (4, HighZeroBytesDroppedBigSize(*cltv_expiry_height), required),
(10, *encrypted_tlvs, required_vec),
(12, intro_node_blinding_point, option),
(18, HighZeroBytesDroppedBigSize(*total_msat), required)
});
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;
payment_relay,
payment_constraints,
features,
- intro_node_blinding_point: blinding_point,
+ intro_node_blinding_point,
})
},
ChaChaPolyReadAdapter { readable: BlindedPaymentTlvs::Receive(ReceiveTlvs {
})} => {
if total_msat.unwrap_or(0) > MAX_VALUE_MSAT { return Err(DecodeError::InvalidValue) }
Ok(Self::BlindedReceive {
- amt_msat: amt.ok_or(DecodeError::InvalidValue)?,
+ sender_intended_htlc_amt_msat: amt.ok_or(DecodeError::InvalidValue)?,
total_msat: total_msat.ok_or(DecodeError::InvalidValue)?,
- outgoing_cltv_value: cltv_value.ok_or(DecodeError::InvalidValue)?,
+ cltv_expiry_height: cltv_value.ok_or(DecodeError::InvalidValue)?,
payment_secret,
payment_constraints,
- intro_node_blinding_point: blinding_point,
+ intro_node_blinding_point,
})
},
}
payment_data,
payment_metadata: payment_metadata.map(|w| w.0),
keysend_preimage,
- amt_msat: amt.ok_or(DecodeError::InvalidValue)?,
- outgoing_cltv_value: cltv_value.ok_or(DecodeError::InvalidValue)?,
+ sender_intended_htlc_amt_msat: amt.ok_or(DecodeError::InvalidValue)?,
+ cltv_expiry_height: cltv_value.ok_or(DecodeError::InvalidValue)?,
custom_tlvs,
})
}
payment_data: None,
payment_metadata: None,
keysend_preimage: None,
- amt_msat: 0x0badf00d01020304,
- outgoing_cltv_value: 0xffffffff,
+ sender_intended_htlc_amt_msat: 0x0badf00d01020304,
+ cltv_expiry_height: 0xffffffff,
custom_tlvs: vec![],
};
let encoded_value = outbound_msg.encode();
let node_signer = test_utils::TestKeysInterface::new(&[42; 32], Network::Testnet);
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, ..
+ payment_data: None, sender_intended_htlc_amt_msat, cltv_expiry_height, ..
} = inbound_msg {
- assert_eq!(amt_msat, 0x0badf00d01020304);
- assert_eq!(outgoing_cltv_value, 0xffffffff);
+ assert_eq!(sender_intended_htlc_amt_msat, 0x0badf00d01020304);
+ assert_eq!(cltv_expiry_height, 0xffffffff);
} else { panic!(); }
}
}),
payment_metadata: None,
keysend_preimage: None,
- amt_msat: 0x0badf00d01020304,
- outgoing_cltv_value: 0xffffffff,
+ sender_intended_htlc_amt_msat: 0x0badf00d01020304,
+ cltv_expiry_height: 0xffffffff,
custom_tlvs: vec![],
};
let encoded_value = outbound_msg.encode();
payment_secret,
total_msat: 0x1badca1f
}),
- amt_msat, outgoing_cltv_value,
+ sender_intended_htlc_amt_msat, cltv_expiry_height,
payment_metadata: None,
keysend_preimage: None,
custom_tlvs,
} = inbound_msg {
assert_eq!(payment_secret, expected_payment_secret);
- assert_eq!(amt_msat, 0x0badf00d01020304);
- assert_eq!(outgoing_cltv_value, 0xffffffff);
+ assert_eq!(sender_intended_htlc_amt_msat, 0x0badf00d01020304);
+ assert_eq!(cltv_expiry_height, 0xffffffff);
assert_eq!(custom_tlvs, vec![]);
} else { panic!(); }
}
payment_metadata: None,
keysend_preimage: None,
custom_tlvs: bad_type_range_tlvs,
- amt_msat: 0x0badf00d01020304,
- outgoing_cltv_value: 0xffffffff,
+ sender_intended_htlc_amt_msat: 0x0badf00d01020304,
+ cltv_expiry_height: 0xffffffff,
};
let encoded_value = msg.encode();
let node_signer = test_utils::TestKeysInterface::new(&[42; 32], Network::Testnet);
payment_metadata: None,
keysend_preimage: None,
custom_tlvs: expected_custom_tlvs.clone(),
- amt_msat: 0x0badf00d01020304,
- outgoing_cltv_value: 0xffffffff,
+ sender_intended_htlc_amt_msat: 0x0badf00d01020304,
+ cltv_expiry_height: 0xffffffff,
};
let encoded_value = msg.encode();
let target_value = <Vec<u8>>::from_hex("2e02080badf00d010203040404ffffffffff0000000146c6616b021234ff0000000146c6616f084242424242424242").unwrap();
payment_metadata: None,
keysend_preimage: None,
custom_tlvs,
- amt_msat,
- outgoing_cltv_value,
+ sender_intended_htlc_amt_msat,
+ cltv_expiry_height: outgoing_cltv_value,
..
} = inbound_msg {
assert_eq!(custom_tlvs, expected_custom_tlvs);
- assert_eq!(amt_msat, 0x0badf00d01020304);
+ assert_eq!(sender_intended_htlc_amt_msat, 0x0badf00d01020304);
assert_eq!(outgoing_cltv_value, 0xffffffff);
} else { panic!(); }
}