use std::io;
use chrono::DateTime;
use chrono::Utc;
use unc_primitives::block::BlockValidityError;
use unc_primitives::challenge::{ChunkProofs, ChunkState};
use unc_primitives::errors::{BlockError, EpochError, StorageError};
use unc_primitives::hash::CryptoHash;
use unc_primitives::shard_layout::ShardLayoutError;
use unc_primitives::sharding::{ChunkHash, ShardChunkHeader};
use unc_primitives::types::{BlockHeight, EpochId, ShardId};
#[derive(thiserror::Error, Debug)]
pub enum QueryError {
#[error("Account ID {requested_account_id} is invalid")]
InvalidAccount {
requested_account_id: unc_primitives::types::AccountId,
block_height: unc_primitives::types::BlockHeight,
block_hash: unc_primitives::hash::CryptoHash,
},
#[error("Account {requested_account_id} does not exist while viewing")]
UnknownAccount {
requested_account_id: unc_primitives::types::AccountId,
block_height: unc_primitives::types::BlockHeight,
block_hash: unc_primitives::hash::CryptoHash,
},
#[error(
"Contract code for contract ID {contract_account_id} has never been observed on the node"
)]
NoContractCode {
contract_account_id: unc_primitives::types::AccountId,
block_height: unc_primitives::types::BlockHeight,
block_hash: unc_primitives::hash::CryptoHash,
},
#[error("Access key for public key {public_key} does not exist while viewing")]
UnknownAccessKey {
public_key: unc_crypto::PublicKey,
block_height: unc_primitives::types::BlockHeight,
block_hash: unc_primitives::hash::CryptoHash,
},
#[error("Internal error occurred: {error_message}")]
InternalError {
error_message: String,
block_height: unc_primitives::types::BlockHeight,
block_hash: unc_primitives::hash::CryptoHash,
},
#[error("Function call returned an error: {error_message}")]
ContractExecutionError {
error_message: String,
block_height: unc_primitives::types::BlockHeight,
block_hash: unc_primitives::hash::CryptoHash,
},
#[error("The state of account {requested_account_id} is too large")]
TooLargeContractState {
requested_account_id: unc_primitives::types::AccountId,
block_height: unc_primitives::types::BlockHeight,
block_hash: unc_primitives::hash::CryptoHash,
},
}
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("Block is known: {0}")]
BlockKnown(#[from] BlockKnownError),
#[error("Too many blocks being processed")]
TooManyProcessingBlocks,
#[error("Orphan")]
Orphan,
#[error("Chunk Missing (unavailable on the node): {0:?}")]
ChunkMissing(ChunkHash),
#[error("Chunks Missing: {0:?}")]
ChunksMissing(Vec<ShardChunkHeader>),
#[error("Invalid Block Time: block time {1} before previous {0}")]
InvalidBlockPastTime(DateTime<Utc>, DateTime<Utc>),
#[error("Invalid Block Time: Too far in the future: {0}")]
InvalidBlockFutureTime(DateTime<Utc>),
#[error("Invalid Block Height {0}")]
InvalidBlockHeight(BlockHeight),
#[error("Invalid Block Proposer Signature")]
InvalidBlockProposer,
#[error("Invalid State Root Hash")]
InvalidStateRoot,
#[error("Invalid Block Tx Root Hash")]
InvalidTxRoot,
#[error("Invalid Chunk Receipts Root Hash")]
InvalidChunkReceiptsRoot,
#[error("Invalid Chunk Headers Root Hash")]
InvalidChunkHeadersRoot,
#[error("Invalid Chunk Tx Root Hash")]
InvalidChunkTxRoot,
#[error("Invalid Receipts Proof")]
InvalidReceiptsProof,
#[error("Invalid Outcomes Proof")]
InvalidOutcomesProof,
#[error("Invalid State Payload")]
InvalidStatePayload,
#[error("Invalid Transactions")]
InvalidTransactions,
#[error("Invalid Challenge Root")]
InvalidChallengeRoot,
#[error("Invalid Challenge")]
InvalidChallenge,
#[error("Malicious Challenge")]
MaliciousChallenge,
#[error("Incorrect Number of Chunk Headers")]
IncorrectNumberOfChunkHeaders,
#[error("Invalid Chunk")]
InvalidChunk,
#[error("Invalid Chunk Proofs")]
InvalidChunkProofs(Box<ChunkProofs>),
#[error("Invalid Chunk State")]
InvalidChunkState(Box<ChunkState>),
#[error("Invalid Chunk State Witness")]
InvalidChunkStateWitness(String),
#[error("Invalid Chunk Mask")]
InvalidChunkMask,
#[error("Invalid Chunk Height")]
InvalidChunkHeight,
#[error("Invalid Epoch Hash")]
InvalidEpochHash,
#[error("Invalid Next BP Hash")]
InvalidNextBPHash,
#[error("Invalid protocol version")]
InvalidProtocolVersion,
#[error("Not enough approvals")]
NotEnoughApprovals,
#[error("Invalid finality info")]
InvalidFinalityInfo,
#[error("Invalid Validator Proposals")]
InvalidValidatorProposals,
#[error("Invalid Signature")]
InvalidSignature,
#[error("Invalid Approvals")]
InvalidApprovals,
#[error("Invalid Gas Limit")]
InvalidGasLimit,
#[error("Invalid Gas Price")]
InvalidGasPrice,
#[error("Invalid Gas Used")]
InvalidGasUsed,
#[error("Invalid Balance Burnt")]
InvalidBalanceBurnt,
#[error("Shard id {0} does not exist")]
InvalidShardId(ShardId),
#[error("Invalid state request: {0}")]
InvalidStateRequest(String),
#[error("Invalid Randomness Beacon Output")]
InvalidRandomnessBeaconOutput,
#[error("Invalid Block Merkle Root")]
InvalidBlockMerkleRoot,
#[error("Invalid Split Shard Ids when resharding. shard_id: {0}, parent_shard_id: {1}")]
InvalidSplitShardsIds(u64, u64),
#[error("Not A Validator")]
NotAValidator,
#[error("Not A Chunk Validator")]
NotAChunkValidator,
#[error("Validator Error: {0}")]
ValidatorError(String),
#[error("Epoch Out Of Bounds: {:?}", _0)]
BlockOutOfBounds(CryptoHash),
#[error("Epoch Out Of Bounds: {:?}", _0)]
EpochOutOfBounds(EpochId),
#[error("Challenged block on chain")]
ChallengedBlockOnChain,
#[error("Block cannot be finalized")]
CannotBeFinalized,
#[error("IO Error: {0}")]
IOErr(#[from] io::Error),
#[error("DB Not Found Error: {0}")]
DBNotFoundErr(String),
#[error("Storage Error: {0}")]
StorageError(#[from] StorageError),
#[error("GC Error: {0}")]
GCError(String),
#[error("Other Error: {0}")]
Other(String),
}
pub trait LogTransientStorageError {
fn log_storage_error(self, message: &str) -> Self;
}
impl<T> LogTransientStorageError for Result<T, Error> {
fn log_storage_error(self, message: &str) -> Self {
if let Err(err) = &self {
tracing::error!(target: "client", "Transient storage error: {message}, {err}");
}
self
}
}
impl Error {
pub fn is_bad_data(&self) -> bool {
match self {
Error::BlockKnown(_)
| Error::TooManyProcessingBlocks
| Error::Orphan
| Error::ChunkMissing(_)
| Error::ChunksMissing(_)
| Error::InvalidChunkHeight
| Error::IOErr(_)
| Error::Other(_)
| Error::ValidatorError(_)
| Error::EpochOutOfBounds(_)
| Error::ChallengedBlockOnChain
| Error::CannotBeFinalized
| Error::StorageError(_)
| Error::GCError(_)
| Error::DBNotFoundErr(_) => false,
Error::InvalidBlockPastTime(_, _)
| Error::InvalidBlockFutureTime(_)
| Error::InvalidBlockHeight(_)
| Error::InvalidBlockProposer
| Error::InvalidChunk
| Error::InvalidChunkProofs(_)
| Error::InvalidChunkState(_)
| Error::InvalidChunkStateWitness(_)
| Error::InvalidChunkMask
| Error::InvalidStateRoot
| Error::InvalidTxRoot
| Error::InvalidChunkReceiptsRoot
| Error::InvalidOutcomesProof
| Error::InvalidChunkHeadersRoot
| Error::InvalidChunkTxRoot
| Error::InvalidReceiptsProof
| Error::InvalidStatePayload
| Error::InvalidTransactions
| Error::InvalidChallenge
| Error::InvalidSplitShardsIds(_, _)
| Error::MaliciousChallenge
| Error::IncorrectNumberOfChunkHeaders
| Error::InvalidEpochHash
| Error::InvalidNextBPHash
| Error::NotEnoughApprovals
| Error::InvalidFinalityInfo
| Error::InvalidValidatorProposals
| Error::InvalidSignature
| Error::InvalidApprovals
| Error::InvalidGasLimit
| Error::InvalidGasPrice
| Error::InvalidGasUsed
| Error::InvalidBalanceBurnt
| Error::InvalidShardId(_)
| Error::InvalidStateRequest(_)
| Error::InvalidRandomnessBeaconOutput
| Error::InvalidBlockMerkleRoot
| Error::InvalidProtocolVersion
| Error::NotAValidator
| Error::NotAChunkValidator
| Error::BlockOutOfBounds(_)
| Error::InvalidChallengeRoot => true,
}
}
pub fn is_error(&self) -> bool {
match self {
Error::IOErr(_) | Error::Other(_) | Error::DBNotFoundErr(_) => true,
_ => false,
}
}
pub fn prometheus_label_value(&self) -> &'static str {
match self {
Error::BlockKnown(_) => "block_known",
Error::TooManyProcessingBlocks => "too_many_processing_blocks",
Error::Orphan => "orphan",
Error::ChunkMissing(_) => "chunk_missing",
Error::ChunksMissing(_) => "chunks_missing",
Error::InvalidChunkHeight => "invalid_chunk_height",
Error::IOErr(_) => "io_err",
Error::Other(_) => "other",
Error::ValidatorError(_) => "validator_error",
Error::EpochOutOfBounds(_) => "epoch_out_of_bounds",
Error::ChallengedBlockOnChain => "challenged_block_on_chain",
Error::CannotBeFinalized => "cannot_be_finalized",
Error::StorageError(_) => "storage_error",
Error::GCError(_) => "gc_error",
Error::DBNotFoundErr(_) => "db_not_found_err",
Error::InvalidBlockPastTime(_, _) => "invalid_block_past_time",
Error::InvalidBlockFutureTime(_) => "invalid_block_future_time",
Error::InvalidBlockHeight(_) => "invalid_block_height",
Error::InvalidBlockProposer => "invalid_block_proposer",
Error::InvalidChunk => "invalid_chunk",
Error::InvalidChunkProofs(_) => "invalid_chunk_proofs",
Error::InvalidChunkState(_) => "invalid_chunk_state",
Error::InvalidChunkStateWitness(_) => "invalid_chunk_state_witness",
Error::InvalidChunkMask => "invalid_chunk_mask",
Error::InvalidStateRoot => "invalid_state_root",
Error::InvalidTxRoot => "invalid_tx_root",
Error::InvalidChunkReceiptsRoot => "invalid_chunk_receipts_root",
Error::InvalidOutcomesProof => "invalid_outcomes_proof",
Error::InvalidChunkHeadersRoot => "invalid_chunk_headers_root",
Error::InvalidChunkTxRoot => "invalid_chunk_tx_root",
Error::InvalidReceiptsProof => "invalid_receipts_proof",
Error::InvalidStatePayload => "invalid_state_payload",
Error::InvalidTransactions => "invalid_transactions",
Error::InvalidChallenge => "invalid_challenge",
Error::InvalidSplitShardsIds(_, _) => "invalid_split_shard_ids",
Error::MaliciousChallenge => "malicious_challenge",
Error::IncorrectNumberOfChunkHeaders => "incorrect_number_of_chunk_headers",
Error::InvalidEpochHash => "invalid_epoch_hash",
Error::InvalidNextBPHash => "invalid_next_bp_hash",
Error::NotEnoughApprovals => "not_enough_approvals",
Error::InvalidFinalityInfo => "invalid_finality_info",
Error::InvalidValidatorProposals => "invalid_validator_proposals",
Error::InvalidSignature => "invalid_signature",
Error::InvalidApprovals => "invalid_approvals",
Error::InvalidGasLimit => "invalid_gas_limit",
Error::InvalidGasPrice => "invalid_gas_price",
Error::InvalidGasUsed => "invalid_gas_used",
Error::InvalidBalanceBurnt => "invalid_balance_burnt",
Error::InvalidShardId(_) => "invalid_shard_id",
Error::InvalidStateRequest(_) => "invalid_state_request",
Error::InvalidRandomnessBeaconOutput => "invalid_randomness_beacon_output",
Error::InvalidBlockMerkleRoot => "invalid_block_merkele_root",
Error::InvalidProtocolVersion => "invalid_protocol_version",
Error::NotAValidator => "not_a_validator",
Error::NotAChunkValidator => "not_a_chunk_validator",
Error::InvalidChallengeRoot => "invalid_challenge_root",
Error::BlockOutOfBounds(_)=> "block_out_of_bounds"
}
}
}
impl From<EpochError> for Error {
fn from(error: EpochError) -> Self {
match error {
EpochError::EpochOutOfBounds(epoch_id) => Error::EpochOutOfBounds(epoch_id),
EpochError::MissingBlock(h) => Error::DBNotFoundErr(format!("epoch block: {h}")),
EpochError::NotAValidator(_account_id, _epoch_id) => Error::NotAValidator,
err => Error::Other(err.to_string()),
}
}
}
impl From<BlockError> for Error {
fn from(error: BlockError) -> Self {
match error {
err => Error::ValidatorError(err.to_string()),
}
}
}
pub trait EpochErrorResultToChainError<T> {
fn into_chain_error(self) -> Result<T, Error>;
}
impl<T> EpochErrorResultToChainError<T> for Result<T, EpochError> {
fn into_chain_error(self: Result<T, EpochError>) -> Result<T, Error> {
self.map_err(|err| err.into())
}
}
impl From<ShardLayoutError> for Error {
fn from(error: ShardLayoutError) -> Self {
match error {
ShardLayoutError::InvalidShardIdError { shard_id } => Error::InvalidShardId(shard_id),
}
}
}
impl From<BlockValidityError> for Error {
fn from(error: BlockValidityError) -> Self {
match error {
BlockValidityError::InvalidStateRoot => Error::InvalidStateRoot,
BlockValidityError::InvalidReceiptRoot => Error::InvalidChunkReceiptsRoot,
BlockValidityError::InvalidTransactionRoot => Error::InvalidTxRoot,
BlockValidityError::InvalidChunkHeaderRoot => Error::InvalidChunkHeadersRoot,
BlockValidityError::InvalidChunkMask => Error::InvalidChunkMask,
BlockValidityError::InvalidChallengeRoot => Error::InvalidChallengeRoot,
}
}
}
#[derive(Clone, Eq, PartialEq, Debug, thiserror::Error)]
pub enum BlockKnownError {
#[error("already known in header")]
KnownInHeader,
#[error("already known in head")]
KnownInHead,
#[error("already known in orphan")]
KnownInOrphan,
#[error("already known in missing chunks")]
KnownInMissingChunks,
#[error("already known in store")]
KnownInStore,
#[error("already known in blocks in processing")]
KnownInProcessing,
#[error("already known in invalid blocks")]
KnownAsInvalid,
}
#[cfg(feature = "new_epoch_sync")]
pub mod epoch_sync {
#[derive(thiserror::Error, std::fmt::Debug)]
pub enum EpochSyncInfoError {
#[error(transparent)]
EpochSyncInfoErr(#[from] unc_primitives::errors::epoch_sync::EpochSyncInfoError),
#[error(transparent)]
IOErr(#[from] std::io::Error),
#[error(transparent)]
ChainErr(#[from] crate::Error),
}
}