Support a minimum protocol version during initial block download (#2395)
* Support a min protocol version during initial block download But don't actually use the state height yet. Also rename some functions and constants. Co-authored-by: Janito Vaqueiro Ferreira Filho <janito.vff@gmail.com>
This commit is contained in:
parent
c06cd19239
commit
7586699f86
|
@ -100,19 +100,25 @@ pub const USER_AGENT: &str = "/Zebra:1.0.0-alpha.11/";
|
||||||
/// during connection setup.
|
/// during connection setup.
|
||||||
///
|
///
|
||||||
/// The current protocol version is checked by our peers. If it is too old,
|
/// The current protocol version is checked by our peers. If it is too old,
|
||||||
/// newer peers will refuse to connect to us.
|
/// newer peers will disconnect from us.
|
||||||
///
|
///
|
||||||
/// The current protocol version typically changes before Mainnet and Testnet
|
/// The current protocol version typically changes before Mainnet and Testnet
|
||||||
/// network upgrades.
|
/// network upgrades.
|
||||||
pub const CURRENT_VERSION: Version = Version(170_013);
|
pub const CURRENT_NETWORK_PROTOCOL_VERSION: Version = Version(170_013);
|
||||||
|
|
||||||
/// The most recent bilateral consensus upgrade implemented by this crate.
|
/// The minimum network protocol version accepted by this crate for each network,
|
||||||
|
/// represented as a network upgrade.
|
||||||
///
|
///
|
||||||
/// The minimum network upgrade is used to check the protocol versions of our
|
/// The minimum protocol version is used to check the protocol versions of our
|
||||||
/// peers. If their versions are too old, we will disconnect from them.
|
/// peers during the initial block download. After the intial block download,
|
||||||
//
|
/// we use the current block height to select the minimum network protocol
|
||||||
// TODO: replace with NetworkUpgrade::current(network, height). (#1334)
|
/// version.
|
||||||
pub const MIN_NETWORK_UPGRADE: NetworkUpgrade = NetworkUpgrade::Canopy;
|
///
|
||||||
|
/// If peer versions are too old, we will disconnect from them.
|
||||||
|
///
|
||||||
|
/// The minimum network protocol version typically changes after Mainnet network
|
||||||
|
/// upgrades.
|
||||||
|
pub const INITIAL_MIN_NETWORK_PROTOCOL_VERSION: NetworkUpgrade = NetworkUpgrade::Canopy;
|
||||||
|
|
||||||
/// The default RTT estimate for peer responses.
|
/// The default RTT estimate for peer responses.
|
||||||
///
|
///
|
||||||
|
|
|
@ -487,7 +487,7 @@ pub async fn negotiate_version(
|
||||||
};
|
};
|
||||||
|
|
||||||
let our_version = Message::Version {
|
let our_version = Message::Version {
|
||||||
version: constants::CURRENT_VERSION,
|
version: constants::CURRENT_NETWORK_PROTOCOL_VERSION,
|
||||||
services: our_services,
|
services: our_services,
|
||||||
timestamp,
|
timestamp,
|
||||||
address_recv: (PeerServices::NODE_NETWORK, their_addr),
|
address_recv: (PeerServices::NODE_NETWORK, their_addr),
|
||||||
|
@ -552,29 +552,17 @@ pub async fn negotiate_version(
|
||||||
Err(HandshakeError::NonceReuse)?;
|
Err(HandshakeError::NonceReuse)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXX in zcashd remote peer can only send one version message and
|
// TODO: Reject connections with nodes that don't know about the current network upgrade (#1334)
|
||||||
// we would disconnect here if it received a second one. Is it even possible
|
// Use the latest non-finalized block height, rather than the minimum
|
||||||
// for that to happen to us here?
|
if remote_version
|
||||||
|
< Version::min_remote_for_height(
|
||||||
// TODO: Reject incoming connections from nodes that don't know about the current epoch.
|
config.network,
|
||||||
// zcashd does this:
|
// This code will be replaced in #1334
|
||||||
// const Consensus::Params& consensusParams = chainparams.GetConsensus();
|
constants::INITIAL_MIN_NETWORK_PROTOCOL_VERSION
|
||||||
// auto currentEpoch = CurrentEpoch(GetHeight(), consensusParams);
|
.activation_height(config.network)
|
||||||
// if (pfrom->nVersion < consensusParams.vUpgrades[currentEpoch].nProtocolVersion)
|
.expect("minimum network protocol network upgrade has an activation height"),
|
||||||
//
|
)
|
||||||
// For approximately 1.5 days before a network upgrade, zcashd also:
|
{
|
||||||
// - avoids old peers, and
|
|
||||||
// - prefers updated peers.
|
|
||||||
// We haven't decided if we need this behaviour in Zebra yet (see #706).
|
|
||||||
//
|
|
||||||
// At the network upgrade, we also need to disconnect from old peers (see #1334).
|
|
||||||
//
|
|
||||||
// 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_for_upgrade(config.network, constants::MIN_NETWORK_UPGRADE) {
|
|
||||||
// Disconnect if peer is using an obsolete version.
|
// Disconnect if peer is using an obsolete version.
|
||||||
Err(HandshakeError::ObsoleteVersion(remote_version))?;
|
Err(HandshakeError::ObsoleteVersion(remote_version))?;
|
||||||
}
|
}
|
||||||
|
@ -680,7 +668,8 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the connection's version to the minimum of the received version or our own.
|
// Set the connection's version to the minimum of the received version or our own.
|
||||||
let negotiated_version = std::cmp::min(remote_version, constants::CURRENT_VERSION);
|
let negotiated_version =
|
||||||
|
std::cmp::min(remote_version, constants::CURRENT_NETWORK_PROTOCOL_VERSION);
|
||||||
|
|
||||||
// Reconfigure the codec to use the negotiated version.
|
// Reconfigure the codec to use the negotiated version.
|
||||||
//
|
//
|
||||||
|
|
|
@ -54,7 +54,7 @@ impl Codec {
|
||||||
pub fn builder() -> Builder {
|
pub fn builder() -> Builder {
|
||||||
Builder {
|
Builder {
|
||||||
network: Network::Mainnet,
|
network: Network::Mainnet,
|
||||||
version: constants::CURRENT_VERSION,
|
version: constants::CURRENT_NETWORK_PROTOCOL_VERSION,
|
||||||
max_len: MAX_PROTOCOL_MESSAGE_LEN,
|
max_len: MAX_PROTOCOL_MESSAGE_LEN,
|
||||||
metrics_addr_label: None,
|
metrics_addr_label: None,
|
||||||
}
|
}
|
||||||
|
@ -650,7 +650,7 @@ mod tests {
|
||||||
let services = PeerServices::NODE_NETWORK;
|
let services = PeerServices::NODE_NETWORK;
|
||||||
let timestamp = Utc.timestamp(1_568_000_000, 0);
|
let timestamp = Utc.timestamp(1_568_000_000, 0);
|
||||||
Message::Version {
|
Message::Version {
|
||||||
version: crate::constants::CURRENT_VERSION,
|
version: crate::constants::CURRENT_NETWORK_PROTOCOL_VERSION,
|
||||||
services,
|
services,
|
||||||
timestamp,
|
timestamp,
|
||||||
address_recv: (
|
address_recv: (
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
#![allow(clippy::unit_arg)]
|
#![allow(clippy::unit_arg)]
|
||||||
|
|
||||||
use crate::constants::magics;
|
use crate::constants::{self, magics};
|
||||||
|
|
||||||
use std::fmt;
|
use std::{cmp::max, fmt};
|
||||||
|
|
||||||
use zebra_chain::{
|
use zebra_chain::{
|
||||||
block,
|
block,
|
||||||
|
@ -42,9 +42,49 @@ impl From<Network> for Magic {
|
||||||
pub struct Version(pub u32);
|
pub struct Version(pub u32);
|
||||||
|
|
||||||
impl Version {
|
impl Version {
|
||||||
/// Returns the minimum network protocol version for `network` and
|
/// Returns the minimum remote node network protocol version for `network` and
|
||||||
|
/// `height`. Zebra disconnects from peers with lower versions.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// If we are incompatible with our own minimum remote protocol version.
|
||||||
|
pub fn min_remote_for_height(network: Network, height: block::Height) -> Version {
|
||||||
|
let min_spec = Version::min_specified_for_height(network, height);
|
||||||
|
|
||||||
|
// shut down if our own version is too old
|
||||||
|
assert!(
|
||||||
|
constants::CURRENT_NETWORK_PROTOCOL_VERSION >= min_spec,
|
||||||
|
"Zebra does not implement the minimum specified {:?} protocol version for {:?} at {:?}",
|
||||||
|
NetworkUpgrade::current(network, height),
|
||||||
|
network,
|
||||||
|
height,
|
||||||
|
);
|
||||||
|
|
||||||
|
max(min_spec, Version::initial_min_for_network(network))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the minimum supported network protocol version for `network`.
|
||||||
|
///
|
||||||
|
/// This is the minimum peer version when Zebra is significantly behind current tip:
|
||||||
|
/// - during the initial block download,
|
||||||
|
/// - after Zebra restarts, and
|
||||||
|
/// - after Zebra's local network is slow or shut down.
|
||||||
|
fn initial_min_for_network(network: Network) -> Version {
|
||||||
|
Version::min_specified_for_upgrade(network, constants::INITIAL_MIN_NETWORK_PROTOCOL_VERSION)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the minimum specified network protocol version for `network` and
|
||||||
|
/// `height`.
|
||||||
|
///
|
||||||
|
/// This is the minimum peer version when Zebra is close to the current tip.
|
||||||
|
fn min_specified_for_height(network: Network, height: block::Height) -> Version {
|
||||||
|
let network_upgrade = NetworkUpgrade::current(network, height);
|
||||||
|
Version::min_specified_for_upgrade(network, network_upgrade)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the minimum specified network protocol version for `network` and
|
||||||
/// `network_upgrade`.
|
/// `network_upgrade`.
|
||||||
pub fn min_for_upgrade(network: Network, network_upgrade: NetworkUpgrade) -> Self {
|
fn min_specified_for_upgrade(network: Network, network_upgrade: NetworkUpgrade) -> Version {
|
||||||
// TODO: Should we reject earlier protocol versions during our initial
|
// TODO: Should we reject earlier protocol versions during our initial
|
||||||
// sync? zcashd accepts 170_002 or later during its initial sync.
|
// sync? zcashd accepts 170_002 or later during its initial sync.
|
||||||
Version(match (network, network_upgrade) {
|
Version(match (network, network_upgrade) {
|
||||||
|
@ -62,15 +102,6 @@ impl Version {
|
||||||
(Mainnet, Nu5) => 170_015,
|
(Mainnet, Nu5) => 170_015,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the current minimum protocol version for `network` and `height`.
|
|
||||||
///
|
|
||||||
/// Returns None if the network has no branch id at this height.
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn current_min(network: Network, height: block::Height) -> Version {
|
|
||||||
let network_upgrade = NetworkUpgrade::current(network, height);
|
|
||||||
Version::min_for_upgrade(network, network_upgrade)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
|
@ -159,21 +190,21 @@ mod test {
|
||||||
version_extremes(Testnet)
|
version_extremes(Testnet)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Test the min_for_upgrade and current_min functions for `network` with
|
/// Test the min_specified_for_upgrade and min_specified_for_height functions for `network` with
|
||||||
/// extreme values.
|
/// extreme values.
|
||||||
fn version_extremes(network: Network) {
|
fn version_extremes(network: Network) {
|
||||||
zebra_test::init();
|
zebra_test::init();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Version::current_min(network, block::Height(0)),
|
Version::min_specified_for_height(network, block::Height(0)),
|
||||||
Version::min_for_upgrade(network, BeforeOverwinter),
|
Version::min_specified_for_upgrade(network, BeforeOverwinter),
|
||||||
);
|
);
|
||||||
|
|
||||||
// We assume that the last version we know about continues forever
|
// We assume that the last version we know about continues forever
|
||||||
// (even if we suspect that won't be true)
|
// (even if we suspect that won't be true)
|
||||||
assert_ne!(
|
assert_ne!(
|
||||||
Version::current_min(network, block::Height::MAX),
|
Version::min_specified_for_height(network, block::Height::MAX),
|
||||||
Version::min_for_upgrade(network, BeforeOverwinter),
|
Version::min_specified_for_upgrade(network, BeforeOverwinter),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,7 +218,7 @@ mod test {
|
||||||
version_consistent(Testnet)
|
version_consistent(Testnet)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check that the min_for_upgrade and current_min functions
|
/// Check that the min_specified_for_upgrade and min_specified_for_height functions
|
||||||
/// are consistent for `network`.
|
/// are consistent for `network`.
|
||||||
fn version_consistent(network: Network) {
|
fn version_consistent(network: Network) {
|
||||||
zebra_test::init();
|
zebra_test::init();
|
||||||
|
@ -208,8 +239,8 @@ mod test {
|
||||||
let height = network_upgrade.activation_height(network);
|
let height = network_upgrade.activation_height(network);
|
||||||
if let Some(height) = height {
|
if let Some(height) = height {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Version::min_for_upgrade(network, network_upgrade),
|
Version::min_specified_for_upgrade(network, network_upgrade),
|
||||||
Version::current_min(network, height)
|
Version::min_specified_for_height(network, height)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue