Skip to content

Commit eecc6fc

Browse files
authored
chore(deps): bump revm 29->40, alloy-evm 0.21.3->0.36.0 (#108)
## Summary - Bumps `revm` workspace from **29.0.1 -> 40.0.3** and `alloy-evm` from **0.21.3 -> 0.36.0** to align with reth **v2.3.0**. - Continues the migration started in #107 (fork -> crates.io) — all `revm-*` and `alloy-evm` deps now pin crates.io versions, no `Galxe/revm` or `Galxe/alloy-evm` fork references remain. - Bumps MSRV to Rust 1.93 (`revm 40` requires 1.91+; matched to reth v2.3.0's `rust-version = "1.93"`). ## Motivation gravity-reth just landed the reth v2.3.0 squash merge on `gravity-reth-merge-v2.3.0`. Its Cargo.toml now depends on `revm = "40.0.3"` / `revm-inspectors = "0.40.1"` / `alloy-evm = "0.36.0"` (crates.io). grevm was still on `revm 29.0.1` and would have caused a version resolution conflict. ## Version pins | crate | before | after | |---|---|---| | `revm` | Galxe fork `v29.0.1-gravity` | crates.io **40.0.3** | | `revm-database` | Galxe fork | crates.io **15.0.2** | | `revm-state` | Galxe fork | crates.io **12.0.1** | | `revm-primitives` | Galxe fork | crates.io **24.0.1** | | `revm-inspector` | Galxe fork | crates.io **21.0.3** | | `revm-context` | Galxe fork | crates.io **18.0.3** | | `alloy-evm` | Galxe fork `v0.21.3-gravity` | crates.io **0.36.0** | ## API migrations Five main categories of source changes: 1. **State-clear removal.** `CacheState::new()` dropped the `has_state_clear` parameter — revm v40 assumes Spurious Dragon is permanently active. Deleted `ParallelCacheState::has_state_clear` field and the `touch_create_pre_eip161` branch. 2. **`DatabaseCommit::commit` signature.** Now takes `AddressMap<Account>` (with `FbBuildHasher`) instead of `HashMap<Address, Account>`. Updated `EvmState` alias accordingly. 3. **`AccountInfo` new private field.** Added `account_id: Option<AccountId>` — all construction sites use `..Default::default()`. 4. **`BlockEnv::slot_num: u64` added** (EIP-7843 Amsterdam). Test fixtures set to 0. 5. **`ExecutionResult` / precompile / error wrapping.** - `ExecutionResult::Success { gas_used, gas_refunded }` collapsed into `gas: ResultGas`; `.gas_used()` replaced by `.tx_gas_used()`. - `EthPrecompiles::default()` -> `EthPrecompiles::new(spec)`. - `alloy-evm`'s `transact_raw` now returns errors wrapped in `EvmDatabaseError` — `.into_external_error()` unwraps them at call sites. - `Account` gained a private `original_info` field; test construction switched to `Default::default()` + explicit field sets. ## Test plan - [x] `cargo build --locked --all-features --all-targets` — clean - [x] `cargo test --tests --all-features` — **30/30 pass**: - `lib` 4 / `eip-7702` 10 / `erc20` 4 / `mainnet` 2 / `native_transfers` 9 / `uniswap` 1 - [x] `rust-toolchain.toml` bumped to 1.93 (matches gravity-reth workspace)
1 parent 2a42859 commit eecc6fc

11 files changed

Lines changed: 87 additions & 108 deletions

File tree

Cargo.toml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,16 @@ license = "MIT OR Apache-2.0"
99
autobins = false
1010

1111
[dependencies]
12-
# Upstream revm v29.0.1 (no fork). The miner reward is skipped during parallel execution via a
12+
# Upstream revm v40 (no fork). The miner reward is skipped during parallel execution via a
1313
# custom `Handler` (see `scheduler::NoRewardHandler`) and self-computed at commit time, so the
1414
# previous `Galxe/revm` fork (which only added a `lazy_reward` cfg flag + `ResultAndState` field)
1515
# is no longer needed.
16-
revm = { version = "29.0.1", default-features = false }
17-
revm-database = { version = "7.0.5", default-features = false }
18-
revm-state = { version = "7.0.5", default-features = false }
19-
revm-primitives = { version = "20.2.1", default-features = false }
20-
revm-inspector = { version = "10.0.1", default-features = false }
21-
revm-context = { version = "9.1.0", default-features = false }
16+
revm = { version = "40.0.3", default-features = false }
17+
revm-database = { version = "15.0.0", default-features = false }
18+
revm-state = { version = "12.0.0", default-features = false }
19+
revm-primitives = { version = "24.0.0", default-features = false }
20+
revm-inspector = { version = "21.0.3", default-features = false }
21+
revm-context = { version = "18.0.3", default-features = false }
2222

2323
ahash = "0.8"
2424
rayon = "1.10.0"
@@ -27,7 +27,7 @@ parking_lot = "0.12"
2727

2828
# Alloy — upstream (the `Galxe/alloy-evm` fork only repointed revm to the gravity fork and added a
2929
# `..` to one `ResultAndState` destructure; both are unnecessary against upstream revm).
30-
alloy-evm = { version = "0.21.3", default-features = false }
30+
alloy-evm = { version = "0.36.0", default-features = false }
3131

3232
# async
3333
futures = "0.3"

rust-toolchain.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[toolchain]
2-
channel = "1.88.0"
2+
channel = "1.93.0"
33

44
# Note: we don't specify cargofmt in our toolchain because we rely on
55
# the nightly version of cargofmt and verify formatting in CI/CD.

src/async_commit.rs

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ where
8888
} else {
8989
effective_gas_price
9090
};
91-
coinbase_gas_price.saturating_mul(result.gas_used() as u128)
91+
coinbase_gas_price.saturating_mul(result.tx_gas_used() as u128)
9292
}
9393

