Operation pool: deposit pruning tests

This commit is contained in:
Michael Sproul 2019-03-20 12:44:37 +11:00
parent 9c2dfba843
commit 05dd936a97
No known key found for this signature in database
GPG Key ID: 77B1309D2E54E914

View File

@ -1,6 +1,7 @@
use int_to_bytes::int_to_bytes8; use int_to_bytes::int_to_bytes8;
use itertools::Itertools; use itertools::Itertools;
use ssz::ssz_encode; use ssz::ssz_encode;
use state_processing::per_block_processing::errors::ProposerSlashingValidationError;
use state_processing::per_block_processing::{ use state_processing::per_block_processing::{
validate_attestation, verify_deposit_merkle_proof, verify_exit, verify_proposer_slashing, validate_attestation, verify_deposit_merkle_proof, verify_exit, verify_proposer_slashing,
verify_transfer, verify_transfer_partial, verify_transfer, verify_transfer_partial,
@ -92,7 +93,7 @@ pub enum DepositInsertStatus {
/// The deposit already existed in the pool. /// The deposit already existed in the pool.
Duplicate, Duplicate,
/// The deposit conflicted with an existing deposit, which was replaced. /// The deposit conflicted with an existing deposit, which was replaced.
Replaced(Deposit), Replaced(Box<Deposit>),
} }
impl OperationPool { impl OperationPool {
@ -190,7 +191,7 @@ impl OperationPool {
if entry.get() == &deposit { if entry.get() == &deposit {
Duplicate Duplicate
} else { } else {
Replaced(entry.insert(deposit)) Replaced(Box::new(entry.insert(deposit)))
} }
} }
} }
@ -222,17 +223,21 @@ impl OperationPool {
std::mem::replace(&mut self.deposits, deposits_keep) std::mem::replace(&mut self.deposits, deposits_keep)
} }
/// The number of deposits stored in the pool.
pub fn num_deposits(&self) -> usize {
self.deposits.len()
}
/// Insert a proposer slashing into the pool. /// Insert a proposer slashing into the pool.
pub fn insert_proposer_slashing( pub fn insert_proposer_slashing(
&mut self, &mut self,
slashing: ProposerSlashing, slashing: ProposerSlashing,
state: &BeaconState, state: &BeaconState,
spec: &ChainSpec, spec: &ChainSpec,
) -> Result<(), ()> { ) -> Result<(), ProposerSlashingValidationError> {
// TODO: should maybe insert anyway if the proposer is unknown in the validator index, // TODO: should maybe insert anyway if the proposer is unknown in the validator index,
// because they could *become* known later // because they could *become* known later
// FIXME: error handling verify_proposer_slashing(&slashing, state, spec)?;
verify_proposer_slashing(&slashing, state, spec).map_err(|_| ())?;
self.proposer_slashings self.proposer_slashings
.insert(slashing.proposer_index, slashing); .insert(slashing.proposer_index, slashing);
Ok(()) Ok(())
@ -404,7 +409,22 @@ mod tests {
assert_eq!(op_pool.insert_deposit(deposit1.clone()), Fresh); assert_eq!(op_pool.insert_deposit(deposit1.clone()), Fresh);
assert_eq!(op_pool.insert_deposit(deposit1.clone()), Duplicate); assert_eq!(op_pool.insert_deposit(deposit1.clone()), Duplicate);
assert_eq!(op_pool.insert_deposit(deposit2), Replaced(deposit1)); assert_eq!(
op_pool.insert_deposit(deposit2),
Replaced(Box::new(deposit1))
);
}
// Create `count` dummy deposits with sequential deposit IDs beginning from `start`.
fn dummy_deposits(rng: &mut XorShiftRng, start: u64, count: u64) -> Vec<Deposit> {
let proto_deposit = Deposit::random_for_test(rng);
(start..start + count)
.map(|index| {
let mut deposit = proto_deposit.clone();
deposit.index = index;
deposit
})
.collect()
} }
#[test] #[test]
@ -418,14 +438,7 @@ mod tests {
let offset = 1; let offset = 1;
assert!(offset <= extra); assert!(offset <= extra);
let proto_deposit = Deposit::random_for_test(&mut rng); let deposits = dummy_deposits(&mut rng, start, max_deposits + extra);
let deposits = (start..start + max_deposits + extra)
.map(|index| {
let mut deposit = proto_deposit.clone();
deposit.index = index;
deposit
})
.collect::<Vec<_>>();
for deposit in &deposits { for deposit in &deposits {
assert_eq!(op_pool.insert_deposit(deposit.clone()), Fresh); assert_eq!(op_pool.insert_deposit(deposit.clone()), Fresh);
@ -442,5 +455,55 @@ mod tests {
); );
} }
#[test]
fn prune_deposits() {
let rng = &mut XorShiftRng::from_seed([42; 16]);
let mut op_pool = OperationPool::new();
let spec = ChainSpec::foundation();
let start1 = 100;
let count = 100;
let gap = 25;
let start2 = start1 + count + gap;
let deposits1 = dummy_deposits(rng, start1, count);
let deposits2 = dummy_deposits(rng, start2, count);
for d in deposits1.into_iter().chain(deposits2) {
op_pool.insert_deposit(d);
}
assert_eq!(op_pool.num_deposits(), 2 * count as usize);
let mut state = BeaconState::random_for_test(rng);
state.deposit_index = start1;
// Pruning the first bunch of deposits in batches of 5 should work.
let step = 5;
let mut pool_size = step + 2 * count as usize;
for i in (start1..=(start1 + count)).step_by(step) {
state.deposit_index = i;
op_pool.prune_deposits(&state);
pool_size -= step;
assert_eq!(op_pool.num_deposits(), pool_size);
}
assert_eq!(pool_size, count as usize);
// Pruning in the gap should do nothing.
for i in (start1 + count..start2).step_by(step) {
state.deposit_index = i;
op_pool.prune_deposits(&state);
assert_eq!(op_pool.num_deposits(), count as usize);
}
// Same again for the later deposits.
pool_size += step;
for i in (start2..=(start2 + count)).step_by(step) {
state.deposit_index = i;
op_pool.prune_deposits(&state);
pool_size -= step;
assert_eq!(op_pool.num_deposits(), pool_size);
}
assert_eq!(op_pool.num_deposits(), 0);
}
// TODO: more tests // TODO: more tests
} }