Skip to content

Commit 252dbbd

Browse files
committed
Add regression test and generalise interop builder
1 parent 2d8c308 commit 252dbbd

File tree

5 files changed

+323
-110
lines changed

5 files changed

+323
-110
lines changed

beacon_node/beacon_chain/src/test_utils.rs

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use execution_layer::{
2828
ExecutionLayer,
2929
};
3030
use futures::channel::mpsc::Receiver;
31-
pub use genesis::{interop_genesis_state_with_eth1, DEFAULT_ETH1_BLOCK_HASH};
31+
pub use genesis::{InteropGenesisBuilder, DEFAULT_ETH1_BLOCK_HASH};
3232
use int_to_bytes::int_to_bytes32;
3333
use kzg::trusted_setup::get_trusted_setup;
3434
use kzg::{Kzg, TrustedSetup};
@@ -223,6 +223,7 @@ pub struct Builder<T: BeaconChainTypes> {
223223
mock_execution_layer: Option<MockExecutionLayer<T::EthSpec>>,
224224
testing_slot_clock: Option<TestingSlotClock>,
225225
validator_monitor_config: Option<ValidatorMonitorConfig>,
226+
genesis_state_builder: Option<InteropGenesisBuilder<T::EthSpec>>,
226227
runtime: TestRuntime,
227228
log: Logger,
228229
}
@@ -243,16 +244,19 @@ impl<E: EthSpec> Builder<EphemeralHarnessType<E>> {
243244
)
244245
.unwrap(),
245246
);
247+
let genesis_state_builder = self.genesis_state_builder.take().unwrap_or_default();
248+
246249
let mutator = move |builder: BeaconChainBuilder<_>| {
247250
let header = generate_genesis_header::<E>(builder.get_spec(), false);
248-
let genesis_state = interop_genesis_state_with_eth1::<E>(
249-
&validator_keypairs,
250-
HARNESS_GENESIS_TIME,
251-
Hash256::from_slice(DEFAULT_ETH1_BLOCK_HASH),
252-
header,
253-
builder.get_spec(),
254-
)
255-
.expect("should generate interop state");
251+
let genesis_state = genesis_state_builder
252+
.set_opt_execution_payload_header(header)
253+
.build_genesis_state(
254+
&validator_keypairs,
255+
HARNESS_GENESIS_TIME,
256+
Hash256::from_slice(DEFAULT_ETH1_BLOCK_HASH),
257+
builder.get_spec(),
258+
)
259+
.expect("should generate interop state");
256260
builder
257261
.genesis_state(genesis_state)
258262
.expect("should build state using recent genesis")
@@ -305,16 +309,19 @@ impl<E: EthSpec> Builder<DiskHarnessType<E>> {
305309
.clone()
306310
.expect("cannot build without validator keypairs");
307311

312+
let genesis_state_builder = self.genesis_state_builder.take().unwrap_or_default();
313+
308314
let mutator = move |builder: BeaconChainBuilder<_>| {
309315
let header = generate_genesis_header::<E>(builder.get_spec(), false);
310-
let genesis_state = interop_genesis_state_with_eth1::<E>(
311-
&validator_keypairs,
312-
HARNESS_GENESIS_TIME,
313-
Hash256::from_slice(DEFAULT_ETH1_BLOCK_HASH),
314-
header,
315-
builder.get_spec(),
316-
)
317-
.expect("should generate interop state");
316+
let genesis_state = genesis_state_builder
317+
.set_opt_execution_payload_header(header)
318+
.build_genesis_state(
319+
&validator_keypairs,
320+
HARNESS_GENESIS_TIME,
321+
Hash256::from_slice(DEFAULT_ETH1_BLOCK_HASH),
322+
builder.get_spec(),
323+
)
324+
.expect("should generate interop state");
318325
builder
319326
.genesis_state(genesis_state)
320327
.expect("should build state using recent genesis")
@@ -359,6 +366,7 @@ where
359366
mock_execution_layer: None,
360367
testing_slot_clock: None,
361368
validator_monitor_config: None,
369+
genesis_state_builder: None,
362370
runtime,
363371
log,
364372
}
@@ -538,6 +546,15 @@ where
538546
self
539547
}
540548

549+
pub fn with_genesis_state_builder(
550+
mut self,
551+
f: impl FnOnce(InteropGenesisBuilder<E>) -> InteropGenesisBuilder<E>,
552+
) -> Self {
553+
let builder = self.genesis_state_builder.take().unwrap_or_default();
554+
self.genesis_state_builder = Some(f(builder));
555+
self
556+
}
557+
541558
pub fn build(self) -> BeaconChainHarness<BaseHarnessType<E, Hot, Cold>> {
542559
let (shutdown_tx, shutdown_receiver) = futures::channel::mpsc::channel(1);
543560

beacon_node/beacon_chain/tests/rewards.rs

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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]
564671
async fn test_rewards_base_subset_only() {
565672
let spec = ForkName::Base.make_genesis_spec(E::default_spec());

0 commit comments

Comments
 (0)