use bitcoin::blockdata::script::ScriptBuf;
use bitcoin::hash_types::Txid;
-use crate::blinded_path::payment::ReceiveTlvs;
+use crate::blinded_path::payment::{BlindedPaymentTlvs, ForwardTlvs, ReceiveTlvs};
use crate::ln::{ChannelId, PaymentPreimage, PaymentHash, PaymentSecret};
use crate::ln::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures};
use crate::ln::onion_utils;
use crate::io::{self, Cursor, Read};
use crate::io_extras::read_to_end;
-use crate::events::MessageSendEventsProvider;
+use crate::events::{EventsProvider, MessageSendEventsProvider};
use crate::util::chacha20poly1305rfc::ChaChaPolyReadAdapter;
use crate::util::logger;
use crate::util::ser::{LengthReadable, LengthReadableArgs, Readable, ReadableArgs, Writeable, Writer, WithoutLength, FixedLengthReader, HighZeroBytesDroppedBigSize, Hostname, TransactionU16LenLimited, BigSize};
}
/// A handler for received [`OnionMessage`]s and for providing generated ones to send.
-pub trait OnionMessageHandler {
+pub trait OnionMessageHandler: EventsProvider {
/// Handle an incoming `onion_message` message from the given peer.
fn handle_onion_message(&self, peer_node_id: &PublicKey, msg: &OnionMessage);
/// drop and refuse to forward onion messages to this peer.
fn peer_disconnected(&self, their_node_id: &PublicKey);
+ /// Performs actions that should happen roughly every ten seconds after startup. Allows handlers
+ /// to drop any buffered onion messages intended for prospective peers.
+ fn timer_tick_occurred(&self);
+
// Handler information:
/// Gets the node feature flags which this handler itself supports. All available handlers are
/// queried similarly and their feature flags are OR'd together to form the [`NodeFeatures`]
mod fuzzy_internal_msgs {
use bitcoin::secp256k1::PublicKey;
- use crate::blinded_path::payment::PaymentConstraints;
+ use crate::blinded_path::payment::{PaymentConstraints, PaymentRelay};
use crate::prelude::*;
use crate::ln::{PaymentPreimage, PaymentSecret};
+ use crate::ln::features::BlindedHopFeatures;
// These types aren't intended to be pub, but are exposed for direct fuzzing (as we deserialize
// them from untrusted input):
amt_msat: u64,
outgoing_cltv_value: u32,
},
+ BlindedForward {
+ short_channel_id: u64,
+ payment_relay: PaymentRelay,
+ payment_constraints: PaymentConstraints,
+ features: BlindedHopFeatures,
+ intro_node_blinding_point: PublicKey,
+ },
BlindedReceive {
amt_msat: u64,
total_msat: u64,
outgoing_cltv_value: u32,
payment_secret: PaymentSecret,
payment_constraints: PaymentConstraints,
- intro_node_blinding_point: PublicKey,
+ intro_node_blinding_point: Option<PublicKey>,
}
}
}
}
-impl<NS: Deref> ReadableArgs<&NS> for InboundOnionPayload where NS::Target: NodeSigner {
- fn read<R: Read>(r: &mut R, node_signer: &NS) -> Result<Self, DecodeError> {
+impl<NS: Deref> ReadableArgs<(Option<PublicKey>, &NS)> for InboundOnionPayload where NS::Target: NodeSigner {
+ fn read<R: Read>(r: &mut R, args: (Option<PublicKey>, &NS)) -> Result<Self, DecodeError> {
+ let (update_add_blinding_point, node_signer) = args;
+
let mut amt = None;
let mut cltv_value = None;
let mut short_id: Option<u64> = None;
});
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 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() {
return Err(DecodeError::InvalidValue)
}
let mut s = Cursor::new(&enc_tlvs);
let mut reader = FixedLengthReader::new(&mut s, enc_tlvs.len() as u64);
match ChaChaPolyReadAdapter::read(&mut reader, rho)? {
- ChaChaPolyReadAdapter { readable: ReceiveTlvs { payment_secret, payment_constraints }} => {
+ ChaChaPolyReadAdapter { readable: BlindedPaymentTlvs::Forward(ForwardTlvs {
+ short_channel_id, payment_relay, payment_constraints, features
+ })} => {
+ if amt.is_some() || cltv_value.is_some() || total_msat.is_some() {
+ return Err(DecodeError::InvalidValue)
+ }
+ Ok(Self::BlindedForward {
+ short_channel_id,
+ payment_relay,
+ payment_constraints,
+ features,
+ intro_node_blinding_point: intro_node_blinding_point.ok_or(DecodeError::InvalidValue)?,
+ })
+ },
+ ChaChaPolyReadAdapter { readable: BlindedPaymentTlvs::Receive(ReceiveTlvs {
+ payment_secret, payment_constraints
+ })} => {
if total_msat.unwrap_or(0) > MAX_VALUE_MSAT { return Err(DecodeError::InvalidValue) }
Ok(Self::BlindedReceive {
amt_msat: amt.ok_or(DecodeError::InvalidValue)?,
outgoing_cltv_value: cltv_value.ok_or(DecodeError::InvalidValue)?,
payment_secret,
payment_constraints,
- intro_node_blinding_point: blinding_point,
+ intro_node_blinding_point,
})
},
}
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 {
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 {
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,
};
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]),
*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!(),
let target_value = <Vec<u8>>::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,
let mut rd = Cursor::new(&big_payload[..]);
let node_signer = test_utils::TestKeysInterface::new(&[42; 32], Network::Testnet);
- <msgs::InboundOnionPayload as ReadableArgs<&&test_utils::TestKeysInterface>>
- ::read(&mut rd, &&node_signer).unwrap();
+ <msgs::InboundOnionPayload as ReadableArgs<(Option<PublicKey>, &&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<Vec<u8>, io::Error> {