diff --git a/zebra-network/src/protocol/codec.rs b/zebra-network/src/protocol/codec.rs index 3e73a8cf..3e5455da 100644 --- a/zebra-network/src/protocol/codec.rs +++ b/zebra-network/src/protocol/codec.rs @@ -445,7 +445,7 @@ impl Codec { fn read_headers(&self, mut reader: R) -> Result { let count = reader.read_compactsize()? as usize; // Preallocate a buffer, performing a single allocation in the honest - // case. Although the size of the recieved data buffer is bounded by the + // case. Although the size of the received data buffer is bounded by the // codec's max_len field, it's still possible for someone to send a // short message with a large count field, so if we naively trust // the count field we could be tricked into preallocating a large @@ -462,9 +462,25 @@ impl Codec { Ok(Message::Headers(headers)) } - fn read_getheaders(&self, mut _reader: R) -> Result { - trace!("getheaders"); - bail!("unimplemented message type") + // XXX This and `read_getblocks` are pretty similar, abstract away? + fn read_getheaders(&self, mut reader: R) -> Result { + let version = Version(reader.read_u32::()?); + + let count = reader.read_compactsize()? as usize; + let max_count = self.builder.max_len / 32; + let mut block_locator_hashes = Vec::with_capacity(std::cmp::min(count, max_count)); + + for _ in 0..count { + block_locator_hashes.push(BlockHeaderHash(reader.read_32_bytes()?)); + } + + let hash_stop = BlockHeaderHash(reader.read_32_bytes()?); + + Ok(Message::GetHeaders { + version, + block_locator_hashes, + hash_stop, + }) } fn _read_generic_inventory_hash_vector( diff --git a/zebra-network/src/protocol/message.rs b/zebra-network/src/protocol/message.rs index f855f021..b7610e1e 100644 --- a/zebra-network/src/protocol/message.rs +++ b/zebra-network/src/protocol/message.rs @@ -188,8 +188,31 @@ pub enum Message { /// A `getheaders` message. /// + /// Requests a series of block headers starting right after the + /// last known hash in `block_locator_hashes`, up to `hash_stop` + /// or 2000 blocks, whichever comes first. + /// + /// You can send in fewer known hashes down to a minimum of just + /// one hash. However, the purpose of the block locator object is + /// to detect a wrong branch in the caller's main chain. If the + /// peer detects that you are off the main chain, it will send in + /// block hashes which are earlier than your last known block. So + /// if you just send in your last known hash and it is off the + /// main chain, the peer starts over at block #1. + /// /// [Bitcoin reference](https://en.bitcoin.it/wiki/Protocol_documentation#getheaders) - GetHeaders {/* XXX add fields */}, + GetHeaders { + /// The protocol version. + version: Version, + + /// Block locators, from newest back to genesis block. + block_locator_hashes: Vec, + + /// `BlockHeaderHash` of the last desired block header. + /// + /// Set to zero to get as many block headers as possible (2000). + hash_stop: BlockHeaderHash, + }, /// An `inv` message. ///