Skip to content

Commit

Permalink
Merge of #9224
Browse files Browse the repository at this point in the history
  • Loading branch information
mergify[bot] authored Feb 12, 2025
2 parents 3a0269d + 70893b1 commit e9d8f33
Show file tree
Hide file tree
Showing 4 changed files with 204 additions and 54 deletions.
2 changes: 1 addition & 1 deletion zebra-chain/src/parameters/network/subsidy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ pub(crate) const FIRST_HALVING_TESTNET: Height = Height(1_116_000);
const FIRST_HALVING_REGTEST: Height = Height(287);

/// The funding stream receiver categories.
#[derive(Deserialize, Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum FundingStreamReceiver {
/// The Electric Coin Company (Bootstrap Foundation) funding stream.
#[serde(rename = "ECC")]
Expand Down
82 changes: 78 additions & 4 deletions zebra-chain/src/parameters/network/testnet.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//! Types and implementation for Testnet consensus parameters
use std::{collections::BTreeMap, fmt};
use std::{collections::BTreeMap, fmt, sync::Arc};

use crate::{
block::{self, Height, HeightDiff},
Expand Down Expand Up @@ -57,7 +57,7 @@ const TESTNET_GENESIS_HASH: &str =
const PRE_BLOSSOM_REGTEST_HALVING_INTERVAL: HeightDiff = 144;

/// Configurable funding stream recipient for configured Testnets.
#[derive(Deserialize, Clone, Debug)]
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
pub struct ConfiguredFundingStreamRecipient {
/// Funding stream receiver, see [`FundingStreams::recipients`] for more details.
Expand All @@ -79,7 +79,7 @@ impl ConfiguredFundingStreamRecipient {
}

/// Configurable funding streams for configured Testnets.
#[derive(Deserialize, Clone, Default, Debug)]
#[derive(Serialize, Deserialize, Clone, Default, Debug)]
#[serde(deny_unknown_fields)]
pub struct ConfiguredFundingStreams {
/// Start and end height for funding streams see [`FundingStreams::height_range`] for more details.
Expand All @@ -88,6 +88,71 @@ pub struct ConfiguredFundingStreams {
pub recipients: Option<Vec<ConfiguredFundingStreamRecipient>>,
}

impl From<&FundingStreams> for ConfiguredFundingStreams {
fn from(value: &FundingStreams) -> Self {
Self {
height_range: Some(value.height_range().clone()),
recipients: Some(
value
.recipients()
.iter()
.map(|(receiver, recipient)| ConfiguredFundingStreamRecipient {
receiver: *receiver,
numerator: recipient.numerator(),
addresses: Some(
recipient
.addresses()
.iter()
.map(ToString::to_string)
.collect(),
),
})
.collect(),
),
}
}
}

impl From<&BTreeMap<Height, NetworkUpgrade>> for ConfiguredActivationHeights {
fn from(activation_heights: &BTreeMap<Height, NetworkUpgrade>) -> Self {
let mut configured_activation_heights = ConfiguredActivationHeights::default();

for (height, network_upgrade) in activation_heights.iter() {
match network_upgrade {
NetworkUpgrade::BeforeOverwinter => {
configured_activation_heights.before_overwinter = Some(height.0);
}
NetworkUpgrade::Overwinter => {
configured_activation_heights.overwinter = Some(height.0);
}
NetworkUpgrade::Sapling => {
configured_activation_heights.sapling = Some(height.0);
}
NetworkUpgrade::Blossom => {
configured_activation_heights.blossom = Some(height.0);
}
NetworkUpgrade::Heartwood => {
configured_activation_heights.heartwood = Some(height.0);
}
NetworkUpgrade::Canopy => {
configured_activation_heights.canopy = Some(height.0);
}
NetworkUpgrade::Nu5 => {
configured_activation_heights.nu5 = Some(height.0);
}
NetworkUpgrade::Nu6 => {
configured_activation_heights.nu6 = Some(height.0);
}
NetworkUpgrade::Genesis => {
continue;
}
}
}

configured_activation_heights
}
}

impl ConfiguredFundingStreams {
/// Returns an empty [`ConfiguredFundingStreams`].
fn empty() -> Self {
Expand Down Expand Up @@ -185,7 +250,7 @@ fn check_funding_stream_address_period(funding_streams: &FundingStreams, network
}

/// Configurable activation heights for Regtest and configured Testnets.
#[derive(Deserialize, Default, Clone)]
#[derive(Serialize, Deserialize, Default, Clone)]
#[serde(rename_all = "PascalCase", deny_unknown_fields)]
pub struct ConfiguredActivationHeights {
/// Activation height for `BeforeOverwinter` network upgrade.
Expand Down Expand Up @@ -754,6 +819,15 @@ impl Parameters {
}

impl Network {
/// Returns the parameters of this network if it is a Testnet.
pub fn parameters(&self) -> Option<Arc<Parameters>> {
if let Self::Testnet(parameters) = self {
Some(parameters.clone())
} else {
None
}
}

/// Returns true if proof-of-work validation should be disabled for this network
pub fn disable_pow(&self) -> bool {
if let Self::Testnet(params) = self {
Expand Down
155 changes: 106 additions & 49 deletions zebra-network/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::{
collections::HashSet,
io::{self, ErrorKind},
net::{IpAddr, SocketAddr},
sync::Arc,
time::Duration,
};

Expand Down Expand Up @@ -51,7 +52,7 @@ const MAX_SINGLE_SEED_PEER_DNS_RETRIES: usize = 0;

/// Configuration for networking code.
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields, default)]
#[serde(deny_unknown_fields, default, into = "DConfig")]
pub struct Config {
/// The address on which this node should listen for connections.
///
Expand Down Expand Up @@ -580,60 +581,116 @@ impl Default for Config {
}
}

impl<'de> Deserialize<'de> for Config {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Deserialize)]
#[serde(deny_unknown_fields)]
struct DTestnetParameters {
network_name: Option<String>,
network_magic: Option<[u8; 4]>,
slow_start_interval: Option<u32>,
target_difficulty_limit: Option<String>,
disable_pow: Option<bool>,
genesis_hash: Option<String>,
activation_heights: Option<ConfiguredActivationHeights>,
pre_nu6_funding_streams: Option<ConfiguredFundingStreams>,
post_nu6_funding_streams: Option<ConfiguredFundingStreams>,
pre_blossom_halving_interval: Option<u32>,
#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
struct DTestnetParameters {
network_name: Option<String>,
network_magic: Option<[u8; 4]>,
slow_start_interval: Option<u32>,
target_difficulty_limit: Option<String>,
disable_pow: Option<bool>,
genesis_hash: Option<String>,
activation_heights: Option<ConfiguredActivationHeights>,
pre_nu6_funding_streams: Option<ConfiguredFundingStreams>,
post_nu6_funding_streams: Option<ConfiguredFundingStreams>,
pre_blossom_halving_interval: Option<u32>,
}

#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields, default)]
struct DConfig {
listen_addr: String,
external_addr: Option<String>,
network: NetworkKind,
testnet_parameters: Option<DTestnetParameters>,
initial_mainnet_peers: IndexSet<String>,
initial_testnet_peers: IndexSet<String>,
cache_dir: CacheDir,
peerset_initial_target_size: usize,
#[serde(alias = "new_peer_interval", with = "humantime_serde")]
crawl_new_peer_interval: Duration,
max_connections_per_ip: Option<usize>,
}

impl Default for DConfig {
fn default() -> Self {
let config = Config::default();
Self {
listen_addr: "0.0.0.0".to_string(),
external_addr: None,
network: Default::default(),
testnet_parameters: None,
initial_mainnet_peers: config.initial_mainnet_peers,
initial_testnet_peers: config.initial_testnet_peers,
cache_dir: config.cache_dir,
peerset_initial_target_size: config.peerset_initial_target_size,
crawl_new_peer_interval: config.crawl_new_peer_interval,
max_connections_per_ip: Some(config.max_connections_per_ip),
}
}
}

#[derive(Deserialize)]
#[serde(deny_unknown_fields, default)]
struct DConfig {
listen_addr: String,
external_addr: Option<String>,
network: NetworkKind,
testnet_parameters: Option<DTestnetParameters>,
initial_mainnet_peers: IndexSet<String>,
initial_testnet_peers: IndexSet<String>,
cache_dir: CacheDir,
peerset_initial_target_size: usize,
#[serde(alias = "new_peer_interval", with = "humantime_serde")]
crawl_new_peer_interval: Duration,
max_connections_per_ip: Option<usize>,
impl From<Arc<testnet::Parameters>> for DTestnetParameters {
fn from(params: Arc<testnet::Parameters>) -> Self {
Self {
network_name: Some(params.network_name().to_string()),
network_magic: Some(params.network_magic().0),
slow_start_interval: Some(params.slow_start_interval().0),
target_difficulty_limit: Some(params.target_difficulty_limit().to_string()),
disable_pow: Some(params.disable_pow()),
genesis_hash: Some(params.genesis_hash().to_string()),
activation_heights: Some(params.activation_heights().into()),
pre_nu6_funding_streams: Some(params.pre_nu6_funding_streams().into()),
post_nu6_funding_streams: Some(params.post_nu6_funding_streams().into()),
pre_blossom_halving_interval: Some(
params
.pre_blossom_halving_interval()
.try_into()
.expect("should convert"),
),
}
}
}

impl Default for DConfig {
fn default() -> Self {
let config = Config::default();
Self {
listen_addr: "0.0.0.0".to_string(),
external_addr: None,
network: Default::default(),
testnet_parameters: None,
initial_mainnet_peers: config.initial_mainnet_peers,
initial_testnet_peers: config.initial_testnet_peers,
cache_dir: config.cache_dir,
peerset_initial_target_size: config.peerset_initial_target_size,
crawl_new_peer_interval: config.crawl_new_peer_interval,
max_connections_per_ip: Some(config.max_connections_per_ip),
}
}
impl From<Config> for DConfig {
fn from(
Config {
listen_addr,
external_addr,
network,
initial_mainnet_peers,
initial_testnet_peers,
cache_dir,
peerset_initial_target_size,
crawl_new_peer_interval,
max_connections_per_ip,
}: Config,
) -> Self {
let testnet_parameters = network
.parameters()
.filter(|params| !params.is_default_testnet() && !params.is_regtest())
.map(Into::into);

DConfig {
listen_addr: listen_addr.to_string(),
external_addr: external_addr.map(|addr| addr.to_string()),
network: network.into(),
testnet_parameters,
initial_mainnet_peers,
initial_testnet_peers,
cache_dir,
peerset_initial_target_size,
crawl_new_peer_interval,
max_connections_per_ip: Some(max_connections_per_ip),
}
}
}

impl<'de> Deserialize<'de> for Config {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let DConfig {
listen_addr,
external_addr,
Expand Down
19 changes: 19 additions & 0 deletions zebra-network/src/config/tests/vectors.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Fixed test vectors for zebra-network configuration.
use static_assertions::const_assert;
use zebra_chain::parameters::testnet;

use crate::{
constants::{INBOUND_PEER_LIMIT_MULTIPLIER, OUTBOUND_PEER_LIMIT_MULTIPLIER},
Expand Down Expand Up @@ -46,3 +47,21 @@ fn ensure_peer_connection_limits_consistent() {
"default config should allow more inbound connections, to avoid connection exhaustion",
);
}

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

let config = Config {
network: testnet::Parameters::build()
.with_disable_pow(true)
.to_network(),
initial_testnet_peers: [].into(),
..Config::default()
};

let serialized = toml::to_string(&config).unwrap();
let deserialized: Config = toml::from_str(&serialized).unwrap();

assert_eq!(config, deserialized);
}

0 comments on commit e9d8f33

Please sign in to comment.