@@ -36,6 +36,38 @@ fn get_harness(spec: ChainSpec) -> BeaconChainHarness<EphemeralHarnessType<E>> {
36
36
. keypairs ( KEYPAIRS . to_vec ( ) )
37
37
. fresh_ephemeral_store ( )
38
38
. 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
+ // Use a variety of balances between min activation balance and max effective balance.
61
+ let balance = spec. max_effective_balance_electra
62
+ / ( i as u64 + 1 )
63
+ / spec. effective_balance_increment
64
+ * spec. effective_balance_increment ;
65
+ balance. max ( spec. min_activation_balance )
66
+ } ) )
67
+ } )
68
+ . fresh_ephemeral_store ( )
69
+ . chain_config ( chain_config)
70
+ . mock_execution_layer ( )
39
71
. build ( ) ;
40
72
41
73
harness. advance_slot ( ) ;
@@ -560,6 +592,83 @@ async fn test_rewards_altair_inactivity_leak_justification_epoch() {
560
592
assert_eq ! ( expected_balances, balances) ;
561
593
}
562
594
595
+ #[ tokio:: test]
596
+ async fn test_rewards_electra ( ) {
597
+ let spec = ForkName :: Electra . make_genesis_spec ( E :: default_spec ( ) ) ;
598
+ let harness = get_electra_harness ( spec. clone ( ) ) ;
599
+ let target_epoch = 0 ;
600
+
601
+ // advance until epoch N + 1 and get initial balances
602
+ harness
603
+ . extend_slots ( ( E :: slots_per_epoch ( ) * ( target_epoch + 1 ) ) as usize )
604
+ . await ;
605
+ let mut expected_balances = harness. get_current_state ( ) . balances ( ) . to_vec ( ) ;
606
+
607
+ // advance until epoch N + 2 and build proposal rewards map
608
+ let mut proposal_rewards_map = HashMap :: new ( ) ;
609
+ let mut sync_committee_rewards_map = HashMap :: new ( ) ;
610
+ for _ in 0 ..E :: slots_per_epoch ( ) {
611
+ let state = harness. get_current_state ( ) ;
612
+ let slot = state. slot ( ) + Slot :: new ( 1 ) ;
613
+
614
+ // calculate beacon block rewards / penalties
615
+ let ( ( signed_block, _maybe_blob_sidecars) , mut state) =
616
+ harness. make_block_return_pre_state ( state, slot) . await ;
617
+ let beacon_block_reward = harness
618
+ . chain
619
+ . compute_beacon_block_reward ( signed_block. message ( ) , & mut state)
620
+ . unwrap ( ) ;
621
+
622
+ let total_proposer_reward = proposal_rewards_map
623
+ . entry ( beacon_block_reward. proposer_index )
624
+ . or_insert ( 0 ) ;
625
+ * total_proposer_reward += beacon_block_reward. total as i64 ;
626
+
627
+ // calculate sync committee rewards / penalties
628
+ let reward_payload = harness
629
+ . chain
630
+ . compute_sync_committee_rewards ( signed_block. message ( ) , & mut state)
631
+ . unwrap ( ) ;
632
+
633
+ for reward in reward_payload {
634
+ let total_sync_reward = sync_committee_rewards_map
635
+ . entry ( reward. validator_index )
636
+ . or_insert ( 0 ) ;
637
+ * total_sync_reward += reward. reward ;
638
+ }
639
+
640
+ harness. extend_slots ( 1 ) . await ;
641
+ }
642
+
643
+ // compute reward deltas for all validators in epoch N
644
+ let StandardAttestationRewards {
645
+ ideal_rewards,
646
+ total_rewards,
647
+ } = harness
648
+ . chain
649
+ . compute_attestation_rewards ( Epoch :: new ( target_epoch) , vec ! [ ] )
650
+ . unwrap ( ) ;
651
+
652
+ // assert ideal rewards are greater than 0
653
+ assert_eq ! (
654
+ ideal_rewards. len( ) as u64 ,
655
+ spec. max_effective_balance_electra / spec. effective_balance_increment
656
+ ) ;
657
+ assert ! ( ideal_rewards
658
+ . iter( )
659
+ . all( |reward| reward. head > 0 && reward. target > 0 && reward. source > 0 ) ) ;
660
+
661
+ // apply attestation, proposal, and sync committee rewards and penalties to initial balances
662
+ apply_attestation_rewards ( & mut expected_balances, total_rewards) ;
663
+ apply_other_rewards ( & mut expected_balances, & proposal_rewards_map) ;
664
+ apply_other_rewards ( & mut expected_balances, & sync_committee_rewards_map) ;
665
+
666
+ // verify expected balances against actual balances
667
+ let balances: Vec < u64 > = harness. get_current_state ( ) . balances ( ) . to_vec ( ) ;
668
+
669
+ assert_eq ! ( expected_balances, balances) ;
670
+ }
671
+
563
672
#[ tokio:: test]
564
673
async fn test_rewards_base_subset_only ( ) {
565
674
let spec = ForkName :: Base . make_genesis_spec ( E :: default_spec ( ) ) ;
0 commit comments