+ 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(path, test_msg, None).unwrap();
+ nodes[3].custom_message_handler.expect_message(TestCustomMessage::Response);
+ pass_along_path(&nodes);
+}
+
+#[test]
+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::Response);
+
+ let hop_node_id = nodes[1].get_node_pk();
+ 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);
+}
+
+#[test]
+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::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(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();
+ 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);
+}
+
+#[test]
+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::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 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());
+ }