+
+ #[test]
+ fn sending_query_channel_range() {
+ let (secp_ctx, net_graph_msg_handler) = create_net_graph_msg_handler();
+ let node_privkey_1 = &SecretKey::from_slice(&[42; 32]).unwrap();
+ let node_privkey_2 = &SecretKey::from_slice(&[41; 32]).unwrap();
+ let node_id_1 = PublicKey::from_secret_key(&secp_ctx, node_privkey_1);
+ let node_id_2 = PublicKey::from_secret_key(&secp_ctx, node_privkey_2);
+
+ let chain_hash = genesis_block(Network::Testnet).header.block_hash();
+ let first_blocknum = 0;
+ let number_of_blocks = 0xffff_ffff;
+
+ // When no active query exists for the node, it should send a query message and generate a task
+ {
+ let result = net_graph_msg_handler.query_channel_range(&node_id_1, chain_hash, first_blocknum, number_of_blocks);
+ assert!(result.is_ok());
+
+ // It should create a task for the query
+ assert!(net_graph_msg_handler.chan_range_query_tasks.lock().unwrap().contains_key(&node_id_1));
+
+ // It should send a query_channel_range message with the correct information
+ let events = net_graph_msg_handler.get_and_clear_pending_msg_events();
+ assert_eq!(events.len(), 1);
+ match &events[0] {
+ MessageSendEvent::SendChannelRangeQuery{ node_id, msg } => {
+ assert_eq!(node_id, &node_id_1);
+ assert_eq!(msg.chain_hash, chain_hash);
+ assert_eq!(msg.first_blocknum, first_blocknum);
+ assert_eq!(msg.number_of_blocks, number_of_blocks);
+ },
+ _ => panic!("Expected MessageSendEvent::SendChannelRangeQuery")
+ };
+ }
+
+ // When an active query exists for the node, when there is a subsequent query request, it
+ // should fail to initiate a new query
+ {
+ let result = net_graph_msg_handler.query_channel_range(&node_id_1, chain_hash, first_blocknum, number_of_blocks);
+ assert_eq!(result.is_err(), true);
+ }
+
+ // When no active query exists for a different node, it should send a query message
+ {
+ let result = net_graph_msg_handler.query_channel_range(&node_id_2, chain_hash, first_blocknum, number_of_blocks);
+ assert_eq!(result.is_ok(), true);
+
+ // It should create a task for the query
+ assert!(net_graph_msg_handler.chan_range_query_tasks.lock().unwrap().contains_key(&node_id_2));
+
+ // It should send a query_channel_message with the correct information
+ let events = net_graph_msg_handler.get_and_clear_pending_msg_events();
+ assert_eq!(events.len(), 1);
+ match &events[0] {
+ MessageSendEvent::SendChannelRangeQuery{ node_id, msg } => {
+ assert_eq!(node_id, &node_id_2);
+ assert_eq!(msg.chain_hash, chain_hash);
+ assert_eq!(msg.first_blocknum, first_blocknum);
+ assert_eq!(msg.number_of_blocks, number_of_blocks);
+ },
+ _ => panic!("Expected MessageSendEvent::SendChannelRangeQuery")
+ };
+ }
+ }
+
+ #[test]
+ fn sending_query_short_channel_ids() {
+ let (secp_ctx, net_graph_msg_handler) = create_net_graph_msg_handler();
+ let node_privkey_1 = &SecretKey::from_slice(&[42; 32]).unwrap();
+ let node_id_1 = PublicKey::from_secret_key(&secp_ctx, node_privkey_1);
+
+ let chain_hash = genesis_block(Network::Testnet).header.block_hash();
+
+ // The first query should send the batch of scids to the peer
+ {
+ let short_channel_ids: Vec<u64> = vec![0, 1, 2];
+ let result = net_graph_msg_handler.query_short_channel_ids(&node_id_1, chain_hash, short_channel_ids.clone());
+ assert!(result.is_ok());
+
+ // Validate that we have enqueued a send message event and that it contains the correct information
+ let events = net_graph_msg_handler.get_and_clear_pending_msg_events();
+ assert_eq!(events.len(), 1);
+ match &events[0] {
+ MessageSendEvent::SendShortIdsQuery{ node_id, msg } => {
+ assert_eq!(node_id, &node_id_1);
+ assert_eq!(msg.chain_hash, chain_hash);
+ assert_eq!(msg.short_channel_ids, short_channel_ids);
+ },
+ _ => panic!("Expected MessageSendEvent::SendShortIdsQuery")
+ };
+ }
+
+ // Subsequent queries for scids should enqueue them to be sent in the next batch which will
+ // be sent when a reply_short_channel_ids_end message is handled.
+ {
+ let short_channel_ids: Vec<u64> = vec![3, 4, 5];
+ let result = net_graph_msg_handler.query_short_channel_ids(&node_id_1, chain_hash, short_channel_ids.clone());
+ assert!(result.is_ok());
+
+ // Validate that we have not enqueued another send message event yet
+ let events = net_graph_msg_handler.get_and_clear_pending_msg_events();
+ assert_eq!(events.len(), 0);
+
+ // Validate the task has the queued scids
+ assert_eq!(
+ net_graph_msg_handler.scid_query_tasks.lock().unwrap().get(&node_id_1).unwrap().short_channel_ids,
+ short_channel_ids
+ );
+ }
+ }
+
+ #[test]
+ fn handling_reply_channel_range() {
+ let (secp_ctx, net_graph_msg_handler) = create_net_graph_msg_handler();
+ let node_privkey_1 = &SecretKey::from_slice(&[42; 32]).unwrap();
+ let node_id_1 = PublicKey::from_secret_key(&secp_ctx, node_privkey_1);
+
+ let chain_hash = genesis_block(Network::Testnet).header.block_hash();
+
+ // Test receipt of an unknown reply message. We expect an error
+ {
+ let result = net_graph_msg_handler.handle_reply_channel_range(&node_id_1, &ReplyChannelRange {
+ chain_hash,
+ full_information: true,
+ first_blocknum: 1000,
+ number_of_blocks: 1050,
+ short_channel_ids: vec![
+ 0x0003e8_000000_0000, // 1000x0x0
+ 0x0003e9_000000_0000, // 1001x0x0
+ 0x0003f0_000000_0000 // 1008x0x0
+ ],
+ });
+ assert!(result.is_err());
+ }
+
+ // Test receipt of a single reply_channel_range that exactly matches the queried range.
+ // It sends a query_short_channel_ids with the returned scids and removes the pending task
+ {
+ // Initiate a channel range query to create a query task
+ let result = net_graph_msg_handler.query_channel_range(&node_id_1, chain_hash, 1000, 100);
+ assert!(result.is_ok());
+
+ // Clear the SendRangeQuery event
+ net_graph_msg_handler.get_and_clear_pending_msg_events();
+
+ // Handle a single successful reply that matches the queried channel range
+ let result = net_graph_msg_handler.handle_reply_channel_range(&node_id_1, &ReplyChannelRange {
+ chain_hash,
+ full_information: true,
+ first_blocknum: 1000,
+ number_of_blocks: 100,
+ short_channel_ids: vec![
+ 0x0003e8_000000_0000, // 1000x0x0
+ 0x0003e9_000000_0000, // 1001x0x0
+ 0x0003f0_000000_0000 // 1008x0x0
+ ],
+ });
+ assert!(result.is_ok());
+
+ // The query is now complete, so we expect the task to be removed
+ assert!(net_graph_msg_handler.chan_range_query_tasks.lock().unwrap().is_empty());
+
+ // We expect to emit a query_short_channel_ids message with scids in our query range
+ let events = net_graph_msg_handler.get_and_clear_pending_msg_events();
+ assert_eq!(events.len(), 1);
+ match &events[0] {
+ MessageSendEvent::SendShortIdsQuery { node_id, msg } => {
+ assert_eq!(node_id, &node_id_1);
+ assert_eq!(msg.chain_hash, chain_hash);
+ assert_eq!(msg.short_channel_ids, vec![0x0003e8_000000_0000,0x0003e9_000000_0000,0x0003f0_000000_0000]);
+ },
+ _ => panic!("expected MessageSendEvent::SendShortIdsQuery"),
+ }
+
+ // Clean up scid_task
+ net_graph_msg_handler.scid_query_tasks.lock().unwrap().clear();
+ }
+
+ // Test receipt of a single reply_channel_range for a query that has a u32 overflow. We expect
+ // it sends a query_short_channel_ids with the returned scids and removes the pending task.
+ {
+ // Initiate a channel range query to create a query task
+ let result = net_graph_msg_handler.query_channel_range(&node_id_1, chain_hash, 1000, 0xffff_ffff);
+ assert!(result.is_ok());
+
+ // Clear the SendRangeQuery event
+ net_graph_msg_handler.get_and_clear_pending_msg_events();
+
+ // Handle a single successful reply that matches the queried channel range
+ let result = net_graph_msg_handler.handle_reply_channel_range(&node_id_1, &ReplyChannelRange {
+ chain_hash,
+ full_information: true,
+ first_blocknum: 1000,
+ number_of_blocks: 0xffff_ffff,
+ short_channel_ids: vec![
+ 0x0003e8_000000_0000, // 1000x0x0
+ 0x0003e9_000000_0000, // 1001x0x0
+ 0x0003f0_000000_0000 // 1008x0x0
+ ],
+ });
+ assert!(result.is_ok());
+
+ // The query is now complete, so we expect the task to be removed
+ assert!(net_graph_msg_handler.chan_range_query_tasks.lock().unwrap().is_empty());
+
+ // We expect to emit a query_short_channel_ids message with scids in our query range
+ let events = net_graph_msg_handler.get_and_clear_pending_msg_events();
+ assert_eq!(events.len(), 1);
+ match &events[0] {
+ MessageSendEvent::SendShortIdsQuery { node_id, msg } => {
+ assert_eq!(node_id, &node_id_1);
+ assert_eq!(msg.chain_hash, chain_hash);
+ assert_eq!(msg.short_channel_ids, vec![0x0003e8_000000_0000,0x0003e9_000000_0000,0x0003f0_000000_0000]);
+ },
+ _ => panic!("expected MessageSendEvent::SendShortIdsQuery"),
+ }
+
+ // Clean up scid_task
+ net_graph_msg_handler.scid_query_tasks.lock().unwrap().clear();
+ }
+
+ // Test receipt of a single reply that encompasses the queried channel range. This is allowed
+ // since a reply must contain at least part of the query range. Receipt of the reply should
+ // send a query_short_channel_ids message with scids filtered to the query range and remove
+ // the pending task.
+ {
+ // Initiate a channel range query to create a query task
+ let result = net_graph_msg_handler.query_channel_range(&node_id_1, chain_hash, 1000, 100);
+ assert!(result.is_ok());
+
+ // Clear the SendRangeQuery event
+ net_graph_msg_handler.get_and_clear_pending_msg_events();
+
+ // Handle a single successful reply that encompasses the queried channel range
+ let result = net_graph_msg_handler.handle_reply_channel_range(&node_id_1, &ReplyChannelRange {
+ chain_hash,
+ full_information: true,
+ first_blocknum: 0,
+ number_of_blocks: 2000,
+ short_channel_ids: vec![
+ 0x0003e0_000000_0000, // 992x0x0
+ 0x0003e8_000000_0000, // 1000x0x0
+ 0x0003e9_000000_0000, // 1001x0x0
+ 0x0003f0_000000_0000, // 1008x0x0
+ 0x00044c_000000_0000, // 1100x0x0
+ 0x0006e0_000000_0000, // 1760x0x0
+ ],
+ });
+ assert!(result.is_ok());
+
+ // The query is now complete, so we expect the task to be removed
+ assert!(net_graph_msg_handler.chan_range_query_tasks.lock().unwrap().is_empty());
+
+ // We expect to emit a query_short_channel_ids message with scids filtered to those
+ // within the original query range.
+ let events = net_graph_msg_handler.get_and_clear_pending_msg_events();
+ assert_eq!(events.len(), 1);
+ match &events[0] {
+ MessageSendEvent::SendShortIdsQuery { node_id, msg } => {
+ assert_eq!(node_id, &node_id_1);
+ assert_eq!(msg.chain_hash, chain_hash);
+ assert_eq!(msg.short_channel_ids, vec![0x0003e8_000000_0000,0x0003e9_000000_0000,0x0003f0_000000_0000]);
+ },
+ _ => panic!("expected MessageSendEvent::SendShortIdsQuery"),
+ }
+
+ // Clean up scid_task
+ net_graph_msg_handler.scid_query_tasks.lock().unwrap().clear();
+ }
+
+ // Test receipt of multiple reply messages for a single query. This happens when the number
+ // of scids in the query range exceeds the size limits of a single reply message. We expect
+ // to initiate a query_short_channel_ids for the first batch of scids and we enqueue the
+ // remaining scids for later processing. We remove the range query task after receipt of all
+ // reply messages.
+ {
+ // Initiate a channel range query to create a query task
+ let result = net_graph_msg_handler.query_channel_range(&node_id_1, chain_hash, 1000, 100);
+ assert!(result.is_ok());
+
+ // Clear the SendRangeQuery event
+ net_graph_msg_handler.get_and_clear_pending_msg_events();
+
+ // Handle the first reply message
+ let reply_1_scids = vec![
+ 0x0003e8_000000_0000, // 1000x0x0
+ 0x0003e9_000000_0000, // 1001x0x0
+ 0x000419_000000_0000, // 1049x0x0
+ ];
+ let result = net_graph_msg_handler.handle_reply_channel_range(&node_id_1, &ReplyChannelRange {
+ chain_hash,
+ full_information: true,
+ first_blocknum: 1000,
+ number_of_blocks: 50,
+ short_channel_ids: reply_1_scids.clone(),
+ });
+ assert!(result.is_ok());
+
+ // Handle the next reply in the sequence, which must start at the previous message's
+ // first_blocknum plus number_of_blocks. The scids in this reply will be queued.
+ let reply_2_scids = vec![
+ 0x00041a_000000_0000, // 1050x0x0
+ 0x000432_000000_0000, // 1074x0x0
+ ];
+ let result = net_graph_msg_handler.handle_reply_channel_range(&node_id_1, &ReplyChannelRange {
+ chain_hash,
+ full_information: true,
+ first_blocknum: 1050,
+ number_of_blocks: 25,
+ short_channel_ids: reply_2_scids.clone(),
+ });
+ assert!(result.is_ok());
+
+ // Handle the final reply in the sequence, which must meet or exceed the initial query's
+ // first_blocknum plus number_of_blocks. The scids in this reply will be queued.
+ let reply_3_scids = vec![
+ 0x000433_000000_0000, // 1075x0x0
+ 0x00044b_000000_0000, // 1099x0x0
+ ];
+ let result = net_graph_msg_handler.handle_reply_channel_range(&node_id_1, &ReplyChannelRange {
+ chain_hash,
+ full_information: true,
+ first_blocknum: 1075,
+ number_of_blocks: 25,
+ short_channel_ids: reply_3_scids.clone(),
+ });
+ assert!(result.is_ok());
+
+ // After the final reply we expect the query task to be removed
+ assert!(net_graph_msg_handler.chan_range_query_tasks.lock().unwrap().is_empty());
+
+ // We expect to emit a query_short_channel_ids message with the accumulated scids that
+ // match the queried channel range.
+ let events = net_graph_msg_handler.get_and_clear_pending_msg_events();
+ assert_eq!(events.len(), 1);
+ match &events[0] {
+ MessageSendEvent::SendShortIdsQuery { node_id, msg } => {
+ assert_eq!(node_id, &node_id_1);
+ assert_eq!(msg.chain_hash, chain_hash);
+ assert_eq!(msg.short_channel_ids, [reply_1_scids, reply_2_scids, reply_3_scids].concat());
+ },
+ _ => panic!("expected MessageSendEvent::SendShortIdsQuery"),
+ }
+
+ // Clean up scid_task
+ net_graph_msg_handler.scid_query_tasks.lock().unwrap().clear();
+ }
+
+ // Test receipt of a sequence of replies with a valid first reply and a second reply that
+ // resumes on the same block as the first reply. The spec requires a subsequent
+ // first_blocknum to equal the prior first_blocknum plus number_of_blocks, however
+ // due to discrepancies in implementation we must loosen this restriction.
+ {
+ // Initiate a channel range query to create a query task
+ let result = net_graph_msg_handler.query_channel_range(&node_id_1, chain_hash, 1000, 100);
+ assert!(result.is_ok());
+
+ // Clear the SendRangeQuery event
+ net_graph_msg_handler.get_and_clear_pending_msg_events();
+
+ // Handle the first reply message
+ let reply_1_scids = vec![
+ 0x0003e8_000000_0000, // 1000x0x0
+ 0x0003e9_000000_0000, // 1001x0x0
+ 0x000419_000000_0000, // 1049x0x0
+ ];
+ let result = net_graph_msg_handler.handle_reply_channel_range(&node_id_1, &ReplyChannelRange {
+ chain_hash,
+ full_information: true,
+ first_blocknum: 1000,
+ number_of_blocks: 50,
+ short_channel_ids: reply_1_scids.clone(),
+ });
+ assert!(result.is_ok());
+
+ // Handle the next reply in the sequence, which is non-spec but resumes on the last block
+ // of the first message.
+ let reply_2_scids = vec![
+ 0x000419_000001_0000, // 1049x1x0
+ 0x00041a_000000_0000, // 1050x0x0
+ 0x000432_000000_0000, // 1074x0x0
+ ];
+ let result = net_graph_msg_handler.handle_reply_channel_range(&node_id_1, &ReplyChannelRange {
+ chain_hash,
+ full_information: true,
+ first_blocknum: 1049,
+ number_of_blocks: 51,
+ short_channel_ids: reply_2_scids.clone(),
+ });
+ assert!(result.is_ok());
+
+ // After the final reply we expect the query task to be removed
+ assert!(net_graph_msg_handler.chan_range_query_tasks.lock().unwrap().is_empty());
+
+ // We expect to emit a query_short_channel_ids message with the accumulated scids that
+ // match the queried channel range
+ let events = net_graph_msg_handler.get_and_clear_pending_msg_events();
+ assert_eq!(events.len(), 1);
+ match &events[0] {
+ MessageSendEvent::SendShortIdsQuery { node_id, msg } => {
+ assert_eq!(node_id, &node_id_1);
+ assert_eq!(msg.chain_hash, chain_hash);
+ assert_eq!(msg.short_channel_ids, [reply_1_scids, reply_2_scids].concat());
+ },
+ _ => panic!("expected MessageSendEvent::SendShortIdsQuery"),
+ }
+
+ // Clean up scid_task
+ net_graph_msg_handler.scid_query_tasks.lock().unwrap().clear();
+ }
+
+ // Test receipt of reply with a chain_hash that does not match the query. We expect to return
+ // an error and to remove the query task.
+ {
+ // Initiate a channel range query to create a query task
+ let result = net_graph_msg_handler.query_channel_range(&node_id_1, chain_hash, 1000, 100);
+ assert!(result.is_ok());
+
+ // Clear the SendRangeQuery event
+ net_graph_msg_handler.get_and_clear_pending_msg_events();
+
+ // Handle the reply with a mismatched chain_hash. We expect IgnoreError result and the
+ // task should be removed.
+ let result = net_graph_msg_handler.handle_reply_channel_range(&node_id_1, &ReplyChannelRange {
+ chain_hash: genesis_block(Network::Bitcoin).header.block_hash(),
+ full_information: true,
+ first_blocknum: 1000,
+ number_of_blocks: 1050,
+ short_channel_ids: vec![0x0003e8_000000_0000,0x0003e9_000000_0000,0x0003f0_000000_0000],
+ });
+ assert!(result.is_err());
+ assert_eq!(result.err().unwrap().err, "Received reply_channel_range with invalid chain_hash");
+ assert!(net_graph_msg_handler.chan_range_query_tasks.lock().unwrap().is_empty());
+ }
+
+ // Test receipt of a reply that indicates the remote node does not maintain up-to-date
+ // information for the chain_hash. Because of discrepancies in implementation we use
+ // full_information=false and short_channel_ids=[] as the signal. We should expect an error
+ // and the task should be removed.
+ {
+ // Initiate a channel range query to create a query task
+ let result = net_graph_msg_handler.query_channel_range(&node_id_1, chain_hash, 1000, 100);
+ assert!(result.is_ok());
+
+ // Clear the SendRangeQuery event
+ net_graph_msg_handler.get_and_clear_pending_msg_events();
+
+ // Handle the reply indicating the peer was unable to fulfill our request.
+ let result = net_graph_msg_handler.handle_reply_channel_range(&node_id_1, &ReplyChannelRange {
+ chain_hash,
+ full_information: false,
+ first_blocknum: 1000,
+ number_of_blocks: 100,
+ short_channel_ids: vec![],
+ });
+ assert!(result.is_err());
+ assert_eq!(result.err().unwrap().err, "Received reply_channel_range with no information available");
+ assert!(net_graph_msg_handler.chan_range_query_tasks.lock().unwrap().is_empty());
+ }
+
+ // Test receipt of a reply that has a first_blocknum that is above the first_blocknum
+ // requested in our query. The reply must contain the queried block range. We expect an
+ // error result and the task should be removed.
+ {
+ // Initiate a channel range query to create a query task
+ let result = net_graph_msg_handler.query_channel_range(&node_id_1, chain_hash, 1000, 100);
+ assert!(result.is_ok());
+
+ // Clear the SendRangeQuery event
+ net_graph_msg_handler.get_and_clear_pending_msg_events();
+
+ // Handle the reply that has a first_blocknum above the query's first_blocknum
+ let result = net_graph_msg_handler.handle_reply_channel_range(&node_id_1, &ReplyChannelRange {
+ chain_hash,
+ full_information: true,
+ first_blocknum: 1001,
+ number_of_blocks: 100,
+ short_channel_ids: vec![],
+ });
+ assert!(result.is_err());
+ assert_eq!(result.err().unwrap().err, "Failing reply_channel_range with invalid first_blocknum");
+ assert!(net_graph_msg_handler.chan_range_query_tasks.lock().unwrap().is_empty());
+ }
+
+ // Test receipt of a first reply that does not overlap the query range at all. The first message
+ // must have some overlap with the query. We expect an error result and the task should
+ // be removed.
+ {
+ // Initiate a channel range query to create a query task
+ let result = net_graph_msg_handler.query_channel_range(&node_id_1, chain_hash, 1000, 100);
+ assert!(result.is_ok());
+
+ // Clear the SendRangeQuery event
+ net_graph_msg_handler.get_and_clear_pending_msg_events();
+
+ // Handle a reply that contains a block range that precedes the queried block range
+ let result = net_graph_msg_handler.handle_reply_channel_range(&node_id_1, &ReplyChannelRange {
+ chain_hash,
+ full_information: true,
+ first_blocknum: 0,
+ number_of_blocks: 1000,
+ short_channel_ids: vec![],
+ });
+ assert!(result.is_err());
+ assert_eq!(result.err().unwrap().err, "Failing reply_channel_range with non-overlapping first reply");
+ assert!(net_graph_msg_handler.chan_range_query_tasks.lock().unwrap().is_empty());
+ }
+
+ // Test receipt of a sequence of replies with a valid first reply and a second reply that is
+ // non-sequential. The spec requires a subsequent first_blocknum to equal the prior
+ // first_blocknum plus number_of_blocks. We expect an IgnoreError result and the task should
+ // be removed.
+ {
+ // Initiate a channel range query to create a query task
+ let result = net_graph_msg_handler.query_channel_range(&node_id_1, chain_hash, 1000, 100);
+ assert!(result.is_ok());
+
+ // Clear the SendRangeQuery event
+ net_graph_msg_handler.get_and_clear_pending_msg_events();
+
+ // Handle the first reply
+ let result = net_graph_msg_handler.handle_reply_channel_range(&node_id_1, &ReplyChannelRange {
+ chain_hash,
+ full_information: true,
+ first_blocknum: 1000,
+ number_of_blocks: 50,
+ short_channel_ids: vec![0x0003e8_000000_0000,0x0003e9_000000_0000,0x0003f0_000000_0000],
+ });
+ assert!(result.is_ok());
+
+ // Handle the second reply which does not start at the proper first_blocknum. We expect
+ // to return an error and remove the task.
+ let result = net_graph_msg_handler.handle_reply_channel_range(&node_id_1, &ReplyChannelRange {
+ chain_hash,
+ full_information: true,
+ first_blocknum: 1051,
+ number_of_blocks: 50,
+ short_channel_ids: vec![0x0003f1_000000_0000,0x0003f2_000000_0000],
+ });
+ assert!(result.is_err());
+ assert_eq!(result.err().unwrap().err, "Failing reply_channel_range with invalid sequence");
+ assert!(net_graph_msg_handler.chan_range_query_tasks.lock().unwrap().is_empty());
+ }
+
+ // Test receipt of too many reply messages. We expect an IgnoreError result and the task should
+ // be removed.
+ {
+ // Initiate a channel range query to create a query task
+ let result = net_graph_msg_handler.query_channel_range(&node_id_1, chain_hash, 1000, 0xffff_ffff);
+ assert!(result.is_ok());
+
+ // Clear the SendRangeQuery event
+ net_graph_msg_handler.get_and_clear_pending_msg_events();
+
+ // Handle a sequence of replies that will fail once the max number of reply has been exceeded.
+ for block in 1000..=1000 + super::MAX_REPLY_CHANNEL_RANGE_PER_QUERY + 10 {
+ let result = net_graph_msg_handler.handle_reply_channel_range(&node_id_1, &ReplyChannelRange {
+ chain_hash,
+ full_information: true,
+ first_blocknum: block as u32,
+ number_of_blocks: 1,
+ short_channel_ids: vec![(block as u64) << 40],
+ });
+ if block <= 1000 + super::MAX_REPLY_CHANNEL_RANGE_PER_QUERY {
+ assert!(result.is_ok());
+ } else if block == 1001 + super::MAX_REPLY_CHANNEL_RANGE_PER_QUERY {
+ assert!(result.is_err());
+ assert_eq!(result.err().unwrap().err, "Failing reply_channel_range due to excessive messages");
+ } else {
+ assert!(result.is_err());
+ assert_eq!(result.err().unwrap().err, "Received unknown reply_channel_range message");
+ }
+ }
+
+ // Expect the task to be removed
+ assert!(net_graph_msg_handler.chan_range_query_tasks.lock().unwrap().is_empty());
+ }
+ }
+
+ #[test]
+ fn handling_reply_short_channel_ids() {
+ let (secp_ctx, net_graph_msg_handler) = create_net_graph_msg_handler();
+ let node_privkey = &SecretKey::from_slice(&[41; 32]).unwrap();
+ let node_id = PublicKey::from_secret_key(&secp_ctx, node_privkey);
+
+ let chain_hash = genesis_block(Network::Testnet).header.block_hash();
+
+ // Test receipt of a reply when no query exists. We expect an error to be returned
+ {
+ let result = net_graph_msg_handler.handle_reply_short_channel_ids_end(&node_id, &ReplyShortChannelIdsEnd {
+ chain_hash,
+ full_information: true,
+ });
+ assert!(result.is_err());
+ assert_eq!(result.err().unwrap().err, "Unknown reply_short_channel_ids_end message");
+ }
+
+ // Test receipt of a reply that is for a different chain_hash. We expect an error and the task
+ // should be removed.
+ {
+ // Initiate a query to create a pending query task
+ let result = net_graph_msg_handler.query_short_channel_ids(&node_id, chain_hash, vec![0x0003e8_000000_0000]);
+ assert!(result.is_ok());
+
+ // Process reply with incorrect chain_hash
+ let result = net_graph_msg_handler.handle_reply_short_channel_ids_end(&node_id, &ReplyShortChannelIdsEnd {
+ chain_hash: genesis_block(Network::Bitcoin).header.block_hash(),
+ full_information: true,
+ });
+ assert!(result.is_err());
+ assert_eq!(result.err().unwrap().err, "Received reply_short_channel_ids_end with incorrect chain_hash");
+
+ // Expect the task to be removed
+ assert!(net_graph_msg_handler.scid_query_tasks.lock().unwrap().is_empty());
+ }
+
+ // Test receipt of a reply that indicates the peer does not maintain up-to-date information
+ // for the chain_hash requested in the query. We expect an error and task should be removed.
+ {
+ // Initiate a query to create a pending query task
+ let result = net_graph_msg_handler.query_short_channel_ids(&node_id, chain_hash, vec![0x0003e8_000000_0000]);
+ assert!(result.is_ok());
+
+ // Process failed reply
+ let result = net_graph_msg_handler.handle_reply_short_channel_ids_end(&node_id, &ReplyShortChannelIdsEnd {
+ chain_hash,
+ full_information: false,
+ });
+ assert!(result.is_err());
+ assert_eq!(result.err().unwrap().err, "Received reply_short_channel_ids_end with no information");
+
+ // Expect the task to be removed
+ assert!(net_graph_msg_handler.scid_query_tasks.lock().unwrap().is_empty());
+ }
+
+ // Test receipt of a successful reply when there are no additional scids to query. We expect
+ // the task to be removed.
+ {
+ // Initiate a query to create a pending query task
+ let result = net_graph_msg_handler.query_short_channel_ids(&node_id, chain_hash, vec![0x0003e8_000000_0000]);
+ assert!(result.is_ok());
+
+ // Process success reply
+ let result = net_graph_msg_handler.handle_reply_short_channel_ids_end(&node_id, &ReplyShortChannelIdsEnd {
+ chain_hash,
+ full_information: true,
+ });
+ assert!(result.is_ok());
+
+ // Expect the task to be removed
+ assert!(net_graph_msg_handler.scid_query_tasks.lock().unwrap().is_empty());
+ }
+
+ // Test receipt of a successful reply when there are additional scids to query. We expect
+ // additional queries to be sent until the task can be removed.
+ {
+ // Initiate a query to create a pending query task
+ let result = net_graph_msg_handler.query_short_channel_ids(&node_id, chain_hash, vec![0x0003e8_000000_0000]);
+ assert!(result.is_ok());
+
+ // Initiate a second query to add pending scids to the task
+ let result = net_graph_msg_handler.query_short_channel_ids(&node_id, chain_hash, vec![0x0003e9_000000_0000]);
+ assert!(result.is_ok());
+ assert_eq!(net_graph_msg_handler.scid_query_tasks.lock().unwrap().get(&node_id).unwrap().short_channel_ids, vec![0x0003e9_000000_0000]);
+
+ // Initiate a third query to add pending scids to the task
+ let result = net_graph_msg_handler.query_short_channel_ids(&node_id, chain_hash, vec![0x0003f0_000000_0000]);
+ assert!(result.is_ok());
+ assert_eq!(net_graph_msg_handler.scid_query_tasks.lock().unwrap().get(&node_id).unwrap().short_channel_ids, vec![0x0003e9_000000_0000, 0x0003f0_000000_0000]);
+
+ // Clear all of the pending send events
+ net_graph_msg_handler.get_and_clear_pending_msg_events();
+
+ // Handle the first successful reply, which will send the next batch of scids in a new query
+ let result = net_graph_msg_handler.handle_reply_short_channel_ids_end(&node_id, &ReplyShortChannelIdsEnd {
+ chain_hash,
+ full_information: true,
+ });
+ assert!(result.is_ok());
+
+ // We expect the second batch to be sent in an event
+ let expected_node_id = &node_id;
+ let events = net_graph_msg_handler.get_and_clear_pending_msg_events();
+ assert_eq!(events.len(), 1);
+ match &events[0] {
+ MessageSendEvent::SendShortIdsQuery { node_id, msg } => {
+ assert_eq!(node_id, expected_node_id);
+ assert_eq!(msg.chain_hash, chain_hash);
+ assert_eq!(msg.short_channel_ids, vec![0x0003e9_000000_0000, 0x0003f0_000000_0000]);
+ },
+ _ => panic!("expected MessageSendEvent::SendShortIdsQuery"),
+ }
+
+ // We expect the scids to be cleared from the task
+ assert_eq!(net_graph_msg_handler.scid_query_tasks.lock().unwrap().get(&node_id).unwrap().short_channel_ids.len(), 0);
+
+ // Handle the second successful reply
+ let result = net_graph_msg_handler.handle_reply_short_channel_ids_end(&node_id, &ReplyShortChannelIdsEnd {
+ chain_hash,
+ full_information: true,
+ });
+ assert!(result.is_ok());
+
+ // We expect the task should be removed
+ assert!(net_graph_msg_handler.scid_query_tasks.lock().unwrap().is_empty());
+ }
+ }
+
+ #[test]
+ fn handling_query_channel_range() {
+ let (secp_ctx, net_graph_msg_handler) = create_net_graph_msg_handler();
+ let node_privkey = &SecretKey::from_slice(&[41; 32]).unwrap();
+ let node_id = PublicKey::from_secret_key(&secp_ctx, node_privkey);
+
+ let chain_hash = genesis_block(Network::Testnet).header.block_hash();
+
+ let result = net_graph_msg_handler.handle_query_channel_range(&node_id, &QueryChannelRange {
+ chain_hash,
+ first_blocknum: 0,
+ number_of_blocks: 0xffff_ffff,
+ });
+ assert!(result.is_err());
+ }
+
+ #[test]
+ fn handling_query_short_channel_ids() {
+ let (secp_ctx, net_graph_msg_handler) = create_net_graph_msg_handler();
+ let node_privkey = &SecretKey::from_slice(&[41; 32]).unwrap();
+ let node_id = PublicKey::from_secret_key(&secp_ctx, node_privkey);
+
+ let chain_hash = genesis_block(Network::Testnet).header.block_hash();
+
+ let result = net_graph_msg_handler.handle_query_short_channel_ids(&node_id, &QueryShortChannelIds {
+ chain_hash,
+ short_channel_ids: vec![0x0003e8_000000_0000],
+ });
+ assert!(result.is_err());
+ }