ba55e140ae
## Issue Addressed Windows incompatibility. ## Proposed Changes On windows, lighthouse needs to default to STDIN as tty doesn't exist. Also Windows uses ACLs for file permissions. So to mirror chmod 600, we will remove every entry in a file's ACL and add only a single SID that is an alias for the file owner. Beyond that, there were several changes made to different unit tests because windows has slightly different error messages as well as frustrating nuances around killing a process :/ ## Additional Info Tested on my Windows VM and it appears to work, also compiled & tested on Linux with these changes. Permissions look correct on both platforms now. Just waiting for my validator to activate on Prater so I can test running full validator client on windows. Co-authored-by: ethDreamer <37123614+ethDreamer@users.noreply.github.com> Co-authored-by: Michael Sproul <micsproul@gmail.com>
234 lines
6.1 KiB
Rust
234 lines
6.1 KiB
Rust
use rand::prelude::*;
|
|
use rand::{rngs::StdRng, thread_rng, Rng, SeedableRng};
|
|
use slasher::{
|
|
test_utils::{
|
|
block, indexed_att, logger, slashed_validators_from_attestations,
|
|
slashed_validators_from_slashings, E,
|
|
},
|
|
Config, Slasher,
|
|
};
|
|
use std::cmp::max;
|
|
use tempfile::tempdir;
|
|
use types::{Epoch, EthSpec};
|
|
|
|
#[derive(Debug)]
|
|
struct TestConfig {
|
|
num_validators: usize,
|
|
max_attestations: usize,
|
|
check_slashings: bool,
|
|
add_blocks: bool,
|
|
}
|
|
|
|
impl Default for TestConfig {
|
|
fn default() -> Self {
|
|
Self {
|
|
num_validators: 4,
|
|
max_attestations: 50,
|
|
check_slashings: false,
|
|
add_blocks: false,
|
|
}
|
|
}
|
|
}
|
|
|
|
fn random_test(seed: u64, test_config: TestConfig) {
|
|
let check_slashings = test_config.check_slashings;
|
|
let num_validators = test_config.num_validators;
|
|
let max_attestations = test_config.max_attestations;
|
|
|
|
println!("Running with seed {}", seed);
|
|
let mut rng = StdRng::seed_from_u64(seed);
|
|
|
|
let tempdir = tempdir().unwrap();
|
|
|
|
let mut config = Config::new(tempdir.path().into()).for_testing();
|
|
config.validator_chunk_size = 1 << rng.gen_range(1, 4);
|
|
|
|
let chunk_size_exponent = rng.gen_range(1, 4);
|
|
config.chunk_size = 1 << chunk_size_exponent;
|
|
config.history_length = 1 << rng.gen_range(chunk_size_exponent, chunk_size_exponent + 3);
|
|
|
|
let slasher = Slasher::<E>::open(config.clone(), logger()).unwrap();
|
|
|
|
let validators = (0..num_validators as u64).collect::<Vec<u64>>();
|
|
|
|
let num_attestations = rng.gen_range(2, max_attestations + 1);
|
|
|
|
let mut current_epoch = Epoch::new(0);
|
|
let mut attestations = vec![];
|
|
|
|
for _ in 0..num_attestations {
|
|
let num_attesters = rng.gen_range(1, num_validators);
|
|
let mut attesting_indices = validators
|
|
.choose_multiple(&mut rng, num_attesters)
|
|
.copied()
|
|
.collect::<Vec<u64>>();
|
|
attesting_indices.sort_unstable();
|
|
|
|
// If checking slashings, generate valid attestations in range.
|
|
let (source, target) = if check_slashings {
|
|
let source = rng.gen_range(
|
|
current_epoch
|
|
.as_u64()
|
|
.saturating_sub(config.history_length as u64 - 1),
|
|
current_epoch.as_u64() + 1,
|
|
);
|
|
let target = rng.gen_range(source, current_epoch.as_u64() + 1);
|
|
(source, target)
|
|
} else {
|
|
let source = rng.gen_range(0, max(3 * current_epoch.as_u64(), 1));
|
|
let target = rng.gen_range(source, max(3 * current_epoch.as_u64(), source + 1));
|
|
(source, target)
|
|
};
|
|
let target_root = rng.gen_range(0, 3);
|
|
let attestation = indexed_att(&attesting_indices, source, target, target_root);
|
|
|
|
if check_slashings {
|
|
attestations.push(attestation.clone());
|
|
}
|
|
|
|
// Supply to slasher
|
|
slasher.accept_attestation(attestation);
|
|
|
|
// Maybe add a random block too
|
|
if test_config.add_blocks && rng.gen_bool(0.1) {
|
|
let slot = rng.gen_range(0, 1 + 3 * current_epoch.as_u64() * E::slots_per_epoch() / 2);
|
|
let proposer = rng.gen_range(0, num_validators as u64);
|
|
let block_root = rng.gen_range(0, 2);
|
|
slasher.accept_block_header(block(slot, proposer, block_root));
|
|
}
|
|
|
|
// Maybe process
|
|
if rng.gen_bool(0.1) {
|
|
slasher.process_queued(current_epoch).unwrap();
|
|
|
|
// Maybe prune
|
|
if rng.gen_bool(0.1) {
|
|
slasher.prune_database(current_epoch).unwrap();
|
|
}
|
|
}
|
|
|
|
// Maybe advance to the next epoch
|
|
if rng.gen_bool(0.5) {
|
|
if check_slashings {
|
|
slasher.process_queued(current_epoch).unwrap();
|
|
}
|
|
current_epoch += 1;
|
|
}
|
|
}
|
|
|
|
if !check_slashings {
|
|
return;
|
|
}
|
|
|
|
slasher.process_queued(current_epoch).unwrap();
|
|
|
|
let slashings = slasher.get_attester_slashings();
|
|
|
|
let slashed_validators = slashed_validators_from_slashings(&slashings);
|
|
let expected_slashed_validators = slashed_validators_from_attestations(&attestations);
|
|
assert_eq!(slashed_validators, expected_slashed_validators);
|
|
}
|
|
|
|
// Fuzz-like test that runs forever on different seeds looking for crashes.
|
|
#[test]
|
|
#[ignore]
|
|
fn no_crash() {
|
|
let mut rng = thread_rng();
|
|
loop {
|
|
random_test(rng.gen(), TestConfig::default());
|
|
}
|
|
}
|
|
|
|
// Fuzz-like test that runs forever on different seeds looking for crashes.
|
|
#[test]
|
|
#[ignore]
|
|
fn no_crash_with_blocks() {
|
|
let mut rng = thread_rng();
|
|
loop {
|
|
random_test(
|
|
rng.gen(),
|
|
TestConfig {
|
|
add_blocks: true,
|
|
..TestConfig::default()
|
|
},
|
|
);
|
|
}
|
|
}
|
|
|
|
// Fuzz-like test that runs forever on different seeds looking for missed slashings.
|
|
#[test]
|
|
#[ignore]
|
|
fn check_slashings() {
|
|
let mut rng = thread_rng();
|
|
loop {
|
|
random_test(
|
|
rng.gen(),
|
|
TestConfig {
|
|
check_slashings: true,
|
|
..TestConfig::default()
|
|
},
|
|
);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn check_slashings_example1() {
|
|
random_test(
|
|
1,
|
|
TestConfig {
|
|
check_slashings: true,
|
|
..TestConfig::default()
|
|
},
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn check_slashings_example2() {
|
|
random_test(
|
|
2,
|
|
TestConfig {
|
|
check_slashings: true,
|
|
max_attestations: 3,
|
|
..TestConfig::default()
|
|
},
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn check_slashings_example3() {
|
|
random_test(
|
|
3,
|
|
TestConfig {
|
|
check_slashings: true,
|
|
max_attestations: 100,
|
|
..TestConfig::default()
|
|
},
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn no_crash_example1() {
|
|
random_test(1, TestConfig::default());
|
|
}
|
|
|
|
#[test]
|
|
fn no_crash_example2() {
|
|
random_test(2, TestConfig::default());
|
|
}
|
|
|
|
#[test]
|
|
fn no_crash_example3() {
|
|
random_test(3, TestConfig::default());
|
|
}
|
|
|
|
#[test]
|
|
fn no_crash_blocks_example1() {
|
|
random_test(
|
|
1,
|
|
TestConfig {
|
|
add_blocks: true,
|
|
..TestConfig::default()
|
|
},
|
|
);
|
|
}
|