Skip to content

Commit

Permalink
change(consensus): Refactor production code for network consensus rul…
Browse files Browse the repository at this point in the history
…es to `Network` methods (#8340)

* begin refactor suggested as "step 2": #7968 (comment)
Squashed from multiple commits to enable partial rebase

* break out more little traits

* add activation implementation leveraging From<Network> for lrz::cons::

* for transfer of ownership I cannot return a type that's owned by the method

* hrp_sapling_extended_full_viewing_key

* complete implementation of interface of Parameters on Network reuse Parameters on zcash Network where possible

* move doc-comments to trait declarations (from impls)

* Simplify/complete Parameters impl for Network

* Add checkpoint_list method, move documentation, etc

* move last match network to inside network method

* add back comment

* use zcash_address for parameter types in zebra-chain

* use inherent methods instead of big parameters passthrough

* revert to implementation of From on zcash_primitives::..::Network vs &zcash_prim...

* move match

* add test to block maximum time rule

* update changelog

* finish porting target_difficutly_limit

* remove obscelete code comment

* revert non-functional change

* finish migrating target_difficulty_limit, checkpoint_list

* update changelog

---------

Co-authored-by: Hazel OHearn <[email protected]>
  • Loading branch information
zancas and AloeareV authored Mar 12, 2024
1 parent 9b91d4b commit 3bef54b
Show file tree
Hide file tree
Showing 32 changed files with 284 additions and 243 deletions.
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,20 @@ 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_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

This release exposes the shielded scanning functionality through an initial
Expand Down
4 changes: 1 addition & 3 deletions zebra-chain/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ async-error = [

# Mining RPC support
getblocktemplate-rpcs = [
"zcash_address",
]

# Experimental shielded scanning support
Expand Down Expand Up @@ -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 }
Expand Down
16 changes: 1 addition & 15 deletions zebra-chain/src/parameters/genesis.rs
Original file line number Diff line number Diff line change
@@ -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]);
31 changes: 30 additions & 1 deletion zebra-chain/src/parameters/network.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::{fmt, str::FromStr};
use thiserror::Error;

use crate::{
block::{Height, HeightDiff},
block::{self, Height, HeightDiff},
parameters::NetworkUpgrade::Canopy,
};

Expand Down Expand Up @@ -63,6 +63,35 @@ pub enum Network {
Testnet,
}

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()
}

/// 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()
}
/// 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 <https://zips.z.cash/protocol/protocol.pdf#blockheader>
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 From<Network> for &'static str {
fn from(network: Network) -> &'static str {
match network {
Expand Down
17 changes: 16 additions & 1 deletion zebra-chain/src/parameters/network/tests/prop.rs
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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::<Height>()) {
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);


}
}
34 changes: 12 additions & 22 deletions zebra-chain/src/parameters/network_upgrade.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ const TESTNET_MINIMUM_DIFFICULTY_START_HEIGHT: block::Height = block::Height(299
/// <https://zips.z.cash/protocol/protocol.pdf#blockheader>
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.
///
Expand All @@ -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<block::Height, NetworkUpgrade> {
pub fn activation_list(&self) -> BTreeMap<block::Height, NetworkUpgrade> {
let (mainnet_heights, testnet_heights) = {
#[cfg(not(feature = "zebra-test"))]
{
Expand Down Expand Up @@ -269,18 +269,20 @@ impl NetworkUpgrade {
(MAINNET_ACTIVATION_HEIGHTS, TESTNET_ACTIVATION_HEIGHTS)
}
};
match network {
match self {
Mainnet => mainnet_heights,
Testnet => testnet_heights,
}
.iter()
.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()
Expand All @@ -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> {
NetworkUpgrade::activation_list(network)
network
.activation_list()
.range((Excluded(height), Unbounded))
.map(|(_, nu)| *nu)
.next()
Expand All @@ -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<block::Height> {
NetworkUpgrade::activation_list(network)
network
.activation_list()
.iter()
.filter(|(_, nu)| nu == &self)
.map(|(height, _)| *height)
Expand All @@ -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.
Expand Down Expand Up @@ -445,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 <https://zips.z.cash/protocol/protocol.pdf#blockheader>
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<NetworkUpgrade> {
CONSENSUS_BRANCH_IDS
Expand Down
12 changes: 6 additions & 6 deletions zebra-chain/src/parameters/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());

Expand All @@ -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)));
Expand All @@ -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!(
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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 {
Expand Down
24 changes: 6 additions & 18 deletions zebra-chain/src/primitives/zcash_note_encryption.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
&<zcash_primitives::consensus::Network>::from(network),
alt_height,
&null_sapling_ovk,
output,
);
if recovery.is_none() {
return false;
}
Expand Down
Loading

0 comments on commit 3bef54b

Please sign in to comment.