2020-07-22 05:10:02 -07:00
|
|
|
//! Network upgrade consensus parameters for Zcash.
|
|
|
|
|
|
|
|
use NetworkUpgrade::*;
|
|
|
|
|
2020-08-16 11:42:02 -07:00
|
|
|
use crate::block;
|
2020-08-15 15:45:37 -07:00
|
|
|
use crate::parameters::{Network, Network::*};
|
2020-08-09 16:56:57 -07:00
|
|
|
|
2020-07-22 05:34:48 -07:00
|
|
|
use std::collections::{BTreeMap, HashMap};
|
2022-03-25 05:25:31 -07:00
|
|
|
use std::fmt;
|
2020-07-22 05:10:02 -07:00
|
|
|
use std::ops::Bound::*;
|
|
|
|
|
2020-11-19 00:00:56 -08:00
|
|
|
use chrono::{DateTime, Duration, Utc};
|
2022-03-25 05:25:31 -07:00
|
|
|
use hex::{FromHex, ToHex};
|
2020-11-10 06:41:24 -08:00
|
|
|
|
Send crawled transaction IDs to downloader (#2801)
* Rename type parameter to be more explicit
Replace the single letter with a proper name.
* Remove imports for `Request` and `Response`
The type names will conflict with the ones for the mempool service.
* Attach `Mempool` service to the `Crawler`
Add a field to the `Crawler` type to store a way to access the `Mempool`
service.
* Forward crawled transactions to downloader
The crawled transactions are now sent to the transaction downloader and
verifier, to be included in the mempool.
* Derive `Eq` and `PartialEq` for `mempool::Request`
Make it simpler to use the `MockService::expect_request` method.
* Test if crawled transactions are downloaded
Create some dummy crawled transactions, and let the crawler discover
them. Then check if they are forwarded to the mempool to be downloaded
and verified.
* Don't send empty transaction ID list to downloader
Ignore response from peers that don't provide any crawled transactions.
* Log errors when forwarding crawled transaction IDs
Calling the Mempool service should not fail, so if an error happens it
should be visible. However, errors when downloading individual
transactions can happen from time to time, so there's no need for them
to be very visible.
* Document existing `mempool::Crawler` test
Provide some depth as to what the test expect from the crawler's
behavior.
* Refactor to create `setup_crawler` helper function
Make it easier to reuse the common test setup code.
* Simplify code to expect requests
Now that `zebra_network::Request` implement `Eq`, the call can be
simplified into `expect_request`.
* Refactor to create `respond_with_transaction_ids`
A helper function that checks for a network crawl request and responds
with the given list of crawled transaction IDs.
* Refactor to create `crawler_iterator` helper
A function to intercept and respond to the fanned-out requests sent
during a single crawl iteration.
* Refactor to create `respond_to_queue_request`
Reduce the repeated code necessary to intercept and reply to a request
for queuing transactions to be downloaded.
* Add `respond_to_queue_request_with_error` helper
Intercepts a mempool request to queue transactions to be downloaded, and
responds with an error, simulating an internal problem in the mempool
service implementation.
* Derive `Arbitrary` for `NetworkUpgrade`
This is required for deriving `Arbitrary` for some error types.
* Derive `Arbitrary` for `TransactionError`
Allow random transaction errors to be generated for property tests.
* Derive `Arbitrary` for `MempoolError`
Allow random Mempool errors to be generated for property tests.
* Test if errors don't stop the mempool crawler
The crawler should be robust enough to continue operating even if the
mempool service fails to download transactions or even fails to handle
requests to enqueue transactions.
* Reduce the log level for download errors
They should happen regularly, so there's no need to have them with a
high visibility level.
Co-authored-by: teor <teor@riseup.net>
* Stop crawler if service stops
If `Mempool::poll_ready` returns an error, it's because the mempool
service has stopped and can't handle any requests, so the crawler should
stop as well.
Co-authored-by: teor <teor@riseup.net>
Co-authored-by: Conrado Gouvea <conrado@zfnd.org>
2021-10-04 17:55:42 -07:00
|
|
|
#[cfg(any(test, feature = "proptest-impl"))]
|
|
|
|
use proptest_derive::Arbitrary;
|
|
|
|
|
2020-07-27 00:54:55 -07:00
|
|
|
/// A Zcash network upgrade.
|
|
|
|
///
|
|
|
|
/// Network upgrades can change the Zcash network protocol or consensus rules in
|
|
|
|
/// incompatible ways.
|
2021-04-28 18:55:29 -07:00
|
|
|
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
Send crawled transaction IDs to downloader (#2801)
* Rename type parameter to be more explicit
Replace the single letter with a proper name.
* Remove imports for `Request` and `Response`
The type names will conflict with the ones for the mempool service.
* Attach `Mempool` service to the `Crawler`
Add a field to the `Crawler` type to store a way to access the `Mempool`
service.
* Forward crawled transactions to downloader
The crawled transactions are now sent to the transaction downloader and
verifier, to be included in the mempool.
* Derive `Eq` and `PartialEq` for `mempool::Request`
Make it simpler to use the `MockService::expect_request` method.
* Test if crawled transactions are downloaded
Create some dummy crawled transactions, and let the crawler discover
them. Then check if they are forwarded to the mempool to be downloaded
and verified.
* Don't send empty transaction ID list to downloader
Ignore response from peers that don't provide any crawled transactions.
* Log errors when forwarding crawled transaction IDs
Calling the Mempool service should not fail, so if an error happens it
should be visible. However, errors when downloading individual
transactions can happen from time to time, so there's no need for them
to be very visible.
* Document existing `mempool::Crawler` test
Provide some depth as to what the test expect from the crawler's
behavior.
* Refactor to create `setup_crawler` helper function
Make it easier to reuse the common test setup code.
* Simplify code to expect requests
Now that `zebra_network::Request` implement `Eq`, the call can be
simplified into `expect_request`.
* Refactor to create `respond_with_transaction_ids`
A helper function that checks for a network crawl request and responds
with the given list of crawled transaction IDs.
* Refactor to create `crawler_iterator` helper
A function to intercept and respond to the fanned-out requests sent
during a single crawl iteration.
* Refactor to create `respond_to_queue_request`
Reduce the repeated code necessary to intercept and reply to a request
for queuing transactions to be downloaded.
* Add `respond_to_queue_request_with_error` helper
Intercepts a mempool request to queue transactions to be downloaded, and
responds with an error, simulating an internal problem in the mempool
service implementation.
* Derive `Arbitrary` for `NetworkUpgrade`
This is required for deriving `Arbitrary` for some error types.
* Derive `Arbitrary` for `TransactionError`
Allow random transaction errors to be generated for property tests.
* Derive `Arbitrary` for `MempoolError`
Allow random Mempool errors to be generated for property tests.
* Test if errors don't stop the mempool crawler
The crawler should be robust enough to continue operating even if the
mempool service fails to download transactions or even fails to handle
requests to enqueue transactions.
* Reduce the log level for download errors
They should happen regularly, so there's no need to have them with a
high visibility level.
Co-authored-by: teor <teor@riseup.net>
* Stop crawler if service stops
If `Mempool::poll_ready` returns an error, it's because the mempool
service has stopped and can't handle any requests, so the crawler should
stop as well.
Co-authored-by: teor <teor@riseup.net>
Co-authored-by: Conrado Gouvea <conrado@zfnd.org>
2021-10-04 17:55:42 -07:00
|
|
|
#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))]
|
2020-07-22 05:10:02 -07:00
|
|
|
pub enum NetworkUpgrade {
|
2020-07-27 00:54:55 -07:00
|
|
|
/// The Zcash protocol for a Genesis block.
|
|
|
|
///
|
|
|
|
/// Zcash genesis blocks use a different set of consensus rules from
|
|
|
|
/// other BeforeOverwinter blocks, so we treat them like a separate network
|
|
|
|
/// upgrade.
|
|
|
|
Genesis,
|
2020-07-22 05:10:02 -07:00
|
|
|
/// The Zcash protocol before the Overwinter upgrade.
|
|
|
|
///
|
|
|
|
/// We avoid using `Sprout`, because the specification says that Sprout
|
|
|
|
/// is the name of the pre-Sapling protocol, before and after Overwinter.
|
|
|
|
BeforeOverwinter,
|
|
|
|
/// The Zcash protocol after the Overwinter upgrade.
|
|
|
|
Overwinter,
|
|
|
|
/// The Zcash protocol after the Sapling upgrade.
|
|
|
|
Sapling,
|
|
|
|
/// The Zcash protocol after the Blossom upgrade.
|
|
|
|
Blossom,
|
|
|
|
/// The Zcash protocol after the Heartwood upgrade.
|
|
|
|
Heartwood,
|
|
|
|
/// The Zcash protocol after the Canopy upgrade.
|
|
|
|
Canopy,
|
2021-03-27 17:31:08 -07:00
|
|
|
/// The Zcash protocol after the Nu5 upgrade.
|
2021-03-02 12:22:11 -08:00
|
|
|
///
|
2023-09-05 16:07:26 -07:00
|
|
|
/// Note: Network Upgrade 5 includes the Orchard Shielded Protocol, non-malleable transaction
|
|
|
|
/// IDs, and other changes. There is no special code name for Nu5.
|
|
|
|
#[serde(rename = "NU5")]
|
2021-03-25 14:22:50 -07:00
|
|
|
Nu5,
|
2020-07-22 05:10:02 -07:00
|
|
|
}
|
|
|
|
|
2023-04-13 01:42:17 -07:00
|
|
|
impl fmt::Display for NetworkUpgrade {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
// Same as the debug representation for now
|
|
|
|
fmt::Debug::fmt(self, f)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-22 05:10:02 -07:00
|
|
|
/// Mainnet network upgrade activation heights.
|
|
|
|
///
|
|
|
|
/// This is actually a bijective map, but it is const, so we use a vector, and
|
|
|
|
/// do the uniqueness check in the unit tests.
|
2022-03-05 09:32:46 -08:00
|
|
|
///
|
|
|
|
/// # Correctness
|
|
|
|
///
|
|
|
|
/// Don't use this directly; use NetworkUpgrade::activation_list() so that
|
|
|
|
/// we can switch to fake activation heights for some tests.
|
|
|
|
#[allow(unused)]
|
|
|
|
pub(super) const MAINNET_ACTIVATION_HEIGHTS: &[(block::Height, NetworkUpgrade)] = &[
|
2020-08-16 11:42:02 -07:00
|
|
|
(block::Height(0), Genesis),
|
|
|
|
(block::Height(1), BeforeOverwinter),
|
|
|
|
(block::Height(347_500), Overwinter),
|
|
|
|
(block::Height(419_200), Sapling),
|
|
|
|
(block::Height(653_600), Blossom),
|
|
|
|
(block::Height(903_000), Heartwood),
|
|
|
|
(block::Height(1_046_400), Canopy),
|
2022-05-18 18:04:11 -07:00
|
|
|
(block::Height(1_687_104), Nu5),
|
2020-07-22 05:10:02 -07:00
|
|
|
];
|
|
|
|
|
2022-03-05 09:32:46 -08:00
|
|
|
/// Fake mainnet network upgrade activation heights, used in tests.
|
|
|
|
#[allow(unused)]
|
|
|
|
const FAKE_MAINNET_ACTIVATION_HEIGHTS: &[(block::Height, NetworkUpgrade)] = &[
|
2021-08-23 07:17:33 -07:00
|
|
|
(block::Height(0), Genesis),
|
|
|
|
(block::Height(5), BeforeOverwinter),
|
|
|
|
(block::Height(10), Overwinter),
|
|
|
|
(block::Height(15), Sapling),
|
|
|
|
(block::Height(20), Blossom),
|
|
|
|
(block::Height(25), Heartwood),
|
|
|
|
(block::Height(30), Canopy),
|
|
|
|
(block::Height(35), Nu5),
|
|
|
|
];
|
|
|
|
|
2020-07-22 05:10:02 -07:00
|
|
|
/// Testnet network upgrade activation heights.
|
|
|
|
///
|
|
|
|
/// This is actually a bijective map, but it is const, so we use a vector, and
|
|
|
|
/// do the uniqueness check in the unit tests.
|
2022-03-05 09:32:46 -08:00
|
|
|
///
|
|
|
|
/// # Correctness
|
|
|
|
///
|
|
|
|
/// Don't use this directly; use NetworkUpgrade::activation_list() so that
|
|
|
|
/// we can switch to fake activation heights for some tests.
|
|
|
|
#[allow(unused)]
|
|
|
|
pub(super) const TESTNET_ACTIVATION_HEIGHTS: &[(block::Height, NetworkUpgrade)] = &[
|
2020-08-16 11:42:02 -07:00
|
|
|
(block::Height(0), Genesis),
|
|
|
|
(block::Height(1), BeforeOverwinter),
|
|
|
|
(block::Height(207_500), Overwinter),
|
|
|
|
(block::Height(280_000), Sapling),
|
|
|
|
(block::Height(584_000), Blossom),
|
|
|
|
(block::Height(903_800), Heartwood),
|
|
|
|
(block::Height(1_028_500), Canopy),
|
2022-04-18 17:14:16 -07:00
|
|
|
(block::Height(1_842_420), Nu5),
|
2020-07-22 05:10:02 -07:00
|
|
|
];
|
|
|
|
|
2022-03-05 09:32:46 -08:00
|
|
|
/// Fake testnet network upgrade activation heights, used in tests.
|
|
|
|
#[allow(unused)]
|
|
|
|
const FAKE_TESTNET_ACTIVATION_HEIGHTS: &[(block::Height, NetworkUpgrade)] = &[
|
2021-08-23 07:17:33 -07:00
|
|
|
(block::Height(0), Genesis),
|
|
|
|
(block::Height(5), BeforeOverwinter),
|
|
|
|
(block::Height(10), Overwinter),
|
|
|
|
(block::Height(15), Sapling),
|
|
|
|
(block::Height(20), Blossom),
|
|
|
|
(block::Height(25), Heartwood),
|
|
|
|
(block::Height(30), Canopy),
|
|
|
|
(block::Height(35), Nu5),
|
|
|
|
];
|
|
|
|
|
2020-07-22 05:34:48 -07:00
|
|
|
/// The Consensus Branch Id, used to bind transactions and blocks to a
|
|
|
|
/// particular network upgrade.
|
2022-03-25 05:25:31 -07:00
|
|
|
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
2020-07-22 05:34:48 -07:00
|
|
|
pub struct ConsensusBranchId(u32);
|
|
|
|
|
2022-03-25 05:25:31 -07:00
|
|
|
impl ConsensusBranchId {
|
|
|
|
/// Return the hash bytes in big-endian byte-order suitable for printing out byte by byte.
|
|
|
|
///
|
|
|
|
/// Zebra displays consensus branch IDs in big-endian byte-order,
|
|
|
|
/// following the convention set by zcashd.
|
|
|
|
fn bytes_in_display_order(&self) -> [u8; 4] {
|
|
|
|
self.0.to_be_bytes()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-18 11:08:53 -07:00
|
|
|
impl From<ConsensusBranchId> for u32 {
|
|
|
|
fn from(branch: ConsensusBranchId) -> u32 {
|
|
|
|
branch.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-25 05:25:31 -07:00
|
|
|
impl ToHex for &ConsensusBranchId {
|
|
|
|
fn encode_hex<T: FromIterator<char>>(&self) -> T {
|
|
|
|
self.bytes_in_display_order().encode_hex()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn encode_hex_upper<T: FromIterator<char>>(&self) -> T {
|
|
|
|
self.bytes_in_display_order().encode_hex_upper()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ToHex for ConsensusBranchId {
|
|
|
|
fn encode_hex<T: FromIterator<char>>(&self) -> T {
|
|
|
|
self.bytes_in_display_order().encode_hex()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn encode_hex_upper<T: FromIterator<char>>(&self) -> T {
|
|
|
|
self.bytes_in_display_order().encode_hex_upper()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl FromHex for ConsensusBranchId {
|
|
|
|
type Error = <[u8; 4] as FromHex>::Error;
|
|
|
|
|
|
|
|
fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error> {
|
|
|
|
let branch = <[u8; 4]>::from_hex(hex)?;
|
|
|
|
Ok(ConsensusBranchId(u32::from_be_bytes(branch)))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for ConsensusBranchId {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
f.write_str(&self.encode_hex::<String>())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-22 05:34:48 -07:00
|
|
|
/// Network Upgrade Consensus Branch Ids.
|
|
|
|
///
|
|
|
|
/// Branch ids are the same for mainnet and testnet. If there is a testnet
|
|
|
|
/// rollback after a bug, the branch id changes.
|
|
|
|
///
|
2020-07-27 00:54:55 -07:00
|
|
|
/// Branch ids were introduced in the Overwinter upgrade, so there are no
|
|
|
|
/// Genesis or BeforeOverwinter branch ids.
|
2020-07-22 05:34:48 -07:00
|
|
|
///
|
|
|
|
/// This is actually a bijective map, but it is const, so we use a vector, and
|
|
|
|
/// do the uniqueness check in the unit tests.
|
|
|
|
pub(crate) const CONSENSUS_BRANCH_IDS: &[(NetworkUpgrade, ConsensusBranchId)] = &[
|
2020-08-18 22:14:58 -07:00
|
|
|
(Overwinter, ConsensusBranchId(0x5ba81b19)),
|
|
|
|
(Sapling, ConsensusBranchId(0x76b809bb)),
|
|
|
|
(Blossom, ConsensusBranchId(0x2bb40e60)),
|
|
|
|
(Heartwood, ConsensusBranchId(0xf5b9230b)),
|
|
|
|
(Canopy, ConsensusBranchId(0xe9ff75a6)),
|
2022-04-18 17:14:16 -07:00
|
|
|
(Nu5, ConsensusBranchId(0xc2d6d0b4)),
|
2020-07-22 05:34:48 -07:00
|
|
|
];
|
|
|
|
|
2020-11-10 06:41:24 -08:00
|
|
|
/// The target block spacing before Blossom.
|
|
|
|
const PRE_BLOSSOM_POW_TARGET_SPACING: i64 = 150;
|
|
|
|
|
|
|
|
/// The target block spacing after Blossom activation.
|
2022-12-13 13:25:04 -08:00
|
|
|
pub const POST_BLOSSOM_POW_TARGET_SPACING: u32 = 75;
|
2020-11-10 06:41:24 -08:00
|
|
|
|
2020-11-18 17:55:34 -08:00
|
|
|
/// The averaging window for difficulty threshold arithmetic mean calculations.
|
|
|
|
///
|
|
|
|
/// `PoWAveragingWindow` in the Zcash specification.
|
|
|
|
pub const POW_AVERAGING_WINDOW: usize = 17;
|
|
|
|
|
2020-11-10 06:41:24 -08:00
|
|
|
/// The multiplier used to derive the testnet minimum difficulty block time gap
|
|
|
|
/// threshold.
|
|
|
|
///
|
2022-05-30 13:12:11 -07:00
|
|
|
/// Based on <https://zips.z.cash/zip-0208#minimum-difficulty-blocks-on-the-test-network>
|
2020-11-10 06:41:24 -08:00
|
|
|
const TESTNET_MINIMUM_DIFFICULTY_GAP_MULTIPLIER: i32 = 6;
|
|
|
|
|
|
|
|
/// The start height for the testnet minimum difficulty consensus rule.
|
|
|
|
///
|
2022-05-30 13:12:11 -07:00
|
|
|
/// Based on <https://zips.z.cash/zip-0208#minimum-difficulty-blocks-on-the-test-network>
|
2020-11-10 06:41:24 -08:00
|
|
|
const TESTNET_MINIMUM_DIFFICULTY_START_HEIGHT: block::Height = block::Height(299_188);
|
|
|
|
|
2020-12-14 14:30:38 -08:00
|
|
|
/// The activation height for the block maximum time rule on Testnet.
|
|
|
|
///
|
|
|
|
/// Part of the block header consensus rules in the Zcash specification at
|
2022-05-30 13:12:11 -07:00
|
|
|
/// <https://zips.z.cash/protocol/protocol.pdf#blockheader>
|
2020-12-14 14:30:38 -08:00
|
|
|
pub const TESTNET_MAX_TIME_START_HEIGHT: block::Height = block::Height(653_606);
|
|
|
|
|
2024-03-12 14:41:44 -07:00
|
|
|
impl Network {
|
2022-03-25 05:25:31 -07:00
|
|
|
/// Returns a map between activation heights and network upgrades for `network`,
|
|
|
|
/// in ascending height order.
|
2020-07-22 05:10:02 -07:00
|
|
|
///
|
|
|
|
/// If the activation height of a future upgrade is not known, that
|
|
|
|
/// network upgrade does not appear in the list.
|
|
|
|
///
|
|
|
|
/// This is actually a bijective map.
|
2022-03-05 09:32:46 -08:00
|
|
|
///
|
|
|
|
/// 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.
|
2024-03-12 14:41:44 -07:00
|
|
|
pub fn activation_list(&self) -> BTreeMap<block::Height, NetworkUpgrade> {
|
2022-03-05 09:32:46 -08:00
|
|
|
let (mainnet_heights, testnet_heights) = {
|
|
|
|
#[cfg(not(feature = "zebra-test"))]
|
|
|
|
{
|
|
|
|
(MAINNET_ACTIVATION_HEIGHTS, TESTNET_ACTIVATION_HEIGHTS)
|
|
|
|
}
|
2022-03-07 04:44:03 -08:00
|
|
|
|
2022-03-05 09:32:46 -08:00
|
|
|
// To prevent accidentally setting this somehow, only check the env var
|
|
|
|
// when being compiled for tests. We can't use cfg(test) since the
|
|
|
|
// test that uses this is in zebra-state, and cfg(test) is not
|
|
|
|
// set for dependencies. However, zebra-state does set the
|
|
|
|
// zebra-test feature of zebra-chain if it's a dev dependency.
|
2022-03-07 04:44:03 -08:00
|
|
|
//
|
|
|
|
// Cargo features are additive, so all test binaries built along with
|
|
|
|
// zebra-state will have this feature enabled. But we are using
|
|
|
|
// Rust Edition 2021 and Cargo resolver version 2, so the "zebra-test"
|
|
|
|
// feature should only be enabled for tests:
|
|
|
|
// https://doc.rust-lang.org/cargo/reference/features.html#resolver-version-2-command-line-flags
|
2022-03-05 09:32:46 -08:00
|
|
|
#[cfg(feature = "zebra-test")]
|
|
|
|
if std::env::var_os("TEST_FAKE_ACTIVATION_HEIGHTS").is_some() {
|
|
|
|
(
|
|
|
|
FAKE_MAINNET_ACTIVATION_HEIGHTS,
|
|
|
|
FAKE_TESTNET_ACTIVATION_HEIGHTS,
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
(MAINNET_ACTIVATION_HEIGHTS, TESTNET_ACTIVATION_HEIGHTS)
|
|
|
|
}
|
|
|
|
};
|
2024-03-12 14:41:44 -07:00
|
|
|
match self {
|
2022-03-05 09:32:46 -08:00
|
|
|
Mainnet => mainnet_heights,
|
|
|
|
Testnet => testnet_heights,
|
2020-07-22 05:10:02 -07:00
|
|
|
}
|
|
|
|
.iter()
|
|
|
|
.cloned()
|
|
|
|
.collect()
|
|
|
|
}
|
2024-03-12 14:41:44 -07:00
|
|
|
}
|
|
|
|
impl NetworkUpgrade {
|
2020-07-22 05:10:02 -07:00
|
|
|
/// Returns the current network upgrade for `network` and `height`.
|
2020-08-16 11:42:02 -07:00
|
|
|
pub fn current(network: Network, height: block::Height) -> NetworkUpgrade {
|
2024-03-12 14:41:44 -07:00
|
|
|
network
|
|
|
|
.activation_list()
|
2020-07-22 05:10:02 -07:00
|
|
|
.range(..=height)
|
|
|
|
.map(|(_, nu)| *nu)
|
|
|
|
.next_back()
|
|
|
|
.expect("every height has a current network upgrade")
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the next network upgrade for `network` and `height`.
|
|
|
|
///
|
2021-04-23 06:23:43 -07:00
|
|
|
/// Returns None if the next upgrade has not been implemented in Zebra
|
|
|
|
/// yet.
|
2020-08-16 11:42:02 -07:00
|
|
|
pub fn next(network: Network, height: block::Height) -> Option<NetworkUpgrade> {
|
2024-03-12 14:41:44 -07:00
|
|
|
network
|
|
|
|
.activation_list()
|
2020-07-22 05:10:02 -07:00
|
|
|
.range((Excluded(height), Unbounded))
|
|
|
|
.map(|(_, nu)| *nu)
|
|
|
|
.next()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the activation height for this network upgrade on `network`.
|
|
|
|
///
|
|
|
|
/// Returns None if this network upgrade is a future upgrade, and its
|
|
|
|
/// activation height has not been set yet.
|
2020-08-16 11:42:02 -07:00
|
|
|
pub fn activation_height(&self, network: Network) -> Option<block::Height> {
|
2024-03-12 14:41:44 -07:00
|
|
|
network
|
|
|
|
.activation_list()
|
2020-07-22 05:10:02 -07:00
|
|
|
.iter()
|
|
|
|
.filter(|(_, nu)| nu == &self)
|
|
|
|
.map(|(height, _)| *height)
|
|
|
|
.next()
|
|
|
|
}
|
2020-07-22 05:34:48 -07:00
|
|
|
|
2021-09-01 19:25:42 -07:00
|
|
|
/// Returns `true` if `height` is the activation height of any network upgrade
|
|
|
|
/// on `network`.
|
|
|
|
///
|
2022-06-02 08:07:35 -07:00
|
|
|
/// Use [`NetworkUpgrade::activation_height`] to get the specific network
|
|
|
|
/// upgrade.
|
2021-09-01 19:25:42 -07:00
|
|
|
pub fn is_activation_height(network: Network, height: block::Height) -> bool {
|
2024-03-12 14:41:44 -07:00
|
|
|
network.activation_list().contains_key(&height)
|
2021-09-01 19:25:42 -07:00
|
|
|
}
|
|
|
|
|
2022-03-25 05:25:31 -07:00
|
|
|
/// Returns an unordered mapping between NetworkUpgrades and their ConsensusBranchIds.
|
2020-07-22 05:34:48 -07:00
|
|
|
///
|
|
|
|
/// Branch ids are the same for mainnet and testnet.
|
|
|
|
///
|
|
|
|
/// If network upgrade does not have a branch id, that network upgrade does
|
|
|
|
/// not appear in the list.
|
|
|
|
///
|
|
|
|
/// This is actually a bijective map.
|
|
|
|
pub(crate) fn branch_id_list() -> HashMap<NetworkUpgrade, ConsensusBranchId> {
|
|
|
|
CONSENSUS_BRANCH_IDS.iter().cloned().collect()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the consensus branch id for this network upgrade.
|
|
|
|
///
|
|
|
|
/// Returns None if this network upgrade has no consensus branch id.
|
|
|
|
pub fn branch_id(&self) -> Option<ConsensusBranchId> {
|
2021-06-06 20:26:34 -07:00
|
|
|
NetworkUpgrade::branch_id_list().get(self).cloned()
|
2020-07-22 05:34:48 -07:00
|
|
|
}
|
2020-11-10 06:41:24 -08:00
|
|
|
|
|
|
|
/// Returns the target block spacing for the network upgrade.
|
|
|
|
///
|
2022-06-02 08:07:35 -07:00
|
|
|
/// Based on [`PRE_BLOSSOM_POW_TARGET_SPACING`] and
|
|
|
|
/// [`POST_BLOSSOM_POW_TARGET_SPACING`] from the Zcash specification.
|
2020-11-10 06:41:24 -08:00
|
|
|
pub fn target_spacing(&self) -> Duration {
|
|
|
|
let spacing_seconds = match self {
|
|
|
|
Genesis | BeforeOverwinter | Overwinter | Sapling => PRE_BLOSSOM_POW_TARGET_SPACING,
|
2022-12-13 13:25:04 -08:00
|
|
|
Blossom | Heartwood | Canopy | Nu5 => POST_BLOSSOM_POW_TARGET_SPACING.into(),
|
2020-11-10 06:41:24 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
Duration::seconds(spacing_seconds)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the target block spacing for `network` and `height`.
|
|
|
|
///
|
2022-06-02 08:07:35 -07:00
|
|
|
/// See [`NetworkUpgrade::target_spacing`] for details.
|
2020-11-10 06:41:24 -08:00
|
|
|
pub fn target_spacing_for_height(network: Network, height: block::Height) -> Duration {
|
|
|
|
NetworkUpgrade::current(network, height).target_spacing()
|
|
|
|
}
|
|
|
|
|
2022-02-10 17:27:02 -08:00
|
|
|
/// Returns all the target block spacings for `network` and the heights where they start.
|
|
|
|
pub fn target_spacings(network: Network) -> impl Iterator<Item = (block::Height, Duration)> {
|
|
|
|
[
|
|
|
|
(NetworkUpgrade::Genesis, PRE_BLOSSOM_POW_TARGET_SPACING),
|
2022-12-13 13:25:04 -08:00
|
|
|
(
|
|
|
|
NetworkUpgrade::Blossom,
|
|
|
|
POST_BLOSSOM_POW_TARGET_SPACING.into(),
|
|
|
|
),
|
2022-02-10 17:27:02 -08:00
|
|
|
]
|
|
|
|
.into_iter()
|
|
|
|
.map(move |(upgrade, spacing_seconds)| {
|
|
|
|
let activation_height = upgrade
|
|
|
|
.activation_height(network)
|
|
|
|
.expect("missing activation height for target spacing change");
|
|
|
|
|
|
|
|
let target_spacing = Duration::seconds(spacing_seconds);
|
|
|
|
|
|
|
|
(activation_height, target_spacing)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-11-10 06:41:24 -08:00
|
|
|
/// Returns the minimum difficulty block spacing for `network` and `height`.
|
|
|
|
/// Returns `None` if the testnet minimum difficulty consensus rule is not active.
|
|
|
|
///
|
2022-05-30 13:12:11 -07:00
|
|
|
/// Based on <https://zips.z.cash/zip-0208#minimum-difficulty-blocks-on-the-test-network>
|
2020-11-10 06:41:24 -08:00
|
|
|
pub fn minimum_difficulty_spacing_for_height(
|
|
|
|
network: Network,
|
|
|
|
height: block::Height,
|
|
|
|
) -> Option<Duration> {
|
|
|
|
match (network, height) {
|
|
|
|
(Network::Testnet, height) if height < TESTNET_MINIMUM_DIFFICULTY_START_HEIGHT => None,
|
|
|
|
(Network::Mainnet, _) => None,
|
|
|
|
(Network::Testnet, _) => {
|
|
|
|
let network_upgrade = NetworkUpgrade::current(network, height);
|
|
|
|
Some(network_upgrade.target_spacing() * TESTNET_MINIMUM_DIFFICULTY_GAP_MULTIPLIER)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-11-18 17:55:34 -08:00
|
|
|
|
2020-11-19 00:00:56 -08:00
|
|
|
/// Returns true if the gap between `block_time` and `previous_block_time` is
|
|
|
|
/// greater than the Testnet minimum difficulty time gap. This time gap
|
|
|
|
/// depends on the `network` and `block_height`.
|
|
|
|
///
|
|
|
|
/// Returns false on Mainnet, when `block_height` is less than the minimum
|
|
|
|
/// difficulty start height, and when the time gap is too small.
|
|
|
|
///
|
|
|
|
/// `block_time` can be less than, equal to, or greater than
|
|
|
|
/// `previous_block_time`, because block times are provided by miners.
|
|
|
|
///
|
|
|
|
/// Implements the Testnet minimum difficulty adjustment from ZIPs 205 and 208.
|
|
|
|
///
|
|
|
|
/// Spec Note: Some parts of ZIPs 205 and 208 previously specified an incorrect
|
|
|
|
/// check for the time gap. This function implements the correct "greater than"
|
|
|
|
/// check.
|
|
|
|
pub fn is_testnet_min_difficulty_block(
|
|
|
|
network: Network,
|
|
|
|
block_height: block::Height,
|
|
|
|
block_time: DateTime<Utc>,
|
|
|
|
previous_block_time: DateTime<Utc>,
|
|
|
|
) -> bool {
|
|
|
|
let block_time_gap = block_time - previous_block_time;
|
|
|
|
if let Some(min_difficulty_gap) =
|
|
|
|
NetworkUpgrade::minimum_difficulty_spacing_for_height(network, block_height)
|
|
|
|
{
|
|
|
|
block_time_gap > min_difficulty_gap
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-18 17:55:34 -08:00
|
|
|
/// Returns the averaging window timespan for the network upgrade.
|
|
|
|
///
|
|
|
|
/// `AveragingWindowTimespan` from the Zcash specification.
|
|
|
|
pub fn averaging_window_timespan(&self) -> Duration {
|
2022-01-27 06:34:15 -08:00
|
|
|
self.target_spacing() * POW_AVERAGING_WINDOW.try_into().expect("fits in i32")
|
2020-11-18 17:55:34 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the averaging window timespan for `network` and `height`.
|
|
|
|
///
|
2022-06-02 08:07:35 -07:00
|
|
|
/// See [`NetworkUpgrade::averaging_window_timespan`] for details.
|
2020-11-18 17:55:34 -08:00
|
|
|
pub fn averaging_window_timespan_for_height(
|
|
|
|
network: Network,
|
|
|
|
height: block::Height,
|
|
|
|
) -> Duration {
|
|
|
|
NetworkUpgrade::current(network, height).averaging_window_timespan()
|
|
|
|
}
|
2020-12-14 14:30:38 -08:00
|
|
|
|
2021-04-28 18:55:29 -07:00
|
|
|
/// Returns the NetworkUpgrade given an u32 as ConsensusBranchId
|
|
|
|
pub fn from_branch_id(branch_id: u32) -> Option<NetworkUpgrade> {
|
|
|
|
CONSENSUS_BRANCH_IDS
|
|
|
|
.iter()
|
|
|
|
.find(|id| id.1 == ConsensusBranchId(branch_id))
|
|
|
|
.map(|nu| nu.0)
|
|
|
|
}
|
2020-07-22 05:34:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ConsensusBranchId {
|
2022-03-25 05:25:31 -07:00
|
|
|
/// The value used by `zcashd` RPCs for missing consensus branch IDs.
|
|
|
|
///
|
|
|
|
/// # Consensus
|
|
|
|
///
|
|
|
|
/// This value must only be used in RPCs.
|
|
|
|
///
|
|
|
|
/// The consensus rules handle missing branch IDs by rejecting blocks and transactions,
|
|
|
|
/// so this substitute value must not be used in consensus-critical code.
|
|
|
|
pub const RPC_MISSING_ID: ConsensusBranchId = ConsensusBranchId(0);
|
|
|
|
|
2020-07-22 05:34:48 -07:00
|
|
|
/// Returns the current consensus branch id for `network` and `height`.
|
|
|
|
///
|
|
|
|
/// Returns None if the network has no branch id at this height.
|
2020-08-16 11:42:02 -07:00
|
|
|
pub fn current(network: Network, height: block::Height) -> Option<ConsensusBranchId> {
|
2020-07-22 05:34:48 -07:00
|
|
|
NetworkUpgrade::current(network, height).branch_id()
|
|
|
|
}
|
2020-07-22 05:10:02 -07:00
|
|
|
}
|