From 918a337d8bfef7d2748fb75f462a6cbaa16531bf Mon Sep 17 00:00:00 2001 From: Alfredo Garcia Date: Wed, 29 Dec 2021 20:07:27 -0300 Subject: [PATCH] Document part of the block header consensus rules (#3296) * document header version consensus rule * document nbits threshold consensus rule * document difficulty filter consensus rule * document header solution consensus rule * document header time consensus rule * document upper time limit consensus rule * document max block size consensus rule * skip genesis in conesnsus rule check * remove fixed comment Co-authored-by: teor --- zebra-chain/src/block/serialize.rs | 12 ++++++++++++ zebra-consensus/src/block/check.rs | 17 +++++++++++------ zebra-state/src/service/check.rs | 26 ++++++++++++++++++++++++-- 3 files changed, 47 insertions(+), 8 deletions(-) diff --git a/zebra-chain/src/block/serialize.rs b/zebra-chain/src/block/serialize.rs index 039d8d0a4..edae4824d 100644 --- a/zebra-chain/src/block/serialize.rs +++ b/zebra-chain/src/block/serialize.rs @@ -67,6 +67,12 @@ impl ZcashDeserialize for Header { "high bit was set in version field", )); } + + // # Consensus + // + // > The block version number MUST be greater than or equal to 4. + // + // https://zips.z.cash/protocol/protocol.pdf#blockheader if version < 4 { return Err(SerializationError::Parse("version must be at least 4")); } @@ -115,6 +121,12 @@ impl ZcashSerialize for Block { impl ZcashDeserialize for Block { fn zcash_deserialize(reader: R) -> Result { + // # Consensus + // + // > The size of a block MUST be less than or equal to 2000000 bytes. + // + // https://zips.z.cash/protocol/protocol.pdf#blockheader + // // If the limit is reached, we'll get an UnexpectedEof error let limited_reader = &mut reader.take(MAX_BLOCK_BYTES); Ok(Block { diff --git a/zebra-consensus/src/block/check.rs b/zebra-consensus/src/block/check.rs index 46dc593b2..733b18ca9 100644 --- a/zebra-consensus/src/block/check.rs +++ b/zebra-consensus/src/block/check.rs @@ -71,13 +71,13 @@ pub fn difficulty_is_valid( ))?; } - // The difficulty filter is also context-free. + // # Consensus // - // ZIP 205 and ZIP 208 incorrectly describe testnet minimum difficulty blocks - // as a change to the difficulty filter. But in `zcashd`, it is implemented - // as a change to the difficulty adjustment algorithm. So we don't need to - // do anything special for testnet here. - // For details, see https://github.com/zcash/zips/issues/416 + // > The block MUST pass the difficulty filter. + // + // https://zips.z.cash/protocol/protocol.pdf#blockheader + // + // The difficulty filter is also context-free. if hash > &difficulty_threshold { Err(BlockError::DifficultyFilter( *height, @@ -92,6 +92,11 @@ pub fn difficulty_is_valid( /// Returns `Ok(())` if the `EquihashSolution` is valid for `header` pub fn equihash_solution_is_valid(header: &Header) -> Result<(), equihash::Error> { + // # Consensus + // + // > `solution` MUST represent a valid Equihash solution. + // + // https://zips.z.cash/protocol/protocol.pdf#blockheader header.solution.check(header) } diff --git a/zebra-state/src/service/check.rs b/zebra-state/src/service/check.rs index f8262041f..befd52132 100644 --- a/zebra-state/src/service/check.rs +++ b/zebra-state/src/service/check.rs @@ -229,14 +229,31 @@ fn difficulty_threshold_is_valid( let median_time_past = difficulty_adjustment.median_time_past(); let block_time_max = median_time_past + Duration::seconds(difficulty::BLOCK_MAX_TIME_SINCE_MEDIAN); - if candidate_time <= median_time_past { + + // # Consensus + // + // > For each block other than the genesis block, `nTime` MUST be strictly greater + // than the median-time-past of that block. + // + // https://zips.z.cash/protocol/protocol.pdf#blockheader + let genesis_height = NetworkUpgrade::Genesis + .activation_height(network) + .expect("Zebra always has a genesis height available"); + + if candidate_time <= median_time_past && candidate_height != genesis_height { Err(ValidateContextError::TimeTooEarly { candidate_time, median_time_past, })? } - // The maximum time rule is only active on Testnet from a specific height + // # Consensus + // + // > For each block at block height 2 or greater on Mainnet, or block height 653_606 + // or greater on Testnet, `nTime` MUST be less than or equal to the median-time-past + // of that block plus 90*60 seconds. + // + // https://zips.z.cash/protocol/protocol.pdf#blockheader if NetworkUpgrade::is_max_block_time_enforced(network, candidate_height) && candidate_time > block_time_max { @@ -246,6 +263,11 @@ fn difficulty_threshold_is_valid( })? } + // # Consensus + // + // > For a block at block height `Height`, `nBits` MUST be equal to `ThresholdBits(Height)`. + // + // https://zips.z.cash/protocol/protocol.pdf#blockheader let expected_difficulty = difficulty_adjustment.expected_difficulty_threshold(); if difficulty_threshold != expected_difficulty { Err(ValidateContextError::InvalidDifficultyThreshold {