use datasize::DataSize;
use serde::Serialize;
use thiserror::Error;
use casper_binary_port::ErrorCode as BinaryPortErrorCode;
use casper_types::{
AddressableEntityHash, BlockHash, BlockHeader, Digest, EntityVersionKey, InitiatorAddr,
InvalidTransaction, PackageHash, Timestamp,
};
#[allow(clippy::large_enum_variant)]
#[derive(Debug, Error, Serialize)]
pub(crate) enum Error {
#[error("block chain has no blocks")]
EmptyBlockchain,
#[error("invalid transaction: {0}")]
InvalidTransaction(#[from] InvalidTransaction),
#[error(
"{failure} at state root hash {:?} of block {:?} at height {block_height}",
state_root_hash,
block_hash.inner(),
)]
Parameters {
state_root_hash: Digest,
block_hash: BlockHash,
block_height: u64,
failure: ParameterFailure,
},
#[error(
"transaction received by the node expired at {expiry_timestamp} with node's time at \
{current_node_timestamp}"
)]
Expired {
expiry_timestamp: Timestamp,
current_node_timestamp: Timestamp,
},
#[error("internal error: expected a deploy")]
ExpectedDeploy,
#[error("internal error: expected a transaction")]
ExpectedTransactionV1,
}
impl Error {
pub(super) fn parameter_failure(block_header: &BlockHeader, failure: ParameterFailure) -> Self {
Error::Parameters {
state_root_hash: *block_header.state_root_hash(),
block_hash: block_header.block_hash(),
block_height: block_header.height(),
failure,
}
}
}
impl From<Error> for BinaryPortErrorCode {
fn from(err: Error) -> Self {
match err {
Error::EmptyBlockchain => BinaryPortErrorCode::EmptyBlockchain,
Error::ExpectedDeploy => BinaryPortErrorCode::ExpectedDeploy,
Error::ExpectedTransactionV1 => BinaryPortErrorCode::ExpectedTransaction,
Error::Expired { .. } => BinaryPortErrorCode::TransactionExpired,
Error::Parameters { failure, .. } => match failure {
ParameterFailure::NoSuchAddressableEntity { .. } => {
BinaryPortErrorCode::NoSuchAddressableEntity
}
ParameterFailure::NoSuchContractAtHash { .. } => {
BinaryPortErrorCode::NoSuchContractAtHash
}
ParameterFailure::NoSuchEntryPoint { .. } => BinaryPortErrorCode::NoSuchEntryPoint,
ParameterFailure::NoSuchPackageAtHash { .. } => {
BinaryPortErrorCode::NoSuchPackageAtHash
}
ParameterFailure::InvalidEntityAtVersion { .. } => {
BinaryPortErrorCode::InvalidEntityAtVersion
}
ParameterFailure::DisabledEntityAtVersion { .. } => {
BinaryPortErrorCode::DisabledEntityAtVersion
}
ParameterFailure::MissingEntityAtVersion { .. } => {
BinaryPortErrorCode::MissingEntityAtVersion
}
ParameterFailure::InvalidAssociatedKeys => {
BinaryPortErrorCode::InvalidAssociatedKeys
}
ParameterFailure::InsufficientSignatureWeight => {
BinaryPortErrorCode::InsufficientSignatureWeight
}
ParameterFailure::InsufficientBalance { .. } => {
BinaryPortErrorCode::InsufficientBalance
}
ParameterFailure::UnknownBalance { .. } => BinaryPortErrorCode::UnknownBalance,
ParameterFailure::Deploy(deploy_failure) => match deploy_failure {
DeployParameterFailure::InvalidPaymentVariant => {
BinaryPortErrorCode::DeployInvalidPaymentVariant
}
DeployParameterFailure::MissingPaymentAmount => {
BinaryPortErrorCode::DeployMissingPaymentAmount
}
DeployParameterFailure::FailedToParsePaymentAmount => {
BinaryPortErrorCode::DeployFailedToParsePaymentAmount
}
DeployParameterFailure::MissingTransferTarget => {
BinaryPortErrorCode::DeployMissingTransferTarget
}
DeployParameterFailure::MissingModuleBytes => {
BinaryPortErrorCode::DeployMissingModuleBytes
}
},
},
Error::InvalidTransaction(invalid_transaction) => {
BinaryPortErrorCode::from(invalid_transaction)
}
}
}
}
#[derive(Clone, DataSize, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Error, Serialize)]
pub(crate) enum ParameterFailure {
#[error("addressable entity under {initiator_addr} does not exist")]
NoSuchAddressableEntity { initiator_addr: InitiatorAddr },
#[error("contract at {contract_hash} does not exist")]
NoSuchContractAtHash {
contract_hash: AddressableEntityHash,
},
#[error("contract does not have entry point '{entry_point_name}'")]
NoSuchEntryPoint { entry_point_name: String },
#[error("package at {package_hash} does not exist")]
NoSuchPackageAtHash { package_hash: PackageHash },
#[error("invalid entity at version key: {entity_version_key}")]
InvalidEntityAtVersion {
entity_version_key: EntityVersionKey,
},
#[error("disabled entity at version key: {entity_version_key}")]
DisabledEntityAtVersion {
entity_version_key: EntityVersionKey,
},
#[error("missing entity at version key: {entity_version_key}")]
MissingEntityAtVersion {
entity_version_key: EntityVersionKey,
},
#[error("account authorization invalid")]
InvalidAssociatedKeys,
#[error("insufficient transaction signature weight")]
InsufficientSignatureWeight,
#[error("insufficient balance in {initiator_addr}")]
InsufficientBalance { initiator_addr: InitiatorAddr },
#[error("unable to determine balance for {initiator_addr}")]
UnknownBalance { initiator_addr: InitiatorAddr },
#[error(transparent)]
Deploy(#[from] DeployParameterFailure),
}
#[derive(Clone, DataSize, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Error, Serialize)]
pub(crate) enum DeployParameterFailure {
#[error("transfer is not valid for payment code")]
InvalidPaymentVariant,
#[error("missing payment 'amount' runtime argument")]
MissingPaymentAmount,
#[error("failed to parse payment 'amount' runtime argument as U512")]
FailedToParsePaymentAmount,
#[error("missing transfer 'target' runtime argument")]
MissingTransferTarget,
#[error("module bytes for session code cannot be empty")]
MissingModuleBytes,
}