From cf707545186d3f3f1a7796d2034b52b6b3606962 Mon Sep 17 00:00:00 2001 From: Hazel OHearn Date: Thu, 22 Feb 2024 17:07:18 -0400 Subject: [PATCH 01/22] begin refactor suggested as "step 2": https://github.com/ZcashFoundation/zebra/issues/7968#issue-2003245309 Squashed from multiple commits to enable partial rebase --- zebra-chain/src/parameters/network.rs | 94 +++++++++++++++++++ .../src/primitives/zcash_note_encryption.rs | 24 ++--- zebra-chain/src/transparent/address.rs | 55 ++++++----- .../src/block/subsidy/funding_streams.rs | 12 +-- zebra-consensus/src/block/subsidy/general.rs | 6 +- zebra-consensus/src/checkpoint/list.rs | 6 +- zebra-consensus/src/parameters/subsidy.rs | 12 +++ zebra-network/src/protocol/external/codec.rs | 9 +- 8 files changed, 151 insertions(+), 67 deletions(-) diff --git a/zebra-chain/src/parameters/network.rs b/zebra-chain/src/parameters/network.rs index 15a6d392476..4d78d55be09 100644 --- a/zebra-chain/src/parameters/network.rs +++ b/zebra-chain/src/parameters/network.rs @@ -63,6 +63,100 @@ pub enum Network { Testnet, } +/// A magic number identifying the network. +#[derive(Copy, Clone, Eq, PartialEq)] +#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))] +pub struct Magic(pub [u8; 4]); + +impl fmt::Debug for Magic { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("Magic").field(&hex::encode(self.0)).finish() + } +} + +/// Magic numbers used to identify different Zcash networks. +pub mod magics { + use super::*; + /// The production mainnet. + pub const MAINNET: Magic = Magic([0x24, 0xe9, 0x27, 0x64]); + /// The testnet. + pub const TESTNET: Magic = Magic([0xfa, 0x1a, 0xf9, 0xbf]); +} +pub trait AllParameters: zcash_primitives::consensus::Parameters { + fn height_for_first_halving(&self) -> Height; + fn genesis_hash(&self) -> crate::block::Hash; + fn magic_value(&self) -> Magic; +} +impl AllParameters for Network { + fn height_for_first_halving(&self) -> Height { + match self { + Network::Mainnet => Canopy + .activation_height(*self) + .expect("canopy activation height should be available"), + Network::Testnet => constants::FIRST_HALVING_TESTNET, + } + } + + fn genesis_hash(&self) -> crate::block::Hash { + match self { + // zcash-cli getblockhash 0 + Network::Mainnet => "00040fe8ec8471911baa1db1266ea15dd06b4a8a5c453883c000b031973dce08", + // zcash-cli -testnet getblockhash 0 + Network::Testnet => "05a60a92d99d85997cce3b87616c089f6124d7342af37106edc76126334a2c38", + } + .parse() + .expect("hard-coded hash parses") + } + + fn magic_value(&self) -> Magic { + match self { + Network::Mainnet => magics::MAINNET, + Network::Testnet => magics::TESTNET, + } + } +} +impl zcash_primitives::consensus::Parameters for Network { + fn activation_height( + &self, + nu: zcash_primitives::consensus::NetworkUpgrade, + ) -> Option { + todo!() + } + + fn coin_type(&self) -> u32 { + match self { + Network::Mainnet => zcash_primitives::constants::mainnet::COIN_TYPE, + Network::Testnet => zcash_primitives::constants::testnet::COIN_TYPE, + } + } + + fn address_network(&self) -> Option { + todo!() + } + + fn hrp_sapling_extended_spending_key(&self) -> &str { + todo!() + } + + fn hrp_sapling_extended_full_viewing_key(&self) -> &str { + todo!() + } + + fn hrp_sapling_payment_address(&self) -> &str { + todo!() + } + + fn b58_pubkey_address_prefix(&self) -> [u8; 2] { + match self { + Network::Mainnet => zcash_primitives::constants::mainnet::B58_PUBKEY_ADDRESS_PREFIX, + Network::Testnet => zcash_primitives::constants::testnet::B58_PUBKEY_ADDRESS_PREFIX, + } + } + + fn b58_script_address_prefix(&self) -> [u8; 2] { + todo!() + } +} impl From for &'static str { fn from(network: Network) -> &'static str { match network { diff --git a/zebra-chain/src/primitives/zcash_note_encryption.rs b/zebra-chain/src/primitives/zcash_note_encryption.rs index 6f46af82d27..81cc4a557d8 100644 --- a/zebra-chain/src/primitives/zcash_note_encryption.rs +++ b/zebra-chain/src/primitives/zcash_note_encryption.rs @@ -25,24 +25,12 @@ pub fn decrypts_successfully(transaction: &Transaction, network: Network, height if let Some(bundle) = alt_tx.sapling_bundle() { for output in bundle.shielded_outputs().iter() { - let recovery = match network { - Network::Mainnet => { - zcash_primitives::sapling::note_encryption::try_sapling_output_recovery( - &zcash_primitives::consensus::MAIN_NETWORK, - alt_height, - &null_sapling_ovk, - output, - ) - } - Network::Testnet => { - zcash_primitives::sapling::note_encryption::try_sapling_output_recovery( - &zcash_primitives::consensus::TEST_NETWORK, - alt_height, - &null_sapling_ovk, - output, - ) - } - }; + let recovery = zcash_primitives::sapling::note_encryption::try_sapling_output_recovery( + &network, + alt_height, + &null_sapling_ovk, + output, + ); if recovery.is_none() { return false; } diff --git a/zebra-chain/src/transparent/address.rs b/zebra-chain/src/transparent/address.rs index 0faeb9216fb..48c392cd7bc 100644 --- a/zebra-chain/src/transparent/address.rs +++ b/zebra-chain/src/transparent/address.rs @@ -5,6 +5,7 @@ use std::{fmt, io}; use ripemd::{Digest, Ripemd160}; use secp256k1::PublicKey; use sha2::Sha256; +use zcash_primitives::consensus::Parameters as _; use crate::{ parameters::Network, @@ -118,24 +119,14 @@ impl ZcashSerialize for Address { network, script_hash, } => { - // Dev network doesn't have a recommendation so we - // default to testnet bytes if it's not mainnet. - match *network { - Network::Mainnet => writer.write_all(&magics::p2sh::MAINNET[..])?, - _ => writer.write_all(&magics::p2sh::TESTNET[..])?, - } + writer.write_all(&network.b58_script_address_prefix())?; writer.write_all(script_hash)? } Address::PayToPublicKeyHash { network, pub_key_hash, } => { - // Dev network doesn't have a recommendation so we - // default to testnet bytes if it's not mainnet. - match *network { - Network::Mainnet => writer.write_all(&magics::p2pkh::MAINNET[..])?, - _ => writer.write_all(&magics::p2pkh::TESTNET[..])?, - } + writer.write_all(&network.b58_pubkey_address_prefix())?; writer.write_all(pub_key_hash)? } } @@ -153,22 +144,30 @@ impl ZcashDeserialize for Address { reader.read_exact(&mut hash_bytes)?; match version_bytes { - magics::p2sh::MAINNET => Ok(Address::PayToScriptHash { - network: Network::Mainnet, - script_hash: hash_bytes, - }), - magics::p2sh::TESTNET => Ok(Address::PayToScriptHash { - network: Network::Testnet, - script_hash: hash_bytes, - }), - magics::p2pkh::MAINNET => Ok(Address::PayToPublicKeyHash { - network: Network::Mainnet, - pub_key_hash: hash_bytes, - }), - magics::p2pkh::TESTNET => Ok(Address::PayToPublicKeyHash { - network: Network::Testnet, - pub_key_hash: hash_bytes, - }), + zcash_primitives::constants::mainnet::B58_SCRIPT_ADDRESS_PREFIX => { + Ok(Address::PayToScriptHash { + network: Network::Mainnet, + script_hash: hash_bytes, + }) + } + zcash_primitives::constants::testnet::B58_SCRIPT_ADDRESS_PREFIX => { + Ok(Address::PayToScriptHash { + network: Network::Testnet, + script_hash: hash_bytes, + }) + } + zcash_primitives::constants::mainnet::B58_PUBKEY_ADDRESS_PREFIX => { + Ok(Address::PayToPublicKeyHash { + network: Network::Mainnet, + pub_key_hash: hash_bytes, + }) + } + zcash_primitives::constants::testnet::B58_PUBKEY_ADDRESS_PREFIX => { + Ok(Address::PayToPublicKeyHash { + network: Network::Testnet, + pub_key_hash: hash_bytes, + }) + } _ => Err(SerializationError::Parse("bad t-addr version/type")), } } diff --git a/zebra-consensus/src/block/subsidy/funding_streams.rs b/zebra-consensus/src/block/subsidy/funding_streams.rs index 977b14a56d8..0820040ef58 100644 --- a/zebra-consensus/src/block/subsidy/funding_streams.rs +++ b/zebra-consensus/src/block/subsidy/funding_streams.rs @@ -56,12 +56,7 @@ pub fn height_for_first_halving(network: Network) -> Height { // First halving on Mainnet is at Canopy // while in Testnet is at block constant height of `1_116_000` // https://zips.z.cash/protocol/protocol.pdf#zip214fundingstreams - match network { - Network::Mainnet => Canopy - .activation_height(network) - .expect("canopy activation height should be available"), - Network::Testnet => FIRST_HALVING_TESTNET, - } + network.height_for_first_halving() } /// Returns the address change period @@ -93,10 +88,7 @@ fn funding_stream_address_period(height: Height, network: Network) -> u32 { /// /// [7.10]: https://zips.z.cash/protocol/protocol.pdf#fundingstreams fn funding_stream_address_index(height: Height, network: Network) -> usize { - let num_addresses = match network { - Network::Mainnet => FUNDING_STREAMS_NUM_ADDRESSES_MAINNET, - Network::Testnet => FUNDING_STREAMS_NUM_ADDRESSES_TESTNET, - }; + let num_addresses = network.num_funding_streams(); let index = 1u32 .checked_add(funding_stream_address_period(height, network)) diff --git a/zebra-consensus/src/block/subsidy/general.rs b/zebra-consensus/src/block/subsidy/general.rs index 5be97f3a990..57f33ee1237 100644 --- a/zebra-consensus/src/block/subsidy/general.rs +++ b/zebra-consensus/src/block/subsidy/general.rs @@ -131,11 +131,7 @@ mod test { fn halving_for_network(network: Network) -> Result<(), Report> { let blossom_height = Blossom.activation_height(network).unwrap(); - let first_halving_height = match network { - Network::Mainnet => Canopy.activation_height(network).unwrap(), - // Based on "7.8 Calculation of Block Subsidy and Founders' Reward" - Network::Testnet => Height(1_116_000), - }; + let first_halving_height = network.height_for_first_halving(); assert_eq!( 1, diff --git a/zebra-consensus/src/checkpoint/list.rs b/zebra-consensus/src/checkpoint/list.rs index a22ce888c4b..98a64667064 100644 --- a/zebra-consensus/src/checkpoint/list.rs +++ b/zebra-consensus/src/checkpoint/list.rs @@ -94,7 +94,7 @@ impl CheckpointList { }; match checkpoint_list.hash(block::Height(0)) { - Some(hash) if hash == genesis_hash(network) => checkpoint_list, + Some(hash) if hash == network.genesis_hash() => checkpoint_list, Some(_) => { panic!("The hard-coded genesis checkpoint does not match the network genesis hash") } @@ -123,8 +123,8 @@ impl CheckpointList { // Check that the list starts with the correct genesis block match checkpoints.iter().next() { Some((block::Height(0), hash)) - if (hash == &genesis_hash(Network::Mainnet) - || hash == &genesis_hash(Network::Testnet)) => {} + if (hash == &Network::Mainnet.genesis_hash() + || hash == &Network::Testnet.genesis_hash()) => {} Some((block::Height(0), _)) => { Err("the genesis checkpoint does not match the Mainnet or Testnet genesis hash")? } diff --git a/zebra-consensus/src/parameters/subsidy.rs b/zebra-consensus/src/parameters/subsidy.rs index ba8f910d8e3..80df5b97c0c 100644 --- a/zebra-consensus/src/parameters/subsidy.rs +++ b/zebra-consensus/src/parameters/subsidy.rs @@ -198,6 +198,18 @@ pub const FUNDING_STREAM_ECC_ADDRESSES_MAINNET: [&str; FUNDING_STREAMS_NUM_ADDRE "t3XHAGxRP2FNfhAjxGjxbrQPYtQQjc3RCQD", ]; +pub trait ParameterSubsidy { + fn num_funding_streams(&self) -> usize; +} + +impl ParameterSubsidy for Network { + fn num_funding_streams(&self) -> usize { + match self { + Network::Mainnet => FUNDING_STREAMS_NUM_ADDRESSES_MAINNET, + Network::Testnet => FUNDING_STREAMS_NUM_ADDRESSES_TESTNET, + } + } +} /// List of addresses for the Zcash Foundation funding stream in the Mainnet. pub const FUNDING_STREAM_ZF_ADDRESSES_MAINNET: [&str; FUNDING_STREAMS_NUM_ADDRESSES_MAINNET] = ["t3dvVE3SQEi7kqNzwrfNePxZ1d4hUyztBA1"; FUNDING_STREAMS_NUM_ADDRESSES_MAINNET]; diff --git a/zebra-network/src/protocol/external/codec.rs b/zebra-network/src/protocol/external/codec.rs index 88f54c6b242..79b65b141b5 100644 --- a/zebra-network/src/protocol/external/codec.rs +++ b/zebra-network/src/protocol/external/codec.rs @@ -13,7 +13,10 @@ use tokio_util::codec::{Decoder, Encoder}; use zebra_chain::{ block::{self, Block}, - parameters::Network, + parameters::{ + network::{AllParameters as _, Magic}, + Network, + }, serialization::{ sha256d, zcash_deserialize_bytes_external_count, zcash_deserialize_string_external_count, CompactSizeMessage, FakeWriter, ReadZcashExt, SerializationError as Error, @@ -163,7 +166,7 @@ impl Encoder for Codec { let start_len = dst.len(); { let dst = &mut dst.writer(); - dst.write_all(&Magic::from(self.builder.network).0[..])?; + dst.write_all(&self.builder.network.magic_value().0[..])?; dst.write_all(command)?; dst.write_u32::(body_length as u32)?; @@ -389,7 +392,7 @@ impl Decoder for Codec { "read header from src buffer" ); - if magic != Magic::from(self.builder.network) { + if magic != self.builder.network.magic_value() { return Err(Parse("supplied magic did not meet expectations")); } if body_len > self.builder.max_len { From 72fe76c93449ecdc1ea61295890d81162da6e402 Mon Sep 17 00:00:00 2001 From: Hazel OHearn Date: Thu, 22 Feb 2024 17:34:06 -0400 Subject: [PATCH 02/22] break out more little traits --- zebra-chain/src/parameters/network.rs | 52 ------------------- zebra-chain/src/transparent/address.rs | 14 ----- .../src/block/subsidy/funding_streams.rs | 13 +---- zebra-consensus/src/checkpoint/list.rs | 18 ++++++- zebra-consensus/src/lib.rs | 4 +- zebra-consensus/src/parameters/subsidy.rs | 21 +++++++- zebra-network/src/protocol/external/codec.rs | 5 +- zebra-network/src/protocol/external/types.rs | 11 ++-- .../src/methods/get_block_template_rpcs.rs | 4 +- 9 files changed, 49 insertions(+), 93 deletions(-) diff --git a/zebra-chain/src/parameters/network.rs b/zebra-chain/src/parameters/network.rs index 4d78d55be09..4c16529262f 100644 --- a/zebra-chain/src/parameters/network.rs +++ b/zebra-chain/src/parameters/network.rs @@ -63,58 +63,6 @@ pub enum Network { Testnet, } -/// A magic number identifying the network. -#[derive(Copy, Clone, Eq, PartialEq)] -#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))] -pub struct Magic(pub [u8; 4]); - -impl fmt::Debug for Magic { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("Magic").field(&hex::encode(self.0)).finish() - } -} - -/// Magic numbers used to identify different Zcash networks. -pub mod magics { - use super::*; - /// The production mainnet. - pub const MAINNET: Magic = Magic([0x24, 0xe9, 0x27, 0x64]); - /// The testnet. - pub const TESTNET: Magic = Magic([0xfa, 0x1a, 0xf9, 0xbf]); -} -pub trait AllParameters: zcash_primitives::consensus::Parameters { - fn height_for_first_halving(&self) -> Height; - fn genesis_hash(&self) -> crate::block::Hash; - fn magic_value(&self) -> Magic; -} -impl AllParameters for Network { - fn height_for_first_halving(&self) -> Height { - match self { - Network::Mainnet => Canopy - .activation_height(*self) - .expect("canopy activation height should be available"), - Network::Testnet => constants::FIRST_HALVING_TESTNET, - } - } - - fn genesis_hash(&self) -> crate::block::Hash { - match self { - // zcash-cli getblockhash 0 - Network::Mainnet => "00040fe8ec8471911baa1db1266ea15dd06b4a8a5c453883c000b031973dce08", - // zcash-cli -testnet getblockhash 0 - Network::Testnet => "05a60a92d99d85997cce3b87616c089f6124d7342af37106edc76126334a2c38", - } - .parse() - .expect("hard-coded hash parses") - } - - fn magic_value(&self) -> Magic { - match self { - Network::Mainnet => magics::MAINNET, - Network::Testnet => magics::TESTNET, - } - } -} impl zcash_primitives::consensus::Parameters for Network { fn activation_height( &self, diff --git a/zebra-chain/src/transparent/address.rs b/zebra-chain/src/transparent/address.rs index 48c392cd7bc..b3a134c0996 100644 --- a/zebra-chain/src/transparent/address.rs +++ b/zebra-chain/src/transparent/address.rs @@ -16,20 +16,6 @@ use crate::{ #[cfg(test)] use proptest::prelude::*; -/// Magic numbers used to identify what networks Transparent Addresses -/// are associated with. -mod magics { - pub mod p2sh { - pub const MAINNET: [u8; 2] = [0x1C, 0xBD]; - pub const TESTNET: [u8; 2] = [0x1C, 0xBA]; - } - - pub mod p2pkh { - pub const MAINNET: [u8; 2] = [0x1C, 0xB8]; - pub const TESTNET: [u8; 2] = [0x1D, 0x25]; - } -} - /// Transparent Zcash Addresses /// /// In Bitcoin a single byte is used for the version field identifying diff --git a/zebra-consensus/src/block/subsidy/funding_streams.rs b/zebra-consensus/src/block/subsidy/funding_streams.rs index 0820040ef58..22cfec72998 100644 --- a/zebra-consensus/src/block/subsidy/funding_streams.rs +++ b/zebra-consensus/src/block/subsidy/funding_streams.rs @@ -48,17 +48,6 @@ pub fn funding_stream_values( Ok(results) } -/// Returns the minimum height after the first halving -/// as described in [protocol specification §7.10][7.10] -/// -/// [7.10]: https://zips.z.cash/protocol/protocol.pdf#fundingstreams -pub fn height_for_first_halving(network: Network) -> Height { - // First halving on Mainnet is at Canopy - // while in Testnet is at block constant height of `1_116_000` - // https://zips.z.cash/protocol/protocol.pdf#zip214fundingstreams - network.height_for_first_halving() -} - /// Returns the address change period /// as described in [protocol specification §7.10][7.10] /// @@ -73,7 +62,7 @@ fn funding_stream_address_period(height: Height, network: Network) -> u32 { // // This is the same as `floor()`, because these numbers are all positive. - let height_after_first_halving = height - height_for_first_halving(network); + let height_after_first_halving = height - network.height_for_first_halving(); let address_period = (height_after_first_halving + POST_BLOSSOM_HALVING_INTERVAL) / FUNDING_STREAM_ADDRESS_CHANGE_INTERVAL; diff --git a/zebra-consensus/src/checkpoint/list.rs b/zebra-consensus/src/checkpoint/list.rs index 98a64667064..36ead795ec9 100644 --- a/zebra-consensus/src/checkpoint/list.rs +++ b/zebra-consensus/src/checkpoint/list.rs @@ -17,7 +17,7 @@ use std::{ }; use zebra_chain::block; -use zebra_chain::parameters::{genesis_hash, Network}; +use zebra_chain::parameters::Network; /// The hard-coded checkpoints for mainnet, generated using the /// `zebra-checkpoints` tool. @@ -42,6 +42,22 @@ const MAINNET_CHECKPOINTS: &str = include_str!("main-checkpoints.txt"); /// See [`MAINNET_CHECKPOINTS`] for detailed `zebra-checkpoints` usage /// information. const TESTNET_CHECKPOINTS: &str = include_str!("test-checkpoints.txt"); +pub trait ParameterCheckpoint { + fn genesis_hash(&self) -> zebra_chain::block::Hash; +} + +impl ParameterCheckpoint for Network { + fn genesis_hash(&self) -> zebra_chain::block::Hash { + match self { + // zcash-cli getblockhash 0 + Network::Mainnet => "00040fe8ec8471911baa1db1266ea15dd06b4a8a5c453883c000b031973dce08", + // zcash-cli -testnet getblockhash 0 + Network::Testnet => "05a60a92d99d85997cce3b87616c089f6124d7342af37106edc76126334a2c38", + } + .parse() + .expect("hard-coded hash parses") + } +} /// A list of block height and hash checkpoints. /// diff --git a/zebra-consensus/src/lib.rs b/zebra-consensus/src/lib.rs index 253c11d4912..d872e0c594e 100644 --- a/zebra-consensus/src/lib.rs +++ b/zebra-consensus/src/lib.rs @@ -49,7 +49,7 @@ pub use block::{ subsidy::{ funding_streams::{ funding_stream_address, funding_stream_recipient_info, funding_stream_values, - height_for_first_halving, new_coinbase_script, + new_coinbase_script, }, general::miner_subsidy, }, @@ -60,7 +60,7 @@ pub use checkpoint::{ }; pub use config::Config; pub use error::BlockError; -pub use parameters::FundingStreamReceiver; +pub use parameters::{FundingStreamReceiver, ParameterSubsidy}; pub use primitives::{ed25519, groth16, halo2, redjubjub, redpallas}; pub use router::RouterError; diff --git a/zebra-consensus/src/parameters/subsidy.rs b/zebra-consensus/src/parameters/subsidy.rs index 80df5b97c0c..5857a1b1c3b 100644 --- a/zebra-consensus/src/parameters/subsidy.rs +++ b/zebra-consensus/src/parameters/subsidy.rs @@ -7,7 +7,7 @@ use lazy_static::lazy_static; use zebra_chain::{ amount::COIN, block::{Height, HeightDiff}, - parameters::Network, + parameters::{Network, NetworkUpgrade}, }; /// An initial period from Genesis to this Height where the block subsidy is gradually incremented. [What is slow-start mining][slow-mining] @@ -200,15 +200,34 @@ pub const FUNDING_STREAM_ECC_ADDRESSES_MAINNET: [&str; FUNDING_STREAMS_NUM_ADDRE pub trait ParameterSubsidy { fn num_funding_streams(&self) -> usize; + fn height_for_first_halving(&self) -> Height; } +/// Network methods related to Block Subsidy and Funding Streams impl ParameterSubsidy for Network { + /// Number of addresses for each funding stream in the Network. + /// [7.10]: https://zips.z.cash/protocol/protocol.pdf#fundingstreams fn num_funding_streams(&self) -> usize { match self { Network::Mainnet => FUNDING_STREAMS_NUM_ADDRESSES_MAINNET, Network::Testnet => FUNDING_STREAMS_NUM_ADDRESSES_TESTNET, } } + /// Returns the minimum height after the first halving + /// as described in [protocol specification §7.10][7.10] + /// + /// [7.10]: https://zips.z.cash/protocol/protocol.pdf#fundingstreams + fn height_for_first_halving(&self) -> Height { + // First halving on Mainnet is at Canopy + // while in Testnet is at block constant height of `1_116_000` + // https://zips.z.cash/protocol/protocol.pdf#zip214fundingstreams + match self { + Network::Mainnet => NetworkUpgrade::Canopy + .activation_height(*self) + .expect("canopy activation height should be available"), + Network::Testnet => FIRST_HALVING_TESTNET, + } + } } /// List of addresses for the Zcash Foundation funding stream in the Mainnet. pub const FUNDING_STREAM_ZF_ADDRESSES_MAINNET: [&str; FUNDING_STREAMS_NUM_ADDRESSES_MAINNET] = diff --git a/zebra-network/src/protocol/external/codec.rs b/zebra-network/src/protocol/external/codec.rs index 79b65b141b5..d511b50f7db 100644 --- a/zebra-network/src/protocol/external/codec.rs +++ b/zebra-network/src/protocol/external/codec.rs @@ -13,10 +13,7 @@ use tokio_util::codec::{Decoder, Encoder}; use zebra_chain::{ block::{self, Block}, - parameters::{ - network::{AllParameters as _, Magic}, - Network, - }, + parameters::Network, serialization::{ sha256d, zcash_deserialize_bytes_external_count, zcash_deserialize_string_external_count, CompactSizeMessage, FakeWriter, ReadZcashExt, SerializationError as Error, diff --git a/zebra-network/src/protocol/external/types.rs b/zebra-network/src/protocol/external/types.rs index 8cf65765b21..87a5449064d 100644 --- a/zebra-network/src/protocol/external/types.rs +++ b/zebra-network/src/protocol/external/types.rs @@ -23,11 +23,12 @@ impl fmt::Debug for Magic { f.debug_tuple("Magic").field(&hex::encode(self.0)).finish() } } - -impl From for Magic { - /// Get the magic value associated to this `Network`. - fn from(network: Network) -> Self { - match network { +pub trait ParameterMagic { + fn magic_value(&self) -> Magic; +} +impl ParameterMagic for Network { + fn magic_value(&self) -> Magic { + match self { Network::Mainnet => magics::MAINNET, Network::Testnet => magics::TESTNET, } diff --git a/zebra-rpc/src/methods/get_block_template_rpcs.rs b/zebra-rpc/src/methods/get_block_template_rpcs.rs index 7d0550c0598..54ad7daed16 100644 --- a/zebra-rpc/src/methods/get_block_template_rpcs.rs +++ b/zebra-rpc/src/methods/get_block_template_rpcs.rs @@ -23,7 +23,7 @@ use zebra_chain::{ work::difficulty::{ExpandedDifficulty, U256}, }; use zebra_consensus::{ - funding_stream_address, funding_stream_values, height_for_first_halving, miner_subsidy, + funding_stream_address, funding_stream_values, miner_subsidy, ParameterSubsidy as _, RouterError, }; use zebra_network::AddressBookPeers; @@ -1098,7 +1098,7 @@ where best_chain_tip_height(&latest_chain_tip)? }; - if height < height_for_first_halving(network) { + if height < network.height_for_first_halving() { return Err(Error { code: ErrorCode::ServerError(0), message: "Zebra does not support founders' reward subsidies, \ From 2c5dcbf62f0474a5be1d9fcfbb26ded481db3f2c Mon Sep 17 00:00:00 2001 From: zancas Date: Thu, 22 Feb 2024 19:57:13 -0700 Subject: [PATCH 03/22] add activation implementation leveraging From for lrz::cons:: --- zebra-chain/src/parameters/network.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/zebra-chain/src/parameters/network.rs b/zebra-chain/src/parameters/network.rs index 4c16529262f..dbf2c9330e9 100644 --- a/zebra-chain/src/parameters/network.rs +++ b/zebra-chain/src/parameters/network.rs @@ -62,13 +62,14 @@ pub enum Network { /// The oldest public test network. Testnet, } - impl zcash_primitives::consensus::Parameters for Network { fn activation_height( &self, nu: zcash_primitives::consensus::NetworkUpgrade, ) -> Option { - todo!() + // Convert `self` (zebra-chain's Network) to librustzcash's Network + let librustzcash_network: zcash_primitives::consensus::Network = (*self).into(); + librustzcash_network.activation_height(nu) } fn coin_type(&self) -> u32 { From ad8530d609badfe7dba6a15accd7b31e36fa1c2a Mon Sep 17 00:00:00 2001 From: zancas Date: Thu, 22 Feb 2024 20:27:09 -0700 Subject: [PATCH 04/22] for transfer of ownership I cannot return a type that's owned by the method --- zebra-chain/src/parameters/network.rs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/zebra-chain/src/parameters/network.rs b/zebra-chain/src/parameters/network.rs index dbf2c9330e9..d01835ab997 100644 --- a/zebra-chain/src/parameters/network.rs +++ b/zebra-chain/src/parameters/network.rs @@ -62,29 +62,33 @@ pub enum Network { /// The oldest public test network. Testnet, } +use zcash_primitives::consensus::Network as ZcashPrimitivesNetwork; impl zcash_primitives::consensus::Parameters for Network { fn activation_height( &self, nu: zcash_primitives::consensus::NetworkUpgrade, ) -> Option { // Convert `self` (zebra-chain's Network) to librustzcash's Network - let librustzcash_network: zcash_primitives::consensus::Network = (*self).into(); - librustzcash_network.activation_height(nu) + ZcashPrimitivesNetwork::from(*self).activation_height(nu) } fn coin_type(&self) -> u32 { - match self { - Network::Mainnet => zcash_primitives::constants::mainnet::COIN_TYPE, - Network::Testnet => zcash_primitives::constants::testnet::COIN_TYPE, - } + ZcashPrimitivesNetwork::from(*self).coin_type() } fn address_network(&self) -> Option { - todo!() + ZcashPrimitivesNetwork::from(*self).address_network() } fn hrp_sapling_extended_spending_key(&self) -> &str { - todo!() + match self { + Network::Mainnet => { + zcash_primitives::consensus::MAIN_NETWORK.hrp_sapling_extended_spending_key() + } + Network::Testnet => { + zcash_primitives::consensus::TEST_NETWORK.hrp_sapling_extended_spending_key() + } + } } fn hrp_sapling_extended_full_viewing_key(&self) -> &str { From a43134a74432d5a9add0c7d0ba1623ed59d5658c Mon Sep 17 00:00:00 2001 From: zancas Date: Thu, 22 Feb 2024 20:30:30 -0700 Subject: [PATCH 05/22] hrp_sapling_extended_full_viewing_key --- zebra-chain/src/parameters/network.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/zebra-chain/src/parameters/network.rs b/zebra-chain/src/parameters/network.rs index d01835ab997..e1368750045 100644 --- a/zebra-chain/src/parameters/network.rs +++ b/zebra-chain/src/parameters/network.rs @@ -92,7 +92,14 @@ impl zcash_primitives::consensus::Parameters for Network { } fn hrp_sapling_extended_full_viewing_key(&self) -> &str { - todo!() + match self { + Network::Mainnet => { + zcash_primitives::consensus::MAIN_NETWORK.hrp_sapling_extended_full_viewing_key() + } + Network::Testnet => { + zcash_primitives::consensus::TEST_NETWORK.hrp_sapling_extended_full_viewing_key() + } + } } fn hrp_sapling_payment_address(&self) -> &str { From 950a3b6348feea4c873650f1d17ba403820b20c1 Mon Sep 17 00:00:00 2001 From: zancas Date: Thu, 22 Feb 2024 20:38:34 -0700 Subject: [PATCH 06/22] complete implementation of interface of Parameters on Network reuse Parameters on zcash Network where possible --- zebra-chain/src/parameters/network.rs | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/zebra-chain/src/parameters/network.rs b/zebra-chain/src/parameters/network.rs index e1368750045..e2c773e5fe0 100644 --- a/zebra-chain/src/parameters/network.rs +++ b/zebra-chain/src/parameters/network.rs @@ -103,18 +103,36 @@ impl zcash_primitives::consensus::Parameters for Network { } fn hrp_sapling_payment_address(&self) -> &str { - todo!() + match self { + Network::Mainnet => { + zcash_primitives::consensus::MAIN_NETWORK.hrp_sapling_payment_address() + } + Network::Testnet => { + zcash_primitives::consensus::TEST_NETWORK.hrp_sapling_payment_address() + } + } } fn b58_pubkey_address_prefix(&self) -> [u8; 2] { match self { - Network::Mainnet => zcash_primitives::constants::mainnet::B58_PUBKEY_ADDRESS_PREFIX, - Network::Testnet => zcash_primitives::constants::testnet::B58_PUBKEY_ADDRESS_PREFIX, + Network::Mainnet => { + zcash_primitives::consensus::MAIN_NETWORK.b58_pubkey_address_prefix() + } + Network::Testnet => { + zcash_primitives::consensus::TEST_NETWORK.b58_pubkey_address_prefix() + } } } fn b58_script_address_prefix(&self) -> [u8; 2] { - todo!() + match self { + Network::Mainnet => { + zcash_primitives::consensus::MAIN_NETWORK.b58_script_address_prefix() + } + Network::Testnet => { + zcash_primitives::consensus::TEST_NETWORK.b58_script_address_prefix() + } + } } } impl From for &'static str { From 74770c6a4312968088fa07ffb4ed9902ef7b2de8 Mon Sep 17 00:00:00 2001 From: zancas Date: Thu, 22 Feb 2024 21:03:44 -0700 Subject: [PATCH 07/22] move doc-comments to trait declarations (from impls) --- zebra-consensus/src/parameters/subsidy.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/zebra-consensus/src/parameters/subsidy.rs b/zebra-consensus/src/parameters/subsidy.rs index 5857a1b1c3b..50dd78d8ba5 100644 --- a/zebra-consensus/src/parameters/subsidy.rs +++ b/zebra-consensus/src/parameters/subsidy.rs @@ -198,25 +198,26 @@ pub const FUNDING_STREAM_ECC_ADDRESSES_MAINNET: [&str; FUNDING_STREAMS_NUM_ADDRE "t3XHAGxRP2FNfhAjxGjxbrQPYtQQjc3RCQD", ]; +/// Functionality specific to block subsidy-related consensus rules pub trait ParameterSubsidy { + /// Number of addresses for each funding stream in the Network. + /// [7.10]: https://zips.z.cash/protocol/protocol.pdf#fundingstreams fn num_funding_streams(&self) -> usize; + /// Returns the minimum height after the first halving + /// as described in [protocol specification §7.10][7.10] + /// + /// [7.10]: https://zips.z.cash/protocol/protocol.pdf#fundingstreams fn height_for_first_halving(&self) -> Height; } /// Network methods related to Block Subsidy and Funding Streams impl ParameterSubsidy for Network { - /// Number of addresses for each funding stream in the Network. - /// [7.10]: https://zips.z.cash/protocol/protocol.pdf#fundingstreams fn num_funding_streams(&self) -> usize { match self { Network::Mainnet => FUNDING_STREAMS_NUM_ADDRESSES_MAINNET, Network::Testnet => FUNDING_STREAMS_NUM_ADDRESSES_TESTNET, } } - /// Returns the minimum height after the first halving - /// as described in [protocol specification §7.10][7.10] - /// - /// [7.10]: https://zips.z.cash/protocol/protocol.pdf#fundingstreams fn height_for_first_halving(&self) -> Height { // First halving on Mainnet is at Canopy // while in Testnet is at block constant height of `1_116_000` From e6d874bbe00838b787e4ca0729cb5d962f19ab42 Mon Sep 17 00:00:00 2001 From: Hazel OHearn Date: Thu, 29 Feb 2024 14:21:26 -0400 Subject: [PATCH 08/22] Simplify/complete Parameters impl for Network --- zebra-chain/src/parameters/network.rs | 51 +++---------------- .../src/primitives/zcash_primitives.rs | 6 +-- zebra-scan/src/service/scan_task/scan.rs | 4 +- 3 files changed, 13 insertions(+), 48 deletions(-) diff --git a/zebra-chain/src/parameters/network.rs b/zebra-chain/src/parameters/network.rs index e2c773e5fe0..a79cb1acf57 100644 --- a/zebra-chain/src/parameters/network.rs +++ b/zebra-chain/src/parameters/network.rs @@ -69,70 +69,35 @@ impl zcash_primitives::consensus::Parameters for Network { nu: zcash_primitives::consensus::NetworkUpgrade, ) -> Option { // Convert `self` (zebra-chain's Network) to librustzcash's Network - ZcashPrimitivesNetwork::from(*self).activation_height(nu) + <&ZcashPrimitivesNetwork>::from(*self).activation_height(nu) } fn coin_type(&self) -> u32 { - ZcashPrimitivesNetwork::from(*self).coin_type() + <&ZcashPrimitivesNetwork>::from(*self).coin_type() } fn address_network(&self) -> Option { - ZcashPrimitivesNetwork::from(*self).address_network() + <&ZcashPrimitivesNetwork>::from(*self).address_network() } fn hrp_sapling_extended_spending_key(&self) -> &str { - match self { - Network::Mainnet => { - zcash_primitives::consensus::MAIN_NETWORK.hrp_sapling_extended_spending_key() - } - Network::Testnet => { - zcash_primitives::consensus::TEST_NETWORK.hrp_sapling_extended_spending_key() - } - } + <&ZcashPrimitivesNetwork>::from(*self).hrp_sapling_extended_spending_key() } fn hrp_sapling_extended_full_viewing_key(&self) -> &str { - match self { - Network::Mainnet => { - zcash_primitives::consensus::MAIN_NETWORK.hrp_sapling_extended_full_viewing_key() - } - Network::Testnet => { - zcash_primitives::consensus::TEST_NETWORK.hrp_sapling_extended_full_viewing_key() - } - } + <&ZcashPrimitivesNetwork>::from(*self).hrp_sapling_extended_full_viewing_key() } fn hrp_sapling_payment_address(&self) -> &str { - match self { - Network::Mainnet => { - zcash_primitives::consensus::MAIN_NETWORK.hrp_sapling_payment_address() - } - Network::Testnet => { - zcash_primitives::consensus::TEST_NETWORK.hrp_sapling_payment_address() - } - } + <&ZcashPrimitivesNetwork>::from(*self).hrp_sapling_payment_address() } fn b58_pubkey_address_prefix(&self) -> [u8; 2] { - match self { - Network::Mainnet => { - zcash_primitives::consensus::MAIN_NETWORK.b58_pubkey_address_prefix() - } - Network::Testnet => { - zcash_primitives::consensus::TEST_NETWORK.b58_pubkey_address_prefix() - } - } + <&ZcashPrimitivesNetwork>::from(*self).b58_pubkey_address_prefix() } fn b58_script_address_prefix(&self) -> [u8; 2] { - match self { - Network::Mainnet => { - zcash_primitives::consensus::MAIN_NETWORK.b58_script_address_prefix() - } - Network::Testnet => { - zcash_primitives::consensus::TEST_NETWORK.b58_script_address_prefix() - } - } + <&ZcashPrimitivesNetwork>::from(*self).b58_script_address_prefix() } } impl From for &'static str { diff --git a/zebra-chain/src/primitives/zcash_primitives.rs b/zebra-chain/src/primitives/zcash_primitives.rs index a9fbd9f4b95..113997eab96 100644 --- a/zebra-chain/src/primitives/zcash_primitives.rs +++ b/zebra-chain/src/primitives/zcash_primitives.rs @@ -337,11 +337,11 @@ pub(crate) fn transparent_output_address( } } -impl From for zcash_primitives::consensus::Network { +impl From for &zcash_primitives::consensus::Network { fn from(network: Network) -> Self { match network { - Network::Mainnet => zcash_primitives::consensus::Network::MainNetwork, - Network::Testnet => zcash_primitives::consensus::Network::TestNetwork, + Network::Mainnet => &zcash_primitives::consensus::Network::MainNetwork, + Network::Testnet => &zcash_primitives::consensus::Network::TestNetwork, } } } diff --git a/zebra-scan/src/service/scan_task/scan.rs b/zebra-scan/src/service/scan_task/scan.rs index 898183fe135..405182c67ed 100644 --- a/zebra-scan/src/service/scan_task/scan.rs +++ b/zebra-scan/src/service/scan_task/scan.rs @@ -383,7 +383,7 @@ pub fn scan_block( // TODO: Implement a check that returns early when the block height is below the Sapling // activation height. - let network: zcash_primitives::consensus::Network = network.into(); + let network: &zcash_primitives::consensus::Network = Into::into(network); let chain_metadata = ChainMetadata { sapling_commitment_tree_size: sapling_tree_size, @@ -399,7 +399,7 @@ pub fn scan_block( .collect(); zcash_client_backend::scanning::scan_block( - &network, + network, block_to_compact(block, chain_metadata), scanning_keys.as_slice(), // Ignore whether notes are change from a viewer's own spends for now. From aee311d18db389f0548c7cfb843fe8d6e6736b00 Mon Sep 17 00:00:00 2001 From: Hazel OHearn Date: Thu, 29 Feb 2024 16:17:09 -0400 Subject: [PATCH 09/22] Add checkpoint_list method, move documentation, etc --- zebra-chain/src/parameters/genesis.rs | 16 +------ zebra-chain/src/work/difficulty.rs | 50 +++++++++++++------- zebra-consensus/src/block/subsidy/general.rs | 6 +-- zebra-consensus/src/checkpoint/list.rs | 43 ++++++++++------- zebra-consensus/src/lib.rs | 3 +- zebrad/src/components/sync.rs | 4 +- 6 files changed, 65 insertions(+), 57 deletions(-) diff --git a/zebra-chain/src/parameters/genesis.rs b/zebra-chain/src/parameters/genesis.rs index 41f2b7be8de..04d1bad6ec2 100644 --- a/zebra-chain/src/parameters/genesis.rs +++ b/zebra-chain/src/parameters/genesis.rs @@ -1,21 +1,7 @@ //! Genesis consensus parameters for each Zcash network. -use crate::{block, parameters::Network}; - /// The previous block hash for the genesis block. /// /// All known networks use the Bitcoin `null` value for the parent of the /// genesis block. (In Bitcoin, `null` is `[0; 32]`.) -pub const GENESIS_PREVIOUS_BLOCK_HASH: block::Hash = block::Hash([0; 32]); - -/// Returns the hash for the genesis block in `network`. -pub fn genesis_hash(network: Network) -> block::Hash { - match network { - // zcash-cli getblockhash 0 - Network::Mainnet => "00040fe8ec8471911baa1db1266ea15dd06b4a8a5c453883c000b031973dce08", - // zcash-cli -testnet getblockhash 0 - Network::Testnet => "05a60a92d99d85997cce3b87616c089f6124d7342af37106edc76126334a2c38", - } - .parse() - .expect("hard-coded hash parses") -} +pub const GENESIS_PREVIOUS_BLOCK_HASH: crate::block::Hash = crate::block::Hash([0; 32]); diff --git a/zebra-chain/src/work/difficulty.rs b/zebra-chain/src/work/difficulty.rs index 4724188060c..0b5c23c3f9a 100644 --- a/zebra-chain/src/work/difficulty.rs +++ b/zebra-chain/src/work/difficulty.rs @@ -391,23 +391,7 @@ impl ExpandedDifficulty { /// See `PoWLimit` in the Zcash specification: /// pub fn target_difficulty_limit(network: Network) -> ExpandedDifficulty { - let limit: U256 = match network { - /* 2^243 - 1 */ - Network::Mainnet => (U256::one() << 243) - 1, - /* 2^251 - 1 */ - Network::Testnet => (U256::one() << 251) - 1, - }; - - // `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") + network.target_difficulty_limit() } /// Calculate the CompactDifficulty for an expanded difficulty. @@ -705,6 +689,38 @@ impl PartialCumulativeWork { } } +trait ParameterDifficulty { + fn target_difficulty_limit(&self) -> ExpandedDifficulty; +} + +impl ParameterDifficulty for Network { + /// Returns the easiest target difficulty allowed on `network`. + /// + /// # Consensus + /// + /// See `PoWLimit` in the Zcash specification: + /// + fn target_difficulty_limit(&self) -> ExpandedDifficulty { + let limit: U256 = match self { + /* 2^243 - 1 */ + Network::Mainnet => (U256::one() << 243) - 1, + /* 2^251 - 1 */ + Network::Testnet => (U256::one() << 251) - 1, + }; + + // `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") + } +} + impl From for PartialCumulativeWork { fn from(work: Work) -> Self { PartialCumulativeWork(work.0) diff --git a/zebra-consensus/src/block/subsidy/general.rs b/zebra-consensus/src/block/subsidy/general.rs index 57f33ee1237..c906541e010 100644 --- a/zebra-consensus/src/block/subsidy/general.rs +++ b/zebra-consensus/src/block/subsidy/general.rs @@ -257,11 +257,7 @@ mod test { fn block_subsidy_for_network(network: Network) -> Result<(), Report> { let blossom_height = Blossom.activation_height(network).unwrap(); - let first_halving_height = match network { - Network::Mainnet => Canopy.activation_height(network).unwrap(), - // Based on "7.8 Calculation of Block Subsidy and Founders' Reward" - Network::Testnet => Height(1_116_000), - }; + let first_halving_height = network.height_for_first_halving(); // After slow-start mining and before Blossom the block subsidy is 12.5 ZEC // https://z.cash/support/faq/#what-is-slow-start-mining diff --git a/zebra-consensus/src/checkpoint/list.rs b/zebra-consensus/src/checkpoint/list.rs index 36ead795ec9..6e37af76e7b 100644 --- a/zebra-consensus/src/checkpoint/list.rs +++ b/zebra-consensus/src/checkpoint/list.rs @@ -42,8 +42,13 @@ const MAINNET_CHECKPOINTS: &str = include_str!("main-checkpoints.txt"); /// See [`MAINNET_CHECKPOINTS`] for detailed `zebra-checkpoints` usage /// information. const TESTNET_CHECKPOINTS: &str = include_str!("test-checkpoints.txt"); + +/// Network methods related to checkpoints pub trait ParameterCheckpoint { + /// Returns the hash for the genesis block in `network`. fn genesis_hash(&self) -> zebra_chain::block::Hash; + /// Returns the hard-coded checkpoint list for `network`. + fn checkpoint_list(&self) -> CheckpointList; } impl ParameterCheckpoint for Network { @@ -57,6 +62,26 @@ impl ParameterCheckpoint for Network { .parse() .expect("hard-coded hash parses") } + + fn checkpoint_list(&self) -> CheckpointList { + // parse calls CheckpointList::from_list + let checkpoint_list: CheckpointList = match self { + Network::Mainnet => MAINNET_CHECKPOINTS + .parse() + .expect("Hard-coded Mainnet checkpoint list parses and validates"), + Network::Testnet => TESTNET_CHECKPOINTS + .parse() + .expect("Hard-coded Testnet checkpoint list parses and validates"), + }; + + match checkpoint_list.hash(block::Height(0)) { + Some(hash) if hash == self.genesis_hash() => checkpoint_list, + Some(_) => { + panic!("The hard-coded genesis checkpoint does not match the network genesis hash") + } + None => unreachable!("Parser should have checked for a missing genesis checkpoint"), + } + } } /// A list of block height and hash checkpoints. @@ -99,23 +124,7 @@ impl FromStr for CheckpointList { impl CheckpointList { /// Returns the hard-coded checkpoint list for `network`. pub fn new(network: Network) -> Self { - // parse calls CheckpointList::from_list - let checkpoint_list: CheckpointList = match network { - Network::Mainnet => MAINNET_CHECKPOINTS - .parse() - .expect("Hard-coded Mainnet checkpoint list parses and validates"), - Network::Testnet => TESTNET_CHECKPOINTS - .parse() - .expect("Hard-coded Testnet checkpoint list parses and validates"), - }; - - match checkpoint_list.hash(block::Height(0)) { - Some(hash) if hash == network.genesis_hash() => checkpoint_list, - Some(_) => { - panic!("The hard-coded genesis checkpoint does not match the network genesis hash") - } - None => unreachable!("Parser should have checked for a missing genesis checkpoint"), - } + network.checkpoint_list() } /// Create a new checkpoint list for `network` from `checkpoint_list`. diff --git a/zebra-consensus/src/lib.rs b/zebra-consensus/src/lib.rs index d872e0c594e..97fab5150d2 100644 --- a/zebra-consensus/src/lib.rs +++ b/zebra-consensus/src/lib.rs @@ -56,7 +56,8 @@ pub use block::{ Request, VerifyBlockError, MAX_BLOCK_SIGOPS, }; pub use checkpoint::{ - CheckpointList, VerifyCheckpointError, MAX_CHECKPOINT_BYTE_COUNT, MAX_CHECKPOINT_HEIGHT_GAP, + list::ParameterCheckpoint, CheckpointList, VerifyCheckpointError, MAX_CHECKPOINT_BYTE_COUNT, + MAX_CHECKPOINT_HEIGHT_GAP, }; pub use config::Config; pub use error::BlockError; diff --git a/zebrad/src/components/sync.rs b/zebrad/src/components/sync.rs index 651dacc1f8d..cbfd5e7b64c 100644 --- a/zebrad/src/components/sync.rs +++ b/zebrad/src/components/sync.rs @@ -21,8 +21,8 @@ use tower::{ use zebra_chain::{ block::{self, Height, HeightDiff}, chain_tip::ChainTip, - parameters::genesis_hash, }; +use zebra_consensus::ParameterCheckpoint as _; use zebra_network as zn; use zebra_state as zs; @@ -500,7 +500,7 @@ where )); let new_syncer = Self { - genesis_hash: genesis_hash(config.network.network), + genesis_hash: config.network.network.genesis_hash(), max_checkpoint_height, checkpoint_verify_concurrency_limit, full_verify_concurrency_limit, From f561645b9a901bea2027e6f85de49c4cb22a62e9 Mon Sep 17 00:00:00 2001 From: Hazel OHearn Date: Mon, 4 Mar 2024 15:20:18 -0400 Subject: [PATCH 10/22] move last match network to inside network method --- zebra-chain/src/parameters/network_upgrade.rs | 20 +++++++++++-------- zebra-chain/src/parameters/tests.rs | 12 +++++------ zebra-rpc/src/methods.rs | 2 +- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/zebra-chain/src/parameters/network_upgrade.rs b/zebra-chain/src/parameters/network_upgrade.rs index 451d7fe3e0c..6aa534e3cd7 100644 --- a/zebra-chain/src/parameters/network_upgrade.rs +++ b/zebra-chain/src/parameters/network_upgrade.rs @@ -229,7 +229,7 @@ const TESTNET_MINIMUM_DIFFICULTY_START_HEIGHT: block::Height = block::Height(299 /// pub const TESTNET_MAX_TIME_START_HEIGHT: block::Height = block::Height(653_606); -impl NetworkUpgrade { +impl Network { /// Returns a map between activation heights and network upgrades for `network`, /// in ascending height order. /// @@ -241,7 +241,7 @@ impl NetworkUpgrade { /// When the environment variable TEST_FAKE_ACTIVATION_HEIGHTS is set /// and it's a test build, this returns a list of fake activation heights /// used by some tests. - pub fn activation_list(network: Network) -> BTreeMap { + pub fn activation_list(&self) -> BTreeMap { let (mainnet_heights, testnet_heights) = { #[cfg(not(feature = "zebra-test"))] { @@ -269,7 +269,7 @@ impl NetworkUpgrade { (MAINNET_ACTIVATION_HEIGHTS, TESTNET_ACTIVATION_HEIGHTS) } }; - match network { + match self { Mainnet => mainnet_heights, Testnet => testnet_heights, } @@ -277,10 +277,12 @@ impl NetworkUpgrade { .cloned() .collect() } - +} +impl NetworkUpgrade { /// Returns the current network upgrade for `network` and `height`. pub fn current(network: Network, height: block::Height) -> NetworkUpgrade { - NetworkUpgrade::activation_list(network) + network + .activation_list() .range(..=height) .map(|(_, nu)| *nu) .next_back() @@ -292,7 +294,8 @@ impl NetworkUpgrade { /// Returns None if the next upgrade has not been implemented in Zebra /// yet. pub fn next(network: Network, height: block::Height) -> Option { - NetworkUpgrade::activation_list(network) + network + .activation_list() .range((Excluded(height), Unbounded)) .map(|(_, nu)| *nu) .next() @@ -303,7 +306,8 @@ impl NetworkUpgrade { /// Returns None if this network upgrade is a future upgrade, and its /// activation height has not been set yet. pub fn activation_height(&self, network: Network) -> Option { - NetworkUpgrade::activation_list(network) + network + .activation_list() .iter() .filter(|(_, nu)| nu == &self) .map(|(height, _)| *height) @@ -316,7 +320,7 @@ impl NetworkUpgrade { /// Use [`NetworkUpgrade::activation_height`] to get the specific network /// upgrade. pub fn is_activation_height(network: Network, height: block::Height) -> bool { - NetworkUpgrade::activation_list(network).contains_key(&height) + network.activation_list().contains_key(&height) } /// Returns an unordered mapping between NetworkUpgrades and their ConsensusBranchIds. diff --git a/zebra-chain/src/parameters/tests.rs b/zebra-chain/src/parameters/tests.rs index 0525b540e6e..ac4e4ca6918 100644 --- a/zebra-chain/src/parameters/tests.rs +++ b/zebra-chain/src/parameters/tests.rs @@ -14,14 +14,14 @@ use NetworkUpgrade::*; fn activation_bijective() { let _init_guard = zebra_test::init(); - let mainnet_activations = NetworkUpgrade::activation_list(Mainnet); + let mainnet_activations = Mainnet.activation_list(); let mainnet_heights: HashSet<&block::Height> = mainnet_activations.keys().collect(); assert_eq!(MAINNET_ACTIVATION_HEIGHTS.len(), mainnet_heights.len()); let mainnet_nus: HashSet<&NetworkUpgrade> = mainnet_activations.values().collect(); assert_eq!(MAINNET_ACTIVATION_HEIGHTS.len(), mainnet_nus.len()); - let testnet_activations = NetworkUpgrade::activation_list(Testnet); + let testnet_activations = Testnet.activation_list(); let testnet_heights: HashSet<&block::Height> = testnet_activations.keys().collect(); assert_eq!(TESTNET_ACTIVATION_HEIGHTS.len(), testnet_heights.len()); @@ -46,7 +46,7 @@ fn activation_extremes_testnet() { fn activation_extremes(network: Network) { // The first three upgrades are Genesis, BeforeOverwinter, and Overwinter assert_eq!( - NetworkUpgrade::activation_list(network).get(&block::Height(0)), + network.activation_list().get(&block::Height(0)), Some(&Genesis) ); assert_eq!(Genesis.activation_height(network), Some(block::Height(0))); @@ -62,7 +62,7 @@ fn activation_extremes(network: Network) { ); assert_eq!( - NetworkUpgrade::activation_list(network).get(&block::Height(1)), + network.activation_list().get(&block::Height(1)), Some(&BeforeOverwinter) ); assert_eq!( @@ -91,7 +91,7 @@ fn activation_extremes(network: Network) { // We assume that the last upgrade we know about continues forever // (even if we suspect that won't be true) assert_ne!( - NetworkUpgrade::activation_list(network).get(&block::Height::MAX), + network.activation_list().get(&block::Height::MAX), Some(&Genesis) ); assert!(!NetworkUpgrade::is_activation_height( @@ -121,7 +121,7 @@ fn activation_consistent_testnet() { /// Check that the `activation_height`, `is_activation_height`, /// `current`, and `next` functions are consistent for `network`. fn activation_consistent(network: Network) { - let activation_list = NetworkUpgrade::activation_list(network); + let activation_list = network.activation_list(); let network_upgrades: HashSet<&NetworkUpgrade> = activation_list.values().collect(); for &network_upgrade in network_upgrades { diff --git a/zebra-rpc/src/methods.rs b/zebra-rpc/src/methods.rs index 9fc190a9a64..6c2668a34f4 100644 --- a/zebra-rpc/src/methods.rs +++ b/zebra-rpc/src/methods.rs @@ -519,7 +519,7 @@ where // // Get the network upgrades in height order, like `zcashd`. let mut upgrades = IndexMap::new(); - for (activation_height, network_upgrade) in NetworkUpgrade::activation_list(network) { + for (activation_height, network_upgrade) in network.activation_list() { // Zebra defines network upgrades based on incompatible consensus rule changes, // but zcashd defines them based on ZIPs. // From afc09f390ea1093079bfc8da0ff6eb760317fdd6 Mon Sep 17 00:00:00 2001 From: Hazel OHearn Date: Mon, 4 Mar 2024 16:59:18 -0400 Subject: [PATCH 11/22] add back comment --- zebra-network/src/protocol/external/types.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zebra-network/src/protocol/external/types.rs b/zebra-network/src/protocol/external/types.rs index 87a5449064d..049ba1fd731 100644 --- a/zebra-network/src/protocol/external/types.rs +++ b/zebra-network/src/protocol/external/types.rs @@ -23,10 +23,11 @@ impl fmt::Debug for Magic { f.debug_tuple("Magic").field(&hex::encode(self.0)).finish() } } -pub trait ParameterMagic { +pub(crate) trait ParameterMagic { fn magic_value(&self) -> Magic; } impl ParameterMagic for Network { + /// Get the magic value associated to this `Network`. fn magic_value(&self) -> Magic { match self { Network::Mainnet => magics::MAINNET, From 72f26c6d50cf06053d87eb27d9b0d98dae23db2a Mon Sep 17 00:00:00 2001 From: Hazel OHearn Date: Tue, 5 Mar 2024 12:40:12 -0400 Subject: [PATCH 12/22] use zcash_address for parameter types in zebra-chain --- zebra-chain/Cargo.toml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/zebra-chain/Cargo.toml b/zebra-chain/Cargo.toml index 3e714ccd63b..83c44b232d0 100644 --- a/zebra-chain/Cargo.toml +++ b/zebra-chain/Cargo.toml @@ -31,7 +31,6 @@ async-error = [ # Mining RPC support getblocktemplate-rpcs = [ - "zcash_address", ] # Experimental shielded scanning support @@ -132,8 +131,7 @@ serde_json = { version = "1.0.113", optional = true } # Production feature async-error and testing feature proptest-impl tokio = { version = "1.36.0", optional = true } -# Production feature getblocktemplate-rpcs -zcash_address = { version = "0.3.1", optional = true } +zcash_address = { version = "0.3.1" } # Experimental feature shielded-scan zcash_client_backend = { version = "0.10.0-rc.1", optional = true } From cc4dda42e5b0c9494bea2d24f823906f41db1af7 Mon Sep 17 00:00:00 2001 From: Hazel OHearn Date: Tue, 5 Mar 2024 13:30:57 -0400 Subject: [PATCH 13/22] use inherent methods instead of big parameters passthrough --- zebra-chain/src/parameters/network.rs | 44 ++++++------------- .../src/primitives/zcash_note_encryption.rs | 2 +- zebra-chain/src/transparent/address.rs | 1 - 3 files changed, 14 insertions(+), 33 deletions(-) diff --git a/zebra-chain/src/parameters/network.rs b/zebra-chain/src/parameters/network.rs index a79cb1acf57..e24ec98324e 100644 --- a/zebra-chain/src/parameters/network.rs +++ b/zebra-chain/src/parameters/network.rs @@ -62,44 +62,26 @@ pub enum Network { /// The oldest public test network. Testnet, } -use zcash_primitives::consensus::Network as ZcashPrimitivesNetwork; -impl zcash_primitives::consensus::Parameters for Network { - fn activation_height( - &self, - nu: zcash_primitives::consensus::NetworkUpgrade, - ) -> Option { - // Convert `self` (zebra-chain's Network) to librustzcash's Network - <&ZcashPrimitivesNetwork>::from(*self).activation_height(nu) - } - - fn coin_type(&self) -> u32 { - <&ZcashPrimitivesNetwork>::from(*self).coin_type() - } - - fn address_network(&self) -> Option { - <&ZcashPrimitivesNetwork>::from(*self).address_network() - } - - fn hrp_sapling_extended_spending_key(&self) -> &str { - <&ZcashPrimitivesNetwork>::from(*self).hrp_sapling_extended_spending_key() - } - fn hrp_sapling_extended_full_viewing_key(&self) -> &str { - <&ZcashPrimitivesNetwork>::from(*self).hrp_sapling_extended_full_viewing_key() - } - - fn hrp_sapling_payment_address(&self) -> &str { - <&ZcashPrimitivesNetwork>::from(*self).hrp_sapling_payment_address() - } - - fn b58_pubkey_address_prefix(&self) -> [u8; 2] { +use zcash_primitives::consensus::{Network as ZcashPrimitivesNetwork, Parameters as _}; +impl Network { + /// Returns the human-readable prefix for Base58Check-encoded transparent + /// pay-to-public-key-hash payment addresses for the network. + pub fn b58_pubkey_address_prefix(&self) -> [u8; 2] { <&ZcashPrimitivesNetwork>::from(*self).b58_pubkey_address_prefix() } - fn b58_script_address_prefix(&self) -> [u8; 2] { + /// Returns the human-readable prefix for Base58Check-encoded transparent pay-to-script-hash + /// payment addresses for the network. + pub fn b58_script_address_prefix(&self) -> [u8; 2] { <&ZcashPrimitivesNetwork>::from(*self).b58_script_address_prefix() } } + +// impl NetworkSubsetExt for Network { +// type NetworkOffload = ZcashPrimitivesNetwork; +// } + impl From for &'static str { fn from(network: Network) -> &'static str { match network { diff --git a/zebra-chain/src/primitives/zcash_note_encryption.rs b/zebra-chain/src/primitives/zcash_note_encryption.rs index 81cc4a557d8..cb4834247a1 100644 --- a/zebra-chain/src/primitives/zcash_note_encryption.rs +++ b/zebra-chain/src/primitives/zcash_note_encryption.rs @@ -26,7 +26,7 @@ pub fn decrypts_successfully(transaction: &Transaction, network: Network, height if let Some(bundle) = alt_tx.sapling_bundle() { for output in bundle.shielded_outputs().iter() { let recovery = zcash_primitives::sapling::note_encryption::try_sapling_output_recovery( - &network, + <&zcash_primitives::consensus::Network>::from(network), alt_height, &null_sapling_ovk, output, diff --git a/zebra-chain/src/transparent/address.rs b/zebra-chain/src/transparent/address.rs index b3a134c0996..5fb203baf35 100644 --- a/zebra-chain/src/transparent/address.rs +++ b/zebra-chain/src/transparent/address.rs @@ -5,7 +5,6 @@ use std::{fmt, io}; use ripemd::{Digest, Ripemd160}; use secp256k1::PublicKey; use sha2::Sha256; -use zcash_primitives::consensus::Parameters as _; use crate::{ parameters::Network, From 1da36d71894873833dea237a7e491c6e275aae23 Mon Sep 17 00:00:00 2001 From: zancas Date: Tue, 5 Mar 2024 13:09:02 -0700 Subject: [PATCH 14/22] revert to implementation of From on zcash_primitives::..::Network vs &zcash_prim... --- zebra-chain/src/parameters/network.rs | 4 ++-- zebra-chain/src/primitives/zcash_note_encryption.rs | 2 +- zebra-chain/src/primitives/zcash_primitives.rs | 6 +++--- zebra-scan/src/service/scan_task/scan.rs | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/zebra-chain/src/parameters/network.rs b/zebra-chain/src/parameters/network.rs index e24ec98324e..254d2410787 100644 --- a/zebra-chain/src/parameters/network.rs +++ b/zebra-chain/src/parameters/network.rs @@ -68,13 +68,13 @@ impl Network { /// Returns the human-readable prefix for Base58Check-encoded transparent /// pay-to-public-key-hash payment addresses for the network. pub fn b58_pubkey_address_prefix(&self) -> [u8; 2] { - <&ZcashPrimitivesNetwork>::from(*self).b58_pubkey_address_prefix() + ::from(*self).b58_pubkey_address_prefix() } /// Returns the human-readable prefix for Base58Check-encoded transparent pay-to-script-hash /// payment addresses for the network. pub fn b58_script_address_prefix(&self) -> [u8; 2] { - <&ZcashPrimitivesNetwork>::from(*self).b58_script_address_prefix() + ::from(*self).b58_script_address_prefix() } } diff --git a/zebra-chain/src/primitives/zcash_note_encryption.rs b/zebra-chain/src/primitives/zcash_note_encryption.rs index cb4834247a1..0760c9f3750 100644 --- a/zebra-chain/src/primitives/zcash_note_encryption.rs +++ b/zebra-chain/src/primitives/zcash_note_encryption.rs @@ -26,7 +26,7 @@ pub fn decrypts_successfully(transaction: &Transaction, network: Network, height if let Some(bundle) = alt_tx.sapling_bundle() { for output in bundle.shielded_outputs().iter() { let recovery = zcash_primitives::sapling::note_encryption::try_sapling_output_recovery( - <&zcash_primitives::consensus::Network>::from(network), + &::from(network), alt_height, &null_sapling_ovk, output, diff --git a/zebra-chain/src/primitives/zcash_primitives.rs b/zebra-chain/src/primitives/zcash_primitives.rs index 113997eab96..a9fbd9f4b95 100644 --- a/zebra-chain/src/primitives/zcash_primitives.rs +++ b/zebra-chain/src/primitives/zcash_primitives.rs @@ -337,11 +337,11 @@ pub(crate) fn transparent_output_address( } } -impl From for &zcash_primitives::consensus::Network { +impl From for zcash_primitives::consensus::Network { fn from(network: Network) -> Self { match network { - Network::Mainnet => &zcash_primitives::consensus::Network::MainNetwork, - Network::Testnet => &zcash_primitives::consensus::Network::TestNetwork, + Network::Mainnet => zcash_primitives::consensus::Network::MainNetwork, + Network::Testnet => zcash_primitives::consensus::Network::TestNetwork, } } } diff --git a/zebra-scan/src/service/scan_task/scan.rs b/zebra-scan/src/service/scan_task/scan.rs index 405182c67ed..b492c94f97c 100644 --- a/zebra-scan/src/service/scan_task/scan.rs +++ b/zebra-scan/src/service/scan_task/scan.rs @@ -383,7 +383,7 @@ pub fn scan_block( // TODO: Implement a check that returns early when the block height is below the Sapling // activation height. - let network: &zcash_primitives::consensus::Network = Into::into(network); + let network: zcash_primitives::consensus::Network = Into::into(network); let chain_metadata = ChainMetadata { sapling_commitment_tree_size: sapling_tree_size, @@ -399,7 +399,7 @@ pub fn scan_block( .collect(); zcash_client_backend::scanning::scan_block( - network, + &network, block_to_compact(block, chain_metadata), scanning_keys.as_slice(), // Ignore whether notes are change from a viewer's own spends for now. From 9132e3816144034f4b06823c984310ea531e999a Mon Sep 17 00:00:00 2001 From: Hazel OHearn Date: Wed, 6 Mar 2024 12:38:48 -0400 Subject: [PATCH 15/22] move match --- zebra-chain/src/parameters/network.rs | 16 +++++++++++++++- zebra-chain/src/parameters/network_upgrade.rs | 14 -------------- zebra-state/src/service/check.rs | 4 +--- 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/zebra-chain/src/parameters/network.rs b/zebra-chain/src/parameters/network.rs index 254d2410787..42219f2f095 100644 --- a/zebra-chain/src/parameters/network.rs +++ b/zebra-chain/src/parameters/network.rs @@ -5,7 +5,7 @@ use std::{fmt, str::FromStr}; use thiserror::Error; use crate::{ - block::{Height, HeightDiff}, + block::{self, Height, HeightDiff}, parameters::NetworkUpgrade::Canopy, }; @@ -76,6 +76,20 @@ impl Network { pub fn b58_script_address_prefix(&self) -> [u8; 2] { ::from(*self).b58_script_address_prefix() } + /// Returns true if the maximum block time rule is active for `network` and `height`. + /// + /// Always returns true if `network` is the Mainnet. + /// If `network` is the Testnet, the `height` should be at least + /// TESTNET_MAX_TIME_START_HEIGHT to return true. + /// Returns false otherwise. + /// + /// Part of the consensus rules at + pub fn is_max_block_time_enforced(self, height: block::Height) -> bool { + match self { + Network::Mainnet => true, + Network::Testnet => height >= super::TESTNET_MAX_TIME_START_HEIGHT, + } + } } // impl NetworkSubsetExt for Network { diff --git a/zebra-chain/src/parameters/network_upgrade.rs b/zebra-chain/src/parameters/network_upgrade.rs index 6aa534e3cd7..c262530814b 100644 --- a/zebra-chain/src/parameters/network_upgrade.rs +++ b/zebra-chain/src/parameters/network_upgrade.rs @@ -449,20 +449,6 @@ impl NetworkUpgrade { NetworkUpgrade::current(network, height).averaging_window_timespan() } - /// Returns true if the maximum block time rule is active for `network` and `height`. - /// - /// Always returns true if `network` is the Mainnet. - /// If `network` is the Testnet, the `height` should be at least - /// TESTNET_MAX_TIME_START_HEIGHT to return true. - /// Returns false otherwise. - /// - /// Part of the consensus rules at - pub fn is_max_block_time_enforced(network: Network, height: block::Height) -> bool { - match network { - Network::Mainnet => true, - Network::Testnet => height >= TESTNET_MAX_TIME_START_HEIGHT, - } - } /// Returns the NetworkUpgrade given an u32 as ConsensusBranchId pub fn from_branch_id(branch_id: u32) -> Option { CONSENSUS_BRANCH_IDS diff --git a/zebra-state/src/service/check.rs b/zebra-state/src/service/check.rs index c89f63956e0..0d3a941f2d0 100644 --- a/zebra-state/src/service/check.rs +++ b/zebra-state/src/service/check.rs @@ -277,9 +277,7 @@ fn difficulty_threshold_and_time_are_valid( // 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 - { + if network.is_max_block_time_enforced(candidate_height) && candidate_time > block_time_max { Err(ValidateContextError::TimeTooLate { candidate_time, block_time_max, From 946ff1475769947ddf435386c3b5613849c93def Mon Sep 17 00:00:00 2001 From: Hazel OHearn Date: Wed, 6 Mar 2024 16:36:01 -0400 Subject: [PATCH 16/22] add test to block maximum time rule --- .../src/parameters/network/tests/prop.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/zebra-chain/src/parameters/network/tests/prop.rs b/zebra-chain/src/parameters/network/tests/prop.rs index 9e23e9e9f1e..605f979012e 100644 --- a/zebra-chain/src/parameters/network/tests/prop.rs +++ b/zebra-chain/src/parameters/network/tests/prop.rs @@ -1,7 +1,10 @@ use proptest::prelude::*; use super::super::{Network, ZIP_212_GRACE_PERIOD_DURATION}; -use crate::parameters::NetworkUpgrade; +use crate::{ + block::Height, + parameters::{NetworkUpgrade, TESTNET_MAX_TIME_START_HEIGHT}, +}; proptest! { /// Check that the mandatory checkpoint is after the ZIP-212 grace period. @@ -23,4 +26,16 @@ proptest! { assert!(network.mandatory_checkpoint_height() >= grace_period_end_height); } + + #[test] + /// Asserts that the activation height is correct for the block + /// maximum time rule on Testnet is correct. + fn max_block_times_correct_enforcement(height in any::()) { + let _init_guard = zebra_test::init(); + + assert!(Network::Mainnet.is_max_block_time_enforced(height)); + assert_eq!(Network::Testnet.is_max_block_time_enforced(height), TESTNET_MAX_TIME_START_HEIGHT <= height); + + + } } From 602fa5c880de3709e0d646cb63dd64ef9b390fe1 Mon Sep 17 00:00:00 2001 From: Hazel OHearn Date: Thu, 7 Mar 2024 14:35:28 -0400 Subject: [PATCH 17/22] update changelog --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d9a7b8c3c9..8b2a8f5033e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,18 @@ All notable changes to Zebra are documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org). +## Unreleased + +### Added +- `zebra_chain::Network` methods: + - `b58_pubkey_address_prefix`, `b58_script_address_prefix`, `num_funding_streams` + +### Changed +- Functions that take a `zebra_chain::Network` as an argument have been moved to be methods of `Network`, including + - `zebra_chain::parameters`: + - `genesis::genesis_hash`, `NetworkUpgrade::activation_list`, `NetworkUpgrade::is_max_block_time_enforced`, + - `zebra_consensus::height_for_first_halving` + ## [Zebra 1.6.0](https://github.com/ZcashFoundation/zebra/releases/tag/v1.6.0) - 2024-02-23 This release exposes the shielded scanning functionality through an initial From 94127dc927425d56fe2799d1076c5b83a585e101 Mon Sep 17 00:00:00 2001 From: Hazel OHearn Date: Tue, 12 Mar 2024 16:24:08 -0300 Subject: [PATCH 18/22] finish porting target_difficutly_limit --- zebra-chain/src/work/difficulty.rs | 26 +++++++------------ .../src/work/difficulty/tests/vectors.rs | 10 +++---- zebra-state/src/service/check/difficulty.rs | 9 +++---- 3 files changed, 18 insertions(+), 27 deletions(-) diff --git a/zebra-chain/src/work/difficulty.rs b/zebra-chain/src/work/difficulty.rs index 0b5c23c3f9a..9c5252c2b8d 100644 --- a/zebra-chain/src/work/difficulty.rs +++ b/zebra-chain/src/work/difficulty.rs @@ -384,16 +384,6 @@ impl ExpandedDifficulty { U256::from_little_endian(&hash.0).into() } - /// Returns the easiest target difficulty allowed on `network`. - /// - /// # Consensus - /// - /// See `PoWLimit` in the Zcash specification: - /// - pub fn target_difficulty_limit(network: Network) -> ExpandedDifficulty { - network.target_difficulty_limit() - } - /// Calculate the CompactDifficulty for an expanded difficulty. /// /// # Consensus @@ -665,7 +655,8 @@ impl PartialCumulativeWork { pub fn difficulty_multiplier_for_display(&self, network: Network) -> f64 { // This calculation is similar to the `getdifficulty` RPC, see that code for details. - let pow_limit = ExpandedDifficulty::target_difficulty_limit(network) + let pow_limit = network + .target_difficulty_limit() .to_compact() .to_work() .expect("target difficult limit is valid work"); @@ -689,17 +680,20 @@ impl PartialCumulativeWork { } } -trait ParameterDifficulty { - fn target_difficulty_limit(&self) -> ExpandedDifficulty; -} - -impl ParameterDifficulty for Network { +/// Network methods related to Difficulty +pub trait ParameterDifficulty { /// Returns the easiest target difficulty allowed on `network`. /// /// # Consensus /// /// See `PoWLimit` in the Zcash specification: /// + fn target_difficulty_limit(&self) -> ExpandedDifficulty; +} + +impl ParameterDifficulty for Network { + /// Returns the easiest target difficulty allowed on `network`. + /// See [`ParameterDifficulty::target_difficulty_limit`] fn target_difficulty_limit(&self) -> ExpandedDifficulty { let limit: U256 = match self { /* 2^243 - 1 */ diff --git a/zebra-chain/src/work/difficulty/tests/vectors.rs b/zebra-chain/src/work/difficulty/tests/vectors.rs index e8b19022199..e18b1541737 100644 --- a/zebra-chain/src/work/difficulty/tests/vectors.rs +++ b/zebra-chain/src/work/difficulty/tests/vectors.rs @@ -309,9 +309,9 @@ fn block_difficulty_for_network(network: Network) -> Result<(), Report> { /// SPANDOC: Check the PoWLimit for block {?height, ?network, ?threshold, ?hash} { // the consensus rule - assert!(threshold <= ExpandedDifficulty::target_difficulty_limit(network)); + assert!(threshold <= network.target_difficulty_limit()); // check that ordering is transitive, we checked `hash <= threshold` above - assert!(hash <= ExpandedDifficulty::target_difficulty_limit(network)); + assert!(hash <= network.target_difficulty_limit()); } /// SPANDOC: Check compact round-trip for block {?height, ?network} @@ -376,7 +376,7 @@ fn genesis_block_difficulty_for_network(network: Network) -> Result<(), Report> { assert_eq!( threshold, - ExpandedDifficulty::target_difficulty_limit(network), + network.target_difficulty_limit(), "genesis block difficulty thresholds must be equal to the PoWLimit" ); } @@ -477,12 +477,12 @@ fn check_testnet_minimum_difficulty_block(height: block::Height) -> Result<(), R /// SPANDOC: Check that the testnet minimum difficulty is the PoWLimit {?height, ?threshold, ?hash} { - assert_eq!(threshold, ExpandedDifficulty::target_difficulty_limit(Network::Testnet), + assert_eq!(threshold, Network::Testnet.target_difficulty_limit(), "testnet minimum difficulty thresholds should be equal to the PoWLimit. Hint: Blocks with large gaps are allowed to have the minimum difficulty, but it's not required."); // all blocks pass the minimum difficulty threshold, even if they aren't minimum // difficulty blocks, because it's the lowest permitted difficulty assert!( - hash <= ExpandedDifficulty::target_difficulty_limit(Network::Testnet), + hash <= Network::Testnet.target_difficulty_limit(), "testnet minimum difficulty hashes must be less than the PoWLimit" ); } diff --git a/zebra-state/src/service/check/difficulty.rs b/zebra-state/src/service/check/difficulty.rs index c81ad2d764e..a5ec6179bcf 100644 --- a/zebra-state/src/service/check/difficulty.rs +++ b/zebra-state/src/service/check/difficulty.rs @@ -15,8 +15,8 @@ use zebra_chain::{ parameters::Network, parameters::NetworkUpgrade, parameters::POW_AVERAGING_WINDOW, - work::difficulty::ExpandedDifficulty, work::difficulty::{CompactDifficulty, U256}, + work::difficulty::{ExpandedDifficulty, ParameterDifficulty as _}, }; /// The median block span for time median calculations. @@ -188,7 +188,7 @@ impl AdjustedDifficulty { Network::Testnet, "invalid network: the minimum difficulty rule only applies on testnet" ); - ExpandedDifficulty::target_difficulty_limit(self.network).to_compact() + self.network.target_difficulty_limit().to_compact() } else { self.threshold_bits() } @@ -210,10 +210,7 @@ impl AdjustedDifficulty { let threshold = (self.mean_target_difficulty() / averaging_window_timespan.num_seconds()) * self.median_timespan_bounded().num_seconds(); - let threshold = min( - ExpandedDifficulty::target_difficulty_limit(self.network), - threshold, - ); + let threshold = min(self.network.target_difficulty_limit(), threshold); threshold.to_compact() } From fa68a73a7aea178bcf7a08790b920617b5640b5f Mon Sep 17 00:00:00 2001 From: Hazel OHearn Date: Tue, 12 Mar 2024 16:25:00 -0300 Subject: [PATCH 19/22] remove obscelete code comment --- zebra-chain/src/parameters/network.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/zebra-chain/src/parameters/network.rs b/zebra-chain/src/parameters/network.rs index 42219f2f095..634a44a19b9 100644 --- a/zebra-chain/src/parameters/network.rs +++ b/zebra-chain/src/parameters/network.rs @@ -92,10 +92,6 @@ impl Network { } } -// impl NetworkSubsetExt for Network { -// type NetworkOffload = ZcashPrimitivesNetwork; -// } - impl From for &'static str { fn from(network: Network) -> &'static str { match network { From ab9f326671ce6d18a32afc64360fb0a22e969c6a Mon Sep 17 00:00:00 2001 From: Hazel OHearn Date: Tue, 12 Mar 2024 16:29:30 -0300 Subject: [PATCH 20/22] revert non-functional change --- zebra-scan/src/service/scan_task/scan.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra-scan/src/service/scan_task/scan.rs b/zebra-scan/src/service/scan_task/scan.rs index b492c94f97c..898183fe135 100644 --- a/zebra-scan/src/service/scan_task/scan.rs +++ b/zebra-scan/src/service/scan_task/scan.rs @@ -383,7 +383,7 @@ pub fn scan_block( // TODO: Implement a check that returns early when the block height is below the Sapling // activation height. - let network: zcash_primitives::consensus::Network = Into::into(network); + let network: zcash_primitives::consensus::Network = network.into(); let chain_metadata = ChainMetadata { sapling_commitment_tree_size: sapling_tree_size, From d2ec3b5045a02a25ed27bb1a63e29debed3f386b Mon Sep 17 00:00:00 2001 From: Hazel OHearn Date: Tue, 12 Mar 2024 16:39:40 -0300 Subject: [PATCH 21/22] finish migrating target_difficulty_limit, checkpoint_list --- zebra-consensus/src/block/check.rs | 9 ++++++--- zebra-consensus/src/block/tests.rs | 4 ++-- zebra-consensus/src/checkpoint.rs | 4 ++-- zebra-consensus/src/checkpoint/list.rs | 5 ----- zebra-consensus/src/checkpoint/list/tests.rs | 8 ++++---- zebra-consensus/src/router.rs | 6 +++--- zebra-rpc/src/methods/get_block_template_rpcs.rs | 4 ++-- .../methods/tests/snapshot/get_block_template_rpcs.rs | 4 ++-- zebra-rpc/src/methods/tests/vectors.rs | 4 ++-- zebrad/src/components/sync/progress.rs | 5 +++-- zebrad/tests/end_of_support.rs | 4 ++-- 11 files changed, 28 insertions(+), 29 deletions(-) diff --git a/zebra-consensus/src/block/check.rs b/zebra-consensus/src/block/check.rs index e539743a3d8..319fa5004c5 100644 --- a/zebra-consensus/src/block/check.rs +++ b/zebra-consensus/src/block/check.rs @@ -9,7 +9,10 @@ use zebra_chain::{ block::{Block, Hash, Header, Height}, parameters::{Network, NetworkUpgrade}, transaction, - work::{difficulty::ExpandedDifficulty, equihash}, + work::{ + difficulty::{ExpandedDifficulty, ParameterDifficulty as _}, + equihash, + }, }; use crate::{error::*, parameters::SLOW_START_INTERVAL}; @@ -78,13 +81,13 @@ pub fn difficulty_threshold_is_valid( // The PowLimit check is part of `Threshold()` in the spec, but it doesn't // actually depend on any previous blocks. - if difficulty_threshold > ExpandedDifficulty::target_difficulty_limit(network) { + if difficulty_threshold > network.target_difficulty_limit() { Err(BlockError::TargetDifficultyLimit( *height, *hash, difficulty_threshold, network, - ExpandedDifficulty::target_difficulty_limit(network), + network.target_difficulty_limit(), ))?; } diff --git a/zebra-consensus/src/block/tests.rs b/zebra-consensus/src/block/tests.rs index f074cf73649..d727378933f 100644 --- a/zebra-consensus/src/block/tests.rs +++ b/zebra-consensus/src/block/tests.rs @@ -19,7 +19,7 @@ use zebra_chain::{ parameters::{Network, NetworkUpgrade}, serialization::{ZcashDeserialize, ZcashDeserializeInto}, transaction::{arbitrary::transaction_to_fake_v5, LockTime, Transaction}, - work::difficulty::{ExpandedDifficulty, INVALID_COMPACT_DIFFICULTY}, + work::difficulty::{ParameterDifficulty as _, INVALID_COMPACT_DIFFICULTY}, }; use zebra_script::CachedFfiTransaction; use zebra_test::transcript::{ExpectedTranscriptError, Transcript}; @@ -241,7 +241,7 @@ fn difficulty_validation_failure() -> Result<(), Report> { hash, difficulty_threshold, Network::Mainnet, - ExpandedDifficulty::target_difficulty_limit(Network::Mainnet), + Network::Mainnet.target_difficulty_limit(), ); assert_eq!(expected, result); diff --git a/zebra-consensus/src/checkpoint.rs b/zebra-consensus/src/checkpoint.rs index 6541c502f9a..e8605c1e3f6 100644 --- a/zebra-consensus/src/checkpoint.rs +++ b/zebra-consensus/src/checkpoint.rs @@ -42,7 +42,7 @@ use crate::{ TargetHeight::{self, *}, }, error::BlockError, - BoxError, + BoxError, ParameterCheckpoint as _, }; pub(crate) mod list; @@ -207,7 +207,7 @@ where initial_tip: Option<(block::Height, block::Hash)>, state_service: S, ) -> Self { - let checkpoint_list = CheckpointList::new(network); + let checkpoint_list = network.checkpoint_list(); let max_height = checkpoint_list.max_height(); tracing::info!( ?max_height, diff --git a/zebra-consensus/src/checkpoint/list.rs b/zebra-consensus/src/checkpoint/list.rs index 6e37af76e7b..2b45e436568 100644 --- a/zebra-consensus/src/checkpoint/list.rs +++ b/zebra-consensus/src/checkpoint/list.rs @@ -122,11 +122,6 @@ impl FromStr for CheckpointList { } impl CheckpointList { - /// Returns the hard-coded checkpoint list for `network`. - pub fn new(network: Network) -> Self { - network.checkpoint_list() - } - /// Create a new checkpoint list for `network` from `checkpoint_list`. /// /// Assumes that the provided genesis checkpoint is correct. diff --git a/zebra-consensus/src/checkpoint/list/tests.rs b/zebra-consensus/src/checkpoint/list/tests.rs index da07c689464..0588a365c12 100644 --- a/zebra-consensus/src/checkpoint/list/tests.rs +++ b/zebra-consensus/src/checkpoint/list/tests.rs @@ -235,8 +235,8 @@ fn checkpoint_list_load_hard_coded() -> Result<(), BoxError> { .parse() .expect("hard-coded Testnet checkpoint list should parse"); - let _ = CheckpointList::new(Mainnet); - let _ = CheckpointList::new(Testnet); + let _ = Mainnet.checkpoint_list(); + let _ = Testnet.checkpoint_list(); Ok(()) } @@ -257,7 +257,7 @@ fn checkpoint_list_hard_coded_mandatory(network: Network) -> Result<(), BoxError let mandatory_checkpoint = network.mandatory_checkpoint_height(); - let list = CheckpointList::new(network); + let list = network.checkpoint_list(); assert!( list.max_height() >= mandatory_checkpoint, @@ -292,7 +292,7 @@ fn checkpoint_list_hard_coded_max_gap(network: Network) -> Result<(), BoxError> HeightDiff::try_from(div_ceil(MAX_CHECKPOINT_BYTE_COUNT, MAX_BLOCK_BYTES)) .expect("constant fits in HeightDiff"); - let list = CheckpointList::new(network); + let list = network.checkpoint_list(); let mut heights = list.0.keys(); // Check that we start at the genesis height diff --git a/zebra-consensus/src/router.rs b/zebra-consensus/src/router.rs index 5c10e545b52..ab99bbd4154 100644 --- a/zebra-consensus/src/router.rs +++ b/zebra-consensus/src/router.rs @@ -36,7 +36,7 @@ use crate::{ block::{Request, SemanticBlockVerifier, VerifyBlockError}, checkpoint::{CheckpointList, CheckpointVerifier, VerifyCheckpointError}, error::TransactionError, - transaction, BoxError, Config, + transaction, BoxError, Config, ParameterCheckpoint as _, }; #[cfg(test)] @@ -263,7 +263,7 @@ where // > activation block hashes given in § 3.12 ‘Mainnet and Testnet’ on p. 20. // // - let full_checkpoints = CheckpointList::new(network); + let full_checkpoints = network.checkpoint_list(); let mut already_warned = false; for (height, checkpoint_hash) in full_checkpoints.iter() { @@ -363,7 +363,7 @@ where pub fn init_checkpoint_list(config: Config, network: Network) -> (CheckpointList, Height) { // TODO: Zebra parses the checkpoint list three times at startup. // Instead, cache the checkpoint list for each `network`. - let list = CheckpointList::new(network); + let list = network.checkpoint_list(); let max_checkpoint_height = if config.checkpoint_sync { list.max_height() diff --git a/zebra-rpc/src/methods/get_block_template_rpcs.rs b/zebra-rpc/src/methods/get_block_template_rpcs.rs index 54ad7daed16..57f27e228f0 100644 --- a/zebra-rpc/src/methods/get_block_template_rpcs.rs +++ b/zebra-rpc/src/methods/get_block_template_rpcs.rs @@ -20,7 +20,7 @@ use zebra_chain::{ transparent::{ self, EXTRA_ZEBRA_COINBASE_DATA, MAX_COINBASE_DATA_LEN, MAX_COINBASE_HEIGHT_DATA_LEN, }, - work::difficulty::{ExpandedDifficulty, U256}, + work::difficulty::{ParameterDifficulty as _, U256}, }; use zebra_consensus::{ funding_stream_address, funding_stream_values, miner_subsidy, ParameterSubsidy as _, @@ -1197,7 +1197,7 @@ where // using this calculation.) // Get expanded difficulties (256 bits), these are the inverse of the work - let pow_limit: U256 = ExpandedDifficulty::target_difficulty_limit(network).into(); + let pow_limit: U256 = network.target_difficulty_limit().into(); let difficulty: U256 = chain_info .expected_difficulty .to_expanded() diff --git a/zebra-rpc/src/methods/tests/snapshot/get_block_template_rpcs.rs b/zebra-rpc/src/methods/tests/snapshot/get_block_template_rpcs.rs index c7299565abf..e93571baed9 100644 --- a/zebra-rpc/src/methods/tests/snapshot/get_block_template_rpcs.rs +++ b/zebra-rpc/src/methods/tests/snapshot/get_block_template_rpcs.rs @@ -23,7 +23,7 @@ use zebra_chain::{ serialization::{DateTime32, ZcashDeserializeInto}, transaction::Transaction, transparent, - work::difficulty::{CompactDifficulty, ExpandedDifficulty}, + work::difficulty::{CompactDifficulty, ParameterDifficulty as _}, }; use zebra_network::{address_book_peers::MockAddressBookPeers, types::MetaAddr}; use zebra_node_services::mempool; @@ -115,7 +115,7 @@ pub async fn test_responses( let fake_max_time = DateTime32::from(1654008728); // Use a valid fractional difficulty for snapshots - let pow_limit = ExpandedDifficulty::target_difficulty_limit(network); + let pow_limit = network.target_difficulty_limit(); let fake_difficulty = pow_limit * 2 / 3; let fake_difficulty = CompactDifficulty::from(fake_difficulty); diff --git a/zebra-rpc/src/methods/tests/vectors.rs b/zebra-rpc/src/methods/tests/vectors.rs index 0a9dcb9e1bd..03aa5b12c66 100644 --- a/zebra-rpc/src/methods/tests/vectors.rs +++ b/zebra-rpc/src/methods/tests/vectors.rs @@ -1658,7 +1658,7 @@ async fn rpc_getdifficulty() { chain_sync_status::MockSyncStatus, chain_tip::mock::MockChainTip, serialization::DateTime32, - work::difficulty::{CompactDifficulty, ExpandedDifficulty, U256}, + work::difficulty::{CompactDifficulty, ExpandedDifficulty, ParameterDifficulty as _, U256}, }; use zebra_network::address_book_peers::MockAddressBookPeers; @@ -1742,7 +1742,7 @@ async fn rpc_getdifficulty() { assert_eq!(format!("{:.9}", get_difficulty.unwrap()), "0.000122072"); // Fake the ChainInfo response: difficulty limit - smallest valid difficulty - let pow_limit = ExpandedDifficulty::target_difficulty_limit(Mainnet); + let pow_limit = Mainnet.target_difficulty_limit(); let fake_difficulty = pow_limit.into(); let mut read_state2 = read_state.clone(); let mock_read_state_request_handler = async move { diff --git a/zebrad/src/components/sync/progress.rs b/zebrad/src/components/sync/progress.rs index 66acfb082c7..9fbf6517c4a 100644 --- a/zebrad/src/components/sync/progress.rs +++ b/zebrad/src/components/sync/progress.rs @@ -16,7 +16,7 @@ use zebra_chain::{ fmt::humantime_seconds, parameters::{Network, NetworkUpgrade, POST_BLOSSOM_POW_TARGET_SPACING}, }; -use zebra_consensus::CheckpointList; +use zebra_consensus::ParameterCheckpoint as _; use zebra_state::MAX_BLOCK_REORG_HEIGHT; use crate::components::sync::SyncStatus; @@ -82,7 +82,8 @@ pub async fn show_block_chain_progress( // The minimum height of the valid best chain, based on: // - the hard-coded checkpoint height, // - the minimum number of blocks after the highest checkpoint. - let after_checkpoint_height = CheckpointList::new(network) + let after_checkpoint_height = network + .checkpoint_list() .max_height() .add(min_after_checkpoint_blocks) .expect("hard-coded checkpoint height is far below Height::MAX"); diff --git a/zebrad/tests/end_of_support.rs b/zebrad/tests/end_of_support.rs index bbc6095f212..2a2a4afc390 100644 --- a/zebrad/tests/end_of_support.rs +++ b/zebrad/tests/end_of_support.rs @@ -5,7 +5,7 @@ use std::time::Duration; use color_eyre::eyre::Result; use zebra_chain::{block::Height, chain_tip::mock::MockChainTip, parameters::Network}; -use zebra_consensus::CheckpointList; +use zebra_consensus::ParameterCheckpoint as _; use zebrad::components::sync::end_of_support::{self, EOS_PANIC_AFTER, ESTIMATED_RELEASE_HEIGHT}; // Estimated blocks per day with the current 75 seconds block spacing. @@ -54,7 +54,7 @@ fn end_of_support_function() { #[tracing_test::traced_test] fn end_of_support_date() { // Get the list of checkpoints. - let list = CheckpointList::new(Network::Mainnet); + let list = Network::Mainnet.checkpoint_list(); // Get the last one we have and use it as tip. let higher_checkpoint = list.max_height(); From dce81379c8e1b09b9bd458cacd355fc48b7f4cc4 Mon Sep 17 00:00:00 2001 From: Hazel OHearn Date: Tue, 12 Mar 2024 16:43:53 -0300 Subject: [PATCH 22/22] update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b2a8f5033e..bddc43ed7b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,9 @@ and this project adheres to [Semantic Versioning](https://semver.org). - Functions that take a `zebra_chain::Network` as an argument have been moved to be methods of `Network`, including - `zebra_chain::parameters`: - `genesis::genesis_hash`, `NetworkUpgrade::activation_list`, `NetworkUpgrade::is_max_block_time_enforced`, + - `zebra_chain::work::difficulty::ExpandedDifficulty::target_difficutly_limit` - `zebra_consensus::height_for_first_halving` + - `zebra_consensus::checkpoint::CheckpointList::new` (now `Network::checkpoint_list`) ## [Zebra 1.6.0](https://github.com/ZcashFoundation/zebra/releases/tag/v1.6.0) - 2024-02-23