Skip to content

Commit 2c9719e

Browse files
authored
chore(anvil): convert panics into errors (#9471)
1 parent 8ac30d9 commit 2c9719e

File tree

5 files changed

+93
-90
lines changed

5 files changed

+93
-90
lines changed

crates/anvil/src/cmd.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,8 @@ pub struct NodeArgs {
8989
pub slots_in_an_epoch: u64,
9090

9191
/// Writes output of `anvil` as json to user-specified file.
92-
#[arg(long, value_name = "OUT_FILE")]
93-
pub config_out: Option<String>,
92+
#[arg(long, value_name = "FILE", value_hint = clap::ValueHint::FilePath)]
93+
pub config_out: Option<PathBuf>,
9494

9595
/// Disable auto and interval mining, and mine on demand instead.
9696
#[arg(long, visible_alias = "no-mine", conflicts_with = "block_time")]

crates/anvil/src/config.rs

Lines changed: 66 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use alloy_signer_local::{
2828
};
2929
use alloy_transport::{Transport, TransportError};
3030
use anvil_server::ServerConfig;
31-
use eyre::Result;
31+
use eyre::{Context, Result};
3232
use foundry_common::{
3333
provider::{ProviderBuilder, RetryProvider},
3434
ALCHEMY_FREE_TIER_CUPS, NON_ARCHIVE_NODE_WARNING, REQUEST_TIMEOUT,
@@ -44,15 +44,17 @@ use itertools::Itertools;
4444
use parking_lot::RwLock;
4545
use rand::thread_rng;
4646
use revm::primitives::BlobExcessGasAndPrice;
47-
use serde_json::{json, to_writer, Value};
47+
use serde_json::{json, Value};
4848
use std::{
4949
fmt::Write as FmtWrite,
5050
fs::File,
51+
io,
5152
net::{IpAddr, Ipv4Addr},
5253
path::{Path, PathBuf},
5354
sync::Arc,
5455
time::Duration,
5556
};
57+
use tokio::sync::RwLock as TokioRwLock;
5658
use yansi::Paint;
5759

5860
/// Default port the rpc will open
@@ -144,7 +146,7 @@ pub struct NodeConfig {
144146
/// How transactions are sorted in the mempool
145147
pub transaction_order: TransactionOrder,
146148
/// Filename to write anvil output as json
147-
pub config_out: Option<String>,
149+
pub config_out: Option<PathBuf>,
148150
/// The genesis to use to initialize the node
149151
pub genesis: Option<Genesis>,
150152
/// Timeout in for requests sent to remote JSON-RPC server in forking mode
@@ -195,13 +197,13 @@ pub struct NodeConfig {
195197

196198
impl NodeConfig {
197199
fn as_string(&self, fork: Option<&ClientFork>) -> String {
198-
let mut config_string: String = String::new();
199-
let _ = write!(config_string, "\n{}", BANNER.green());
200-
let _ = write!(config_string, "\n {VERSION_MESSAGE}");
201-
let _ = write!(config_string, "\n {}", "https://github.com/foundry-rs/foundry".green());
200+
let mut s: String = String::new();
201+
let _ = write!(s, "\n{}", BANNER.green());
202+
let _ = write!(s, "\n {VERSION_MESSAGE}");
203+
let _ = write!(s, "\n {}", "https://github.com/foundry-rs/foundry".green());
202204

203205
let _ = write!(
204-
config_string,
206+
s,
205207
r#"
206208
207209
Available Accounts
@@ -210,11 +212,11 @@ Available Accounts
210212
);
211213
let balance = alloy_primitives::utils::format_ether(self.genesis_balance);
212214
for (idx, wallet) in self.genesis_accounts.iter().enumerate() {
213-
write!(config_string, "\n({idx}) {} ({balance} ETH)", wallet.address()).unwrap();
215+
write!(s, "\n({idx}) {} ({balance} ETH)", wallet.address()).unwrap();
214216
}
215217

216218
let _ = write!(
217-
config_string,
219+
s,
218220
r#"
219221
220222
Private Keys
@@ -224,12 +226,12 @@ Private Keys
224226

225227
for (idx, wallet) in self.genesis_accounts.iter().enumerate() {
226228
let hex = hex::encode(wallet.credential().to_bytes());
227-
let _ = write!(config_string, "\n({idx}) 0x{hex}");
229+
let _ = write!(s, "\n({idx}) 0x{hex}");
228230
}
229231

230232
if let Some(ref gen) = self.account_generator {
231233
let _ = write!(
232-
config_string,
234+
s,
233235
r#"
234236
235237
Wallet
@@ -244,7 +246,7 @@ Derivation path: {}
244246

245247
if let Some(fork) = fork {
246248
let _ = write!(
247-
config_string,
249+
s,
248250
r#"
249251
250252
Fork
@@ -261,11 +263,11 @@ Chain ID: {}
261263
);
262264

263265
if let Some(tx_hash) = fork.transaction_hash() {
264-
let _ = writeln!(config_string, "Transaction hash: {tx_hash}");
266+
let _ = writeln!(s, "Transaction hash: {tx_hash}");
265267
}
266268
} else {
267269
let _ = write!(
268-
config_string,
270+
s,
269271
r#"
270272
271273
Chain ID
@@ -279,7 +281,7 @@ Chain ID
279281

280282
if (SpecId::from(self.get_hardfork()) as u8) < (SpecId::LONDON as u8) {
281283
let _ = write!(
282-
config_string,
284+
s,
283285
r#"
284286
Gas Price
285287
==================
@@ -290,7 +292,7 @@ Gas Price
290292
);
291293
} else {
292294
let _ = write!(
293-
config_string,
295+
s,
294296
r#"
295297
Base Fee
296298
==================
@@ -302,7 +304,7 @@ Base Fee
302304
}
303305

304306
let _ = write!(
305-
config_string,
307+
s,
306308
r#"
307309
Gas Limit
308310
==================
@@ -326,7 +328,7 @@ Gas Limit
326328
);
327329

328330
let _ = write!(
329-
config_string,
331+
s,
330332
r#"
331333
Genesis Timestamp
332334
==================
@@ -336,7 +338,7 @@ Genesis Timestamp
336338
self.get_genesis_timestamp().green()
337339
);
338340

339-
config_string
341+
s
340342
}
341343

342344
fn as_json(&self, fork: Option<&ClientFork>) -> Value {
@@ -749,7 +751,7 @@ impl NodeConfig {
749751

750752
/// Sets the file path to write the Anvil node's config info to.
751753
#[must_use]
752-
pub fn set_config_out(mut self, config_out: Option<String>) -> Self {
754+
pub fn set_config_out(mut self, config_out: Option<PathBuf>) -> Self {
753755
self.config_out = config_out;
754756
self
755757
}
@@ -903,21 +905,18 @@ impl NodeConfig {
903905
}
904906

905907
/// Prints the config info
906-
pub fn print(&self, fork: Option<&ClientFork>) {
907-
if self.config_out.is_some() {
908-
let config_out = self.config_out.as_deref().unwrap();
909-
to_writer(
910-
&File::create(config_out).expect("Unable to create anvil config description file"),
911-
&self.as_json(fork),
912-
)
913-
.expect("Failed writing json");
908+
pub fn print(&self, fork: Option<&ClientFork>) -> Result<()> {
909+
if let Some(path) = &self.config_out {
910+
let file = io::BufWriter::new(
911+
File::create(path).wrap_err("unable to create anvil config description file")?,
912+
);
913+
let value = self.as_json(fork);
914+
serde_json::to_writer(file, &value).wrap_err("failed writing JSON")?;
914915
}
915-
916-
if self.silent {
917-
return;
916+
if !self.silent {
917+
sh_println!("{}", self.as_string(fork))?;
918918
}
919-
920-
let _ = sh_println!("{}", self.as_string(fork));
919+
Ok(())
921920
}
922921

923922
/// Returns the path where the cache file should be stored
@@ -983,7 +982,7 @@ impl NodeConfig {
983982
/// [Backend](mem::Backend)
984983
///
985984
/// *Note*: only memory based backend for now
986-
pub(crate) async fn setup(&mut self) -> mem::Backend {
985+
pub(crate) async fn setup(&mut self) -> Result<mem::Backend> {
987986
// configure the revm environment
988987

989988
let mut cfg =
@@ -1020,11 +1019,11 @@ impl NodeConfig {
10201019
self.get_blob_excess_gas_and_price(),
10211020
);
10221021

1023-
let (db, fork): (Arc<tokio::sync::RwLock<Box<dyn Db>>>, Option<ClientFork>) =
1022+
let (db, fork): (Arc<TokioRwLock<Box<dyn Db>>>, Option<ClientFork>) =
10241023
if let Some(eth_rpc_url) = self.eth_rpc_url.clone() {
1025-
self.setup_fork_db(eth_rpc_url, &mut env, &fees).await
1024+
self.setup_fork_db(eth_rpc_url, &mut env, &fees).await?
10261025
} else {
1027-
(Arc::new(tokio::sync::RwLock::new(Box::<MemDb>::default())), None)
1026+
(Arc::new(TokioRwLock::new(Box::<MemDb>::default())), None)
10281027
};
10291028

10301029
// if provided use all settings of `genesis.json`
@@ -1062,29 +1061,29 @@ impl NodeConfig {
10621061
self.transaction_block_keeper,
10631062
self.block_time,
10641063
self.cache_path.clone(),
1065-
Arc::new(tokio::sync::RwLock::new(self.clone())),
1064+
Arc::new(TokioRwLock::new(self.clone())),
10661065
)
1067-
.await;
1066+
.await?;
10681067

10691068
// Writes the default create2 deployer to the backend,
10701069
// if the option is not disabled and we are not forking.
10711070
if !self.disable_default_create2_deployer && self.eth_rpc_url.is_none() {
10721071
backend
10731072
.set_create2_deployer(DEFAULT_CREATE2_DEPLOYER)
10741073
.await
1075-
.expect("Failed to create default create2 deployer");
1074+
.wrap_err("failed to create default create2 deployer")?;
10761075
}
10771076

10781077
if let Some(state) = self.init_state.clone() {
1079-
backend.load_state(state).await.expect("Failed to load init state");
1078+
backend.load_state(state).await.wrap_err("failed to load init state")?;
10801079
}
10811080

1082-
backend
1081+
Ok(backend)
10831082
}
10841083

10851084
/// Configures everything related to forking based on the passed `eth_rpc_url`:
1086-
/// - returning a tuple of a [ForkedDatabase] wrapped in an [Arc] [RwLock](tokio::sync::RwLock)
1087-
/// and [ClientFork] wrapped in an [Option] which can be used in a [Backend](mem::Backend) to
1085+
/// - returning a tuple of a [ForkedDatabase] wrapped in an [Arc] [RwLock](TokioRwLock) and
1086+
/// [ClientFork] wrapped in an [Option] which can be used in a [Backend](mem::Backend) to
10881087
/// fork from.
10891088
/// - modifying some parameters of the passed `env`
10901089
/// - mutating some members of `self`
@@ -1093,15 +1092,11 @@ impl NodeConfig {
10931092
eth_rpc_url: String,
10941093
env: &mut EnvWithHandlerCfg,
10951094
fees: &FeeManager,
1096-
) -> (Arc<tokio::sync::RwLock<Box<dyn Db>>>, Option<ClientFork>) {
1097-
let (db, config) = self.setup_fork_db_config(eth_rpc_url, env, fees).await;
1098-
1099-
let db: Arc<tokio::sync::RwLock<Box<dyn Db>>> =
1100-
Arc::new(tokio::sync::RwLock::new(Box::new(db)));
1101-
1095+
) -> Result<(Arc<TokioRwLock<Box<dyn Db>>>, Option<ClientFork>)> {
1096+
let (db, config) = self.setup_fork_db_config(eth_rpc_url, env, fees).await?;
1097+
let db: Arc<TokioRwLock<Box<dyn Db>>> = Arc::new(TokioRwLock::new(Box::new(db)));
11021098
let fork = ClientFork::new(config, Arc::clone(&db));
1103-
1104-
(db, Some(fork))
1099+
Ok((db, Some(fork)))
11051100
}
11061101

11071102
/// Configures everything related to forking based on the passed `eth_rpc_url`:
@@ -1114,7 +1109,7 @@ impl NodeConfig {
11141109
eth_rpc_url: String,
11151110
env: &mut EnvWithHandlerCfg,
11161111
fees: &FeeManager,
1117-
) -> (ForkedDatabase, ClientForkConfig) {
1112+
) -> Result<(ForkedDatabase, ClientForkConfig)> {
11181113
// TODO make provider agnostic
11191114
let provider = Arc::new(
11201115
ProviderBuilder::new(&eth_rpc_url)
@@ -1125,23 +1120,22 @@ impl NodeConfig {
11251120
.initial_backoff(1000)
11261121
.headers(self.fork_headers.clone())
11271122
.build()
1128-
.expect("Failed to establish provider to fork url"),
1123+
.wrap_err("failed to establish provider to fork url")?,
11291124
);
11301125

11311126
let (fork_block_number, fork_chain_id, force_transactions) = if let Some(fork_choice) =
11321127
&self.fork_choice
11331128
{
11341129
let (fork_block_number, force_transactions) =
1135-
derive_block_and_transactions(fork_choice, &provider).await.expect(
1136-
"Failed to derive fork block number and force transactions from fork choice",
1137-
);
1130+
derive_block_and_transactions(fork_choice, &provider).await.wrap_err(
1131+
"failed to derive fork block number and force transactions from fork choice",
1132+
)?;
11381133
let chain_id = if let Some(chain_id) = self.fork_chain_id {
11391134
Some(chain_id)
11401135
} else if self.hardfork.is_none() {
1141-
// auto adjust hardfork if not specified
1142-
// but only if we're forking mainnet
1136+
// Auto-adjust hardfork if not specified, but only if we're forking mainnet.
11431137
let chain_id =
1144-
provider.get_chain_id().await.expect("Failed to fetch network chain ID");
1138+
provider.get_chain_id().await.wrap_err("failed to fetch network chain ID")?;
11451139
if alloy_chains::NamedChain::Mainnet == chain_id {
11461140
let hardfork: EthereumHardfork = fork_block_number.into();
11471141
env.handler_cfg.spec_id = hardfork.into();
@@ -1155,15 +1149,16 @@ impl NodeConfig {
11551149
(fork_block_number, chain_id, force_transactions)
11561150
} else {
11571151
// pick the last block number but also ensure it's not pending anymore
1158-
let bn =
1159-
find_latest_fork_block(&provider).await.expect("Failed to get fork block number");
1152+
let bn = find_latest_fork_block(&provider)
1153+
.await
1154+
.wrap_err("failed to get fork block number")?;
11601155
(bn, None, None)
11611156
};
11621157

11631158
let block = provider
11641159
.get_block(BlockNumberOrTag::Number(fork_block_number).into(), false.into())
11651160
.await
1166-
.expect("Failed to get fork block");
1161+
.wrap_err("failed to get fork block")?;
11671162

11681163
let block = if let Some(block) = block {
11691164
block
@@ -1179,9 +1174,9 @@ latest block number: {latest_block}"
11791174
if fork_block_number <= latest_block {
11801175
message.push_str(&format!("\n{NON_ARCHIVE_NODE_WARNING}"));
11811176
}
1182-
panic!("{}", message);
1177+
eyre::bail!("{message}");
11831178
}
1184-
panic!("Failed to get block for block number: {fork_block_number}")
1179+
eyre::bail!("failed to get block for block number: {fork_block_number}")
11851180
};
11861181

11871182
let gas_limit = self.fork_gas_limit(&block);
@@ -1243,7 +1238,7 @@ latest block number: {latest_block}"
12431238
let chain_id = if let Some(fork_chain_id) = fork_chain_id {
12441239
fork_chain_id.to()
12451240
} else {
1246-
provider.get_chain_id().await.unwrap()
1241+
provider.get_chain_id().await.wrap_err("failed to fetch network chain ID")?
12471242
};
12481243

12491244
// need to update the dev signers and env with the chain id
@@ -1296,7 +1291,7 @@ latest block number: {latest_block}"
12961291
// need to insert the forked block's hash
12971292
db.insert_block_hash(U256::from(config.block_number), config.block_hash);
12981293

1299-
(db, config)
1294+
Ok((db, config))
13001295
}
13011296

13021297
/// we only use the gas limit value of the block if it is non-zero and the block gas
@@ -1344,7 +1339,7 @@ async fn derive_block_and_transactions(
13441339
let transaction = provider
13451340
.get_transaction_by_hash(transaction_hash.0.into())
13461341
.await?
1347-
.ok_or(eyre::eyre!("Failed to get fork transaction by hash"))?;
1342+
.ok_or_else(|| eyre::eyre!("failed to get fork transaction by hash"))?;
13481343
let transaction_block_number = transaction.block_number.unwrap();
13491344

13501345
// Get the block pertaining to the fork transaction
@@ -1354,13 +1349,13 @@ async fn derive_block_and_transactions(
13541349
alloy_rpc_types::BlockTransactionsKind::Full,
13551350
)
13561351
.await?
1357-
.ok_or(eyre::eyre!("Failed to get fork block by number"))?;
1352+
.ok_or_else(|| eyre::eyre!("failed to get fork block by number"))?;
13581353

13591354
// Filter out transactions that are after the fork transaction
13601355
let filtered_transactions = transaction_block
13611356
.transactions
13621357
.as_transactions()
1363-
.ok_or(eyre::eyre!("Failed to get transactions from full fork block"))?
1358+
.ok_or_else(|| eyre::eyre!("failed to get transactions from full fork block"))?
13641359
.iter()
13651360
.take_while_inclusive(|&transaction| transaction.tx_hash() != transaction_hash.0)
13661361
.collect::<Vec<_>>();

0 commit comments

Comments
 (0)