From 7049f9d8918c8ddf212f97d274aa7ff1901b96db Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Sat, 8 Feb 2020 10:49:35 -0800 Subject: [PATCH] Add a FindBlocks request to get initial block hashes. Bitcoin does this either with `getblocks` (returns up to 500 following block hashes) or `getheaders` (returns up to 2000 following block headers, not just hashes). However, Bitcoin headers are much smaller than Zcash headers, which contain a giant Equihash solution block, and many Zcash blocks don't have many transactions in them, so the block header is often similarly sized to the block itself. Because we're aiming to have a highly parallel network layer, it seems better to use `getblocks` to implement `FindBlocks` (which is necessarily sequential) and parallelize the processing of the block downloads. --- zebra-network/src/peer/connection.rs | 30 ++++++++++++++++++- zebra-network/src/peer/error.rs | 2 +- .../src/protocol/internal/request.rs | 9 ++++++ .../src/protocol/internal/response.rs | 7 +++-- zebrad/src/commands/connect.rs | 9 ++++++ 5 files changed, 53 insertions(+), 4 deletions(-) diff --git a/zebra-network/src/peer/connection.rs b/zebra-network/src/peer/connection.rs index 39c14d9d3..3f4b0bf13 100644 --- a/zebra-network/src/peer/connection.rs +++ b/zebra-network/src/peer/connection.rs @@ -18,7 +18,7 @@ use zebra_chain::{ use crate::{ constants, protocol::{ - external::{types::Nonce, Message}, + external::{types::Nonce, InventoryHash, Message}, internal::{Request, Response}, }, BoxedStdError, @@ -35,6 +35,7 @@ pub(super) enum Handler { hashes: HashSet, blocks: Vec, }, + FindBlocks, } impl Handler { @@ -81,6 +82,15 @@ impl Handler { Finished(Err(Arc::new(PeerError::WrongBlock).into())) } } + (FindBlocks, Message::Inv(inv_hashes)) => Finished(Ok(Response::BlockHeaderHashes( + inv_hashes + .into_iter() + .filter_map(|inv| match inv { + InventoryHash::Block(hash) => Some(hash), + _ => None, + }) + .collect(), + ))), // By default, messages are not responses. (state, msg) => { ignored_msg = Some(msg); @@ -317,6 +327,15 @@ where tx, ) }), + (AwaitingRequest, FindBlocks { known_blocks, stop }) => self + .peer_tx + .send(Message::GetBlocks { + block_locator_hashes: known_blocks, + hash_stop: stop.unwrap_or(BlockHeaderHash([0; 32])), + }) + .await + .map_err(|e| e.into()) + .map(|()| AwaitingResponse(Handler::FindBlocks, tx)), } { Ok(new_state) => { self.state = new_state; @@ -421,6 +440,15 @@ where } } } + Response::BlockHeaderHashes(hashes) => { + if let Err(e) = self + .peer_tx + .send(Message::Inv(hashes.into_iter().map(Into::into).collect())) + .await + { + self.fail_with(e.into()) + } + } } } } diff --git a/zebra-network/src/peer/error.rs b/zebra-network/src/peer/error.rs index f5cb15f10..fad924da6 100644 --- a/zebra-network/src/peer/error.rs +++ b/zebra-network/src/peer/error.rs @@ -2,7 +2,7 @@ use std::sync::{Arc, Mutex}; use thiserror::Error; -use zebra_chain::{serialization::SerializationError}; +use zebra_chain::serialization::SerializationError; /// A wrapper around `Arc` that implements `Error`. #[derive(Error, Debug, Clone)] diff --git a/zebra-network/src/protocol/internal/request.rs b/zebra-network/src/protocol/internal/request.rs index 990fd592c..b6f495bb1 100644 --- a/zebra-network/src/protocol/internal/request.rs +++ b/zebra-network/src/protocol/internal/request.rs @@ -28,4 +28,13 @@ pub enum Request { /// didn't start with a `Vec` but with, e.g., an iterator, they can collect /// directly into a `HashSet` and save work. BlocksByHash(HashSet), + + /// Request block hashes of subsequent blocks in the chain, giving hashes of + /// known blocks. + FindBlocks { + /// Hashes of known blocks, ordered from highest height to lowest height. + known_blocks: Vec, + /// Optionally, the last header to request. + stop: Option, + }, } diff --git a/zebra-network/src/protocol/internal/response.rs b/zebra-network/src/protocol/internal/response.rs index 6a35cee1b..b7ca82aad 100644 --- a/zebra-network/src/protocol/internal/response.rs +++ b/zebra-network/src/protocol/internal/response.rs @@ -1,5 +1,5 @@ // XXX clean module layout of zebra_chain -use zebra_chain::block::Block; +use zebra_chain::block::{Block, BlockHeaderHash}; use crate::meta_addr::MetaAddr; @@ -14,4 +14,7 @@ pub enum Response { /// A list of blocks. Blocks(Vec), -} \ No newline at end of file + + /// A list of block hashes. + BlockHeaderHashes(Vec), +} diff --git a/zebrad/src/commands/connect.rs b/zebrad/src/commands/connect.rs index 6db13e965..731ebfd53 100644 --- a/zebrad/src/commands/connect.rs +++ b/zebrad/src/commands/connect.rs @@ -112,6 +112,15 @@ impl ConnectCmd { info!(?rsp); } + peer_set.ready().await.unwrap(); + let mut rsp = peer_set + .call(Request::FindBlocks { + known_blocks: Vec::new(), + stop: None, + }) + .await; + info!(?rsp); + let eternity = future::pending::<()>(); eternity.await;