diff --git a/evmlib/src/testnet.rs b/evmlib/src/testnet.rs index c4db116c2e..97c56ef590 100644 --- a/evmlib/src/testnet.rs +++ b/evmlib/src/testnet.rs @@ -1,6 +1,7 @@ use crate::common::Address; use crate::contract::data_payments::DataPaymentsHandler; use crate::contract::network_token::NetworkToken; +use crate::reqwest::Url; use crate::{CustomNetwork, Network}; use alloy::hex::ToHexExt; use alloy::network::{Ethereum, EthereumWallet}; @@ -21,11 +22,12 @@ pub struct Testnet { impl Testnet { /// Starts an Anvil node and automatically deploys the network token and chunk payments smart contracts. pub async fn new() -> Self { - let anvil = start_node(); + let (anvil, rpc_url) = start_node(); - let network_token = deploy_network_token_contract(&anvil).await; + let network_token = deploy_network_token_contract(&rpc_url, &anvil).await; let data_payments = - deploy_data_payments_contract(&anvil, *network_token.contract.address()).await; + deploy_data_payments_contract(&rpc_url, &anvil, *network_token.contract.address()) + .await; Testnet { anvil, @@ -40,6 +42,7 @@ impl Testnet { .endpoint() .parse() .expect("Could not parse RPC URL"); + println!("RPC URL: {}", rpc_url); Network::Custom(CustomNetwork { rpc_url_http: rpc_url, @@ -55,17 +58,31 @@ impl Testnet { } } -/// Runs a local Anvil node. -pub fn start_node() -> AnvilInstance { - // Spin up a local Anvil node. - // Requires you to have Foundry installed: https://book.getfoundry.sh/getting-started/installation - Anvil::new() - .port(4343_u16) +/// Runs a local Anvil node bound to a specified IP address. +/// +/// The `AnvilInstance` `endpoint` function is hardcoded to return "localhost", so we must also +/// return the RPC URL if we want to listen on something other than `localhost`. +/// +/// The `anvil` binary respects the `ANVIL_IP_ADDR` environment variable, but defaults to "localhost". +pub fn start_node() -> (AnvilInstance, Url) { + let host = std::env::var("ANVIL_IP_ADDR").unwrap_or_else(|_| "localhost".to_string()); + let port = std::env::var("ANVIL_PORT") + .unwrap_or_else(|_| "4343".to_string()) + .parse::() + .expect("Invalid port number"); + + let anvil = Anvil::new() + .port(port) .try_spawn() - .expect("Could not spawn Anvil node") + .expect("Could not spawn Anvil node"); + + let url = Url::parse(&format!("http://{}:{}", host, port)).expect("Failed to parse URL"); + + (anvil, url) } pub async fn deploy_network_token_contract( + rpc_url: &Url, anvil: &AnvilInstance, ) -> NetworkToken< Http, @@ -87,18 +104,17 @@ pub async fn deploy_network_token_contract( let signer: PrivateKeySigner = anvil.keys()[0].clone().into(); let wallet = EthereumWallet::from(signer); - let rpc_url = anvil.endpoint().parse().expect("Could not parse RPC URL"); - let provider = ProviderBuilder::new() .with_recommended_fillers() .wallet(wallet) - .on_http(rpc_url); + .on_http(rpc_url.clone()); // Deploy the contract. NetworkToken::deploy(provider).await } pub async fn deploy_data_payments_contract( + rpc_url: &Url, anvil: &AnvilInstance, token_address: Address, ) -> DataPaymentsHandler< @@ -121,12 +137,10 @@ pub async fn deploy_data_payments_contract( let signer: PrivateKeySigner = anvil.keys()[1].clone().into(); let wallet = EthereumWallet::from(signer); - let rpc_url = anvil.endpoint().parse().expect("Could not parse RPC URL"); - let provider = ProviderBuilder::new() .with_recommended_fillers() .wallet(wallet) - .on_http(rpc_url); + .on_http(rpc_url.clone()); // Deploy the contract. DataPaymentsHandler::deploy(provider, token_address).await diff --git a/evmlib/tests/data_payments.rs b/evmlib/tests/data_payments.rs index ed9e2ac413..26223cfcc1 100644 --- a/evmlib/tests/data_payments.rs +++ b/evmlib/tests/data_payments.rs @@ -58,12 +58,12 @@ async fn setup() -> ( Ethereum, >, ) { - let anvil = start_node(); + let (anvil, rpc_url) = start_node(); - let network_token = deploy_network_token_contract(&anvil).await; + let network_token = deploy_network_token_contract(&rpc_url, &anvil).await; let data_payments = - deploy_data_payments_contract(&anvil, *network_token.contract.address()).await; + deploy_data_payments_contract(&rpc_url, &anvil, *network_token.contract.address()).await; (anvil, network_token, data_payments) } diff --git a/evmlib/tests/network_token.rs b/evmlib/tests/network_token.rs index 40ea9ba041..0cc2b1c1eb 100644 --- a/evmlib/tests/network_token.rs +++ b/evmlib/tests/network_token.rs @@ -36,9 +36,9 @@ async fn setup() -> ( Ethereum, >, ) { - let anvil = start_node(); + let (anvil, rpc_url) = start_node(); - let network_token = deploy_network_token_contract(&anvil).await; + let network_token = deploy_network_token_contract(&rpc_url, &anvil).await; (anvil, network_token) } diff --git a/evmlib/tests/wallet.rs b/evmlib/tests/wallet.rs index a95ee34eca..905f719fc3 100644 --- a/evmlib/tests/wallet.rs +++ b/evmlib/tests/wallet.rs @@ -17,11 +17,11 @@ use std::collections::HashSet; #[allow(clippy::unwrap_used)] async fn local_testnet() -> (AnvilInstance, Network, EthereumWallet) { - let anvil = start_node(); - let rpc_url = anvil.endpoint().parse().unwrap(); - let network_token = deploy_network_token_contract(&anvil).await; + let (anvil, rpc_url) = start_node(); + let network_token = deploy_network_token_contract(&rpc_url, &anvil).await; let payment_token_address = *network_token.contract.address(); - let data_payments = deploy_data_payments_contract(&anvil, payment_token_address).await; + let data_payments = + deploy_data_payments_contract(&rpc_url, &anvil, payment_token_address).await; ( anvil,