Skip to content
Merged
Show file tree
Hide file tree
Changes from 47 commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
7c9cc16
BAL
rakita Sep 30, 2025
c08eb30
WIP
rakita Sep 30, 2025
ed712f1
Merge remote-tracking branch 'origin/main' into bal
rakita Oct 3, 2025
46683bb
bal wip
rakita Oct 4, 2025
c542f81
bal followup
rakita Oct 6, 2025
56b6f7a
Merge remote-tracking branch 'origin/main' into bal
rakita Oct 7, 2025
fd3e996
Merge remote-tracking branch 'origin/main' into bal
rakita Oct 7, 2025
45dcfce
Database::bal and Bal IndexMap for accounts
rakita Oct 7, 2025
c9f9c17
bal builder and integration with databases
rakita Oct 8, 2025
bf322c2
chore: bump eest tests v5.3.0
rakita Oct 10, 2025
96aba9a
bump bal for caller/beneficiary
rakita Oct 10, 2025
746bd15
Merge remote-tracking branch 'origin/main' into bal
rakita Oct 13, 2025
b8ca754
bal builder from state on commit, alloy included
rakita Oct 14, 2025
4ea2fb6
cleanup
rakita Oct 14, 2025
4067336
Merge remote-tracking branch 'origin/main' into bal
rakita Oct 15, 2025
b3dc5fb
bal integration in btests
rakita Oct 16, 2025
1fdfb51
wip sys call
rakita Oct 16, 2025
749cc00
fix few bugs, propagate error
rakita Oct 17, 2025
41c5069
remove bal panic from btest
rakita Oct 17, 2025
fd3b209
error handling
rakita Oct 17, 2025
8f185ec
cleanup bal tests
rakita Oct 17, 2025
f418106
Merge remote-tracking branch 'origin/main' into rakita/bal
rakita Oct 19, 2025
d23354b
skip touching beneficiary if reward is 0
rakita Oct 19, 2025
1619254
handle local selfdestruct
rakita Oct 19, 2025
440e6f1
feat: dont load access list immediatly
rakita Oct 20, 2025
810bc40
nits fmt
rakita Oct 20, 2025
6df2e72
Merge remote-tracking branch 'origin/rakita/access-list-load' into ba…
rakita Oct 20, 2025
4a2c5ce
bump output as accounts now have original account info
rakita Oct 20, 2025
5514697
BalDatabase
rakita Oct 21, 2025
c772dd6
nit, rm clone
rakita Oct 21, 2025
0846c20
Merge remote-tracking branch 'origin/main' into al
rakita Oct 21, 2025
f38650c
Merge branch 'al' into rakita/bal
rakita Oct 21, 2025
74975ea
bump tests, add missing imports, cleanup
rakita Oct 22, 2025
c8c6499
reause indexmap from alloy with default hasher
rakita Oct 22, 2025
57d5317
typos
rakita Oct 22, 2025
44e67cc
add missing serde propagation
rakita Oct 22, 2025
ea1e03e
dont skip test
rakita Oct 23, 2025
296d685
Merge remote-tracking branch 'origin/main' into rakita/bal
rakita Oct 24, 2025
b989d83
Merge remote-tracking branch 'origin/main' into rakita/bal
rakita Oct 29, 2025
e4c5beb
Create BalState and add it inside State so that we dont need to use B…
rakita Oct 29, 2025
936105a
nits, and deserialization for Account without original info
rakita Oct 29, 2025
d9d8896
propagate feature
rakita Oct 29, 2025
efe3be8
fix: add bal_builder.commit to state, small cleanup
rakita Oct 31, 2025
180f9ff
fix: bal binary search cases (#3139)
dajuguan Nov 3, 2025
0d6607e
Merge remote-tracking branch 'origin/main' into bal
rakita Nov 5, 2025
b0ff6f4
Merge remote-tracking branch 'origin/main' into bal2
rakita Dec 4, 2025
efd5899
compile tests
rakita Dec 4, 2025
d4d9216
Merge remote-tracking branch 'origin/main' into ball
rakita Dec 12, 2025
40e044b
Rename BalDatabaseError to EvmDatabaseError
rakita Dec 12, 2025
b7f6094
throw error if bal exist but account/storage not
rakita Dec 15, 2025
65afb8e
rename storage_id to account_id
rakita Dec 15, 2025
de9f216
Merge remote-tracking branch 'origin/main' into ball
rakita Dec 15, 2025
db3a47c
rm println
rakita Dec 15, 2025
e3d8186
use alloy main, clippy/typo fixes
rakita Dec 15, 2025
f97c8d5
ark the bytecode
rakita Dec 15, 2025
e57190a
typo
rakita Dec 15, 2025
588a792
add statis default for Bytecode
rakita Dec 15, 2025
82cc2e0
use oncelock
rakita Dec 15, 2025
4ba4b7c
try with oncelock
rakita Dec 15, 2025
2968fb5
box original acc info
rakita Dec 16, 2025
425d2d3
Merge remote-tracking branch 'origin/main' into ball
rakita Dec 16, 2025
fbcb862
Merge remote-tracking branch 'origin/main' into bal
rakita Dec 18, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ ee-tests = { path = "crates/ee-tests", package = "revm-ee-tests", version = "0.1
# alloy
alloy-eip2930 = { version = "0.2.1", default-features = false }
alloy-eip7702 = { version = "0.6.1", default-features = false }
alloy-eip7928 = { version = "0.1.0", default-features = false, git = "https://github.com/alloy-rs/eips.git" }
alloy-primitives = { version = "1.3.1", default-features = false }

# alloy in examples, revme or feature flagged.
Expand Down
40 changes: 37 additions & 3 deletions bins/revme/src/cmd/blockchaintest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use revm::{
handler::EvmTr,
inspector::inspectors::TracerEip3155,
primitives::{hardfork::SpecId, hex, Address, HashMap, U256},
state::AccountInfo,
state::{bal::Bal, AccountInfo},
Context, Database, ExecuteCommitEvm, ExecuteEvm, InspectEvm, MainBuilder, MainContext,
};
use serde_json::json;
Expand All @@ -22,6 +22,7 @@ use std::{
collections::BTreeMap,
fs,
path::{Path, PathBuf},
sync::Arc,
time::Instant,
};
use thiserror::Error;
Expand Down Expand Up @@ -654,7 +655,7 @@ fn execute_blockchain_test(
}

// Create database with initial state
let mut state = State::builder().build();
let mut state = State::builder().with_bal_builder().build();

// Capture pre-state for debug info
let mut pre_state_debug = HashMap::default();
Expand All @@ -667,6 +668,7 @@ fn execute_blockchain_test(
nonce: account.nonce,
code_hash: revm::primitives::keccak256(&account.code),
code: Some(Bytecode::new_raw(account.code.clone())),
storage_id: None,
};

// Store for debug info
Expand Down Expand Up @@ -723,6 +725,15 @@ fn execute_blockchain_test(
this_excess_blob_gas = None;
}

let bal_test = block
.block_access_list
.as_ref()
.and_then(|bal| Bal::try_from(bal.clone()).ok())
.map(Arc::new);

//state.set_bal(bal_test);
state.reset_bal_index();

// Create EVM context for each transaction to ensure fresh state access
let evm_context = Context::mainnet()
.with_block(&block_env)
Expand Down Expand Up @@ -808,6 +819,9 @@ fn execute_blockchain_test(
}
};

// bump bal index
evm.db_mut().bump_bal_index();

// If JSON output requested, output transaction details
let execution_result = if json_output {
evm.inspect_tx(tx_env.clone())
Expand Down Expand Up @@ -917,6 +931,9 @@ fn execute_blockchain_test(
}
}

// bump bal index
evm.db_mut().bump_bal_index();

// uncle rewards are not implemented yet
post_block::post_block_transition(
&mut evm,
Expand All @@ -930,6 +947,19 @@ fn execute_blockchain_test(
.block_hashes
.insert(block_env.number.to::<u64>(), block_hash.unwrap_or_default());

if let Some(bal) = state.bal_state.bal_builder.take() {
if let Some(state_bal) = bal_test {
if &bal != state_bal.as_ref() {
println!("Bal mismatch");
println!("Test bal");
state_bal.pretty_print();
println!("Bal:");
bal.pretty_print();
return Err(TestExecutionError::BalMismatchError);
}
}
}

parent_block_hash = block_hash;
if let Some(excess_blob_gas) = this_excess_blob_gas {
parent_excess_blob_gas = excess_blob_gas;
Expand Down Expand Up @@ -983,7 +1013,8 @@ fn fork_to_spec_id(fork: ForkSpec) -> SpecId {
ForkSpec::Cancun | ForkSpec::ShanghaiToCancunAtTime15k => SpecId::CANCUN,
ForkSpec::Prague | ForkSpec::CancunToPragueAtTime15k => SpecId::PRAGUE,
ForkSpec::Osaka | ForkSpec::PragueToOsakaAtTime15k => SpecId::OSAKA,
_ => SpecId::OSAKA, // For any unknown forks, use latest available
ForkSpec::Amsterdam => SpecId::AMSTERDAM,
_ => SpecId::AMSTERDAM, // For any unknown forks, use latest available
}
}

Expand Down Expand Up @@ -1088,6 +1119,9 @@ pub enum TestExecutionError {
gas_used: u64,
},

#[error("BAL error")]
BalMismatchError,

#[error(
"Post-state validation failed for {address:?}.{field}: expected {expected}, got {actual}"
)]
Expand Down
74 changes: 58 additions & 16 deletions bins/revme/src/cmd/blockchaintest/post_block.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,24 @@
use revm::{
context::{Block, ContextTr},
database::{DatabaseCommitExt as _, State},
context::{Block, ContextTr, JournalTr},
handler::EvmTr,
primitives::{hardfork::SpecId, ONE_ETHER, ONE_GWEI},
Database, SystemCallCommitEvm,
primitives::{address, hardfork::SpecId, Address, Bytes, ONE_ETHER, ONE_GWEI, U256},
Database, DatabaseCommit, SystemCallCommitEvm,
};
use statetest_types::blockchain::Withdrawal;

/// Post block transition that includes:
/// * Block and uncle rewards before the Merge/Paris hardfork.
/// * system calls
/// * Withdrawals (EIP-4895)
/// * Post-block system calls: EIP-7002 (withdrawal requests) and EIP-7251 (consolidation requests)
///
/// # Note
///
/// Uncle rewards are not implemented yet.
#[inline]
pub fn post_block_transition<
'a,
DB: Database + 'a,
EVM: SystemCallCommitEvm<Error: core::fmt::Debug>
+ EvmTr<Context: ContextTr<Db = &'a mut State<DB>>>,
DB: Database + DatabaseCommit + 'a,
EVM: SystemCallCommitEvm<Error: core::fmt::Debug> + EvmTr<Context: ContextTr<Db = DB>>,
>(
evm: &mut EVM,
block: impl Block,
Expand All @@ -29,24 +28,36 @@ pub fn post_block_transition<
// block reward
let block_reward = block_reward(spec, 0);
if block_reward != 0 {
let _ = evm
.ctx_mut()
.db_mut()
.increment_balances(vec![(block.beneficiary(), block_reward)]);
evm.ctx_mut()
.journal_mut()
.balance_incr(block.beneficiary(), U256::from(block_reward))
.expect("Db actions to pass");
}

// withdrawals
if spec.is_enabled_in(SpecId::SHANGHAI) {
for withdrawal in withdrawals {
evm.ctx_mut()
.db_mut()
.increment_balances(vec![(
.journal_mut()
.balance_incr(
withdrawal.address,
withdrawal.amount.to::<u128>().saturating_mul(ONE_GWEI),
)])
withdrawal.amount.saturating_mul(U256::from(ONE_GWEI)),
)
.expect("Db actions to pass");
}
}

evm.commit_inner();

// EIP-7002: Withdrawal requests system call
if spec.is_enabled_in(SpecId::PRAGUE) {
system_call_eip7002_withdrawal_request(evm);
}

// EIP-7251: Consolidation requests system call
if spec.is_enabled_in(SpecId::PRAGUE) {
system_call_eip7251_consolidation_request(evm);
}
}

/// Block reward for a block.
Expand All @@ -66,3 +77,34 @@ pub const fn block_reward(spec: SpecId, ommers: usize) -> u128 {

reward + (reward >> 5) * ommers as u128
}

pub const WITHDRAWAL_REQUEST_ADDRESS: Address =
address!("0x00000961Ef480Eb55e80D19ad83579A64c007002");

/// EIP-7002: Withdrawal requests system call
pub(crate) fn system_call_eip7002_withdrawal_request(
evm: &mut impl SystemCallCommitEvm<Error: core::fmt::Debug>,
) {
// empty data is valid for EIP-7002
let _ = match evm.system_call_commit(WITHDRAWAL_REQUEST_ADDRESS, Bytes::new()) {
Ok(res) => res,
Err(e) => {
panic!("System call failed: {e:?}");
}
};
}

pub const CONSOLIDATION_REQUEST_ADDRESS: Address =
address!("0x0000BBdDc7CE488642fb579F8B00f3a590007251");

/// EIP-7251: Consolidation requests system call
pub(crate) fn system_call_eip7251_consolidation_request(
evm: &mut impl SystemCallCommitEvm<Error: core::fmt::Debug>,
) {
let _ = match evm.system_call_commit(CONSOLIDATION_REQUEST_ADDRESS, Bytes::new()) {
Ok(res) => res,
Err(e) => {
panic!("System call failed: {e:?}");
}
};
}
41 changes: 15 additions & 26 deletions bins/revme/src/cmd/blockchaintest/pre_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,21 @@

use revm::{
context::{Block, ContextTr},
database::{Database, State},
database::Database,
handler::EvmTr,
primitives::{address, hardfork::SpecId, Address, B256},
SystemCallCommitEvm,
DatabaseCommit, SystemCallCommitEvm,
};

/// Pre block state transition
///
/// # Note
///
/// Contains only withdrawal processing. And it is missing block hash system call.
/// Contains pre-block system calls: EIP-2935 (blockhash) and EIP-4788 (beacon root).
pub fn pre_block_transition<
'a,
DB: Database + 'a,
EVM: SystemCallCommitEvm<Error: core::fmt::Debug>
+ EvmTr<Context: ContextTr<Db = &'a mut State<DB>>>,
DB: Database + DatabaseCommit + 'a,
EVM: SystemCallCommitEvm<Error: core::fmt::Debug> + EvmTr<Context: ContextTr<Db = DB>>,
>(
evm: &mut EVM,
spec: SpecId,
Expand All @@ -31,11 +30,15 @@ pub fn pre_block_transition<

// blockhash system call
if let Some(parent_block_hash) = parent_block_hash {
system_call_eip2935_blockhash(spec, parent_block_hash, evm);
if spec.is_enabled_in(SpecId::PRAGUE) {
system_call_eip2935_blockhash(evm, parent_block_hash);
}
}

if let Some(parent_beacon_block_root) = parent_beacon_block_root {
system_call_eip4788_beacon_root(spec, parent_beacon_block_root, evm);
if spec.is_enabled_in(SpecId::CANCUN) {
system_call_eip4788_beacon_root(evm, parent_beacon_block_root);
}
}
}

Expand All @@ -44,42 +47,28 @@ pub const HISTORY_STORAGE_ADDRESS: Address = address!("0x0000F90827F1C53a10cb7A0
/// Blockhash system callEIP-2935
#[inline]
pub(crate) fn system_call_eip2935_blockhash(
spec: SpecId,
parent_block_hash: B256,
evm: &mut impl SystemCallCommitEvm<Error: core::fmt::Debug>,
) -> bool {
if !spec.is_enabled_in(SpecId::PRAGUE) {
return true;
}

parent_block_hash: B256,
) {
let _ = match evm.system_call_commit(HISTORY_STORAGE_ADDRESS, parent_block_hash.0.into()) {
Ok(res) => res,
Err(e) => {
panic!("System call failed: {e:?}");
}
};

true
}

pub const BEACON_ROOTS_ADDRESS: Address = address!("000F3df6D732807Ef1319fB7B8bB8522d0Beac02");

/// Beacon root system call EIP-4788
pub(crate) fn system_call_eip4788_beacon_root(
spec: SpecId,
parent_beacon_block_root: B256,
evm: &mut impl SystemCallCommitEvm<Error: core::fmt::Debug>,
) -> bool {
if !spec.is_enabled_in(SpecId::CANCUN) {
return true;
}

parent_beacon_block_root: B256,
) {
let _ = match evm.system_call_commit(BEACON_ROOTS_ADDRESS, parent_beacon_block_root.0.into()) {
Ok(res) => res,
Err(e) => {
panic!("System call failed: {e:?}");
}
};

true
}
1 change: 1 addition & 0 deletions bins/revme/src/cmd/statetest/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,7 @@ fn execute_single_test(ctx: TestExecutionContext) -> Result<(), TestErrorKind> {
};
*ctx.elapsed.lock().unwrap() += timer.elapsed();

let exec_result = exec_result.map_err(|b| b.map_db_err(|db| db.into_db_error()));
// Check results
check_evm_execution(
ctx.test,
Expand Down
Loading
Loading