Skip to content

Commit ec344b3

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 ec344b3

File tree

1 file changed

+353
-0
lines changed

1 file changed

+353
-0
lines changed

lightning/src/ln/msgs.rs

Lines changed: 353 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(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(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(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(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(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,170 @@ 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 encoding_len: u16 = Readable::read(r)?;
1594+
if encoding_len == 0 || (encoding_len - 1) % 8 != 0 {
1595+
return Err(DecodeError::InvalidValue);
1596+
}
1597+
1598+
let encoding_type: u8 = Readable::read(r)?;
1599+
if encoding_type != EncodingType::Uncompressed as u8 {
1600+
return Err(DecodeError::InvalidValue);
1601+
}
1602+
1603+
let mut short_channel_ids = vec![];
1604+
let mut read_remaining = encoding_len - 1;
1605+
while read_remaining > 0 {
1606+
short_channel_ids.push(Readable::read(r)?);
1607+
read_remaining -= 8;
1608+
}
1609+
1610+
Ok(QueryShortChannelIds {
1611+
chain_hash,
1612+
short_channel_ids,
1613+
})
1614+
}
1615+
}
1616+
1617+
impl Writeable for QueryShortChannelIds {
1618+
fn write<W: Writer>(&self, w: &mut W) -> Result<(), ::std::io::Error> {
1619+
let encoding_len: u16 = 1 + self.short_channel_ids.len() as u16 * 8;
1620+
w.size_hint(32 + 2 + encoding_len as usize);
1621+
self.chain_hash.write(w)?;
1622+
1623+
encoding_len.write(w)?;
1624+
(EncodingType::Uncompressed as u8).write(w)?;
1625+
for scid in self.short_channel_ids.iter() {
1626+
scid.write(w)?;
1627+
}
1628+
1629+
Ok(())
1630+
}
1631+
}
1632+
1633+
impl Readable for ReplyShortChannelIdsEnd {
1634+
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
1635+
let chain_hash: BlockHash = Readable::read(r)?;
1636+
let full_information: bool = Readable::read(r)?;
1637+
Ok(ReplyShortChannelIdsEnd {
1638+
chain_hash,
1639+
full_information,
1640+
})
1641+
}
1642+
}
1643+
1644+
impl Writeable for ReplyShortChannelIdsEnd {
1645+
fn write<W: Writer>(&self, w: &mut W) -> Result<(), ::std::io::Error> {
1646+
w.size_hint(32 + 1);
1647+
self.chain_hash.write(w)?;
1648+
self.full_information.write(w)?;
1649+
Ok(())
1650+
}
1651+
}
1652+
1653+
impl Readable for QueryChannelRange {
1654+
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
1655+
let chain_hash: BlockHash = Readable::read(r)?;
1656+
let first_blocknum: u32 = Readable::read(r)?;
1657+
let number_of_blocks: u32 = Readable::read(r)?;
1658+
Ok(QueryChannelRange {
1659+
chain_hash,
1660+
first_blocknum,
1661+
number_of_blocks
1662+
})
1663+
}
1664+
}
1665+
1666+
impl Writeable for QueryChannelRange {
1667+
fn write<W: Writer>(&self, w: &mut W) -> Result<(), ::std::io::Error> {
1668+
w.size_hint(32 + 4 + 4);
1669+
self.chain_hash.write(w)?;
1670+
self.first_blocknum.write(w)?;
1671+
self.number_of_blocks.write(w)?;
1672+
Ok(())
1673+
}
1674+
}
1675+
1676+
impl Readable for ReplyChannelRange {
1677+
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
1678+
let chain_hash: BlockHash = Readable::read(r)?;
1679+
let first_blocknum: u32 = Readable::read(r)?;
1680+
let number_of_blocks: u32 = Readable::read(r)?;
1681+
let full_information: bool = Readable::read(r)?;
1682+
1683+
let encoding_len: u16 = Readable::read(r)?;
1684+
if encoding_len == 0 || (encoding_len - 1) % 8 != 0 {
1685+
return Err(DecodeError::InvalidValue);
1686+
}
1687+
1688+
let encoding_type: u8 = Readable::read(r)?;
1689+
if encoding_type != EncodingType::Uncompressed as u8 {
1690+
return Err(DecodeError::InvalidValue);
1691+
}
1692+
1693+
let mut short_channel_ids = vec![];
1694+
let mut read_remaining = encoding_len - 1;
1695+
while read_remaining > 0 {
1696+
short_channel_ids.push(Readable::read(r)?);
1697+
read_remaining -= 8;
1698+
}
1699+
1700+
Ok(ReplyChannelRange {
1701+
chain_hash,
1702+
first_blocknum,
1703+
number_of_blocks,
1704+
full_information,
1705+
short_channel_ids
1706+
})
1707+
}
1708+
}
1709+
1710+
impl Writeable for ReplyChannelRange {
1711+
fn write<W: Writer>(&self, w: &mut W) -> Result<(), ::std::io::Error> {
1712+
let encoding_len: u16 = 1 + self.short_channel_ids.len() as u16 * 8;
1713+
w.size_hint(32 + 4 + 4 + 1 + 2 + encoding_len as usize);
1714+
self.chain_hash.write(w)?;
1715+
self.first_blocknum.write(w)?;
1716+
self.number_of_blocks.write(w)?;
1717+
self.full_information.write(w)?;
1718+
1719+
encoding_len.write(w)?;
1720+
(EncodingType::Uncompressed as u8).write(w)?;
1721+
for scid in self.short_channel_ids.iter() {
1722+
scid.write(w)?;
1723+
}
1724+
1725+
Ok(())
1726+
}
1727+
}
1728+
1729+
impl Readable for GossipTimestampFilter {
1730+
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
1731+
let chain_hash: BlockHash = Readable::read(r)?;
1732+
let first_timestamp: u32 = Readable::read(r)?;
1733+
let timestamp_range: u32 = Readable::read(r)?;
1734+
Ok(GossipTimestampFilter {
1735+
chain_hash,
1736+
first_timestamp,
1737+
timestamp_range,
1738+
})
1739+
}
1740+
}
1741+
1742+
impl Writeable for GossipTimestampFilter {
1743+
fn write<W: Writer>(&self, w: &mut W) -> Result<(), ::std::io::Error> {
1744+
w.size_hint(32 + 4 + 4);
1745+
self.chain_hash.write(w)?;
1746+
self.first_timestamp.write(w)?;
1747+
self.timestamp_range.write(w)?;
1748+
Ok(())
1749+
}
1750+
}
1751+
1752+
15181753
#[cfg(test)]
15191754
mod tests {
15201755
use hex;
@@ -2246,4 +2481,122 @@ mod tests {
22462481
assert_eq!(msg.amt_to_forward, 0x0badf00d01020304);
22472482
assert_eq!(msg.outgoing_cltv_value, 0xffffffff);
22482483
}
2484+
2485+
#[test]
2486+
fn encoding_query_channel_range() {
2487+
let mut query_channel_range = msgs::QueryChannelRange {
2488+
chain_hash: BlockHash::from_hex("06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f").unwrap(),
2489+
first_blocknum: 100000,
2490+
number_of_blocks: 1500,
2491+
};
2492+
let encoded_value = query_channel_range.encode();
2493+
let target_value = hex::decode("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206000186a0000005dc").unwrap();
2494+
assert_eq!(encoded_value, target_value);
2495+
2496+
query_channel_range = Readable::read(&mut Cursor::new(&target_value[..])).unwrap();
2497+
assert_eq!(query_channel_range.first_blocknum, 100000);
2498+
assert_eq!(query_channel_range.number_of_blocks, 1500);
2499+
}
2500+
2501+
#[test]
2502+
fn encoding_reply_channel_range() {
2503+
do_encoding_reply_channel_range(0);
2504+
do_encoding_reply_channel_range(1);
2505+
}
2506+
2507+
fn do_encoding_reply_channel_range(encoding_type: u8) {
2508+
let mut target_value = hex::decode("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206000b8a06000005dc01").unwrap();
2509+
let expected_chain_hash = BlockHash::from_hex("06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f").unwrap();
2510+
let mut reply_channel_range = msgs::ReplyChannelRange {
2511+
chain_hash: expected_chain_hash,
2512+
first_blocknum: 756230,
2513+
number_of_blocks: 1500,
2514+
full_information: true,
2515+
short_channel_ids: vec![0x000000000000008e, 0x0000000000003c69, 0x000000000045a6c4],
2516+
};
2517+
2518+
if encoding_type == 0 {
2519+
target_value.append(&mut hex::decode("001900000000000000008e0000000000003c69000000000045a6c4").unwrap());
2520+
let encoded_value = reply_channel_range.encode();
2521+
assert_eq!(encoded_value, target_value);
2522+
2523+
reply_channel_range = Readable::read(&mut Cursor::new(&target_value[..])).unwrap();
2524+
assert_eq!(reply_channel_range.chain_hash, expected_chain_hash);
2525+
assert_eq!(reply_channel_range.first_blocknum, 756230);
2526+
assert_eq!(reply_channel_range.number_of_blocks, 1500);
2527+
assert_eq!(reply_channel_range.full_information, true);
2528+
assert_eq!(reply_channel_range.short_channel_ids[0], 0x000000000000008e);
2529+
assert_eq!(reply_channel_range.short_channel_ids[1], 0x0000000000003c69);
2530+
assert_eq!(reply_channel_range.short_channel_ids[2], 0x000000000045a6c4);
2531+
} else {
2532+
target_value.append(&mut hex::decode("001601789c636000833e08659309a65878be010010a9023a").unwrap());
2533+
let result: Result<msgs::ReplyChannelRange, msgs::DecodeError> = Readable::read(&mut Cursor::new(&target_value[..]));
2534+
assert!(result.is_err(), "Expected decode failure with unsupported zlib encoding");
2535+
}
2536+
}
2537+
2538+
#[test]
2539+
fn encoding_query_short_channel_ids() {
2540+
do_encoding_query_short_channel_ids(0);
2541+
do_encoding_query_short_channel_ids(1);
2542+
}
2543+
2544+
fn do_encoding_query_short_channel_ids(encoding_type: u8) {
2545+
let mut target_value = hex::decode("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206").unwrap();
2546+
let expected_chain_hash = BlockHash::from_hex("06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f").unwrap();
2547+
let mut query_short_channel_ids = msgs::QueryShortChannelIds {
2548+
chain_hash: expected_chain_hash,
2549+
short_channel_ids: vec![0x0000000000008e, 0x0000000000003c69, 0x000000000045a6c4],
2550+
};
2551+
2552+
if encoding_type == 0 {
2553+
target_value.append(&mut hex::decode("001900000000000000008e0000000000003c69000000000045a6c4").unwrap());
2554+
let encoded_value = query_short_channel_ids.encode();
2555+
assert_eq!(encoded_value, target_value);
2556+
2557+
query_short_channel_ids = Readable::read(&mut Cursor::new(&target_value[..])).unwrap();
2558+
assert_eq!(query_short_channel_ids.chain_hash, expected_chain_hash);
2559+
assert_eq!(query_short_channel_ids.short_channel_ids[0], 0x000000000000008e);
2560+
assert_eq!(query_short_channel_ids.short_channel_ids[1], 0x0000000000003c69);
2561+
assert_eq!(query_short_channel_ids.short_channel_ids[2], 0x000000000045a6c4);
2562+
} else {
2563+
target_value.append(&mut hex::decode("001601789c636000833e08659309a65878be010010a9023a").unwrap());
2564+
let result: Result<msgs::QueryShortChannelIds, msgs::DecodeError> = Readable::read(&mut Cursor::new(&target_value[..]));
2565+
assert!(result.is_err(), "Expected decode failure with unsupported zlib encoding");
2566+
}
2567+
}
2568+
2569+
#[test]
2570+
fn encoding_reply_short_channel_ids_end() {
2571+
let expected_chain_hash = BlockHash::from_hex("06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f").unwrap();
2572+
let mut reply_short_channel_ids_end = msgs::ReplyShortChannelIdsEnd {
2573+
chain_hash: expected_chain_hash,
2574+
full_information: true,
2575+
};
2576+
let encoded_value = reply_short_channel_ids_end.encode();
2577+
let target_value = hex::decode("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e220601").unwrap();
2578+
assert_eq!(encoded_value, target_value);
2579+
2580+
reply_short_channel_ids_end = Readable::read(&mut Cursor::new(&target_value[..])).unwrap();
2581+
assert_eq!(reply_short_channel_ids_end.chain_hash, expected_chain_hash);
2582+
assert_eq!(reply_short_channel_ids_end.full_information, true);
2583+
}
2584+
2585+
#[test]
2586+
fn encoding_gossip_timestamp_filter(){
2587+
let expected_chain_hash = BlockHash::from_hex("06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f").unwrap();
2588+
let mut gossip_timestamp_filter = msgs::GossipTimestampFilter {
2589+
chain_hash: expected_chain_hash,
2590+
first_timestamp: 1590000000,
2591+
timestamp_range: 0xffff_ffff,
2592+
};
2593+
let encoded_value = gossip_timestamp_filter.encode();
2594+
let target_value = hex::decode("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e22065ec57980ffffffff").unwrap();
2595+
assert_eq!(encoded_value, target_value);
2596+
2597+
gossip_timestamp_filter = Readable::read(&mut Cursor::new(&target_value[..])).unwrap();
2598+
assert_eq!(gossip_timestamp_filter.chain_hash, expected_chain_hash);
2599+
assert_eq!(gossip_timestamp_filter.first_timestamp, 1590000000);
2600+
assert_eq!(gossip_timestamp_filter.timestamp_range, 0xffff_ffff);
2601+
}
22492602
}

0 commit comments

Comments
 (0)