forked from foundry-rs/foundry
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(anvil): add support for trailing fork block number (foundry-rs#2243
- Loading branch information
Showing
1 changed file
with
85 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,9 +5,11 @@ use crate::{ | |
}; | ||
use anvil_server::ServerConfig; | ||
use clap::Parser; | ||
use core::fmt; | ||
use ethers::utils::WEI_IN_ETHER; | ||
use std::{ | ||
net::IpAddr, | ||
str::FromStr, | ||
sync::{ | ||
atomic::{AtomicUsize, Ordering}, | ||
Arc, | ||
|
@@ -131,9 +133,13 @@ impl NodeArgs { | |
.with_account_generator(self.account_generator()) | ||
.with_genesis_balance(genesis_balance) | ||
.with_port(self.port) | ||
.with_eth_rpc_url(self.evm_opts.fork_url) | ||
.with_fork_block_number( | ||
self.evm_opts | ||
.fork_block_number | ||
.or_else(|| self.evm_opts.fork_url.as_ref().and_then(|f| f.block)), | ||
) | ||
.with_eth_rpc_url(self.evm_opts.fork_url.map(|fork| fork.url)) | ||
.with_base_fee(self.evm_opts.block_base_fee_per_gas) | ||
.with_fork_block_number(self.evm_opts.fork_block_number) | ||
.with_storage_caching(self.evm_opts.no_storage_caching) | ||
.with_server_config(self.server_config) | ||
.with_host(self.host) | ||
|
@@ -189,15 +195,15 @@ impl NodeArgs { | |
pub struct AnvilEvmArgs { | ||
/// Fetch state over a remote endpoint instead of starting from an empty state. | ||
/// | ||
/// If you want to fetch state from a specific block number, see --fork-block-number. | ||
/// If you want to fetch state from a specific block number, add a block number like `http://localhost:8545@1400000` or use the `--fork-block-number` argument. | ||
#[clap( | ||
long, | ||
short, | ||
visible_alias = "rpc-url", | ||
value_name = "URL", | ||
help_heading = "FORK CONFIG" | ||
)] | ||
pub fork_url: Option<String>, | ||
pub fork_url: Option<ForkUrl>, | ||
|
||
/// Fetch state from a specific block number over a remote endpoint. | ||
/// | ||
|
@@ -242,3 +248,78 @@ pub struct AnvilEvmArgs { | |
#[clap(long, value_name = "CHAIN_ID", help_heading = "ENVIRONMENT CONFIG")] | ||
pub chain_id: Option<u64>, | ||
} | ||
|
||
/// Represents the input URL for a fork with an optional trailing block number: | ||
/// `http://localhost:8545@1000000` | ||
#[derive(Debug, Clone, PartialEq, Eq)] | ||
pub struct ForkUrl { | ||
/// The endpoint url | ||
pub url: String, | ||
/// Optional trailing block | ||
pub block: Option<u64>, | ||
} | ||
|
||
impl fmt::Display for ForkUrl { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
self.url.fmt(f)?; | ||
if let Some(block) = self.block { | ||
write!(f, "@{block}")?; | ||
} | ||
Ok(()) | ||
} | ||
} | ||
|
||
impl FromStr for ForkUrl { | ||
type Err = String; | ||
|
||
fn from_str(s: &str) -> Result<Self, Self::Err> { | ||
if let Some((url, block)) = s.rsplit_once('@') { | ||
if block == "latest" { | ||
return Ok(ForkUrl { url: url.to_string(), block: None }) | ||
} | ||
// this will prevent false positives for auths `user:[email protected]` | ||
if !block.is_empty() && !block.contains(':') && !block.contains('.') { | ||
let block: u64 = block | ||
.parse() | ||
.map_err(|_| format!("Failed to parse block number: `{block}`"))?; | ||
return Ok(ForkUrl { url: url.to_string(), block: Some(block) }) | ||
} | ||
} | ||
Ok(ForkUrl { url: s.to_string(), block: None }) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
|
||
#[test] | ||
fn test_parse_fork_url() { | ||
let fork: ForkUrl = "http://localhost:8545@1000000".parse().unwrap(); | ||
assert_eq!( | ||
fork, | ||
ForkUrl { url: "http://localhost:8545".to_string(), block: Some(1000000) } | ||
); | ||
|
||
let fork: ForkUrl = "http://localhost:8545".parse().unwrap(); | ||
assert_eq!(fork, ForkUrl { url: "http://localhost:8545".to_string(), block: None }); | ||
|
||
let fork: ForkUrl = "wss://user:[email protected]/".parse().unwrap(); | ||
assert_eq!( | ||
fork, | ||
ForkUrl { url: "wss://user:[email protected]/".to_string(), block: None } | ||
); | ||
|
||
let fork: ForkUrl = "wss://user:[email protected]/@latest".parse().unwrap(); | ||
assert_eq!( | ||
fork, | ||
ForkUrl { url: "wss://user:[email protected]/".to_string(), block: None } | ||
); | ||
|
||
let fork: ForkUrl = "wss://user:[email protected]/@100000".parse().unwrap(); | ||
assert_eq!( | ||
fork, | ||
ForkUrl { url: "wss://user:[email protected]/".to_string(), block: Some(100000) } | ||
); | ||
} | ||
} |