+ 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 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 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 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(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[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(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);
+}
+
+#[test]
+fn invalid_custom_message_type() {
+ let nodes = create_nodes(2);
+
+ struct InvalidCustomMessage{}
+ impl CustomOnionMessageContents for InvalidCustomMessage {
+ fn tlv_type(&self) -> u64 {
+ // Onion message contents must have a TLV >= 64.
+ 63
+ }
+ }
+
+ impl Writeable for InvalidCustomMessage {
+ fn write<W: Writer>(&self, _w: &mut W) -> Result<(), io::Error> { unreachable!() }
+ }
+
+ let test_msg = OnionMessageContents::Custom(InvalidCustomMessage {});
+ 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::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(path.clone(), OnionMessageContents::Custom(test_msg.clone()), None).unwrap();
+ }
+ let err = nodes[0].messenger.send_onion_message(path, OnionMessageContents::Custom(test_msg), None).unwrap_err();
+ assert_eq!(err, SendError::BufferFull);
+}
+
+#[test]
+fn many_hops() {
+ // Check we can send over a route with many hops. This will exercise our logic for onion messages
+ // 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 = TestCustomMessage::Response;
+
+ let mut intermediate_nodes = vec![];
+ for i in 1..(num_nodes-1) {
+ intermediate_nodes.push(nodes[i].get_node_pk());
+ }
+
+ 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);
+}
+
+#[test]
+fn spec_test_vector() {
+ let keys_mgrs = vec![
+ (Arc::new(test_utils::TestKeysInterface::new(&[0; 32], Network::Testnet)), // Alice
+ Arc::new(test_utils::TestNodeSigner::new(SecretKey::from_slice(&hex::decode("4141414141414141414141414141414141414141414141414141414141414141").unwrap()).unwrap()))),
+ (Arc::new(test_utils::TestKeysInterface::new(&[1; 32], Network::Testnet)), // Bob
+ Arc::new(test_utils::TestNodeSigner::new(SecretKey::from_slice(&hex::decode("4242424242424242424242424242424242424242424242424242424242424242").unwrap()).unwrap()))),
+ (Arc::new(test_utils::TestKeysInterface::new(&[2; 32], Network::Testnet)), // Carol
+ Arc::new(test_utils::TestNodeSigner::new(SecretKey::from_slice(&hex::decode("4343434343434343434343434343434343434343434343434343434343434343").unwrap()).unwrap()))),
+ (Arc::new(test_utils::TestKeysInterface::new(&[3; 32], Network::Testnet)), // Dave
+ Arc::new(test_utils::TestNodeSigner::new(SecretKey::from_slice(&hex::decode("4444444444444444444444444444444444444444444444444444444444444444").unwrap()).unwrap()))),
+ ];
+ let message_router = Arc::new(TestMessageRouter {});
+ let offers_message_handler = Arc::new(TestOffersMessageHandler {});
+ let custom_message_handler = Arc::new(TestCustomMessageHandler::new());
+ let mut nodes = Vec::new();
+ for (idx, (entropy_source, node_signer)) in keys_mgrs.iter().enumerate() {
+ let logger = Arc::new(test_utils::TestLogger::with_id(format!("node {}", idx)));
+ nodes.push(OnionMessenger::new(
+ entropy_source.clone(), node_signer.clone(), logger.clone(), message_router.clone(),
+ offers_message_handler.clone(), custom_message_handler.clone()
+ ));
+ }
+ for idx in 0..nodes.len() - 1 {
+ let i = idx as usize;
+ let mut features = InitFeatures::empty();
+ features.set_onion_messages_optional();
+ let init_msg = msgs::Init { features, networks: None, remote_network_address: None };
+ nodes[i].peer_connected(
+ &keys_mgrs[i + 1].1.get_node_id(Recipient::Node).unwrap(), &init_msg.clone(), true).unwrap();
+ nodes[i + 1].peer_connected(
+ &keys_mgrs[i].1.get_node_id(Recipient::Node).unwrap(), &init_msg.clone(), false).unwrap();
+ }