1717 state:: { AccountInfo , Bytecode } ,
1818 } ,
1919 } ,
20- std:: { sync:: Arc , time:: Instant } ,
20+ std:: { iter :: Successors , sync:: Arc , time:: Instant } ,
2121 thiserror:: Error ,
2222} ;
2323
@@ -35,11 +35,11 @@ pub enum Error<P: Platform> {
3535///
3636/// Notes:
3737/// - There is no public API to create a checkpoint directly. Checkpoints are
38- /// created by the [`BlockContext`] when it starts a new payload building
39- /// process or by mutatations applied to an already existing checkpoint.
38+ /// created from the [`BlockContext`] when it starts a new payload building
39+ /// process or by mutations applied to an already existing checkpoint.
4040///
4141/// - Checkpoints contain all the information needed to assemble a full block
42- /// payload, they however cannot be used directly to assemble a block. The
42+ /// payload. However , they cannot be used directly to assemble a block. The
4343/// block assembly process is very node-specific and is part of the pipelines
4444/// api, which has more info and access to the underlying node facilities.
4545///
@@ -48,13 +48,13 @@ pub enum Error<P: Platform> {
4848/// existing ones, forming a chain of checkpoints.
4949///
5050/// - Checkpoints may represent forks in the payload building process. Two
51- /// checkpoints can share a common ancestor, without having linear history
51+ /// checkpoints can share a common ancestor without having a linear history
5252/// between them. Each of the diverging checkpoints can be used to build
5353/// alternative versions of the payload.
5454///
55- /// - Checkpoints are cheap to clone, discard and move around. They are
56- /// expensive to create, as they require executing a transaction by the EVM
57- /// and storing the resulting state changes.
55+ /// - Checkpoints are inexpensive to clone, discard and move around. However,
56+ /// they are expensive to create, as they require executing transactions
57+ /// through the EVM and storing the resulting state changes.
5858///
5959/// - Checkpoints are thread-safe, Send + Sync + 'static.
6060///
@@ -75,11 +75,11 @@ pub struct Checkpoint<P: Platform> {
7575
7676/// Public read API
7777impl < P : Platform > Checkpoint < P > {
78- /// Returns the number of checkpoints preceeding this checkpoint since the
79- /// beginning of the block payload we're building .
78+ /// Returns the number of checkpoints preceding this checkpoint from the
79+ /// beginning of the block payload.
8080 ///
8181 /// Depth zero is when [`BlockContext::start`] is called, and the first
82- /// checkpoint is created and has no previous checkpoints.
82+ /// checkpoint is created with no previous checkpoints.
8383 pub fn depth ( & self ) -> usize {
8484 self . inner . depth
8585 }
@@ -89,7 +89,7 @@ impl<P: Platform> Checkpoint<P> {
8989 self . inner . created_at
9090 }
9191
92- /// The returns the payload version before the current checkpoint.
92+ /// Returns the previous checkpoint before the current checkpoint.
9393 ///
9494 /// Using the previous checkpoint is equivalent to discarding the
9595 /// state mutations made in the current checkpoint.
@@ -102,16 +102,19 @@ impl<P: Platform> Checkpoint<P> {
102102 } )
103103 }
104104
105- /// Returns the block context that is the root of theis checkpoint.
105+ /// Returns the block context at the root of the checkpoint.
106106 pub fn block ( & self ) -> & BlockContext < P > {
107107 & self . inner . block
108108 }
109109
110- /// The transactions that created this checkpoint. This could be either an
111- /// empty iterator if this checkpoint is a barrier or other non-transaction
112- /// checkpoint, it can be one transaction if this checkpoint was created by
113- /// applying a single transaction, or it can be multiple if this checkpoint
114- /// represents a bundle.
110+ /// The transactions that created this checkpoint.
111+ /// The returned slice is a view into all applied transactions in this
112+ /// checkpoint:
113+ /// - Empty if this checkpoint is a barrier or other non-transaction
114+ /// checkpoint.
115+ /// - Single transaction if this checkpoint was created by applying a single
116+ /// transaction.
117+ /// - Multiple transactions if this checkpoint represents a bundle.
115118 pub fn transactions ( & self ) -> & [ Recovered < types:: Transaction < P > > ] {
116119 match & self . inner . mutation {
117120 Mutation :: Barrier | Mutation :: NamedBarrier ( _) => & [ ] ,
@@ -128,7 +131,7 @@ impl<P: Platform> Checkpoint<P> {
128131 }
129132 }
130133
131- /// The state changes that occured as a result of executing the
134+ /// The state changes that occurred as a result of executing the
132135 /// transaction(s) that created this checkpoint.
133136 pub fn state ( & self ) -> Option < & BundleState > {
134137 match self . inner . mutation {
@@ -147,27 +150,25 @@ impl<P: Platform> Checkpoint<P> {
147150 matches ! ( self . inner. mutation, Mutation :: NamedBarrier ( ref barrier_name) if barrier_name == name)
148151 }
149152
150- /// If this checkpoint is a single transaction, returns a reference to the
151- /// transaction that created this checkpoint. otherwise returns `None`.
153+ /// If this checkpoint is created from a single transaction, returns a
154+ /// reference to this transaction. Otherwise, returns `None`.
152155 pub fn as_transaction ( & self ) -> Option < & Recovered < types:: Transaction < P > > > {
153156 if let Mutation :: Executable ( result) = & self . inner . mutation {
154157 if let Executable :: Transaction ( tx) = result. source ( ) {
155158 return Some ( tx) ;
156159 }
157160 }
158-
159161 None
160162 }
161163
162- /// If this checkpoint is a bundle, returns a reference to the bundle that
163- /// created this checkpoint. otherwise returns `None`.
164+ /// If this checkpoint is created from a bundle, returns a reference to this
165+ /// bundle. Otherwise, returns `None`.
164166 pub fn as_bundle ( & self ) -> Option < & types:: Bundle < P > > {
165167 if let Mutation :: Executable ( result) = & self . inner . mutation {
166168 if let Executable :: Bundle ( bundle) = result. source ( ) {
167169 return Some ( bundle) ;
168170 }
169171 }
170-
171172 None
172173 }
173174}
@@ -182,32 +183,35 @@ impl<P: Platform> Checkpoint<P> {
182183 & self ,
183184 executable : impl IntoExecutable < P , S > ,
184185 ) -> Result < Self , ExecutionError < P > > {
185- Ok ( Self {
186- inner : Arc :: new ( CheckpointInner {
187- block : self . inner . block . clone ( ) ,
188- prev : Some ( Arc :: clone ( & self . inner ) ) ,
189- depth : self . inner . depth + 1 ,
190- mutation : Mutation :: Executable (
191- executable
192- . try_into_executable ( ) ?
193- . execute ( self . block ( ) , self ) ?,
194- ) ,
195- created_at : Instant :: now ( ) ,
196- } ) ,
197- } )
186+ let mutation = Mutation :: Executable (
187+ executable
188+ . try_into_executable ( ) ?
189+ . execute ( self . block ( ) , self ) ?,
190+ ) ;
191+ Ok ( self . apply_with ( mutation) )
198192 }
199193
200194 /// Creates a new checkpoint on top of the current checkpoint that introduces
201195 /// a barrier. This new checkpoint will be now considered the new beginning of
202196 /// mutable history.
203197 #[ must_use]
204198 pub fn barrier ( & self ) -> Self {
199+ Self :: apply_with ( self , Mutation :: Barrier )
200+ }
201+ }
202+
203+ /// Internal API
204+ impl < P : Platform > Checkpoint < P > {
205+ // Create a new checkpoint on top of the current one with the given mutation.
206+ // See public builder API.
207+ #[ must_use]
208+ fn apply_with ( & self , mutation : Mutation < P > ) -> Self {
205209 Self {
206210 inner : Arc :: new ( CheckpointInner {
207211 block : self . inner . block . clone ( ) ,
208212 prev : Some ( Arc :: clone ( & self . inner ) ) ,
209213 depth : self . inner . depth + 1 ,
210- mutation : Mutation :: Barrier ,
214+ mutation,
211215 created_at : Instant :: now ( ) ,
212216 } ) ,
213217 }
@@ -228,13 +232,11 @@ impl<P: Platform> Checkpoint<P> {
228232 } ) ,
229233 }
230234 }
231- }
232235
233- /// Internal API
234- impl < P : Platform > Checkpoint < P > {
235236 /// Start a new checkpoint for an empty payload rooted at the
236237 /// state of the parent block of the block for which the payload is
237238 /// being built.
239+ #[ must_use]
238240 pub ( super ) fn new_at_block ( block : BlockContext < P > ) -> Self {
239241 Self {
240242 inner : Arc :: new ( CheckpointInner {
@@ -246,14 +248,35 @@ impl<P: Platform> Checkpoint<P> {
246248 } ) ,
247249 }
248250 }
251+
252+ /// Lazy iterator over historic checkpoints.
253+ /// Note that it is in reverse history order, starting from the latest applied
254+ /// checkpoint up to the first one.
255+ fn iter ( & self ) -> Successors < Self , fn ( & Self ) -> Option < Self > > {
256+ <& Self as IntoIterator >:: into_iter ( self )
257+ }
249258}
250259
251- /// Describes the type of state mutation that was applied to the
252- /// previous checkpoint to create this checkpoint.
260+ impl < P : Platform > IntoIterator for & Checkpoint < P > {
261+ type IntoIter =
262+ Successors < Checkpoint < P > , fn ( & Checkpoint < P > ) -> Option < Checkpoint < P > > > ;
263+ type Item = Checkpoint < P > ;
264+
265+ fn into_iter ( self ) -> Self :: IntoIter {
266+ std:: iter:: successors ( Some ( self . clone ( ) ) , |cp| {
267+ cp. inner . prev . as_ref ( ) . map ( |prev| Checkpoint {
268+ inner : Arc :: clone ( prev) ,
269+ } )
270+ } )
271+ }
272+ }
273+
274+ /// Describes the type of state mutation that was applied to the previous
275+ /// checkpoint to create this checkpoint.
253276enum Mutation < P : Platform > {
254277 /// A checkpoint that indicates that any prior checkpoints are immutable and
255278 /// should not be discarded or reordered. An example of this would be placing
256- /// a barrier after applying sequencer transactions, to ensure that they do
279+ /// a barrier after applying sequencer transactions to ensure that they do
257280 /// not get reordered by pipelines. Another example would be placing a barrier
258281 /// after every commited flashblock, to ensure that any steps in the pipeline
259282 /// do not modify the commited state of the payload in process.
@@ -284,13 +307,14 @@ struct CheckpointInner<P: Platform> {
284307 /// The previous checkpoint in this chain of checkpoints, if any.
285308 prev : Option < Arc < Self > > ,
286309
287- /// The number of checkpoints in the chain starting from the begining of the
310+ /// The number of checkpoints in the chain starting from the beginning of the
288311 /// block context.
289312 ///
290- /// Depth zero is when [`BlockContext::start`] is called, and the first
313+ /// Depth zero is when [`BlockContext::start`] is called, as the first
314+ /// checkpoint
291315 depth : usize ,
292316
293- /// The mutation
317+ /// The mutation kind for the checkpoint.
294318 mutation : Mutation < P > ,
295319
296320 /// The timestamp when this checkpoint was created.
@@ -311,7 +335,7 @@ impl<P: Platform> From<Checkpoint<P>> for Vec<types::Transaction<P>> {
311335
312336/// Any checkpoint can be used as a database reference for an EVM instance.
313337/// The state at a checkpoint is the cumulative aggregate of all state mutations
314- /// that occured in the current checkpoint and all its ancestors on top of the
338+ /// that occurred in the current checkpoint and all its ancestors on top of the
315339/// base state of the parent block of the block for which the payload is being
316340/// built.
317341impl < P : Platform > DatabaseRef for Checkpoint < P > {
@@ -327,19 +351,15 @@ impl<P: Platform> DatabaseRef for Checkpoint<P> {
327351 // starting from the most recent one, to find the first checkpoint
328352 // that has touched the given address.
329353
330- let mut current = Some ( & self . inner ) ;
331- while let Some ( checkpoint) = current {
332- if let Mutation :: Executable ( result) = & checkpoint. mutation {
333- if let Some ( account) = result
334- . state ( )
335- . account ( & address)
336- . and_then ( |account| account. info . as_ref ( ) )
337- {
338- return Ok ( Some ( account. clone ( ) ) ) ;
339- }
340- }
341-
342- current = checkpoint. prev . as_ref ( ) ;
354+ if let Some ( account) = self . iter ( ) . find_map ( |checkpoint| {
355+ checkpoint
356+ . result ( ) ?
357+ . state ( )
358+ . account ( & address)
359+ . and_then ( |account| account. info . as_ref ( ) )
360+ . cloned ( )
361+ } ) {
362+ return Ok ( Some ( account) ) ;
343363 }
344364
345365 // none of the checkpoints priori to this have touched this address,
@@ -359,17 +379,14 @@ impl<P: Platform> DatabaseRef for Checkpoint<P> {
359379 // starting from the most recent one, to find the first checkpoint
360380 // that has created the code with the given hash.
361381
362- let mut current = Some ( & self . inner ) ;
363- while let Some ( checkpoint) = current {
364- if let Mutation :: Executable ( result) = & checkpoint. mutation {
365- if let Some ( code) = result. state ( ) . bytecode ( & code_hash) {
366- return Ok ( code) ;
367- }
368- }
369-
370- current = checkpoint. prev . as_ref ( ) ;
382+ if let Some ( code) = self
383+ . iter ( )
384+ . find_map ( |checkpoint| checkpoint. result ( ) ?. state ( ) . bytecode ( & code_hash) )
385+ {
386+ return Ok ( code) ;
371387 }
372388
389+ // check if the code exists in the base state of the block context.
373390 Ok (
374391 self
375392 . block ( )
@@ -389,19 +406,15 @@ impl<P: Platform> DatabaseRef for Checkpoint<P> {
389406 // traverse checkpoints history looking for the first checkpoint that
390407 // has touched the given address.
391408
392- let mut current = Some ( & self . inner ) ;
393- while let Some ( checkpoint) = current {
394- if let Mutation :: Executable ( result) = & checkpoint. mutation {
395- if let Some ( slot) = result
396- . state ( )
397- . account ( & address)
398- . and_then ( |account| account. storage . get ( & index) )
399- {
400- return Ok ( slot. present_value ) ;
401- }
402- }
403-
404- current = checkpoint. prev . as_ref ( ) ;
409+ if let Some ( value) = self . iter ( ) . find_map ( |checkpoint| {
410+ checkpoint
411+ . result ( ) ?
412+ . state ( )
413+ . account ( & address)
414+ . and_then ( |account| account. storage . get ( & index) )
415+ . map ( |slot| slot. present_value )
416+ } ) {
417+ return Ok ( value) ;
405418 }
406419
407420 // none of the checkpoints prior to this have touched this address,
0 commit comments