parent
d0a833f3fb
commit
7b8707be1e
|
@ -2125,10 +2125,16 @@ version = "0.1.0"
|
||||||
name = "zebra-consensus"
|
name = "zebra-consensus"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures",
|
"color-eyre",
|
||||||
|
"eyre",
|
||||||
|
"tokio",
|
||||||
"tower",
|
"tower",
|
||||||
|
"tracing",
|
||||||
|
"tracing-error",
|
||||||
|
"tracing-subscriber",
|
||||||
"zebra-chain",
|
"zebra-chain",
|
||||||
"zebra-state",
|
"zebra-state",
|
||||||
|
"zebra-test-vectors",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -11,4 +11,12 @@ edition = "2018"
|
||||||
zebra-chain = { path = "../zebra-chain" }
|
zebra-chain = { path = "../zebra-chain" }
|
||||||
zebra-state = { path = "../zebra-state" }
|
zebra-state = { path = "../zebra-state" }
|
||||||
tower = "0.3.1"
|
tower = "0.3.1"
|
||||||
futures = "0.3.5"
|
|
||||||
|
[dev-dependencies]
|
||||||
|
zebra-test-vectors = { path = "../zebra-test-vectors/" }
|
||||||
|
color-eyre = "0.3.4"
|
||||||
|
eyre = "0.4.2"
|
||||||
|
tokio = { version = "0.2.21", features = ["full"] }
|
||||||
|
tracing = "0.1.15"
|
||||||
|
tracing-error = "0.1.2"
|
||||||
|
tracing-subscriber = "0.2.5"
|
||||||
|
|
|
@ -34,8 +34,9 @@ type ZS<ZSF> = Box<
|
||||||
|
|
||||||
/// Block verification service.
|
/// Block verification service.
|
||||||
///
|
///
|
||||||
/// After verification, blocks and their associated transactions are added to
|
/// After verification, blocks are added to `state_service`. We use a generic
|
||||||
/// `zebra_state::ZebraState`.
|
/// future `ZSF` for that service, so that the underlying state service can be
|
||||||
|
/// wrapped in other services as needed.
|
||||||
struct BlockVerifier<ZSF>
|
struct BlockVerifier<ZSF>
|
||||||
where
|
where
|
||||||
ZSF: Future<Output = Result<zebra_state::Response, ZSE>> + Send + 'static,
|
ZSF: Future<Output = Result<zebra_state::Response, ZSE>> + Send + 'static,
|
||||||
|
@ -51,6 +52,8 @@ type Response = BlockHeaderHash;
|
||||||
type Error = Box<dyn error::Error + Send + Sync + 'static>;
|
type Error = Box<dyn error::Error + Send + Sync + 'static>;
|
||||||
|
|
||||||
/// The BlockVerifier service implementation.
|
/// The BlockVerifier service implementation.
|
||||||
|
///
|
||||||
|
/// After verification, blocks are added to the underlying state service.
|
||||||
impl<ZSF> Service<Block> for BlockVerifier<ZSF>
|
impl<ZSF> Service<Block> for BlockVerifier<ZSF>
|
||||||
where
|
where
|
||||||
ZSF: Future<Output = Result<zebra_state::Response, ZSE>> + Send + 'static,
|
ZSF: Future<Output = Result<zebra_state::Response, ZSE>> + Send + 'static,
|
||||||
|
@ -72,6 +75,7 @@ where
|
||||||
// TODO(teor):
|
// TODO(teor):
|
||||||
// - handle chain reorgs, adjust state_service "unique block height" conditions
|
// - handle chain reorgs, adjust state_service "unique block height" conditions
|
||||||
// - handle block validation errors (including errors in the block's transactions)
|
// - handle block validation errors (including errors in the block's transactions)
|
||||||
|
// - handle state_service AddBlock errors, and add unit tests for those errors
|
||||||
let _: ZSF = self.state_service.call(zebra_state::Request::AddBlock {
|
let _: ZSF = self.state_service.call(zebra_state::Request::AddBlock {
|
||||||
block: block.into(),
|
block: block.into(),
|
||||||
});
|
});
|
||||||
|
@ -81,6 +85,10 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialise the BlockVerifier service.
|
/// Initialise the BlockVerifier service.
|
||||||
|
///
|
||||||
|
/// We use a generic type `ZS<ZSF>` for `state_service`, so that the
|
||||||
|
/// underlying state service can be wrapped in other services as needed.
|
||||||
|
/// For similar reasons, we also return a dynamic service type.
|
||||||
pub fn init<ZSF>(
|
pub fn init<ZSF>(
|
||||||
state_service: ZS<ZSF>,
|
state_service: ZS<ZSF>,
|
||||||
) -> impl Service<
|
) -> impl Service<
|
||||||
|
@ -96,3 +104,57 @@ where
|
||||||
{
|
{
|
||||||
Buffer::new(BlockVerifier::<ZSF> { state_service }, 1)
|
Buffer::new(BlockVerifier::<ZSF> { state_service }, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use color_eyre::Report;
|
||||||
|
use eyre::{ensure, eyre};
|
||||||
|
use tower::{util::ServiceExt, Service};
|
||||||
|
use zebra_chain::serialization::ZcashDeserialize;
|
||||||
|
|
||||||
|
fn install_tracing() {
|
||||||
|
use tracing_error::ErrorLayer;
|
||||||
|
use tracing_subscriber::prelude::*;
|
||||||
|
use tracing_subscriber::{fmt, EnvFilter};
|
||||||
|
|
||||||
|
let fmt_layer = fmt::layer().with_target(false);
|
||||||
|
let filter_layer = EnvFilter::try_from_default_env()
|
||||||
|
.or_else(|_| EnvFilter::try_new("info"))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
tracing_subscriber::registry()
|
||||||
|
.with(filter_layer)
|
||||||
|
.with(fmt_layer)
|
||||||
|
.with(ErrorLayer::default())
|
||||||
|
.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn verify() -> Result<(), Report> {
|
||||||
|
install_tracing();
|
||||||
|
|
||||||
|
let block = Block::zcash_deserialize(&zebra_test_vectors::BLOCK_MAINNET_415000_BYTES[..])?;
|
||||||
|
// TODO(teor): why does rustc say that _hash is unused?
|
||||||
|
let _hash: BlockHeaderHash = (&block).into();
|
||||||
|
|
||||||
|
let state_service = Box::new(zebra_state::in_memory::init());
|
||||||
|
let mut block_verifier = super::init(state_service);
|
||||||
|
|
||||||
|
let verify_response = block_verifier
|
||||||
|
.ready_and()
|
||||||
|
.await
|
||||||
|
.map_err(|e| eyre!(e))?
|
||||||
|
.call(block.clone())
|
||||||
|
.await
|
||||||
|
.map_err(|e| eyre!(e))?;
|
||||||
|
|
||||||
|
ensure!(
|
||||||
|
matches!(verify_response, _hash),
|
||||||
|
"unexpected response kind: {:?}",
|
||||||
|
verify_response
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue