1
1
//! `block.rs` contains the Simulator and everything that wires it into an
2
2
//! actor that handles the simulation of a stream of bundles and transactions
3
3
//! and turns them into valid Pecorino blocks for network submission.
4
- use crate :: config:: { BuilderConfig , RuProvider } ;
4
+ use crate :: {
5
+ config:: { BuilderConfig , RuProvider } ,
6
+ tasks:: env:: SimEnv ,
7
+ } ;
5
8
use alloy:: { eips:: BlockId , network:: Ethereum , providers:: Provider } ;
6
9
use init4_bin_base:: {
7
10
deps:: tracing:: { debug, error} ,
@@ -17,6 +20,7 @@ use tokio::{
17
20
} ,
18
21
task:: JoinHandle ,
19
22
} ;
23
+ use tracing:: info;
20
24
use trevm:: revm:: {
21
25
context:: BlockEnv ,
22
26
database:: { AlloyDB , WrapDatabaseAsync } ,
@@ -34,9 +38,17 @@ pub struct Simulator {
34
38
pub config : BuilderConfig ,
35
39
/// A provider that cannot sign transactions, used for interacting with the rollup.
36
40
pub ru_provider : RuProvider ,
37
-
38
41
/// The block configuration environment on which to simulate
39
- pub block_env : watch:: Receiver < Option < BlockEnv > > ,
42
+ pub sim_env : watch:: Receiver < Option < SimEnv > > ,
43
+ }
44
+
45
+ /// SimResult bundles a BuiltBlock to the BlockEnv it was simulated against.
46
+ #[ derive( Debug , Clone ) ]
47
+ pub struct SimResult {
48
+ /// The block built with the successfully simulated transactions
49
+ pub block : BuiltBlock ,
50
+ /// The block environment the transactions were simulated against.
51
+ pub env : SimEnv ,
40
52
}
41
53
42
54
impl Simulator {
@@ -46,16 +58,17 @@ impl Simulator {
46
58
///
47
59
/// - `config`: The configuration for the builder.
48
60
/// - `ru_provider`: A provider for interacting with the rollup.
61
+ /// - `block_env`: A receiver for the block environment to simulate against.
49
62
///
50
63
/// # Returns
51
64
///
52
65
/// A new `Simulator` instance.
53
66
pub fn new (
54
67
config : & BuilderConfig ,
55
68
ru_provider : RuProvider ,
56
- block_env : wa
F440
tch:: Receiver < Option < BlockEnv > > ,
69
+ sim_env : watch:: Receiver < Option < SimEnv > > ,
57
70
) -> Self {
58
- Self { config : config. clone ( ) , ru_provider, block_env }
71
+ Self { config : config. clone ( ) , ru_provider, sim_env }
59
72
}
60
73
61
74
/// Get the slot calculator.
@@ -65,11 +78,16 @@ impl Simulator {
65
78
66
79
/// Handles building a single block.
67
80
///
81
+ /// Builds a block in the block environment with items from the simulation cache
82
+ /// against the database state. When the `finish_by` deadline is reached, it
83
+ /// stops simulating and returns the block.
84
+ ///
68
85
/// # Arguments
69
86
///
70
87
/// - `constants`: The system constants for the rollup.
71
88
/// - `sim_items`: The simulation cache containing transactions and bundles.
72
89
/// - `finish_by`: The deadline by which the block must be built.
90
+ /// - `block_env`: The block environment to simulate against.
73
91
///
74
92
/// # Returns
75
93
///
@@ -79,28 +97,35 @@ impl Simulator {
79
97
constants : SignetSystemConstants ,
80
98
sim_items : SimCache ,
81
99
finish_by : Instant ,
82
- block : BlockEnv ,
100
+ block_env : BlockEnv ,
83
101
) -> eyre:: Result < BuiltBlock > {
102
+ debug ! ( block_number = block_env. number, tx_count = sim_items. len( ) , "starting block build" , ) ;
103
+
84
104
let db = self . create_db ( ) . await . unwrap ( ) ;
105
+
85
106
let block_build: BlockBuild < _ , NoOpInspector > = BlockBuild :: new (
86
107
db,
87
108
constants,
88
109
self . config . cfg_env ( ) ,
89
- block ,
110
+ block_env ,
90
111
finish_by,
91
112
self . config . concurrency_limit ,
92
113
sim_items,
93
114
self . config . rollup_block_gas_limit ,
94
115
) ;
95
116
96
117
let built_block = block_build. build ( ) . await ;
97
- debug ! ( block_number = ?built_block. block_number( ) , "finished building block" ) ;
118
+ debug ! (
119
+ tx_count = built_block. tx_count( ) ,
120
+ block_number = built_block. block_number( ) ,
121
+ "block simulation completed" ,
122
+ ) ;
98
123
99
124
Ok ( built_block)
100
125
}
101
126
102
- /// Spawns the simulator task, which handles the setup and sets the deadline
103
- /// for the each round of simulation .
127
+ /// Spawns the simulator task, which ticks along the simulation loop
128
+ /// as it receives block environments .
104
129
///
105
130
/// # Arguments
106
131
///
@@ -115,21 +140,23 @@ impl Simulator {
115
140
self ,
116
141
constants : SignetSystemConstants ,
117
142
cache : SimCache ,
118
- submit_sender : mpsc:: UnboundedSender < BuiltBlock > ,
143
+ submit_sender : mpsc:: UnboundedSender < SimResult > ,
119
144
) -> JoinHandle < ( ) > {
120
145
debug ! ( "starting simulator task" ) ;
121
146
122
147
tokio:: spawn ( async move { self . run_simulator ( constants, cache, submit_sender) . await } )
123
148
}
124
149
125
- /// Continuously runs the block simulation and submission loop.
150
+ /// This function runs indefinitely, waiting for the block environment to be set and checking
151
+ /// if the current slot is valid before building a block and sending it along for to the submit channel.
126
152
///
127
- /// This function clones the simulation cache, calculates a deadline for block building,
128
- /// attempts to build a block using the latest cache and constants, and submits the built
129
- /// block through the provided channel. If an error occurs during block building or submission,
130
- /// it logs the error and continues the loop.
153
+ /// If it is authorized for the current slot, then the simulator task
154
+ /// - clones the simulation cache,
155
+ /// - calculates a deadline for block building,
156
+ /// - attempts to build a block using the latest cache and constants,
157
+ /// - then submits the built block through the provided channel.
131
158
///
132
- /// This function runs indefinitely and never returns .
159
+ /// If an error occurs during block building or submission, it logs the error and continues the loop .
133
160
///
134
161
/// # Arguments
135
162
///
@@ -140,26 +167,29 @@ impl Simulator {
140
167
mut self ,
141
168
constants : SignetSystemConstants ,
142
169
cache : SimCache ,
143
- submit_sender : mpsc:: UnboundedSender < BuiltBlock > ,
170
+ submit_sender : mpsc:: UnboundedSender < SimResult > ,
144
171
) {
145
172
loop {
146
- let sim_cache = cache. clone ( ) ;
147
- let finish_by = self . calculate_deadline ( ) ;
148
-
149
173
// Wait for the block environment to be set
150
- if self . block_env . changed ( ) . await . is_err ( ) {
151
- error ! ( "block_env channel closed" ) ;
174
+ if self . sim_env . changed ( ) . await . is_err ( ) {
175
+ error ! ( "block_env channel closed - shutting down simulator task " ) ;
152
176
return ;
153
177
}
178
+ let Some ( sim_env) = self . sim_env . borrow_and_update ( ) . clone ( ) else { return } ;
179
+ info ! ( sim_env. block_env. number, "new block environment received" ) ;
154
180
155
- // If no env, skip this run
156
- let Some ( block_env) = self . block_env . borrow_and_update ( ) . clone ( ) else { return } ;
157
- debug ! ( block_env = ?block_env, "building on block env" ) ;
158
-
159
- match self . handle_build ( constants, sim_cache, finish_by, block_env) . await {
181
+ // Calculate the deadline for this block simulation.
182
+ // NB: This must happen _after_ taking a reference to the sim cache,
37BF
td>183
+ // waiting for a new block, and checking current slot authorization.
184
+ let finish_by = self . calculate_deadline ( ) ;
185
+ let sim_cache = cache. clone ( ) ;
186
+ match self
187
+ . handle_build ( constants, sim_cache, finish_by, sim_env. block_env . clone ( ) )
188
+ . await
189
+ {
160
190
Ok ( block) => {
161
- debug ! ( block = ?block, "built block" ) ;
162
- let _ = submit_sender. send ( block) ;
191
+ debug ! ( block = ?block. block_number ( ) , tx_count = block . transactions ( ) . len ( ) , "built simulated block" ) ;
192
+ let _ = submit_sender. send ( SimResult { block, env : sim_env } ) ;
163
193
}
164
194
Err ( e) => {
165
195
error ! ( err = %e, "failed to build block" ) ;
@@ -184,11 +214,10 @@ impl Simulator {
184
214
let remaining = self . slot_calculator ( ) . slot_duration ( ) - timepoint;
185
215
186
216
// We add a 1500 ms buffer to account for sequencer stopping signing.
187
-
188
- let candidate =
217
+ let deadline =
189
218
Instant :: now ( ) + Duration :: from_secs ( remaining) - Duration :: from_millis ( 1500 ) ;
190
219
191
- candidate . max ( Instant :: now ( ) )
220
+ deadline . max ( Instant :: now ( ) )
192
221
}
193
222
194
223
/// Creates an `AlloyDB` instance from the rollup provider.
0 commit comments