diff --git a/crates/anvil/tests/it/fork.rs b/crates/anvil/tests/it/fork.rs index c9d9b2c80b8fc..526f3263b67f8 100644 --- a/crates/anvil/tests/it/fork.rs +++ b/crates/anvil/tests/it/fork.rs @@ -837,7 +837,7 @@ async fn test_reset_fork_on_new_blocks() { let anvil_provider = handle.http_provider(); let endpoint = next_http_rpc_endpoint(); - let provider = Arc::new(get_http_provider(&endpoint)); + let provider = Arc::new(get_http_provider(&endpoint, false)); let current_block = anvil_provider.get_block_number().await.unwrap(); diff --git a/crates/anvil/tests/it/utils.rs b/crates/anvil/tests/it/utils.rs index 4a82c27745edd..9b79916427d80 100644 --- a/crates/anvil/tests/it/utils.rs +++ b/crates/anvil/tests/it/utils.rs @@ -8,7 +8,7 @@ use foundry_common::provider::{ }; pub fn http_provider(http_endpoint: &str) -> RetryProvider { - get_http_provider(http_endpoint) + get_http_provider(http_endpoint, false) } pub fn http_provider_with_signer( diff --git a/crates/cli/src/opts/evm.rs b/crates/cli/src/opts/evm.rs index e2e22f7d343ff..0193af2c05786 100644 --- a/crates/cli/src/opts/evm.rs +++ b/crates/cli/src/opts/evm.rs @@ -40,6 +40,14 @@ use foundry_common::shell; #[derive(Clone, Debug, Default, Serialize, Parser)] #[command(next_help_heading = "EVM options", about = None, long_about = None)] // override doc pub struct EvmArgs { + /// Allow insecure RPC connections (accept invalid HTTPS certificates). + /// + /// When the provider's inner runtime transport variant is HTTP, this configures the reqwest + /// client to accept invalid certificates. + #[arg(short = 'k', long = "insecure", default_value = "false")] + #[serde(rename = "eth_rpc_accept_invalid_certs")] + pub accept_invalid_certs: bool, + /// 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. @@ -190,6 +198,10 @@ impl Provider for EvmArgs { dict.insert("eth_rpc_url".to_string(), fork_url.clone().into()); } + if self.accept_invalid_certs { + dict.insert("eth_rpc_accept_invalid_certs".to_string(), self.accept_invalid_certs.into()); + } + Ok(Map::from([(Config::selected_profile(), dict)])) } } diff --git a/crates/cli/src/utils/mod.rs b/crates/cli/src/utils/mod.rs index 942fe6ae805b9..de785d3a6bc95 100644 --- a/crates/cli/src/utils/mod.rs +++ b/crates/cli/src/utils/mod.rs @@ -105,12 +105,32 @@ pub fn get_provider(config: &Config) -> Result { get_provider_builder(config)?.build() } +/// Returns a [RetryProvider] instantiated using the given +/// RPC URL instead of the [Config]'s RPC +pub fn get_provider_url(config: &Config, url_str: &str) -> Result { + provider_builder_with_url(config, url_str)?.build() +} + /// Returns a [ProviderBuilder] instantiated using [Config] values. /// /// Defaults to `http://localhost:8545` and `Mainnet`. pub fn get_provider_builder(config: &Config) -> Result { let url = config.get_rpc_url_or_localhost_http()?; - let mut builder = ProviderBuilder::new(url.as_ref()); + provider_builder_with_url(config, url.as_ref()) +} + +/// Returns a [ProviderBuilder] instantiated using [Config] values and +/// the given RPC URL. +fn provider_builder_with_url(config: &Config, url_str: &str) -> Result { + let builder = ProviderBuilder::new(url_str); + apply_config_to_builder(builder, config) +} + +// Applies [Config] values to a [ProviderBuilder]. +fn apply_config_to_builder( + mut builder: ProviderBuilder, + config: &Config, +) -> Result { builder = builder.accept_invalid_certs(config.eth_rpc_accept_invalid_certs); diff --git a/crates/evm/core/src/backend/mod.rs b/crates/evm/core/src/backend/mod.rs index 3da6cb45fe657..208dcdee5e955 100644 --- a/crates/evm/core/src/backend/mod.rs +++ b/crates/evm/core/src/backend/mod.rs @@ -2044,7 +2044,7 @@ mod tests { async fn can_read_write_cache() { let Some(endpoint) = ENDPOINT else { return }; - let provider = get_http_provider(endpoint); + let provider = get_http_provider(endpoint, false); let block_num = provider.get_block_number().await.unwrap(); diff --git a/crates/evm/core/src/fork/database.rs b/crates/evm/core/src/fork/database.rs index 6a53a19843b1b..a7b0bfb32bdd8 100644 --- a/crates/evm/core/src/fork/database.rs +++ b/crates/evm/core/src/fork/database.rs @@ -278,7 +278,7 @@ mod tests { #[tokio::test(flavor = "multi_thread")] async fn fork_db_insert_basic_default() { let rpc = foundry_test_utils::rpc::next_http_rpc_endpoint(); - let provider = get_http_provider(rpc.clone()); + let provider = get_http_provider(rpc.clone(), false); let meta = BlockchainDbMeta::new(Default::default(), rpc); let db = BlockchainDb::new(meta, None); diff --git a/crates/evm/core/src/fork/multi.rs b/crates/evm/core/src/fork/multi.rs index d33fcf837105c..871f70de49447 100644 --- a/crates/evm/core/src/fork/multi.rs +++ b/crates/evm/core/src/fork/multi.rs @@ -544,6 +544,7 @@ async fn create_fork(mut fork: CreateFork) -> eyre::Result<(ForkId, CreatedFork, .maybe_initial_backoff(fork.evm_opts.fork_retry_backoff) .maybe_headers(fork.evm_opts.fork_headers.clone()) .compute_units_per_second(fork.evm_opts.get_compute_units_per_second()) + .accept_invalid_certs(fork.evm_opts.eth_rpc_accept_invalid_certs) .build()?, ); diff --git a/crates/evm/core/src/opts.rs b/crates/evm/core/src/opts.rs index 0a517d0c77f92..747b241214b21 100644 --- a/crates/evm/core/src/opts.rs +++ b/crates/evm/core/src/opts.rs @@ -82,6 +82,9 @@ pub struct EvmOpts { /// The CREATE2 deployer's address. pub create2_deployer: Address, + + /// Whether to accept invalid certificates for the rpc server. + pub eth_rpc_accept_invalid_certs: bool, } impl Default for EvmOpts { @@ -107,6 +110,7 @@ impl Default for EvmOpts { enable_tx_gas_limit: false, networks: NetworkConfigs::default(), create2_deployer: DEFAULT_CREATE2_DEPLOYER, + eth_rpc_accept_invalid_certs: false, } } } @@ -129,6 +133,7 @@ impl EvmOpts { pub async fn fork_evm_env(&self, fork_url: &str) -> eyre::Result<(crate::Env, AnyRpcBlock)> { let provider = ProviderBuilder::new(fork_url) .compute_units_per_second(self.get_compute_units_per_second()) + .accept_invalid_certs(self.eth_rpc_accept_invalid_certs) .build()?; environment( &provider, diff --git a/crates/script/src/broadcast.rs b/crates/script/src/broadcast.rs index f62387e532d52..6479fe3a104e5 100644 --- a/crates/script/src/broadcast.rs +++ b/crates/script/src/broadcast.rs @@ -17,10 +17,10 @@ use alloy_serde::WithOtherFields; use eyre::{Context, Result, bail}; use forge_verify::provider::VerificationProviderType; use foundry_cheatcodes::Wallets; -use foundry_cli::utils::{has_batch_support, has_different_gas_calc}; +use foundry_cli::utils::{get_provider_url, has_batch_support, has_different_gas_calc}; use foundry_common::{ TransactionMaybeSigned, - provider::{RetryProvider, get_http_provider, try_get_http_provider}, + provider::{RetryProvider}, shell, }; use foundry_config::Config; @@ -49,8 +49,9 @@ pub async fn next_nonce( caller: Address, provider_url: &str, block_number: Option, + config: &Config, ) -> eyre::Result { - let provider = try_get_http_provider(provider_url) + let provider = get_provider_url(config, provider_url) .wrap_err_with(|| format!("bad fork_url provider: {provider_url}"))?; let block_id = block_number.map_or(BlockId::latest(), BlockId::number); @@ -185,6 +186,7 @@ impl BundledState { pub async fn wait_for_pending(mut self) -> Result { let progress = ScriptProgress::default(); let progress_ref = &progress; + let config = &self.script_config.config.clone(); let futs = self .sequence .sequences_mut() @@ -192,7 +194,7 @@ impl BundledState { .enumerate() .map(|(sequence_idx, sequence)| async move { let rpc_url = sequence.rpc_url(); - let provider = Arc::new(get_http_provider(rpc_url)); + let provider = Arc::new(get_provider_url(config, rpc_url)?); progress_ref .wait_for_pending( sequence_idx, @@ -268,7 +270,7 @@ impl BundledState { for i in 0..self.sequence.sequences().len() { let mut sequence = self.sequence.sequences_mut().get_mut(i).unwrap(); - let provider = Arc::new(try_get_http_provider(sequence.rpc_url())?); + let provider = Arc::new(get_provider_url(&self.script_config.config,sequence.rpc_url())?); let already_broadcasted = sequence.receipts.len(); let seq_progress = progress.get_sequence_progress(i, sequence); diff --git a/crates/script/src/build.rs b/crates/script/src/build.rs index 9ee4403923e06..c092fdd531977 100644 --- a/crates/script/src/build.rs +++ b/crates/script/src/build.rs @@ -7,8 +7,9 @@ use alloy_provider::Provider; use eyre::{OptionExt, Result}; use forge_script_sequence::ScriptSequence; use foundry_cheatcodes::Wallets; +use foundry_cli::utils::{get_provider_url}; use foundry_common::{ - ContractData, ContractsByArtifact, compile::ProjectCompiler, provider::try_get_http_provider, + ContractData, ContractsByArtifact, compile::ProjectCompiler, }; use foundry_compilers::{ ArtifactId, ProjectCompileOutput, @@ -42,7 +43,7 @@ impl BuildData { pub async fn link(self, script_config: &ScriptConfig) -> Result { let create2_deployer = script_config.evm_opts.create2_deployer; let can_use_create2 = if let Some(fork_url) = &script_config.evm_opts.fork_url { - let provider = try_get_http_provider(fork_url)?; + let provider = get_provider_url(&script_config.config,fork_url)?; let deployer_code = provider.get_code_at(create2_deployer).await?; !deployer_code.is_empty() @@ -260,7 +261,7 @@ impl CompiledState { None } else { let fork_url = self.script_config.evm_opts.fork_url.clone().ok_or_eyre("Missing --fork-url field, if you were trying to broadcast a multi-chain sequence, please use --multi flag")?; - let provider = Arc::new(try_get_http_provider(fork_url)?); + let provider = Arc::new(get_provider_url(&self.script_config.config, &fork_url)?); Some(provider.get_chain_id().await?) }; diff --git a/crates/script/src/execute.rs b/crates/script/src/execute.rs index 06a665b86823a..75f104356b7ce 100644 --- a/crates/script/src/execute.rs +++ b/crates/script/src/execute.rs @@ -14,13 +14,12 @@ use alloy_provider::Provider; use alloy_rpc_types::TransactionInput; use eyre::{OptionExt, Result}; use foundry_cheatcodes::Wallets; -use foundry_cli::utils::{ensure_clean_constructor, needs_setup}; +use foundry_cli::utils::{ensure_clean_constructor, get_provider_url, needs_setup}; use foundry_common::{ ContractsByArtifact, fmt::{format_token, format_token_raw}, - provider::get_http_provider, }; -use foundry_config::NamedChain; +use foundry_config::{Config, NamedChain}; use foundry_debugger::Debugger; use foundry_evm::{ decode::decode_console_logs, @@ -234,9 +233,9 @@ impl RpcData { } /// Checks if all RPCs support EIP-3855. Prints a warning if not. - async fn check_shanghai_support(&self) -> Result<()> { + async fn check_shanghai_support(&self, config: &Config) -> Result<()> { let chain_ids = self.total_rpcs.iter().map(|rpc| async move { - let provider = get_http_provider(rpc); + let provider = get_provider_url(config, rpc).unwrap(); let id = provider.get_chain_id().await.ok()?; NamedChain::try_from(id).ok() }); @@ -307,7 +306,7 @@ impl ExecutedState { ) } } - rpc_data.check_shanghai_support().await?; + rpc_data.check_shanghai_support(&self.script_config.config).await?; Ok(PreSimulationState { args: self.args, diff --git a/crates/script/src/lib.rs b/crates/script/src/lib.rs index 6a90aef307c19..b29e6ce633b15 100644 --- a/crates/script/src/lib.rs +++ b/crates/script/src/lib.rs @@ -234,6 +234,7 @@ impl ScriptArgs { if let Some(sender) = self.maybe_load_private_key()? { evm_opts.sender = sender; } + evm_opts.eth_rpc_accept_invalid_certs = config.eth_rpc_accept_invalid_certs; let script_config = ScriptConfig::new(config, evm_opts).await?; @@ -243,7 +244,6 @@ impl ScriptArgs { /// Executes the script pub async fn run_script(self) -> Result<()> { trace!(target: "script", "executing script command"); - let state = self.preprocess().await?; let create2_deployer = state.script_config.evm_opts.create2_deployer; let compiled = state.compile()?; @@ -584,7 +584,7 @@ pub struct ScriptConfig { impl ScriptConfig { pub async fn new(config: Config, evm_opts: EvmOpts) -> Result { let sender_nonce = if let Some(fork_url) = evm_opts.fork_url.as_ref() { - next_nonce(evm_opts.sender, fork_url, evm_opts.fork_block_number).await? + next_nonce(evm_opts.sender, fork_url, evm_opts.fork_block_number, &config).await? } else { // dapptools compatibility 1 @@ -595,7 +595,7 @@ impl ScriptConfig { pub async fn update_sender(&mut self, sender: Address) -> Result<()> { self.sender_nonce = if let Some(fork_url) = self.evm_opts.fork_url.as_ref() { - next_nonce(sender, fork_url, None).await? + next_nonce(sender, fork_url, None, &self.config).await? } else { // dapptools compatibility 1 diff --git a/crates/script/src/providers.rs b/crates/script/src/providers.rs index 2252010f43d3d..7828f1d0dafe7 100644 --- a/crates/script/src/providers.rs +++ b/crates/script/src/providers.rs @@ -1,8 +1,9 @@ use alloy_primitives::map::{HashMap, hash_map::Entry}; use alloy_provider::{Provider, utils::Eip1559Estimation}; use eyre::{Result, WrapErr}; -use foundry_common::provider::{RetryProvider, get_http_provider}; -use foundry_config::Chain; +use foundry_cli::utils::get_provider_url; +use foundry_common::provider::{RetryProvider}; +use foundry_config::{Chain, Config}; use std::{ops::Deref, sync::Arc}; /// Contains a map of RPC urls to single instances of [`ProviderInfo`]. @@ -17,11 +18,12 @@ impl ProvidersManager { &mut self, rpc: &str, is_legacy: bool, + config: &Config, ) -> Result<&ProviderInfo> { Ok(match self.inner.entry(rpc.to_string()) { Entry::Occupied(entry) => entry.into_mut(), Entry::Vacant(entry) => { - let info = ProviderInfo::new(rpc, is_legacy).await?; + let info = ProviderInfo::new(rpc, is_legacy, config).await?; entry.insert(info) } }) @@ -52,8 +54,8 @@ pub enum GasPrice { } impl ProviderInfo { - pub async fn new(rpc: &str, mut is_legacy: bool) -> Result { - let provider = Arc::new(get_http_provider(rpc)); + pub async fn new(rpc: &str, mut is_legacy: bool, config: &Config) -> Result { + let provider = Arc::new(get_provider_url(config, rpc).unwrap()); let chain = provider.get_chain_id().await?; if let Some(chain) = Chain::from(chain).named() { diff --git a/crates/script/src/simulate.rs b/crates/script/src/simulate.rs index 354b4a3dabdf8..d4ea1914457ec 100644 --- a/crates/script/src/simulate.rs +++ b/crates/script/src/simulate.rs @@ -283,7 +283,7 @@ impl FilledTransactionsState { while let Some(mut tx) = txes_iter.next() { let tx_rpc = tx.rpc.to_owned(); - let provider_info = manager.get_or_init_provider(&tx.rpc, self.args.legacy).await?; + let provider_info = manager.get_or_init_provider(&tx.rpc, self.args.legacy, &self.script_config.config).await?; if let Some(tx) = tx.tx_mut().as_unsigned_mut() { // Handles chain specific requirements for unsigned transactions. diff --git a/crates/test-utils/src/script.rs b/crates/test-utils/src/script.rs index 2dfd11986d13c..2727d701ad2b8 100644 --- a/crates/test-utils/src/script.rs +++ b/crates/test-utils/src/script.rs @@ -64,7 +64,7 @@ impl ScriptTester { let mut provider = None; if let Some(endpoint) = endpoint { - provider = Some(get_http_provider(endpoint)) + provider = Some(get_http_provider(endpoint, false)) } Self {