Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

merge queue: embarking main (e0da45b) and #8524 together #8555

Closed
wants to merge 13 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion zebra-chain/src/parameters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ mod transaction;
pub mod arbitrary;

pub use genesis::*;
pub use network::{testnet, Network, NetworkKind};
pub use network::{magic::Magic, testnet, Network, NetworkKind};
pub use network_upgrade::*;
pub use transaction::*;

Expand Down
12 changes: 12 additions & 0 deletions zebra-chain/src/parameters/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,15 @@ pub const SLOW_START_INTERVAL: Height = Height(20_000);
///
/// This calculation is exact, because `SLOW_START_INTERVAL` is divisible by 2.
pub const SLOW_START_SHIFT: Height = Height(SLOW_START_INTERVAL.0 / 2);

/// Magic numbers used to identify different Zcash networks.
pub mod magics {
use crate::parameters::network::magic::Magic;

/// The production mainnet.
pub const MAINNET: Magic = Magic([0x24, 0xe9, 0x27, 0x64]);
/// The testnet.
pub const TESTNET: Magic = Magic([0xfa, 0x1a, 0xf9, 0xbf]);
/// The regtest, see <https://github.com/zcash/zcash/blob/master/src/chainparams.cpp#L716-L719>
pub const REGTEST: Magic = Magic([0xaa, 0xe8, 0x3f, 0x5f]);
}
3 changes: 2 additions & 1 deletion zebra-chain/src/parameters/network.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use crate::{
parameters::NetworkUpgrade,
};

pub mod magic;
pub mod testnet;

#[cfg(test)]
Expand Down Expand Up @@ -75,7 +76,7 @@ impl From<Network> for NetworkKind {
}

/// An enum describing the possible network choices.
#[derive(Clone, Debug, Default, Eq, PartialEq, Hash, Serialize)]
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize)]
#[serde(into = "NetworkKind")]
pub enum Network {
/// The production mainnet.
Expand Down
56 changes: 56 additions & 0 deletions zebra-chain/src/parameters/network/magic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//! Network `Magic` type and implementation.

use std::fmt;

use crate::parameters::{constants::magics, Network};

#[cfg(any(test, feature = "proptest-impl"))]
use proptest_derive::Arbitrary;

/// A magic number identifying the network.
#[derive(Copy, Clone, Eq, PartialEq)]
#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))]
pub struct Magic(pub [u8; 4]);

impl fmt::Debug for Magic {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("Magic").field(&hex::encode(self.0)).finish()
}
}

impl Network {
/// Get the magic value associated to this `Network`.
pub fn magic(&self) -> Magic {
match self {
Network::Mainnet => magics::MAINNET,
Network::Testnet(params) => params.network_magic(),
}
}
}

#[cfg(test)]
mod proptest {

use proptest::prelude::*;

use super::{magics, Magic};

#[test]
fn magic_debug() {
let _init_guard = zebra_test::init();

assert_eq!(format!("{:?}", magics::MAINNET), "Magic(\"24e92764\")");
assert_eq!(format!("{:?}", magics::TESTNET), "Magic(\"fa1af9bf\")");
assert_eq!(format!("{:?}", magics::REGTEST), "Magic(\"aae83f5f\")");
}

proptest! {

#[test]
fn proptest_magic_from_array(data in any::<[u8; 4]>()) {
let _init_guard = zebra_test::init();

assert_eq!(format!("{:?}", Magic(data)), format!("Magic({:x?})", hex::encode(data)));
}
}
}
37 changes: 34 additions & 3 deletions zebra-chain/src/parameters/network/testnet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ use zcash_primitives::constants as zp_constants;
use crate::{
block::{self, Height},
parameters::{
constants::{SLOW_START_INTERVAL, SLOW_START_SHIFT},
constants::{magics, SLOW_START_INTERVAL, SLOW_START_SHIFT},
network_upgrade::TESTNET_ACTIVATION_HEIGHTS,
Network, NetworkUpgrade, NETWORK_UPGRADES_IN_ORDER,
},
work::difficulty::{ExpandedDifficulty, U256},
};

use super::magic::Magic;

/// The Regtest NU5 activation height in tests
// TODO: Serialize testnet parameters in Config then remove this and use a configured NU5 activation height.
#[cfg(any(test, feature = "proptest-impl"))]
Expand Down Expand Up @@ -64,10 +66,12 @@ pub struct ConfiguredActivationHeights {
}

