mirror of
https://gitlab.com/pulsechaincom/lighthouse-pulse.git
synced 2024-12-28 14:57:17 +00:00
Add Exit support to test_harness
This commit is contained in:
parent
f4d8b41a09
commit
ef006bfb2c
@ -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]
|
||||
|
||||
|
@ -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
|
||||
|
@ -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`.
|
||||
|
@ -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![];
|
||||
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user