diff --git a/fuzz/src/onion_message.rs b/fuzz/src/onion_message.rs index 5fb2122ced4..d323ecb21fb 100644 --- a/fuzz/src/onion_message.rs +++ b/fuzz/src/onion_message.rs @@ -11,7 +11,7 @@ use lightning::ln::script::ShutdownScript; use lightning::util::enforcing_trait_impls::EnforcingSigner; use lightning::util::logger::Logger; use lightning::util::ser::{Readable, Writeable, Writer}; -use lightning::onion_message::{CustomOnionMessageContents, CustomOnionMessageHandler, OnionMessenger}; +use lightning::onion_message::{CustomOnionMessageContents, CustomOnionMessageHandler, Destination, MessageRouter, OffersMessage, OffersMessageHandler, OnionMessagePath, OnionMessenger}; use crate::utils::test_logger; @@ -22,15 +22,20 @@ use std::sync::atomic::{AtomicU64, Ordering}; /// Actual fuzz test, method signature and name are fixed pub fn do_test(data: &[u8], logger: &L) { if let Ok(msg) = ::read(&mut Cursor::new(data)) { - let mut secret_bytes = [0; 32]; + let mut secret_bytes = [1; 32]; secret_bytes[31] = 2; let secret = SecretKey::from_slice(&secret_bytes).unwrap(); let keys_manager = KeyProvider { node_secret: secret, counter: AtomicU64::new(0), }; + let message_router = TestMessageRouter {}; + let offers_msg_handler = TestOffersMessageHandler {}; let custom_msg_handler = TestCustomMessageHandler {}; - let onion_messenger = OnionMessenger::new(&keys_manager, &keys_manager, logger, &custom_msg_handler); + let onion_messenger = OnionMessenger::new( + &keys_manager, &keys_manager, logger, &message_router, &offers_msg_handler, + &custom_msg_handler + ); let mut pk = [2; 33]; pk[1] = 0xff; let peer_node_id_not_used = PublicKey::from_slice(&pk).unwrap(); onion_messenger.handle_onion_message(&peer_node_id_not_used, &msg); @@ -50,6 +55,27 @@ pub extern "C" fn onion_message_run(data: *const u8, datalen: usize) { do_test(unsafe { std::slice::from_raw_parts(data, datalen) }, &logger); } +struct TestMessageRouter {} + +impl MessageRouter for TestMessageRouter { + fn find_path( + &self, _sender: PublicKey, _peers: Vec, destination: Destination + ) -> Result { + Ok(OnionMessagePath { + intermediate_nodes: vec![], + destination, + }) + } +} + +struct TestOffersMessageHandler {} + +impl OffersMessageHandler for TestOffersMessageHandler { + fn handle_message(&self, _message: OffersMessage) -> Option { + None + } +} + struct TestCustomMessage {} const CUSTOM_MESSAGE_TYPE: u64 = 4242; @@ -71,7 +97,9 @@ struct TestCustomMessageHandler {} impl CustomOnionMessageHandler for TestCustomMessageHandler { type CustomMessage = TestCustomMessage; - fn handle_custom_message(&self, _msg: Self::CustomMessage) {} + fn handle_custom_message(&self, _msg: Self::CustomMessage) -> Option { + Some(TestCustomMessage {}) + } fn read_custom_message(&self, _message_type: u64, buffer: &mut R) -> Result, msgs::DecodeError> { let mut buf = Vec::new(); buffer.read_to_end(&mut buf)?; @@ -165,37 +193,41 @@ mod tests { #[test] fn test_no_onion_message_breakage() { - let one_hop_om = "020000000000000000000000000000000000000000000000000000000000000e01055600020000000000000000000000000000000000000000000000000000000000000e0136041095000000000000000000000000000000fd1092202a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000"; + let one_hop_om = "020000000000000000000000000000000000000000000000000000000000000e01055600020000000000000000000000000000000000000000000000000000000000000e01ae0276020000000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000000000000000000000e0101022a0000000000000000000000000000014551231950b75fc4402da1732fc9bebf00109500000000000000000000000000000004106d000000000000000000000000000000fd1092202a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005600000000000000000000000000000000000000000000000000000000000000"; let logger = TrackingLogger { lines: Mutex::new(HashMap::new()) }; super::do_test(&::hex::decode(one_hop_om).unwrap(), &logger); { let log_entries = logger.lines.lock().unwrap(); assert_eq!(log_entries.get(&("lightning::onion_message::messenger".to_string(), - "Received an onion message with path_id None and no reply_path".to_string())), Some(&1)); + "Received an onion message with path_id None and a reply_path".to_string())), Some(&1)); + assert_eq!(log_entries.get(&("lightning::onion_message::messenger".to_string(), + "Responding to onion message with path_id None".to_string())), Some(&1)); + assert_eq!(log_entries.get(&("lightning::onion_message::messenger".to_string(), + "Failed responding to onion message with path_id None: TooFewBlindedHops".to_string())), Some(&1)); } - let two_unblinded_hops_om = "020000000000000000000000000000000000000000000000000000000000000e01055600020000000000000000000000000000000000000000000000000000000000000e0135043304210200000000000000000000000000000000000000000000000000000000000000029500000000000000000000000000000036000000000000000000000000000000000000000000000000000000000000003604104b000000000000000000000000000000fd1092202a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b200000000000000000000000000000000000000000000000000000000000000"; + let two_unblinded_hops_om = "020000000000000000000000000000000000000000000000000000000000000e01055600020000000000000000000000000000000000000000000000000000000000000e0135043304210202020202020202020202020202020202020202020202020202020202020202026d000000000000000000000000000000eb0000000000000000000000000000000000000000000000000000000000000036041096000000000000000000000000000000fd1092202a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000"; let logger = TrackingLogger { lines: Mutex::new(HashMap::new()) }; super::do_test(&::hex::decode(two_unblinded_hops_om).unwrap(), &logger); { let log_entries = logger.lines.lock().unwrap(); - assert_eq!(log_entries.get(&("lightning::onion_message::messenger".to_string(), "Forwarding an onion message to peer 020000000000000000000000000000000000000000000000000000000000000002".to_string())), Some(&1)); + assert_eq!(log_entries.get(&("lightning::onion_message::messenger".to_string(), "Forwarding an onion message to peer 020202020202020202020202020202020202020202020202020202020202020202".to_string())), Some(&1)); } - let two_unblinded_two_blinded_om = "020000000000000000000000000000000000000000000000000000000000000e01055600020000000000000000000000000000000000000000000000000000000000000e01350433042102000000000000000000000000000000000000000000000000000000000000000295000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000058045604210200000000000000000000000000000000000000000000000000000000000000020821020000000000000000000000000000000000000000000000000000000000000e014b000000000000000000000000000000b20000000000000000000000000000000000000000000000000000000000000035043304210200000000000000000000000000000000000000000000000000000000000000029500000000000000000000000000000036000000000000000000000000000000000000000000000000000000000000003604104b000000000000000000000000000000fd1092202a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b200000000000000000000000000000000000000000000000000000000000000"; + let two_unblinded_two_blinded_om = "020000000000000000000000000000000000000000000000000000000000000e01055600020000000000000000000000000000000000000000000000000000000000000e0135043304210202020202020202020202020202020202020202020202020202020202020202026d0000000000000000000000000000009e0000000000000000000000000000000000000000000000000000000000000058045604210203030303030303030303030303030303030303030303030303030303030303020821020000000000000000000000000000000000000000000000000000000000000e0196000000000000000000000000000000e9000000000000000000000000000000000000000000000000000000000000003504330421020404040404040404040404040404040404040404040404040404040404040402ca00000000000000000000000000000042000000000000000000000000000000000000000000000000000000000000003604103f000000000000000000000000000000fd1092202a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000"; let logger = TrackingLogger { lines: Mutex::new(HashMap::new()) }; super::do_test(&::hex::decode(two_unblinded_two_blinded_om).unwrap(), &logger); { let log_entries = logger.lines.lock().unwrap(); - assert_eq!(log_entries.get(&("lightning::onion_message::messenger".to_string(), "Forwarding an onion message to peer 020000000000000000000000000000000000000000000000000000000000000002".to_string())), Some(&1)); + assert_eq!(log_entries.get(&("lightning::onion_message::messenger".to_string(), "Forwarding an onion message to peer 020202020202020202020202020202020202020202020202020202020202020202".to_string())), Some(&1)); } - let three_blinded_om = "020000000000000000000000000000000000000000000000000000000000000e01055600020000000000000000000000000000000000000000000000000000000000000e013504330421020000000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000006c0000000000000000000000000000000000000000000000000000000000000035043304210200000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000ac00000000000000000000000000000000000000000000000000000000000000360410d1000000000000000000000000000000fd1092202a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b200000000000000000000000000000000000000000000000000000000000000"; + let three_blinded_om = "020000000000000000000000000000000000000000000000000000000000000e01055600020000000000000000000000000000000000000000000000000000000000000e0135043304210202020202020202020202020202020202020202020202020202020202020202026d000000000000000000000000000000b20000000000000000000000000000000000000000000000000000000000000035043304210203030303030303030303030303030303030303030303030303030303030303029600000000000000000000000000000033000000000000000000000000000000000000000000000000000000000000003604104e000000000000000000000000000000fd1092202a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000"; let logger = TrackingLogger { lines: Mutex::new(HashMap::new()) }; super::do_test(&::hex::decode(three_blinded_om).unwrap(), &logger); { let log_entries = logger.lines.lock().unwrap(); - assert_eq!(log_entries.get(&("lightning::onion_message::messenger".to_string(), "Forwarding an onion message to peer 020000000000000000000000000000000000000000000000000000000000000002".to_string())), Some(&1)); + assert_eq!(log_entries.get(&("lightning::onion_message::messenger".to_string(), "Forwarding an onion message to peer 020202020202020202020202020202020202020202020202020202020202020202".to_string())), Some(&1)); } } } diff --git a/lightning-background-processor/src/lib.rs b/lightning-background-processor/src/lib.rs index 248f79dd59e..0cfa9801bad 100644 --- a/lightning-background-processor/src/lib.rs +++ b/lightning-background-processor/src/lib.rs @@ -519,8 +519,9 @@ use core::task; /// # type MyUtxoLookup = dyn lightning::routing::utxo::UtxoLookup + Send + Sync; /// # type MyFilter = dyn lightning::chain::Filter + Send + Sync; /// # type MyLogger = dyn lightning::util::logger::Logger + Send + Sync; +/// # type MyMessageRouter = dyn lightning::onion_message::MessageRouter + Send + Sync; /// # type MyChainMonitor = lightning::chain::chainmonitor::ChainMonitor, Arc, Arc, Arc, Arc>; -/// # type MyPeerManager = lightning::ln::peer_handler::SimpleArcPeerManager; +/// # type MyPeerManager = lightning::ln::peer_handler::SimpleArcPeerManager; /// # type MyNetworkGraph = lightning::routing::gossip::NetworkGraph>; /// # type MyGossipSync = lightning::routing::gossip::P2PGossipSync, Arc, Arc>; /// # type MyChannelManager = lightning::ln::channelmanager::SimpleArcChannelManager; diff --git a/lightning/src/ln/peer_handler.rs b/lightning/src/ln/peer_handler.rs index 06c6932cce3..931e8c4e424 100644 --- a/lightning/src/ln/peer_handler.rs +++ b/lightning/src/ln/peer_handler.rs @@ -28,7 +28,7 @@ use crate::util::ser::{VecWriter, Writeable, Writer}; use crate::ln::peer_channel_encryptor::{PeerChannelEncryptor,NextNoiseStep}; use crate::ln::wire; use crate::ln::wire::{Encode, Type}; -use crate::onion_message::{CustomOnionMessageContents, CustomOnionMessageHandler, SimpleArcOnionMessenger, SimpleRefOnionMessenger}; +use crate::onion_message::{CustomOnionMessageContents, CustomOnionMessageHandler, OffersMessage, OffersMessageHandler, SimpleArcOnionMessenger, SimpleRefOnionMessenger}; use crate::routing::gossip::{NetworkGraph, P2PGossipSync, NodeId, NodeAlias}; use crate::util::atomic_counter::AtomicCounter; use crate::util::logger::Logger; @@ -118,9 +118,12 @@ impl OnionMessageHandler for IgnoringMessageHandler { InitFeatures::empty() } } +impl OffersMessageHandler for IgnoringMessageHandler { + fn handle_message(&self, _msg: OffersMessage) -> Option { None } +} impl CustomOnionMessageHandler for IgnoringMessageHandler { type CustomMessage = Infallible; - fn handle_custom_message(&self, _msg: Infallible) { + fn handle_custom_message(&self, _msg: Infallible) -> Option { // Since we always return `None` in the read the handle method should never be called. unreachable!(); } @@ -604,7 +607,15 @@ impl Peer { /// issues such as overly long function definitions. /// /// This is not exported to bindings users as `Arc`s don't make sense in bindings. -pub type SimpleArcPeerManager = PeerManager>, Arc>>, Arc, Arc>>, Arc>, Arc, IgnoringMessageHandler, Arc>; +pub type SimpleArcPeerManager = PeerManager< + SD, + Arc>, + Arc>>, Arc, Arc>>, + Arc>, + Arc, + IgnoringMessageHandler, + Arc +>; /// SimpleRefPeerManager is a type alias for a PeerManager reference, and is the reference /// counterpart to the SimpleArcPeerManager type alias. Use this type by default when you don't @@ -614,7 +625,17 @@ pub type SimpleArcPeerManager = PeerManager = PeerManager, &'f P2PGossipSync<&'g NetworkGraph<&'f L>, &'h C, &'f L>, &'i SimpleRefOnionMessenger<'j, 'k, L>, &'f L, IgnoringMessageHandler, &'c KeysManager>; +pub type SimpleRefPeerManager< + 'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k, 'l, 'm, 'n, SD, M, T, F, C, L, R +> = PeerManager< + SD, + &'n SimpleRefChannelManager<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'm, M, T, F, L>, + &'f P2PGossipSync<&'g NetworkGraph<&'f L>, &'h C, &'f L>, + &'i SimpleRefOnionMessenger<'g, 'm, 'n, L, R>, + &'f L, + IgnoringMessageHandler, + &'c KeysManager +>; /// A generic trait which is implemented for all [`PeerManager`]s. This makes bounding functions or diff --git a/lightning/src/offers/invoice_error.rs b/lightning/src/offers/invoice_error.rs new file mode 100644 index 00000000000..e843264b4e3 --- /dev/null +++ b/lightning/src/offers/invoice_error.rs @@ -0,0 +1,233 @@ +// This file is Copyright its original authors, visible in version control +// history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license +// , at your option. +// You may not use this file except in accordance with one or both of these +// licenses. + +//! Data structures and encoding for `invoice_error` messages. + +use crate::io; +use crate::ln::msgs::DecodeError; +use crate::offers::parse::SemanticError; +use crate::util::ser::{HighZeroBytesDroppedBigSize, Readable, WithoutLength, Writeable, Writer}; +use crate::util::string::UntrustedString; + +use crate::prelude::*; + +/// An error in response to an [`InvoiceRequest`] or an [`Invoice`]. +/// +/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest +/// [`Invoice`]: crate::offers::invoice::Invoice +#[derive(Clone, Debug)] +#[cfg_attr(test, derive(PartialEq))] +pub struct InvoiceError { + /// The field in the [`InvoiceRequest`] or the [`Invoice`] that contained an error. + /// + /// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest + /// [`Invoice`]: crate::offers::invoice::Invoice + pub erroneous_field: Option, + + /// An explanation of the error. + pub message: UntrustedString, +} + +/// The field in the [`InvoiceRequest`] or the [`Invoice`] that contained an error. +/// +/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest +/// [`Invoice`]: crate::offers::invoice::Invoice +#[derive(Clone, Debug)] +#[cfg_attr(test, derive(PartialEq))] +pub struct ErroneousField { + /// The type number of the TLV field containing the error. + pub tlv_fieldnum: u64, + + /// A value to use for the TLV field to avoid the error. + pub suggested_value: Option>, +} + +impl core::fmt::Display for InvoiceError { + fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> { + self.message.fmt(f) + } +} + +impl Writeable for InvoiceError { + fn write(&self, writer: &mut W) -> Result<(), io::Error> { + let tlv_fieldnum = self.erroneous_field.as_ref().map(|f| f.tlv_fieldnum); + let suggested_value = + self.erroneous_field.as_ref().and_then(|f| f.suggested_value.as_ref()); + write_tlv_fields!(writer, { + (1, tlv_fieldnum, (option, encoding: (u64, HighZeroBytesDroppedBigSize))), + (3, suggested_value, (option, encoding: (Vec, WithoutLength))), + (5, WithoutLength(&self.message), required), + }); + Ok(()) + } +} + +impl Readable for InvoiceError { + fn read(reader: &mut R) -> Result { + _init_and_read_tlv_fields!(reader, { + (1, erroneous_field, (option, encoding: (u64, HighZeroBytesDroppedBigSize))), + (3, suggested_value, (option, encoding: (Vec, WithoutLength))), + (5, error, (option, encoding: (UntrustedString, WithoutLength))), + }); + + let erroneous_field = match (erroneous_field, suggested_value) { + (None, None) => None, + (None, Some(_)) => return Err(DecodeError::InvalidValue), + (Some(tlv_fieldnum), suggested_value) => { + Some(ErroneousField { tlv_fieldnum, suggested_value }) + }, + }; + + let message = match error { + None => return Err(DecodeError::InvalidValue), + Some(error) => error, + }; + + Ok(InvoiceError { erroneous_field, message }) + } +} + +impl From for InvoiceError { + fn from(error: SemanticError) -> Self { + InvoiceError { + erroneous_field: None, + message: UntrustedString(format!("{:?}", error)), + } + } +} + +#[cfg(test)] +mod tests { + use super::{ErroneousField, InvoiceError}; + + use crate::ln::msgs::DecodeError; + use crate::util::ser::{HighZeroBytesDroppedBigSize, Readable, VecWriter, WithoutLength, Writeable}; + use crate::util::string::UntrustedString; + + #[test] + fn parses_invoice_error_without_erroneous_field() { + let mut writer = VecWriter(Vec::new()); + let invoice_error = InvoiceError { + erroneous_field: None, + message: UntrustedString("Invalid value".to_string()), + }; + invoice_error.write(&mut writer).unwrap(); + + let buffer = writer.0; + match InvoiceError::read(&mut &buffer[..]) { + Ok(invoice_error) => { + assert_eq!(invoice_error.message, UntrustedString("Invalid value".to_string())); + assert_eq!(invoice_error.erroneous_field, None); + } + Err(e) => panic!("Unexpected error: {:?}", e), + } + } + + #[test] + fn parses_invoice_error_with_erroneous_field() { + let mut writer = VecWriter(Vec::new()); + let invoice_error = InvoiceError { + erroneous_field: Some(ErroneousField { + tlv_fieldnum: 42, + suggested_value: Some(vec![42; 32]), + }), + message: UntrustedString("Invalid value".to_string()), + }; + invoice_error.write(&mut writer).unwrap(); + + let buffer = writer.0; + match InvoiceError::read(&mut &buffer[..]) { + Ok(invoice_error) => { + assert_eq!(invoice_error.message, UntrustedString("Invalid value".to_string())); + assert_eq!( + invoice_error.erroneous_field, + Some(ErroneousField { tlv_fieldnum: 42, suggested_value: Some(vec![42; 32]) }), + ); + } + Err(e) => panic!("Unexpected error: {:?}", e), + } + } + + #[test] + fn parses_invoice_error_without_suggested_value() { + let mut writer = VecWriter(Vec::new()); + let invoice_error = InvoiceError { + erroneous_field: Some(ErroneousField { + tlv_fieldnum: 42, + suggested_value: None, + }), + message: UntrustedString("Invalid value".to_string()), + }; + invoice_error.write(&mut writer).unwrap(); + + let buffer = writer.0; + match InvoiceError::read(&mut &buffer[..]) { + Ok(invoice_error) => { + assert_eq!(invoice_error.message, UntrustedString("Invalid value".to_string())); + assert_eq!( + invoice_error.erroneous_field, + Some(ErroneousField { tlv_fieldnum: 42, suggested_value: None }), + ); + } + Err(e) => panic!("Unexpected error: {:?}", e), + } + } + + #[test] + fn fails_parsing_invoice_error_without_message() { + let tlv_fieldnum: Option = None; + let suggested_value: Option<&Vec> = None; + let error: Option<&String> = None; + + let mut writer = VecWriter(Vec::new()); + let mut write_tlv = || -> Result<(), DecodeError> { + write_tlv_fields!(&mut writer, { + (1, tlv_fieldnum, (option, encoding: (u64, HighZeroBytesDroppedBigSize))), + (3, suggested_value, (option, encoding: (Vec, WithoutLength))), + (5, error, (option, encoding: (String, WithoutLength))), + }); + Ok(()) + }; + write_tlv().unwrap(); + + let buffer = writer.0; + match InvoiceError::read(&mut &buffer[..]) { + Ok(_) => panic!("Expected error"), + Err(e) => { + assert_eq!(e, DecodeError::InvalidValue); + }, + } + } + + #[test] + fn fails_parsing_invoice_error_without_field() { + let tlv_fieldnum: Option = None; + let suggested_value = vec![42; 32]; + let error = "Invalid value".to_string(); + + let mut writer = VecWriter(Vec::new()); + let mut write_tlv = || -> Result<(), DecodeError> { + write_tlv_fields!(&mut writer, { + (1, tlv_fieldnum, (option, encoding: (u64, HighZeroBytesDroppedBigSize))), + (3, Some(&suggested_value), (option, encoding: (Vec, WithoutLength))), + (5, Some(&error), (option, encoding: (String, WithoutLength))), + }); + Ok(()) + }; + write_tlv().unwrap(); + + let buffer = writer.0; + match InvoiceError::read(&mut &buffer[..]) { + Ok(_) => panic!("Expected error"), + Err(e) => { + assert_eq!(e, DecodeError::InvalidValue); + }, + } + } +} diff --git a/lightning/src/offers/mod.rs b/lightning/src/offers/mod.rs index 0fb20f42d79..31d8bf9cbdf 100644 --- a/lightning/src/offers/mod.rs +++ b/lightning/src/offers/mod.rs @@ -13,6 +13,7 @@ //! Offers are a flexible protocol for Lightning payments. pub mod invoice; +pub mod invoice_error; pub mod invoice_request; mod merkle; pub mod offer; diff --git a/lightning/src/onion_message/functional_tests.rs b/lightning/src/onion_message/functional_tests.rs index 96e0c44b2ce..d1b01b71eef 100644 --- a/lightning/src/onion_message/functional_tests.rs +++ b/lightning/src/onion_message/functional_tests.rs @@ -13,23 +13,30 @@ use crate::blinded_path::BlindedPath; use crate::sign::{NodeSigner, Recipient}; use crate::ln::features::InitFeatures; use crate::ln::msgs::{self, DecodeError, OnionMessageHandler}; -use super::{CustomOnionMessageContents, CustomOnionMessageHandler, Destination, OnionMessageContents, OnionMessenger, SendError}; +use super::{CustomOnionMessageContents, CustomOnionMessageHandler, Destination, MessageRouter, OffersMessage, OffersMessageHandler, OnionMessageContents, OnionMessagePath, OnionMessenger, SendError}; use crate::util::ser::{Writeable, Writer}; use crate::util::test_utils; use bitcoin::network::constants::Network; use bitcoin::secp256k1::{PublicKey, Secp256k1}; -use core::sync::atomic::{AtomicU16, Ordering}; use crate::io; use crate::io_extras::read_to_end; -use crate::sync::Arc; +use crate::sync::{Arc, Mutex}; + +use crate::prelude::*; struct MessengerNode { keys_manager: Arc, - messenger: OnionMessenger, Arc, Arc, Arc>, + messenger: OnionMessenger< + Arc, + Arc, + Arc, + Arc, + Arc, + Arc + >, custom_message_handler: Arc, - logger: Arc, } impl MessengerNode { @@ -38,31 +45,67 @@ impl MessengerNode { } } -#[derive(Clone)] -struct TestCustomMessage {} +struct TestMessageRouter {} + +impl MessageRouter for TestMessageRouter { + fn find_path( + &self, _sender: PublicKey, _peers: Vec, destination: Destination + ) -> Result { + Ok(OnionMessagePath { + intermediate_nodes: vec![], + destination, + }) + } +} + +struct TestOffersMessageHandler {} + +impl OffersMessageHandler for TestOffersMessageHandler { + fn handle_message(&self, _message: OffersMessage) -> Option { + None + } +} + +#[derive(Clone, Debug, PartialEq)] +enum TestCustomMessage { + Request, + Response, +} -const CUSTOM_MESSAGE_TYPE: u64 = 4242; -const CUSTOM_MESSAGE_CONTENTS: [u8; 32] = [42; 32]; +const CUSTOM_REQUEST_MESSAGE_TYPE: u64 = 4242; +const CUSTOM_RESPONSE_MESSAGE_TYPE: u64 = 4343; +const CUSTOM_REQUEST_MESSAGE_CONTENTS: [u8; 32] = [42; 32]; +const CUSTOM_RESPONSE_MESSAGE_CONTENTS: [u8; 32] = [43; 32]; impl CustomOnionMessageContents for TestCustomMessage { fn tlv_type(&self) -> u64 { - CUSTOM_MESSAGE_TYPE + match self { + TestCustomMessage::Request => CUSTOM_REQUEST_MESSAGE_TYPE, + TestCustomMessage::Response => CUSTOM_RESPONSE_MESSAGE_TYPE, + } } } impl Writeable for TestCustomMessage { fn write(&self, w: &mut W) -> Result<(), io::Error> { - Ok(CUSTOM_MESSAGE_CONTENTS.write(w)?) + match self { + TestCustomMessage::Request => Ok(CUSTOM_REQUEST_MESSAGE_CONTENTS.write(w)?), + TestCustomMessage::Response => Ok(CUSTOM_RESPONSE_MESSAGE_CONTENTS.write(w)?), + } } } struct TestCustomMessageHandler { - num_messages_expected: AtomicU16, + expected_messages: Mutex>, } impl TestCustomMessageHandler { fn new() -> Self { - Self { num_messages_expected: AtomicU16::new(0) } + Self { expected_messages: Mutex::new(VecDeque::new()) } + } + + fn expect_message(&self, message: TestCustomMessage) { + self.expected_messages.lock().unwrap().push_back(message); } } @@ -73,22 +116,37 @@ impl Drop for TestCustomMessageHandler { return; } } - assert_eq!(self.num_messages_expected.load(Ordering::SeqCst), 0); + assert!(self.expected_messages.lock().unwrap().is_empty()); } } impl CustomOnionMessageHandler for TestCustomMessageHandler { type CustomMessage = TestCustomMessage; - fn handle_custom_message(&self, _msg: Self::CustomMessage) { - self.num_messages_expected.fetch_sub(1, Ordering::SeqCst); + fn handle_custom_message(&self, msg: Self::CustomMessage) -> Option { + match self.expected_messages.lock().unwrap().pop_front() { + Some(expected_msg) => assert_eq!(expected_msg, msg), + None => panic!("Unexpected message: {:?}", msg), + } + + match msg { + TestCustomMessage::Request => Some(TestCustomMessage::Response), + TestCustomMessage::Response => None, + } } fn read_custom_message(&self, message_type: u64, buffer: &mut R) -> Result, DecodeError> where Self: Sized { - if message_type == CUSTOM_MESSAGE_TYPE { - let buf = read_to_end(buffer)?; - assert_eq!(buf, CUSTOM_MESSAGE_CONTENTS); - return Ok(Some(TestCustomMessage {})) + match message_type { + CUSTOM_REQUEST_MESSAGE_TYPE => { + let buf = read_to_end(buffer)?; + assert_eq!(buf, CUSTOM_REQUEST_MESSAGE_CONTENTS); + Ok(Some(TestCustomMessage::Request)) + }, + CUSTOM_RESPONSE_MESSAGE_TYPE => { + let buf = read_to_end(buffer)?; + assert_eq!(buf, CUSTOM_RESPONSE_MESSAGE_CONTENTS); + Ok(Some(TestCustomMessage::Response)) + }, + _ => Ok(None), } - Ok(None) } } @@ -98,12 +156,16 @@ fn create_nodes(num_messengers: u8) -> Vec { let logger = Arc::new(test_utils::TestLogger::with_id(format!("node {}", i))); let seed = [i as u8; 32]; let keys_manager = Arc::new(test_utils::TestKeysInterface::new(&seed, Network::Testnet)); + let message_router = Arc::new(TestMessageRouter {}); + let offers_message_handler = Arc::new(TestOffersMessageHandler {}); let custom_message_handler = Arc::new(TestCustomMessageHandler::new()); nodes.push(MessengerNode { keys_manager: keys_manager.clone(), - messenger: OnionMessenger::new(keys_manager.clone(), keys_manager.clone(), logger.clone(), custom_message_handler.clone()), + messenger: OnionMessenger::new( + keys_manager.clone(), keys_manager, logger.clone(), message_router, + offers_message_handler, custom_message_handler.clone() + ), custom_message_handler, - logger, }); } for idx in 0..num_messengers - 1 { @@ -118,7 +180,6 @@ fn create_nodes(num_messengers: u8) -> Vec { } fn pass_along_path(path: &Vec) { - path[path.len() - 1].custom_message_handler.num_messages_expected.fetch_add(1, Ordering::SeqCst); let mut prev_node = &path[0]; for node in path.into_iter().skip(1) { let events = prev_node.messenger.release_pending_msgs(); @@ -135,42 +196,62 @@ fn pass_along_path(path: &Vec) { #[test] fn one_hop() { let nodes = create_nodes(2); - let test_msg = OnionMessageContents::Custom(TestCustomMessage {}); - - nodes[0].messenger.send_onion_message(&[], Destination::Node(nodes[1].get_node_pk()), test_msg, None).unwrap(); + let test_msg = OnionMessageContents::Custom(TestCustomMessage::Response); + + let path = OnionMessagePath { + intermediate_nodes: vec![], + destination: Destination::Node(nodes[1].get_node_pk()), + }; + nodes[0].messenger.send_onion_message(path, test_msg, None).unwrap(); + nodes[1].custom_message_handler.expect_message(TestCustomMessage::Response); pass_along_path(&nodes); } #[test] fn two_unblinded_hops() { let nodes = create_nodes(3); - let test_msg = OnionMessageContents::Custom(TestCustomMessage {}); - - nodes[0].messenger.send_onion_message(&[nodes[1].get_node_pk()], Destination::Node(nodes[2].get_node_pk()), test_msg, None).unwrap(); + let test_msg = OnionMessageContents::Custom(TestCustomMessage::Response); + + let path = OnionMessagePath { + intermediate_nodes: vec![nodes[1].get_node_pk()], + destination: Destination::Node(nodes[2].get_node_pk()), + }; + nodes[0].messenger.send_onion_message(path, test_msg, None).unwrap(); + nodes[2].custom_message_handler.expect_message(TestCustomMessage::Response); pass_along_path(&nodes); } #[test] fn two_unblinded_two_blinded() { let nodes = create_nodes(5); - let test_msg = OnionMessageContents::Custom(TestCustomMessage {}); + let test_msg = OnionMessageContents::Custom(TestCustomMessage::Response); let secp_ctx = Secp256k1::new(); let blinded_path = BlindedPath::new_for_message(&[nodes[3].get_node_pk(), nodes[4].get_node_pk()], &*nodes[4].keys_manager, &secp_ctx).unwrap(); + let path = OnionMessagePath { + intermediate_nodes: vec![nodes[1].get_node_pk(), nodes[2].get_node_pk()], + destination: Destination::BlindedPath(blinded_path), + }; - nodes[0].messenger.send_onion_message(&[nodes[1].get_node_pk(), nodes[2].get_node_pk()], Destination::BlindedPath(blinded_path), test_msg, None).unwrap(); + nodes[0].messenger.send_onion_message(path, test_msg, None).unwrap(); + nodes[4].custom_message_handler.expect_message(TestCustomMessage::Response); pass_along_path(&nodes); } #[test] fn three_blinded_hops() { let nodes = create_nodes(4); - let test_msg = OnionMessageContents::Custom(TestCustomMessage {}); + let test_msg = OnionMessageContents::Custom(TestCustomMessage::Response); let secp_ctx = Secp256k1::new(); let blinded_path = BlindedPath::new_for_message(&[nodes[1].get_node_pk(), nodes[2].get_node_pk(), nodes[3].get_node_pk()], &*nodes[3].keys_manager, &secp_ctx).unwrap(); + let path = OnionMessagePath { + intermediate_nodes: vec![], + destination: Destination::BlindedPath(blinded_path), + }; - nodes[0].messenger.send_onion_message(&[], Destination::BlindedPath(blinded_path), test_msg, None).unwrap(); + nodes[0].messenger.send_onion_message(path, test_msg, None).unwrap(); + nodes[3].custom_message_handler.expect_message(TestCustomMessage::Response); pass_along_path(&nodes); } @@ -178,11 +259,15 @@ fn three_blinded_hops() { fn too_big_packet_error() { // Make sure we error as expected if a packet is too big to send. let nodes = create_nodes(2); - let test_msg = OnionMessageContents::Custom(TestCustomMessage {}); + let test_msg = OnionMessageContents::Custom(TestCustomMessage::Response); let hop_node_id = nodes[1].get_node_pk(); - let hops = [hop_node_id; 400]; - let err = nodes[0].messenger.send_onion_message(&hops, Destination::Node(hop_node_id), test_msg, None).unwrap_err(); + let hops = vec![hop_node_id; 400]; + let path = OnionMessagePath { + intermediate_nodes: hops, + destination: Destination::Node(hop_node_id), + }; + let err = nodes[0].messenger.send_onion_message(path, test_msg, None).unwrap_err(); assert_eq!(err, SendError::TooBigPacket); } @@ -191,17 +276,27 @@ fn we_are_intro_node() { // If we are sending straight to a blinded path and we are the introduction node, we need to // advance the blinded path by 1 hop so the second hop is the new introduction node. let mut nodes = create_nodes(3); - let test_msg = TestCustomMessage {}; + let test_msg = TestCustomMessage::Response; let secp_ctx = Secp256k1::new(); let blinded_path = BlindedPath::new_for_message(&[nodes[0].get_node_pk(), nodes[1].get_node_pk(), nodes[2].get_node_pk()], &*nodes[2].keys_manager, &secp_ctx).unwrap(); + let path = OnionMessagePath { + intermediate_nodes: vec![], + destination: Destination::BlindedPath(blinded_path), + }; - nodes[0].messenger.send_onion_message(&[], Destination::BlindedPath(blinded_path), OnionMessageContents::Custom(test_msg.clone()), None).unwrap(); + nodes[0].messenger.send_onion_message(path, OnionMessageContents::Custom(test_msg.clone()), None).unwrap(); + nodes[2].custom_message_handler.expect_message(TestCustomMessage::Response); pass_along_path(&nodes); // Try with a two-hop blinded path where we are the introduction node. let blinded_path = BlindedPath::new_for_message(&[nodes[0].get_node_pk(), nodes[1].get_node_pk()], &*nodes[1].keys_manager, &secp_ctx).unwrap(); - nodes[0].messenger.send_onion_message(&[], Destination::BlindedPath(blinded_path), OnionMessageContents::Custom(test_msg), None).unwrap(); + let path = OnionMessagePath { + intermediate_nodes: vec![], + destination: Destination::BlindedPath(blinded_path), + }; + nodes[0].messenger.send_onion_message(path, OnionMessageContents::Custom(test_msg), None).unwrap(); + nodes[1].custom_message_handler.expect_message(TestCustomMessage::Response); nodes.remove(2); pass_along_path(&nodes); } @@ -210,47 +305,67 @@ fn we_are_intro_node() { fn invalid_blinded_path_error() { // Make sure we error as expected if a provided blinded path has 0 or 1 hops. let nodes = create_nodes(3); - let test_msg = TestCustomMessage {}; + let test_msg = TestCustomMessage::Response; // 0 hops let secp_ctx = Secp256k1::new(); let mut blinded_path = BlindedPath::new_for_message(&[nodes[1].get_node_pk(), nodes[2].get_node_pk()], &*nodes[2].keys_manager, &secp_ctx).unwrap(); blinded_path.blinded_hops.clear(); - let err = nodes[0].messenger.send_onion_message(&[], Destination::BlindedPath(blinded_path), OnionMessageContents::Custom(test_msg.clone()), None).unwrap_err(); + let path = OnionMessagePath { + intermediate_nodes: vec![], + destination: Destination::BlindedPath(blinded_path), + }; + let err = nodes[0].messenger.send_onion_message(path, OnionMessageContents::Custom(test_msg.clone()), None).unwrap_err(); assert_eq!(err, SendError::TooFewBlindedHops); // 1 hop let mut blinded_path = BlindedPath::new_for_message(&[nodes[1].get_node_pk(), nodes[2].get_node_pk()], &*nodes[2].keys_manager, &secp_ctx).unwrap(); blinded_path.blinded_hops.remove(0); assert_eq!(blinded_path.blinded_hops.len(), 1); - let err = nodes[0].messenger.send_onion_message(&[], Destination::BlindedPath(blinded_path), OnionMessageContents::Custom(test_msg), None).unwrap_err(); + let path = OnionMessagePath { + intermediate_nodes: vec![], + destination: Destination::BlindedPath(blinded_path), + }; + let err = nodes[0].messenger.send_onion_message(path, OnionMessageContents::Custom(test_msg), None).unwrap_err(); assert_eq!(err, SendError::TooFewBlindedHops); } #[test] fn reply_path() { - let nodes = create_nodes(4); - let test_msg = TestCustomMessage {}; + let mut nodes = create_nodes(4); + let test_msg = TestCustomMessage::Request; let secp_ctx = Secp256k1::new(); // Destination::Node + let path = OnionMessagePath { + intermediate_nodes: vec![nodes[1].get_node_pk(), nodes[2].get_node_pk()], + destination: Destination::Node(nodes[3].get_node_pk()), + }; let reply_path = BlindedPath::new_for_message(&[nodes[2].get_node_pk(), nodes[1].get_node_pk(), nodes[0].get_node_pk()], &*nodes[0].keys_manager, &secp_ctx).unwrap(); - nodes[0].messenger.send_onion_message(&[nodes[1].get_node_pk(), nodes[2].get_node_pk()], Destination::Node(nodes[3].get_node_pk()), OnionMessageContents::Custom(test_msg.clone()), Some(reply_path)).unwrap(); + nodes[0].messenger.send_onion_message(path, OnionMessageContents::Custom(test_msg.clone()), Some(reply_path)).unwrap(); + nodes[3].custom_message_handler.expect_message(TestCustomMessage::Request); pass_along_path(&nodes); // Make sure the last node successfully decoded the reply path. - nodes[3].logger.assert_log_contains( - "lightning::onion_message::messenger", - &format!("Received an onion message with path_id None and a reply_path"), 1); + nodes[0].custom_message_handler.expect_message(TestCustomMessage::Response); + nodes.reverse(); + pass_along_path(&nodes); // Destination::BlindedPath let blinded_path = BlindedPath::new_for_message(&[nodes[1].get_node_pk(), nodes[2].get_node_pk(), nodes[3].get_node_pk()], &*nodes[3].keys_manager, &secp_ctx).unwrap(); + let path = OnionMessagePath { + intermediate_nodes: vec![], + destination: Destination::BlindedPath(blinded_path), + }; let reply_path = BlindedPath::new_for_message(&[nodes[2].get_node_pk(), nodes[1].get_node_pk(), nodes[0].get_node_pk()], &*nodes[0].keys_manager, &secp_ctx).unwrap(); - nodes[0].messenger.send_onion_message(&[], Destination::BlindedPath(blinded_path), OnionMessageContents::Custom(test_msg), Some(reply_path)).unwrap(); + nodes[0].messenger.send_onion_message(path, OnionMessageContents::Custom(test_msg), Some(reply_path)).unwrap(); + nodes[3].custom_message_handler.expect_message(TestCustomMessage::Request); + pass_along_path(&nodes); + + // Make sure the last node successfully decoded the reply path. + nodes[0].custom_message_handler.expect_message(TestCustomMessage::Response); + nodes.reverse(); pass_along_path(&nodes); - nodes[3].logger.assert_log_contains( - "lightning::onion_message::messenger", - &format!("Received an onion message with path_id None and a reply_path"), 2); } #[test] @@ -270,18 +385,26 @@ fn invalid_custom_message_type() { } let test_msg = OnionMessageContents::Custom(InvalidCustomMessage {}); - let err = nodes[0].messenger.send_onion_message(&[], Destination::Node(nodes[1].get_node_pk()), test_msg, None).unwrap_err(); + let path = OnionMessagePath { + intermediate_nodes: vec![], + destination: Destination::Node(nodes[1].get_node_pk()), + }; + let err = nodes[0].messenger.send_onion_message(path, test_msg, None).unwrap_err(); assert_eq!(err, SendError::InvalidMessage); } #[test] fn peer_buffer_full() { let nodes = create_nodes(2); - let test_msg = TestCustomMessage {}; + let test_msg = TestCustomMessage::Request; + let path = OnionMessagePath { + intermediate_nodes: vec![], + destination: Destination::Node(nodes[1].get_node_pk()), + }; for _ in 0..188 { // Based on MAX_PER_PEER_BUFFER_SIZE in OnionMessenger - nodes[0].messenger.send_onion_message(&[], Destination::Node(nodes[1].get_node_pk()), OnionMessageContents::Custom(test_msg.clone()), None).unwrap(); + nodes[0].messenger.send_onion_message(path.clone(), OnionMessageContents::Custom(test_msg.clone()), None).unwrap(); } - let err = nodes[0].messenger.send_onion_message(&[], Destination::Node(nodes[1].get_node_pk()), OnionMessageContents::Custom(test_msg), None).unwrap_err(); + let err = nodes[0].messenger.send_onion_message(path, OnionMessageContents::Custom(test_msg), None).unwrap_err(); assert_eq!(err, SendError::BufferFull); } @@ -291,13 +414,18 @@ fn many_hops() { // of size [`crate::onion_message::packet::BIG_PACKET_HOP_DATA_LEN`]. let num_nodes: usize = 25; let nodes = create_nodes(num_nodes as u8); - let test_msg = OnionMessageContents::Custom(TestCustomMessage {}); + let test_msg = TestCustomMessage::Response; - let mut intermediates = vec![]; + let mut intermediate_nodes = vec![]; for i in 1..(num_nodes-1) { - intermediates.push(nodes[i].get_node_pk()); + intermediate_nodes.push(nodes[i].get_node_pk()); } - nodes[0].messenger.send_onion_message(&intermediates, Destination::Node(nodes[num_nodes-1].get_node_pk()), test_msg, None).unwrap(); + let path = OnionMessagePath { + intermediate_nodes, + destination: Destination::Node(nodes[num_nodes-1].get_node_pk()), + }; + nodes[0].messenger.send_onion_message(path, OnionMessageContents::Custom(test_msg), None).unwrap(); + nodes[num_nodes-1].custom_message_handler.expect_message(TestCustomMessage::Response); pass_along_path(&nodes); } diff --git a/lightning/src/onion_message/messenger.rs b/lightning/src/onion_message/messenger.rs index 5171422cb89..2c3cf430734 100644 --- a/lightning/src/onion_message/messenger.rs +++ b/lightning/src/onion_message/messenger.rs @@ -23,6 +23,7 @@ use crate::ln::msgs::{self, OnionMessageHandler}; use crate::ln::onion_utils; use crate::ln::peer_handler::IgnoringMessageHandler; pub use super::packet::{CustomOnionMessageContents, OnionMessageContents}; +use super::offers::OffersMessageHandler; use super::packet::{BIG_PACKET_HOP_DATA_LEN, ForwardControlTlvs, Packet, Payload, ReceiveControlTlvs, SMALL_PACKET_HOP_DATA_LEN}; use crate::util::logger::Logger; use crate::util::ser::Writeable; @@ -45,7 +46,7 @@ use crate::prelude::*; /// # use lightning::blinded_path::BlindedPath; /// # use lightning::sign::KeysManager; /// # use lightning::ln::peer_handler::IgnoringMessageHandler; -/// # use lightning::onion_message::{CustomOnionMessageContents, Destination, OnionMessageContents, OnionMessenger}; +/// # use lightning::onion_message::{CustomOnionMessageContents, Destination, MessageRouter, OnionMessageContents, OnionMessagePath, OnionMessenger}; /// # use lightning::util::logger::{Logger, Record}; /// # use lightning::util::ser::{Writeable, Writer}; /// # use lightning::io; @@ -54,6 +55,12 @@ use crate::prelude::*; /// # impl Logger for FakeLogger { /// # fn log(&self, record: &Record) { unimplemented!() } /// # } +/// # struct FakeMessageRouter {} +/// # impl MessageRouter for FakeMessageRouter { +/// # fn find_path(&self, sender: PublicKey, peers: Vec, destination: Destination) -> Result { +/// # unimplemented!() +/// # } +/// # } /// # let seed = [42u8; 32]; /// # let time = Duration::from_secs(123456); /// # let keys_manager = KeysManager::new(&seed, time.as_secs(), time.subsec_nanos()); @@ -63,10 +70,15 @@ use crate::prelude::*; /// # let hop_node_id1 = PublicKey::from_secret_key(&secp_ctx, &node_secret); /// # let (hop_node_id2, hop_node_id3, hop_node_id4) = (hop_node_id1, hop_node_id1, hop_node_id1); /// # let destination_node_id = hop_node_id1; -/// # let your_custom_message_handler = IgnoringMessageHandler {}; +/// # let message_router = Arc::new(FakeMessageRouter {}); +/// # let custom_message_handler = IgnoringMessageHandler {}; +/// # let offers_message_handler = IgnoringMessageHandler {}; /// // Create the onion messenger. This must use the same `keys_manager` as is passed to your /// // ChannelManager. -/// let onion_messenger = OnionMessenger::new(&keys_manager, &keys_manager, logger, &your_custom_message_handler); +/// let onion_messenger = OnionMessenger::new( +/// &keys_manager, &keys_manager, logger, message_router, &offers_message_handler, +/// &custom_message_handler +/// ); /// /// # struct YourCustomMessage {} /// impl Writeable for YourCustomMessage { @@ -82,11 +94,14 @@ use crate::prelude::*; /// } /// } /// // Send a custom onion message to a node id. -/// let intermediate_hops = [hop_node_id1, hop_node_id2]; +/// let path = OnionMessagePath { +/// intermediate_nodes: vec![hop_node_id1, hop_node_id2], +/// destination: Destination::Node(destination_node_id), +/// }; /// let reply_path = None; /// # let your_custom_message = YourCustomMessage {}; /// let message = OnionMessageContents::Custom(your_custom_message); -/// onion_messenger.send_onion_message(&intermediate_hops, Destination::Node(destination_node_id), message, reply_path); +/// onion_messenger.send_onion_message(path, message, reply_path); /// /// // Create a blinded path to yourself, for someone to send an onion message to. /// # let your_node_id = hop_node_id1; @@ -94,32 +109,61 @@ use crate::prelude::*; /// let blinded_path = BlindedPath::new_for_message(&hops, &keys_manager, &secp_ctx).unwrap(); /// /// // Send a custom onion message to a blinded path. -/// # let intermediate_hops = [hop_node_id1, hop_node_id2]; +/// let path = OnionMessagePath { +/// intermediate_nodes: vec![hop_node_id1, hop_node_id2], +/// destination: Destination::BlindedPath(blinded_path), +/// }; /// let reply_path = None; /// # let your_custom_message = YourCustomMessage {}; /// let message = OnionMessageContents::Custom(your_custom_message); -/// onion_messenger.send_onion_message(&intermediate_hops, Destination::BlindedPath(blinded_path), message, reply_path); +/// onion_messenger.send_onion_message(path, message, reply_path); /// ``` /// /// [offers]: /// [`OnionMessenger`]: crate::onion_message::OnionMessenger -pub struct OnionMessenger - where ES::Target: EntropySource, - NS::Target: NodeSigner, - L::Target: Logger, - CMH:: Target: CustomOnionMessageHandler, +pub struct OnionMessenger +where + ES::Target: EntropySource, + NS::Target: NodeSigner, + L::Target: Logger, + MR::Target: MessageRouter, + OMH::Target: OffersMessageHandler, + CMH:: Target: CustomOnionMessageHandler, { entropy_source: ES, node_signer: NS, logger: L, pending_messages: Mutex>>, secp_ctx: Secp256k1, + message_router: MR, + offers_handler: OMH, custom_handler: CMH, - // Coming soon: - // invoice_handler: InvoiceHandler, +} + +/// A trait defining behavior for routing an [`OnionMessage`]. +/// +/// [`OnionMessage`]: msgs::OnionMessage +pub trait MessageRouter { + /// Returns a route for sending an [`OnionMessage`] to the given [`Destination`]. + /// + /// [`OnionMessage`]: msgs::OnionMessage + fn find_path( + &self, sender: PublicKey, peers: Vec, destination: Destination + ) -> Result; +} + +/// A path for sending an [`msgs::OnionMessage`]. +#[derive(Clone)] +pub struct OnionMessagePath { + /// Nodes on the path between the sender and the destination. + pub intermediate_nodes: Vec, + + /// The recipient of the message. + pub destination: Destination, } /// The destination of an onion message. +#[derive(Clone)] pub enum Destination { /// We're sending this onion message to a node. Node(PublicKey), @@ -180,22 +224,31 @@ pub trait CustomOnionMessageHandler { /// The message known to the handler. To support multiple message types, you may want to make this /// an enum with a variant for each supported message. type CustomMessage: CustomOnionMessageContents; - /// Called with the custom message that was received. - fn handle_custom_message(&self, msg: Self::CustomMessage); + + /// Called with the custom message that was received, returning a response to send, if any. + fn handle_custom_message(&self, msg: Self::CustomMessage) -> Option; + /// Read a custom message of type `message_type` from `buffer`, returning `Ok(None)` if the /// message type is unknown. fn read_custom_message(&self, message_type: u64, buffer: &mut R) -> Result, msgs::DecodeError>; } -impl OnionMessenger - where ES::Target: EntropySource, - NS::Target: NodeSigner, - L::Target: Logger, - CMH::Target: CustomOnionMessageHandler, +impl +OnionMessenger +where + ES::Target: EntropySource, + NS::Target: NodeSigner, + L::Target: Logger, + MR::Target: MessageRouter, + OMH::Target: OffersMessageHandler, + CMH::Target: CustomOnionMessageHandler, { /// Constructs a new `OnionMessenger` to send, forward, and delegate received onion messages to /// their respective handlers. - pub fn new(entropy_source: ES, node_signer: NS, logger: L, custom_handler: CMH) -> Self { + pub fn new( + entropy_source: ES, node_signer: NS, logger: L, message_router: MR, offers_handler: OMH, + custom_handler: CMH + ) -> Self { let mut secp_ctx = Secp256k1::new(); secp_ctx.seeded_randomize(&entropy_source.get_secure_random_bytes()); OnionMessenger { @@ -204,20 +257,27 @@ impl OnionMessenger pending_messages: Mutex::new(HashMap::new()), secp_ctx, logger, + message_router, + offers_handler, custom_handler, } } - /// Send an onion message with contents `message` to `destination`, routing it through `intermediate_nodes`. + /// Send an onion message with contents `message` to the destination of `path`. + /// /// See [`OnionMessenger`] for example usage. - pub fn send_onion_message(&self, intermediate_nodes: &[PublicKey], mut destination: Destination, message: OnionMessageContents, reply_path: Option) -> Result<(), SendError> { + pub fn send_onion_message( + &self, path: OnionMessagePath, message: OnionMessageContents, + reply_path: Option + ) -> Result<(), SendError> { + let OnionMessagePath { intermediate_nodes, mut destination } = path; if let Destination::BlindedPath(BlindedPath { ref blinded_hops, .. }) = destination { if blinded_hops.len() < 2 { return Err(SendError::TooFewBlindedHops); } } - let OnionMessageContents::Custom(ref msg) = message; - if msg.tlv_type() < 64 { return Err(SendError::InvalidMessage) } + + if message.tlv_type() < 64 { return Err(SendError::InvalidMessage) } // If we are sending straight to a blinded path and we are the introduction node, we need to // advance the blinded path by 1 hop so the second hop is the new introduction node. @@ -244,7 +304,7 @@ impl OnionMessenger } }; let (packet_payloads, packet_keys) = packet_payloads_and_keys( - &self.secp_ctx, intermediate_nodes, destination, message, reply_path, &blinding_secret) + &self.secp_ctx, &intermediate_nodes, destination, message, reply_path, &blinding_secret) .map_err(|e| SendError::Secp256k1(e))?; let prng_seed = self.entropy_source.get_secure_random_bytes(); @@ -262,6 +322,56 @@ impl OnionMessenger } } + fn respond_with_onion_message( + &self, response: OnionMessageContents, path_id: Option<[u8; 32]>, + reply_path: Option + ) { + let sender = match self.node_signer.get_node_id(Recipient::Node) { + Ok(node_id) => node_id, + Err(_) => { + log_warn!( + self.logger, "Unable to retrieve node id when responding to onion message with \ + path_id {:02x?}", path_id + ); + return; + } + }; + + let peers = self.pending_messages.lock().unwrap().keys().copied().collect(); + + let destination = match reply_path { + Some(reply_path) => Destination::BlindedPath(reply_path), + None => { + log_trace!( + self.logger, "Missing reply path when responding to onion message with path_id \ + {:02x?}", path_id + ); + return; + }, + }; + + let path = match self.message_router.find_path(sender, peers, destination) { + Ok(path) => path, + Err(()) => { + log_trace!( + self.logger, "Failed to find path when responding to onion message with \ + path_id {:02x?}", path_id + ); + return; + }, + }; + + log_trace!(self.logger, "Responding to onion message with path_id {:02x?}", path_id); + + if let Err(e) = self.send_onion_message(path, response, None) { + log_trace!( + self.logger, "Failed responding to onion message with path_id {:02x?}: {:?}", + path_id, e + ); + return; + } + } + #[cfg(test)] pub(super) fn release_pending_msgs(&self) -> HashMap> { let mut pending_msgs = self.pending_messages.lock().unwrap(); @@ -298,11 +408,15 @@ fn outbound_buffer_full(peer_node_id: &PublicKey, buffer: &HashMap OnionMessageHandler for OnionMessenger - where ES::Target: EntropySource, - NS::Target: NodeSigner, - L::Target: Logger, - CMH::Target: CustomOnionMessageHandler + Sized, +impl OnionMessageHandler +for OnionMessenger +where + ES::Target: EntropySource, + NS::Target: NodeSigner, + L::Target: Logger, + MR::Target: MessageRouter, + OMH::Target: OffersMessageHandler, + CMH::Target: CustomOnionMessageHandler, { /// Handle an incoming onion message. Currently, if a message was destined for us we will log, but /// soon we'll delegate the onion message to a handler that can generate invoices or send @@ -331,17 +445,30 @@ impl OnionMessageHandler for OnionMe } } }; - match onion_utils::decode_next_untagged_hop(onion_decode_ss, &msg.onion_routing_packet.hop_data[..], - msg.onion_routing_packet.hmac, (control_tlvs_ss, &*self.custom_handler)) - { + match onion_utils::decode_next_untagged_hop( + onion_decode_ss, &msg.onion_routing_packet.hop_data[..], msg.onion_routing_packet.hmac, + (control_tlvs_ss, &*self.custom_handler, &*self.logger) + ) { Ok((Payload::Receive::<<::Target as CustomOnionMessageHandler>::CustomMessage> { message, control_tlvs: ReceiveControlTlvs::Unblinded(ReceiveTlvs { path_id }), reply_path, }, None)) => { - log_info!(self.logger, + log_trace!(self.logger, "Received an onion message with path_id {:02x?} and {} reply_path", path_id, if reply_path.is_some() { "a" } else { "no" }); - match message { - OnionMessageContents::Custom(msg) => self.custom_handler.handle_custom_message(msg), + + let response = match message { + OnionMessageContents::Offers(msg) => { + self.offers_handler.handle_message(msg) + .map(|msg| OnionMessageContents::Offers(msg)) + }, + OnionMessageContents::Custom(msg) => { + self.custom_handler.handle_custom_message(msg) + .map(|msg| OnionMessageContents::Custom(msg)) + }, + }; + + if let Some(response) = response { + self.respond_with_onion_message(response, path_id, reply_path); } }, Ok((Payload::Forward(ForwardControlTlvs::Unblinded(ForwardTlvs { @@ -443,11 +570,15 @@ impl OnionMessageHandler for OnionMe } } -impl OnionMessageProvider for OnionMessenger - where ES::Target: EntropySource, - NS::Target: NodeSigner, - L::Target: Logger, - CMH::Target: CustomOnionMessageHandler, +impl OnionMessageProvider +for OnionMessenger +where + ES::Target: EntropySource, + NS::Target: NodeSigner, + L::Target: Logger, + MR::Target: MessageRouter, + OMH::Target: OffersMessageHandler, + CMH::Target: CustomOnionMessageHandler, { fn next_onion_message_for_peer(&self, peer_node_id: PublicKey) -> Option { let mut pending_msgs = self.pending_messages.lock().unwrap(); @@ -467,7 +598,15 @@ impl OnionMessageProvider for OnionM /// /// [`SimpleArcChannelManager`]: crate::ln::channelmanager::SimpleArcChannelManager /// [`SimpleArcPeerManager`]: crate::ln::peer_handler::SimpleArcPeerManager -pub type SimpleArcOnionMessenger = OnionMessenger, Arc, Arc, IgnoringMessageHandler>; +pub type SimpleArcOnionMessenger = OnionMessenger< + Arc, + Arc, + Arc, + Arc, + IgnoringMessageHandler, + IgnoringMessageHandler +>; + /// Useful for simplifying the parameters of [`SimpleRefChannelManager`] and /// [`SimpleRefPeerManager`]. See their docs for more details. /// @@ -475,7 +614,14 @@ pub type SimpleArcOnionMessenger = OnionMessenger, Arc = OnionMessenger<&'a KeysManager, &'a KeysManager, &'b L, IgnoringMessageHandler>; +pub type SimpleRefOnionMessenger<'a, 'b, 'c, L, R> = OnionMessenger< + &'a KeysManager, + &'a KeysManager, + &'b L, + &'c R, + IgnoringMessageHandler, + IgnoringMessageHandler +>; /// Construct onion packet payloads and keys for sending an onion message along the given /// `unblinded_path` to the given `destination`. diff --git a/lightning/src/onion_message/mod.rs b/lightning/src/onion_message/mod.rs index 713b83c62d6..556ae89820b 100644 --- a/lightning/src/onion_message/mod.rs +++ b/lightning/src/onion_message/mod.rs @@ -21,10 +21,12 @@ //! [blinded paths]: crate::blinded_path::BlindedPath mod messenger; +mod offers; mod packet; #[cfg(test)] mod functional_tests; // Re-export structs so they can be imported with just the `onion_message::` module prefix. -pub use self::messenger::{CustomOnionMessageContents, CustomOnionMessageHandler, Destination, OnionMessageContents, OnionMessenger, SendError, SimpleArcOnionMessenger, SimpleRefOnionMessenger}; +pub use self::messenger::{CustomOnionMessageContents, CustomOnionMessageHandler, Destination, MessageRouter, OnionMessageContents, OnionMessagePath, OnionMessenger, SendError, SimpleArcOnionMessenger, SimpleRefOnionMessenger}; +pub use self::offers::{OffersMessage, OffersMessageHandler}; pub(crate) use self::packet::{ControlTlvs, Packet}; diff --git a/lightning/src/onion_message/offers.rs b/lightning/src/onion_message/offers.rs new file mode 100644 index 00000000000..f82afdd618a --- /dev/null +++ b/lightning/src/onion_message/offers.rs @@ -0,0 +1,118 @@ +// This file is Copyright its original authors, visible in version control +// history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license +// , at your option. +// You may not use this file except in accordance with one or both of these +// licenses. + +//! Message handling for BOLT 12 Offers. + +use core::convert::TryFrom; +use crate::io::{self, Read}; +use crate::ln::msgs::DecodeError; +use crate::offers::invoice_error::InvoiceError; +use crate::offers::invoice_request::InvoiceRequest; +use crate::offers::invoice::Invoice; +use crate::offers::parse::ParseError; +use crate::util::logger::Logger; +use crate::util::ser::{Readable, ReadableArgs, Writeable, Writer}; + +use crate::prelude::*; + +// TLV record types for the `onionmsg_tlv` TLV stream as defined in BOLT 4. +const INVOICE_REQUEST_TLV_TYPE: u64 = 64; +const INVOICE_TLV_TYPE: u64 = 66; +const INVOICE_ERROR_TLV_TYPE: u64 = 68; + +/// A handler for an [`OnionMessage`] containing a BOLT 12 Offers message as its payload. +/// +/// [`OnionMessage`]: crate::ln::msgs::OnionMessage +pub trait OffersMessageHandler { + /// Handles the given message by either responding with an [`Invoice`], sending a payment, or + /// replying with an error. + fn handle_message(&self, message: OffersMessage) -> Option; +} + +/// Possible BOLT 12 Offers messages sent and received via an [`OnionMessage`]. +/// +/// [`OnionMessage`]: crate::ln::msgs::OnionMessage +#[derive(Debug)] +pub enum OffersMessage { + /// A request for an [`Invoice`] for a particular [`Offer`]. + /// + /// [`Offer`]: crate::offers::offer::Offer + InvoiceRequest(InvoiceRequest), + + /// An [`Invoice`] sent in response to an [`InvoiceRequest`] or a [`Refund`]. + /// + /// [`Refund`]: crate::offers::refund::Refund + Invoice(Invoice), + + /// An error from handling an [`OffersMessage`]. + InvoiceError(InvoiceError), +} + +impl OffersMessage { + /// Returns whether `tlv_type` corresponds to a TLV record for Offers. + pub fn is_known_type(tlv_type: u64) -> bool { + match tlv_type { + INVOICE_REQUEST_TLV_TYPE | INVOICE_TLV_TYPE | INVOICE_ERROR_TLV_TYPE => true, + _ => false, + } + } + + /// The TLV record type for the message as used in an `onionmsg_tlv` TLV stream. + pub fn tlv_type(&self) -> u64 { + match self { + OffersMessage::InvoiceRequest(_) => INVOICE_REQUEST_TLV_TYPE, + OffersMessage::Invoice(_) => INVOICE_TLV_TYPE, + OffersMessage::InvoiceError(_) => INVOICE_ERROR_TLV_TYPE, + } + } + + fn parse(tlv_type: u64, bytes: Vec) -> Result { + match tlv_type { + INVOICE_REQUEST_TLV_TYPE => Ok(Self::InvoiceRequest(InvoiceRequest::try_from(bytes)?)), + INVOICE_TLV_TYPE => Ok(Self::Invoice(Invoice::try_from(bytes)?)), + _ => Err(ParseError::Decode(DecodeError::InvalidValue)), + } + } +} + +impl Writeable for OffersMessage { + fn write(&self, w: &mut W) -> Result<(), io::Error> { + match self { + OffersMessage::InvoiceRequest(message) => message.write(w), + OffersMessage::Invoice(message) => message.write(w), + OffersMessage::InvoiceError(message) => message.write(w), + } + } +} + +impl ReadableArgs<(u64, &L)> for OffersMessage { + fn read(r: &mut R, read_args: (u64, &L)) -> Result { + let (tlv_type, logger) = read_args; + if tlv_type == INVOICE_ERROR_TLV_TYPE { + return Ok(Self::InvoiceError(InvoiceError::read(r)?)); + } + + let mut bytes = Vec::new(); + r.read_to_end(&mut bytes).unwrap(); + + match Self::parse(tlv_type, bytes) { + Ok(message) => Ok(message), + Err(ParseError::Decode(e)) => Err(e), + Err(ParseError::InvalidSemantics(e)) => { + log_trace!(logger, "Invalid semantics for TLV type {}: {:?}", tlv_type, e); + Err(DecodeError::InvalidValue) + }, + Err(ParseError::InvalidSignature(e)) => { + log_trace!(logger, "Invalid signature for TLV type {}: {:?}", tlv_type, e); + Err(DecodeError::InvalidValue) + }, + Err(_) => Err(DecodeError::InvalidValue), + } + } +} diff --git a/lightning/src/onion_message/packet.rs b/lightning/src/onion_message/packet.rs index 2fb2407dbdd..1c3595c3712 100644 --- a/lightning/src/onion_message/packet.rs +++ b/lightning/src/onion_message/packet.rs @@ -16,7 +16,9 @@ use crate::blinded_path::{BlindedPath, ForwardTlvs, ReceiveTlvs}; use crate::ln::msgs::DecodeError; use crate::ln::onion_utils; use super::messenger::CustomOnionMessageHandler; +use super::offers::OffersMessage; use crate::util::chacha20poly1305rfc::{ChaChaPolyReadAdapter, ChaChaPolyWriteAdapter}; +use crate::util::logger::Logger; use crate::util::ser::{BigSize, FixedLengthReader, LengthRead, LengthReadable, LengthReadableArgs, Readable, ReadableArgs, Writeable, Writer}; use core::cmp; @@ -108,10 +110,8 @@ pub(super) enum Payload { /// The contents of an onion message. In the context of offers, this would be the invoice, invoice /// request, or invoice error. pub enum OnionMessageContents { - // Coming soon: - // Invoice, - // InvoiceRequest, - // InvoiceError, + /// A message related to BOLT 12 Offers. + Offers(OffersMessage), /// A custom onion message specified by the user. Custom(T), } @@ -122,6 +122,7 @@ impl OnionMessageContents { /// This is not exported to bindings users as methods on non-cloneable enums are not currently exportable pub fn tlv_type(&self) -> u64 { match self { + &OnionMessageContents::Offers(ref msg) => msg.tlv_type(), &OnionMessageContents::Custom(ref msg) => msg.tlv_type(), } } @@ -131,6 +132,7 @@ impl OnionMessageContents { impl Writeable for OnionMessageContents { fn write(&self, w: &mut W) -> Result<(), io::Error> { match self { + OnionMessageContents::Offers(msg) => Ok(msg.write(w)?), OnionMessageContents::Custom(msg) => Ok(msg.write(w)?), } } @@ -201,9 +203,10 @@ impl Writeable for (Payload, [u8; 32]) { } // Uses the provided secret to simultaneously decode and decrypt the control TLVs and data TLV. -impl ReadableArgs<(SharedSecret, &H)> for Payload<::CustomMessage> { - fn read(r: &mut R, args: (SharedSecret, &H)) -> Result { - let (encrypted_tlvs_ss, handler) = args; +impl +ReadableArgs<(SharedSecret, &H, &L)> for Payload<::CustomMessage> { + fn read(r: &mut R, args: (SharedSecret, &H, &L)) -> Result { + let (encrypted_tlvs_ss, handler, logger) = args; let v: BigSize = Readable::read(r)?; let mut rd = FixedLengthReader::new(r, v.0); @@ -221,13 +224,19 @@ impl ReadableArgs<(SharedSecret, &H)> for Payload< if message_type.is_some() { return Err(DecodeError::InvalidValue) } message_type = Some(msg_type); - match handler.read_custom_message(msg_type, msg_reader) { - Ok(Some(msg)) => { - message = Some(msg); + match msg_type { + tlv_type if OffersMessage::is_known_type(tlv_type) => { + let msg = OffersMessage::read(msg_reader, (tlv_type, logger))?; + message = Some(OnionMessageContents::Offers(msg)); Ok(true) }, - Ok(None) => Ok(false), - Err(e) => Err(e), + _ => match handler.read_custom_message(msg_type, msg_reader)? { + Some(msg) => { + message = Some(OnionMessageContents::Custom(msg)); + Ok(true) + }, + None => Ok(false), + }, } }); rd.eat_remaining().map_err(|_| DecodeError::ShortRead)?; @@ -241,13 +250,12 @@ impl ReadableArgs<(SharedSecret, &H)> for Payload< Ok(Payload::Forward(ForwardControlTlvs::Unblinded(tlvs))) }, Some(ChaChaPolyReadAdapter { readable: ControlTlvs::Receive(tlvs)}) => { - if message.is_none() { return Err(DecodeError::InvalidValue) } Ok(Payload::Receive { control_tlvs: ReceiveControlTlvs::Unblinded(tlvs), reply_path, - message: OnionMessageContents::Custom(message.unwrap()), + message: message.ok_or(DecodeError::InvalidValue)?, }) - } + }, } } } diff --git a/lightning/src/util/ser.rs b/lightning/src/util/ser.rs index cbdb5485e7b..fb0d0ad8e44 100644 --- a/lightning/src/util/ser.rs +++ b/lightning/src/util/ser.rs @@ -43,6 +43,7 @@ use crate::ln::msgs::PartialSignatureWithNonce; use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret}; use crate::util::byte_utils::{be48_to_array, slice_to_be48}; +use crate::util::string::UntrustedString; /// serialization buffer size pub const MAX_BUF_SIZE: usize = 64 * 1024; @@ -629,6 +630,21 @@ impl<'a> From<&'a String> for WithoutLength<&'a String> { fn from(s: &'a String) -> Self { Self(s) } } + +impl Writeable for WithoutLength<&UntrustedString> { + #[inline] + fn write(&self, w: &mut W) -> Result<(), io::Error> { + WithoutLength(&self.0.0).write(w) + } +} +impl Readable for WithoutLength { + #[inline] + fn read(r: &mut R) -> Result { + let s: WithoutLength = Readable::read(r)?; + Ok(Self(UntrustedString(s.0))) + } +} + impl<'a, T: Writeable> Writeable for WithoutLength<&'a Vec> { #[inline] fn write(&self, writer: &mut W) -> Result<(), io::Error> { diff --git a/lightning/src/util/ser_macros.rs b/lightning/src/util/ser_macros.rs index d6a03a88fbe..8ffcec6d175 100644 --- a/lightning/src/util/ser_macros.rs +++ b/lightning/src/util/ser_macros.rs @@ -178,6 +178,9 @@ macro_rules! _get_varint_length_prefixed_tlv_length { ($len: expr, $type: expr, $field: expr, (option: $trait: ident $(, $read_arg: expr)?)) => { $crate::_get_varint_length_prefixed_tlv_length!($len, $type, $field, option); }; + ($len: expr, $type: expr, $field: expr, (option, encoding: ($fieldty: ty, $encoding: ident))) => { + $crate::_get_varint_length_prefixed_tlv_length!($len, $type, $field.map(|f| $encoding(f)), option); + }; ($len: expr, $type: expr, $field: expr, upgradable_required) => { $crate::_get_varint_length_prefixed_tlv_length!($len, $type, $field, required); };