Skip to content

Commit 097f72e

Browse files
committed
Merge branch 'master' into warn-unknown-key
2 parents 42df5d6 + f891afd commit 097f72e

File tree

8 files changed

+157
-87
lines changed

8 files changed

+157
-87
lines changed

Cargo.lock

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -344,8 +344,8 @@ semver = "1"
344344
serde = { version = "1.0", features = ["derive"] }
345345
serde_json = { version = "1.0", features = ["arbitrary_precision"] }
346346
similar-asserts = "1.7"
347-
soldeer-commands = "=0.7.1"
348-
soldeer-core = { version = "=0.7.1", features = ["serde"] }
347+
soldeer-commands = "=0.8.0"
348+
soldeer-core = { version = "=0.8.0", features = ["serde"] }
349349
strum = "0.27"
350350
tempfile = "3.20"
351351
tokio = "1"

crates/anvil/src/eth/backend/mem/mod.rs

Lines changed: 97 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -113,15 +113,15 @@ use op_alloy_consensus::DEPOSIT_TX_TYPE_ID;
113113
use op_revm::{
114114
OpContext, OpHaltReason, OpTransaction, transaction::deposit::DepositTransactionParts,
115115
};
116-
use parking_lot::{Mutex, RwLock};
116+
use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard};
117117
use revm::{
118118
DatabaseCommit, Inspector,
119119
context::{Block as RevmBlock, BlockEnv, Cfg, TxEnv},
120120
context_interface::{
121121
block::BlobExcessGasAndPrice,
122122
result::{ExecutionResult, Output, ResultAndState},
123123
},
124-
database::{CacheDB, WrapDatabaseRef},
124+
database::{CacheDB, DbAccount, WrapDatabaseRef},
125125
interpreter::InstructionResult,
126126
precompile::{PrecompileSpecId, Precompiles},
127127
primitives::{KECCAK_EMPTY, hardfork::SpecId},
@@ -2465,19 +2465,16 @@ impl Backend {
24652465
.block_by_number(BlockNumber::Number(block_number))
24662466
.await?
24672467
.map(|block| (block.header.hash, block))
2468-
&& let Some(state) = self.states.write().get(&block_hash)
24692468
{
2470-
let block = BlockEnv {
2471-
number: U256::from(block_number),
2472-
beneficiary: block.header.beneficiary,
2473-
timestamp: U256::from(block.header.timestamp),
2474-
difficulty: block.header.difficulty,
2475-
prevrandao: block.header.mix_hash,
2476-
basefee: block.header.base_fee_per_gas.unwrap_or_default(),
2477-
gas_limit: block.header.gas_limit,
2478-
..Default::default()
2479-
};
2480-
return Ok(f(Box::new(state), block));
2469+
let read_guard = self.states.upgradable_read();
2470+
if let Some(state_db) = read_guard.get_state(&block_hash) {
2471+
return Ok(get_block_env(state_db, block_number, block, f));
2472+
} else {
2473+
let mut write_guard = RwLockUpgradableReadGuard::upgrade(read_guard);
2474+
if let Some(state) = write_guard.get_on_disk_state(&block_hash) {
2475+
return Ok(get_block_env(state, block_number, block, f));
2476+
}
2477+
}
24812478
}
24822479

24832480
warn!(target: "backend", "Not historic state found for block={}", block_number);
@@ -2716,57 +2713,67 @@ impl Backend {
27162713
})
27172714
.collect();
27182715

2719-
let mut states = self.states.write();
2720-
let parent_state =
2721-
states.get(&block.header.parent_hash).ok_or(BlockchainError::BlockNotFound)?;
2722-
let mut cache_db = CacheDB::new(Box::new(parent_state));
2716+
let trace = |parent_state: &StateDb| -> Result<T, BlockchainError> {
2717+
let mut cache_db = CacheDB::new(Box::new(parent_state));
27232718

2724-
// configure the blockenv for the block of the transaction
2725-
let mut env = self.env.read().clone();
2719+
// configure the blockenv for the block of the transaction
2720+
let mut env = self.env.read().clone();
27262721

2727-
env.evm_env.block_env = BlockEnv {
2728-
number: U256::from(block.header.number),
2729-
beneficiary: block.header.beneficiary,
2730-
timestamp: U256::from(block.header.timestamp),
2731-
difficulty: block.header.difficulty,
2732-
prevrandao: Some(block.header.mix_hash),
2733-
basefee: block.header.base_fee_per_gas.unwrap_or_default(),
2734-
gas_limit: block.header.gas_limit,
2735-
..Default::default()
2736-
};
2722+
env.evm_env.block_env = BlockEnv {
2723+
number: U256::from(block.header.number),
2724+
beneficiary: block.header.beneficiary,
2725+
timestamp: U256::from(block.header.timestamp),
2726+
difficulty: block.header.difficulty,
2727+
prevrandao: Some(block.header.mix_hash),
2728+
basefee: block.header.base_fee_per_gas.unwrap_or_default(),
2729+
gas_limit: block.header.gas_limit,
2730+
..Default::default()
2731+
};
27372732

2738-
let executor = TransactionExecutor {
2739-
db: &mut cache_db,
2740-
validator: self,
2741-
pending: pool_txs.into_iter(),
2742-
block_env: env.evm_env.block_env.clone(),
2743-
cfg_env: env.evm_env.cfg_env.clone(),
2744-
parent_hash: block.header.parent_hash,
2745-
gas_used: 0,
2746-
blob_gas_used: 0,
2747-
enable_steps_tracing: self.enable_steps_tracing,
2748-
print_logs: self.print_logs,
2749-
print_traces: self.print_traces,
2750-
call_trace_decoder: self.call_trace_decoder.clone(),
2751-
precompile_factory: self.precompile_factory.clone(),
2752-
networks: self.env.read().networks,
2753-
blob_params: self.blob_params(),
2754-
cheats: self.cheats().clone(),
2755-
};
2733+
let executor = TransactionExecutor {
2734+
db: &mut cache_db,
2735+
validator: self,
2736+
pending: pool_txs.into_iter(),
2737+
block_env: env.evm_env.block_env.clone(),
2738+
cfg_env: env.evm_env.cfg_env.clone(),
2739+
parent_hash: block.header.parent_hash,
2740+
gas_used: 0,
2741+
blob_gas_used: 0,
2742+
enable_steps_tracing: self.enable_steps_tracing,
2743+
print_logs: self.print_logs,
2744+
print_traces: self.print_traces,
2745+
call_trace_decoder: self.call_trace_decoder.clone(),
2746+
precompile_factory: self.precompile_factory.clone(),
2747+
networks: self.env.read().networks,
2748+
blob_params: self.blob_params(),
2749+
cheats: self.cheats().clone(),
2750+
};
27562751

2757-
let _ = executor.execute();
2752+
let _ = executor.execute();
27582753

2759-
let target_tx = block.transactions[index].clone();
2760-
let target_tx = PendingTransaction::from_maybe_impersonated(target_tx)?;
2761-
let tx_env = target_tx.to_revm_tx_env();
2754+
let target_tx = block.transactions[index].clone();
2755+
let target_tx = PendingTransaction::from_maybe_impersonated(target_tx)?;
2756+
let tx_env = target_tx.to_revm_tx_env();
27622757

2763-
let mut evm = self.new_evm_with_inspector_ref(&cache_db, &env, &mut inspector);
2758+
let mut evm = self.new_evm_with_inspector_ref(&cache_db, &env, &mut inspector);
27642759

2765-
let result = evm
2766-
.transact(tx_env.clone())
2767-
.map_err(|err| BlockchainError::Message(err.to_string()))?;
2760+
let result = evm
2761+
.transact(tx_env.clone())
2762+
.map_err(|err| BlockchainError::Message(err.to_string()))?;
2763+
2764+
Ok(f(result, cache_db, inspector, tx_env.base, env))
2765+
};
27682766

2769-
Ok(f(result, cache_db, inspector, tx_env.base, env))
2767+
let read_guard = self.states.upgradable_read();
2768+
if let Some(state) = read_guard.get_state(&block.header.parent_hash) {
2769+
trace(state)
2770+
} else {
2771+
let mut write_guard = RwLockUpgradableReadGuard::upgrade(read_guard);
2772+
let state = write_guard
2773+
.get_on_disk_state(&block.header.parent_hash)
2774+
.ok_or(BlockchainError::BlockNotFound)?;
2775+
trace(state)
2776+
}
27702777
}
27712778

