Skip to content

Commit 9b88d5f

Browse files
committed
Adding gossip_queries message structs and serialization.
This adds the message structs and implements Readable and Writeable traits for the standard gossip_queries messages.
1 parent 3defcc8 commit 9b88d5f

File tree

1 file changed

+347
-0
lines changed

1 file changed

+347
-0
lines changed

lightning/src/ln/msgs.rs

Lines changed: 347 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,77 @@ pub struct ChannelUpdate {
570570
pub contents: UnsignedChannelUpdate,
571571
}
572572

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+
573644
/// Used to put an error message in a LightningError
574645
#[derive(Clone)]
575646
pub enum ErrorAction {
@@ -1515,6 +1586,164 @@ impl_writeable_len_match!(NodeAnnouncement, {
15151586
contents
15161587
});
15171588

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+
15181747
#[cfg(test)]
15191748
mod tests {
15201749
use hex;
@@ -2246,4 +2475,122 @@ mod tests {
22462475
assert_eq!(msg.amt_to_forward, 0x0badf00d01020304);
22472476
assert_eq!(msg.outgoing_cltv_value, 0xffffffff);
22482477
}
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+
}
22492596
}

0 commit comments

Comments
 (0)