Skip to content

Commit

Permalink
Retry strategy in config
Browse files Browse the repository at this point in the history
  • Loading branch information
sergerad committed May 24, 2024
1 parent 8b17054 commit 930d982
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 10 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/net/types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ thiserror.workspace = true
url.workspace = true
tokio = { workspace = true, features = ["full"] }
tokio-retry = { workspace = true }
eyre.workspace = true

[dev-dependencies]
alloy-primitives = { workspace = true, features = ["rand"] }
Expand Down
43 changes: 36 additions & 7 deletions crates/net/types/src/dns_node_record.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,41 @@ pub struct DNSNodeRecord {
}

/// Retry strategy for DNS lookups.
#[derive(Debug)]
#[derive(Clone, Debug, Eq, PartialEq, Hash, SerializeDisplay, DeserializeFromStr)]
pub struct RetryStrategy {
/// The amount of time between retries.
interval: u64,
/// The number of retries.
retries: usize,
/// The amount of time between attempts.
pub interval: u64,
/// The number of attempts to make before failing.
pub attempts: usize,
}

impl fmt::Display for RetryStrategy {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "interval={},attempts={}", self.interval, self.attempts)
}
}

impl FromStr for RetryStrategy {
type Err = eyre::Error;

fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut interval = None;
let mut attempts = None;

for pair in s.split(',') {
let mut parts = pair.split('=');
let key = parts.next().unwrap();
let value = parts.next().unwrap();

match key {
"interval" => interval = Some(value.parse()?),
"attempts" => attempts = Some(value.parse()?),
_ => return Err(eyre::eyre!("Invalid key: {}", key)),
}
}

Ok(Self { interval: interval.unwrap_or(0), attempts: attempts.unwrap_or(0) })
}
}

impl DNSNodeRecord {
Expand Down Expand Up @@ -86,7 +115,7 @@ impl DNSNodeRecord {
if let Some(strat) = retry_strategy {
let lookup = || async { Self::lookup_host(&domain).await };
let strat = tokio_retry::strategy::FixedInterval::from_millis(strat.interval)
.take(strat.retries);
.take(strat.attempts);
let ip = tokio_retry::Retry::spawn(strat, lookup).await?;
Ok(NodeRecord {
address: ip,
Expand Down Expand Up @@ -311,7 +340,7 @@ mod tests {
// Set up tests
let tests = vec![
("localhost", None),
("localhost", Some(RetryStrategy { interval: 1000, retries: 3 })),
("localhost", Some(RetryStrategy { interval: 1000, attempts: 3 })),
];

// Run tests
Expand Down
2 changes: 1 addition & 1 deletion crates/net/types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ pub mod node_record;
pub use node_record::{NodeRecord, NodeRecordParseError};

pub mod dns_node_record;
pub use dns_node_record::DNSNodeRecord;
pub use dns_node_record::{DNSNodeRecord, RetryStrategy};

/// This tag should be set to indicate to libsecp256k1 that the following bytes denote an
/// uncompressed pubkey.
Expand Down
1 change: 1 addition & 0 deletions crates/node-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ reth-db = { workspace = true, features = ["mdbx"] }
reth-interfaces = { workspace = true, features = ["clap"] }
reth-provider.workspace = true
reth-network = { workspace = true, features = ["serde"] }
reth-network-types.workspace = true
reth-rpc-engine-api.workspace = true
reth-rpc-builder.workspace = true
reth-rpc.workspace = true
Expand Down
23 changes: 22 additions & 1 deletion crates/node-core/src/args/network.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ use reth_network::{
},
HelloMessageWithProtocols, NetworkConfigBuilder, SessionsConfig,
};
use reth_primitives::{mainnet_nodes, ChainSpec, DNSNodeRecord};
use reth_network_types::{DNSNodeRecord, RetryStrategy};
use reth_primitives::{mainnet_nodes, ChainSpec};
use secp256k1::SecretKey;
use std::{
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
Expand Down Expand Up @@ -50,6 +51,10 @@ pub struct NetworkArgs {
#[arg(long, value_delimiter = ',')]
pub bootnodes: Option<Vec<DNSNodeRecord>>,

/// DNS retry strategy for bootnode or peer hostname resolution.
#[arg(long)]
pub dns_retry_strategy: Option<RetryStrategy>,

/// The path to the known peers file. Connected peers are dumped to this file on nodes
/// shutdown, and read on startup. Cannot be used with `--no-persist-peers`.
#[arg(long, value_name = "FILE", verbatim_doc_comment, conflicts_with = "no_persist_peers")]
Expand Down Expand Up @@ -219,6 +224,7 @@ impl Default for NetworkArgs {
trusted_peers: vec![],
trusted_only: false,
bootnodes: None,
dns_retry_strategy: None,
peers_file: None,
identity: P2P_CLIENT_VERSION.to_string(),
p2p_secret_key: None,
Expand Down Expand Up @@ -411,6 +417,21 @@ mod tests {
);
}

#[test]
fn parse_retry_strategy_args() {
let args = CommandParser::<NetworkArgs>::parse_from([
"reth",
"--dns-retry-strategy",
"interval=5,attempts=3",
])
.args;

assert_eq!(
args.dns_retry_strategy,
Some(reth_network_types::RetryStrategy { interval: 5, attempts: 3 }),
);
}

#[cfg(not(feature = "optimism"))]
#[test]
fn network_args_default_sanity_test() {
Expand Down
2 changes: 1 addition & 1 deletion crates/node/builder/src/launch/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ impl LaunchContext {
// resolve trusted peers if they use a domain instead of dns
for peer in &config.network.trusted_peers {
let resolved = peer
.resolve(None)
.resolve(config.network.dns_retry_strategy.clone())
.await
.wrap_err_with(|| format!("Could not resolve trusted peer {peer}"))?;
toml_config.peers.trusted_nodes.insert(resolved);
Expand Down

0 comments on commit 930d982

Please sign in to comment.