op-pool: propagate errors, sort by transfer fee

This commit is contained in:
Michael Sproul 2019-03-20 16:28:04 +11:00
parent 95ed402228
commit 3396f2f08e
No known key found for this signature in database
GPG Key ID: 77B1309D2E54E914

View File

@ -1,7 +1,10 @@
use int_to_bytes::int_to_bytes8;
use itertools::Itertools;
use ssz::ssz_encode;
use state_processing::per_block_processing::errors::ProposerSlashingValidationError;
use state_processing::per_block_processing::errors::{
AttestationValidationError, DepositValidationError, ExitValidationError,
ProposerSlashingValidationError, TransferValidationError,
};
use state_processing::per_block_processing::{
validate_attestation, verify_deposit, verify_exit, verify_exit_time_independent_only,
verify_proposer_slashing, verify_transfer, verify_transfer_time_independent_only,
@ -108,10 +111,10 @@ impl OperationPool {
attestation: Attestation,
state: &BeaconState,
spec: &ChainSpec,
) -> Result<(), ()> {
) -> Result<(), AttestationValidationError> {
// Check that attestation signatures are valid.
// FIXME: should disable the time-dependent checks.
validate_attestation(state, &attestation, spec).map_err(|_| ())?;
validate_attestation(state, &attestation, spec)?;
let id = AttestationId::from_data(&attestation.data, state, spec);
@ -143,7 +146,7 @@ impl OperationPool {
/// Get a list of attestations for inclusion in a block.
pub fn get_attestations(&self, state: &BeaconState, spec: &ChainSpec) -> Vec<Attestation> {
// Attestations for the current fork...
// TODO: should we also check domain bytes for the previous epoch?
// FIXME: should we also check domain bytes for the previous epoch?
let current_epoch = state.slot.epoch(spec.slots_per_epoch);
let domain_bytes = AttestationId::compute_domain_bytes(current_epoch, state, spec);
self.attestations
@ -184,13 +187,12 @@ impl OperationPool {
deposit: Deposit,
state: &BeaconState,
spec: &ChainSpec,
) -> Result<DepositInsertStatus, ()> {
) -> Result<DepositInsertStatus, DepositValidationError> {
use DepositInsertStatus::*;
match self.deposits.entry(deposit.index) {
Entry::Vacant(entry) => {
// FIXME: error prop
verify_deposit(state, &deposit, VERIFY_DEPOSIT_PROOFS, spec).map_err(|_| ())?;
verify_deposit(state, &deposit, VERIFY_DEPOSIT_PROOFS, spec)?;
entry.insert(deposit);
Ok(Fresh)
}
@ -198,7 +200,7 @@ impl OperationPool {
if entry.get() == &deposit {
Ok(Duplicate)
} else {
verify_deposit(state, &deposit, VERIFY_DEPOSIT_PROOFS, spec).map_err(|_| ())?;
verify_deposit(state, &deposit, VERIFY_DEPOSIT_PROOFS, spec)?;
Ok(Replaced(Box::new(entry.insert(deposit))))
}
}
@ -279,7 +281,7 @@ impl OperationPool {
);
}
// TODO: copy ProposerSlashing code for AttesterSlashing
// FIXME: copy ProposerSlashing code for AttesterSlashing
/// Insert a voluntary exit, validating it almost-entirely (future exits are permitted).
pub fn insert_voluntary_exit(
@ -287,14 +289,13 @@ impl OperationPool {
exit: VoluntaryExit,
state: &BeaconState,
spec: &ChainSpec,
) -> Result<(), ()> {
verify_exit_time_independent_only(state, &exit, spec).map_err(|_| ())?;
) -> Result<(), ExitValidationError> {
verify_exit_time_independent_only(state, &exit, spec)?;
self.voluntary_exits.insert(exit.validator_index, exit);
Ok(())
}
/// Get a list of voluntary exits for inclusion in a block.
// TODO: could optimise this by eliding the checks that have already been done on insert
pub fn get_voluntary_exits(&self, state: &BeaconState, spec: &ChainSpec) -> Vec<VoluntaryExit> {
filter_limit_operations(
self.voluntary_exits.values(),
@ -318,25 +319,26 @@ impl OperationPool {
transfer: Transfer,
state: &BeaconState,
spec: &ChainSpec,
) -> Result<(), ()> {
) -> Result<(), TransferValidationError> {
// The signature of the transfer isn't hashed, but because we check
// it before we insert into the HashSet, we can't end up with duplicate
// transactions.
verify_transfer_time_independent_only(state, &transfer, spec).map_err(|_| ())?;
verify_transfer_time_independent_only(state, &transfer, spec)?;
self.transfers.insert(transfer);
Ok(())
}
/// Get a list of transfers for inclusion in a block.
// TODO: improve the economic optimality of this function by taking the transfer
// fees into account, and dependencies between transfers in the same block
// e.g. A pays B, B pays C
// 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
pub fn get_transfers(&self, state: &BeaconState, spec: &ChainSpec) -> Vec<Transfer> {
filter_limit_operations(
&self.transfers,
|transfer| verify_transfer(state, transfer, spec).is_ok(),
spec.max_transfers,
)
self.transfers
.iter()
.filter(|transfer| verify_transfer(state, transfer, spec).is_ok())
.sorted_by_key(|transfer| std::cmp::Reverse(transfer.fee))
.take(spec.max_transfers as usize)
.cloned()
.collect()
}
/// Prune the set of transfers by removing all those whose slot has already passed.