From b2a9ea62fee6569018ed9cd27662499bd42abc17 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 846583eb..119a97c3 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 9379c88a..bb4488b3 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]