From a16b6f79b5b7fb201c2e666428cee7f756c5a934 Mon Sep 17 00:00:00 2001 From: Arya Date: Fri, 3 May 2024 16:44:25 -0400 Subject: [PATCH 1/6] Allow configurable Nu5 activation height on Regtest --- zebra-chain/src/block/commitment.rs | 2 +- zebra-chain/src/parameters/network.rs | 4 +-- zebra-chain/src/parameters/network/testnet.rs | 27 ++++++++++++------- .../src/parameters/network/tests/vectors.rs | 8 +++--- zebra-consensus/src/checkpoint/list/tests.rs | 2 +- zebra-network/src/config.rs | 8 +++++- zebra-network/src/constants.rs | 2 +- .../types/get_block_template/proposal.rs | 16 ++++++++++- .../bin/block-template-to-proposal/main.rs | 7 +++-- zebrad/src/components/miner.rs | 6 +++-- zebrad/tests/acceptance.rs | 2 +- .../get_block_template.rs | 13 ++++++--- zebrad/tests/common/regtest.rs | 26 ++++++++++++++---- 13 files changed, 90 insertions(+), 33 deletions(-) diff --git a/zebra-chain/src/block/commitment.rs b/zebra-chain/src/block/commitment.rs index 03acf350349..532c47d81a7 100644 --- a/zebra-chain/src/block/commitment.rs +++ b/zebra-chain/src/block/commitment.rs @@ -119,7 +119,7 @@ impl Commitment { // on Regtest for heights above height 0, it returns NU5, and it's possible for the current network upgrade // to be NU5 (or Canopy, or any network upgrade above Heartwood) at the Heartwood activation height. // TODO: Check Canopy too once Zebra can construct Canopy block templates. - Heartwood | Nu5 if Some(height) == Heartwood.activation_height(network) => { + Heartwood | Canopy | Nu5 if Some(height) == Heartwood.activation_height(network) => { if bytes == CHAIN_HISTORY_ACTIVATION_RESERVED { Ok(ChainHistoryActivationReserved) } else { diff --git a/zebra-chain/src/parameters/network.rs b/zebra-chain/src/parameters/network.rs index 0bd9518dd2d..f61bf71ef95 100644 --- a/zebra-chain/src/parameters/network.rs +++ b/zebra-chain/src/parameters/network.rs @@ -167,8 +167,8 @@ impl Network { } /// Creates a new [`Network::Testnet`] with `Regtest` parameters and the provided network upgrade activation heights. - pub fn new_regtest() -> Self { - Self::new_configured_testnet(testnet::Parameters::new_regtest()) + pub fn new_regtest(nu5_activation_height: Option) -> Self { + Self::new_configured_testnet(testnet::Parameters::new_regtest(nu5_activation_height)) } /// Returns true if the network is the default Testnet, or false otherwise. diff --git a/zebra-chain/src/parameters/network/testnet.rs b/zebra-chain/src/parameters/network/testnet.rs index aa1b1e192ff..9b562f0ac70 100644 --- a/zebra-chain/src/parameters/network/testnet.rs +++ b/zebra-chain/src/parameters/network/testnet.rs @@ -11,6 +11,11 @@ use crate::{ }, }; +/// The Regtest NU5 activation height in tests +// TODO: Serialize testnet parameters in Config then remove this and use a configured NU5 activation height. +#[cfg(any(test, feature = "proptest-impl"))] +pub const REGTEST_NU5_ACTIVATION_HEIGHT: u32 = 100; + /// Reserved network names that should not be allowed for configured Testnets. pub const RESERVED_NETWORK_NAMES: [&str; 6] = [ "Mainnet", @@ -175,9 +180,7 @@ impl ParametersBuilder { pub fn with_activation_heights( mut self, ConfiguredActivationHeights { - // TODO: Find out if `BeforeOverwinter` is required at Height(1), allow for - // configuring its activation height if it's not required to be at Height(1) - before_overwinter: _, + before_overwinter, overwinter, sapling, blossom, @@ -192,9 +195,10 @@ impl ParametersBuilder { // // These must be in order so that later network upgrades overwrite prior ones // if multiple network upgrades are configured with the same activation height. - let activation_heights: BTreeMap<_, _> = overwinter + let activation_heights: BTreeMap<_, _> = before_overwinter .into_iter() - .map(|h| (h, Overwinter)) + .map(|h| (h, BeforeOverwinter)) + .chain(overwinter.into_iter().map(|h| (h, Overwinter))) .chain(sapling.into_iter().map(|h| (h, Sapling))) .chain(blossom.into_iter().map(|h| (h, Blossom))) .chain(heartwood.into_iter().map(|h| (h, Heartwood))) @@ -227,8 +231,7 @@ impl ParametersBuilder { // # Correctness // // Height(0) must be reserved for the `NetworkUpgrade::Genesis`. - // TODO: Find out if `BeforeOverwinter` must always be active at Height(1), remove it here if it's not required. - self.activation_heights.split_off(&Height(2)); + self.activation_heights.split_off(&Height(1)); self.activation_heights.extend(activation_heights); self @@ -310,7 +313,10 @@ impl Parameters { /// Accepts a [`ConfiguredActivationHeights`]. /// /// Creates an instance of [`Parameters`] with `Regtest` values. - pub fn new_regtest() -> Self { + pub fn new_regtest(nu5_activation_height: Option) -> Self { + #[cfg(any(test, feature = "proptest-impl"))] + let nu5_activation_height = nu5_activation_height.or(Some(100)); + Self { network_name: "Regtest".to_string(), ..Self::build() @@ -324,7 +330,8 @@ impl Parameters { // Removes default Testnet activation heights if not configured, // most network upgrades are disabled by default for Regtest in zcashd .with_activation_heights(ConfiguredActivationHeights { - nu5: Some(1), + canopy: Some(1), + nu5: nu5_activation_height, ..Default::default() }) .finish() @@ -347,7 +354,7 @@ impl Parameters { hrp_sapling_extended_full_viewing_key, hrp_sapling_payment_address, disable_pow, - } = Self::new_regtest(); + } = Self::new_regtest(None); self.network_name == network_name && self.genesis_hash == genesis_hash diff --git a/zebra-chain/src/parameters/network/tests/vectors.rs b/zebra-chain/src/parameters/network/tests/vectors.rs index 0ac782c11ff..c528a9ad4c1 100644 --- a/zebra-chain/src/parameters/network/tests/vectors.rs +++ b/zebra-chain/src/parameters/network/tests/vectors.rs @@ -135,14 +135,14 @@ fn activates_network_upgrades_correctly() { let expected_default_regtest_activation_heights = &[ (Height(0), NetworkUpgrade::Genesis), - (Height(1), NetworkUpgrade::Nu5), + (Height(1), NetworkUpgrade::Canopy), ]; for (network, expected_activation_heights) in [ (Network::Mainnet, MAINNET_ACTIVATION_HEIGHTS), (Network::new_default_testnet(), TESTNET_ACTIVATION_HEIGHTS), ( - Network::new_regtest(), + Network::new_regtest(None), expected_default_regtest_activation_heights, ), ] { @@ -193,7 +193,7 @@ fn check_configured_network_name() { "Mainnet should be displayed as 'Mainnet'" ); assert_eq!( - Network::new_regtest().to_string(), + Network::new_regtest(None).to_string(), "Regtest", "Regtest should be displayed as 'Regtest'" ); @@ -238,6 +238,7 @@ fn check_configured_sapling_hrps() { .expect_err("should panic when setting Sapling HRPs that are too long or contain non-alphanumeric characters (except '-')"); } + // Restore the regular panic hook for any unexpected panics drop(std::panic::take_hook()); // Check that Sapling HRPs can contain lowercase ascii characters and dashes. @@ -317,6 +318,7 @@ fn check_network_name() { .expect_err("should panic when setting network name that's too long or contains non-alphanumeric characters (except '_')"); } + // Restore the regular panic hook for any unexpected panics drop(std::panic::take_hook()); // Checks that network names are displayed correctly diff --git a/zebra-consensus/src/checkpoint/list/tests.rs b/zebra-consensus/src/checkpoint/list/tests.rs index b266d99ffec..9e23efd06aa 100644 --- a/zebra-consensus/src/checkpoint/list/tests.rs +++ b/zebra-consensus/src/checkpoint/list/tests.rs @@ -237,7 +237,7 @@ fn checkpoint_list_load_hard_coded() -> Result<(), BoxError> { let _ = Mainnet.checkpoint_list(); let _ = Network::new_default_testnet().checkpoint_list(); - let _ = Network::new_regtest().checkpoint_list(); + let _ = Network::new_regtest(None).checkpoint_list(); Ok(()) } diff --git a/zebra-network/src/config.rs b/zebra-network/src/config.rs index 8ee97a12ac7..b324c8e7537 100644 --- a/zebra-network/src/config.rs +++ b/zebra-network/src/config.rs @@ -707,7 +707,13 @@ impl<'de> Deserialize<'de> for Config { let network = match (network_kind, testnet_parameters) { (NetworkKind::Mainnet, _) => Network::Mainnet, (NetworkKind::Testnet, None) => Network::new_default_testnet(), - (NetworkKind::Regtest, _) => Network::new_regtest(), + (NetworkKind::Regtest, testnet_parameters) => { + let nu5_activation_height = testnet_parameters + .and_then(|params| params.activation_heights) + .and_then(|activation_height| activation_height.nu5); + + Network::new_regtest(nu5_activation_height) + } ( NetworkKind::Testnet, Some(DTestnetParameters { diff --git a/zebra-network/src/constants.rs b/zebra-network/src/constants.rs index 3b015a6e210..4e49698b747 100644 --- a/zebra-network/src/constants.rs +++ b/zebra-network/src/constants.rs @@ -399,7 +399,7 @@ lazy_static! { hash_map.insert(NetworkKind::Mainnet, Version::min_specified_for_upgrade(&Mainnet, Nu5)); hash_map.insert(NetworkKind::Testnet, Version::min_specified_for_upgrade(&Network::new_default_testnet(), Nu5)); - hash_map.insert(NetworkKind::Regtest, Version::min_specified_for_upgrade(&Network::new_regtest(), Nu5)); + hash_map.insert(NetworkKind::Regtest, Version::min_specified_for_upgrade(&Network::new_regtest(None), Nu5)); hash_map }; diff --git a/zebra-rpc/src/methods/get_block_template_rpcs/types/get_block_template/proposal.rs b/zebra-rpc/src/methods/get_block_template_rpcs/types/get_block_template/proposal.rs index cf4471d5a8c..386b81da756 100644 --- a/zebra-rpc/src/methods/get_block_template_rpcs/types/get_block_template/proposal.rs +++ b/zebra-rpc/src/methods/get_block_template_rpcs/types/get_block_template/proposal.rs @@ -6,6 +6,7 @@ use std::{num::ParseIntError, str::FromStr, sync::Arc}; use zebra_chain::{ block::{self, Block, Height}, + parameters::NetworkUpgrade, serialization::{DateTime32, SerializationError, ZcashDeserializeInto}, work::equihash::Solution, }; @@ -167,6 +168,7 @@ impl FromStr for TimeSource { pub fn proposal_block_from_template( template: &GetBlockTemplate, time_source: impl Into>, + network_upgrade: NetworkUpgrade, ) -> Result { let GetBlockTemplate { version, @@ -176,6 +178,7 @@ pub fn proposal_block_from_template( DefaultRoots { merkle_root, block_commitments_hash, + chain_history_root, .. }, bits: difficulty_threshold, @@ -201,12 +204,23 @@ pub fn proposal_block_from_template( transactions.push(tx_template.data.as_ref().zcash_deserialize_into()?); } + let commitment_bytes = match network_upgrade { + NetworkUpgrade::Genesis + | NetworkUpgrade::BeforeOverwinter + | NetworkUpgrade::Overwinter + | NetworkUpgrade::Sapling + | NetworkUpgrade::Blossom + | NetworkUpgrade::Heartwood => panic!("pre-Canopy block templates not supported"), + NetworkUpgrade::Canopy => chain_history_root.bytes_in_serialized_order().into(), + NetworkUpgrade::Nu5 => block_commitments_hash.bytes_in_serialized_order().into(), + }; + Ok(Block { header: Arc::new(block::Header { version, previous_block_hash, merkle_root, - commitment_bytes: block_commitments_hash.bytes_in_serialized_order().into(), + commitment_bytes, time: time.into(), difficulty_threshold, nonce: [0; 32].into(), diff --git a/zebra-utils/src/bin/block-template-to-proposal/main.rs b/zebra-utils/src/bin/block-template-to-proposal/main.rs index cb62a399ee1..236f30d20c9 100644 --- a/zebra-utils/src/bin/block-template-to-proposal/main.rs +++ b/zebra-utils/src/bin/block-template-to-proposal/main.rs @@ -10,7 +10,10 @@ use color_eyre::eyre::Result; use serde_json::Value; use structopt::StructOpt; -use zebra_chain::serialization::{DateTime32, ZcashSerialize}; +use zebra_chain::{ + parameters::NetworkUpgrade, + serialization::{DateTime32, ZcashSerialize}, +}; use zebra_rpc::methods::get_block_template_rpcs::{ get_block_template::proposal_block_from_template, types::{get_block_template::GetBlockTemplate, long_poll::LONG_POLL_ID_LENGTH}, @@ -96,7 +99,7 @@ fn main() -> Result<()> { let template: GetBlockTemplate = serde_json::from_value(template)?; // generate proposal according to arguments - let proposal = proposal_block_from_template(&template, time_source)?; + let proposal = proposal_block_from_template(&template, time_source, NetworkUpgrade::Nu5)?; eprintln!("{proposal:#?}"); let proposal = proposal diff --git a/zebrad/src/components/miner.rs b/zebrad/src/components/miner.rs index ace2ffe5e83..47732257b4f 100644 --- a/zebrad/src/components/miner.rs +++ b/zebrad/src/components/miner.rs @@ -20,6 +20,7 @@ use zebra_chain::{ chain_sync_status::ChainSyncStatus, chain_tip::ChainTip, diagnostic::task::WaitForPanics, + parameters::NetworkUpgrade, serialization::{AtLeastOne, ZcashSerialize}, shutdown::is_shutting_down, work::equihash::{Solution, SolverCancelled}, @@ -290,8 +291,9 @@ where // Tell the next get_block_template() call to wait until the template has changed. parameters.long_poll_id = Some(template.long_poll_id); - let block = proposal_block_from_template(&template, TimeSource::CurTime) - .expect("unexpected invalid block template"); + let block = + proposal_block_from_template(&template, TimeSource::CurTime, NetworkUpgrade::Nu5) + .expect("unexpected invalid block template"); // If the template has actually changed, send an updated template. template_sender.send_if_modified(|old_block| { diff --git a/zebrad/tests/acceptance.rs b/zebrad/tests/acceptance.rs index 80d4386ad51..4993e27b9ac 100644 --- a/zebrad/tests/acceptance.rs +++ b/zebrad/tests/acceptance.rs @@ -3108,7 +3108,7 @@ async fn scan_task_commands() -> Result<()> { async fn validate_regtest_genesis_block() { let _init_guard = zebra_test::init(); - let network = Network::new_regtest(); + let network = Network::new_regtest(None); let state = zebra_state::init_test(&network); let ( block_verifier_router, diff --git a/zebrad/tests/common/get_block_template_rpcs/get_block_template.rs b/zebrad/tests/common/get_block_template_rpcs/get_block_template.rs index 58b12446965..b13c7f04236 100644 --- a/zebrad/tests/common/get_block_template_rpcs/get_block_template.rs +++ b/zebrad/tests/common/get_block_template_rpcs/get_block_template.rs @@ -11,7 +11,10 @@ use color_eyre::eyre::{eyre, Context, Result}; use futures::FutureExt; -use zebra_chain::{parameters::Network, serialization::ZcashSerialize}; +use zebra_chain::{ + parameters::{Network, NetworkUpgrade}, + serialization::ZcashSerialize, +}; use zebra_node_services::rpc_client::RpcRequestClient; use zebra_rpc::methods::get_block_template_rpcs::{ get_block_template::{ @@ -214,8 +217,12 @@ async fn try_validate_block_template(client: &RpcRequestClient) -> Result<()> { // Propose a new block with an empty solution and nonce field let raw_proposal_block = hex::encode( - proposal_block_from_template(&response_json_result, time_source)? - .zcash_serialize_to_vec()?, + proposal_block_from_template( + &response_json_result, + time_source, + NetworkUpgrade::Nu5, + )? + .zcash_serialize_to_vec()?, ); let template = response_json_result.clone(); diff --git a/zebrad/tests/common/regtest.rs b/zebrad/tests/common/regtest.rs index 551508de45c..a14d51b2824 100644 --- a/zebrad/tests/common/regtest.rs +++ b/zebrad/tests/common/regtest.rs @@ -8,7 +8,10 @@ use std::{net::SocketAddr, time::Duration}; use color_eyre::eyre::{Context, Result}; use tracing::*; -use zebra_chain::{parameters::Network, serialization::ZcashSerialize}; +use zebra_chain::{ + parameters::{testnet::REGTEST_NU5_ACTIVATION_HEIGHT, Network, NetworkUpgrade}, + serialization::ZcashSerialize, +}; use zebra_node_services::rpc_client::RpcRequestClient; use zebra_rpc::methods::get_block_template_rpcs::get_block_template::{ proposal::TimeSource, proposal_block_from_template, GetBlockTemplate, @@ -27,7 +30,7 @@ pub(crate) async fn submit_blocks_test() -> Result<()> { let _init_guard = zebra_test::init(); info!("starting regtest submit_blocks test"); - let network = Network::new_regtest(); + let network = Network::new_regtest(None); let mut config = random_known_rpc_port_config(false, &network)?; config.mempool.debug_enable_at_height = Some(0); let rpc_address = config.rpc.listen_addr.unwrap(); @@ -58,14 +61,20 @@ pub(crate) async fn submit_blocks_test() -> Result<()> { async fn submit_blocks(rpc_address: SocketAddr) -> Result<()> { let client = RpcRequestClient::new(rpc_address); - for _ in 0..NUM_BLOCKS_TO_SUBMIT { + for height in 1..=NUM_BLOCKS_TO_SUBMIT { let block_template: GetBlockTemplate = client .json_result_from_call("getblocktemplate", "[]".to_string()) .await .expect("response should be success output with a serialized `GetBlockTemplate`"); + let network_upgrade = if height < REGTEST_NU5_ACTIVATION_HEIGHT.try_into().unwrap() { + NetworkUpgrade::Canopy + } else { + NetworkUpgrade::Nu5 + }; + let block_data = hex::encode( - proposal_block_from_template(&block_template, TimeSource::default())? + proposal_block_from_template(&block_template, TimeSource::default(), network_upgrade)? .zcash_serialize_to_vec()?, ); @@ -75,7 +84,14 @@ async fn submit_blocks(rpc_address: SocketAddr) -> Result<()> { let was_submission_successful = submit_block_response.contains(r#""result":null"#); - info!(was_submission_successful, "submitted block"); + if height % 40 == 0 { + info!( + was_submission_successful, + ?block_template, + ?network_upgrade, + "submitted block" + ); + } // Check that the block was validated and committed. assert!( From 77feb3c367e446ac8dbdf135f32e49185ef1d097 Mon Sep 17 00:00:00 2001 From: Arya Date: Fri, 3 May 2024 17:42:03 -0400 Subject: [PATCH 2/6] Fixes test --- zebra-chain/src/parameters/network/tests/vectors.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/zebra-chain/src/parameters/network/tests/vectors.rs b/zebra-chain/src/parameters/network/tests/vectors.rs index c528a9ad4c1..07a337acdb4 100644 --- a/zebra-chain/src/parameters/network/tests/vectors.rs +++ b/zebra-chain/src/parameters/network/tests/vectors.rs @@ -136,6 +136,8 @@ fn activates_network_upgrades_correctly() { let expected_default_regtest_activation_heights = &[ (Height(0), NetworkUpgrade::Genesis), (Height(1), NetworkUpgrade::Canopy), + // TODO: Remove this once the testnet parameters are being serialized. + (Height(100), NetworkUpgrade::Nu5), ]; for (network, expected_activation_heights) in [ From 99cb52b13c994020226cb15caa39dc47f884aaf0 Mon Sep 17 00:00:00 2001 From: Arya Date: Fri, 3 May 2024 17:43:11 -0400 Subject: [PATCH 3/6] removes outdated TODO --- zebra-chain/src/block/commitment.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/zebra-chain/src/block/commitment.rs b/zebra-chain/src/block/commitment.rs index 532c47d81a7..2767fc24de2 100644 --- a/zebra-chain/src/block/commitment.rs +++ b/zebra-chain/src/block/commitment.rs @@ -118,7 +118,6 @@ impl Commitment { // NetworkUpgrade::current() returns the latest network upgrade that's activated at the provided height, so // on Regtest for heights above height 0, it returns NU5, and it's possible for the current network upgrade // to be NU5 (or Canopy, or any network upgrade above Heartwood) at the Heartwood activation height. - // TODO: Check Canopy too once Zebra can construct Canopy block templates. Heartwood | Canopy | Nu5 if Some(height) == Heartwood.activation_height(network) => { if bytes == CHAIN_HISTORY_ACTIVATION_RESERVED { Ok(ChainHistoryActivationReserved) From b0298a239d84bd123fc7bbda31f658fa90a1e748 Mon Sep 17 00:00:00 2001 From: Arya Date: Fri, 3 May 2024 17:52:23 -0400 Subject: [PATCH 4/6] Adds `current_with_activation_height()` method and uses it in `Commitment::from_bytes()` --- zebra-chain/src/block/commitment.rs | 22 ++++++++++++++----- zebra-chain/src/parameters/network_upgrade.rs | 13 +++++++++++ 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/zebra-chain/src/block/commitment.rs b/zebra-chain/src/block/commitment.rs index 2767fc24de2..2071773ff66 100644 --- a/zebra-chain/src/block/commitment.rs +++ b/zebra-chain/src/block/commitment.rs @@ -109,24 +109,34 @@ impl Commitment { use Commitment::*; use CommitmentError::*; - match NetworkUpgrade::current(network, height) { - Genesis | BeforeOverwinter | Overwinter => Ok(PreSaplingReserved(bytes)), - Sapling | Blossom => match sapling::tree::Root::try_from(bytes) { + match NetworkUpgrade::current_with_activation_height(network, height) { + (Genesis | BeforeOverwinter | Overwinter, _) => Ok(PreSaplingReserved(bytes)), + (Sapling | Blossom, _) => match sapling::tree::Root::try_from(bytes) { Ok(root) => Ok(FinalSaplingRoot(root)), _ => Err(InvalidSapingRootBytes), }, + (Heartwood, activation_height) if height == activation_height => { + if bytes == CHAIN_HISTORY_ACTIVATION_RESERVED { + Ok(ChainHistoryActivationReserved) + } else { + Err(InvalidChainHistoryActivationReserved { actual: bytes }) + } + } // NetworkUpgrade::current() returns the latest network upgrade that's activated at the provided height, so // on Regtest for heights above height 0, it returns NU5, and it's possible for the current network upgrade // to be NU5 (or Canopy, or any network upgrade above Heartwood) at the Heartwood activation height. - Heartwood | Canopy | Nu5 if Some(height) == Heartwood.activation_height(network) => { + (Canopy | Nu5, activation_height) + if height == activation_height + && Some(height) == Heartwood.activation_height(network) => + { if bytes == CHAIN_HISTORY_ACTIVATION_RESERVED { Ok(ChainHistoryActivationReserved) } else { Err(InvalidChainHistoryActivationReserved { actual: bytes }) } } - Heartwood | Canopy => Ok(ChainHistoryRoot(ChainHistoryMmrRootHash(bytes))), - Nu5 => Ok(ChainHistoryBlockTxAuthCommitment( + (Heartwood | Canopy, _) => Ok(ChainHistoryRoot(ChainHistoryMmrRootHash(bytes))), + (Nu5, _) => Ok(ChainHistoryBlockTxAuthCommitment( ChainHistoryBlockTxAuthCommitmentHash(bytes), )), } diff --git a/zebra-chain/src/parameters/network_upgrade.rs b/zebra-chain/src/parameters/network_upgrade.rs index 0b9486d7f44..1cd2be65c38 100644 --- a/zebra-chain/src/parameters/network_upgrade.rs +++ b/zebra-chain/src/parameters/network_upgrade.rs @@ -280,6 +280,19 @@ impl Network { } impl NetworkUpgrade { + /// Returns the current network upgrade and its activation height for `network` and `height`. + pub fn current_with_activation_height( + network: &Network, + height: block::Height, + ) -> (NetworkUpgrade, block::Height) { + network + .activation_list() + .range(..=height) + .map(|(&h, &nu)| (nu, h)) + .next_back() + .expect("every height has a current network upgrade") + } + /// Returns the current network upgrade for `network` and `height`. pub fn current(network: &Network, height: block::Height) -> NetworkUpgrade { network From cadb4be95e552ff0e3156cb37cd8bf366c931edf Mon Sep 17 00:00:00 2001 From: Arya Date: Fri, 3 May 2024 22:00:26 -0400 Subject: [PATCH 5/6] Enables parts of the internal miner for use on Regtest when the solution isn't checked --- zebra-chain/src/work/equihash.rs | 6 ++--- zebra-rpc/src/config/mining.rs | 13 +++++++++- .../tests/snapshot/get_block_template_rpcs.rs | 2 +- zebra-rpc/src/methods/tests/vectors.rs | 4 +-- zebrad/src/commands/start.rs | 2 +- zebrad/src/components/miner.rs | 25 ++++++++++++------- 6 files changed, 35 insertions(+), 17 deletions(-) diff --git a/zebra-chain/src/work/equihash.rs b/zebra-chain/src/work/equihash.rs index 200a59f8041..f79b9212e53 100644 --- a/zebra-chain/src/work/equihash.rs +++ b/zebra-chain/src/work/equihash.rs @@ -132,7 +132,7 @@ impl Solution { #[cfg(feature = "internal-miner")] #[allow(clippy::unwrap_in_result)] pub fn solve( - mut _header: Header, + mut header: Header, mut _cancel_fn: F, ) -> Result, SolverCancelled> where @@ -141,8 +141,8 @@ impl Solution { // TODO: Function code was removed as part of https://github.com/ZcashFoundation/zebra/issues/8180 // Find the removed code at https://github.com/ZcashFoundation/zebra/blob/v1.5.1/zebra-chain/src/work/equihash.rs#L115-L166 // Restore the code when conditions are met. https://github.com/ZcashFoundation/zebra/issues/8183 - - Err(SolverCancelled) + header.solution = Solution::for_proposal(); + Ok(AtLeastOne::from_one(header)) } // TODO: Some methods were removed as part of https://github.com/ZcashFoundation/zebra/issues/8180 diff --git a/zebra-rpc/src/config/mining.rs b/zebra-rpc/src/config/mining.rs index 040b3a9e7a7..b3d98ea4661 100644 --- a/zebra-rpc/src/config/mining.rs +++ b/zebra-rpc/src/config/mining.rs @@ -29,6 +29,15 @@ pub struct Config { /// /// This developer-only config is not supported for general use. pub debug_like_zcashd: bool, + + /// Mine blocks using Zebra's internal miner, without an external mining pool or equihash solver. + /// + /// This experimental feature is only supported on testnet. + /// Mainnet miners should use a mining pool with GPUs or ASICs designed for efficient mining. + /// + /// The internal miner is off by default. + #[cfg(feature = "internal-miner")] + pub internal_miner: bool, } impl Default for Config { @@ -42,6 +51,8 @@ impl Default for Config { // TODO: Internal miner config code was removed as part of https://github.com/ZcashFoundation/zebra/issues/8180 // Find the removed code at https://github.com/ZcashFoundation/zebra/blob/v1.5.1/zebra-rpc/src/config/mining.rs#L61-L66 // Restore the code when conditions are met. https://github.com/ZcashFoundation/zebra/issues/8183 + #[cfg(feature = "internal-miner")] + internal_miner: false, } } } @@ -61,6 +72,6 @@ impl Config { // TODO: Changed to return always false so internal miner is never started. Part of https://github.com/ZcashFoundation/zebra/issues/8180 // Find the removed code at https://github.com/ZcashFoundation/zebra/blob/v1.5.1/zebra-rpc/src/config/mining.rs#L83 // Restore the code when conditions are met. https://github.com/ZcashFoundation/zebra/issues/8183 - false + self.internal_miner } } 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 7517b3e4dbe..04b3139913f 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 @@ -101,7 +101,7 @@ pub async fn test_responses( extra_coinbase_data: None, debug_like_zcashd: true, // TODO: Use default field values when optional features are enabled in tests #8183 - //..Default::default() + ..Default::default() }; // nu5 block height diff --git a/zebra-rpc/src/methods/tests/vectors.rs b/zebra-rpc/src/methods/tests/vectors.rs index fe80a8dd236..4d830c51e93 100644 --- a/zebra-rpc/src/methods/tests/vectors.rs +++ b/zebra-rpc/src/methods/tests/vectors.rs @@ -1286,7 +1286,7 @@ async fn rpc_getblocktemplate_mining_address(use_p2pkh: bool) { extra_coinbase_data: None, debug_like_zcashd: true, // TODO: Use default field values when optional features are enabled in tests #8183 - //..Default::default() + ..Default::default() }; // nu5 block height @@ -1735,7 +1735,7 @@ async fn rpc_getdifficulty() { extra_coinbase_data: None, debug_like_zcashd: true, // TODO: Use default field values when optional features are enabled in tests #8183 - //..Default::default() + ..Default::default() }; // nu5 block height diff --git a/zebrad/src/commands/start.rs b/zebrad/src/commands/start.rs index 7efabf08ecc..2f2dabf0daa 100644 --- a/zebrad/src/commands/start.rs +++ b/zebrad/src/commands/start.rs @@ -359,7 +359,7 @@ impl StartCmd { address_book, ); - crate::components::miner::spawn_init(&config.mining, rpc) + crate::components::miner::spawn_init(&config.network.network, &config.mining, rpc) } else { tokio::spawn(std::future::pending().in_current_span()) }; diff --git a/zebrad/src/components/miner.rs b/zebrad/src/components/miner.rs index 47732257b4f..193f30e8c5b 100644 --- a/zebrad/src/components/miner.rs +++ b/zebrad/src/components/miner.rs @@ -16,11 +16,11 @@ use tower::Service; use tracing::{Instrument, Span}; use zebra_chain::{ - block::{self, Block}, + block::{self, Block, Height}, chain_sync_status::ChainSyncStatus, chain_tip::ChainTip, diagnostic::task::WaitForPanics, - parameters::NetworkUpgrade, + parameters::{Network, NetworkUpgrade}, serialization::{AtLeastOne, ZcashSerialize}, shutdown::is_shutting_down, work::equihash::{Solution, SolverCancelled}, @@ -61,6 +61,7 @@ pub const BLOCK_MINING_WAIT_TIME: Duration = Duration::from_secs(3); /// /// See [`run_mining_solver()`] for more details. pub fn spawn_init( + network: &Network, config: &Config, rpc: GetBlockTemplateRpcImpl, ) -> JoinHandle> @@ -94,10 +95,11 @@ where SyncStatus: ChainSyncStatus + Clone + Send + Sync + 'static, AddressBook: AddressBookPeers + Clone + Send + Sync + 'static, { + let network = network.clone(); let config = config.clone(); // TODO: spawn an entirely new executor here, so mining is isolated from higher priority tasks. - tokio::spawn(init(config, rpc).in_current_span()) + tokio::spawn(init(network, config, rpc).in_current_span()) } /// Initialize the miner based on its config. @@ -107,6 +109,7 @@ where /// /// See [`run_mining_solver()`] for more details. pub async fn init( + network: Network, _config: Config, rpc: GetBlockTemplateRpcImpl, ) -> Result<(), Report> @@ -163,7 +166,7 @@ where let mut abort_handles = Vec::new(); let template_generator = tokio::task::spawn( - generate_block_templates(rpc.clone(), template_sender).in_current_span(), + generate_block_templates(network, rpc.clone(), template_sender).in_current_span(), ); abort_handles.push(template_generator.abort_handle()); let template_generator = template_generator.wait_for_panics(); @@ -217,6 +220,7 @@ pub async fn generate_block_templates< SyncStatus, AddressBook, >( + network: Network, rpc: GetBlockTemplateRpcImpl, template_sender: watch::Sender>>, ) -> Result<(), Report> @@ -260,11 +264,11 @@ where // Shut down the task when all the template receivers are dropped, or Zebra shuts down. while !template_sender.is_closed() && !is_shutting_down() { - let template = rpc.get_block_template(Some(parameters.clone())).await; + let template: Result<_, _> = rpc.get_block_template(Some(parameters.clone())).await; // Wait for the chain to sync so we get a valid template. let Ok(template) = template else { - debug!( + info!( ?BLOCK_TEMPLATE_WAIT_TIME, "waiting for a valid block template", ); @@ -291,9 +295,12 @@ where // Tell the next get_block_template() call to wait until the template has changed. parameters.long_poll_id = Some(template.long_poll_id); - let block = - proposal_block_from_template(&template, TimeSource::CurTime, NetworkUpgrade::Nu5) - .expect("unexpected invalid block template"); + let block = proposal_block_from_template( + &template, + TimeSource::CurTime, + NetworkUpgrade::current(&network, Height(template.height)), + ) + .expect("unexpected invalid block template"); // If the template has actually changed, send an updated template. template_sender.send_if_modified(|old_block| { From 752949e8f4c58c64a0cb77e6d820b758624d3c2a Mon Sep 17 00:00:00 2001 From: Arya Date: Fri, 10 May 2024 09:40:18 -0400 Subject: [PATCH 6/6] Update internal miner config field docs --- zebra-rpc/src/config/mining.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/zebra-rpc/src/config/mining.rs b/zebra-rpc/src/config/mining.rs index b3d98ea4661..0594d96b822 100644 --- a/zebra-rpc/src/config/mining.rs +++ b/zebra-rpc/src/config/mining.rs @@ -32,10 +32,12 @@ pub struct Config { /// Mine blocks using Zebra's internal miner, without an external mining pool or equihash solver. /// - /// This experimental feature is only supported on testnet. - /// Mainnet miners should use a mining pool with GPUs or ASICs designed for efficient mining. + /// This experimental feature is only supported on regtest as it uses null solutions and skips checking + /// for a valid Proof of Work. /// /// The internal miner is off by default. + // TODO: Restore equihash solver and recommend that Mainnet miners should use a mining pool with + // GPUs or ASICs designed for efficient mining. #[cfg(feature = "internal-miner")] pub internal_miner: bool, }