Update operations_pool for new BeaconStateTypes

This commit is contained in:
Paul Hauner 2019-05-08 17:07:26 +10:00
parent ae09a00090
commit 9fd8af8428
No known key found for this signature in database
GPG Key ID: D362883A9218FCC6
3 changed files with 65 additions and 40 deletions

View File

@ -13,10 +13,11 @@ use state_processing::per_block_processing::{
verify_transfer_time_independent_only, verify_transfer_time_independent_only,
}; };
use std::collections::{btree_map::Entry, hash_map, BTreeMap, HashMap, HashSet}; use std::collections::{btree_map::Entry, hash_map, BTreeMap, HashMap, HashSet};
use std::marker::PhantomData;
use types::chain_spec::Domain; use types::chain_spec::Domain;
use types::{ use types::{
Attestation, AttestationData, AttesterSlashing, BeaconState, ChainSpec, Deposit, Epoch, Attestation, AttestationData, AttesterSlashing, BeaconState, BeaconStateTypes, ChainSpec,
ProposerSlashing, Transfer, Validator, VoluntaryExit, Deposit, Epoch, ProposerSlashing, Transfer, Validator, VoluntaryExit,
}; };
#[cfg(test)] #[cfg(test)]
@ -25,7 +26,7 @@ const VERIFY_DEPOSIT_PROOFS: bool = false;
const VERIFY_DEPOSIT_PROOFS: bool = false; // TODO: enable this const VERIFY_DEPOSIT_PROOFS: bool = false; // TODO: enable this
#[derive(Default)] #[derive(Default)]
pub struct OperationPool { pub struct OperationPool<T: BeaconStateTypes + Default> {
/// Map from attestation ID (see below) to vectors of attestations. /// Map from attestation ID (see below) to vectors of attestations.
attestations: RwLock<HashMap<AttestationId, Vec<Attestation>>>, attestations: RwLock<HashMap<AttestationId, Vec<Attestation>>>,
/// Map from deposit index to deposit data. /// Map from deposit index to deposit data.
@ -42,6 +43,7 @@ pub struct OperationPool {
voluntary_exits: RwLock<HashMap<u64, VoluntaryExit>>, voluntary_exits: RwLock<HashMap<u64, VoluntaryExit>>,
/// Set of transfers. /// Set of transfers.
transfers: RwLock<HashSet<Transfer>>, transfers: RwLock<HashSet<Transfer>>,
_phantom: PhantomData<T>,
} }
/// Serialized `AttestationData` augmented with a domain to encode the fork info. /// Serialized `AttestationData` augmented with a domain to encode the fork info.
@ -52,14 +54,22 @@ struct AttestationId(Vec<u8>);
const DOMAIN_BYTES_LEN: usize = 8; const DOMAIN_BYTES_LEN: usize = 8;
impl AttestationId { impl AttestationId {
fn from_data(attestation: &AttestationData, state: &BeaconState, spec: &ChainSpec) -> Self { fn from_data<T: BeaconStateTypes>(
attestation: &AttestationData,
state: &BeaconState<T>,
spec: &ChainSpec,
) -> Self {
let mut bytes = ssz_encode(attestation); let mut bytes = ssz_encode(attestation);
let epoch = attestation.slot.epoch(spec.slots_per_epoch); let epoch = attestation.slot.epoch(spec.slots_per_epoch);
bytes.extend_from_slice(&AttestationId::compute_domain_bytes(epoch, state, spec)); bytes.extend_from_slice(&AttestationId::compute_domain_bytes(epoch, state, spec));
AttestationId(bytes) AttestationId(bytes)
} }
fn compute_domain_bytes(epoch: Epoch, state: &BeaconState, spec: &ChainSpec) -> Vec<u8> { fn compute_domain_bytes<T: BeaconStateTypes>(
epoch: Epoch,
state: &BeaconState<T>,
spec: &ChainSpec,
) -> Vec<u8> {
int_to_bytes8(spec.get_domain(epoch, Domain::Attestation, &state.fork)) int_to_bytes8(spec.get_domain(epoch, Domain::Attestation, &state.fork))
} }
@ -75,7 +85,11 @@ impl AttestationId {
/// receive for including it in a block. /// receive for including it in a block.
// TODO: this could be optimised with a map from validator index to whether that validator has // TODO: this could be optimised with a map from validator index to whether that validator has
// attested in each of the current and previous epochs. Currently quadractic in number of validators. // attested in each of the current and previous epochs. Currently quadractic in number of validators.
fn attestation_score(attestation: &Attestation, state: &BeaconState, spec: &ChainSpec) -> usize { fn attestation_score<T: BeaconStateTypes>(
attestation: &Attestation,
state: &BeaconState<T>,
spec: &ChainSpec,
) -> usize {
// Bitfield of validators whose attestations are new/fresh. // Bitfield of validators whose attestations are new/fresh.
let mut new_validators = attestation.aggregation_bitfield.clone(); let mut new_validators = attestation.aggregation_bitfield.clone();
@ -113,7 +127,7 @@ pub enum DepositInsertStatus {
Replaced(Box<Deposit>), Replaced(Box<Deposit>),
} }
impl OperationPool { impl<T: BeaconStateTypes> OperationPool<T> {
/// Create a new operation pool. /// Create a new operation pool.
pub fn new() -> Self { pub fn new() -> Self {
Self::default() Self::default()
@ -123,7 +137,7 @@ impl OperationPool {
pub fn insert_attestation( pub fn insert_attestation(
&self, &self,
attestation: Attestation, attestation: Attestation,
state: &BeaconState, state: &BeaconState<T>,
spec: &ChainSpec, spec: &ChainSpec,
) -> Result<(), AttestationValidationError> { ) -> Result<(), AttestationValidationError> {
// Check that attestation signatures are valid. // Check that attestation signatures are valid.
@ -169,7 +183,7 @@ impl OperationPool {
} }
/// Get a list of attestations for inclusion in a block. /// Get a list of attestations for inclusion in a block.
pub fn get_attestations(&self, state: &BeaconState, spec: &ChainSpec) -> Vec<Attestation> { pub fn get_attestations(&self, state: &BeaconState<T>, spec: &ChainSpec) -> Vec<Attestation> {
// Attestations for the current fork, which may be from the current or previous epoch. // Attestations for the current fork, which may be from the current or previous epoch.
let prev_epoch = state.previous_epoch(spec); let prev_epoch = state.previous_epoch(spec);
let current_epoch = state.current_epoch(spec); let current_epoch = state.current_epoch(spec);
@ -204,7 +218,7 @@ impl OperationPool {
// TODO: we could probably prune other attestations here: // TODO: we could probably prune other attestations here:
// - ones that are completely covered by attestations included in the state // - ones that are completely covered by attestations included in the state
// - maybe ones invalidated by the confirmation of one fork over another // - maybe ones invalidated by the confirmation of one fork over another
pub fn prune_attestations(&self, finalized_state: &BeaconState, spec: &ChainSpec) { pub fn prune_attestations(&self, finalized_state: &BeaconState<T>, spec: &ChainSpec) {
self.attestations.write().retain(|_, attestations| { self.attestations.write().retain(|_, attestations| {
// All the attestations in this bucket have the same data, so we only need to // All the attestations in this bucket have the same data, so we only need to
// check the first one. // check the first one.
@ -220,7 +234,7 @@ impl OperationPool {
pub fn insert_deposit( pub fn insert_deposit(
&self, &self,
deposit: Deposit, deposit: Deposit,
state: &BeaconState, state: &BeaconState<T>,
spec: &ChainSpec, spec: &ChainSpec,
) -> Result<DepositInsertStatus, DepositValidationError> { ) -> Result<DepositInsertStatus, DepositValidationError> {
use DepositInsertStatus::*; use DepositInsertStatus::*;
@ -245,7 +259,7 @@ impl OperationPool {
/// Get an ordered list of deposits for inclusion in a block. /// Get an ordered list of deposits for inclusion in a block.
/// ///
/// Take at most the maximum number of deposits, beginning from the current deposit index. /// Take at most the maximum number of deposits, beginning from the current deposit index.
pub fn get_deposits(&self, state: &BeaconState, spec: &ChainSpec) -> Vec<Deposit> { pub fn get_deposits(&self, state: &BeaconState<T>, spec: &ChainSpec) -> Vec<Deposit> {
let start_idx = state.deposit_index; let start_idx = state.deposit_index;
(start_idx..start_idx + spec.max_deposits) (start_idx..start_idx + spec.max_deposits)
.map(|idx| self.deposits.read().get(&idx).cloned()) .map(|idx| self.deposits.read().get(&idx).cloned())
@ -255,7 +269,7 @@ impl OperationPool {
} }
/// Remove all deposits with index less than the deposit index of the latest finalised block. /// Remove all deposits with index less than the deposit index of the latest finalised block.
pub fn prune_deposits(&self, state: &BeaconState) -> BTreeMap<u64, Deposit> { pub fn prune_deposits(&self, state: &BeaconState<T>) -> BTreeMap<u64, Deposit> {
let deposits_keep = self.deposits.write().split_off(&state.deposit_index); let deposits_keep = self.deposits.write().split_off(&state.deposit_index);
std::mem::replace(&mut self.deposits.write(), deposits_keep) std::mem::replace(&mut self.deposits.write(), deposits_keep)
} }
@ -269,7 +283,7 @@ impl OperationPool {
pub fn insert_proposer_slashing( pub fn insert_proposer_slashing(
&self, &self,
slashing: ProposerSlashing, slashing: ProposerSlashing,
state: &BeaconState, state: &BeaconState<T>,
spec: &ChainSpec, spec: &ChainSpec,
) -> Result<(), ProposerSlashingValidationError> { ) -> 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,
@ -286,7 +300,7 @@ impl OperationPool {
/// Depends on the fork field of the state, but not on the state's epoch. /// Depends on the fork field of the state, but not on the state's epoch.
fn attester_slashing_id( fn attester_slashing_id(
slashing: &AttesterSlashing, slashing: &AttesterSlashing,
state: &BeaconState, state: &BeaconState<T>,
spec: &ChainSpec, spec: &ChainSpec,
) -> (AttestationId, AttestationId) { ) -> (AttestationId, AttestationId) {
( (
@ -299,7 +313,7 @@ impl OperationPool {
pub fn insert_attester_slashing( pub fn insert_attester_slashing(
&self, &self,
slashing: AttesterSlashing, slashing: AttesterSlashing,
state: &BeaconState, state: &BeaconState<T>,
spec: &ChainSpec, spec: &ChainSpec,
) -> Result<(), AttesterSlashingValidationError> { ) -> Result<(), AttesterSlashingValidationError> {
verify_attester_slashing(state, &slashing, true, spec)?; verify_attester_slashing(state, &slashing, true, spec)?;
@ -315,7 +329,7 @@ impl OperationPool {
/// earlier in the block. /// earlier in the block.
pub fn get_slashings( pub fn get_slashings(
&self, &self,
state: &BeaconState, state: &BeaconState<T>,
spec: &ChainSpec, spec: &ChainSpec,
) -> (Vec<ProposerSlashing>, Vec<AttesterSlashing>) { ) -> (Vec<ProposerSlashing>, Vec<AttesterSlashing>) {
let proposer_slashings = filter_limit_operations( let proposer_slashings = filter_limit_operations(
@ -370,7 +384,7 @@ impl OperationPool {
} }
/// Prune proposer slashings for all slashed or withdrawn validators. /// Prune proposer slashings for all slashed or withdrawn validators.
pub fn prune_proposer_slashings(&self, finalized_state: &BeaconState, spec: &ChainSpec) { pub fn prune_proposer_slashings(&self, finalized_state: &BeaconState<T>, spec: &ChainSpec) {
prune_validator_hash_map( prune_validator_hash_map(
&mut self.proposer_slashings.write(), &mut self.proposer_slashings.write(),
|validator| { |validator| {
@ -383,7 +397,7 @@ impl OperationPool {
/// Prune attester slashings for all slashed or withdrawn validators, or attestations on another /// Prune attester slashings for all slashed or withdrawn validators, or attestations on another
/// fork. /// fork.
pub fn prune_attester_slashings(&self, finalized_state: &BeaconState, spec: &ChainSpec) { pub fn prune_attester_slashings(&self, finalized_state: &BeaconState<T>, spec: &ChainSpec) {
self.attester_slashings.write().retain(|id, slashing| { self.attester_slashings.write().retain(|id, slashing| {
let fork_ok = &Self::attester_slashing_id(slashing, finalized_state, spec) == id; let fork_ok = &Self::attester_slashing_id(slashing, finalized_state, spec) == id;
let curr_epoch = finalized_state.current_epoch(spec); let curr_epoch = finalized_state.current_epoch(spec);
@ -402,7 +416,7 @@ impl OperationPool {
pub fn insert_voluntary_exit( pub fn insert_voluntary_exit(
&self, &self,
exit: VoluntaryExit, exit: VoluntaryExit,
state: &BeaconState, state: &BeaconState<T>,
spec: &ChainSpec, spec: &ChainSpec,
) -> Result<(), ExitValidationError> { ) -> Result<(), ExitValidationError> {
verify_exit_time_independent_only(state, &exit, spec)?; verify_exit_time_independent_only(state, &exit, spec)?;
@ -413,7 +427,11 @@ impl OperationPool {
} }
/// Get a list of voluntary exits for inclusion in a block. /// Get a list of voluntary exits for inclusion in a block.
pub fn get_voluntary_exits(&self, state: &BeaconState, spec: &ChainSpec) -> Vec<VoluntaryExit> { pub fn get_voluntary_exits(
&self,
state: &BeaconState<T>,
spec: &ChainSpec,
) -> Vec<VoluntaryExit> {
filter_limit_operations( filter_limit_operations(
self.voluntary_exits.read().values(), self.voluntary_exits.read().values(),
|exit| verify_exit(state, exit, spec).is_ok(), |exit| verify_exit(state, exit, spec).is_ok(),
@ -422,7 +440,7 @@ impl OperationPool {
} }
/// Prune if validator has already exited at the last finalized state. /// Prune if validator has already exited at the last finalized state.
pub fn prune_voluntary_exits(&self, finalized_state: &BeaconState, spec: &ChainSpec) { pub fn prune_voluntary_exits(&self, finalized_state: &BeaconState<T>, spec: &ChainSpec) {
prune_validator_hash_map( prune_validator_hash_map(
&mut self.voluntary_exits.write(), &mut self.voluntary_exits.write(),
|validator| validator.is_exited_at(finalized_state.current_epoch(spec)), |validator| validator.is_exited_at(finalized_state.current_epoch(spec)),
@ -434,7 +452,7 @@ impl OperationPool {
pub fn insert_transfer( pub fn insert_transfer(
&self, &self,
transfer: Transfer, transfer: Transfer,
state: &BeaconState, state: &BeaconState<T>,
spec: &ChainSpec, spec: &ChainSpec,
) -> Result<(), TransferValidationError> { ) -> Result<(), TransferValidationError> {
// The signature of the transfer isn't hashed, but because we check // The signature of the transfer isn't hashed, but because we check
@ -448,7 +466,7 @@ impl OperationPool {
/// Get a list of transfers for inclusion in a block. /// Get a list of transfers for inclusion in a block.
// TODO: improve the economic optimality of this function by accounting for // TODO: improve the economic optimality of this function by accounting for
// dependencies between transfers in the same block e.g. A pays B, B pays C // dependencies between transfers in the same block e.g. A pays B, B pays C
pub fn get_transfers(&self, state: &BeaconState, spec: &ChainSpec) -> Vec<Transfer> { pub fn get_transfers(&self, state: &BeaconState<T>, spec: &ChainSpec) -> Vec<Transfer> {
self.transfers self.transfers
.read() .read()
.iter() .iter()
@ -460,14 +478,14 @@ impl OperationPool {
} }
/// Prune the set of transfers by removing all those whose slot has already passed. /// Prune the set of transfers by removing all those whose slot has already passed.
pub fn prune_transfers(&self, finalized_state: &BeaconState) { pub fn prune_transfers(&self, finalized_state: &BeaconState<T>) {
self.transfers self.transfers
.write() .write()
.retain(|transfer| transfer.slot > finalized_state.slot) .retain(|transfer| transfer.slot > finalized_state.slot)
} }
/// Prune all types of transactions given the latest finalized state. /// Prune all types of transactions given the latest finalized state.
pub fn prune_all(&self, finalized_state: &BeaconState, spec: &ChainSpec) { pub fn prune_all(&self, finalized_state: &BeaconState<T>, spec: &ChainSpec) {
self.prune_attestations(finalized_state, spec); self.prune_attestations(finalized_state, spec);
self.prune_deposits(finalized_state); self.prune_deposits(finalized_state);
self.prune_proposer_slashings(finalized_state, spec); self.prune_proposer_slashings(finalized_state, spec);
@ -487,7 +505,10 @@ impl OperationPool {
/// ///
/// - Their `AttestationData` is equal. /// - Their `AttestationData` is equal.
/// - `attestation` does not contain any signatures that `PendingAttestation` does not have. /// - `attestation` does not contain any signatures that `PendingAttestation` does not have.
fn superior_attestation_exists_in_state(state: &BeaconState, attestation: &Attestation) -> bool { fn superior_attestation_exists_in_state<T: BeaconStateTypes>(
state: &BeaconState<T>,
attestation: &Attestation,
) -> bool {
state state
.current_epoch_attestations .current_epoch_attestations
.iter() .iter()
@ -522,10 +543,10 @@ where
/// The keys in the map should be validator indices, which will be looked up /// The keys in the map should be validator indices, which will be looked up
/// in the state's validator registry and then passed to `prune_if`. /// in the state's validator registry and then passed to `prune_if`.
/// Entries for unknown validators will be kept. /// Entries for unknown validators will be kept.
fn prune_validator_hash_map<T, F>( fn prune_validator_hash_map<T, F, B: BeaconStateTypes>(
map: &mut HashMap<u64, T>, map: &mut HashMap<u64, T>,
prune_if: F, prune_if: F,
finalized_state: &BeaconState, finalized_state: &BeaconState<B>,
) where ) where
F: Fn(&Validator) -> bool, F: Fn(&Validator) -> bool,
{ {
@ -649,7 +670,11 @@ mod tests {
} }
// Create a random deposit (with a valid proof of posession) // Create a random deposit (with a valid proof of posession)
fn make_deposit(rng: &mut XorShiftRng, state: &BeaconState, spec: &ChainSpec) -> Deposit { fn make_deposit<T: BeaconStateTypes>(
rng: &mut XorShiftRng,
state: &BeaconState<T>,
spec: &ChainSpec,
) -> Deposit {
let keypair = Keypair::random(); let keypair = Keypair::random();
let mut deposit = Deposit::random_for_test(rng); let mut deposit = Deposit::random_for_test(rng);
let mut deposit_input = DepositInput { let mut deposit_input = DepositInput {
@ -668,9 +693,9 @@ mod tests {
} }
// Create `count` dummy deposits with sequential deposit IDs beginning from `start`. // Create `count` dummy deposits with sequential deposit IDs beginning from `start`.
fn dummy_deposits( fn dummy_deposits<T: BeaconStateTypes>(
rng: &mut XorShiftRng, rng: &mut XorShiftRng,
state: &BeaconState, state: &BeaconState<T>,
spec: &ChainSpec, spec: &ChainSpec,
start: u64, start: u64,
count: u64, count: u64,
@ -685,9 +710,11 @@ mod tests {
.collect() .collect()
} }
fn test_state(rng: &mut XorShiftRng) -> (ChainSpec, BeaconState) { fn test_state(rng: &mut XorShiftRng) -> (ChainSpec, BeaconState<FoundationStateTypes>) {
let spec = ChainSpec::foundation(); let spec = FoundationStateTypes::spec();
let mut state = BeaconState::random_for_test(rng); let mut state = BeaconState::random_for_test(rng);
state.fork = Fork::genesis(&spec); state.fork = Fork::genesis(&spec);
(spec, state) (spec, state)

View File

@ -1,7 +1,7 @@
use crate::*; use crate::*;
use fixed_len_vec::typenum::{Unsigned, U1024, U8, U8192}; use fixed_len_vec::typenum::{Unsigned, U1024, U8, U8192};
pub trait BeaconStateTypes { pub trait BeaconStateTypes: Default {
type ShardCount: Unsigned + Clone + Sync + Send; type ShardCount: Unsigned + Clone + Sync + Send;
type SlotsPerHistoricalRoot: Unsigned + Clone + Sync + Send; type SlotsPerHistoricalRoot: Unsigned + Clone + Sync + Send;
type LatestRandaoMixesLength: Unsigned + Clone + Sync + Send; type LatestRandaoMixesLength: Unsigned + Clone + Sync + Send;
@ -11,7 +11,7 @@ pub trait BeaconStateTypes {
fn spec() -> ChainSpec; fn spec() -> ChainSpec;
} }
#[derive(Clone, PartialEq, Debug)] #[derive(Clone, PartialEq, Debug, Default)]
pub struct FoundationStateTypes; pub struct FoundationStateTypes;
impl BeaconStateTypes for FoundationStateTypes { impl BeaconStateTypes for FoundationStateTypes {
@ -28,7 +28,7 @@ impl BeaconStateTypes for FoundationStateTypes {
pub type FoundationBeaconState = BeaconState<FoundationStateTypes>; pub type FoundationBeaconState = BeaconState<FoundationStateTypes>;
#[derive(Clone, PartialEq, Debug)] #[derive(Clone, PartialEq, Debug, Default)]
pub struct FewValidatorsStateTypes; pub struct FewValidatorsStateTypes;
impl BeaconStateTypes for FewValidatorsStateTypes { impl BeaconStateTypes for FewValidatorsStateTypes {

View File

@ -1,7 +1,6 @@
use crate::test_utils::TestRandom; use crate::test_utils::TestRandom;
use crate::Hash256; use crate::*;
use crate::beacon_state::BeaconStateTypes;
use fixed_len_vec::FixedLenVec; use fixed_len_vec::FixedLenVec;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode}; use ssz_derive::{Decode, Encode};
@ -31,7 +30,6 @@ pub struct HistoricalBatch<T: BeaconStateTypes> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::beacon_state::beacon_state_types::FoundationStateTypes;
pub type FoundationHistoricalBatch = HistoricalBatch<FoundationStateTypes>; pub type FoundationHistoricalBatch = HistoricalBatch<FoundationStateTypes>;