27722779
/// Traces the transaction with the js tracer
@@ -3451,12 +3458,22 @@ impl Backend {
34513458
pub async fn rollback(&self, common_block: Block) -> Result<(), BlockchainError> {
34523459
// Get the database at the common block
34533460
let common_state = {
3454-
let mut state = self.states.write();
3455-
let state_db = state
3456-
.get(&common_block.header.hash_slow())
3457-
.ok_or(BlockchainError::DataUnavailable)?;
3458-
let db_full = state_db.maybe_as_full_db().ok_or(BlockchainError::DataUnavailable)?;
3459-
db_full.clone()
3461+
let return_state_or_throw_err =
3462+
|db: Option<&StateDb>| -> Result<HashMap<Address, DbAccount>, BlockchainError> {
3463+
let state_db = db.ok_or(BlockchainError::DataUnavailable)?;
3464+
let db_full =
3465+
state_db.maybe_as_full_db().ok_or(BlockchainError::DataUnavailable)?;
3466+
Ok(db_full.clone())
3467+
};
3468+
3469+
let hash = &common_block.header.hash_slow();
3470+
let read_guard = self.states.upgradable_read();
3471+
if let Some(db) = read_guard.get_state(hash) {
3472+
return_state_or_throw_err(Some(db))?
3473+
} else {
3474+
let mut write_guard = RwLockUpgradableReadGuard::upgrade(read_guard);
3475+
return_state_or_throw_err(write_guard.get_on_disk_state(hash))?
3476+
}
34603477
};
34613478

34623479
{
@@ -3491,6 +3508,23 @@ impl Backend {
34913508
}
34923509
}
34933510

3511+
fn get_block_env<F, T>(state: &StateDb, block_number: u64, block: AnyRpcBlock, f: F) -> T
3512+
where
3513+
F: FnOnce(Box<dyn MaybeFullDatabase + '_>, BlockEnv) -> T,
3514+
{
3515+
let block = BlockEnv {
3516+
number: U256::from(block_number),
3517+
beneficiary: block.header.beneficiary,
3518+
timestamp: U256::from(block.header.timestamp),
3519+
difficulty: block.header.difficulty,
3520+
prevrandao: block.header.mix_hash,
3521+
basefee: block.header.base_fee_per_gas.unwrap_or_default(),
3522+
gas_limit: block.header.gas_limit,
3523+
..Default::default()
3524+
};
3525+
f(Box::new(state), block)
3526+
}
3527+
34943528
/// Get max nonce from transaction pool by address.
34953529
fn get_pool_transactions_nonce(
34963530
pool_transactions: &[Arc<PoolTransaction>],

crates/anvil/src/eth/backend/mem/storage.rs

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -165,17 +165,21 @@ impl InMemoryBlockStates {
165165
}
166166
}
167167

168-
/// Returns the state for the given `hash` if present
169-
pub fn get(&mut self, hash: &B256) -> Option<&StateDb> {
170-
self.states.get(hash).or_else(|| {
171-
if let Some(state) = self.on_disk_states.get_mut(hash)
172-
&& let Some(cached) = self.disk_cache.read(*hash)
173-
{
174-
state.init_from_state_snapshot(cached);
175-
return Some(state);
176-
}
177-
None
178-
})
168+
/// Returns the in-memory state for the given `hash` if present
169+
pub fn get_state(&self, hash: &B256) -> Option<&StateDb> {
170+
self.states.get(hash)
171+
}
172+
173+
/// Returns on-disk state for the given `hash` if present
174+
pub fn get_on_disk_state(&mut self, hash: &B256) -> Option<&StateDb> {
175+
if let Some(state) = self.on_disk_states.get_mut(hash)
176+
&& let Some(cached) = self.disk_cache.read(*hash)
177+
{
178+
state.init_from_state_snapshot(cached);
179+
return Some(state);
180+
}
181+
182+
None
179183
}
180184

181185
/// Sets the maximum number of stats we keep in memory
@@ -619,7 +623,7 @@ mod tests {
619623
assert_eq!(storage.on_disk_states.len(), 1);
620624
assert!(storage.on_disk_states.contains_key(&one));
621625

622-
let loaded = storage.get(&one).unwrap();
626+
let loaded = storage.get_on_disk_state(&one).unwrap();
623627

624628
let acc = loaded.basic_ref(addr).unwrap().unwrap();
625629
assert_eq!(acc.balance, U256::from(1337u64));
@@ -644,13 +648,21 @@ mod tests {
644648
// wait for files to be flushed
645649
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
646650

647-
assert_eq!(storage.on_disk_states.len(), num_states - storage.min_in_memory_limit);
651+
let on_disk_states_len = num_states - storage.min_in_memory_limit;
652+
653+
assert_eq!(storage.on_disk_states.len(), on_disk_states_len);
648654
assert_eq!(storage.present.len(), storage.min_in_memory_limit);
649655

650656
for idx in 0..num_states {
651657
let hash = B256::from(U256::from(idx));
652658
let addr = Address::from_word(hash);
653-
let loaded = storage.get(&hash).unwrap();
659+
660+
let loaded = if idx < on_disk_states_len {
661+
storage.get_on_disk_state(&hash).unwrap()
662+
} else {
663+
storage.get_state(&hash).unwrap()
664+
};
665+
654666
let acc = loaded.basic_ref(addr).unwrap().unwrap();
655667
let balance = (idx * 2) as u64;
656668
assert_eq!(acc.balance, U256::from(balance));

crates/common/src/fs.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,9 @@ pub fn write_json_gzip_file<T: Serialize>(path: &Path, obj: &T) -> Result<()> {
109109
let mut encoder = GzEncoder::new(writer, Compression::default());
110110
serde_json::to_writer(&mut encoder, obj)
111111
.map_err(|source| FsPathError::WriteJson { source, path: path.into() })?;
112-
encoder
113-
.finish()
114-
.map_err(serde_json::Error::io)
115-
.map_err(|source| FsPathError::WriteJson { source, path: path.into() })?;
112+
// Ensure we surface any I/O errors on final gzip write and buffer flush.
113+
let mut inner_writer = encoder.finish().map_err(|e| FsPathError::write(e, path))?;
114+
inner_writer.flush().map_err(|e| FsPathError::write(e, path))?;
116115
Ok(())
117116
}
118117

crates/config/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -679,6 +679,9 @@ impl Config {
679679
/// TOML section for profiles
680680
pub const PROFILE_SECTION: &'static str = "profile";
681681

682+
/// External config sections, ignored from warnings.
683+
pub const EXTERNAL_SECTION: &'static str = "external";
684+
682685
/// Standalone sections in the config which get integrated into the selected profile
683686
pub const STANDALONE_SECTIONS: &'static [&'static str] = &[
684687
"rpc_endpoints",

crates/config/src/providers/warnings.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ impl<P: Provider> WarningsProvider<P> {
4949
data.keys()
5050
.filter(|k| {
5151
**k != Config::PROFILE_SECTION
52+
&& **k != Config::EXTERNAL_SECTION
5253
&& !Config::STANDALONE_SECTIONS.iter().any(|s| s == k)
5354
})
5455
.map(|unknown_section| {

crates/forge/tests/cli/config.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1925,6 +1925,27 @@ Warning: Key `deny_warnings` is being deprecated in favor of `deny = warnings`.
19251925
"#]]);
19261926
});
19271927

1928+
// <https://github.com/foundry-rs/foundry/issues/5866>
1929+
forgetest!(no_warnings_on_external_sections, |prj, cmd| {
1930+
cmd.git_init();
1931+
1932+
let toml = r"[profile.default]
1933+
src = 'src'
1934+
out = 'out'
1935+
1936+
# Custom sections for other tools
1937+
[external.scopelint]
1938+
some_flag = 1
1939+
1940+
[external.forge_deploy]
1941+
another_setting = 123";
1942+
1943+
fs::write(prj.root().join("foundry.toml"), toml).unwrap();
1944+
cmd.forge_fuse().args(["config"]).assert_success().stderr_eq(str![[r#"
1945+
1946+
"#]]);
1947+
});
1948+
19281949
// <https://github.com/foundry-rs/foundry/issues/10550>
19291950
forgetest!(config_warnings_on_unknown_keys, |prj, cmd| {
19301951
cmd.git_init();

0 commit comments

Comments
 (0)