diff --git a/zebra-chain/src/parameters/constants.rs b/zebra-chain/src/parameters/constants.rs index 444b410f330..b20f38d739a 100644 --- a/zebra-chain/src/parameters/constants.rs +++ b/zebra-chain/src/parameters/constants.rs @@ -1,6 +1,7 @@ //! Definitions of Zebra chain constants, including: //! - slow start interval, -//! - slow start shift +//! - slow start shift, +//! - maximum reorg height use crate::block::Height; @@ -16,6 +17,18 @@ pub const SLOW_START_INTERVAL: Height = Height(20_000); /// This calculation is exact, because `SLOW_START_INTERVAL` is divisible by 2. pub const SLOW_START_SHIFT: Height = Height(SLOW_START_INTERVAL.0 / 2); +/// The maximum chain reorganisation height. +/// +/// This threshold determines the maximum length of the best non-finalized +/// chain. Once the chain grows past this height, Zebra finalizes its oldest +/// blocks; deeper reorganisations are outside Zebra's rollback window. +/// +/// This is a local-only node policy; it is not part of consensus. The window is +/// sized as a defence-in-depth measure against sustained consensus splits. +// +// TODO: change to HeightDiff +pub const MAX_BLOCK_REORG_HEIGHT: u32 = 1000; + /// Magic numbers used to identify different Zcash networks. pub mod magics { use crate::parameters::network::magic::Magic; diff --git a/zebra-state/src/constants.rs b/zebra-state/src/constants.rs index 0b368634d35..1b47a6c37c1 100644 --- a/zebra-state/src/constants.rs +++ b/zebra-state/src/constants.rs @@ -25,7 +25,7 @@ pub use zebra_chain::transparent::MIN_TRANSPARENT_COINBASE_MATURITY; /// sized as a defence-in-depth measure against sustained consensus splits. // // TODO: change to HeightDiff -pub const MAX_BLOCK_REORG_HEIGHT: u32 = 1000; +pub const MAX_BLOCK_REORG_HEIGHT: u32 = zebra_chain::parameters::constants::MAX_BLOCK_REORG_HEIGHT; /// The directory name used to distinguish the state database from Zebra's other databases or flat files. pub const STATE_DATABASE_KIND: &str = "state"; diff --git a/zebra-utils/src/bin/zebra-checkpoints/main.rs b/zebra-utils/src/bin/zebra-checkpoints/main.rs index e4cd5a58f2d..2e185581b42 100644 --- a/zebra-utils/src/bin/zebra-checkpoints/main.rs +++ b/zebra-utils/src/bin/zebra-checkpoints/main.rs @@ -23,6 +23,7 @@ use structopt::StructOpt; use zebra_chain::{ block::{self, Block, Height, HeightDiff, TryIntoHeight}, + parameters::constants::MAX_BLOCK_REORG_HEIGHT, serialization::ZcashDeserializeInto, transparent::MIN_TRANSPARENT_COINBASE_MATURITY, }; @@ -32,6 +33,11 @@ use zebra_node_services::{ }; use zebra_utils::init_tracing; +const _: () = assert!( + MAX_BLOCK_REORG_HEIGHT >= MIN_TRANSPARENT_COINBASE_MATURITY, + "checkpoint settlement margin must be at least the coinbase maturity", +); + pub mod args; use args::{Args, Backend, Transport}; @@ -162,14 +168,14 @@ async fn main() -> Result<()> { .try_into_height() .expect("height: unexpected invalid value, missing field, or field type"); - // Checkpoints must be on the main chain, so we skip blocks that are within the - // Zcash reorg limit. - let height_limit = height_limit - HeightDiff::from(MIN_TRANSPARENT_COINBASE_MATURITY); + // Checkpoints must be on a settled part of the best chain, so skip blocks + // within Zebra's rollback window. + let height_limit = height_limit - HeightDiff::from(MAX_BLOCK_REORG_HEIGHT); let height_limit = height_limit .ok_or_else(|| { eyre!( "checkpoint generation needs at least {:?} blocks", - MIN_TRANSPARENT_COINBASE_MATURITY + MAX_BLOCK_REORG_HEIGHT ) }) .with_suggestion(|| "Hint: wait for the node to sync more blocks")?;