@@ -1191,6 +1191,96 @@ fn check_shuffling_compatible(
11911191 }
11921192}
11931193
1194+ /// These tests check the consistency of:
1195+ ///
1196+ /// - ProtoBlock::proposer_shuffling_root_for_child_block, and
1197+ /// - BeaconState::proposer_shuffling_decision_root{_at_epoch}
1198+ async fn proposer_shuffling_root_consistency_test ( parent_slot : u64 , child_slot : u64 ) {
1199+ let child_slot = Slot :: new ( child_slot) ;
1200+ let db_path = tempdir ( ) . unwrap ( ) ;
1201+ let store = get_store ( & db_path) ;
1202+ let validators_keypairs =
1203+ types:: test_utils:: generate_deterministic_keypairs ( LOW_VALIDATOR_COUNT ) ;
1204+ let harness = TestHarness :: builder ( MinimalEthSpec )
1205+ . default_spec ( )
1206+ . keypairs ( validators_keypairs)
1207+ . fresh_disk_store ( store)
1208+ . mock_execution_layer ( )
1209+ . build ( ) ;
1210+ let spec = & harness. chain . spec ;
1211+
1212+ // Build chain out to parent block.
1213+ let initial_slots: Vec < Slot > = ( 1 ..=parent_slot) . map ( Into :: into) . collect ( ) ;
1214+ let ( state, state_root) = harness. get_current_state_and_root ( ) ;
1215+ let all_validators = harness. get_all_validators ( ) ;
1216+ let ( _, _, parent_root, _) = harness
1217+ . add_attested_blocks_at_slots ( state, state_root, & initial_slots, & all_validators)
1218+ . await ;
1219+
1220+ // Add the child block.
1221+ let ( state, state_root) = harness. get_current_state_and_root ( ) ;
1222+ let all_validators = harness. get_all_validators ( ) ;
1223+ let ( _, _, child_root, child_block_state) = harness
1224+ . add_attested_blocks_at_slots ( state, state_root, & [ child_slot] , & all_validators)
1225+ . await ;
1226+
1227+ let child_block_epoch = child_slot. epoch ( E :: slots_per_epoch ( ) ) ;
1228+
1229+ // Load parent block from fork choice.
1230+ let fc_parent = harness
1231+ . chain
1232+ . canonical_head
1233+ . fork_choice_read_lock ( )
1234+ . get_block ( & parent_root. into ( ) )
1235+ . unwrap ( ) ;
1236+
1237+ // The proposer shuffling decision root computed using fork choice should equal the root
1238+ // computed from the child state.
1239+ let decision_root = fc_parent. proposer_shuffling_root_for_child_block ( child_block_epoch, spec) ;
1240+
1241+ assert_eq ! (
1242+ decision_root,
1243+ child_block_state
1244+ . proposer_shuffling_decision_root( child_root. into( ) , spec)
1245+ . unwrap( )
1246+ ) ;
1247+ assert_eq ! (
1248+ decision_root,
1249+ child_block_state
1250+ . proposer_shuffling_decision_root_at_epoch( child_block_epoch, child_root. into( ) , spec)
1251+ . unwrap( )
1252+ ) ;
1253+
1254+ // The passed block root argument should be irrelevant for all blocks except the genesis block.
1255+ assert_eq ! (
1256+ decision_root,
1257+ child_block_state
1258+ . proposer_shuffling_decision_root( Hash256 :: ZERO , spec)
1259+ . unwrap( )
1260+ ) ;
1261+ assert_eq ! (
1262+ decision_root,
1263+ child_block_state
1264+ . proposer_shuffling_decision_root_at_epoch( child_block_epoch, Hash256 :: ZERO , spec)
1265+ . unwrap( )
1266+ ) ;
1267+ }
1268+
1269+ #[ tokio:: test]
1270+ async fn proposer_shuffling_root_consistency_same_epoch ( ) {
1271+ proposer_shuffling_root_consistency_test ( 32 , 39 ) . await ;
1272+ }
1273+
1274+ #[ tokio:: test]
1275+ async fn proposer_shuffling_root_consistency_next_epoch ( ) {
1276+ proposer_shuffling_root_consistency_test ( 32 , 47 ) . await ;
1277+ }
1278+
1279+ #[ tokio:: test]
1280+ async fn proposer_shuffling_root_consistency_two_epochs ( ) {
1281+ proposer_shuffling_root_consistency_test ( 32 , 55 ) . await ;
1282+ }
1283+
11941284// Ensure blocks from abandoned forks are pruned from the Hot DB
11951285#[ tokio:: test]
11961286async fn prunes_abandoned_fork_between_two_finalized_checkpoints ( ) {
0 commit comments