Skip to content

Commit

Permalink
Run altair specific checks with the simulator (#2556)
Browse files Browse the repository at this point in the history
## Issue Addressed

N/A

## Proposed Changes

Set a valid fork epoch in the simulator and run checks on 
1. If all nodes transitioned at the fork
2. If all altair block sync aggregates are full
  • Loading branch information
pawanjay176 committed Sep 3, 2021
1 parent 6f18f95 commit ac27422
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 4 deletions.
66 changes: 65 additions & 1 deletion testing/simulator/src/checks.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::local_network::LocalNetwork;
use node_test_rig::eth2::types::StateId;
use node_test_rig::eth2::types::{BlockId, StateId};
use std::time::Duration;
use types::{Epoch, EthSpec, Slot, Unsigned};

Expand Down Expand Up @@ -143,3 +143,67 @@ pub async fn verify_full_block_production_up_to<E: EthSpec>(
}
Ok(())
}

/// Verify that all nodes have the correct fork version after the `fork_epoch`.
pub async fn verify_fork_version<E: EthSpec>(
network: LocalNetwork<E>,
fork_epoch: Epoch,
slot_duration: Duration,
altair_fork_version: [u8; 4],
) -> Result<(), String> {
epoch_delay(fork_epoch, slot_duration, E::slots_per_epoch()).await;
for remote_node in network.remote_nodes()? {
let fork_version = remote_node
.get_beacon_states_fork(StateId::Head)
.await
.map(|resp| resp.unwrap().data.current_version)
.map_err(|e| format!("Failed to get fork from beacon node: {:?}", e))?;
if fork_version != altair_fork_version {
return Err(format!(
"Fork version after FORK_EPOCH is incorrect, got: {:?}, expected: {:?}",
fork_version, altair_fork_version,
));
}
}
Ok(())
}

/// Verify that all sync aggregates from `sync_committee_start_slot` until `upto_slot`
/// have full aggregates.
pub async fn verify_full_sync_aggregates_up_to<E: EthSpec>(
network: LocalNetwork<E>,
sync_committee_start_slot: Slot,
upto_slot: Slot,
slot_duration: Duration,
) -> Result<(), String> {
slot_delay(upto_slot, slot_duration).await;
let remote_nodes = network.remote_nodes()?;
let remote_node = remote_nodes.first().unwrap();

for slot in sync_committee_start_slot.as_u64()..=upto_slot.as_u64() {
let sync_aggregate_count = remote_node
.get_beacon_blocks::<E>(BlockId::Slot(Slot::new(slot)))
.await
.map(|resp| {
resp.unwrap()
.data
.message()
.body()
.sync_aggregate()
.map(|agg| agg.num_set_bits())
})
.map_err(|e| format!("Error while getting beacon block: {:?}", e))?
.ok_or(format!("Altair block {} should have sync aggregate", slot))?;

if sync_aggregate_count != E::sync_committee_size() {
return Err(format!(
"Sync aggregate at slot {} was not full, got: {}, expected: {}",
slot,
sync_aggregate_count,
E::sync_committee_size()
));
}
}

Ok(())
}
29 changes: 26 additions & 3 deletions testing/simulator/src/eth1_sim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ use std::cmp::max;
use std::net::{IpAddr, Ipv4Addr};
use std::time::Duration;
use tokio::time::sleep;
use types::{Epoch, EthSpec, MainnetEthSpec};
use types::{Epoch, EthSpec, MinimalEthSpec};

const FORK_EPOCH: u64 = 2;
const END_EPOCH: u64 = 16;

pub fn run_eth1_sim(matches: &ArgMatches) -> Result<(), String> {
let node_count = value_t!(matches, "nodes", usize).expect("missing nodes default");
Expand Down Expand Up @@ -59,6 +62,7 @@ pub fn run_eth1_sim(matches: &ArgMatches) -> Result<(), String> {
let spec = &mut env.eth2_config.spec;

let total_validator_count = validators_per_node * node_count;
let altair_fork_version = spec.altair_fork_version;

spec.seconds_per_slot /= speed_up_factor;
spec.seconds_per_slot = max(1, spec.seconds_per_slot);
Expand All @@ -67,6 +71,7 @@ pub fn run_eth1_sim(matches: &ArgMatches) -> Result<(), String> {
spec.min_genesis_time = 0;
spec.min_genesis_active_validator_count = total_validator_count as u64;
spec.seconds_per_eth1_block = 1;
spec.altair_fork_epoch = Some(Epoch::new(FORK_EPOCH));

let slot_duration = Duration::from_secs(spec.seconds_per_slot);
let initial_validator_count = spec.min_genesis_active_validator_count as usize;
Expand Down Expand Up @@ -174,13 +179,13 @@ pub fn run_eth1_sim(matches: &ArgMatches) -> Result<(), String> {
* tests start at the right time. Whilst this is works well for now, it's subject to
* breakage by changes to the VC.
*/
let (finalization, block_prod, validator_count, onboarding) = futures::join!(
let (finalization, block_prod, validator_count, onboarding, fork, sync_aggregate) = futures::join!(
// Check that the chain finalizes at the first given opportunity.
checks::verify_first_finalization(network.clone(), slot_duration),
// Check that a block is produced at every slot.
checks::verify_full_block_production_up_to(
network.clone(),
Epoch::new(4).start_slot(MainnetEthSpec::slots_per_epoch()),
Epoch::new(END_EPOCH).start_slot(MinimalEthSpec::slots_per_epoch()),
slot_duration,
),
// Check that the chain starts with the expected validator count.
Expand All @@ -195,13 +200,31 @@ pub fn run_eth1_sim(matches: &ArgMatches) -> Result<(), String> {
network.clone(),
slot_duration,
total_validator_count,
),
// Check that all nodes have transitioned to the new fork.
checks::verify_fork_version(
network.clone(),
Epoch::new(FORK_EPOCH),
slot_duration,
altair_fork_version
),
// Check that all sync aggregates are full.
checks::verify_full_sync_aggregates_up_to(
network.clone(),
// Start checking for sync_aggregates at `FORK_EPOCH + 1` to account for
// inefficiencies in finding subnet peers at the `fork_slot`.
Epoch::new(FORK_EPOCH + 1).start_slot(MinimalEthSpec::slots_per_epoch()),
Epoch::new(END_EPOCH).start_slot(MinimalEthSpec::slots_per_epoch()),
slot_duration,
)
);

block_prod?;
finalization?;
validator_count?;
onboarding?;
fork?;
sync_aggregate?;

// The `final_future` either completes immediately or never completes, depending on the value
// of `continue_after_checks`.
Expand Down

0 comments on commit ac27422

Please sign in to comment.