From c98714fb15e0b86ff3b88edad168e20ea89a78b0 Mon Sep 17 00:00:00 2001 From: teor Date: Wed, 11 Nov 2020 00:48:50 +1000 Subject: [PATCH] Round-trip the PoWLimit through the compact representation `zcashd` converts the PoWLimit into a compact representation before using it to perform difficulty filter checks. The Zcash specification converts to compact for the default difficulty filter, but not for testnet minimum difficulty blocks. (ZIP 205 and ZIP 208 don't specify this conversion either.) See #1277. --- zebra-chain/src/work/difficulty.rs | 11 +++++- .../src/work/difficulty/tests/vectors.rs | 38 +++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/zebra-chain/src/work/difficulty.rs b/zebra-chain/src/work/difficulty.rs index 846583eb89c..119a97c3c22 100644 --- a/zebra-chain/src/work/difficulty.rs +++ b/zebra-chain/src/work/difficulty.rs @@ -280,7 +280,16 @@ impl ExpandedDifficulty { Network::Testnet => (U256::one() << 251) - 1, }; - limit.into() + // `zcashd` converts the PoWLimit into a compact representation before + // using it to perform difficulty filter checks. + // + // The Zcash specification converts to compact for the default difficulty + // filter, but not for testnet minimum difficulty blocks. (ZIP 205 and + // ZIP 208 don't specify this conversion either.) See #1277 for details. + ExpandedDifficulty(limit) + .to_compact() + .to_expanded() + .expect("difficulty limits are valid expanded values") } /// Calculate the CompactDifficulty for an expanded difficulty. diff --git a/zebra-chain/src/work/difficulty/tests/vectors.rs b/zebra-chain/src/work/difficulty/tests/vectors.rs index 9379c88a9a7..bb4488b3513 100644 --- a/zebra-chain/src/work/difficulty/tests/vectors.rs +++ b/zebra-chain/src/work/difficulty/tests/vectors.rs @@ -318,6 +318,44 @@ fn block_difficulty() -> Result<(), Report> { Ok(()) } +/// Test that the genesis block threshold is PowLimit +#[test] +fn genesis_block_difficulty() -> Result<(), Report> { + genesis_block_difficulty_for_network(Network::Mainnet)?; + genesis_block_difficulty_for_network(Network::Testnet)?; + + Ok(()) +} + +#[spandoc::spandoc] +fn genesis_block_difficulty_for_network(network: Network) -> Result<(), Report> { + zebra_test::init(); + + let block = match network { + Network::Mainnet => zebra_test::vectors::MAINNET_BLOCKS.get(&0), + Network::Testnet => zebra_test::vectors::TESTNET_BLOCKS.get(&0), + }; + + let block = block.expect("test vectors contain the genesis block"); + let block = Block::zcash_deserialize(&block[..]).expect("block test vector should deserialize"); + let hash = block.hash(); + + /// SPANDOC: Calculate the threshold for the genesis block {?network} + let threshold = block + .header + .difficulty_threshold + .to_expanded() + .expect("Chain blocks have valid difficulty thresholds."); + + /// SPANDOC: Check the genesis PoWLimit {?network, ?threshold, ?hash} + { + assert_eq!(threshold, ExpandedDifficulty::target_difficulty_limit(network), + "genesis block difficulty thresholds must be equal to the PoWLimit"); + } + + Ok(()) +} + /// Test ExpandedDifficulty ordering #[test] #[spandoc::spandoc]