chore: add Anvil::at and anvil example (#1486)

This commit is contained in:
Matthias Seitz 2022-07-20 09:08:25 +02:00 committed by GitHub
parent 9e586cd9f6
commit 1d4f3efe8a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 58 additions and 1 deletions

View File

@ -5,6 +5,7 @@ use crate::{
use k256::{ecdsa::SigningKey, SecretKey as K256SecretKey}; use k256::{ecdsa::SigningKey, SecretKey as K256SecretKey};
use std::{ use std::{
io::{BufRead, BufReader}, io::{BufRead, BufReader},
path::PathBuf,
process::{Child, Command}, process::{Child, Command},
time::{Duration, Instant}, time::{Duration, Instant},
}; };
@ -78,6 +79,7 @@ impl Drop for AnvilInstance {
/// ``` /// ```
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
pub struct Anvil { pub struct Anvil {
program: Option<PathBuf>,
port: Option<u16>, port: Option<u16>,
block_time: Option<u64>, block_time: Option<u64>,
mnemonic: Option<String>, mnemonic: Option<String>,
@ -89,10 +91,47 @@ pub struct Anvil {
impl Anvil { impl Anvil {
/// Creates an empty Anvil builder. /// Creates an empty Anvil builder.
/// The default port is 8545. The mnemonic is chosen randomly. /// The default port is 8545. The mnemonic is chosen randomly.
///
/// # Example
///
/// ```
/// # use ethers_core::utils::Anvil;
/// fn a() {
/// let anvil = Anvil::default().spawn();
///
/// println!("Anvil running at `{}`", anvil.endpoint());
/// # }
/// ```
pub fn new() -> Self { pub fn new() -> Self {
Self::default() Self::default()
} }
/// Creates an Anvil builder which will execute `anvil` at the given path.
///
/// # Example
///
/// ```
/// # use ethers_core::utils::Anvil;
/// fn a() {
/// let anvil = Anvil::at("~/.foundry/bin/anvil").spawn();
///
/// println!("Anvil running at `{}`", anvil.endpoint());
/// # }
/// ```
pub fn at(path: impl Into<PathBuf>) -> Self {
Self::new().path(path)
}
/// Sets the `path` to the `anvil` cli
///
/// By default, it's expected that `anvil` is in `$PATH`, see also
/// [`std::process::Command::new()`]
#[must_use]
pub fn path<T: Into<PathBuf>>(mut self, path: T) -> Self {
self.program = Some(path.into());
self
}
/// Sets the port which will be used when the `anvil` instance is launched. /// Sets the port which will be used when the `anvil` instance is launched.
#[must_use] #[must_use]
pub fn port<T: Into<u16>>(mut self, port: T) -> Self { pub fn port<T: Into<u16>>(mut self, port: T) -> Self {
@ -156,7 +195,11 @@ impl Anvil {
/// Consumes the builder and spawns `anvil` with stdout redirected /// Consumes the builder and spawns `anvil` with stdout redirected
/// to /dev/null. /// to /dev/null.
pub fn spawn(self) -> AnvilInstance { pub fn spawn(self) -> AnvilInstance {
let mut cmd = Command::new("anvil"); let mut cmd = if let Some(ref prg) = self.program {
Command::new(prg)
} else {
Command::new("anvil")
};
cmd.stdout(std::process::Stdio::piped()); cmd.stdout(std::process::Stdio::piped());
let port = if let Some(port) = self.port { port } else { unused_port() }; let port = if let Some(port) = self.port { port } else { unused_port() };
cmd.arg("-p").arg(port.to_string()); cmd.arg("-p").arg(port.to_string());

14
examples/anvil_fork.rs Normal file
View File

@ -0,0 +1,14 @@
//! Spawn an [anvil](https://github.com/foundry-rs/foundry/tree/master/anvil) instance in forking mode
use ethers::utils::Anvil;
#[tokio::main]
async fn main() -> eyre::Result<()> {
// ensure `anvil` is available in $PATH
let anvil =
Anvil::new().fork("https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27").spawn();
println!("Anvil running at `{}`", anvil.endpoint());
Ok(())
}