use super::signature_sets::Error as SignatureSetError; use merkle_proof::MerkleTreeError; use safe_arith::ArithError; use types::*; /// The error returned from the `per_block_processing` function. Indicates that a block is either /// invalid, or we were unable to determine its validity (we encountered an unexpected error). /// /// Any of the `...Error` variants indicate that at some point during block (and block operation) /// verification, there was an error. There is no indication as to _where_ that error happened /// (e.g., when processing attestations instead of when processing deposits). #[derive(Debug, PartialEq, Clone)] pub enum BlockProcessingError { RandaoSignatureInvalid, BulkSignatureVerificationFailed, StateRootMismatch, DepositCountInvalid { expected: usize, found: usize, }, HeaderInvalid { reason: HeaderInvalid, }, ProposerSlashingInvalid { index: usize, reason: ProposerSlashingInvalid, }, AttesterSlashingInvalid { index: usize, reason: AttesterSlashingInvalid, }, IndexedAttestationInvalid { index: usize, reason: IndexedAttestationInvalid, }, AttestationInvalid { index: usize, reason: AttestationInvalid, }, DepositInvalid { index: usize, reason: DepositInvalid, }, ExitInvalid { index: usize, reason: ExitInvalid, }, BeaconStateError(BeaconStateError), SignatureSetError(SignatureSetError), SszTypesError(ssz_types::Error), MerkleTreeError(MerkleTreeError), ArithError(ArithError), } impl From for BlockProcessingError { fn from(e: BeaconStateError) -> Self { BlockProcessingError::BeaconStateError(e) } } impl From for BlockProcessingError { fn from(e: SignatureSetError) -> Self { BlockProcessingError::SignatureSetError(e) } } impl From for BlockProcessingError { fn from(error: ssz_types::Error) -> Self { BlockProcessingError::SszTypesError(error) } } impl From for BlockProcessingError { fn from(e: ArithError) -> Self { BlockProcessingError::ArithError(e) } } impl From> for BlockProcessingError { fn from(e: BlockOperationError) -> BlockProcessingError { match e { BlockOperationError::Invalid(reason) => BlockProcessingError::HeaderInvalid { reason }, BlockOperationError::BeaconStateError(e) => BlockProcessingError::BeaconStateError(e), BlockOperationError::SignatureSetError(e) => BlockProcessingError::SignatureSetError(e), BlockOperationError::SszTypesError(e) => BlockProcessingError::SszTypesError(e), BlockOperationError::ArithError(e) => BlockProcessingError::ArithError(e), } } } /// A conversion that consumes `self` and adds an `index` variable to resulting struct. /// /// Used here to allow converting an error into an upstream error that points to the object that /// caused the error. For example, pointing to the index of an attestation that caused the /// `AttestationInvalid` error. pub trait IntoWithIndex: Sized { fn into_with_index(self, index: usize) -> T; } macro_rules! impl_into_block_processing_error_with_index { ($($type: ident),*) => { $( impl IntoWithIndex for BlockOperationError<$type> { fn into_with_index(self, index: usize) -> BlockProcessingError { match self { BlockOperationError::Invalid(reason) => BlockProcessingError::$type { index, reason }, BlockOperationError::BeaconStateError(e) => BlockProcessingError::BeaconStateError(e), BlockOperationError::SignatureSetError(e) => BlockProcessingError::SignatureSetError(e), BlockOperationError::SszTypesError(e) => BlockProcessingError::SszTypesError(e), BlockOperationError::ArithError(e) => BlockProcessingError::ArithError(e), } } } )* }; } impl_into_block_processing_error_with_index!( ProposerSlashingInvalid, AttesterSlashingInvalid, IndexedAttestationInvalid, AttestationInvalid, DepositInvalid, ExitInvalid ); pub type HeaderValidationError = BlockOperationError; pub type AttesterSlashingValidationError = BlockOperationError; pub type ProposerSlashingValidationError = BlockOperationError; pub type AttestationValidationError = BlockOperationError; pub type DepositValidationError = BlockOperationError; pub type ExitValidationError = BlockOperationError; #[derive(Debug, PartialEq, Clone)] pub enum BlockOperationError { Invalid(T), BeaconStateError(BeaconStateError), SignatureSetError(SignatureSetError), SszTypesError(ssz_types::Error), ArithError(ArithError), } impl BlockOperationError { pub fn invalid(reason: T) -> BlockOperationError { BlockOperationError::Invalid(reason) } } impl From for BlockOperationError { fn from(e: BeaconStateError) -> Self { BlockOperationError::BeaconStateError(e) } } impl From for BlockOperationError { fn from(e: SignatureSetError) -> Self { BlockOperationError::SignatureSetError(e) } } impl From for BlockOperationError { fn from(error: ssz_types::Error) -> Self { BlockOperationError::SszTypesError(error) } } impl From for BlockOperationError { fn from(e: ArithError) -> Self { BlockOperationError::ArithError(e) } } #[derive(Debug, PartialEq, Clone)] pub enum HeaderInvalid { ProposalSignatureInvalid, StateSlotMismatch, ProposerIndexMismatch { block_proposer_index: usize, state_proposer_index: usize, }, ParentBlockRootMismatch { state: Hash256, block: Hash256, }, ProposerSlashed(usize), } #[derive(Debug, PartialEq, Clone)] pub enum ProposerSlashingInvalid { /// The proposer index is not a known validator. ProposerUnknown(u64), /// The two proposal have different slots. /// /// (proposal_1_slot, proposal_2_slot) ProposalSlotMismatch(Slot, Slot), /// The two proposals have different proposer indices. /// /// (proposer_index_1, proposer_index_2) ProposerIndexMismatch(u64, u64), /// The proposals are identical and therefore not slashable. ProposalsIdentical, /// The specified proposer cannot be slashed because they are already slashed, or not active. ProposerNotSlashable(u64), /// The first proposal signature was invalid. BadProposal1Signature, /// The second proposal signature was invalid. BadProposal2Signature, } #[derive(Debug, PartialEq, Clone)] pub enum AttesterSlashingInvalid { /// The attestations were not in conflict. NotSlashable, /// The first `IndexedAttestation` was invalid. IndexedAttestation1Invalid(BlockOperationError), /// The second `IndexedAttestation` was invalid. IndexedAttestation2Invalid(BlockOperationError), /// The validator index is unknown. One cannot slash one who does not exist. UnknownValidator(u64), /// The specified validator has already been withdrawn. ValidatorAlreadyWithdrawn(u64), /// There were no indices able to be slashed. NoSlashableIndices, } /// Describes why an object is invalid. #[derive(Debug, PartialEq, Clone)] pub enum AttestationInvalid { /// Commmittee index exceeds number of committees in that slot. BadCommitteeIndex, /// Attestation included before the inclusion delay. IncludedTooEarly { state: Slot, delay: u64, attestation: Slot, }, /// Attestation slot is too far in the past to be included in a block. IncludedTooLate { state: Slot, attestation: Slot }, /// Attestation target epoch does not match attestation slot. TargetEpochSlotMismatch { target_epoch: Epoch, slot_epoch: Epoch, }, /// Attestation target epoch does not match the current or previous epoch. BadTargetEpoch, /// Attestation justified checkpoint doesn't match the state's current or previous justified /// checkpoint. /// /// `is_current` is `true` if the attestation was compared to the /// `state.current_justified_checkpoint`, `false` if compared to `state.previous_justified_checkpoint`. WrongJustifiedCheckpoint { state: Checkpoint, attestation: Checkpoint, is_current: bool, }, /// There are no set bits on the attestation -- an attestation must be signed by at least one /// validator. AggregationBitfieldIsEmpty, /// The aggregation bitfield length is not the smallest possible size to represent the committee. BadAggregationBitfieldLength { committee_len: usize, bitfield_len: usize, }, /// The attestation was not disjoint compared to already seen attestations. NotDisjoint, /// The validator index was unknown. UnknownValidator(u64), /// The attestation signature verification failed. BadSignature, /// The indexed attestation created from this attestation was found to be invalid. BadIndexedAttestation(IndexedAttestationInvalid), } impl From> for BlockOperationError { fn from(e: BlockOperationError) -> Self { match e { BlockOperationError::Invalid(e) => { BlockOperationError::invalid(AttestationInvalid::BadIndexedAttestation(e)) } BlockOperationError::BeaconStateError(e) => BlockOperationError::BeaconStateError(e), BlockOperationError::SignatureSetError(e) => BlockOperationError::SignatureSetError(e), BlockOperationError::SszTypesError(e) => BlockOperationError::SszTypesError(e), BlockOperationError::ArithError(e) => BlockOperationError::ArithError(e), } } } #[derive(Debug, PartialEq, Clone)] pub enum IndexedAttestationInvalid { /// The number of indices exceeds the global maximum. /// /// (max_indices, indices_given) MaxIndicesExceed(usize, usize), /// The validator indices were not in increasing order. /// /// The error occurred between the given `index` and `index + 1` BadValidatorIndicesOrdering(usize), /// The validator index is unknown. One cannot slash one who does not exist. UnknownValidator(u64), /// The indexed attestation aggregate signature was not valid. BadSignature, /// There was an error whilst attempting to get a set of signatures. The signatures may have /// been invalid or an internal error occurred. SignatureSetError(SignatureSetError), } #[derive(Debug, PartialEq, Clone)] pub enum DepositInvalid { /// The signature (proof-of-possession) does not match the given pubkey. BadSignature, /// The signature or pubkey does not represent a valid BLS point. BadBlsBytes, /// The specified `branch` and `index` did not form a valid proof that the deposit is included /// in the eth1 deposit root. BadMerkleProof, } #[derive(Debug, PartialEq, Clone)] pub enum ExitInvalid { /// The specified validator is not active. NotActive(u64), /// The specified validator is not in the state's validator registry. ValidatorUnknown(u64), /// The specified validator has a non-maximum exit epoch. AlreadyExited(u64), /// The specified validator has already initiated exit. AlreadyInitiatedExit(u64), /// The exit is for a future epoch. FutureEpoch { state: Epoch, exit: Epoch }, /// The validator has not been active for long enough. TooYoungToExit { current_epoch: Epoch, earliest_exit_epoch: Epoch, }, /// The exit signature was not signed by the validator. BadSignature, /// There was an error whilst attempting to get a set of signatures. The signatures may have /// been invalid or an internal error occurred. SignatureSetError(SignatureSetError), }