@@ -10,6 +10,7 @@ use crate::tree::{
10
10
use alloy_consensus:: transaction:: Recovered ;
11
11
use alloy_evm:: Database ;
12
12
use alloy_primitives:: { keccak256, map:: B256Set , B256 } ;
13
+ use itertools:: Itertools ;
13
14
use metrics:: { Gauge , Histogram } ;
14
15
use reth_evm:: { ConfigureEvm , Evm , EvmFor } ;
15
16
use reth_metrics:: Metrics ;
@@ -37,8 +38,6 @@ pub(super) struct PrewarmCacheTask<N: NodePrimitives, P, Evm> {
37
38
pending : VecDeque < Recovered < N :: SignedTx > > ,
38
39
/// Context provided to execution tasks
39
40
ctx : PrewarmContext < N , P , Evm > ,
40
- /// How many txs are currently in progress
41
- in_progress : usize ,
42
41
/// How many transactions should be executed in parallel
43
42
max_concurrency : usize ,
44
43
/// Sender to emit evm state outcome messages, if any.
69
68
execution_cache,
70
69
pending,
71
70
ctx,
72
- in_progress : 0 ,
73
71
max_concurrency : 64 ,
74
72
to_multi_proof,
75
73
actions_rx,
@@ -82,45 +80,19 @@ where
82
80
self . actions_tx . clone ( )
83
81
}
84
82
85
- /// Spawns the next transactions
86
- fn spawn_next ( & mut self ) {
87
- while self . in_progress < self . max_concurrency {
88
- if let Some ( tx) = self . pending . pop_front ( ) {
89
- // increment the in progress counter
90
- self . in_progress += 1 ;
83
+ /// Spawns all pending transactions as blocking tasks by first chunking them.
84
+ fn spawn_all ( & mut self ) {
85
+ let chunk_size = ( self . pending . len ( ) / self . max_concurrency ) . max ( 1 ) ;
91
86
92
- self . spawn_transaction ( tx) ;
93
- } else {
94
- break
95
- }
96
- }
97
- }
98
-
99
- /// Spawns the given transaction as a blocking task.
100
- fn spawn_transaction ( & self , tx : Recovered < N :: SignedTx > ) {
101
- let ctx = self . ctx . clone ( ) ;
102
- let metrics = self . ctx . metrics . clone ( ) ;
103
- let actions_tx = self . actions_tx . clone ( ) ;
104
- let prepare_proof_targets = self . should_prepare_multi_proof_targets ( ) ;
87
+ for chunk in & self . pending . drain ( ..) . chunks ( chunk_size) {
88
+ let sender = self . actions_tx . clone ( ) ;
89
+ let ctx = self . ctx . clone ( ) ;
90
+ let pending_chunk = chunk. collect :: < Vec < _ > > ( ) ;
105
91
106
- self . executor . spawn_blocking ( move || {
107
- let start = Instant :: now ( ) ;
108
- // depending on whether this task needs he proof targets we either just transact or
109
- // transact and prepare the targets
110
- let proof_targets = if prepare_proof_targets {
111
- ctx. prepare_multiproof_targets ( tx)
112
- } else {
113
- ctx. transact ( tx) ;
114
- None
115
- } ;
116
- let _ = actions_tx. send ( PrewarmTaskEvent :: Outcome { proof_targets } ) ;
117
- metrics. total_runtime . record ( start. elapsed ( ) ) ;
118
- } ) ;
119
- }
120
-
121
- /// Returns true if the tx prewarming tasks should prepare multiproof targets.
122
- fn should_prepare_multi_proof_targets ( & self ) -> bool {
123
- self . to_multi_proof . is_some ( )
92
+ self . executor . spawn_blocking ( move || {
93
+ ctx. transact_batch ( & pending_chunk, sender) ;
94
+ } ) ;
95
+ }
124
96
}
125
97
126
98
/// If configured and the tx returned proof targets, emit the targets the transaction produced
@@ -160,7 +132,7 @@ where
160
132
self . ctx . metrics . transactions_histogram . record ( self . pending . len ( ) as f64 ) ;
161
133
162
134
// spawn execution tasks.
163
- self . spawn_next ( ) ;
135
+ self . spawn_all ( ) ;
164
136
165
137
while let Ok ( event) = self . actions_rx . recv ( ) {
166
138
match event {
@@ -170,7 +142,6 @@ where
170
142
}
171
143
PrewarmTaskEvent :: Outcome { proof_targets } => {
172
144
// completed a transaction, frees up one slot
173
- self . in_progress -= 1 ;
174
145
self . send_multi_proof_targets ( proof_targets) ;
175
146
}
176
147
PrewarmTaskEvent :: Terminate { block_output } => {
@@ -182,9 +153,6 @@ where
182
153
break
183
154
}
184
155
}
185
-
186
- // schedule followup transactions
187
- self . spawn_next ( ) ;
188
156
}
189
157
}
190
158
}
@@ -207,17 +175,6 @@ where
207
175
P : BlockReader + StateProviderFactory + StateReader + StateCommitmentProvider + Clone + ' static ,
208
176
Evm : ConfigureEvm < Primitives = N > + ' static ,
209
177
{
210
- /// Transacts the transactions and transform the state into [`MultiProofTargets`].
211
- fn prepare_multiproof_targets ( self , tx : Recovered < N :: SignedTx > ) -> Option < MultiProofTargets > {
212
- let metrics = self . metrics . clone ( ) ;
213
- let state = self . transact ( tx) ?;
214
-
215
- let ( targets, storage_targets) = multiproof_targets_from_state ( state) ;
216
- metrics. prefetch_storage_targets . record ( storage_targets as f64 ) ;
217
-
218
- Some ( targets)
219
- }
220
-
221
178
/// Splits this context into an evm, an evm config, and metrics.
222
179
fn evm_for_ctx ( self ) -> Option < ( EvmFor < Evm , impl Database > , Evm , PrewarmMetrics ) > {
223
180
let Self { header, evm_config, cache : caches, cache_metrics, provider, metrics } = self ;
@@ -252,35 +209,41 @@ where
252
209
Some ( ( evm, evm_config, metrics) )
253
210
}
254
211
255
- /// Transacts the transaction and returns the state outcome.
212
+ /// Transacts the vec of transactions and returns the state outcome.
256
213
///
257
- /// Returns `None` if executing the transaction failed to a non Revert error.
214
+ /// Returns `None` if executing the transactions failed to a non Revert error.
258
215
/// Returns the touched+modified state of the transaction.
259
216
///
260
- /// Note: Since here are no ordering guarantees this won't the state the tx produces when
217
+ /// Note: Since here are no ordering guarantees this won't the state the txs produce when
261
218
/// executed sequentially.
262
- fn transact ( self , tx : Recovered < N :: SignedTx > ) -> Option < EvmState > {
263
- let ( mut evm, evm_config, metrics) = self . evm_for_ctx ( ) ? ;
219
+ fn transact_batch ( self , txs : & [ Recovered < N :: SignedTx > ] , sender : Sender < PrewarmTaskEvent > ) {
220
+ let Some ( ( mut evm, evm_config, metrics) ) = self . evm_for_ctx ( ) else { return } ;
264
221
265
- // create the tx env and reset nonce
266
- let tx_env = evm_config. tx_env ( & tx) ;
267
- let start = Instant :: now ( ) ;
268
- let res = match evm. transact ( tx_env) {
269
- Ok ( res) => res,
270
- Err ( err) => {
271
- trace ! (
272
- target: "engine::tree" ,
273
- %err,
274
- tx_hash=%tx. tx_hash( ) ,
275
- sender=%tx. signer( ) ,
276
- "Error when executing prewarm transaction" ,
277
- ) ;
278
- return None
279
- }
280
- } ;
281
- metrics. execution_duration . record ( start. elapsed ( ) ) ;
222
+ for tx in txs {
223
+ // create the tx env
224
+ let tx_env = evm_config. tx_env ( tx) ;
225
+ let start = Instant :: now ( ) ;
226
+ let res = match evm. transact ( tx_env) {
227
+ Ok ( res) => res,
228
+ Err ( err) => {
229
+ trace ! (
230
+ target: "engine::tree" ,
231
+ %err,
232
+ tx_hash=%tx. tx_hash( ) ,
233
+ sender=%tx. signer( ) ,
234
+ "Error when executing prewarm transaction" ,
235
+ ) ;
236
+ return
237
+ }
238
+ } ;
239
+ metrics. execution_duration . record ( start. elapsed ( ) ) ;
282
240
283
- Some ( res. state )
241
+ let ( targets, storage_targets) = multiproof_targets_from_state ( res. state ) ;
242
+ metrics. prefetch_storage_targets . record ( storage_targets as f64 ) ;
243
+ metrics. total_runtime . record ( start. elapsed ( ) ) ;
244
+
245
+ let _ = sender. send ( PrewarmTaskEvent :: Outcome { proof_targets : Some ( targets) } ) ;
246
+ }
284
247
}
285
248
}
286
249
0 commit comments