@@ -36,6 +36,36 @@ fn get_harness(spec: ChainSpec) -> BeaconChainHarness<EphemeralHarnessType<E>> {
3636 . keypairs ( KEYPAIRS . to_vec ( ) )
3737 . fresh_ephemeral_store ( )
3838 . chain_config ( chain_config)
39+ . mock_execution_layer ( )
40+ . build ( ) ;
41+
42+ harness. advance_slot ( ) ;
43+
44+ harness
45+ }
46+
47+ fn get_electra_harness ( spec : ChainSpec ) -> BeaconChainHarness < EphemeralHarnessType < E > > {
48+ let chain_config = ChainConfig {
49+ reconstruct_historic_states : true ,
50+ ..Default :: default ( )
51+ } ;
52+
53+ let spec = Arc :: new ( spec) ;
54+
55+ let harness = BeaconChainHarness :: builder ( E :: default ( ) )
56+ . spec ( spec. clone ( ) )
57+ . keypairs ( KEYPAIRS . to_vec ( ) )
58+ . with_genesis_state_builder ( |builder| {
59+ builder. set_initial_balance_fn ( Box :: new ( move |i| {
60+ spec. max_effective_balance_electra
61+ / ( i as u64 + 1 )
62+ / spec. effective_balance_increment
63+ * spec. effective_balance_increment
64+ } ) )
65+ } )
66+ . fresh_ephemeral_store ( )
67+ . chain_config ( chain_config)
68+ . mock_execution_layer ( )
3969 . build ( ) ;
4070
4171 harness. advance_slot ( ) ;
@@ -560,6 +590,83 @@ async fn test_rewards_altair_inactivity_leak_justification_epoch() {
560590 assert_eq ! ( expected_balances, balances) ;
561591}
562592
593+ #[ tokio:: test]
594+ async fn test_rewards_electra ( ) {
595+ let spec = ForkName :: Electra . make_genesis_spec ( E :: default_spec ( ) ) ;
596+ let harness = get_electra_harness ( spec. clone ( ) ) ;
597+ let target_epoch = 0 ;
598+
599+ // advance until epoch N + 1 and get initial balances
600+ harness
601+ . extend_slots ( ( E :: slots_per_epoch ( ) * ( target_epoch + 1 ) ) as usize )
602+ . await ;
603+ let mut expected_balances = harness. get_current_state ( ) . balances ( ) . to_vec ( ) ;
604+
605+ // advance until epoch N + 2 and build proposal rewards map
606+ let mut proposal_rewards_map = HashMap :: new ( ) ;
607+ let mut sync_committee_rewards_map = HashMap :: new ( ) ;
608+ for _ in 0 ..E :: slots_per_epoch ( ) {
609+ let state = harness. get_current_state ( ) ;
610+ let slot = state. slot ( ) + Slot :: new ( 1 ) ;
611+
612+ // calculate beacon block rewards / penalties
613+ let ( ( signed_block, _maybe_blob_sidecars) , mut state) =
614+ harness. make_block_return_pre_state ( state, slot) . await ;
615+ let beacon_block_reward = harness
616+ . chain
617+ . compute_beacon_block_reward ( signed_block. message ( ) , & mut state)
618+ . unwrap ( ) ;
619+
620+ let total_proposer_reward = proposal_rewards_map
621+ . entry ( beacon_block_reward. proposer_index )
622+ . or_insert ( 0 ) ;
623+ * total_proposer_reward += beacon_block_reward. total as i64 ;
624+
625+ // calculate sync committee rewards / penalties
626+ let reward_payload = harness
627+ . chain
628+ . compute_sync_committee_rewards ( signed_block. message ( ) , & mut state)
629+ . unwrap ( ) ;
630+
631+ for reward in reward_payload {
632+ let total_sync_reward = sync_committee_rewards_map
633+ . entry ( reward. validator_index )
634+ . or_insert ( 0 ) ;
635+ * total_sync_reward += reward. reward ;
636+ }
637+
638+ harness. extend_slots ( 1 ) . await ;
639+ }
640+
641+ // compute reward deltas for all validators in epoch N
642+ let StandardAttestationRewards {
643+ ideal_rewards,
644+ total_rewards,
645+ } = harness
646+ . chain
647+ . compute_attestation_rewards ( Epoch :: new ( target_epoch) , vec ! [ ] )
648+ . unwrap ( ) ;
649+
650+ // assert ideal rewards are greater than 0
651+ assert_eq ! (
652+ ideal_rewards. len( ) as u64 ,
653+ spec. max_effective_balance_electra / spec. effective_balance_increment
654+ ) ;
655+ assert ! ( ideal_rewards
656+ . iter( )
657+ . all( |reward| reward. head > 0 && reward. target > 0 && reward. source > 0 ) ) ;
658+
659+ // apply attestation, proposal, and sync committee rewards and penalties to initial balances
660+ apply_attestation_rewards ( & mut expected_balances, total_rewards) ;
661+ apply_other_rewards ( & mut expected_balances, & proposal_rewards_map) ;
662+ apply_other_rewards ( & mut expected_balances, & sync_committee_rewards_map) ;
663+
664+ // verify expected balances against actual balances
665+ let balances: Vec < u64 > = harness. get_current_state ( ) . balances ( ) . to_vec ( ) ;
666+
667+ assert_eq ! ( expected_balances, balances) ;
668+ }
669+
563670#[ tokio:: test]
564671async fn test_rewards_base_subset_only ( ) {
565672 let spec = ForkName :: Base . make_genesis_spec ( E :: default_spec ( ) ) ;
0 commit comments