@@ -390,29 +390,15 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
390
390
. map ( |slot| slot. epoch ( T :: EthSpec :: slots_per_epoch ( ) ) )
391
391
}
392
392
393
- /// Iterates across all `(block_root, slot)` pairs from the head of the chain (inclusive) to
394
- /// the earliest reachable ancestor (may or may not be genesis ).
393
+ /// Iterates across all `(block_root, slot)` pairs from `start_slot`
394
+ /// to the head of the chain (inclusive ).
395
395
///
396
396
/// ## Notes
397
397
///
398
- /// `slot` always decreases by `1`.
398
+ /// - `slot` always increases by `1`.
399
399
/// - Skipped slots contain the root of the closest prior
400
- /// non-skipped slot (identical to the way they are stored in `state.block_roots`) .
400
+ /// non-skipped slot (identical to the way they are stored in `state.block_roots`).
401
401
/// - Iterator returns `(Hash256, Slot)`.
402
- /// - As this iterator starts at the `head` of the chain (viz., the best block), the first slot
403
- /// returned may be earlier than the wall-clock slot.
404
- pub fn rev_iter_block_roots (
405
- & self ,
406
- ) -> Result < impl Iterator < Item = Result < ( Hash256 , Slot ) , Error > > , Error > {
407
- let head = self . head ( ) ?;
408
- let iter = BlockRootsIterator :: owned ( self . store . clone ( ) , head. beacon_state ) ;
409
- Ok (
410
- std:: iter:: once ( Ok ( ( head. beacon_block_root , head. beacon_block . slot ( ) ) ) )
411
- . chain ( iter)
412
- . map ( |result| result. map_err ( |e| e. into ( ) ) ) ,
413
- )
414
- }
415
-
416
402
pub fn forwards_iter_block_roots (
417
403
& self ,
418
404
start_slot : Slot ,
@@ -434,7 +420,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
434
420
///
435
421
/// ## Notes
436
422
///
437
- /// `slot` always decreases by `1`.
423
+ /// - `slot` always decreases by `1`.
438
424
/// - Skipped slots contain the root of the closest prior
439
425
/// non-skipped slot (identical to the way they are stored in `state.block_roots`) .
440
426
/// - Iterator returns `(Hash256, Slot)`.
@@ -526,29 +512,15 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
526
512
} )
527
513
}
528
514
529
- /// Iterates across all `(state_root, slot)` pairs from the head of the chain (inclusive) to
530
- /// the earliest reachable ancestor (may or may not be genesis).
515
+ /// Iterates backwards across all `(state_root, slot)` pairs starting from
516
+ /// an arbitrary `BeaconState` to the earliest reachable ancestor (may or may not be genesis).
531
517
///
532
518
/// ## Notes
533
519
///
534
- /// `slot` always decreases by `1`.
520
+ /// - `slot` always decreases by `1`.
535
521
/// - Iterator returns `(Hash256, Slot)`.
536
522
/// - As this iterator starts at the `head` of the chain (viz., the best block), the first slot
537
523
/// returned may be earlier than the wall-clock slot.
538
- pub fn rev_iter_state_roots (
539
- & self ,
540
- ) -> Result < impl Iterator < Item = Result < ( Hash256 , Slot ) , Error > > , Error > {
541
- let head = self . head ( ) ?;
542
- let head_slot = head. beacon_state . slot ;
543
- let head_state_root = head. beacon_state_root ( ) ;
544
- let iter = StateRootsIterator :: owned ( self . store . clone ( ) , head. beacon_state ) ;
545
- let iter = std:: iter:: once ( Ok ( ( head_state_root, head_slot) ) )
546
- . chain ( iter)
547
- . map ( |result| result. map_err ( Into :: into) ) ;
548
- Ok ( iter)
549
- }
550
-
551
- /// As for `rev_iter_state_roots` but starting from an arbitrary `BeaconState`.
552
524
pub fn rev_iter_state_roots_from < ' a > (
553
525
& self ,
554
526
state_root : Hash256 ,
@@ -559,6 +531,30 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
559
531
. map ( |result| result. map_err ( Into :: into) )
560
532
}
561
533
534
+ /// Iterates across all `(state_root, slot)` pairs from `start_slot`
535
+ /// to the head of the chain (inclusive).
536
+ ///
537
+ /// ## Notes
538
+ ///
539
+ /// - `slot` always increases by `1`.
540
+ /// - Iterator returns `(Hash256, Slot)`.
541
+ pub fn forwards_iter_state_roots (
542
+ & self ,
543
+ start_slot : Slot ,
544
+ ) -> Result < impl Iterator < Item = Result < ( Hash256 , Slot ) , Error > > , Error > {
545
+ let local_head = self . head ( ) ?;
546
+
547
+ let iter = HotColdDB :: forwards_state_roots_iterator (
548
+ self . store . clone ( ) ,
549
+ start_slot,
550
+ local_head. beacon_state_root ( ) ,
551
+ local_head. beacon_state ,
552
+ & self . spec ,
553
+ ) ?;
554
+
555
+ Ok ( iter. map ( |result| result. map_err ( Into :: into) ) )
556
+ }
557
+
562
558
/// Returns the block at the given slot, if any. Only returns blocks in the canonical chain.
563
559
///
564
560
/// Use the `skips` parameter to define the behaviour when `request_slot` is a skipped slot.
@@ -580,16 +576,48 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
580
576
}
581
577
}
582
578
583
- /// Returns the block at the given slot, if any. Only returns blocks in the canonical chain.
579
+ /// Returns the state root at the given slot, if any. Only returns state roots in the canonical chain.
584
580
///
585
581
/// ## Errors
586
582
///
587
583
/// May return a database error.
588
- pub fn state_root_at_slot ( & self , slot : Slot ) -> Result < Option < Hash256 > , Error > {
589
- process_results ( self . rev_iter_state_roots ( ) ?, |mut iter| {
590
- iter. find ( |( _, this_slot) | * this_slot == slot)
591
- . map ( |( root, _) | root)
592
- } )
584
+ pub fn state_root_at_slot ( & self , request_slot : Slot ) -> Result < Option < Hash256 > , Error > {
585
+ if request_slot > self . slot ( ) ? {
586
+ return Ok ( None ) ;
587
+ } else if request_slot == self . spec . genesis_slot {
588
+ return Ok ( Some ( self . genesis_state_root ) ) ;
589
+ }
590
+
591
+ // Try an optimized path of reading the root directly from the head state.
592
+ let fast_lookup: Option < Hash256 > = self . with_head ( |head| {
593
+ if head. beacon_block . slot ( ) <= request_slot {
594
+ // Return the head state root if all slots between the request and the head are skipped.
595
+ Ok ( Some ( head. beacon_state_root ( ) ) )
596
+ } else if let Ok ( root) = head. beacon_state . get_state_root ( request_slot) {
597
+ // Return the root if it's easily accessible from the head state.
598
+ Ok ( Some ( * root) )
599
+ } else {
600
+ // Fast lookup is not possible.
601
+ Ok :: < _ , Error > ( None )
602
+ }
603
+ } ) ?;
604
+
605
+ if let Some ( root) = fast_lookup {
606
+ return Ok ( Some ( root) ) ;
607
+ }
608
+
609
+ process_results ( self . forwards_iter_state_roots ( request_slot) ?, |mut iter| {
610
+ if let Some ( ( root, slot) ) = iter. next ( ) {
611
+ if slot == request_slot {
612
+ Ok ( Some ( root) )
613
+ } else {
614
+ // Sanity check.
615
+ Err ( Error :: InconsistentForwardsIter { request_slot, slot } )
616
+ }
617
+ } else {
618
+ Ok ( None )
619
+ }
620
+ } ) ?
593
621
}
594
622
595
623
/// Returns the block root at the given slot, if any. Only returns roots in the canonical chain.
@@ -896,7 +924,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
896
924
Ok ( state)
897
925
}
898
926
Ordering :: Less => {
899
- let state_root = process_results ( self . rev_iter_state_roots ( ) ?, |iter| {
927
+ let state_root = process_results ( self . forwards_iter_state_roots ( slot ) ?, |iter| {
900
928
iter. take_while ( |( _, current_slot) | * current_slot >= slot)
901
929
. find ( |( _, current_slot) | * current_slot == slot)
902
930
. map ( |( root, _slot) | root)
0 commit comments