9494
pub(crate) fn state_mut(&mut self) -> &mut ParallelState<DB> {
@@ -191,38 +191,39 @@ mod tests {
191191
use super::*;
192192
use revm_context::{
193193
either::Either,
194-
result::{Output, SuccessReason},
194+
result::{Output, ResultGas, SuccessReason},
195195
transaction::{Authorization, RecoveredAuthority, RecoveredAuthorization},
196196
};
197197
use revm_database::EmptyDB;
198-
use revm_primitives::{Address, B256, Bytes, HashMap, U256};
199-
use revm_state::{Account, AccountInfo, AccountStatus, EvmStorage};
198+
use revm_primitives::{Address, B256, Bytes, U256};
199+
use revm_state::{Account, AccountInfo, AccountStatus};
200200

201201
fn make_account_info(nonce: u64) -> AccountInfo {
202202
AccountInfo {
203203
balance: U256::from(10u128.pow(18)),
204204
nonce,
205205
code_hash: B256::ZERO,
206206
code: None,
207+
..Default::default()
207208
}
208209
}
209210

211+
fn make_account(info: AccountInfo) -> Account {
212+
// `Account` has private `original_info`; build via Default and set the public fields.
213+
let mut account = Account::default();
214+
account.info = info;
215+
account.status = AccountStatus::Touched;
216+
account
217+
}
218+
210219
fn make_result_and_state(caller: Address, post_nonce: u64) -> ResultAndState {
211-
let mut state: HashMap<Address, Account> = HashMap::default();
212-
state.insert(
213-
caller,
214-
Account {
215-
info: make_account_info(post_nonce),
216-
transaction_id: 0,
217-
storage: EvmStorage::default(),
218-
status: AccountStatus::Touched,
219-
},
220-
);
220+
let mut state: revm_primitives::AddressMap<Account> =
221+
revm_primitives::AddressMap::default();
222+
state.insert(caller, make_account(make_account_info(post_nonce)));
221223
ResultAndState {
222224
result: ExecutionResult::Success {
223225
reason: SuccessReason::Stop,
224-
gas_used: 21_000,
225-
gas_refunded: 0,
226+
gas: ResultGas::default().with_total_gas_spent(21_000),
226227
logs: Vec::new(),
227228
output: Output::Call(Bytes::new()),
228229
},
@@ -322,8 +323,7 @@ mod tests {
322323
let gas_used = 21_000u64;
323324
let result = ExecutionResult::Success {
324325
reason: SuccessReason::Stop,
325-
gas_used,
326-
gas_refunded: 0,
326+
gas: ResultGas::default().with_total_gas_spent(gas_used),
327327
logs: Vec::new(),
328328
output: Output::Call(Bytes::new()),
329329
};

src/parallel_state.rs

Lines changed: 14 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use revm_database::{
77
TransitionAccount, TransitionState,
88
states::{CacheAccount, bundle_state::BundleRetention, plain_account::PlainStorage},
99
};
10-
use revm_primitives::{Address, B256, HashMap, U256};
10+
use revm_primitives::{Address, B256, U256};
1111
use revm_state::{Account, AccountInfo, Bytecode, EvmState};
1212
use std::{fmt::Formatter, time::Instant, vec::Vec};
1313

@@ -152,39 +152,6 @@ impl CacheAccountInfo {
152152
}
153153
}
154154

155-
/// Account got touched and before EIP161 state clear this account is considered created.
156-
pub fn touch_create_pre_eip161(
157-
&mut self,
158-
storage: StorageWithOriginalValues,
159-
) -> (Option<TransitionAccount>, PlainStorage) {
160-
let previous_status = self.status.clone();
161-
162-
let had_no_info = self.account.as_ref().map(|info| info.is_empty()).unwrap_or_default();
163-
match self.status.on_touched_created_pre_eip161(had_no_info) {
164-
None => return (None, PlainStorage::default()),
165-
Some(new_status) => {
166-
self.status = new_status;
167-
}
168-
}
169-
170-
let plain_storage = storage.iter().map(|(k, v)| (*k, v.present_value)).collect();
171-
let previous_info = self.account.take();
172-
173-
self.account = Some(AccountInfo::default());
174-
175-
(
176-
Some(TransitionAccount {
177-
info: Some(AccountInfo::default()),
178-
status: self.status.clone(),
179-
previous_info,
180-
previous_status,
181-
storage,
182-
storage_was_destroyed: false,
183-
}),
184-
plain_storage,
185-
)
186-
}
187-
188155
pub fn change(
189156
&mut self,
190157
new: AccountInfo,
@@ -219,38 +186,25 @@ impl CacheAccountInfo {
219186
/// It loads all accounts from database and applies revm output to it.
220187
///
221188
/// It generates transitions that is used to build BundleState.
222-
#[derive(Clone, Debug)]
189+
#[derive(Clone, Debug, Default)]
223190
pub struct ParallelCacheState {
224191
/// Cached accounts
225192
pub accounts: DashMap<Address, CacheAccountInfo>,
226193
/// Cached storage slots
227194
pub storage: DashMap<Address, DashMap<U256, U256>>,
228195
/// Cache contracts
229196
pub contracts: DashMap<B256, Bytecode>,
230-
/// Has EIP-161 state clear enabled (Spurious Dragon hardfork).
231-
pub has_state_clear: bool,
232-
}
233-
234-
impl Default for ParallelCacheState {
235-
fn default() -> Self {
236-
Self::new(true)
237-
}
238197
}
239198

240199
impl ParallelCacheState {
241200
/// New default state.
242-
pub fn new(has_state_clear: bool) -> Self {
243-
Self {
244-
accounts: Default::default(),
245-
storage: Default::default(),
246-
contracts: Default::default(),
247-
has_state_clear,
248-
}
201+
pub fn new() -> Self {
202+
Self::default()
249203
}
250204

251205
/// Copy the cached data and convert to CacheState
252206
pub fn as_cache_state(&self) -> CacheState {
253-
let mut state = CacheState::new(self.has_state_clear);
207+
let mut state = CacheState::new();
254208
for kv in self.accounts.iter() {
255209
let info = kv.value();
256210
state.accounts.insert(
@@ -283,11 +237,6 @@ impl ParallelCacheState {
283237
state
284238
}
285239

286-
/// Set state clear flag. EIP-161.
287-
pub fn set_state_clear_flag(&mut self, has_state_clear: bool) {
288-
self.has_state_clear = has_state_clear;
289-
}
290-
291240
/// Insert not existing account.
292241
pub fn insert_not_existing(&self, address: Address) {
293242
self.accounts
@@ -376,19 +325,12 @@ impl ParallelCacheState {
376325
// Account is touched, but not selfdestructed or newly created.
377326
// Account can be touched and not changed.
378327
// And when empty account is touched it needs to be removed from database.
379-
// EIP-161 state clear
328+
// EIP-161 state clear (revm v40+ dropped pre-EIP161 support; Spurious Dragon
329+
// is always assumed active).
380330
else if is_empty {
381331
self.storage.remove(&address);
382-
if self.has_state_clear {
383-
// touch empty account.
384-
(self.get_account_mut(address).touch_empty_eip161(), None)
385-
} else {
386-
// if account is empty and state clear is not enabled we should save
387-
// empty account.
388-
let (transition, changed_slots) =
389-
self.get_account_mut(address).touch_create_pre_eip161(changed_storage);
390-
(transition, Some(changed_slots))
391-
}
332+
drop(changed_storage);
333+
(self.get_account_mut(address).touch_empty_eip161(), None)
392334
} else {
393335
let (transition, changed_slots) =
394336
self.get_account_mut(address).change(account.info, changed_storage);
@@ -591,9 +533,10 @@ impl<DB: DatabaseRef> ParallelState<DB> {
591533
}
592534

593535
/// State clear EIP-161 is enabled in Spurious Dragon hardfork.
594-
pub fn set_state_clear_flag(&mut self, has_state_clear: bool) {
595-
self.cache.set_state_clear_flag(has_state_clear);
596-
}
536+
///
537+
/// revm v40+ dropped pre-EIP161 support and always assumes Spurious Dragon is active;
538+
/// this setter is kept as a no-op for API compatibility with older callers.
539+
pub fn set_state_clear_flag(&mut self, _has_state_clear: bool) {}
597540

598541
/// Insert non-existent account
599542
pub fn insert_not_existing(&self, address: Address) {
@@ -795,7 +738,7 @@ impl<DB: DatabaseRef> DatabaseRef for ParallelState<DB> {
795738
}
796739

797740
impl<DB: DatabaseRef> DatabaseCommit for ParallelState<DB> {
798-
fn commit(&mut self, evm_state: HashMap<Address, Account>) {
741+
fn commit(&mut self, evm_state: revm_primitives::AddressMap<Account>) {
799742
let transitions = self.cache.apply_evm_state(evm_state);
800743
self.apply_transition(transitions);
801744
}

src/test_utils/common/account.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,13 @@ pub const MINER_ADDRESS: Address = address!("00000000000000000000000000000000000
88

99
pub fn mock_miner_account() -> (Address, PlainAccount) {
1010
let account = PlainAccount {
11-
info: AccountInfo { balance: U256::from(0), nonce: 1, code_hash: KECCAK_EMPTY, code: None },
11+
info: AccountInfo {
12+
balance: U256::from(0),
13+
nonce: 1,
14+
code_hash: KECCAK_EMPTY,
15+
code: None,
16+
..Default::default()
17+
},
1218
storage: Default::default(),
1319
};
1420
(MINER_ADDRESS, account)
@@ -28,6 +34,7 @@ pub fn mock_eoa_account(idx: usize) -> (Address, PlainAccount) {
2834
nonce: 1,
2935
code_hash: KECCAK_EMPTY,
3036
code: None,
37+
..Default::default()
3138
},
3239
storage: Default::default(),
3340
};

src/test_utils/common/execute.rs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -231,18 +231,27 @@ where
231231
DB: DatabaseRef + Debug,
232232
DB::Error: Send + Sync + Debug + 'static,
233233
{
234+
let spec = cfg.spec;
234235
let db = StateBuilder::new().with_bundle_update().with_database_ref(db).build();
235236
let evm = Context::mainnet()
236237
.with_db(db)
237238
.with_cfg(cfg)
238239
.with_block(env)
239240
.build_mainnet_with_inspector(NoOpInspector {})
240-
.with_precompiles(PrecompilesMap::from_static(EthPrecompiles::default().precompiles));
241+
.with_precompiles(PrecompilesMap::from_static(EthPrecompiles::new(spec).precompiles));
241242
let mut evm = EthEvm::new(evm, false);
242243

243244
let mut results = Vec::with_capacity(txs.len());
244245
for tx in txs {
245-
let result_and_state = evm.transact_raw(tx.clone())?;
246+
// v40 wraps DB errors in `EvmDatabaseError`; the outer signature keeps the historical
247+
// `EVMError<DB::Error>` shape so unwrap the wrapper here.
248+
let result_and_state = evm.transact_raw(tx.clone()).map_err(|e| match e {
249+
EVMError::Transaction(t) => EVMError::Transaction(t),
250+
EVMError::Header(h) => EVMError::Header(h),
251+
EVMError::Database(inner) => EVMError::Database(inner.into_external_error()),
252+
EVMError::Custom(s) => EVMError::Custom(s),
253+
EVMError::CustomAny(a) => EVMError::CustomAny(a),
254+
})?;
246255
evm.db_mut().commit(result_and_state.state);
247256
results.push(result_and_state.result);
248257
}
@@ -272,21 +281,22 @@ where
272281
DB: DatabaseRef + Debug,
273282
DB::Error: Send + Sync + Debug + 'static,
274283
{
284+
let spec = cfg.spec;
275285
let db = StateBuilder::new().with_bundle_update().with_database_ref(db).build();
276286
let evm = Context::mainnet()
277287
.with_db(db)
278288
.with_cfg(cfg)
279289
.with_block(env)
280290
.build_mainnet_with_inspector(NoOpInspector {})
281-
.with_precompiles(PrecompilesMap::from_static(EthPrecompiles::default().precompiles));
291+
.with_precompiles(PrecompilesMap::from_static(EthPrecompiles::new(spec).precompiles));
282292
let mut evm = EthEvm::new(evm, false);
283293

284294
let mut kept = Vec::new();
285295
let mut total_gas: u64 = 0;
286296
for (i, tx) in txs.iter().enumerate() {
287297
match evm.transact_raw(tx.clone()) {
288298
Ok(result_and_state) => {
289-
total_gas = total_gas.saturating_add(result_and_state.result.gas_used());
299+
total_gas = total_gas.saturating_add(result_and_state.result.tx_gas_used());
290300
evm.db_mut().commit(result_and_state.state);
291301
kept.push(i);
292302
if total_gas >= gas_cap {

src/test_utils/common/mainnet.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,8 @@ impl BlockFixture {
110110
difficulty: self.difficulty,
111111
prevrandao: self.prevrandao,
112112
blob_excess_gas_and_price: None,
113+
// Amsterdam (EIP-7843) is not modeled in the test fixtures; leave slot_num at zero.
114+
slot_num: 0,
113115
};
114116
if let Some(excess) = self.excess_blob_gas {
115117
// Record the real `excess_blob_gas` but pin the blob gas price to the protocol minimum
@@ -273,7 +275,13 @@ pub fn pre_state_to_db(pre_state: &PreState) -> InMemoryDB {
273275
}
274276
_ => (KECCAK_EMPTY, None),
275277
};
276-
let info = AccountInfo { balance: acc.balance, nonce: acc.nonce, code_hash, code };
278+
let info = AccountInfo {
279+
balance: acc.balance,
280+
nonce: acc.nonce,
281+
code_hash,
282+
code,
283+
..Default::default()
284+
};
277285
let storage = acc.storage.iter().map(|(k, v)| (*k, *v)).collect();
278286
accounts.insert(*addr, PlainAccount { info, storage });
279287
}

src/test_utils/common/storage.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use revm::{
88
};
99
use revm_context::DBErrorMarker;
1010
use revm_database::PlainAccount;
11-
use revm_primitives::HashMap;
11+
use revm_primitives::{HashMap, StorageKeyMap};
1212
use revm_state::{AccountInfo, Bytecode};
1313

1414
/// A DatabaseRef that stores chain data in memory.
@@ -95,12 +95,12 @@ impl DatabaseRef for InMemoryDB {
9595

9696
#[derive(Debug, Default)]
9797
pub struct StorageBuilder {
98-
dict: HashMap<U256, U256>,
98+
dict: StorageKeyMap<U256>,
9999
}
100100

101101
impl StorageBuilder {
102102
pub fn new() -> Self {
103-
StorageBuilder { dict: HashMap::default() }
103+
StorageBuilder { dict: StorageKeyMap::default() }
104104
}
105105

106106
pub fn set<K, V>(&mut self, slot: K, value: V)
@@ -135,7 +135,7 @@ impl StorageBuilder {
135135
*entry = buffer.into();
136136
}
137137

138-
pub fn build(self) -> HashMap<U256, U256> {
138+
pub fn build(self) -> StorageKeyMap<U256> {
139139
self.dict
140140
}
141141
}

0 commit comments

Comments
 (0)