Add block locator request to state layer (#712)
* Add block locator request to state layer * pass genesis in request * Update zebrad/src/commands/start/sync.rs * fix errors
This commit is contained in:
parent
49aa41544d
commit
7d4e717182
|
@ -84,6 +84,11 @@ impl Block {
|
|||
Err("no coinbase transaction in block")?
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the hash for the current block
|
||||
pub fn hash(&self) -> BlockHeaderHash {
|
||||
BlockHeaderHash::from(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a Block> for BlockHeaderHash {
|
||||
|
|
|
@ -54,7 +54,7 @@ async fn batch_flushes_on_max_items() -> Result<()> {
|
|||
// flushing is happening based on hitting max_items.
|
||||
let verifier = Batch::new(Verifier::new(), 10, Duration::from_secs(1000));
|
||||
timeout(Duration::from_secs(5), sign_and_verify(verifier, 100))
|
||||
.await
|
||||
.await?
|
||||
.map_err(|e| eyre!(e))?;
|
||||
|
||||
Ok(())
|
||||
|
@ -69,7 +69,7 @@ async fn batch_flushes_on_max_latency() -> Result<()> {
|
|||
// flushing is happening based on hitting max_latency.
|
||||
let verifier = Batch::new(Verifier::new(), 100, Duration::from_millis(500));
|
||||
timeout(Duration::from_secs(5), sign_and_verify(verifier, 10))
|
||||
.await
|
||||
.await?
|
||||
.map_err(|e| eyre!(e))?;
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -60,6 +60,7 @@ impl Service<Request> for InMemoryState {
|
|||
let result = self
|
||||
.index
|
||||
.get_tip()
|
||||
.map(|block| block.hash())
|
||||
.map(|hash| Response::Tip { hash })
|
||||
.ok_or_else(|| "zebra-state contains no blocks".into());
|
||||
|
||||
|
@ -75,6 +76,35 @@ impl Service<Request> for InMemoryState {
|
|||
}
|
||||
.boxed()
|
||||
}
|
||||
Request::GetBlockLocator { genesis } => {
|
||||
let tip = self.index.get_tip();
|
||||
let tip = match tip {
|
||||
Some(tip) => tip,
|
||||
None => {
|
||||
return async move {
|
||||
Ok(Response::BlockLocator {
|
||||
block_locator: vec![genesis],
|
||||
})
|
||||
}
|
||||
.boxed()
|
||||
}
|
||||
};
|
||||
|
||||
let tip_height = tip
|
||||
.coinbase_height()
|
||||
.expect("tip block will have a coinbase height");
|
||||
|
||||
let block_locator = crate::block_locator_heights(tip_height)
|
||||
.map(|height| {
|
||||
self.index
|
||||
.get(height)
|
||||
.expect("there should be no holes in the chain")
|
||||
.hash()
|
||||
})
|
||||
.collect();
|
||||
|
||||
async move { Ok(Response::BlockLocator { block_locator }) }.boxed()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,12 +40,11 @@ impl BlockIndex {
|
|||
.cloned()
|
||||
}
|
||||
|
||||
pub(super) fn get_tip(&self) -> Option<BlockHeaderHash> {
|
||||
pub(super) fn get_tip(&self) -> Option<Arc<Block>> {
|
||||
self.by_height
|
||||
.iter()
|
||||
.next_back()
|
||||
.map(|(_key, value)| value)
|
||||
.map(|block| block.as_ref().into())
|
||||
.map(|(_key, value)| value.clone())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,8 +16,11 @@
|
|||
#![allow(clippy::try_err)]
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use zebra_chain::block::{Block, BlockHeaderHash};
|
||||
use std::{iter, sync::Arc};
|
||||
use zebra_chain::{
|
||||
block::{Block, BlockHeaderHash},
|
||||
types::BlockHeight,
|
||||
};
|
||||
|
||||
pub mod in_memory;
|
||||
pub mod on_disk;
|
||||
|
@ -58,6 +61,11 @@ pub enum Request {
|
|||
/// The hash used to identify the block
|
||||
hash: BlockHeaderHash,
|
||||
},
|
||||
/// Get a block locator list for the current best chain
|
||||
GetBlockLocator {
|
||||
/// The genesis block of the current best chain
|
||||
genesis: BlockHeaderHash,
|
||||
},
|
||||
/// Get the block that is the tip of the current chain
|
||||
GetTip,
|
||||
/// Ask the state if the given hash is part of the current best chain
|
||||
|
@ -81,6 +89,11 @@ pub enum Response {
|
|||
/// The block that was requested
|
||||
block: Arc<Block>,
|
||||
},
|
||||
/// The response to a `GetBlockLocator` request
|
||||
BlockLocator {
|
||||
/// The set of blocks that make up the block locator
|
||||
block_locator: Vec<BlockHeaderHash>,
|
||||
},
|
||||
/// The response to a `GetTip` request
|
||||
Tip {
|
||||
/// The hash of the block at the tip of the current chain
|
||||
|
@ -93,3 +106,11 @@ pub enum Response {
|
|||
Option<u32>,
|
||||
),
|
||||
}
|
||||
|
||||
/// Get the heights of the blocks for constructing a block_locator list
|
||||
fn block_locator_heights(tip_height: BlockHeight) -> impl Iterator<Item = BlockHeight> {
|
||||
iter::successors(Some(1u32), |h| h.checked_mul(2))
|
||||
.flat_map(move |step| tip_height.0.checked_sub(step))
|
||||
.map(BlockHeight)
|
||||
.chain(iter::once(BlockHeight(0)))
|
||||
}
|
||||
|
|
|
@ -161,6 +161,39 @@ impl Service<Request> for SledState {
|
|||
}
|
||||
.boxed()
|
||||
}
|
||||
Request::GetBlockLocator { genesis } => {
|
||||
let storage = self.clone();
|
||||
|
||||
async move {
|
||||
let tip = match storage.get_tip()? {
|
||||
Some(tip) => tip,
|
||||
None => {
|
||||
return Ok(Response::BlockLocator {
|
||||
block_locator: vec![genesis],
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
let tip_height = tip
|
||||
.coinbase_height()
|
||||
.expect("tip of the current chain will have a coinbase height");
|
||||
|
||||
let heights = crate::block_locator_heights(tip_height);
|
||||
|
||||
let block_locator = heights
|
||||
.map(|height| {
|
||||
storage.get(height).map(|block| {
|
||||
block
|
||||
.expect("there should be no holes in the current chain")
|
||||
.hash()
|
||||
})
|
||||
})
|
||||
.collect::<Result<_, _>>()?;
|
||||
|
||||
Ok(Response::BlockLocator { block_locator })
|
||||
}
|
||||
.boxed()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ use tracing_futures::{Instrument, Instrumented};
|
|||
|
||||
use zebra_chain::{
|
||||
block::{Block, BlockHeaderHash},
|
||||
types::BlockHeight,
|
||||
Network,
|
||||
};
|
||||
use zebra_consensus::checkpoint;
|
||||
use zebra_network::{self as zn, RetryLimit};
|
||||
|
@ -118,8 +118,25 @@ where
|
|||
// Query the current state to construct the sequence of hashes: handled by
|
||||
// the caller
|
||||
//
|
||||
// TODO(jlusby): get the block_locator from the state
|
||||
let block_locator = vec![super::GENESIS];
|
||||
// TODO(teor): get the real network
|
||||
let network = Network::Mainnet;
|
||||
let block_locator = self
|
||||
.state
|
||||
.ready_and()
|
||||
.await
|
||||
.map_err(|e| eyre!(e))?
|
||||
.call(zebra_state::Request::GetBlockLocator {
|
||||
genesis: zebra_consensus::parameters::genesis_hash(network),
|
||||
})
|
||||
.await
|
||||
.map(|response| match response {
|
||||
zebra_state::Response::BlockLocator { block_locator } => block_locator,
|
||||
_ => unreachable!(
|
||||
"GetBlockLocator request can only result in Response::BlockLocator"
|
||||
),
|
||||
})
|
||||
.map_err(|e| eyre!(e))?;
|
||||
|
||||
tracing::info!(?block_locator, "trying to obtain new chain tips");
|
||||
|
||||
// ObtainTips Step 2
|
||||
|
@ -349,13 +366,4 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Get the heights of the blocks for constructing a block_locator list
|
||||
#[allow(dead_code)]
|
||||
pub fn block_locator_heights(tip_height: BlockHeight) -> impl Iterator<Item = BlockHeight> {
|
||||
iter::successors(Some(1u32), |h| h.checked_mul(2))
|
||||
.flat_map(move |step| tip_height.0.checked_sub(step))
|
||||
.map(BlockHeight)
|
||||
.chain(iter::once(BlockHeight(0)))
|
||||
}
|
||||
|
||||
type Error = Box<dyn std::error::Error + Send + Sync + 'static>;
|
||||
|
|
Loading…
Reference in New Issue