feature: Get the current minimum protocol version

This commit is contained in:
teor 2020-07-23 12:53:12 +10:00
parent 0e0c36c010
commit da09965a5f
2 changed files with 80 additions and 5 deletions

View File

@ -199,12 +199,12 @@ where
// For example, we could reject old peers with probability 0.5.
//
// At the network upgrade, we also need to disconnect from old peers.
// TODO: replace MIN_NETWORK_UPGRADE with
// NetworkUpgrade::current(network, height) where network is
// the configured network, and height is the best tip's block
// TODO: replace min_for_upgrade(network, MIN_NETWORK_UPGRADE) with
// current_min(network, height) where network is the
// configured network, and height is the best tip's block
// height.
if remote_version < Version::min_version(network, constants::MIN_NETWORK_UPGRADE) {
if remote_version < Version::min_for_upgrade(network, constants::MIN_NETWORK_UPGRADE) {
// Disconnect if peer is using an obsolete version.
return Err(HandshakeError::ObsoleteVersion(remote_version));
}

View File

@ -4,6 +4,7 @@ use crate::constants::magics;
use std::fmt;
use zebra_chain::types::BlockHeight;
use zebra_chain::Network::{self, *};
use zebra_consensus::parameters::NetworkUpgrade::{self, *};
@ -38,7 +39,7 @@ pub struct Version(pub u32);
impl Version {
/// Returns the minimum network protocol version for `network` and
/// `network_upgrade`.
pub fn min_version(network: Network, network_upgrade: NetworkUpgrade) -> Self {
pub fn min_for_upgrade(network: Network, network_upgrade: NetworkUpgrade) -> Self {
// TODO: Should we reject earlier protocol versions during our initial
// sync? zcashd accepts 170_002 or later during its initial sync.
Version(match (network, network_upgrade) {
@ -54,6 +55,14 @@ impl Version {
(Mainnet, Canopy) => 170_013,
})
}
/// Returns the current minimum protocol version for `network` and `height`.
///
/// Returns None if the network has no branch id at this height.
pub fn current_min(network: Network, height: BlockHeight) -> Version {
let network_upgrade = NetworkUpgrade::current(network, height);
Version::min_for_upgrade(network, network_upgrade)
}
}
bitflags! {
@ -120,3 +129,69 @@ mod proptest {
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn version_extremes_mainnet() {
version_extremes(Mainnet)
}
#[test]
fn version_extremes_testnet() {
version_extremes(Testnet)
}
/// Test the min_for_upgrade and current_min functions for `network` with
/// extreme values.
fn version_extremes(network: Network) {
assert_eq!(
Version::current_min(network, BlockHeight(0)),
Version::min_for_upgrade(network, BeforeOverwinter),
);
// We assume that the last version we know about continues forever
// (even if we suspect that won't be true)
assert_ne!(
Version::current_min(network, BlockHeight::MAX),
Version::min_for_upgrade(network, BeforeOverwinter),
);
}
#[test]
fn version_consistent_mainnet() {
version_consistent(Mainnet)
}
#[test]
fn version_consistent_testnet() {
version_consistent(Testnet)
}
/// Check that the min_for_upgrade and current_min functions
/// are consistent for `network`.
fn version_consistent(network: Network) {
let highest_network_upgrade = NetworkUpgrade::current(network, BlockHeight::MAX);
assert!(highest_network_upgrade == Canopy || highest_network_upgrade == Heartwood,
"expected coverage of all network upgrades: add the new network upgrade to the list in this test");
for &network_upgrade in &[
BeforeOverwinter,
Overwinter,
Sapling,
Blossom,
Heartwood,
Canopy,
] {
let height = network_upgrade.activation_height(network);
if let Some(height) = height {
assert_eq!(
Version::min_for_upgrade(network, network_upgrade),
Version::current_min(network, height)
);
}
}
}
}