+ let msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_announcement.encode()[..])[..]);
+ let valid_announcement = ChannelAnnouncement {
+ node_signature_1: secp_ctx.sign(&msghash, node_1_privkey),
+ node_signature_2: secp_ctx.sign(&msghash, node_2_privkey),
+ bitcoin_signature_1: secp_ctx.sign(&msghash, node_1_btckey),
+ bitcoin_signature_2: secp_ctx.sign(&msghash, node_2_btckey),
+ contents: unsigned_announcement.clone(),
+ };
+ match net_graph_msg_handler.handle_channel_announcement(&valid_announcement) {
+ Ok(_) => (),
+ _ => panic!()
+ };
+ }
+
+ // Empty reply when number_of_blocks=0
+ test_handling_query_channel_range(
+ &net_graph_msg_handler,
+ &node_id_2,
+ QueryChannelRange {
+ chain_hash: chain_hash.clone(),
+ first_blocknum: 0,
+ number_of_blocks: 0,
+ },
+ vec![ReplyChannelRange {
+ chain_hash: chain_hash.clone(),
+ first_blocknum: 0,
+ number_of_blocks: 0,
+ sync_complete: true,
+ short_channel_ids: vec![]
+ }]
+ );
+
+ // Empty when wrong chain
+ test_handling_query_channel_range(
+ &net_graph_msg_handler,
+ &node_id_2,
+ QueryChannelRange {
+ chain_hash: genesis_block(Network::Bitcoin).header.block_hash(),
+ first_blocknum: 0,
+ number_of_blocks: 0xffff_ffff,
+ },
+ vec![ReplyChannelRange {
+ chain_hash: genesis_block(Network::Bitcoin).header.block_hash(),
+ first_blocknum: 0,
+ number_of_blocks: 0xffff_ffff,
+ sync_complete: true,
+ short_channel_ids: vec![],
+ }]
+ );
+
+ // Empty reply when first_blocknum > 0xffffff
+ test_handling_query_channel_range(
+ &net_graph_msg_handler,
+ &node_id_2,
+ QueryChannelRange {
+ chain_hash: chain_hash.clone(),
+ first_blocknum: 0x01000000,
+ number_of_blocks: 0xffffffff,
+ },
+ vec![ReplyChannelRange {
+ chain_hash: chain_hash.clone(),
+ first_blocknum: 0x01000000,
+ number_of_blocks: 0xffffffff,
+ sync_complete: true,
+ short_channel_ids: vec![]
+ }]
+ );
+
+ // Empty reply when max valid SCID block num.
+ // Unlike prior test this is a valid but no results are found
+ test_handling_query_channel_range(
+ &net_graph_msg_handler,
+ &node_id_2,
+ QueryChannelRange {
+ chain_hash: chain_hash.clone(),
+ first_blocknum: 0xffffff,
+ number_of_blocks: 1,
+ },
+ vec![
+ ReplyChannelRange {
+ chain_hash: chain_hash.clone(),
+ first_blocknum: 0xffffff,
+ number_of_blocks: 1,
+ sync_complete: true,
+ short_channel_ids: vec![]
+ },
+ ]
+ );
+
+ // No results in valid query range
+ test_handling_query_channel_range(
+ &net_graph_msg_handler,
+ &node_id_2,
+ QueryChannelRange {
+ chain_hash: chain_hash.clone(),
+ first_blocknum: 0x00100000,
+ number_of_blocks: 1000,
+ },
+ vec![
+ ReplyChannelRange {
+ chain_hash: chain_hash.clone(),
+ first_blocknum: 0x00100000,
+ number_of_blocks: 1000,
+ sync_complete: true,
+ short_channel_ids: vec![],
+ }
+ ]
+ );
+
+ // Single reply - all blocks
+ test_handling_query_channel_range(
+ &net_graph_msg_handler,
+ &node_id_2,
+ QueryChannelRange {
+ chain_hash: chain_hash.clone(),
+ first_blocknum: 0,
+ number_of_blocks: 0xffffffff,
+ },
+ vec![
+ ReplyChannelRange {
+ chain_hash: chain_hash.clone(),
+ first_blocknum: 0,
+ number_of_blocks: 0xffffffff,
+ sync_complete: true,
+ short_channel_ids: vec![
+ 0x000000_000000_0000, // 0x0x0
+ 0x000001_000000_0000, // 1x0x0
+ 0x000002_000000_0000, // 2x0x0
+ 0x000002_000001_0000, // 2x1x0
+ 0x000100_000000_0000, // 256x0x0
+ 0x000101_000000_0000, // 257x0x0
+ 0xfffffe_ffffff_ffff, // max
+ ]
+ }
+ ]
+ );
+
+ // Single reply - overflow of first_blocknum + number_of_blocks
+ test_handling_query_channel_range(
+ &net_graph_msg_handler,
+ &node_id_2,
+ QueryChannelRange {
+ chain_hash: chain_hash.clone(),
+ first_blocknum: 1,
+ number_of_blocks: 0xffffffff,
+ },
+ vec![
+ ReplyChannelRange {
+ chain_hash: chain_hash.clone(),
+ first_blocknum: 1,
+ number_of_blocks: 0xfffffffe,
+ sync_complete: true,
+ short_channel_ids: vec![
+ 0x000001_000000_0000, // 1x0x0
+ 0x000002_000000_0000, // 2x0x0
+ 0x000002_000001_0000, // 2x1x0
+ 0x000100_000000_0000, // 256x0x0
+ 0x000101_000000_0000, // 257x0x0
+ 0xfffffe_ffffff_ffff, // max
+ ]
+ }
+ ]
+ );
+
+ // Single reply - query larger than found results
+ test_handling_query_channel_range(
+ &net_graph_msg_handler,
+ &node_id_2,
+ QueryChannelRange {
+ chain_hash: chain_hash.clone(),
+ first_blocknum: 100,
+ number_of_blocks: 1000,
+ },
+ vec![
+ ReplyChannelRange {
+ chain_hash: chain_hash.clone(),
+ first_blocknum: 100,
+ number_of_blocks: 1000,
+ sync_complete: true,
+ short_channel_ids: vec![
+ 0x000100_000000_0000, // 256x0x0
+ 0x000101_000000_0000, // 257x0x0
+ ]
+ }
+ ]
+ );
+
+ // Tests below here will chunk replies
+ net_graph_msg_handler.max_reply_scids = 1;
+
+ // Multipart - new block per messages
+ test_handling_query_channel_range(
+ &net_graph_msg_handler,
+ &node_id_2,
+ QueryChannelRange {
+ chain_hash: chain_hash.clone(),
+ first_blocknum: 0,
+ number_of_blocks: 2,
+ },
+ vec![
+ ReplyChannelRange {
+ chain_hash: chain_hash.clone(),
+ first_blocknum: 0,
+ number_of_blocks: 1,
+ sync_complete: false,
+ short_channel_ids: vec![
+ 0x000000_000000_0000, // 0x0x0
+ ]
+ },
+ ReplyChannelRange {
+ chain_hash: chain_hash.clone(),
+ first_blocknum: 1,
+ number_of_blocks: 1,
+ sync_complete: true,
+ short_channel_ids: vec![
+ 0x000001_000000_0000, // 1x0x0
+ ]
+ },
+ ]
+ );
+
+ // Multiplart - resumption of same block
+ test_handling_query_channel_range(
+ &net_graph_msg_handler,
+ &node_id_2,
+ QueryChannelRange {
+ chain_hash: chain_hash.clone(),
+ first_blocknum: 2,
+ number_of_blocks: 1,
+ },
+ vec![
+ ReplyChannelRange {
+ chain_hash: chain_hash.clone(),
+ first_blocknum: 2,
+ number_of_blocks: 1,
+ sync_complete: false,
+ short_channel_ids: vec![
+ 0x000002_000000_0000, // 2x0x0
+ ]
+ },
+ ReplyChannelRange {
+ chain_hash: chain_hash.clone(),
+ first_blocknum: 2,
+ number_of_blocks: 1,
+ sync_complete: true,
+ short_channel_ids: vec![
+ 0x000002_000001_0000, // 2x1x0
+ ]
+ }
+ ]
+ );
+
+ // Multipart - query larger than found results, similar to single reply
+ test_handling_query_channel_range(
+ &net_graph_msg_handler,
+ &node_id_2,
+ QueryChannelRange {
+ chain_hash: chain_hash.clone(),
+ first_blocknum: 100,
+ number_of_blocks: 1000,
+ },
+ vec![
+ ReplyChannelRange {
+ chain_hash: chain_hash.clone(),
+ first_blocknum: 100, // <= query first_blocknum
+ number_of_blocks: 157,
+ sync_complete: false,
+ short_channel_ids: vec![
+ 0x000100_000000_0000, // 256x0x0
+ ]
+ },
+ ReplyChannelRange {
+ chain_hash: chain_hash.clone(),
+ first_blocknum: 257,
+ number_of_blocks: 843, // >= query first_blocknum+number_of_blocks
+ sync_complete: true,
+ short_channel_ids: vec![
+ 0x000101_000000_0000, // 257x0x0
+ ]
+ }
+ ]
+ );
+ }
+
+ fn test_handling_query_channel_range(
+ net_graph_msg_handler: &NetGraphMsgHandler<Arc<test_utils::TestChainSource>, Arc<test_utils::TestLogger>>,
+ test_node_id: &PublicKey,
+ msg: QueryChannelRange,
+ expected_replies: Vec<ReplyChannelRange>
+ ) {
+ let result = net_graph_msg_handler.handle_query_channel_range(test_node_id, msg);
+ assert!(result.is_ok());
+
+ let events = net_graph_msg_handler.get_and_clear_pending_msg_events();
+ assert_eq!(events.len(), expected_replies.len());
+
+ for i in 0..events.len() {
+ let expected_reply = &expected_replies[i];
+ match &events[i] {
+ MessageSendEvent::SendReplyChannelRange { node_id, msg } => {
+ assert_eq!(node_id, test_node_id);
+ assert_eq!(msg.chain_hash, expected_reply.chain_hash);
+ assert_eq!(msg.first_blocknum, expected_reply.first_blocknum);
+ assert_eq!(msg.number_of_blocks, expected_reply.number_of_blocks);
+ assert_eq!(msg.sync_complete, expected_reply.sync_complete);
+ assert_eq!(msg.short_channel_ids, expected_reply.short_channel_ids);
+ },
+ _ => panic!("expected MessageSendEvent::SendReplyChannelRange"),
+ }
+ }