2020-10-16 16:44:30 -07:00
|
|
|
//! Errors that can occur when checking consensus rules.
|
|
|
|
//!
|
|
|
|
//! Each error variant corresponds to a consensus rule, so enumerating
|
|
|
|
//! all possible verification failures enumerates the consensus rules we
|
|
|
|
//! implement, and ensures that we don't reject blocks or transactions
|
|
|
|
//! for a non-enumerated reason.
|
2020-09-21 11:54:06 -07:00
|
|
|
|
|
|
|
use thiserror::Error;
|
|
|
|
|
2020-10-26 23:42:27 -07:00
|
|
|
use zebra_chain::primitives::ed25519;
|
|
|
|
|
|
|
|
use crate::BoxError;
|
|
|
|
|
2020-10-12 13:54:48 -07:00
|
|
|
#[derive(Error, Debug, PartialEq)]
|
|
|
|
pub enum SubsidyError {
|
|
|
|
#[error("no coinbase transaction in block")]
|
|
|
|
NoCoinbase,
|
|
|
|
|
|
|
|
#[error("founders reward output not found")]
|
|
|
|
FoundersRewardNotFound,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Error, Debug, PartialEq)]
|
2020-09-21 11:54:06 -07:00
|
|
|
pub enum TransactionError {
|
|
|
|
#[error("first transaction must be coinbase")]
|
|
|
|
CoinbasePosition,
|
|
|
|
|
|
|
|
#[error("coinbase input found in non-coinbase transaction")]
|
|
|
|
CoinbaseInputFound,
|
2020-10-12 13:54:48 -07:00
|
|
|
|
2020-11-19 19:06:10 -08:00
|
|
|
#[error("coinbase transaction MUST NOT have any JoinSplit descriptions")]
|
|
|
|
CoinbaseHasJoinSplit,
|
|
|
|
|
|
|
|
#[error("coinbase transaction MUST NOT have any Spend descriptions")]
|
|
|
|
CoinbaseHasSpend,
|
|
|
|
|
|
|
|
#[error("coinbase transaction MUST NOT have any Output descriptions pre-Heartwood")]
|
|
|
|
CoinbaseHasOutputPreHeartwood,
|
2020-10-26 23:42:27 -07:00
|
|
|
|
2020-10-12 13:54:48 -07:00
|
|
|
#[error("coinbase transaction failed subsidy validation")]
|
|
|
|
Subsidy(#[from] SubsidyError),
|
2020-10-26 23:42:27 -07:00
|
|
|
|
|
|
|
#[error("transaction version number MUST be >= 4")]
|
|
|
|
WrongVersion,
|
|
|
|
|
|
|
|
#[error("at least one of tx_in_count, nShieldedSpend, and nJoinSplit MUST be nonzero")]
|
|
|
|
NoTransfer,
|
|
|
|
|
|
|
|
#[error("if there are no Spends or Outputs, the value balance MUST be 0.")]
|
|
|
|
BadBalance,
|
|
|
|
|
2020-10-28 17:22:25 -07:00
|
|
|
#[error("could not verify a transparent script")]
|
2020-10-26 23:42:27 -07:00
|
|
|
Script(#[from] zebra_script::Error),
|
|
|
|
|
|
|
|
// XXX change this when we align groth16 verifier errors with bellman
|
|
|
|
// and add a from annotation when the error type is more precise
|
|
|
|
#[error("spend proof MUST be valid given a primary input formed from the other fields except spendAuthSig")]
|
2020-10-28 17:22:25 -07:00
|
|
|
Groth16,
|
2020-10-26 23:42:27 -07:00
|
|
|
|
|
|
|
#[error(
|
|
|
|
"joinSplitSig MUST represent a valid signature under joinSplitPubKey of dataToBeSigned"
|
|
|
|
)]
|
|
|
|
Ed25519(#[from] ed25519::Error),
|
|
|
|
|
|
|
|
#[error("bindingSig MUST represent a valid signature under the transaction binding validating key bvk of SigHash")]
|
|
|
|
RedJubjub(redjubjub::Error),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<BoxError> for TransactionError {
|
|
|
|
fn from(err: BoxError) -> Self {
|
|
|
|
match err.downcast::<redjubjub::Error>() {
|
|
|
|
Ok(e) => TransactionError::RedJubjub(*e),
|
2020-10-28 17:22:25 -07:00
|
|
|
Err(e) => panic!(e),
|
2020-10-26 23:42:27 -07:00
|
|
|
}
|
|
|
|
}
|
2020-10-12 13:54:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
impl From<SubsidyError> for BlockError {
|
|
|
|
fn from(err: SubsidyError) -> BlockError {
|
|
|
|
BlockError::Transaction(TransactionError::Subsidy(err))
|
|
|
|
}
|
2020-09-21 11:54:06 -07:00
|
|
|
}
|
|
|
|
|
2020-10-12 13:54:48 -07:00
|
|
|
#[derive(Error, Debug, PartialEq)]
|
2020-09-21 11:54:06 -07:00
|
|
|
pub enum BlockError {
|
|
|
|
#[error("block contains invalid transactions")]
|
|
|
|
Transaction(#[from] TransactionError),
|
|
|
|
|
2020-11-06 11:07:30 -08:00
|
|
|
#[error("block has no transactions")]
|
2020-09-21 11:54:06 -07:00
|
|
|
NoTransactions,
|
|
|
|
|
|
|
|
#[error("block {0:?} is already in the chain at depth {1:?}")]
|
|
|
|
AlreadyInChain(zebra_chain::block::Hash, u32),
|
|
|
|
|
|
|
|
#[error("invalid block {0:?}: missing block height")]
|
|
|
|
MissingHeight(zebra_chain::block::Hash),
|
|
|
|
|
|
|
|
#[error("invalid block height {0:?} in {1:?}: greater than the maximum height {2:?}")]
|
|
|
|
MaxHeight(
|
|
|
|
zebra_chain::block::Height,
|
|
|
|
zebra_chain::block::Hash,
|
|
|
|
zebra_chain::block::Height,
|
|
|
|
),
|
|
|
|
|
|
|
|
#[error("invalid difficulty threshold in block header {0:?} {1:?}")]
|
|
|
|
InvalidDifficulty(zebra_chain::block::Height, zebra_chain::block::Hash),
|
|
|
|
|
2020-10-13 18:35:45 -07:00
|
|
|
#[error("block {0:?} has a difficulty threshold {2:?} that is easier than the {3:?} difficulty limit {4:?}, hash: {1:?}")]
|
2020-10-12 15:17:40 -07:00
|
|
|
TargetDifficultyLimit(
|
|
|
|
zebra_chain::block::Height,
|
|
|
|
zebra_chain::block::Hash,
|
|
|
|
zebra_chain::work::difficulty::ExpandedDifficulty,
|
|
|
|
zebra_chain::parameters::Network,
|
|
|
|
zebra_chain::work::difficulty::ExpandedDifficulty,
|
|
|
|
),
|
|
|
|
|
2020-11-04 18:57:31 -08:00
|
|
|
#[error(
|
|
|
|
"block {0:?} on {3:?} has a hash {1:?} that is easier than its difficulty threshold {2:?}"
|
|
|
|
)]
|
2020-09-21 11:54:06 -07:00
|
|
|
DifficultyFilter(
|
|
|
|
zebra_chain::block::Height,
|
|
|
|
zebra_chain::block::Hash,
|
|
|
|
zebra_chain::work::difficulty::ExpandedDifficulty,
|
2020-11-04 18:57:31 -08:00
|
|
|
zebra_chain::parameters::Network,
|
2020-09-21 11:54:06 -07:00
|
|
|
),
|
|
|
|
}
|