2020-10-09 01:37:24 -07:00
|
|
|
use std::sync::Arc;
|
2020-12-02 20:48:34 -08:00
|
|
|
|
|
|
|
use chrono::{DateTime, Utc};
|
2020-10-09 01:37:24 -07:00
|
|
|
use thiserror::Error;
|
|
|
|
|
2021-07-22 16:40:15 -07:00
|
|
|
use zebra_chain::{
|
|
|
|
block, orchard, sapling, sprout, transparent, work::difficulty::CompactDifficulty,
|
|
|
|
};
|
2020-12-02 20:48:34 -08:00
|
|
|
|
2020-10-09 01:37:24 -07:00
|
|
|
/// A wrapper for type erased errors that is itself clonable and implements the
|
|
|
|
/// Error trait
|
|
|
|
#[derive(Debug, Error, Clone)]
|
|
|
|
#[error(transparent)]
|
|
|
|
pub struct CloneError {
|
|
|
|
source: Arc<dyn std::error::Error + Send + Sync + 'static>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<CommitBlockError> for CloneError {
|
|
|
|
fn from(source: CommitBlockError) -> Self {
|
|
|
|
let source = Arc::new(source);
|
|
|
|
Self { source }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<BoxError> for CloneError {
|
|
|
|
fn from(source: BoxError) -> Self {
|
|
|
|
let source = Arc::from(source);
|
|
|
|
Self { source }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A boxed [`std::error::Error`].
|
|
|
|
pub type BoxError = Box<dyn std::error::Error + Send + Sync + 'static>;
|
|
|
|
|
|
|
|
/// An error describing the reason a block could not be committed to the state.
|
2021-07-14 05:06:43 -07:00
|
|
|
#[derive(Debug, Error, PartialEq, Eq)]
|
2020-10-09 01:37:24 -07:00
|
|
|
#[error("block is not contextually valid")]
|
|
|
|
pub struct CommitBlockError(#[from] ValidateContextError);
|
|
|
|
|
|
|
|
/// An error describing why a block failed contextual validation.
|
2021-07-14 05:06:43 -07:00
|
|
|
#[derive(Debug, Error, PartialEq, Eq)]
|
2020-10-09 01:37:24 -07:00
|
|
|
#[non_exhaustive]
|
2020-12-02 20:48:34 -08:00
|
|
|
#[allow(missing_docs)]
|
2020-10-09 01:37:24 -07:00
|
|
|
pub enum ValidateContextError {
|
2020-12-03 15:59:54 -08:00
|
|
|
#[error("block height {candidate_height:?} is lower than the current finalized height {finalized_tip_height:?}")]
|
2020-10-09 01:37:24 -07:00
|
|
|
#[non_exhaustive]
|
2020-12-02 20:48:34 -08:00
|
|
|
OrphanedBlock {
|
|
|
|
candidate_height: block::Height,
|
|
|
|
finalized_tip_height: block::Height,
|
|
|
|
},
|
2020-11-12 20:26:16 -08:00
|
|
|
|
2020-12-03 15:59:54 -08:00
|
|
|
#[error("block height {candidate_height:?} is not one greater than its parent block's height {parent_height:?}")]
|
2020-11-12 20:26:16 -08:00
|
|
|
#[non_exhaustive]
|
2020-12-02 20:48:34 -08:00
|
|
|
NonSequentialBlock {
|
|
|
|
candidate_height: block::Height,
|
|
|
|
parent_height: block::Height,
|
|
|
|
},
|
2020-11-19 00:05:48 -08:00
|
|
|
|
2020-12-03 15:59:54 -08:00
|
|
|
#[error("block time {candidate_time:?} is less than or equal to the median-time-past for the block {median_time_past:?}")]
|
2020-12-02 20:28:42 -08:00
|
|
|
#[non_exhaustive]
|
2020-12-02 20:48:34 -08:00
|
|
|
TimeTooEarly {
|
|
|
|
candidate_time: DateTime<Utc>,
|
|
|
|
median_time_past: DateTime<Utc>,
|
|
|
|
},
|
2020-12-02 20:28:42 -08:00
|
|
|
|
2020-12-03 15:59:54 -08:00
|
|
|
#[error("block time {candidate_time:?} is greater than the median-time-past for the block plus 90 minutes {block_time_max:?}")]
|
2020-12-02 20:28:42 -08:00
|
|
|
#[non_exhaustive]
|
2020-12-02 20:48:34 -08:00
|
|
|
TimeTooLate {
|
|
|
|
candidate_time: DateTime<Utc>,
|
|
|
|
block_time_max: DateTime<Utc>,
|
|
|
|
},
|
2020-12-02 20:28:42 -08:00
|
|
|
|
2020-12-03 15:59:54 -08:00
|
|
|
#[error("block difficulty threshold {difficulty_threshold:?} is not equal to the expected difficulty for the block {expected_difficulty:?}")]
|
2020-11-19 00:05:48 -08:00
|
|
|
#[non_exhaustive]
|
2020-12-02 20:48:34 -08:00
|
|
|
InvalidDifficultyThreshold {
|
|
|
|
difficulty_threshold: CompactDifficulty,
|
|
|
|
expected_difficulty: CompactDifficulty,
|
|
|
|
},
|
2021-07-14 05:06:43 -07:00
|
|
|
|
2021-07-22 16:40:15 -07:00
|
|
|
#[error("transparent double-spend: {outpoint:?} is spent twice in {location:?}")]
|
|
|
|
#[non_exhaustive]
|
|
|
|
DuplicateTransparentSpend {
|
|
|
|
outpoint: transparent::OutPoint,
|
|
|
|
location: &'static str,
|
|
|
|
},
|
|
|
|
|
|
|
|
#[error("missing transparent output: possible double-spend of {outpoint:?} in {location:?}")]
|
|
|
|
#[non_exhaustive]
|
|
|
|
MissingTransparentOutput {
|
|
|
|
outpoint: transparent::OutPoint,
|
|
|
|
location: &'static str,
|
|
|
|
},
|
|
|
|
|
|
|
|
#[error("out-of-order transparent spend: {outpoint:?} is created by a later transaction in the same block")]
|
|
|
|
#[non_exhaustive]
|
|
|
|
EarlyTransparentSpend { outpoint: transparent::OutPoint },
|
|
|
|
|
2021-07-14 05:06:43 -07:00
|
|
|
#[error("sprout double-spend: duplicate nullifier: {nullifier:?}, in finalized state: {in_finalized_state:?}")]
|
|
|
|
#[non_exhaustive]
|
|
|
|
DuplicateSproutNullifier {
|
|
|
|
nullifier: sprout::Nullifier,
|
|
|
|
in_finalized_state: bool,
|
|
|
|
},
|
Reject duplicate Sapling and Orchard nullifiers (#2497)
* Add sapling and orchard duplicate nullifier errors
* Reject duplicate finalized sapling and orchard nullifiers
Reject duplicate sapling and orchard nullifiers in a new block,
when the block is added to a non-finalized chain,
and the duplicate nullifier is already in the finalized state.
* Reject duplicate non-finalized sapling and orchard nullifiers
Reject duplicate sapling and orchard nullifiers in a new block,
when the block is added to a non-finalized chain,
and the duplicate nullifier is in:
* the same shielded data,
* the same transaction,
* the same block, or
* an earlier block in the non-finalized chain.
* Refactor sprout nullifier tests to remove common code
* Add sapling nullifier tests
Test that the state rejects duplicate sapling nullifiers in a new block,
when the block is added to a non-finalized chain,
and the duplicate nullifier is in:
* the same shielded data,
* the same transaction,
* the same block,
* an earlier block in the non-finalized chain, or
* the finalized state.
* Add orchard nullifier tests
Test that the state rejects duplicate orchard nullifiers in a new block,
when the block is added to a non-finalized chain,
and the duplicate nullifier is in:
* the same shielded data,
* the same transaction,
* the same block,
* an earlier block in the non-finalized chain, or
* the finalized state.
* Check for specific nullifiers in the state in tests
* Replace slices with vectors in arguments
* Remove redundant code and variables
* Simplify sapling TransferData tests
Co-authored-by: Janito Vaqueiro Ferreira Filho <janito.vff@gmail.com>
* Remove an extra :
* Remove redundant vec!
Co-authored-by: Janito Vaqueiro Ferreira Filho <janito.vff@gmail.com>
2021-07-19 17:39:05 -07:00
|
|
|
|
|
|
|
#[error("sapling double-spend: duplicate nullifier: {nullifier:?}, in finalized state: {in_finalized_state:?}")]
|
|
|
|
#[non_exhaustive]
|
|
|
|
DuplicateSaplingNullifier {
|
|
|
|
nullifier: sapling::Nullifier,
|
|
|
|
in_finalized_state: bool,
|
|
|
|
},
|
|
|
|
|
|
|
|
#[error("orchard double-spend: duplicate nullifier: {nullifier:?}, in finalized state: {in_finalized_state:?}")]
|
|
|
|
#[non_exhaustive]
|
|
|
|
DuplicateOrchardNullifier {
|
|
|
|
nullifier: orchard::Nullifier,
|
|
|
|
in_finalized_state: bool,
|
|
|
|
},
|
2021-07-14 05:06:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Trait for creating the corresponding duplicate nullifier error from a nullifier.
|
|
|
|
pub(crate) trait DuplicateNullifierError {
|
|
|
|
/// Returns the corresponding duplicate nullifier error for `self`.
|
|
|
|
fn duplicate_nullifier_error(&self, in_finalized_state: bool) -> ValidateContextError;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl DuplicateNullifierError for sprout::Nullifier {
|
|
|
|
fn duplicate_nullifier_error(&self, in_finalized_state: bool) -> ValidateContextError {
|
|
|
|
ValidateContextError::DuplicateSproutNullifier {
|
|
|
|
nullifier: *self,
|
|
|
|
in_finalized_state,
|
|
|
|
}
|
|
|
|
}
|
2020-10-09 01:37:24 -07:00
|
|
|
}
|
Reject duplicate Sapling and Orchard nullifiers (#2497)
* Add sapling and orchard duplicate nullifier errors
* Reject duplicate finalized sapling and orchard nullifiers
Reject duplicate sapling and orchard nullifiers in a new block,
when the block is added to a non-finalized chain,
and the duplicate nullifier is already in the finalized state.
* Reject duplicate non-finalized sapling and orchard nullifiers
Reject duplicate sapling and orchard nullifiers in a new block,
when the block is added to a non-finalized chain,
and the duplicate nullifier is in:
* the same shielded data,
* the same transaction,
* the same block, or
* an earlier block in the non-finalized chain.
* Refactor sprout nullifier tests to remove common code
* Add sapling nullifier tests
Test that the state rejects duplicate sapling nullifiers in a new block,
when the block is added to a non-finalized chain,
and the duplicate nullifier is in:
* the same shielded data,
* the same transaction,
* the same block,
* an earlier block in the non-finalized chain, or
* the finalized state.
* Add orchard nullifier tests
Test that the state rejects duplicate orchard nullifiers in a new block,
when the block is added to a non-finalized chain,
and the duplicate nullifier is in:
* the same shielded data,
* the same transaction,
* the same block,
* an earlier block in the non-finalized chain, or
* the finalized state.
* Check for specific nullifiers in the state in tests
* Replace slices with vectors in arguments
* Remove redundant code and variables
* Simplify sapling TransferData tests
Co-authored-by: Janito Vaqueiro Ferreira Filho <janito.vff@gmail.com>
* Remove an extra :
* Remove redundant vec!
Co-authored-by: Janito Vaqueiro Ferreira Filho <janito.vff@gmail.com>
2021-07-19 17:39:05 -07:00
|
|
|
|
|
|
|
impl DuplicateNullifierError for sapling::Nullifier {
|
|
|
|
fn duplicate_nullifier_error(&self, in_finalized_state: bool) -> ValidateContextError {
|
|
|
|
ValidateContextError::DuplicateSaplingNullifier {
|
|
|
|
nullifier: *self,
|
|
|
|
in_finalized_state,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl DuplicateNullifierError for orchard::Nullifier {
|
|
|
|
fn duplicate_nullifier_error(&self, in_finalized_state: bool) -> ValidateContextError {
|
|
|
|
ValidateContextError::DuplicateOrchardNullifier {
|
|
|
|
nullifier: *self,
|
|
|
|
in_finalized_state,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|