state: fill in RFC5-style Request, Response enums

The test transcripts need to be rewritten, so they are removed for now.
This commit is contained in:
Henry de Valence 2020-09-09 17:59:58 -07:00
parent 98d5351206
commit 070013439e
5 changed files with 157 additions and 189 deletions

View File

@ -23,7 +23,7 @@ use memory_state::MemoryState;
use sled_state::SledState; use sled_state::SledState;
pub use config::Config; pub use config::Config;
pub use request::Request; pub use request::{HashOrHeight, Request};
pub use response::Response; pub use response::Response;
pub use service::init; pub use service::init;

View File

@ -1,32 +1,110 @@
use std::sync::Arc; 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<block::Hash> for HashOrHeight {
fn from(hash: block::Hash) -> Self {
Self::Hash(hash)
}
}
impl From<block::Height> for HashOrHeight {
fn from(hash: block::Height) -> Self {
Self::Height(hash)
}
}
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
/// A query about or modification to the chain state. /// A query about or modification to the chain state.
///
/// TODO: replace these variants with the ones in RFC5.
pub enum Request { pub enum Request {
// TODO(jlusby): deprecate in the future based on our validation story /// Performs contextual validation of the given block, committing it to the
/// Add a block to the zebra-state /// state if successful.
AddBlock { ///
/// The block to be added to the state /// 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<Block>, block: Arc<Block>,
// 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 { /// Commit a finalized block to the state, skipping contextual validation.
/// The hash used to identify the block /// This is exposed for use in checkpointing, which produces finalized
hash: block::Hash, /// blocks.
}, ///
/// Get a block locator list for the current best chain /// Returns [`Response::Committed`] with the hash of the newly
GetBlockLocator { /// committed block, or an error.
/// The genesis block of the current best chain ///
genesis: block::Hash, /// This request can be made out-of-order; the state service will buffer it
}, /// until its parent is ready.
/// Get the block that is the tip of the current chain CommitFinalizedBlock {
GetTip, /// The block to commit to the state.
/// Ask the state if the given hash is part of the current best chain block: Arc<Block>,
GetDepth { // TODO: add these parameters when we can compute anchors.
/// The hash to check against the current chain // sprout_anchor: sprout::tree::Root,
hash: block::Hash, // 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<Transaction>))`](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<Block>))`](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),
} }

View File

@ -1,34 +1,33 @@
use std::sync::Arc; 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)] #[derive(Clone, Debug, PartialEq, Eq)]
/// A response to a state [`Request`](super::Request). /// A response to a state [`Request`].
pub enum Response { pub enum Response {
/// The response to a `AddBlock` request indicating a block was successfully /// Response to [`Request::CommitBlock`] indicating that a block was
/// added to the state /// successfully committed to the state.
Added { Committed(block::Hash),
/// The hash of the block that was added
hash: block::Hash, /// Response to [`Request::Depth`] with the depth of the specified block.
}, Depth(Option<block::Height>),
/// The response to a `GetBlock` request by hash
Block { /// Response to [`Request::Tip`] with the current best chain tip.
/// The block that was requested Tip(Option<block::Hash>),
block: Arc<Block>,
}, /// Response to [`Request::BlockLocator`] with a block locator object.
/// The response to a `GetBlockLocator` request BlockLocator(Vec<block::Hash>),
BlockLocator {
/// The set of blocks that make up the block locator /// Response to [`Request::Transaction`] with the specified transaction.
block_locator: Vec<block::Hash>, Transaction(Option<Arc<Transaction>>),
},
/// The response to a `GetTip` request /// Response to [`Request::Block`] with the specified block.
Tip { Block(Option<Arc<Block>>),
/// 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<u32>,
),
} }

View File

@ -6,7 +6,7 @@ use std::{
use tower::{buffer::Buffer, util::BoxService, Service}; use tower::{buffer::Buffer, util::BoxService, Service};
use zebra_chain::parameters::Network; use zebra_chain::parameters::Network;
use crate::{BoxError, Config, MemoryState, Request, Response, SledState}; use crate::{BoxError, Config, HashOrHeight, MemoryState, Request, Response, SledState};
struct StateService { struct StateService {
/// Holds data relating to finalized chain state. /// Holds data relating to finalized chain state.
@ -35,11 +35,14 @@ impl Service<Request> for StateService {
fn call(&mut self, req: Request) -> Self::Future { fn call(&mut self, req: Request) -> Self::Future {
match req { match req {
Request::AddBlock { block } => unimplemented!(), Request::CommitBlock { block } => unimplemented!(),
Request::GetBlock { hash } => unimplemented!(), Request::CommitFinalizedBlock { block } => unimplemented!(),
Request::GetTip => unimplemented!(), Request::Depth(hash) => unimplemented!(),
Request::GetDepth { hash } => unimplemented!(), Request::Tip => unimplemented!(),
Request::GetBlockLocator { genesis } => unimplemented!(), Request::BlockLocator => unimplemented!(),
Request::Transaction(hash) => unimplemented!(),
Request::Block(HashOrHeight::Hash(hash)) => unimplemented!(),
Request::Block(HashOrHeight::Height(height)) => unimplemented!(),
} }
} }
} }

View File

@ -7,145 +7,43 @@ use zebra_test::transcript::{TransError, Transcript};
use zebra_state::*; use zebra_state::*;
static ADD_BLOCK_TRANSCRIPT_MAINNET: Lazy<Vec<(Request, Result<Response, TransError>)>> = static COMMIT_FINALIZED_BLOCK_MAINNET: Lazy<Vec<(Request, Result<Response, TransError>)>> =
Lazy::new(|| { Lazy::new(|| {
let block: Arc<_> = let block: Arc<_> =
Block::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_GENESIS_BYTES[..]) Block::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_GENESIS_BYTES[..])
.unwrap() .unwrap()
.into(); .into();
let hash = block.as_ref().into(); let block2 = block.clone();
let hash = block.hash();
vec![ vec![
( (
Request::AddBlock { Request::CommitFinalizedBlock { block },
block: block.clone(), Ok(Response::Committed(hash)),
}, ),
Ok(Response::Added { hash }), (
Request::Block(hash.into()),
Ok(Response::Block(Some(block2))),
), ),
(Request::GetBlock { hash }, Ok(Response::Block { block })),
] ]
}); });
static ADD_BLOCK_TRANSCRIPT_TESTNET: Lazy<Vec<(Request, Result<Response, TransError>)>> = static COMMIT_FINALIZED_BLOCK_TESTNET: Lazy<Vec<(Request, Result<Response, TransError>)>> =
Lazy::new(|| { Lazy::new(|| {
let block: Arc<_> = let block: Arc<_> =
Block::zcash_deserialize(&zebra_test::vectors::BLOCK_TESTNET_GENESIS_BYTES[..]) Block::zcash_deserialize(&zebra_test::vectors::BLOCK_TESTNET_GENESIS_BYTES[..])
.unwrap() .unwrap()
.into(); .into();
let hash = block.as_ref().into(); let block2 = block.clone();
let hash = block.hash();
vec![ vec![
( (
Request::AddBlock { Request::CommitFinalizedBlock { block },
block: block.clone(), Ok(Response::Committed(hash)),
},
Ok(Response::Added { hash }),
),
(Request::GetBlock { hash }, Ok(Response::Block { block })),
]
});
static GET_TIP_ADD_ORDERED_TRANSCRIPT_MAINNET: Lazy<Vec<(Request, Result<Response, TransError>)>> =
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::AddBlock { block: block1 }, Request::Block(hash.into()),
Ok(Response::Added { hash: hash1 }), Ok(Response::Block(Some(block2))),
), ),
(Request::GetTip, Ok(Response::Tip { hash: hash1 })),
]
});
static GET_TIP_ADD_ORDERED_TRANSCRIPT_TESTNET: Lazy<Vec<(Request, Result<Response, TransError>)>> =
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<Vec<(Request, Result<Response, TransError>)>> =
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<Vec<(Request, Result<Response, TransError>)>> =
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> { async fn check_transcripts(network: Network) -> Result<(), Report> {
zebra_test::init(); zebra_test::init();
let mainnet_transcript = &[ let mainnet_transcript = &[&COMMIT_FINALIZED_BLOCK_MAINNET];
&ADD_BLOCK_TRANSCRIPT_MAINNET, let testnet_transcript = &[&COMMIT_FINALIZED_BLOCK_TESTNET];
&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,
];
for transcript_data in match network { for transcript_data in match network {
Network::Mainnet => mainnet_transcript, Network::Mainnet => mainnet_transcript,