From 03032dda656ea48a62551376a4e115e6e1e6e5e8 Mon Sep 17 00:00:00 2001 From: morito Date: Tue, 16 Jul 2024 19:27:56 +0900 Subject: [PATCH] fix(provider): Prevent panic from having 0 keys when calling `on_anvil_with_wallet_and_config` (#1055) * node-bindings: Add AnvilError::NoKeysAvailable * prevent panic from having 0 keys * fix the error handlings for `on_anvil_with_wallet` * fix clippy * fix(clippy): Add type alias * Add `try_on_anvil_with_wallet_and_config` and call it in `on_anvil_with_wallet_and_config` * Revert test changes * Fix docs --- crates/node-bindings/src/anvil.rs | 4 +++ crates/provider/src/builder.rs | 49 +++++++++++++++++++++++++------ 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/crates/node-bindings/src/anvil.rs b/crates/node-bindings/src/anvil.rs index 0928957203c..62903e9c2e7 100644 --- a/crates/node-bindings/src/anvil.rs +++ b/crates/node-bindings/src/anvil.rs @@ -119,6 +119,10 @@ pub enum AnvilError { /// An error occurred while parsing a hex string. #[error(transparent)] FromHexError(#[from] hex::FromHexError), + + /// No keys available in anvil instance. + #[error("no keys available in anvil instance")] + NoKeysAvailable, } /// Builder for launching `anvil`. diff --git a/crates/provider/src/builder.rs b/crates/provider/src/builder.rs index 5105351d75f..3871ac86865 100644 --- a/crates/provider/src/builder.rs +++ b/crates/provider/src/builder.rs @@ -10,7 +10,6 @@ use alloy_chains::NamedChain; use alloy_network::{Ethereum, Network}; use alloy_primitives::ChainId; use alloy_rpc_client::{BuiltInConnectionString, ClientBuilder, RpcClient}; - use alloy_transport::{BoxTransport, Transport, TransportError, TransportResult}; use std::marker::PhantomData; @@ -347,6 +346,11 @@ impl ProviderBuilder { } } +type JoinedEthereumWalletFiller = JoinFill>; + +#[cfg(any(test, feature = "anvil-node"))] +type AnvilProviderResult = Result; + // Enabled when the `anvil` feature is enabled, or when both in test and the // `reqwest` feature is enabled. #[cfg(any(test, feature = "anvil-node"))] @@ -372,7 +376,7 @@ impl ProviderBuilder { /// use in tests. pub fn on_anvil_with_wallet( self, - ) -> > as ProviderLayer< + ) -> as ProviderLayer< L::Provider, alloy_transport_http::Http, >>::Provider @@ -413,17 +417,42 @@ impl ProviderBuilder { self.layer(anvil_layer).on_http(url) } - /// Build this provider with anvil, using an Reqwest HTTP transport. The - /// given function is used to configure the anvil instance. This - /// function configures a wallet backed by anvil keys, and is intended for - /// use in tests. + /// Build this provider with anvil, using an Reqwest HTTP transport. + /// This calls `try_on_anvil_with_wallet_and_config` and panics on error. pub fn on_anvil_with_wallet_and_config( self, f: impl FnOnce(alloy_node_bindings::Anvil) -> alloy_node_bindings::Anvil, - ) -> > as ProviderLayer< + ) -> as ProviderLayer< L::Provider, alloy_transport_http::Http, >>::Provider + where + F: TxFiller + + ProviderLayer, Ethereum>, + L: crate::builder::ProviderLayer< + crate::layers::AnvilProvider< + crate::provider::RootProvider>, + alloy_transport_http::Http, + >, + alloy_transport_http::Http, + >, + { + self.try_on_anvil_with_wallet_and_config(f).unwrap() + } + + /// Build this provider with anvil, using an Reqwest HTTP transport. The + /// given function is used to configure the anvil instance. This + /// function configures a wallet backed by anvil keys, and is intended for + /// use in tests. + pub fn try_on_anvil_with_wallet_and_config( + self, + f: impl FnOnce(alloy_node_bindings::Anvil) -> alloy_node_bindings::Anvil, + ) -> AnvilProviderResult< + as ProviderLayer< + L::Provider, + alloy_transport_http::Http, + >>::Provider, + > where F: TxFiller + ProviderLayer, Ethereum>, @@ -439,7 +468,9 @@ impl ProviderBuilder { let url = anvil_layer.endpoint_url(); let default_keys = anvil_layer.instance().keys().to_vec(); - let (default_key, remaining_keys) = default_keys.split_first().expect("no keys available"); + let (default_key, remaining_keys) = default_keys + .split_first() + .ok_or(alloy_node_bindings::anvil::AnvilError::NoKeysAvailable)?; let default_signer = alloy_signer_local::LocalSigner::from(default_key.clone()); let mut wallet = alloy_network::EthereumWallet::from(default_signer); @@ -448,7 +479,7 @@ impl ProviderBuilder { wallet.register_signer(alloy_signer_local::LocalSigner::from(key.clone())) }); - self.wallet(wallet).layer(anvil_layer).on_http(url) + Ok(self.wallet(wallet).layer(anvil_layer).on_http(url)) } }