/// Builder for the [`Parameters`] struct.
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ParametersBuilder {
/// The name of this network to be used by the `Display` trait impl.
network_name: String,
/// The network magic, acts as an identifier for the network.
network_magic: Magic,
/// The genesis block hash
genesis_hash: block::Hash,
/// The network upgrade activation heights for this network, see [`Parameters::activation_heights`] for more details.
Expand All @@ -91,6 +95,7 @@ impl Default for ParametersBuilder {
fn default() -> Self {
Self {
network_name: "UnknownTestnet".to_string(),
network_magic: magics::TESTNET,
// # Correctness
//
// `Genesis` network upgrade activation height must always be 0
Expand Down Expand Up @@ -148,6 +153,20 @@ impl ParametersBuilder {
self
}

/// Sets the network name to be used in the [`Parameters`] being built.
pub fn with_network_magic(mut self, network_magic: Magic) -> Self {
assert!(
[magics::MAINNET, magics::REGTEST]
.into_iter()
.all(|reserved_magic| network_magic != reserved_magic),
"network magic should be distinct from reserved network magics"
);

self.network_magic = network_magic;

self
}

/// Checks that the provided Sapling human-readable prefixes (HRPs) are valid and unique, then
/// sets the Sapling HRPs to be used in the [`Parameters`] being built.
pub fn with_sapling_hrps(
Expand Down Expand Up @@ -283,6 +302,7 @@ impl ParametersBuilder {
pub fn finish(self) -> Parameters {
let Self {
network_name,
network_magic,
genesis_hash,
activation_heights,
hrp_sapling_extended_spending_key,
Expand All @@ -294,6 +314,7 @@ impl ParametersBuilder {
} = self;
Parameters {
network_name,
network_magic,
genesis_hash,
activation_heights,
hrp_sapling_extended_spending_key,
Expand All @@ -313,10 +334,12 @@ impl ParametersBuilder {
}

/// Network consensus parameters for test networks such as Regtest and the default Testnet.
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Parameters {
/// The name of this network to be used by the `Display` trait impl.
network_name: String,
/// The network magic, acts as an identifier for the network.
network_magic: Magic,
/// The genesis block hash
genesis_hash: block::Hash,
/// The network upgrade activation heights for this network.
Expand Down Expand Up @@ -366,6 +389,7 @@ impl Parameters {

Self {
network_name: "Regtest".to_string(),
network_magic: magics::REGTEST,
..Self::build()
.with_genesis_hash(REGTEST_GENESIS_HASH)
// This value is chosen to match zcashd, see: <https://github.com/zcash/zcash/blob/master/src/chainparams.cpp#L654>
Expand Down Expand Up @@ -397,6 +421,7 @@ impl Parameters {
pub fn is_regtest(&self) -> bool {
let Self {
network_name,
network_magic,
genesis_hash,
// Activation heights are configurable on Regtest
activation_heights: _,
Expand All @@ -410,6 +435,7 @@ impl Parameters {
} = Self::new_regtest(None);

self.network_name == network_name
&& self.network_magic == network_magic
&& self.genesis_hash == genesis_hash
&& self.hrp_sapling_extended_spending_key == hrp_sapling_extended_spending_key
&& self.hrp_sapling_extended_full_viewing_key == hrp_sapling_extended_full_viewing_key
Expand All @@ -425,6 +451,11 @@ impl Parameters {
&self.network_name
}

/// Returns the network magic
pub fn network_magic(&self) -> Magic {
self.network_magic
}

/// Returns the genesis hash
pub fn genesis_hash(&self) -> block::Hash {
self.genesis_hash
Expand Down
29 changes: 19 additions & 10 deletions zebra-network/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use tracing::Span;

use zebra_chain::parameters::{
testnet::{self, ConfiguredActivationHeights},
Network, NetworkKind,
Magic, Network, NetworkKind,
};

use crate::{
Expand Down Expand Up @@ -636,6 +636,7 @@ impl<'de> Deserialize<'de> for Config {
{
#[derive(Deserialize)]
struct DTestnetParameters {
network_magic: Option<[u8; 4]>,
network_name: Option<String>,
activation_heights: Option<ConfiguredActivationHeights>,
}
Expand Down Expand Up @@ -718,26 +719,34 @@ impl<'de> Deserialize<'de> for Config {
NetworkKind::Testnet,
Some(DTestnetParameters {
network_name,
network_magic,
activation_heights,
}),
) => {
let mut params_builder = testnet::Parameters::build();
let should_avoid_default_peers =
network_magic.is_some() || activation_heights.is_some();

// Return an error if the initial testnet peers includes any of the default initial Mainnet or Testnet
// peers while activation heights or a custom network magic is configured.
if should_avoid_default_peers
&& contains_default_initial_peers(&initial_testnet_peers)
{
return Err(de::Error::custom(
"cannot use default initials peers with incompatible testnet",
));
}

if let Some(network_name) = network_name {
params_builder = params_builder.with_network_name(network_name)
}

if let Some(network_magic) = network_magic {
params_builder = params_builder.with_network_magic(Magic(network_magic));
}

// Retain default Testnet activation heights unless there's an empty [testnet_parameters.activation_heights] section.
if let Some(activation_heights) = activation_heights {
// Return an error if the initial testnet peers includes any of the default initial Mainnet or Testnet
// peers while activation heights are configured.
// TODO: Check that the network magic is different from the default Mainnet/Testnet network magic too?
if contains_default_initial_peers(&initial_testnet_peers) {
return Err(de::Error::custom(
"cannot use default initial testnet peers with configured activation heights",
));
}

params_builder = params_builder.with_activation_heights(activation_heights)
}

Expand Down
9 changes: 0 additions & 9 deletions zebra-network/src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -422,15 +422,6 @@ lazy_static! {
/// [6.1.3.3 Efficient Resource Usage] <https://tools.ietf.org/rfcmarkup?doc=1123#page-77>
pub const DNS_LOOKUP_TIMEOUT: Duration = Duration::from_secs(5);

/// Magic numbers used to identify different Zcash networks.
pub mod magics {
use super::*;
/// The production mainnet.
pub const MAINNET: Magic = Magic([0x24, 0xe9, 0x27, 0x64]);
/// The testnet.
pub const TESTNET: Magic = Magic([0xfa, 0x1a, 0xf9, 0xbf]);
}

#[cfg(test)]
mod tests {
use zebra_chain::parameters::POST_BLOSSOM_POW_TARGET_SPACING;
Expand Down
6 changes: 3 additions & 3 deletions zebra-network/src/protocol/external/codec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use tokio_util::codec::{Decoder, Encoder};

use zebra_chain::{
block::{self, Block},
parameters::Network,
parameters::{Magic, Network},
serialization::{
sha256d, zcash_deserialize_bytes_external_count, zcash_deserialize_string_external_count,
CompactSizeMessage, FakeWriter, ReadZcashExt, SerializationError as Error,
Expand Down Expand Up @@ -163,7 +163,7 @@ impl Encoder<Message> for Codec {
let start_len = dst.len();
{
let dst = &mut dst.writer();
dst.write_all(&self.builder.network.magic_value().0[..])?;
dst.write_all(&self.builder.network.magic().0[..])?;
dst.write_all(command)?;
dst.write_u32::<LittleEndian>(body_length as u32)?;

Expand Down Expand Up @@ -389,7 +389,7 @@ impl Decoder for Codec {
"read header from src buffer"
);

if magic != self.builder.network.magic_value() {
if magic != self.builder.network.magic() {
return Err(Parse("supplied magic did not meet expectations"));
}
if body_len > self.builder.max_len {
Expand Down
20 changes: 20 additions & 0 deletions zebra-network/src/protocol/external/codec/tests/vectors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -587,3 +587,23 @@ fn reject_command_and_reason_size_limits() {
};
}
}

/// Check that the version test vector deserialization fails when there's a network magic mismatch.
#[test]
fn message_with_wrong_network_magic_returns_error() {
let _init_guard = zebra_test::init();
let mut codec = Codec::builder().finish();
let mut bytes = BytesMut::new();

codec
.encode(VERSION_TEST_VECTOR.clone(), &mut bytes)
.expect("encoding should succeed");

let mut codec = Codec::builder()
.for_network(&Network::new_default_testnet())
.finish();

codec
.decode(&mut bytes)
.expect_err("decoding message with mismatching network magic should return an error");
}
Loading
Loading