diff --git a/zebra-consensus/src/block.rs b/zebra-consensus/src/block.rs index b12a71eb2..aed15fdd3 100644 --- a/zebra-consensus/src/block.rs +++ b/zebra-consensus/src/block.rs @@ -1,12 +1,11 @@ -//! Block verification for Zebra. +//! Consensus-based block verification. //! -//! Verification occurs in multiple stages: -//! - getting blocks (disk- or network-bound) -//! - context-free verification of signatures, proofs, and scripts (CPU-bound) -//! - context-dependent verification of the chain state (depends on previous blocks) +//! In contrast to checkpoint verification, which only checks hardcoded +//! hashes, block verification checks all Zcash consensus rules. //! -//! Verification is provided via a `tower::Service`, to support backpressure and batch -//! verification. +//! The block verifier performs all of the semantic validation checks. +//! If accepted, the block is sent to the state service for contextual +//! verification, where it may be accepted or rejected. use std::{ future::Future, @@ -40,16 +39,12 @@ mod subsidy; #[cfg(test)] mod tests; -/// A service that verifies blocks. +/// Asynchronous block verification. #[derive(Debug)] pub struct BlockVerifier { /// The network to be verified. network: Network, - - /// The underlying state service, possibly wrapped in other services. state_service: S, - - /// The transaction verification service transaction_verifier: transaction::Verifier, } diff --git a/zebra-consensus/src/checkpoint.rs b/zebra-consensus/src/checkpoint.rs index 1ae074ad1..7e27c542e 100644 --- a/zebra-consensus/src/checkpoint.rs +++ b/zebra-consensus/src/checkpoint.rs @@ -1,17 +1,17 @@ -//! Checkpoint-based block verification for Zebra. +//! Checkpoint-based block verification. //! -//! Checkpoint-based verification uses a list of checkpoint hashes to speed up the -//! initial chain sync for Zebra. This list is distributed with Zebra. +//! Checkpoint-based verification uses a list of checkpoint hashes to +//! speed up the initial chain sync for Zebra. This list is distributed +//! with Zebra. //! -//! The CheckpointVerifier queues pending blocks. Once there is a chain from the -//! previous checkpoint to a target checkpoint, it verifies all the blocks in -//! that chain. +//! The checkpoint verifier queues pending blocks. Once there is a +//! chain from the previous checkpoint to a target checkpoint, it +//! verifies all the blocks in that chain, and sends accepted blocks to +//! the state service as finalized chain state, skipping contextual +//! verification checks. //! -//! Verification starts at the first checkpoint, which is the genesis block for the -//! configured network. -//! -//! Verification is provided via a `tower::Service`, to support backpressure and batch -//! verification. +//! Verification starts at the first checkpoint, which is the genesis +//! block for the configured network. use std::{ collections::BTreeMap, diff --git a/zebra-consensus/src/config.rs b/zebra-consensus/src/config.rs index 661cd4578..c66766b20 100644 --- a/zebra-consensus/src/config.rs +++ b/zebra-consensus/src/config.rs @@ -1,5 +1,3 @@ -//! Configuration for zebra-consensus - use serde::{Deserialize, Serialize}; /// Consensus configuration. diff --git a/zebra-consensus/src/error.rs b/zebra-consensus/src/error.rs index 27b456a4d..5b836d3db 100644 --- a/zebra-consensus/src/error.rs +++ b/zebra-consensus/src/error.rs @@ -1,4 +1,9 @@ -//! Consensus validation errors +//! Errors that can occur when checking consensus rules. +//! +//! Each error variant corresponds to a consensus rule, so enumerating +//! all possible verification failures enumerates the consensus rules we +//! implement, and ensures that we don't reject blocks or transactions +//! for a non-enumerated reason. use thiserror::Error; diff --git a/zebra-consensus/src/lib.rs b/zebra-consensus/src/lib.rs index 442f56dc2..fd2e0a711 100644 --- a/zebra-consensus/src/lib.rs +++ b/zebra-consensus/src/lib.rs @@ -37,20 +37,20 @@ //#![deny(missing_docs)] #![allow(clippy::try_err)] -pub mod block; -pub mod chain; -pub mod checkpoint; -pub mod config; -pub mod error; -pub mod mempool; -pub mod parameters; -pub mod script; - +mod block; +mod checkpoint; +mod config; +mod parameters; #[allow(dead_code)] // Remove this once transaction verification is implemented mod primitives; +mod script; mod transaction; -pub use crate::config::Config; +pub mod chain; +pub mod error; + +pub use checkpoint::MAX_CHECKPOINT_HEIGHT_GAP; +pub use config::Config; /// A boxed [`std::error::Error`]. pub type BoxError = Box; diff --git a/zebra-consensus/src/mempool.rs b/zebra-consensus/src/mempool.rs deleted file mode 100644 index e1e5f95b9..000000000 --- a/zebra-consensus/src/mempool.rs +++ /dev/null @@ -1,29 +0,0 @@ -//! Mempool transaction verification and state for Zebra. -//! -//! Mempool updates occur in multiple stages: -//! - getting transactions (disk- or network-bound) -//! - context-free verification of signatures, proofs, and scripts (CPU-bound) -//! - context-dependent verification of mempool transactions against the chain state -//! (awaits an up-to-date chain) -//! - adding transactions to the mempool -//! -//! The mempool is provided via a `tower::Service`, to support backpressure and batch -//! verification. - -/// Mempool state. -/// -/// New transactions are verified, checked against the chain state, then added to the -/// mempool. -/// -/// `ZebraMempoolState` is not yet implemented. -#[derive(Default)] -struct ZebraMempoolState {} - -/// Mempool transaction verification. -/// -/// New transactions are verified, checked against the chain state, then added to the -/// mempool. -/// -/// `MempoolTransactionVerifier` is not yet implemented. -#[derive(Default)] -struct MempoolTransactionVerifier {} diff --git a/zebra-consensus/src/script.rs b/zebra-consensus/src/script.rs index 0b342e1a9..4d37c1a09 100644 --- a/zebra-consensus/src/script.rs +++ b/zebra-consensus/src/script.rs @@ -1,17 +1,3 @@ -//! Script verification for Zebra. -//! -//! Verification occurs in multiple stages: -//! - getting transactions from blocks or the mempool (disk- or network-bound) -//! - context-free verification of scripts, signatures, and proofs (CPU-bound) -//! - context-dependent verification of transactions against the chain state -//! (awaits an up-to-date chain) -//! -//! Verification is provided via a `tower::Service`, to support backpressure and batch -//! verification. -//! -//! This is an internal module. Use `verify::BlockVerifier` for blocks and their -//! transactions, or `mempool::MempoolTransactionVerifier` for mempool transactions. - use std::{pin::Pin, sync::Arc}; use std::future::Future; @@ -19,10 +5,17 @@ use zebra_chain::{parameters::ConsensusBranchId, transaction::Transaction, trans use crate::BoxError; -/// Internal script verification service. +/// Asynchronous script verification. /// -/// After verification, the script future completes. State changes are handled by -/// `BlockVerifier` or `MempoolTransactionVerifier`. +/// The verifier asynchronously requests the UTXO a transaction attempts +/// to use as an input, and verifies the script as soon as it becomes +/// available. This allows script verification to be performed +/// asynchronously, rather than requiring that the entire chain up to +/// the previous block is ready. +/// +/// The asynchronous script verification design is documented in [RFC4]. +/// +/// [RFC4]: https://zebra.zfnd.org/dev/rfcs/0004-asynchronous-script-verification.html #[derive(Debug, Clone)] pub struct Verifier { state: ZS, @@ -35,6 +28,13 @@ impl Verifier { } } +/// A script verification request. +/// +/// Ideally, this would supply only an `Outpoint` and the unlock script, +/// rather than the entire `Transaction`, but we call a C++ +/// implementation, and its FFI requires the entire transaction. +/// At some future point, we could investigate reducing the size of the +/// request. #[derive(Debug)] pub struct Request { pub transaction: Arc, diff --git a/zebra-utils/src/bin/zebra-checkpoints/main.rs b/zebra-utils/src/bin/zebra-checkpoints/main.rs index 456f75f44..171843059 100644 --- a/zebra-utils/src/bin/zebra-checkpoints/main.rs +++ b/zebra-utils/src/bin/zebra-checkpoints/main.rs @@ -152,7 +152,7 @@ fn main() -> Result<()> { // check if checkpoint if height == block::Height(0) || cumulative_bytes >= MAX_CHECKPOINT_BYTE_COUNT - || height_gap.0 >= zebra_consensus::checkpoint::MAX_CHECKPOINT_HEIGHT_GAP as u32 + || height_gap.0 >= zebra_consensus::MAX_CHECKPOINT_HEIGHT_GAP as u32 { // print to output println!("{} {}", height.0, &hex::encode(hash.0),); diff --git a/zebrad/src/components/sync.rs b/zebrad/src/components/sync.rs index 1609f4b2e..a9362d6a6 100644 --- a/zebrad/src/components/sync.rs +++ b/zebrad/src/components/sync.rs @@ -13,13 +13,12 @@ use zebra_chain::{ block::{self, Block}, parameters::{genesis_hash, Network}, }; -use zebra_consensus::checkpoint; use zebra_network as zn; use zebra_state as zs; /// Controls the number of peers used for each ObtainTips and ExtendTips request. -// XXX in the future, we may not be able to access the checkpoint module. -const FANOUT: usize = checkpoint::MAX_QUEUED_BLOCKS_PER_HEIGHT; +const FANOUT: usize = 4; + /// Controls how many times we will retry each block download. /// /// If all the retries fail, then the syncer will reset, and start downloading @@ -40,7 +39,7 @@ const BLOCK_DOWNLOAD_RETRY_LIMIT: usize = 5; /// /// Some checkpoints contain larger blocks, so the maximum checkpoint gap can /// represent multiple gigabytes of data. -const LOOKAHEAD_LIMIT: usize = checkpoint::MAX_CHECKPOINT_HEIGHT_GAP * 2; +const LOOKAHEAD_LIMIT: usize = zebra_consensus::MAX_CHECKPOINT_HEIGHT_GAP * 2; /// Controls how long we wait for a tips response to return. ///