From da09965a5f65c4f1c462188776585269c6c05c3a Mon Sep 17 00:00:00 2001 From: teor Date: Thu, 23 Jul 2020 12:53:12 +1000 Subject: [PATCH] feature: Get the current minimum protocol version --- zebra-network/src/peer/handshake.rs | 8 +- zebra-network/src/protocol/external/types.rs | 77 +++++++++++++++++++- 2 files changed, 80 insertions(+), 5 deletions(-) diff --git a/zebra-network/src/peer/handshake.rs b/zebra-network/src/peer/handshake.rs index 34e30f4db..07e5ebb97 100644 --- a/zebra-network/src/peer/handshake.rs +++ b/zebra-network/src/peer/handshake.rs @@ -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)); } diff --git a/zebra-network/src/protocol/external/types.rs b/zebra-network/src/protocol/external/types.rs index 8fd338158..2cbd28d6f 100644 --- a/zebra-network/src/protocol/external/types.rs +++ b/zebra-network/src/protocol/external/types.rs @@ -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) + ); + } + } + } +}