mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-14 10:22:38 +00:00
Implement slashing protection interchange format (#1544)
## Issue Addressed Implements support for importing and exporting the slashing protection DB interchange format described here: https://hackmd.io/@sproul/Bk0Y0qdGD Also closes #1584 ## Proposed Changes * [x] Support for serializing and deserializing the format * [x] Support for importing and exporting Lighthouse's database * [x] CLI commands to invoke import and export * [x] Export to minimal format (required when a minimal format has been previously imported) * [x] Tests for export to minimal (utilising mixed importing and attestation signing?) * [x] Tests for import/export of complete format, and import of minimal format * [x] ~~Prevent attestations with sources less than our max source (Danny's suggestion). Required for the fake attestation that we put in for the minimal format to block attestations from source 0.~~ * [x] Add the concept of a "low watermark" for compatibility with the minimal format Bonus! * [x] A fix to a potentially nasty bug involving validators getting re-registered each time the validator client ran! Thankfully, the ordering of keys meant that the validator IDs used for attestations and blocks remained stable -- otherwise we could have had some slashings on our hands! 😱 * [x] Tests to confirm that this bug is indeed vanquished
This commit is contained in:
128
validator_client/slashing_protection/src/bin/test_generator.rs
Normal file
128
validator_client/slashing_protection/src/bin/test_generator.rs
Normal file
@@ -0,0 +1,128 @@
|
||||
use slashing_protection::interchange::{
|
||||
CompleteInterchangeData, Interchange, InterchangeFormat, InterchangeMetadata,
|
||||
SignedAttestation, SignedBlock,
|
||||
};
|
||||
use slashing_protection::interchange_test::TestCase;
|
||||
use slashing_protection::test_utils::{pubkey, DEFAULT_GENESIS_VALIDATORS_ROOT};
|
||||
use slashing_protection::SUPPORTED_INTERCHANGE_FORMAT_VERSION;
|
||||
use std::fs::{self, File};
|
||||
use std::path::Path;
|
||||
use types::{Epoch, Hash256, Slot};
|
||||
|
||||
fn metadata(genesis_validators_root: Hash256) -> InterchangeMetadata {
|
||||
InterchangeMetadata {
|
||||
interchange_format: InterchangeFormat::Complete,
|
||||
interchange_format_version: SUPPORTED_INTERCHANGE_FORMAT_VERSION,
|
||||
genesis_validators_root,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
fn interchange(data: Vec<(usize, Vec<u64>, Vec<(u64, u64)>)>) -> Interchange {
|
||||
let data = data
|
||||
.into_iter()
|
||||
.map(|(pk, blocks, attestations)| CompleteInterchangeData {
|
||||
pubkey: pubkey(pk),
|
||||
signed_blocks: blocks
|
||||
.into_iter()
|
||||
.map(|slot| SignedBlock {
|
||||
slot: Slot::new(slot),
|
||||
signing_root: None,
|
||||
})
|
||||
.collect(),
|
||||
signed_attestations: attestations
|
||||
.into_iter()
|
||||
.map(|(source, target)| SignedAttestation {
|
||||
source_epoch: Epoch::new(source),
|
||||
target_epoch: Epoch::new(target),
|
||||
signing_root: None,
|
||||
})
|
||||
.collect(),
|
||||
})
|
||||
.collect();
|
||||
Interchange {
|
||||
metadata: metadata(DEFAULT_GENESIS_VALIDATORS_ROOT),
|
||||
data,
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let single_validator_blocks =
|
||||
vec![(0, 32, false), (0, 33, true), (0, 31, false), (0, 1, false)];
|
||||
let single_validator_attestations = vec![
|
||||
(0, 3, 4, false),
|
||||
(0, 14, 19, false),
|
||||
(0, 15, 20, false),
|
||||
(0, 16, 20, false),
|
||||
(0, 15, 21, true),
|
||||
];
|
||||
|
||||
let tests = vec![
|
||||
TestCase::new(
|
||||
"single_validator_import_only",
|
||||
interchange(vec![(0, vec![22], vec![(0, 2)])]),
|
||||
),
|
||||
TestCase::new(
|
||||
"single_validator_single_block",
|
||||
interchange(vec![(0, vec![32], vec![])]),
|
||||
)
|
||||
.with_blocks(single_validator_blocks.clone()),
|
||||
TestCase::new(
|
||||
"single_validator_single_attestation",
|
||||
interchange(vec![(0, vec![], vec![(15, 20)])]),
|
||||
)
|
||||
.with_attestations(single_validator_attestations.clone()),
|
||||
TestCase::new(
|
||||
"single_validator_single_block_and_attestation",
|
||||
interchange(vec![(0, vec![32], vec![(15, 20)])]),
|
||||
)
|
||||
.with_blocks(single_validator_blocks)
|
||||
.with_attestations(single_validator_attestations),
|
||||
TestCase::new(
|
||||
"single_validator_genesis_attestation",
|
||||
interchange(vec![(0, vec![], vec![(0, 0)])]),
|
||||
)
|
||||
.with_attestations(vec![(0, 0, 0, false)]),
|
||||
TestCase::new(
|
||||
"single_validator_multiple_blocks_and_attestations",
|
||||
interchange(vec![(
|
||||
0,
|
||||
vec![2, 3, 10, 1200],
|
||||
vec![(10, 11), (12, 13), (20, 24)],
|
||||
)]),
|
||||
)
|
||||
.with_blocks(vec![
|
||||
(0, 1, false),
|
||||
(0, 2, false),
|
||||
(0, 3, false),
|
||||
(0, 10, false),
|
||||
(0, 1200, false),
|
||||
(0, 4, true),
|
||||
(0, 256, true),
|
||||
(0, 1201, true),
|
||||
])
|
||||
.with_attestations(vec![
|
||||
(0, 9, 10, false),
|
||||
(0, 12, 13, false),
|
||||
(0, 11, 14, false),
|
||||
(0, 21, 22, false),
|
||||
(0, 10, 24, false),
|
||||
(0, 11, 12, true),
|
||||
(0, 20, 25, true),
|
||||
]),
|
||||
TestCase::new("wrong_genesis_validators_root", interchange(vec![]))
|
||||
.gvr(Hash256::from_low_u64_be(1))
|
||||
.should_fail(),
|
||||
];
|
||||
// TODO: multi-validator test
|
||||
|
||||
let args = std::env::args().collect::<Vec<_>>();
|
||||
let output_dir = Path::new(&args[1]);
|
||||
fs::create_dir_all(output_dir).unwrap();
|
||||
|
||||
for test in tests {
|
||||
test.run();
|
||||
let f = File::create(output_dir.join(format!("{}.json", test.name))).unwrap();
|
||||
serde_json::to_writer(f, &test).unwrap();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user