@@ -570,6 +570,77 @@ pub struct ChannelUpdate {
570
570
pub contents : UnsignedChannelUpdate ,
571
571
}
572
572
573
+ /// A query_channel_range message that can be sent or received from a peer
574
+ #[ derive( PartialEq , Clone , Debug ) ]
575
+ pub struct QueryChannelRange {
576
+ /// The genesis hash of the blockchain being queried
577
+ pub chain_hash : BlockHash ,
578
+ /// The height of the first block for the channel UTXOs being queried
579
+ pub first_blocknum : u32 ,
580
+ /// The number of blocks to include in the query results
581
+ pub number_of_blocks : u32 ,
582
+ }
583
+
584
+ /// A reply_channel_range message that can be sent or received from a peer.
585
+ /// Multiple reply_channel_range messages can be sent in reply to a single
586
+ /// query_channel_range message. The query recipient makes a best effort
587
+ /// to respond based on their local network view which may not be
588
+ /// a perfect view of the network.
589
+ #[ derive( PartialEq , Clone , Debug ) ]
590
+ pub struct ReplyChannelRange {
591
+ /// The genesis hash of the blockchain being queried
592
+ pub chain_hash : BlockHash ,
593
+ /// The height of the first block in the range of the reply
594
+ pub first_blocknum : u32 ,
595
+ /// The number of blocks included in the range of the reply
596
+ pub number_of_blocks : u32 ,
597
+ /// Indicates if the query recipient maintains up-to-date channel
598
+ /// information for the chain_hash
599
+ pub full_information : bool ,
600
+ /// The short_channel_ids in the channel range
601
+ pub short_channel_ids : Vec < u64 > ,
602
+ }
603
+
604
+ /// A query_short_channel_ids that can be seent or received from a peer
605
+ #[ derive( PartialEq , Clone , Debug ) ]
606
+ pub struct QueryShortChannelIds {
607
+ /// The genesis hash of the blockchain being queried
608
+ pub chain_hash : BlockHash ,
609
+ /// The short_channel_ids that are being queried
610
+ pub short_channel_ids : Vec < u64 > ,
611
+ }
612
+
613
+ /// A reply_short_channel_ids_end message that can be sent or received
614
+ /// from a peer. This message is sent as a reply to a query_short_channel_ids
615
+ /// message. The query recipient makes a best effort to respond based on
616
+ /// their local network view which may not be a perfect view of the network.
617
+ #[ derive( PartialEq , Clone , Debug ) ]
618
+ pub struct ReplyShortChannelIdsEnd {
619
+ /// The genesis hash of the blockchain that was queried
620
+ pub chain_hash : BlockHash ,
621
+ /// Indicates if the query recipient maintains up-to-date channel
622
+ /// information for the chain_hash
623
+ pub full_information : bool ,
624
+ }
625
+
626
+ /// A gossip_timestamp_filter message is used by a node to request
627
+ /// gossip relay for messages in the requested time range when the
628
+ /// gossip_queries feature has been negotiated.
629
+ #[ derive( PartialEq , Clone , Debug ) ]
630
+ pub struct GossipTimestampFilter {
631
+ /// The genesis hash of the blockchain for channel and node information
632
+ pub chain_hash : BlockHash ,
633
+ /// The starting unix timestamp
634
+ pub first_timestamp : u32 ,
635
+ /// The range of information in seconds
636
+ pub timestamp_range : u32 ,
637
+ }
638
+
639
+ /// Encoding type for data compression of collections in gossip queries
640
+ enum EncodingType {
641
+ Uncompressed = 0x00 ,
642
+ }
643
+
573
644
/// Used to put an error message in a LightningError
574
645
#[ derive( Clone ) ]
575
646
pub enum ErrorAction {
@@ -1515,6 +1586,164 @@ impl_writeable_len_match!(NodeAnnouncement, {
1515
1586
contents
1516
1587
} ) ;
1517
1588
1589
+ impl Readable for QueryShortChannelIds {
1590
+ fn read < R : Read > ( r : & mut R ) -> Result < Self , DecodeError > {
1591
+ let chain_hash: BlockHash = Readable :: read ( r) ?;
1592
+
1593
+ let mut encoding_len: u16 = Readable :: read ( r) ?;
1594
+ let encoding_type: u8 = Readable :: read ( r) ?;
1595
+ if encoding_type != EncodingType :: Uncompressed as u8 {
1596
+ return Err ( DecodeError :: InvalidValue ) ;
1597
+ }
1598
+ encoding_len -= 1 ;
1599
+ let mut read_len = 0 ;
1600
+ let mut short_channel_ids = vec ! [ ] ;
1601
+ loop {
1602
+ if read_len >= encoding_len { break ; }
1603
+ short_channel_ids. push ( Readable :: read ( r) ?) ;
1604
+ read_len += 8 ;
1605
+ }
1606
+
1607
+ Ok ( QueryShortChannelIds {
1608
+ chain_hash,
1609
+ short_channel_ids,
1610
+ } )
1611
+ }
1612
+ }
1613
+
1614
+ impl Writeable for QueryShortChannelIds {
1615
+ fn write < W : Writer > ( & self , w : & mut W ) -> Result < ( ) , :: std:: io:: Error > {
1616
+ let encoding_len: u16 = 1 + self . short_channel_ids . len ( ) as u16 * 8 ;
1617
+ w. size_hint ( 32 + 2 + encoding_len as usize ) ;
1618
+ self . chain_hash . write ( w) ?;
1619
+
1620
+ encoding_len. write ( w) ?;
1621
+ ( EncodingType :: Uncompressed as u8 ) . write ( w) ?;
1622
+ for scid in self . short_channel_ids . iter ( ) {
1623
+ scid. write ( w) ?;
1624
+ }
1625
+
1626
+ Ok ( ( ) )
1627
+ }
1628
+ }
1629
+
1630
+ impl Readable for ReplyShortChannelIdsEnd {
1631
+ fn read < R : Read > ( r : & mut R ) -> Result < Self , DecodeError > {
1632
+ let chain_hash: BlockHash = Readable :: read ( r) ?;
1633
+ let full_information: bool = Readable :: read ( r) ?;
1634
+ Ok ( ReplyShortChannelIdsEnd {
1635
+ chain_hash,
1636
+ full_information,
1637
+ } )
1638
+ }
1639
+ }
1640
+
1641
+ impl Writeable for ReplyShortChannelIdsEnd {
1642
+ fn write < W : Writer > ( & self , w : & mut W ) -> Result < ( ) , :: std:: io:: Error > {
1643
+ w. size_hint ( 32 + 1 ) ;
1644
+ self . chain_hash . write ( w) ?;
1645
+ self . full_information . write ( w) ?;
1646
+ Ok ( ( ) )
1647
+ }
1648
+ }
1649
+
1650
+ impl Readable for QueryChannelRange {
1651
+ fn read < R : Read > ( r : & mut R ) -> Result < Self , DecodeError > {
1652
+ let chain_hash: BlockHash = Readable :: read ( r) ?;
1653
+ let first_blocknum: u32 = Readable :: read ( r) ?;
1654
+ let number_of_blocks: u32 = Readable :: read ( r) ?;
1655
+ Ok ( QueryChannelRange {
1656
+ chain_hash,
1657
+ first_blocknum,
1658
+ number_of_blocks
1659
+ } )
1660
+ }
1661
+ }
1662
+
1663
+ impl Writeable for QueryChannelRange {
1664
+ fn write < W : Writer > ( & self , w : & mut W ) -> Result < ( ) , :: std:: io:: Error > {
1665
+ w. size_hint ( 32 + 4 + 4 ) ;
1666
+ self . chain_hash . write ( w) ?;
1667
+ self . first_blocknum . write ( w) ?;
1668
+ self . number_of_blocks . write ( w) ?;
1669
+ Ok ( ( ) )
1670
+ }
1671
+ }
1672
+
1673
+ impl Readable for ReplyChannelRange {
1674
+ fn read < R : Read > ( r : & mut R ) -> Result < Self , DecodeError > {
1675
+ let chain_hash: BlockHash = Readable :: read ( r) ?;
1676
+ let first_blocknum: u32 = Readable :: read ( r) ?;
1677
+ let number_of_blocks: u32 = Readable :: read ( r) ?;
1678
+ let full_information: bool = Readable :: read ( r) ?;
1679
+
1680
+ let mut encoding_len: u16 = Readable :: read ( r) ?;
1681
+ let encoding_type: u8 = Readable :: read ( r) ?;
1682
+ if encoding_type != EncodingType :: Uncompressed as u8 {
1683
+ return Err ( DecodeError :: InvalidValue ) ;
1684
+ }
1685
+ encoding_len -= 1 ;
1686
+ let mut read_len = 0 ;
1687
+ let mut short_channel_ids = vec ! [ ] ;
1688
+ loop {
1689
+ if read_len >= encoding_len { break ; }
1690
+ short_channel_ids. push ( Readable :: read ( r) ?) ;
1691
+ read_len += 8 ;
1692
+ }
1693
+
1694
+ Ok ( ReplyChannelRange {
1695
+ chain_hash,
1696
+ first_blocknum,
1697
+ number_of_blocks,
1698
+ full_information,
1699
+ short_channel_ids
1700
+ } )
1701
+ }
1702
+ }
1703
+
1704
+ impl Writeable for ReplyChannelRange {
1705
+ fn write < W : Writer > ( & self , w : & mut W ) -> Result < ( ) , :: std:: io:: Error > {
1706
+ let encoding_len: u16 = 1 + self . short_channel_ids . len ( ) as u16 * 8 ;
1707
+ w. size_hint ( 32 + 4 + 4 + 1 + 2 + encoding_len as usize ) ;
1708
+ self . chain_hash . write ( w) ?;
1709
+ self . first_blocknum . write ( w) ?;
1710
+ self . number_of_blocks . write ( w) ?;
1711
+ self . full_information . write ( w) ?;
1712
+
1713
+ encoding_len. write ( w) ?;
1714
+ ( EncodingType :: Uncompressed as u8 ) . write ( w) ?;
1715
+ for scid in self . short_channel_ids . iter ( ) {
1716
+ scid. write ( w) ?;
1717
+ }
1718
+
1719
+ Ok ( ( ) )
1720
+ }
1721
+ }
1722
+
1723
+ impl Readable for GossipTimestampFilter {
1724
+ fn read < R : Read > ( r : & mut R ) -> Result < Self , DecodeError > {
1725
+ let chain_hash: BlockHash = Readable :: read ( r) ?;
1726
+ let first_timestamp: u32 = Readable :: read ( r) ?;
1727
+ let timestamp_range: u32 = Readable :: read ( r) ?;
1728
+ Ok ( GossipTimestampFilter {
1729
+ chain_hash,
1730
+ first_timestamp,
1731
+ timestamp_range,
1732
+ } )
1733
+ }
1734
+ }
1735
+
1736
+ impl Writeable for GossipTimestampFilter {
1737
+ fn write < W : Writer > ( & self , w : & mut W ) -> Result < ( ) , :: std:: io:: Error > {
1738
+ w. size_hint ( 32 + 4 + 4 ) ;
1739
+ self . chain_hash . write ( w) ?;
1740
+ self . first_timestamp . write ( w) ?;
1741
+ self . timestamp_range . write ( w) ?;
1742
+ Ok ( ( ) )
1743
+ }
1744
+ }
1745
+
1746
+
1518
1747
#[ cfg( test) ]
1519
1748
mod tests {
1520
1749
use hex;
@@ -2246,4 +2475,122 @@ mod tests {
2246
2475
assert_eq ! ( msg. amt_to_forward, 0x0badf00d01020304 ) ;
2247
2476
assert_eq ! ( msg. outgoing_cltv_value, 0xffffffff ) ;
2248
2477
}
2478
+
2479
+ #[ test]
2480
+ fn encoding_query_channel_range ( ) {
2481
+ let mut query_channel_range = msgs:: QueryChannelRange {
2482
+ chain_hash : BlockHash :: from_hex ( "06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f" ) . unwrap ( ) ,
2483
+ first_blocknum : 100000 ,
2484
+ number_of_blocks : 1500 ,
2485
+ } ;
2486
+ let encoded_value = query_channel_range. encode ( ) ;
2487
+ let target_value = hex:: decode ( "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206000186a0000005dc" ) . unwrap ( ) ;
2488
+ assert_eq ! ( encoded_value, target_value) ;
2489
+
2490
+ query_channel_range = Readable :: read ( & mut Cursor :: new ( & target_value[ ..] ) ) . unwrap ( ) ;
2491
+ assert_eq ! ( query_channel_range. first_blocknum, 100000 ) ;
2492
+ assert_eq ! ( query_channel_range. number_of_blocks, 1500 ) ;
2493
+ }
2494
+
2495
+ #[ test]
2496
+ fn encoding_reply_channel_range ( ) {
2497
+ do_encoding_reply_channel_range ( 0 ) ;
2498
+ do_encoding_reply_channel_range ( 1 ) ;
2499
+ }
2500
+
2501
+ fn do_encoding_reply_channel_range ( encoding_type : u8 ) {
2502
+ let mut target_value = hex:: decode ( "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206000b8a06000005dc01" ) . unwrap ( ) ;
2503
+ let expected_chain_hash = BlockHash :: from_hex ( "06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f" ) . unwrap ( ) ;
2504
+ let mut reply_channel_range = msgs:: ReplyChannelRange {
2505
+ chain_hash : expected_chain_hash,
2506
+ first_blocknum : 756230 ,
2507
+ number_of_blocks : 1500 ,
2508
+ full_information : true ,
2509
+ short_channel_ids : vec ! [ 0x000000000000008e , 0x0000000000003c69 , 0x000000000045a6c4 ] ,
2510
+ } ;
2511
+
2512
+ if encoding_type == 0 {
2513
+ target_value. append ( & mut hex:: decode ( "001900000000000000008e0000000000003c69000000000045a6c4" ) . unwrap ( ) ) ;
2514
+ let encoded_value = reply_channel_range. encode ( ) ;
2515
+ assert_eq ! ( encoded_value, target_value) ;
2516
+
2517
+ reply_channel_range = Readable :: read ( & mut Cursor :: new ( & target_value[ ..] ) ) . unwrap ( ) ;
2518
+ assert_eq ! ( reply_channel_range. chain_hash, expected_chain_hash) ;
2519
+ assert_eq ! ( reply_channel_range. first_blocknum, 756230 ) ;
2520
+ assert_eq ! ( reply_channel_range. number_of_blocks, 1500 ) ;
2521
+ assert_eq ! ( reply_channel_range. full_information, true ) ;
2522
+ assert_eq ! ( reply_channel_range. short_channel_ids[ 0 ] , 0x000000000000008e ) ;
2523
+ assert_eq ! ( reply_channel_range. short_channel_ids[ 1 ] , 0x0000000000003c69 ) ;
2524
+ assert_eq ! ( reply_channel_range. short_channel_ids[ 2 ] , 0x000000000045a6c4 ) ;
2525
+ } else {
2526
+ target_value. append ( & mut hex:: decode ( "001601789c636000833e08659309a65878be010010a9023a" ) . unwrap ( ) ) ;
2527
+ let result: Result < msgs:: ReplyChannelRange , msgs:: DecodeError > = Readable :: read ( & mut Cursor :: new ( & target_value[ ..] ) ) ;
2528
+ assert ! ( result. is_err( ) , "Expected decode failure with unsupported zlib encoding" ) ;
2529
+ }
2530
+ }
2531
+
2532
+ #[ test]
2533
+ fn encoding_query_short_channel_ids ( ) {
2534
+ do_encoding_query_short_channel_ids ( 0 ) ;
2535
+ do_encoding_query_short_channel_ids ( 1 ) ;
2536
+ }
2537
+
2538
+ fn do_encoding_query_short_channel_ids ( encoding_type : u8 ) {
2539
+ let mut target_value = hex:: decode ( "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206" ) . unwrap ( ) ;
2540
+ let expected_chain_hash = BlockHash :: from_hex ( "06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f" ) . unwrap ( ) ;
2541
+ let mut query_short_channel_ids = msgs:: QueryShortChannelIds {
2542
+ chain_hash : expected_chain_hash,
2543
+ short_channel_ids : vec ! [ 0x0000000000008e , 0x0000000000003c69 , 0x000000000045a6c4 ] ,
2544
+ } ;
2545
+
2546
+ if encoding_type == 0 {
2547
+ target_value. append ( & mut hex:: decode ( "001900000000000000008e0000000000003c69000000000045a6c4" ) . unwrap ( ) ) ;
2548
+ let encoded_value = query_short_channel_ids. encode ( ) ;
2549
+ assert_eq ! ( encoded_value, target_value) ;
2550
+
2551
+ query_short_channel_ids = Readable :: read ( & mut Cursor :: new ( & target_value[ ..] ) ) . unwrap ( ) ;
2552
+ assert_eq ! ( query_short_channel_ids. chain_hash, expected_chain_hash) ;
2553
+ assert_eq ! ( query_short_channel_ids. short_channel_ids[ 0 ] , 0x000000000000008e ) ;
2554
+ assert_eq ! ( query_short_channel_ids. short_channel_ids[ 1 ] , 0x0000000000003c69 ) ;
2555
+ assert_eq ! ( query_short_channel_ids. short_channel_ids[ 2 ] , 0x000000000045a6c4 ) ;
2556
+ } else {
2557
+ target_value. append ( & mut hex:: decode ( "001601789c636000833e08659309a65878be010010a9023a" ) . unwrap ( ) ) ;
2558
+ let result: Result < msgs:: QueryShortChannelIds , msgs:: DecodeError > = Readable :: read ( & mut Cursor :: new ( & target_value[ ..] ) ) ;
2559
+ assert ! ( result. is_err( ) , "Expected decode failure with unsupported zlib encoding" ) ;
2560
+ }
2561
+ }
2562
+
2563
+ #[ test]
2564
+ fn encoding_reply_short_channel_ids_end ( ) {
2565
+ let expected_chain_hash = BlockHash :: from_hex ( "06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f" ) . unwrap ( ) ;
2566
+ let mut reply_short_channel_ids_end = msgs:: ReplyShortChannelIdsEnd {
2567
+ chain_hash : expected_chain_hash,
2568
+ full_information : true ,
2569
+ } ;
2570
+ let encoded_value = reply_short_channel_ids_end. encode ( ) ;
2571
+ let target_value = hex:: decode ( "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e220601" ) . unwrap ( ) ;
2572
+ assert_eq ! ( encoded_value, target_value) ;
2573
+
2574
+ reply_short_channel_ids_end = Readable :: read ( & mut Cursor :: new ( & target_value[ ..] ) ) . unwrap ( ) ;
2575
+ assert_eq ! ( reply_short_channel_ids_end. chain_hash, expected_chain_hash) ;
2576
+ assert_eq ! ( reply_short_channel_ids_end. full_information, true ) ;
2577
+ }
2578
+
2579
+ #[ test]
2580
+ fn encoding_gossip_timestamp_filter ( ) {
2581
+ let expected_chain_hash = BlockHash :: from_hex ( "06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f" ) . unwrap ( ) ;
2582
+ let mut gossip_timestamp_filter = msgs:: GossipTimestampFilter {
2583
+ chain_hash : expected_chain_hash,
2584
+ first_timestamp : 1590000000 ,
2585
+ timestamp_range : 0xffff_ffff ,
2586
+ } ;
2587
+ let encoded_value = gossip_timestamp_filter. encode ( ) ;
2588
+ let target_value = hex:: decode ( "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e22065ec57980ffffffff" ) . unwrap ( ) ;
2589
+ assert_eq ! ( encoded_value, target_value) ;
2590
+
2591
+ gossip_timestamp_filter = Readable :: read ( & mut Cursor :: new ( & target_value[ ..] ) ) . unwrap ( ) ;
2592
+ assert_eq ! ( gossip_timestamp_filter. chain_hash, expected_chain_hash) ;
2593
+ assert_eq ! ( gossip_timestamp_filter. first_timestamp, 1590000000 ) ;
2594
+ assert_eq ! ( gossip_timestamp_filter. timestamp_range, 0xffff_ffff ) ;
2595
+ }
2249
2596
}
0 commit comments