NU7 constants (#9256)

* Introduce Nu7

* Introduce Nu7 fo other crates of Zebra

* Fix of new_regtest call (as it additionally needs Nu7 arg now)

* Fix of new_regtest call (as it additionally needs Nu7 arg now) (2)

* Set Nu7 as a network update for testnet in zebra-chain network tests

* Fix serde names for NU7

* Update test snapshot in zebra-rpc to use NU7

* Copy Nu7-related changes from zsa-integration-state

* Uncomment zcash_unstable = nu7

* Fix Nu7 constants and add cfg(zcash_unstable ...) attribute according to PR #15 review comments

* Update network constant values according to PR #15 review comments

* Add zcash_unstable=nu6 Rust flag to .cargo/config.toml to use nu6 by default

* Add zcash_unstable = nu6 cfg in zebra-network/.../types.rs

* Fix nu7 activation heights in network_upgrade.rs (nu6 value + 1 does not work - causes a test failure)

* Add cfg for CURRENT_NETWORK_PROTOCOL_VERSION constant definition, add FIXMEs for a couple of Nu6 processing cases, add processing of Nu7

* Update get_blockchain_info@testnet_10.snap

* Update get_blockchain_info@mainnet_10.snap

* updated cfg flag

* remove `zcash_unstable` flag

* Remove testnet and mainnet NU7 activation heights, comment out consensus branch id and conversion to zcash primitives nu type

* Yep, it'll work after NU7

* Yep, the test should work fine after NU7

* Yep, it only needs to be a post-nu6 height.

* other fixes and cleanups

* Updates snapshots, removes unnecessary FIXMEs, fixes issues with bad merge conflict resolution

* fixes test hang when there are NUs defined without activation heights

* fixes test, applies suggestion from code review.

* Enable consensus branch ID for Nu7

---------

Co-authored-by: Dmitry Demin <dmitry@qed-it.com>
Co-authored-by: Arya <aryasolhi@gmail.com>
Co-authored-by: Marek <mail@marek.onl>
This commit is contained in:
Paul 2025-04-21 16:38:44 +03:00 committed by GitHub
parent 9002cfcbd3
commit e6dc3b6fd3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 86 additions and 68 deletions

View File

@ -125,7 +125,7 @@ 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 could return NU6, and it's possible for the current network upgrade
// to be NU6 (or Canopy, or any network upgrade above Heartwood) at the Heartwood activation height.
(Canopy | Nu5 | Nu6, activation_height)
(Canopy | Nu5 | Nu6 | Nu7, activation_height)
if height == activation_height
&& Some(height) == Heartwood.activation_height(network) =>
{
@ -136,7 +136,7 @@ impl Commitment {
}
}
(Heartwood | Canopy, _) => Ok(ChainHistoryRoot(ChainHistoryMmrRootHash(bytes))),
(Nu5 | Nu6, _) => Ok(ChainHistoryBlockTxAuthCommitment(
(Nu5 | Nu6 | Nu7, _) => Ok(ChainHistoryBlockTxAuthCommitment(
ChainHistoryBlockTxAuthCommitmentHash(bytes),
)),
}

View File

@ -102,7 +102,7 @@ impl NonEmptyHistoryTree {
)?;
InnerHistoryTree::PreOrchard(tree)
}
NetworkUpgrade::Nu5 | NetworkUpgrade::Nu6 => {
NetworkUpgrade::Nu5 | NetworkUpgrade::Nu6 | NetworkUpgrade::Nu7 => {
let tree = Tree::<OrchardOnward>::new_from_cache(
network,
network_upgrade,
@ -156,7 +156,7 @@ impl NonEmptyHistoryTree {
)?;
(InnerHistoryTree::PreOrchard(tree), entry)
}
NetworkUpgrade::Nu5 | NetworkUpgrade::Nu6 => {
NetworkUpgrade::Nu5 | NetworkUpgrade::Nu6 | NetworkUpgrade::Nu7 => {
let (tree, entry) = Tree::<OrchardOnward>::new_from_block(
network,
block,

View File

@ -149,12 +149,10 @@ impl Network {
/// Creates a new [`Network::Testnet`] with `Regtest` parameters and the provided network upgrade activation heights.
pub fn new_regtest(
nu5_activation_height: Option<u32>,
nu6_activation_height: Option<u32>,
configured_activation_heights: testnet::ConfiguredActivationHeights,
) -> Self {
Self::new_configured_testnet(testnet::Parameters::new_regtest(
nu5_activation_height,
nu6_activation_height,
configured_activation_heights,
))
}

View File

@ -77,8 +77,8 @@ impl FundingStreamReceiver {
/// [ZIP-1014]: https://zips.z.cash/zip-1014#abstract
/// [`zcashd`]: https://github.com/zcash/zcash/blob/3f09cfa00a3c90336580a127e0096d99e25a38d6/src/consensus/funding.cpp#L13-L32
/// [ZIP-1015]: https://zips.z.cash/zip-1015
pub fn info(&self, is_nu6: bool) -> (&'static str, &'static str) {
if is_nu6 {
pub fn info(&self, is_post_nu6: bool) -> (&'static str, &'static str) {
if is_post_nu6 {
(
match self {
FundingStreamReceiver::Ecc => "Electric Coin Company",

View File

@ -118,35 +118,24 @@ impl From<&BTreeMap<Height, NetworkUpgrade>> for ConfiguredActivationHeights {
let mut configured_activation_heights = ConfiguredActivationHeights::default();
for (height, network_upgrade) in activation_heights.iter() {
match network_upgrade {
let field = match network_upgrade {
NetworkUpgrade::BeforeOverwinter => {
configured_activation_heights.before_overwinter = Some(height.0);
}
NetworkUpgrade::Overwinter => {
configured_activation_heights.overwinter = Some(height.0);
}
NetworkUpgrade::Sapling => {
configured_activation_heights.sapling = Some(height.0);
}
NetworkUpgrade::Blossom => {
configured_activation_heights.blossom = Some(height.0);
}
NetworkUpgrade::Heartwood => {
configured_activation_heights.heartwood = Some(height.0);
}
NetworkUpgrade::Canopy => {
configured_activation_heights.canopy = Some(height.0);
}
NetworkUpgrade::Nu5 => {
configured_activation_heights.nu5 = Some(height.0);
}
NetworkUpgrade::Nu6 => {
configured_activation_heights.nu6 = Some(height.0);
&mut configured_activation_heights.before_overwinter
}
NetworkUpgrade::Overwinter => &mut configured_activation_heights.overwinter,
NetworkUpgrade::Sapling => &mut configured_activation_heights.sapling,
NetworkUpgrade::Blossom => &mut configured_activation_heights.blossom,
NetworkUpgrade::Heartwood => &mut configured_activation_heights.heartwood,
NetworkUpgrade::Canopy => &mut configured_activation_heights.canopy,
NetworkUpgrade::Nu5 => &mut configured_activation_heights.nu5,
NetworkUpgrade::Nu6 => &mut configured_activation_heights.nu6,
NetworkUpgrade::Nu7 => &mut configured_activation_heights.nu7,
NetworkUpgrade::Genesis => {
continue;
}
}
};
*field = Some(height.0)
}
configured_activation_heights
@ -271,6 +260,9 @@ pub struct ConfiguredActivationHeights {
/// Activation height for `NU6` network upgrade.
#[serde(rename = "NU6")]
pub nu6: Option<u32>,
/// Activation height for `NU7` network upgrade.
#[serde(rename = "NU7")]
pub nu7: Option<u32>,
}
/// Builder for the [`Parameters`] struct.
@ -405,6 +397,7 @@ impl ParametersBuilder {
canopy,
nu5,
nu6,
nu7,
}: ConfiguredActivationHeights,
) -> Self {
use NetworkUpgrade::*;
@ -427,6 +420,7 @@ impl ParametersBuilder {
.chain(canopy.into_iter().map(|h| (h, Canopy)))
.chain(nu5.into_iter().map(|h| (h, Nu5)))
.chain(nu6.into_iter().map(|h| (h, Nu6)))
.chain(nu7.into_iter().map(|h| (h, Nu7)))
.map(|(h, nu)| (h.try_into().expect("activation height must be valid"), nu))
.collect();
@ -672,11 +666,10 @@ impl Parameters {
///
/// Creates an instance of [`Parameters`] with `Regtest` values.
pub fn new_regtest(
nu5_activation_height: Option<u32>,
nu6_activation_height: Option<u32>,
ConfiguredActivationHeights { nu5, nu6, nu7, .. }: ConfiguredActivationHeights,
) -> Self {
#[cfg(any(test, feature = "proptest-impl"))]
let nu5_activation_height = nu5_activation_height.or(Some(100));
let nu5 = nu5.or(Some(100));
let parameters = Self::build()
.with_genesis_hash(REGTEST_GENESIS_HASH)
@ -689,8 +682,9 @@ impl Parameters {
// most network upgrades are disabled by default for Regtest in zcashd
.with_activation_heights(ConfiguredActivationHeights {
canopy: Some(1),
nu5: nu5_activation_height,
nu6: nu6_activation_height,
nu5,
nu6,
nu7,
..Default::default()
})
.with_halving_interval(PRE_BLOSSOM_REGTEST_HALVING_INTERVAL);
@ -735,7 +729,7 @@ impl Parameters {
should_allow_unshielded_coinbase_spends,
pre_blossom_halving_interval,
post_blossom_halving_interval,
} = Self::new_regtest(None, None);
} = Self::new_regtest(Default::default());
self.network_name == network_name
&& self.genesis_hash == genesis_hash

View File

@ -107,7 +107,7 @@ fn activates_network_upgrades_correctly() {
let expected_activation_height = 1;
let network = testnet::Parameters::build()
.with_activation_heights(ConfiguredActivationHeights {
nu6: Some(expected_activation_height),
nu7: Some(expected_activation_height),
..Default::default()
})
.to_network();
@ -145,7 +145,7 @@ fn activates_network_upgrades_correctly() {
(Network::Mainnet, MAINNET_ACTIVATION_HEIGHTS),
(Network::new_default_testnet(), TESTNET_ACTIVATION_HEIGHTS),
(
Network::new_regtest(None, None),
Network::new_regtest(Default::default()),
expected_default_regtest_activation_heights,
),
] {
@ -196,7 +196,7 @@ fn check_configured_network_name() {
"Mainnet should be displayed as 'Mainnet'"
);
assert_eq!(
Network::new_regtest(None, None).to_string(),
Network::new_regtest(Default::default()).to_string(),
"Regtest",
"Regtest should be displayed as 'Regtest'"
);

View File

@ -15,7 +15,7 @@ use hex::{FromHex, ToHex};
use proptest_derive::Arbitrary;
/// A list of network upgrades in the order that they must be activated.
const NETWORK_UPGRADES_IN_ORDER: [NetworkUpgrade; 9] = [
const NETWORK_UPGRADES_IN_ORDER: [NetworkUpgrade; 10] = [
Genesis,
BeforeOverwinter,
Overwinter,
@ -25,6 +25,7 @@ const NETWORK_UPGRADES_IN_ORDER: [NetworkUpgrade; 9] = [
Canopy,
Nu5,
Nu6,
Nu7,
];
/// A Zcash network upgrade.
@ -61,6 +62,9 @@ pub enum NetworkUpgrade {
/// The Zcash protocol after the NU6 upgrade.
#[serde(rename = "NU6")]
Nu6,
/// The Zcash protocol after the NU7 upgrade.
#[serde(rename = "NU7")]
Nu7,
}
impl TryFrom<u32> for NetworkUpgrade {
@ -116,6 +120,7 @@ const FAKE_MAINNET_ACTIVATION_HEIGHTS: &[(block::Height, NetworkUpgrade)] = &[
(block::Height(30), Canopy),
(block::Height(35), Nu5),
(block::Height(40), Nu6),
(block::Height(45), Nu7),
];
/// Testnet network upgrade activation heights.
@ -243,6 +248,7 @@ pub(crate) const CONSENSUS_BRANCH_IDS: &[(NetworkUpgrade, ConsensusBranchId)] =
(Canopy, ConsensusBranchId(0xe9ff75a6)),
(Nu5, ConsensusBranchId(0xc2d6d0b4)),
(Nu6, ConsensusBranchId(0xc8e71055)),
(Nu7, ConsensusBranchId(0x77190ad8)),
];
/// The target block spacing before Blossom.
@ -431,7 +437,9 @@ impl NetworkUpgrade {
pub fn target_spacing(&self) -> Duration {
let spacing_seconds = match self {
Genesis | BeforeOverwinter | Overwinter | Sapling => PRE_BLOSSOM_POW_TARGET_SPACING,
Blossom | Heartwood | Canopy | Nu5 | Nu6 => POST_BLOSSOM_POW_TARGET_SPACING.into(),
Blossom | Heartwood | Canopy | Nu5 | Nu6 | Nu7 => {
POST_BLOSSOM_POW_TARGET_SPACING.into()
}
};
Duration::seconds(spacing_seconds)
@ -550,6 +558,7 @@ impl From<zcash_protocol::consensus::NetworkUpgrade> for NetworkUpgrade {
zcash_protocol::consensus::NetworkUpgrade::Canopy => Self::Canopy,
zcash_protocol::consensus::NetworkUpgrade::Nu5 => Self::Nu5,
zcash_protocol::consensus::NetworkUpgrade::Nu6 => Self::Nu6,
// zcash_protocol::consensus::NetworkUpgrade::Nu7 => Self::Nu7,
}
}
}

View File

@ -276,7 +276,8 @@ impl Version for zcash_history::V1 {
NetworkUpgrade::Heartwood
| NetworkUpgrade::Canopy
| NetworkUpgrade::Nu5
| NetworkUpgrade::Nu6 => zcash_history::NodeData {
| NetworkUpgrade::Nu6
| NetworkUpgrade::Nu7 => zcash_history::NodeData {
consensus_branch_id: branch_id.into(),
subtree_commitment: block_hash,
start_time: time,

View File

@ -778,7 +778,7 @@ impl Arbitrary for Transaction {
NetworkUpgrade::Blossom | NetworkUpgrade::Heartwood | NetworkUpgrade::Canopy => {
Self::v4_strategy(ledger_state)
}
NetworkUpgrade::Nu5 | NetworkUpgrade::Nu6 => prop_oneof![
NetworkUpgrade::Nu5 | NetworkUpgrade::Nu6 | NetworkUpgrade::Nu7 => prop_oneof![
Self::v4_strategy(ledger_state.clone()),
Self::v5_strategy(ledger_state)
]

View File

@ -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(None, None).checkpoint_list();
let _ = Network::new_regtest(Default::default()).checkpoint_list();
Ok(())
}

View File

@ -938,7 +938,8 @@ where
| NetworkUpgrade::Heartwood
| NetworkUpgrade::Canopy
| NetworkUpgrade::Nu5
| NetworkUpgrade::Nu6 => Ok(()),
| NetworkUpgrade::Nu6
| NetworkUpgrade::Nu7 => Ok(()),
// Does not support V4 transactions
NetworkUpgrade::Genesis
@ -1024,7 +1025,7 @@ where
//
// Note: Here we verify the transaction version number of the above rule, the group
// id is checked in zebra-chain crate, in the transaction serialize.
NetworkUpgrade::Nu5 | NetworkUpgrade::Nu6 => Ok(()),
NetworkUpgrade::Nu5 | NetworkUpgrade::Nu6 | NetworkUpgrade::Nu7 => Ok(()),
// Does not support V5 transactions
NetworkUpgrade::Genesis

View File

@ -17,7 +17,7 @@ use zebra_chain::{
amount::{Amount, NonNegative},
block::{self, Block, Height},
orchard::{Action, AuthorizedAction, Flags},
parameters::{Network, NetworkUpgrade},
parameters::{testnet::ConfiguredActivationHeights, Network, NetworkUpgrade},
primitives::{ed25519, x25519, Groth16Proof},
sapling,
serialization::{DateTime32, ZcashDeserialize, ZcashDeserializeInto},
@ -1007,7 +1007,10 @@ async fn mempool_request_with_immature_spend_is_rejected() {
async fn mempool_request_with_transparent_coinbase_spend_is_accepted_on_regtest() {
let _init_guard = zebra_test::init();
let network = Network::new_regtest(None, Some(1_000));
let network = Network::new_regtest(ConfiguredActivationHeights {
nu6: Some(1_000),
..Default::default()
});
let mut state: MockService<_, _, _, _> = MockService::build().for_unit_tests();
let verifier = Verifier::new_for_tests(&network, state.clone());
@ -2865,7 +2868,12 @@ async fn v5_consensus_branch_ids() {
while let Some(next_nu) = network_upgrade.next_upgrade() {
// Check an outdated network upgrade.
let height = next_nu.activation_height(&network).expect("height");
let Some(height) = next_nu.activation_height(&network) else {
tracing::warn!(?next_nu, "missing activation height",);
// Shift the network upgrade for the next loop iteration.
network_upgrade = next_nu;
continue;
};
let block_req = verifier
.clone()

View File

@ -347,7 +347,8 @@ fn sanitize_transaction_version(
BeforeOverwinter => 2,
Overwinter => 3,
Sapling | Blossom | Heartwood | Canopy => 4,
Nu5 | Nu6 => 5,
// FIXME: Use 6 for Nu7
Nu5 | Nu6 | Nu7 => 5,
}
};

View File

@ -725,12 +725,11 @@ impl<'de> Deserialize<'de> for Config {
(NetworkKind::Mainnet, _) => Network::Mainnet,
(NetworkKind::Testnet, None) => Network::new_default_testnet(),
(NetworkKind::Regtest, testnet_parameters) => {
let (nu5_activation_height, nu6_activation_height) = testnet_parameters
let configured_activation_heights = testnet_parameters
.and_then(|params| params.activation_heights)
.map(|ConfiguredActivationHeights { nu5, nu6, .. }| (nu5, nu6))
.unwrap_or_default();
Network::new_regtest(nu5_activation_height, nu6_activation_height)
Network::new_regtest(configured_activation_heights)
}
(
NetworkKind::Testnet,

View File

@ -340,6 +340,8 @@ pub const TIMESTAMP_TRUNCATION_SECONDS: u32 = 30 * 60;
///
/// This version of Zebra draws the current network protocol version from
/// [ZIP-253](https://zips.z.cash/zip-0253).
// TODO: Update this constant to the correct value after NU7 activation,
// pub const CURRENT_NETWORK_PROTOCOL_VERSION: Version = Version(170_140);
pub const CURRENT_NETWORK_PROTOCOL_VERSION: Version = Version(170_120);
/// The default RTT estimate for peer responses.
@ -410,7 +412,7 @@ lazy_static! {
hash_map.insert(NetworkKind::Mainnet, Version::min_specified_for_upgrade(&Mainnet, Nu6));
hash_map.insert(NetworkKind::Testnet, Version::min_specified_for_upgrade(&Network::new_default_testnet(), Nu6));
hash_map.insert(NetworkKind::Regtest, Version::min_specified_for_upgrade(&Network::new_regtest(None, None), Nu6));
hash_map.insert(NetworkKind::Regtest, Version::min_specified_for_upgrade(&Network::new_regtest(Default::default()), Nu6));
hash_map
};

View File

@ -106,6 +106,8 @@ impl Version {
(Mainnet, Nu5) => 170_100,
(Testnet(params), Nu6) if params.is_default_testnet() => 170_110,
(Mainnet, Nu6) => 170_120,
(Testnet(params), Nu7) if params.is_default_testnet() => 170_130,
(Mainnet, Nu7) => 170_140,
// It should be fine to reject peers with earlier network protocol versions on custom testnets for now.
(Testnet(_), _) => CURRENT_NETWORK_PROTOCOL_VERSION.0,
@ -205,8 +207,9 @@ mod test {
let _init_guard = zebra_test::init();
let highest_network_upgrade = NetworkUpgrade::current(network, block::Height::MAX);
assert!(highest_network_upgrade == Nu6 || highest_network_upgrade == Nu5,
"expected coverage of all network upgrades: add the new network upgrade to the list in this test");
assert!(
highest_network_upgrade == Nu7 || highest_network_upgrade == Nu6,
"expected coverage of all network upgrades: add the new network upgrade to the list in this test");
for &network_upgrade in &[
BeforeOverwinter,
@ -217,6 +220,7 @@ mod test {
Canopy,
Nu5,
Nu6,
Nu7,
] {
let height = network_upgrade.activation_height(network);
if let Some(height) = height {

View File

@ -1207,7 +1207,7 @@ where
// Separate the funding streams into deferred and non-deferred streams
.partition(|(receiver, _)| matches!(receiver, FundingStreamReceiver::Deferred));
let is_nu6 = NetworkUpgrade::current(&network, height) == NetworkUpgrade::Nu6;
let is_post_nu6 = NetworkUpgrade::current(&network, height) >= NetworkUpgrade::Nu6;
let [lockbox_total, funding_streams_total]: [std::result::Result<
Amount<NonNegative>,
@ -1229,7 +1229,7 @@ where
.into_iter()
.map(|(receiver, value)| {
let address = funding_stream_address(height, &network, receiver);
FundingStream::new(is_nu6, receiver, value, address)
FundingStream::new(is_post_nu6, receiver, value, address)
})
.collect()
});

View File

@ -217,7 +217,7 @@ pub fn proposal_block_from_template(
| NetworkUpgrade::Blossom
| NetworkUpgrade::Heartwood => panic!("pre-Canopy block templates not supported"),
NetworkUpgrade::Canopy => chain_history_root.bytes_in_serialized_order().into(),
NetworkUpgrade::Nu5 | NetworkUpgrade::Nu6 => {
NetworkUpgrade::Nu5 | NetworkUpgrade::Nu6 | NetworkUpgrade::Nu7 => {
block_commitments_hash.bytes_in_serialized_order().into()
}
};

View File

@ -76,12 +76,12 @@ pub struct FundingStream {
impl FundingStream {
/// Convert a `receiver`, `value`, and `address` into a `FundingStream` response.
pub fn new(
is_nu6: bool,
is_post_nu6: bool,
receiver: FundingStreamReceiver,
value: Amount<NonNegative>,
address: Option<&transparent::Address>,
) -> FundingStream {
let (name, specification) = receiver.info(is_nu6);
let (name, specification) = receiver.info(is_post_nu6);
FundingStream {
recipient: name.to_string(),

View File

@ -2899,7 +2899,7 @@ async fn fully_synced_rpc_z_getsubtreesbyindex_snapshot_test() -> Result<()> {
async fn validate_regtest_genesis_block() {
let _init_guard = zebra_test::init();
let network = Network::new_regtest(None, None);
let network = Network::new_regtest(Default::default());
let state = zebra_state::init_test(&network);
let (
block_verifier_router,
@ -2973,7 +2973,7 @@ async fn trusted_chain_sync_handles_forks_correctly() -> Result<()> {
use zebra_state::{ReadResponse, Response};
let _init_guard = zebra_test::init();
let mut config = os_assigned_rpc_port_config(false, &Network::new_regtest(None, None))?;
let mut config = os_assigned_rpc_port_config(false, &Network::new_regtest(Default::default()))?;
config.state.ephemeral = false;
let network = config.network.network.clone();

View File

@ -73,6 +73,7 @@ Heartwood = 903_800
Canopy = 1_028_500
NU5 = 1_842_420
NU6 = 2_000_000
NU7 = 2_000_001
[network.testnet_parameters.pre_nu6_funding_streams.height_range]
start = 0

View File

@ -42,7 +42,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(None, None);
let network = Network::new_regtest(Default::default());
let mut config = os_assigned_rpc_port_config(false, &network)?;
config.mempool.debug_enable_at_height = Some(0);