From 23469b23470d5ed4907c6123e218ccfaca9db193 Mon Sep 17 00:00:00 2001 From: teor Date: Wed, 5 Aug 2020 18:49:21 +1000 Subject: [PATCH] fix: Only ask for blocks within the reorg limit Instead of creating a block locator all the way back to the genesis block, only ask for blocks within the reorg limit (99 blocks). Use the reorg limit as the final locator. (Or if the chain is less than 99 blocks, use the genesis block.) Fixes some instances of #818 at very small block heights. --- zebra-state/src/lib.rs | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/zebra-state/src/lib.rs b/zebra-state/src/lib.rs index 06dd883af..76d96a916 100644 --- a/zebra-state/src/lib.rs +++ b/zebra-state/src/lib.rs @@ -31,6 +31,19 @@ use zebra_chain::{ pub mod in_memory; pub mod on_disk; +/// The maturity threshold for transparent coinbase outputs. +/// +/// A transaction MUST NOT spend a transparent output of a coinbase transaction +/// from a block less than 100 blocks prior to the spend. Note that transparent +/// outputs of coinbase transactions include Founders' Reward outputs. +const MIN_TRASPARENT_COINBASE_MATURITY: BlockHeight = BlockHeight(100); + +/// The maximum chain reorganisation height. +/// +/// Allowing reorganisations past this height could allow double-spends of +/// coinbase transactions. +const MAX_BLOCK_REORG_HEIGHT: BlockHeight = BlockHeight(MIN_TRASPARENT_COINBASE_MATURITY.0 - 1); + /// Configuration for the state service. #[derive(Clone, Debug, Deserialize, Serialize)] #[serde(deny_unknown_fields)] @@ -142,13 +155,27 @@ pub enum Response { /// Get the heights of the blocks for constructing a block_locator list fn block_locator_heights(tip_height: BlockHeight) -> impl Iterator { + // Stop at the reorg limit, or the genesis block. + let min_locator_height = tip_height + .0 + .checked_sub(MAX_BLOCK_REORG_HEIGHT.0) + .map(BlockHeight) + .unwrap_or(BlockHeight(0)); let locators = iter::successors(Some(1u32), |h| h.checked_mul(2)) .flat_map(move |step| tip_height.0.checked_sub(step)) - .filter(|&height| height != 0) + .filter(move |&height| height > min_locator_height.0) .map(BlockHeight); - iter::once(tip_height) + let locators = iter::once(tip_height) .chain(locators) - .chain(iter::once(BlockHeight(0))) + .chain(iter::once(min_locator_height)); + let locators: Vec<_> = locators.collect(); + tracing::info!( + ?tip_height, + ?min_locator_height, + ?locators, + "created block locator" + ); + locators.into_iter() } /// The error type for the State Service.