Skip to content

Commit 04eed56

Browse files
committed
journal: clear no allocation
1 parent 37d3d23 commit 04eed56

5 files changed

Lines changed: 157 additions & 54 deletions

File tree

crates/pevm/src/chain.rs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ pub trait PevmChain: Debug {
5252
// TODO: Support more tx conversions
5353
type Envelope: Debug + From<Signed<TxLegacy>>;
5454

55-
/// The EVM type
55+
/// The EVM type for sequential execution
5656
type Evm<DB: Database>: EvmTr<
5757
Context: ContextTr<
5858
Db = DB,
@@ -76,6 +76,31 @@ pub trait PevmChain: Debug {
7676
Error = EVMError<DB::Error, Self::EvmErrorType>,
7777
>;
7878

79+
/// The EVM type for PEVM parallel execution — uses `Journal<DB, true>` to eliminate
80+
/// dead cross-transaction warm-tracking in the Occupied account/storage paths.
81+
type PevmEvm<DB: Database>: EvmTr<
82+
Context: ContextTr<
83+
Db = DB,
84+
Tx = Self::EvmTx,
85+
Journal = crate::journal::Journal<DB, true>,
86+
Local: LocalContextTr,
87+
> + ContextSetters,
88+
Frame: FrameTr<FrameInit = FrameInit, FrameResult = FrameResult>,
89+
Precompiles: PrecompileProvider<
90+
<Self::PevmEvm<DB> as EvmTr>::Context,
91+
Output = InterpreterResult,
92+
>,
93+
Instructions: InstructionProvider<
94+
Context = <Self::PevmEvm<DB> as EvmTr>::Context,
95+
InterpreterTypes = EthInterpreter,
96+
>,
97+
> + ExecuteEvm<
98+
Tx = Self::EvmTx,
99+
ExecutionResult = ExecutionResult<Self::EvmHaltReason>,
100+
State = EvmState,
101+
Error = EVMError<DB::Error, Self::EvmErrorType>,
102+
>;
103+
79104
/// The EVM Spec type
80105
type EvmSpecId: Into<SpecId> + Copy + Send + Sync + Default;
81106

@@ -123,6 +148,14 @@ pub trait PevmChain: Debug {
123148
db: DB,
124149
) -> Self::Evm<DB>;
125150

151+
/// Get `Self::PevmEvm`
152+
fn build_pevm_evm<DB: Database>(
153+
&self,
154+
spec_id: Self::EvmSpecId,
155+
block_env: BlockEnv,
156+
db: DB,
157+
) -> Self::PevmEvm<DB>;
158+
126159
/// Get `Self::EvmTx`
127160
fn get_tx_env(
128161
&self,
@@ -135,7 +168,7 @@ pub trait PevmChain: Debug {
135168
/// Whether this transaction has a nonce. Return false for types that have no nonce
136169
/// (e.g. OP deposits) so pevm's sender-nonce ordering check is skipped. Implementations
137170
/// may also adjust EVM cfg as a side effect (e.g. setting `disable_nonce_check`).
138-
fn has_nonce<DB: Database>(&self, _: &mut Self::Evm<DB>, _: &Self::EvmTx) -> bool {
171+
fn has_nonce<DB: Database>(&self, _: &mut Self::PevmEvm<DB>, _: &Self::EvmTx) -> bool {
139172
true
140173
}
141174

crates/pevm/src/chain/ethereum.rs

Lines changed: 44 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,46 @@ fn get_ethereum_gas_price(tx: &TxEnvelope) -> Result<u128, EthereumTransactionPa
5959
}
6060
}
6161

62+
impl PevmEthereum {
63+
fn build_evm_inner<DB: Database, const IS_PEVM: bool>(
64+
&self,
65+
spec_id: SpecId,
66+
block_env: BlockEnv,
67+
db: DB,
68+
) -> MainnetEvm<Context<BlockEnv, TxEnv, CfgEnv, DB, crate::journal::Journal<DB, IS_PEVM>, ()>>
69+
{
70+
let mut cfg = CfgEnv::new_with_spec(spec_id).with_chain_id(self.id);
71+
if spec_id >= SpecId::PRAGUE {
72+
cfg = cfg.with_max_blobs_per_tx(MAX_BLOB_NUMBER_PER_BLOCK_PRAGUE);
73+
} else if spec_id >= SpecId::CANCUN {
74+
cfg = cfg.with_max_blobs_per_tx(MAX_BLOB_NUMBER_PER_BLOCK_CANCUN);
75+
}
76+
let journal_cfg = JournalCfg {
77+
spec: spec_id,
78+
eip7708_disabled: cfg.amsterdam_eip7708_disabled,
79+
eip7708_delayed_burn_disabled: cfg.amsterdam_eip7708_delayed_burn_disabled,
80+
};
81+
Context {
82+
block: block_env,
83+
tx: TxEnv::default(),
84+
cfg,
85+
journaled_state: crate::journal::Journal::<DB, IS_PEVM>::new(db, journal_cfg),
86+
chain: (),
87+
local: LocalContext::default(),
88+
error: Ok(()),
89+
}
90+
.build_mainnet()
91+
}
92+
}
93+
6294
impl PevmChain for PevmEthereum {
6395
type Network = alloy_provider::network::Ethereum;
6496
type Transaction = alloy_rpc_types_eth::Transaction;
6597
type Envelope = TxEnvelope;
6698
type Evm<DB: Database> =
6799
MainnetEvm<Context<BlockEnv, TxEnv, CfgEnv, DB, crate::journal::Journal<DB>, ()>>;
100+
type PevmEvm<DB: Database> =
101+
MainnetEvm<Context<BlockEnv, TxEnv, CfgEnv, DB, crate::journal::Journal<DB, true>, ()>>;
68102
type EvmSpecId = SpecId;
69103
type EvmTx = TxEnv;
70104
type EvmHaltReason = HaltReason;
@@ -122,27 +156,16 @@ impl PevmChain for PevmEthereum {
122156
block_env: BlockEnv,
123157
db: DB,
124158
) -> Self::Evm<DB> {
125-
let mut cfg = CfgEnv::new_with_spec(spec_id).with_chain_id(self.id);
126-
if spec_id >= SpecId::PRAGUE {
127-
cfg = cfg.with_max_blobs_per_tx(MAX_BLOB_NUMBER_PER_BLOCK_PRAGUE);
128-
} else if spec_id >= SpecId::CANCUN {
129-
cfg = cfg.with_max_blobs_per_tx(MAX_BLOB_NUMBER_PER_BLOCK_CANCUN);
130-
}
131-
let journal_cfg = JournalCfg {
132-
spec: spec_id,
133-
eip7708_disabled: cfg.amsterdam_eip7708_disabled,
134-
eip7708_delayed_burn_disabled: cfg.amsterdam_eip7708_delayed_burn_disabled,
135-
};
136-
Context {
137-
block: block_env,
138-
tx: TxEnv::default(),
139-
cfg,
140-
journaled_state: crate::journal::Journal::new(db, journal_cfg),
141-
chain: (),
142-
local: LocalContext::default(),
143-
error: Ok(()),
144-
}
145-
.build_mainnet()
159+
self.build_evm_inner::<DB, false>(spec_id, block_env, db)
160+
}
161+
162+
fn build_pevm_evm<DB: Database>(
163+
&self,
164+
spec_id: Self::EvmSpecId,
165+
block_env: BlockEnv,
166+
db: DB,
167+
) -> Self::PevmEvm<DB> {
168+
self.build_evm_inner::<DB, true>(spec_id, block_env, db)
146169
}
147170

148171
/// Get the REVM tx envs of an Alloy block.

crates/pevm/src/chain/rise.rs

Lines changed: 58 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,42 @@ fn get_gas_price(tx: &OpTxEnvelope) -> Result<u128, RiseTransactionParsingError>
6161
}
6262
}
6363

64+
impl PevmRise {
65+
fn build_evm_inner<DB: Database, const IS_PEVM: bool>(
66+
&self,
67+
spec_id: OpSpecId,
68+
block_env: BlockEnv,
69+
db: DB,
70+
) -> OpEvm<
71+
Context<
72+
BlockEnv,
73+
OpTransaction<TxEnv>,
74+
CfgEnv<OpSpecId>,
75+
DB,
76+
crate::journal::Journal<DB, IS_PEVM>,
77+
L1BlockInfo,
78+
>,
79+
(),
80+
> {
81+
let cfg = CfgEnv::new_with_spec(spec_id).with_chain_id(RISE_CHAIN_ID);
82+
let journal_cfg = JournalCfg {
83+
spec: spec_id.into(),
84+
eip7708_disabled: cfg.amsterdam_eip7708_disabled,
85+
eip7708_delayed_burn_disabled: cfg.amsterdam_eip7708_delayed_burn_disabled,
86+
};
87+
Context {
88+
block: block_env,
89+
tx: OpTransaction::default(),
90+
cfg,
91+
journaled_state: crate::journal::Journal::<DB, IS_PEVM>::new(db, journal_cfg),
92+
chain: L1BlockInfo::default(),
93+
local: LocalContext::default(),
94+
error: Ok(()),
95+
}
96+
.build_op()
97+
}
98+
}
99+
64100
impl PevmChain for PevmRise {
65101
type Network = op_alloy_network::Optimism;
66102
type Transaction = op_alloy_rpc_types::Transaction;
@@ -76,6 +112,17 @@ impl PevmChain for PevmRise {
76112
>,
77113
(),
78114
>;
115+
type PevmEvm<DB: Database> = OpEvm<
116+
Context<
117+
BlockEnv,
118+
op_revm::OpTransaction<TxEnv>,
119+
CfgEnv<op_revm::OpSpecId>,
120+
DB,
121+
crate::journal::Journal<DB, true>,
122+
op_revm::L1BlockInfo,
123+
>,
124+
(),
125+
>;
79126
type EvmSpecId = OpSpecId;
80127
type EvmTx = OpTransaction<TxEnv>;
81128
type EvmHaltReason = OpHaltReason;
@@ -106,22 +153,16 @@ impl PevmChain for PevmRise {
106153
block_env: BlockEnv,
107154
db: DB,
108155
) -> Self::Evm<DB> {
109-
let cfg = CfgEnv::new_with_spec(spec_id).with_chain_id(RISE_CHAIN_ID);
110-
let journal_cfg = JournalCfg {
111-
spec: spec_id.into(),
112-
eip7708_disabled: cfg.amsterdam_eip7708_disabled,
113-
eip7708_delayed_burn_disabled: cfg.amsterdam_eip7708_delayed_burn_disabled,
114-
};
115-
Context {
116-
block: block_env,
117-
tx: OpTransaction::default(),
118-
cfg,
119-
journaled_state: crate::journal::Journal::new(db, journal_cfg),
120-
chain: L1BlockInfo::default(),
121-
local: LocalContext::default(),
122-
error: Ok(()),
123-
}
124-
.build_op()
156+
self.build_evm_inner::<DB, false>(spec_id, block_env, db)
157+
}
158+
159+
fn build_pevm_evm<DB: Database>(
160+
&self,
161+
spec_id: Self::EvmSpecId,
162+
block_env: BlockEnv,
163+
db: DB,
164+
) -> Self::PevmEvm<DB> {
165+
self.build_evm_inner::<DB, true>(spec_id, block_env, db)
125166
}
126167

127168
fn build_mv_memory(&self, block_env: &BlockEnv, txs: &[OpTransaction<TxEnv>]) -> MvMemory {
@@ -293,7 +334,7 @@ impl PevmChain for PevmRise {
293334
&tx.base
294335
}
295336

296-
fn has_nonce<DB: Database>(&self, evm: &mut Self::Evm<DB>, tx: &Self::EvmTx) -> bool {
337+
fn has_nonce<DB: Database>(&self, evm: &mut Self::PevmEvm<DB>, tx: &Self::EvmTx) -> bool {
297338
let is_deposit = tx.is_deposit();
298339
evm.ctx()
299340
.modify_cfg(|cfg| cfg.disable_nonce_check = is_deposit);

crates/pevm/src/journal.rs

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -462,7 +462,7 @@ impl<'a, DB: Database> JournaledAccountTr for JournaledAccount<'a, DB> {
462462
/// EIP-7708 (Amsterdam) is omitted — neither Ethereum (CANCUN) nor RISE (JOVIAN=Prague) needs it.
463463
#[allow(missing_docs)]
464464
#[derive(Debug)]
465-
pub struct Journal<DB: Database> {
465+
pub struct Journal<DB: Database, const IS_PEVM: bool = false> {
466466
pub database: DB,
467467
pub state: EvmState,
468468
/// EIP-1153 transient storage, cleared after every transaction.
@@ -474,11 +474,9 @@ pub struct Journal<DB: Database> {
474474
pub transaction_id: usize,
475475
pub cfg: JournalCfg,
476476
pub warm_addresses: WarmAddresses,
477-
/// True when running inside pevm's parallel execution path.
478-
pub is_pevm: bool,
479477
}
480478

481-
impl<DB: Database> Journal<DB> {
479+
impl<DB: Database, const IS_PEVM: bool> Journal<DB, IS_PEVM> {
482480
pub(crate) fn new(database: DB, cfg: JournalCfg) -> Self {
483481
Self {
484482
database,
@@ -490,7 +488,6 @@ impl<DB: Database> Journal<DB> {
490488
transaction_id: 0,
491489
cfg,
492490
warm_addresses: WarmAddresses::new(),
493-
is_pevm: false,
494491
}
495492
}
496493

@@ -621,7 +618,7 @@ impl<DB: Database> Journal<DB> {
621618
}
622619
}
623620

624-
impl<DB: Database> JournalTr for Journal<DB> {
621+
impl<DB: Database, const IS_PEVM: bool> JournalTr for Journal<DB, IS_PEVM> {
625622
type Database = DB;
626623
type State = EvmState;
627624
type JournaledAccount<'a>
@@ -679,7 +676,20 @@ impl<DB: Database> JournalTr for Journal<DB> {
679676
}
680677

681678
fn clear(&mut self) {
682-
self.finalize();
679+
if IS_PEVM {
680+
// State is either already empty (taken by finalize on success) or leftover from
681+
// a failed tx. Either way, clear in-place to retain heap allocations for reuse.
682+
// Pre-Spurious-Dragon fixup in finalize() is irrelevant — state is being discarded.
683+
self.state.clear();
684+
self.warm_addresses.clear_coinbase_and_access_list();
685+
self.logs.clear();
686+
self.transient_storage.clear();
687+
self.journal.clear();
688+
self.depth = 0;
689+
self.transaction_id = 0;
690+
} else {
691+
self.finalize();
692+
}
683693
}
684694

685695
fn depth(&self) -> usize {

crates/pevm/src/vm.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,7 @@ pub(crate) struct Vm<'a, S: Storage, C: PevmChain> {
477477
mv_memory: &'a MvMemory,
478478
beneficiary_location_hash: MemoryLocationHash,
479479
// Dedicated EVM for the worker, reset before each transaction exectution.
480-
evm: C::Evm<VmDb<'a, S>>,
480+
evm: C::PevmEvm<VmDb<'a, S>>,
481481
}
482482

483483
impl<'a, S: Storage, C: PevmChain> Vm<'a, S, C> {
@@ -516,11 +516,7 @@ impl<'a, S: Storage, C: PevmChain> Vm<'a, S, C> {
516516
beneficiary_location_hash: hash_deterministic(MemoryLocation::Basic(
517517
block_env.beneficiary,
518518
)),
519-
evm: {
520-
let mut evm = chain.build_evm(spec_id, block_env.clone(), db);
521-
evm.ctx_mut().journal_mut().is_pevm = true;
522-
evm
523-
},
519+
evm: chain.build_pevm_evm(spec_id, block_env.clone(), db),
524520
}
525521
}
526522

@@ -779,7 +775,7 @@ impl<C, DB> Default for NoBeneficiaryHandler<C, DB> {
779775
}
780776

781777
impl<C: PevmChain, DB: Database> Handler for NoBeneficiaryHandler<C, DB> {
782-
type Evm = C::Evm<DB>;
778+
type Evm = C::PevmEvm<DB>;
783779
type Error = EVMError<DB::Error, InvalidTransaction>;
784780
type HaltReason = C::EvmHaltReason;
785781

0 commit comments

Comments
 (0)