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.
This commit is contained in:
parent
47cafc630f
commit
7049f9d891
|
@ -18,7 +18,7 @@ use zebra_chain::{
|
||||||
use crate::{
|
use crate::{
|
||||||
constants,
|
constants,
|
||||||
protocol::{
|
protocol::{
|
||||||
external::{types::Nonce, Message},
|
external::{types::Nonce, InventoryHash, Message},
|
||||||
internal::{Request, Response},
|
internal::{Request, Response},
|
||||||
},
|
},
|
||||||
BoxedStdError,
|
BoxedStdError,
|
||||||
|
@ -35,6 +35,7 @@ pub(super) enum Handler {
|
||||||
hashes: HashSet<BlockHeaderHash>,
|
hashes: HashSet<BlockHeaderHash>,
|
||||||
blocks: Vec<Block>,
|
blocks: Vec<Block>,
|
||||||
},
|
},
|
||||||
|
FindBlocks,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Handler {
|
impl Handler {
|
||||||
|
@ -81,6 +82,15 @@ impl Handler {
|
||||||
Finished(Err(Arc::new(PeerError::WrongBlock).into()))
|
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.
|
// By default, messages are not responses.
|
||||||
(state, msg) => {
|
(state, msg) => {
|
||||||
ignored_msg = Some(msg);
|
ignored_msg = Some(msg);
|
||||||
|
@ -317,6 +327,15 @@ where
|
||||||
tx,
|
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) => {
|
Ok(new_state) => {
|
||||||
self.state = 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())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use zebra_chain::{serialization::SerializationError};
|
use zebra_chain::serialization::SerializationError;
|
||||||
|
|
||||||
/// A wrapper around `Arc<PeerError>` that implements `Error`.
|
/// A wrapper around `Arc<PeerError>` that implements `Error`.
|
||||||
#[derive(Error, Debug, Clone)]
|
#[derive(Error, Debug, Clone)]
|
||||||
|
|
|
@ -28,4 +28,13 @@ pub enum Request {
|
||||||
/// didn't start with a `Vec` but with, e.g., an iterator, they can collect
|
/// didn't start with a `Vec` but with, e.g., an iterator, they can collect
|
||||||
/// directly into a `HashSet` and save work.
|
/// directly into a `HashSet` and save work.
|
||||||
BlocksByHash(HashSet<BlockHeaderHash>),
|
BlocksByHash(HashSet<BlockHeaderHash>),
|
||||||
|
|
||||||
|
/// 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<BlockHeaderHash>,
|
||||||
|
/// Optionally, the last header to request.
|
||||||
|
stop: Option<BlockHeaderHash>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// XXX clean module layout of zebra_chain
|
// XXX clean module layout of zebra_chain
|
||||||
use zebra_chain::block::Block;
|
use zebra_chain::block::{Block, BlockHeaderHash};
|
||||||
|
|
||||||
use crate::meta_addr::MetaAddr;
|
use crate::meta_addr::MetaAddr;
|
||||||
|
|
||||||
|
@ -14,4 +14,7 @@ pub enum Response {
|
||||||
|
|
||||||
/// A list of blocks.
|
/// A list of blocks.
|
||||||
Blocks(Vec<Block>),
|
Blocks(Vec<Block>),
|
||||||
|
|
||||||
|
/// A list of block hashes.
|
||||||
|
BlockHeaderHashes(Vec<BlockHeaderHash>),
|
||||||
}
|
}
|
|
@ -112,6 +112,15 @@ impl ConnectCmd {
|
||||||
info!(?rsp);
|
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::<()>();
|
let eternity = future::pending::<()>();
|
||||||
eternity.await;
|
eternity.await;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue