Add Exit support to test_harness

This commit is contained in:
Paul Hauner 2019-03-04 12:21:24 +11:00
parent f4d8b41a09
commit ef006bfb2c
No known key found for this signature in database
GPG Key ID: D362883A9218FCC6
6 changed files with 111 additions and 1 deletions

View File

@ -18,6 +18,10 @@ test_cases:
amount: 32
- slot: 5
amount: 32
exits:
# At slot 10, submit an exit for validator #50.
- slot: 10
validator_index: 50
proposer_slashings:
# At slot 2, trigger a proposer slashing for validator #42.
- slot: 2
@ -39,4 +43,5 @@ test_cases:
num_validators: 1003
slashed_validators: [11, 12, 13, 14, 42]
exited_validators: []
exit_initiated_validators: [50]

View File

@ -280,6 +280,15 @@ impl BeaconChainHarness {
}
}
/// Submit an exit to the `BeaconChain` for inclusion in some block.
///
/// Note: the `ValidatorHarness` for this validator continues to exist. Once it is exited it
/// will stop receiving duties from the beacon chain and just do nothing when prompted to
/// produce/attest.
pub fn add_exit(&mut self, exit: Exit) {
self.beacon_chain.receive_exit_for_inclusion(exit);
}
/// Submit a proposer slashing to the `BeaconChain` for inclusion in some block.
pub fn add_proposer_slashing(&mut self, proposer_slashing: ProposerSlashing) {
self.beacon_chain

View File

@ -4,6 +4,7 @@
use crate::beacon_chain_harness::BeaconChainHarness;
use beacon_chain::CheckPoint;
use log::{info, warn};
use ssz::TreeHash;
use types::*;
use types::{
attester_slashing::AttesterSlashingBuilder, proposer_slashing::ProposerSlashingBuilder,
@ -121,6 +122,20 @@ impl TestCase {
}
}
// Feed exits to the BeaconChain.
if let Some(ref exits) = self.config.exits {
for (slot, validator_index) in exits {
if *slot == slot_height {
info!(
"Including exit at slot height {} for validator {}.",
slot_height, validator_index
);
let exit = build_exit(&harness, *validator_index);
harness.add_exit(exit);
}
}
}
// Build a block or skip a slot.
match self.config.skip_slots {
Some(ref skip_slots) if skip_slots.contains(&slot_height) => {
@ -185,6 +200,33 @@ impl TestCase {
}
}
fn build_exit(harness: &BeaconChainHarness, validator_index: u64) -> Exit {
let epoch = harness
.beacon_chain
.state
.read()
.current_epoch(&harness.spec);
let mut exit = Exit {
epoch,
validator_index,
signature: Signature::empty_signature(),
};
let message = exit.hash_tree_root();
exit.signature = harness
.validator_sign(
validator_index as usize,
&message[..],
epoch,
harness.spec.domain_exit,
)
.expect("Unable to sign Exit");
exit
}
/// Builds an `AttesterSlashing` for some `validator_indices`.
///
/// Signs the message using a `BeaconChainHarness`.

View File

@ -7,6 +7,7 @@ pub type ValidatorIndex = u64;
pub type ValidatorIndices = Vec<u64>;
pub type DepositTuple = (SlotHeight, Deposit, Keypair);
pub type ExitTuple = (SlotHeight, ValidatorIndex);
pub type ProposerSlashingTuple = (SlotHeight, ValidatorIndex);
pub type AttesterSlashingTuple = (SlotHeight, ValidatorIndices);
@ -27,6 +28,8 @@ pub struct Config {
pub proposer_slashings: Option<Vec<ProposerSlashingTuple>>,
/// Attester slashings to be including during execution.
pub attester_slashings: Option<Vec<AttesterSlashingTuple>>,
/// Exits to be including during execution.
pub exits: Option<Vec<ExitTuple>>,
}
impl Config {
@ -43,10 +46,26 @@ impl Config {
deposits: parse_deposits(&yaml),
proposer_slashings: parse_proposer_slashings(&yaml),
attester_slashings: parse_attester_slashings(&yaml),
exits: parse_exits(&yaml),
}
}
}
/// Parse the `attester_slashings` section of the YAML document.
fn parse_exits(yaml: &Yaml) -> Option<Vec<ExitTuple>> {
let mut tuples = vec![];
for exit in yaml["exits"].as_vec()? {
let slot = as_u64(exit, "slot").expect("Incomplete exit (slot)");
let validator_index =
as_u64(exit, "validator_index").expect("Incomplete exit (validator_index)");
tuples.push((SlotHeight::from(slot), validator_index));
}
Some(tuples)
}
/// Parse the `attester_slashings` section of the YAML document.
fn parse_attester_slashings(yaml: &Yaml) -> Option<Vec<AttesterSlashingTuple>> {
let mut slashings = vec![];

View File

@ -13,8 +13,10 @@ pub struct StateCheck {
pub num_validators: Option<usize>,
/// A list of validator indices which have been penalized. Must be in ascending order.
pub slashed_validators: Option<Vec<u64>>,
/// A list of validator indices which have been exited. Must be in ascending order.
/// A list of validator indices which have been fully exited. Must be in ascending order.
pub exited_validators: Option<Vec<u64>>,
/// A list of validator indices which have had an exit initiated. Must be in ascending order.
pub exit_initiated_validators: Option<Vec<u64>>,
}
impl StateCheck {
@ -27,6 +29,7 @@ impl StateCheck {
num_validators: as_usize(&yaml, "num_validators"),
slashed_validators: as_vec_u64(&yaml, "slashed_validators"),
exited_validators: as_vec_u64(&yaml, "exited_validators"),
exit_initiated_validators: as_vec_u64(&yaml, "exit_initiated_validators"),
}
}
@ -40,6 +43,7 @@ impl StateCheck {
info!("Running state check for slot height {}.", self.slot);
// Check the state slot.
assert_eq!(
self.slot,
state.slot - spec.genesis_epoch.start_slot(spec.epoch_length),
@ -55,6 +59,7 @@ impl StateCheck {
info!("OK: num_validators = {}.", num_validators);
}
// Check for slashed validators.
if let Some(ref slashed_validators) = self.slashed_validators {
let actually_slashed_validators: Vec<u64> = state
.validator_registry
@ -75,6 +80,7 @@ impl StateCheck {
info!("OK: slashed_validators = {:?}.", slashed_validators);
}
// Check for exited validators.
if let Some(ref exited_validators) = self.exited_validators {
let actually_exited_validators: Vec<u64> = state
.validator_registry
@ -94,5 +100,29 @@ impl StateCheck {
);
info!("OK: exited_validators = {:?}.", exited_validators);
}
// Check for validators that have initiated exit.
if let Some(ref exit_initiated_validators) = self.exit_initiated_validators {
let actual: Vec<u64> = state
.validator_registry
.iter()
.enumerate()
.filter_map(|(i, validator)| {
if validator.has_initiated_exit() {
Some(i as u64)
} else {
None
}
})
.collect();
assert_eq!(
actual, *exit_initiated_validators,
"Exit initiated validators != expected."
);
info!(
"OK: exit_initiated_validators = {:?}.",
exit_initiated_validators
);
}
}
}

View File

@ -68,6 +68,11 @@ impl Validator {
pub fn is_penalized_at(&self, epoch: Epoch) -> bool {
self.penalized_epoch <= epoch
}
/// Returns `true` if the validator is considered penalized at some epoch.
pub fn has_initiated_exit(&self) -> bool {
self.status_flags == Some(StatusFlags::InitiatedExit)
}
}
impl Default for Validator {