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