@@ -69,7 +69,7 @@ use state_processing::{
69
69
per_block_processing:: { errors:: AttestationValidationError , is_merge_transition_complete} ,
70
70
per_slot_processing,
71
71
state_advance:: { complete_state_advance, partial_state_advance} ,
72
- BlockSignatureStrategy , SigVerifiedOp ,
72
+ BlockSignatureStrategy , SigVerifiedOp , VerifyBlockRoot ,
73
73
} ;
74
74
use std:: borrow:: Cow ;
75
75
use std:: cmp:: Ordering ;
@@ -488,7 +488,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
488
488
pub fn forwards_iter_block_roots (
489
489
& self ,
490
490
start_slot : Slot ,
491
- ) -> Result < impl Iterator < Item = Result < ( Hash256 , Slot ) , Error > > , Error > {
491
+ ) -> Result < impl Iterator < Item = Result < ( Hash256 , Slot ) , Error > > + ' _ , Error > {
492
492
let oldest_block_slot = self . store . get_oldest_block_slot ( ) ;
493
493
if start_slot < oldest_block_slot {
494
494
return Err ( Error :: HistoricalBlockError (
@@ -501,8 +501,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
501
501
502
502
let local_head = self . head ( ) ?;
503
503
504
- let iter = HotColdDB :: forwards_block_roots_iterator (
505
- self . store . clone ( ) ,
504
+ let iter = self . store . forwards_block_roots_iterator (
506
505
start_slot,
507
506
local_head. beacon_state ,
508
507
local_head. beacon_block_root ,
@@ -512,6 +511,43 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
512
511
Ok ( iter. map ( |result| result. map_err ( Into :: into) ) )
513
512
}
514
513
514
+ /// Even more efficient variant of `forwards_iter_block_roots` that will avoid cloning the head
515
+ /// state if it isn't required for the requested range of blocks.
516
+ pub fn forwards_iter_block_roots_until (
517
+ & self ,
518
+ start_slot : Slot ,
519
+ end_slot : Slot ,
520
+ ) -> Result < impl Iterator < Item = Result < ( Hash256 , Slot ) , Error > > + ' _ , Error > {
521
+ let oldest_block_slot = self . store . get_oldest_block_slot ( ) ;
522
+ if start_slot < oldest_block_slot {
523
+ return Err ( Error :: HistoricalBlockError (
524
+ HistoricalBlockError :: BlockOutOfRange {
525
+ slot : start_slot,
526
+ oldest_block_slot,
527
+ } ,
528
+ ) ) ;
529
+ }
530
+
531
+ self . with_head ( move |head| {
532
+ let iter = self . store . forwards_block_roots_iterator_until (
533
+ start_slot,
534
+ end_slot,
535
+ || {
536
+ (
537
+ head. beacon_state . clone_with_only_committee_caches ( ) ,
538
+ head. beacon_block_root ,
539
+ )
540
+ } ,
541
+ & self . spec ,
542
+ ) ?;
543
+ Ok ( iter
544
+ . map ( |result| result. map_err ( Into :: into) )
545
+ . take_while ( move |result| {
546
+ result. as_ref ( ) . map_or ( true , |( _, slot) | * slot <= end_slot)
547
+ } ) )
548
+ } )
549
+ }
550
+
515
551
/// Traverse backwards from `block_root` to find the block roots of its ancestors.
516
552
///
517
553
/// ## Notes
@@ -524,14 +560,14 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
524
560
pub fn rev_iter_block_roots_from (
525
561
& self ,
526
562
block_root : Hash256 ,
527
- ) -> Result < impl Iterator < Item = Result < ( Hash256 , Slot ) , Error > > , Error > {
563
+ ) -> Result < impl Iterator < Item = Result < ( Hash256 , Slot ) , Error > > + ' _ , Error > {
528
564
let block = self
529
565
. get_block ( & block_root) ?
530
566
. ok_or ( Error :: MissingBeaconBlock ( block_root) ) ?;
531
567
let state = self
532
568
. get_state ( & block. state_root ( ) , Some ( block. slot ( ) ) ) ?
533
569
. ok_or_else ( || Error :: MissingBeaconState ( block. state_root ( ) ) ) ?;
534
- let iter = BlockRootsIterator :: owned ( self . store . clone ( ) , state) ;
570
+ let iter = BlockRootsIterator :: owned ( & self . store , state) ;
535
571
Ok ( std:: iter:: once ( Ok ( ( block_root, block. slot ( ) ) ) )
536
572
. chain ( iter)
537
573
. map ( |result| result. map_err ( |e| e. into ( ) ) ) )
@@ -618,12 +654,12 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
618
654
/// - As this iterator starts at the `head` of the chain (viz., the best block), the first slot
619
655
/// returned may be earlier than the wall-clock slot.
620
656
pub fn rev_iter_state_roots_from < ' a > (
621
- & self ,
657
+ & ' a self ,
622
658
state_root : Hash256 ,
623
659
state : & ' a BeaconState < T :: EthSpec > ,
624
660
) -> impl Iterator < Item = Result < ( Hash256 , Slot ) , Error > > + ' a {
625
661
std:: iter:: once ( Ok ( ( state_root, state. slot ( ) ) ) )
626
- . chain ( StateRootsIterator :: new ( self . store . clone ( ) , state) )
662
+ . chain ( StateRootsIterator :: new ( & self . store , state) )
627
663
. map ( |result| result. map_err ( Into :: into) )
628
664
}
629
665
@@ -637,11 +673,10 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
637
673
pub fn forwards_iter_state_roots (
638
674
& self ,
639
675
start_slot : Slot ,
640
- ) -> Result < impl Iterator < Item = Result < ( Hash256 , Slot ) , Error > > , Error > {
676
+ ) -> Result < impl Iterator < Item = Result < ( Hash256 , Slot ) , Error > > + ' _ , Error > {
641
677
let local_head = self . head ( ) ?;
642
678
643
- let iter = HotColdDB :: forwards_state_roots_iterator (
644
- self . store . clone ( ) ,
679
+ let iter = self . store . forwards_state_roots_iterator (
645
680
start_slot,
646
681
local_head. beacon_state_root ( ) ,
647
682
local_head. beacon_state ,
@@ -651,6 +686,36 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
651
686
Ok ( iter. map ( |result| result. map_err ( Into :: into) ) )
652
687
}
653
688
689
+ /// Super-efficient forwards state roots iterator that avoids cloning the head if the state
690
+ /// roots lie entirely within the freezer database.
691
+ ///
692
+ /// The iterator returned will include roots for `start_slot..=end_slot`, i.e. it
693
+ /// is endpoint inclusive.
694
+ pub fn forwards_iter_state_roots_until (
695
+ & self ,
696
+ start_slot : Slot ,
697
+ end_slot : Slot ,
698
+ ) -> Result < impl Iterator < Item = Result < ( Hash256 , Slot ) , Error > > + ' _ , Error > {
699
+ self . with_head ( move |head| {
700
+ let iter = self . store . forwards_state_roots_iterator_until (
701
+ start_slot,
702
+ end_slot,
703
+ || {
704
+ (
705
+ head. beacon_state . clone_with_only_committee_caches ( ) ,
706
+ head. beacon_state_root ( ) ,
707
+ )
708
+ } ,
709
+ & self . spec ,
710
+ ) ?;
711
+ Ok ( iter
712
+ . map ( |result| result. map_err ( Into :: into) )
713
+ . take_while ( move |result| {
714
+ result. as_ref ( ) . map_or ( true , |( _, slot) | * slot <= end_slot)
715
+ } ) )
716
+ } )
717
+ }
718
+
654
719
/// Returns the block at the given slot, if any. Only returns blocks in the canonical chain.
655
720
///
656
721
/// Use the `skips` parameter to define the behaviour when `request_slot` is a skipped slot.
@@ -708,18 +773,21 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
708
773
return Ok ( Some ( root) ) ;
709
774
}
710
775
711
- process_results ( self . forwards_iter_state_roots ( request_slot) ?, |mut iter| {
712
- if let Some ( ( root, slot) ) = iter. next ( ) {
713
- if slot == request_slot {
714
- Ok ( Some ( root) )
776
+ process_results (
777
+ self . forwards_iter_state_roots_until ( request_slot, request_slot) ?,
778
+ |mut iter| {
779
+ if let Some ( ( root, slot) ) = iter. next ( ) {
780
+ if slot == request_slot {
781
+ Ok ( Some ( root) )
782
+ } else {
783
+ // Sanity check.
784
+ Err ( Error :: InconsistentForwardsIter { request_slot, slot } )
785
+ }
715
786
} else {
716
- // Sanity check.
717
- Err ( Error :: InconsistentForwardsIter { request_slot, slot } )
787
+ Ok ( None )
718
788
}
719
- } else {
720
- Ok ( None )
721
- }
722
- } ) ?
789
+ } ,
790
+ ) ?
723
791
}
724
792
725
793
/// Returns the block root at the given slot, if any. Only returns roots in the canonical chain.
@@ -790,11 +858,10 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
790
858
return Ok ( root_opt) ;
791
859
}
792
860
793
- if let Some ( ( ( prev_root, _) , ( curr_root, curr_slot) ) ) =
794
- process_results ( self . forwards_iter_block_roots ( prev_slot) ?, |iter| {
795
- iter. tuple_windows ( ) . next ( )
796
- } ) ?
797
- {
861
+ if let Some ( ( ( prev_root, _) , ( curr_root, curr_slot) ) ) = process_results (
862
+ self . forwards_iter_block_roots_until ( prev_slot, request_slot) ?,
863
+ |iter| iter. tuple_windows ( ) . next ( ) ,
864
+ ) ? {
798
865
// Sanity check.
799
866
if curr_slot != request_slot {
800
867
return Err ( Error :: InconsistentForwardsIter {
@@ -842,18 +909,21 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
842
909
return Ok ( Some ( root) ) ;
843
910
}
844
911
845
- process_results ( self . forwards_iter_block_roots ( request_slot) ?, |mut iter| {
846
- if let Some ( ( root, slot) ) = iter. next ( ) {
847
- if slot == request_slot {
848
- Ok ( Some ( root) )
912
+ process_results (
913
+ self . forwards_iter_block_roots_until ( request_slot, request_slot) ?,
914
+ |mut iter| {
915
+ if let Some ( ( root, slot) ) = iter. next ( ) {
916
+ if slot == request_slot {
917
+ Ok ( Some ( root) )
918
+ } else {
919
+ // Sanity check.
920
+ Err ( Error :: InconsistentForwardsIter { request_slot, slot } )
921
+ }
849
922
} else {
850
- // Sanity check.
851
- Err ( Error :: InconsistentForwardsIter { request_slot, slot } )
923
+ Ok ( None )
852
924
}
853
- } else {
854
- Ok ( None )
855
- }
856
- } ) ?
925
+ } ,
926
+ ) ?
857
927
}
858
928
859
929
/// Returns the block at the given root, if any.
@@ -1112,12 +1182,13 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
1112
1182
Ok ( state)
1113
1183
}
1114
1184
Ordering :: Less => {
1115
- let state_root = process_results ( self . forwards_iter_state_roots ( slot) ?, |iter| {
1116
- iter. take_while ( |( _, current_slot) | * current_slot >= slot)
1117
- . find ( |( _, current_slot) | * current_slot == slot)
1118
- . map ( |( root, _slot) | root)
1119
- } ) ?
1120
- . ok_or ( Error :: NoStateForSlot ( slot) ) ?;
1185
+ let state_root =
1186
+ process_results ( self . forwards_iter_state_roots_until ( slot, slot) ?, |iter| {
1187
+ iter. take_while ( |( _, current_slot) | * current_slot >= slot)
1188
+ . find ( |( _, current_slot) | * current_slot == slot)
1189
+ . map ( |( root, _slot) | root)
1190
+ } ) ?
1191
+ . ok_or ( Error :: NoStateForSlot ( slot) ) ?;
1121
1192
1122
1193
Ok ( self
1123
1194
. get_state ( & state_root, Some ( slot) ) ?
@@ -1256,7 +1327,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
1256
1327
beacon_block_root : Hash256 ,
1257
1328
state : & BeaconState < T :: EthSpec > ,
1258
1329
) -> Result < Option < Hash256 > , Error > {
1259
- let iter = BlockRootsIterator :: new ( self . store . clone ( ) , state) ;
1330
+ let iter = BlockRootsIterator :: new ( & self . store , state) ;
1260
1331
let iter_with_head = std:: iter:: once ( Ok ( ( beacon_block_root, state. slot ( ) ) ) )
1261
1332
. chain ( iter)
1262
1333
. map ( |result| result. map_err ( |e| e. into ( ) ) ) ;
@@ -2983,6 +3054,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
2983
3054
& block,
2984
3055
None ,
2985
3056
BlockSignatureStrategy :: VerifyRandao ,
3057
+ VerifyBlockRoot :: True ,
2986
3058
& self . spec ,
2987
3059
) ?;
2988
3060
drop ( process_timer) ;
@@ -3324,7 +3396,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
3324
3396
. epoch
3325
3397
. start_slot ( T :: EthSpec :: slots_per_epoch ( ) ) ;
3326
3398
let new_finalized_state_root = process_results (
3327
- StateRootsIterator :: new ( self . store . clone ( ) , & head. beacon_state ) ,
3399
+ StateRootsIterator :: new ( & self . store , & head. beacon_state ) ,
3328
3400
|mut iter| {
3329
3401
iter. find_map ( |( state_root, slot) | {
3330
3402
if slot == new_finalized_slot {
0 commit comments