From b991c413cd2b4f292b3617f5171661d45acafb7d Mon Sep 17 00:00:00 2001 From: Deirdre Connolly Date: Fri, 4 Oct 2019 01:45:59 -0400 Subject: [PATCH] Parse GetBlock messages --- zebra-network/src/protocol/codec.rs | 25 ++++++++++++++++----- zebra-network/src/protocol/message.rs | 32 +++++++++++++++++++++++++-- 2 files changed, 50 insertions(+), 7 deletions(-) diff --git a/zebra-network/src/protocol/codec.rs b/zebra-network/src/protocol/codec.rs index 9cdaad25..3e73a8cf 100644 --- a/zebra-network/src/protocol/codec.rs +++ b/zebra-network/src/protocol/codec.rs @@ -9,7 +9,7 @@ use failure::Error; use tokio::codec::{Decoder, Encoder}; use zebra_chain::{ - block::BlockHeader, + block::{BlockHeader, BlockHeaderHash}, serialization::{ReadZcashExt, WriteZcashExt, ZcashDeserialize, ZcashSerialize}, transaction::Transaction, types::{BlockHeight, Sha256dChecksum}, @@ -417,9 +417,24 @@ impl Codec { bail!("unimplemented message type") } - fn read_getblocks(&self, mut _reader: R) -> Result { - trace!("getblocks"); - bail!("unimplemented message type") + fn read_getblocks(&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::GetBlocks { + version, + block_locator_hashes, + hash_stop, + }) } /// Deserialize a `headers` message. @@ -458,7 +473,7 @@ impl Codec { ) -> Result, Error> { 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 diff --git a/zebra-network/src/protocol/message.rs b/zebra-network/src/protocol/message.rs index 3d0d4b12..f855f021 100644 --- a/zebra-network/src/protocol/message.rs +++ b/zebra-network/src/protocol/message.rs @@ -4,7 +4,7 @@ use std::net; use chrono::{DateTime, Utc}; -use zebra_chain::block::{Block, BlockHeader}; +use zebra_chain::block::{Block, BlockHeader, BlockHeaderHash}; use zebra_chain::{transaction::Transaction, types::BlockHeight}; use crate::meta_addr::MetaAddr; @@ -144,8 +144,36 @@ pub enum Message { /// A `getblocks` message. /// + /// Requests the list of blocks starting right after the last + /// known hash in `block_locator_hashes`, up to `hash_stop` or 500 + /// 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#getblocks) - GetBlocks {/* XXX add fields */}, + // The locator hashes are processed by a node in the order as they + // appear in the message. If a block hash is found in the node's + // main chain, the list of its children is returned back via the + // inv message and the remaining locators are ignored, no matter + // if the requested limit was reached, or not. + GetBlocks { + /// The protocol version. + version: Version, + + /// Block locators, from newest back to genesis block. + block_locator_hashes: Vec, + + /// `BlockHeaderHash` of the last desired block. + /// + /// Set to zero to get as many blocks as possible (500). + hash_stop: BlockHeaderHash, + }, /// A `headers` message. ///