From 070013439e368896b4f12e97f755f77b71eeb4a9 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Wed, 9 Sep 2020 17:59:58 -0700 Subject: [PATCH] state: fill in RFC5-style Request, Response enums The test transcripts need to be rewritten, so they are removed for now. --- zebra-state/src/lib.rs | 2 +- zebra-state/src/request.rs | 124 ++++++++++++++++++++++++------ zebra-state/src/response.rs | 57 +++++++------- zebra-state/src/service.rs | 15 ++-- zebra-state/tests/basic.rs | 148 +++++------------------------------- 5 files changed, 157 insertions(+), 189 deletions(-) diff --git a/zebra-state/src/lib.rs b/zebra-state/src/lib.rs index 4579a6f4a..559bbc87e 100644 --- a/zebra-state/src/lib.rs +++ b/zebra-state/src/lib.rs @@ -23,7 +23,7 @@ use memory_state::MemoryState; use sled_state::SledState; pub use config::Config; -pub use request::Request; +pub use request::{HashOrHeight, Request}; pub use response::Response; pub use service::init; diff --git a/zebra-state/src/request.rs b/zebra-state/src/request.rs index 80ef33b12..29fddf867 100644 --- a/zebra-state/src/request.rs +++ b/zebra-state/src/request.rs @@ -1,32 +1,110 @@ use std::sync::Arc; -use zebra_chain::block::{self, Block}; +use zebra_chain::{ + block::{self, Block}, + transaction, +}; + +// Allow *only* this unused import, so that rustdoc link resolution +// will work with inline links. +#[allow(unused_imports)] +use crate::Response; + +/// Identify a block by hash or height. +/// +/// This enum implements `From` for [`block::Hash`] and [`block::Height`], +/// so it can be created using `hash.into()` or `height.into()`. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum HashOrHeight { + /// A block identified by hash. + Hash(block::Hash), + /// A block identified by height. + Height(block::Height), +} + +impl From for HashOrHeight { + fn from(hash: block::Hash) -> Self { + Self::Hash(hash) + } +} + +impl From for HashOrHeight { + fn from(hash: block::Height) -> Self { + Self::Height(hash) + } +} #[derive(Clone, Debug, PartialEq, Eq)] /// A query about or modification to the chain state. -/// -/// TODO: replace these variants with the ones in RFC5. pub enum Request { - // TODO(jlusby): deprecate in the future based on our validation story - /// Add a block to the zebra-state - AddBlock { - /// The block to be added to the state + /// Performs contextual validation of the given block, committing it to the + /// state if successful. + /// + /// Returns [`Response::Committed`] with the hash of the newly + /// committed block, or an error. + /// + /// This request can be made out-of-order; the state service will buffer it + /// until its parent is ready. + CommitBlock { + /// The block to commit to the state. block: Arc, + // TODO: add these parameters when we can compute anchors. + // sprout_anchor: sprout::tree::Root, + // sapling_anchor: sapling::tree::Root, }, - /// Get a block from the zebra-state - GetBlock { - /// The hash used to identify the block - hash: block::Hash, - }, - /// Get a block locator list for the current best chain - GetBlockLocator { - /// The genesis block of the current best chain - genesis: block::Hash, - }, - /// 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 - GetDepth { - /// The hash to check against the current chain - hash: block::Hash, + + /// Commit a finalized block to the state, skipping contextual validation. + /// This is exposed for use in checkpointing, which produces finalized + /// blocks. + /// + /// Returns [`Response::Committed`] with the hash of the newly + /// committed block, or an error. + /// + /// This request can be made out-of-order; the state service will buffer it + /// until its parent is ready. + CommitFinalizedBlock { + /// The block to commit to the state. + block: Arc, + // TODO: add these parameters when we can compute anchors. + // sprout_anchor: sprout::tree::Root, + // sapling_anchor: sapling::tree::Root, }, + + /// Computes the depth in the best chain of the block identified by the given hash. + /// + /// Returns + /// + /// * [`Response::Depth(Some(depth))`](Response::Depth) if the block is in the main chain; + /// * [`Response::Depth(None)`](Response::Depth) otherwise. + Depth(block::Hash), + + /// Returns [`Response::Tip`] with the current best chain tip. + Tip, + + /// Computes a block locator object based on the current chain state. + /// + /// Returns [`Response::BlockLocator`] with hashes starting + /// from the current chain tip and reaching backwards towards the genesis + /// block. The first hash is the current chain tip. The last hash is the tip + /// of the finalized portion of the state. If the state is empty, the block + /// locator is also empty. + BlockLocator, + + /// Looks up a transaction by hash. + /// + /// Returns + /// + /// * [`Response::Transaction(Some(Arc))`](Response::Transaction) if the transaction is known; + /// * [`Response::Transaction(None)`](Response::Transaction) otherwise. + Transaction(transaction::Hash), + + /// Looks up a block by hash or height. + /// + /// Returns + /// + /// * [`Response::Block(Some(Arc))`](Response::Block) if the block is known; + /// * [`Response::Block(None)`](Response::Transaction) otherwise. + /// + /// Note: the [`HashOrHeight`] can be constructed from a [`block::Hash`] or + /// [`block::Height`] using `.into()`. + Block(HashOrHeight), } diff --git a/zebra-state/src/response.rs b/zebra-state/src/response.rs index 339e8bb73..4f526f8b5 100644 --- a/zebra-state/src/response.rs +++ b/zebra-state/src/response.rs @@ -1,34 +1,33 @@ use std::sync::Arc; -use zebra_chain::block::{self, Block}; +use zebra_chain::{ + block::{self, Block}, + transaction::Transaction, +}; + +// Allow *only* this unused import, so that rustdoc link resolution +// will work with inline links. +#[allow(unused_imports)] +use crate::Request; #[derive(Clone, Debug, PartialEq, Eq)] -/// A response to a state [`Request`](super::Request). +/// A response to a state [`Request`]. pub enum Response { - /// The response to a `AddBlock` request indicating a block was successfully - /// added to the state - Added { - /// The hash of the block that was added - hash: block::Hash, - }, - /// The response to a `GetBlock` request by hash - Block { - /// The block that was requested - block: Arc, - }, - /// The response to a `GetBlockLocator` request - BlockLocator { - /// The set of blocks that make up the block locator - block_locator: Vec, - }, - /// The response to a `GetTip` request - Tip { - /// The hash of the block at the tip of the current chain - hash: block::Hash, - }, - /// The response to a `Contains` request indicating that the given has is in - /// the current best chain - Depth( - /// The number of blocks above the given block in the current best chain - Option, - ), + /// Response to [`Request::CommitBlock`] indicating that a block was + /// successfully committed to the state. + Committed(block::Hash), + + /// Response to [`Request::Depth`] with the depth of the specified block. + Depth(Option), + + /// Response to [`Request::Tip`] with the current best chain tip. + Tip(Option), + + /// Response to [`Request::BlockLocator`] with a block locator object. + BlockLocator(Vec), + + /// Response to [`Request::Transaction`] with the specified transaction. + Transaction(Option>), + + /// Response to [`Request::Block`] with the specified block. + Block(Option>), } diff --git a/zebra-state/src/service.rs b/zebra-state/src/service.rs index 00a1cf85b..f742f5995 100644 --- a/zebra-state/src/service.rs +++ b/zebra-state/src/service.rs @@ -6,7 +6,7 @@ use std::{ use tower::{buffer::Buffer, util::BoxService, Service}; use zebra_chain::parameters::Network; -use crate::{BoxError, Config, MemoryState, Request, Response, SledState}; +use crate::{BoxError, Config, HashOrHeight, MemoryState, Request, Response, SledState}; struct StateService { /// Holds data relating to finalized chain state. @@ -35,11 +35,14 @@ impl Service for StateService { fn call(&mut self, req: Request) -> Self::Future { match req { - Request::AddBlock { block } => unimplemented!(), - Request::GetBlock { hash } => unimplemented!(), - Request::GetTip => unimplemented!(), - Request::GetDepth { hash } => unimplemented!(), - Request::GetBlockLocator { genesis } => unimplemented!(), + Request::CommitBlock { block } => unimplemented!(), + Request::CommitFinalizedBlock { block } => unimplemented!(), + Request::Depth(hash) => unimplemented!(), + Request::Tip => unimplemented!(), + Request::BlockLocator => unimplemented!(), + Request::Transaction(hash) => unimplemented!(), + Request::Block(HashOrHeight::Hash(hash)) => unimplemented!(), + Request::Block(HashOrHeight::Height(height)) => unimplemented!(), } } } diff --git a/zebra-state/tests/basic.rs b/zebra-state/tests/basic.rs index 45a8e7a3d..27b93cb42 100644 --- a/zebra-state/tests/basic.rs +++ b/zebra-state/tests/basic.rs @@ -7,145 +7,43 @@ use zebra_test::transcript::{TransError, Transcript}; use zebra_state::*; -static ADD_BLOCK_TRANSCRIPT_MAINNET: Lazy)>> = +static COMMIT_FINALIZED_BLOCK_MAINNET: Lazy)>> = Lazy::new(|| { let block: Arc<_> = Block::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_GENESIS_BYTES[..]) .unwrap() .into(); - let hash = block.as_ref().into(); + let block2 = block.clone(); + let hash = block.hash(); vec![ ( - Request::AddBlock { - block: block.clone(), - }, - Ok(Response::Added { hash }), + Request::CommitFinalizedBlock { block }, + Ok(Response::Committed(hash)), + ), + ( + Request::Block(hash.into()), + Ok(Response::Block(Some(block2))), ), - (Request::GetBlock { hash }, Ok(Response::Block { block })), ] }); -static ADD_BLOCK_TRANSCRIPT_TESTNET: Lazy)>> = +static COMMIT_FINALIZED_BLOCK_TESTNET: Lazy)>> = Lazy::new(|| { let block: Arc<_> = Block::zcash_deserialize(&zebra_test::vectors::BLOCK_TESTNET_GENESIS_BYTES[..]) .unwrap() .into(); - let hash = block.as_ref().into(); + let block2 = block.clone(); + let hash = block.hash(); vec![ ( - Request::AddBlock { - block: block.clone(), - }, - Ok(Response::Added { hash }), - ), - (Request::GetBlock { hash }, Ok(Response::Block { block })), - ] - }); - -static GET_TIP_ADD_ORDERED_TRANSCRIPT_MAINNET: Lazy)>> = - Lazy::new(|| { - let block0: Arc<_> = - Block::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_GENESIS_BYTES[..]) - .unwrap() - .into(); - let block1: Arc<_> = - Block::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_1_BYTES[..]) - .unwrap() - .into(); - let hash0 = block0.as_ref().into(); - let hash1 = block1.as_ref().into(); - vec![ - // Insert the blocks in order - ( - Request::AddBlock { block: block0 }, - Ok(Response::Added { hash: hash0 }), + Request::CommitFinalizedBlock { block }, + Ok(Response::Committed(hash)), ), ( - Request::AddBlock { block: block1 }, - Ok(Response::Added { hash: hash1 }), + Request::Block(hash.into()), + Ok(Response::Block(Some(block2))), ), - (Request::GetTip, Ok(Response::Tip { hash: hash1 })), - ] - }); - -static GET_TIP_ADD_ORDERED_TRANSCRIPT_TESTNET: Lazy)>> = - Lazy::new(|| { - let block0: Arc<_> = - Block::zcash_deserialize(&zebra_test::vectors::BLOCK_TESTNET_GENESIS_BYTES[..]) - .unwrap() - .into(); - let block1: Arc<_> = - Block::zcash_deserialize(&zebra_test::vectors::BLOCK_TESTNET_1_BYTES[..]) - .unwrap() - .into(); - let hash0 = block0.as_ref().into(); - let hash1 = block1.as_ref().into(); - vec![ - // Insert the blocks in order - ( - Request::AddBlock { block: block0 }, - Ok(Response::Added { hash: hash0 }), - ), - ( - Request::AddBlock { block: block1 }, - Ok(Response::Added { hash: hash1 }), - ), - (Request::GetTip, Ok(Response::Tip { hash: hash1 })), - ] - }); - -#[allow(dead_code)] -static GET_TIP_ADD_REVERSED_TRANSCRIPT_MAINNET: Lazy)>> = - Lazy::new(|| { - let block0: Arc<_> = - Block::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_GENESIS_BYTES[..]) - .unwrap() - .into(); - let block1: Arc<_> = - Block::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_1_BYTES[..]) - .unwrap() - .into(); - let hash0 = block0.as_ref().into(); - let hash1 = block1.as_ref().into(); - vec![ - // Insert the blocks in reverse order - ( - Request::AddBlock { block: block1 }, - Ok(Response::Added { hash: hash1 }), - ), - ( - Request::AddBlock { block: block0 }, - Ok(Response::Added { hash: hash0 }), - ), - (Request::GetTip, Ok(Response::Tip { hash: hash1 })), - ] - }); - -#[allow(dead_code)] -static GET_TIP_ADD_REVERSED_TRANSCRIPT_TESTNET: Lazy)>> = - Lazy::new(|| { - let block0: Arc<_> = - Block::zcash_deserialize(&zebra_test::vectors::BLOCK_TESTNET_GENESIS_BYTES[..]) - .unwrap() - .into(); - let block1: Arc<_> = - Block::zcash_deserialize(&zebra_test::vectors::BLOCK_TESTNET_1_BYTES[..]) - .unwrap() - .into(); - let hash0 = block0.as_ref().into(); - let hash1 = block1.as_ref().into(); - vec![ - // Insert the blocks in reverse order - ( - Request::AddBlock { block: block1 }, - Ok(Response::Added { hash: hash1 }), - ), - ( - Request::AddBlock { block: block0 }, - Ok(Response::Added { hash: hash0 }), - ), - (Request::GetTip, Ok(Response::Tip { hash: hash1 })), ] }); @@ -163,18 +61,8 @@ async fn check_transcripts_testnet() -> Result<(), Report> { async fn check_transcripts(network: Network) -> Result<(), Report> { zebra_test::init(); - let mainnet_transcript = &[ - &ADD_BLOCK_TRANSCRIPT_MAINNET, - &GET_TIP_ADD_ORDERED_TRANSCRIPT_MAINNET, - // Temporarily disabled, until the state accepts out-of-order blocks - //&GET_TIP_ADD_REVERSED_TRANSCRIPT_MAINNET, - ]; - let testnet_transcript = &[ - &ADD_BLOCK_TRANSCRIPT_TESTNET, - &GET_TIP_ADD_ORDERED_TRANSCRIPT_TESTNET, - // Temporarily disabled, until the state accepts out-of-order blocks - //&GET_TIP_ADD_REVERSED_TRANSCRIPT_TESTNET, - ]; + let mainnet_transcript = &[&COMMIT_FINALIZED_BLOCK_MAINNET]; + let testnet_transcript = &[&COMMIT_FINALIZED_BLOCK_TESTNET]; for transcript_data in match network { Network::Mainnet => mainnet_transcript,