Skip to content

Commit 079ff3e

Browse files
rakitakevaundraynemnem7
authored
feat: Add JournalInner (#2311)
* temp * feat: Add JournalInner * fix(ci): Still run statetests from eth/tests repo (#2306) * feat: Add a wrapper for arkworks for EIP196 (#2305) * add read_scalar, point_add and point_mul into the wrapper * modify bn128.rs to use new api methods * preserve previous semantics * initial commit to add matter-labs wrapper * feature gate matter-labs impl -- make substrate impl still default * update revm and precompile cargo.toml file * use cfg_if * make bn an optional dependency * cfg else -> else_if so that there is no silent fallback * follow same cfg_if pattern as other precompiles * fix optimism * add back `self` import * Push empty commit to trigger CI * cargo fmt * clippy fix * make `bn` the default with revm and revme * fix typo * Update crates/revm/Cargo.toml * Update crates/revm/Cargo.toml * Update crates/precompile/src/lib.rs * Update crates/optimism/Cargo.toml * revert Cargo.toml formatting * multi: - remove bn as optional - if default-features and matter-labs-eip1962 feature is enabled, then we choose matter-labs - remove conditional configs in other parts of code since bn is always available * revert crates/optimism/src/precompiles.rs * revert crates/optimism/src/evm.rs * revert unnecessary changes in crates/precompile/src/lib.rs * revert Cargo.toml changes * revert automatic Cargo.toml formatting * revert formatting on secp256k1 in Cargo.toml * revert c-kzg formatting in Cargo.toml * revert dev key in Cargo.toml * revert c-kzg feature in Cargo.toml * Update crates/precompile/Cargo.toml * Apply suggestions from code review * initial commit of arkworks file -- replace matter-labs * add arkworks depedency * grep replace matter-labs with arkworks * make substrate-bn impl optional * propagate arkworks/std * add comment for substrate-bn impl * Update crates/precompile/src/bn128/arkworks.rs --------- * feat: Add criterion to revme bench command (#2295) * temp code preview * add criterion to benchmarks * added args to fn run() calls in bins/revme/ * modifed the code inside the benchmark tests * left only .replay function inside bench_functions and added minor revisions to the rest of the code * edited comment annotation in burntpix.rs file * added comments and set different default value for warm_up_time * clear all Journal fields * doc * formating change --------- Co-authored-by: kevaundray <[email protected]> Co-authored-by: nemnem7 <[email protected]>
1 parent 6f38322 commit 079ff3e

File tree

11 files changed

+385
-334
lines changed

11 files changed

+385
-334
lines changed

bins/revme/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ revm = { workspace = true, features = [
1616
"c-kzg",
1717
"blst",
1818
"serde-json",
19+
"hashbrown",
1920
] }
2021
primitives.workspace = true
2122
database.workspace = true

crates/context/interface/src/journaled_state.rs

+20-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use state::{
77
Account, Bytecode,
88
};
99

10+
/// Trait that contains database and journal of all changes that were made to the state.
1011
pub trait JournalTr {
1112
type Database: Database;
1213
type FinalOutput;
@@ -55,44 +56,55 @@ pub trait JournalTr {
5556
target: Address,
5657
) -> Result<StateLoad<SelfDestructResult>, <Self::Database as Database>::Error>;
5758

59+
/// Warms the account and storage.
5860
fn warm_account_and_storage(
5961
&mut self,
6062
address: Address,
6163
storage_keys: impl IntoIterator<Item = U256>,
6264
) -> Result<(), <Self::Database as Database>::Error>;
6365

66+
/// Warms the account.
6467
fn warm_account(&mut self, address: Address);
6568

69+
/// Warms the precompiles.
6670
fn warm_precompiles(&mut self, addresses: HashSet<Address>);
6771

72+
/// Returns the addresses of the precompiles.
6873
fn precompile_addresses(&self) -> &HashSet<Address>;
6974

75+
/// Sets the spec id.
7076
fn set_spec_id(&mut self, spec_id: SpecId);
7177

78+
/// Touches the account.
7279
fn touch_account(&mut self, address: Address);
7380

81+
/// Transfers the balance from one account to another.
7482
fn transfer(
7583
&mut self,
76-
from: &Address,
77-
to: &Address,
84+
from: Address,
85+
to: Address,
7886
balance: U256,
7987
) -> Result<Option<TransferError>, <Self::Database as Database>::Error>;
8088

89+
/// Increments the nonce of the account.
8190
fn inc_account_nonce(
8291
&mut self,
8392
address: Address,
8493
) -> Result<Option<u64>, <Self::Database as Database>::Error>;
8594

95+
/// Loads the account.
8696
fn load_account(
8797
&mut self,
8898
address: Address,
8999
) -> Result<StateLoad<&mut Account>, <Self::Database as Database>::Error>;
90100

101+
/// Loads the account code.
91102
fn load_account_code(
92103
&mut self,
93104
address: Address,
94105
) -> Result<StateLoad<&mut Account>, <Self::Database as Database>::Error>;
95106

107+
/// Loads the account delegated.
96108
fn load_account_delegated(
97109
&mut self,
98110
address: Address,
@@ -158,12 +170,17 @@ pub trait JournalTr {
158170
/// Called at the end of the transaction to clean all residue data from journal.
159171
fn clear(&mut self);
160172

173+
/// Creates a checkpoint of the current state. State can be revert to this point
174+
/// if needed.
161175
fn checkpoint(&mut self) -> JournalCheckpoint;
162176

177+
/// Commits the changes made since the last checkpoint.
163178
fn checkpoint_commit(&mut self);
164179

180+
/// Reverts the changes made since the last checkpoint.
165181
fn checkpoint_revert(&mut self, checkpoint: JournalCheckpoint);
166182

183+
/// Creates a checkpoint of the account creation.
167184
fn create_account_checkpoint(
168185
&mut self,
169186
caller: Address,
@@ -172,6 +189,7 @@ pub trait JournalTr {
172189
spec_id: SpecId,
173190
) -> Result<JournalCheckpoint, TransferError>;
174191

192+
/// Returns the depth of the journal.
175193
fn depth(&self) -> usize;
176194

177195
/// Does cleanup and returns modified state.

crates/context/src/context.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::{block::BlockEnv, cfg::CfgEnv, journaled_state::Journal, tx::TxEnv};
1+
use crate::{block::BlockEnv, cfg::CfgEnv, journal::Journal, tx::TxEnv};
22
use context_interface::{
33
context::{ContextError, ContextSetters},
44
Block, Cfg, ContextTr, JournalTr, Transaction,
@@ -157,12 +157,14 @@ where
157157
}
158158

159159
/// Creates a new context with a new database type.
160+
///
161+
/// This will create a new [`Journal`] object.
160162
pub fn with_db<ODB: Database>(
161163
self,
162164
db: ODB,
163165
) -> Context<BLOCK, TX, CFG, ODB, Journal<ODB>, CHAIN> {
164166
let spec = self.cfg.spec().into();
165-
let mut journaled_state = Journal::new(spec, db);
167+
let mut journaled_state = Journal::new(db);
166168
journaled_state.set_spec_id(spec);
167169
Context {
168170
tx: self.tx,
@@ -180,7 +182,7 @@ where
180182
db: ODB,
181183
) -> Context<BLOCK, TX, CFG, WrapDatabaseRef<ODB>, Journal<WrapDatabaseRef<ODB>>, CHAIN> {
182184
let spec = self.cfg.spec().into();
183-
let mut journaled_state = Journal::new(spec, WrapDatabaseRef(db));
185+
let mut journaled_state = Journal::new(WrapDatabaseRef(db));
184186
journaled_state.set_spec_id(spec);
185187
Context {
186188
tx: self.tx,

crates/context/src/journal.rs

+256
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
pub mod entry;
2+
pub mod inner;
3+
4+
pub use entry::{JournalEntry, JournalEntryTr};
5+
pub use inner::JournalInner;
6+
7+
use bytecode::Bytecode;
8+
use context_interface::{
9+
context::{SStoreResult, SelfDestructResult, StateLoad},
10+
journaled_state::{AccountLoad, JournalCheckpoint, JournalTr, TransferError},
11+
};
12+
use core::ops::{Deref, DerefMut};
13+
use database_interface::Database;
14+
use primitives::{hardfork::SpecId, Address, HashSet, Log, B256, U256};
15+
use state::{Account, EvmState};
16+
use std::vec::Vec;
17+
18+
/// A journal of state changes internal to the EVM
19+
///
20+
/// On each additional call, the depth of the journaled state is increased (`depth`) and a new journal is added.
21+
///
22+
/// The journal contains every state change that happens within that call, making it possible to revert changes made in a specific call.
23+
#[derive(Debug, Clone, PartialEq, Eq)]
24+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
25+
pub struct Journal<DB, ENTRY = JournalEntry>
26+
where
27+
ENTRY: JournalEntryTr,
28+
{
29+
/// Database
30+
pub database: DB,
31+
/// Inner journal state.
32+
pub inner: JournalInner<ENTRY>,
33+
}
34+
35+
impl<DB, ENTRY> Deref for Journal<DB, ENTRY>
36+
where
37+
ENTRY: JournalEntryTr,
38+
{
39+
type Target = JournalInner<ENTRY>;
40+
41+
fn deref(&self) -> &Self::Target {
42+
&self.inner
43+
}
44+
}
45+
46+
impl<DB, ENTRY> DerefMut for Journal<DB, ENTRY>
47+
where
48+
ENTRY: JournalEntryTr,
49+
{
50+
fn deref_mut(&mut self) -> &mut Self::Target {
51+
&mut self.inner
52+
}
53+
}
54+
55+
impl<DB, ENTRY: JournalEntryTr> Journal<DB, ENTRY> {
56+
/// Creates a new JournaledState by copying state data from a JournalInit and provided database.
57+
/// This allows reusing the state, logs, and other data from a previous execution context while
58+
/// connecting it to a different database backend.
59+
pub fn new_with_inner(database: DB, inner: JournalInner<ENTRY>) -> Self {
60+
Self { database, inner }
61+
}
62+
63+
/// Consumes the [`Journal`] and returns [`JournalInner`].
64+
///
65+
/// If you need to preserve the original journal, use [`Self::to_inner`] instead which clones the state.
66+
pub fn into_init(self) -> JournalInner<ENTRY> {
67+
self.inner
68+
}
69+
}
70+
71+
impl<DB, ENTRY: JournalEntryTr + Clone> Journal<DB, ENTRY> {
72+
/// Creates a new [`JournalInner`] by cloning all internal state data (state, storage, logs, etc)
73+
/// This allows creating a new journaled state with the same state data but without
74+
/// carrying over the original database.
75+
///
76+
/// This is useful when you want to reuse the current state for a new transaction or
77+
/// execution context, but want to start with a fresh database.
78+
pub fn to_inner(&self) -> JournalInner<ENTRY> {
79+
self.inner.clone()
80+
}
81+
}
82+
83+
/// Output of the journal after finalizing.
84+
pub struct JournalOutput {
85+
/// Changes or touched accounts that loads, created or changed in the journal.
86+
pub state: EvmState,
87+
/// Logs that were emitted by contract calls.
88+
pub logs: Vec<Log>,
89+
}
90+
91+
impl<DB: Database, ENTRY: JournalEntryTr> JournalTr for Journal<DB, ENTRY> {
92+
type Database = DB;
93+
type FinalOutput = JournalOutput;
94+
95+
fn new(database: DB) -> Journal<DB, ENTRY> {
96+
Self {
97+
inner: JournalInner::new(SpecId::default()),
98+
database,
99+
}
100+
}
101+
102+
fn db_ref(&self) -> &Self::Database {
103+
&self.database
104+
}
105+
106+
fn db(&mut self) -> &mut Self::Database {
107+
&mut self.database
108+
}
109+
110+
fn sload(
111+
&mut self,
112+
address: Address,
113+
key: U256,
114+
) -> Result<StateLoad<U256>, <Self::Database as Database>::Error> {
115+
self.inner.sload(&mut self.database, address, key)
116+
}
117+
118+
fn sstore(
119+
&mut self,
120+
address: Address,
121+
key: U256,
122+
value: U256,
123+
) -> Result<StateLoad<SStoreResult>, <Self::Database as Database>::Error> {
124+
self.inner.sstore(&mut self.database, address, key, value)
125+
}
126+
127+
fn tload(&mut self, address: Address, key: U256) -> U256 {
128+
self.inner.tload(address, key)
129+
}
130+
131+
fn tstore(&mut self, address: Address, key: U256, value: U256) {
132+
self.inner.tstore(address, key, value)
133+
}
134+
135+
fn log(&mut self, log: Log) {
136+
self.inner.log(log)
137+
}
138+
139+
fn selfdestruct(
140+
&mut self,
141+
address: Address,
142+
target: Address,
143+
) -> Result<StateLoad<SelfDestructResult>, DB::Error> {
144+
self.inner.selfdestruct(&mut self.database, address, target)
145+
}
146+
147+
fn warm_account(&mut self, address: Address) {
148+
self.inner.warm_preloaded_addresses.insert(address);
149+
}
150+
151+
fn warm_precompiles(&mut self, address: HashSet<Address>) {
152+
self.inner.precompiles = address;
153+
self.inner
154+
.warm_preloaded_addresses
155+
.extend(self.inner.precompiles.iter());
156+
}
157+
158+
#[inline]
159+
fn precompile_addresses(&self) -> &HashSet<Address> {
160+
&self.inner.precompiles
161+
}
162+
163+
/// Returns call depth.
164+
#[inline]
165+
fn depth(&self) -> usize {
166+
self.inner.depth
167+
}
168+
169+
fn warm_account_and_storage(
170+
&mut self,
171+
address: Address,
172+
storage_keys: impl IntoIterator<Item = U256>,
173+
) -> Result<(), <Self::Database as Database>::Error> {
174+
self.inner
175+
.initial_account_load(&mut self.database, address, storage_keys)?;
176+
Ok(())
177+
}
178+
179+
fn set_spec_id(&mut self, spec_id: SpecId) {
180+
self.inner.spec = spec_id;
181+
}
182+
183+
fn transfer(
184+
&mut self,
185+
from: Address,
186+
to: Address,
187+
balance: U256,
188+
) -> Result<Option<TransferError>, DB::Error> {
189+
self.inner.transfer(&mut self.database, from, to, balance)
190+
}
191+
192+
fn touch_account(&mut self, address: Address) {
193+
self.inner.touch(address);
194+
}
195+
196+
fn inc_account_nonce(&mut self, address: Address) -> Result<Option<u64>, DB::Error> {
197+
Ok(self.inner.inc_nonce(address))
198+
}
199+
200+
fn load_account(&mut self, address: Address) -> Result<StateLoad<&mut Account>, DB::Error> {
201+
self.inner.load_account(&mut self.database, address)
202+
}
203+
204+
fn load_account_code(
205+
&mut self,
206+
address: Address,
207+
) -> Result<StateLoad<&mut Account>, DB::Error> {
208+
self.inner.load_code(&mut self.database, address)
209+
}
210+
211+
fn load_account_delegated(
212+
&mut self,
213+
address: Address,
214+
) -> Result<StateLoad<AccountLoad>, DB::Error> {
215+
self.inner
216+
.load_account_delegated(&mut self.database, address)
217+
}
218+
219+
fn checkpoint(&mut self) -> JournalCheckpoint {
220+
self.inner.checkpoint()
221+
}
222+
223+
fn checkpoint_commit(&mut self) {
224+
self.inner.checkpoint_commit()
225+
}
226+
227+
fn checkpoint_revert(&mut self, checkpoint: JournalCheckpoint) {
228+
self.inner.checkpoint_revert(checkpoint)
229+
}
230+
231+
fn set_code_with_hash(&mut self, address: Address, code: Bytecode, hash: B256) {
232+
self.inner.set_code_with_hash(address, code, hash);
233+
}
234+
235+
fn clear(&mut self) {
236+
// Clears the inner journal state. Preserving only the spec.
237+
let spec = self.inner.spec;
238+
self.inner = JournalInner::new(spec);
239+
}
240+
241+
fn create_account_checkpoint(
242+
&mut self,
243+
caller: Address,
244+
address: Address,
245+
balance: U256,
246+
spec_id: SpecId,
247+
) -> Result<JournalCheckpoint, TransferError> {
248+
// Ignore error.
249+
self.inner
250+
.create_account_checkpoint(caller, address, balance, spec_id)
251+
}
252+
253+
fn finalize(&mut self) -> Self::FinalOutput {
254+
self.inner.take_output_and_clear()
255+
}
256+
}

0 commit comments

Comments
 (0)