use crate::hash::CryptoHash;
use crate::serialize::dec_format;
use crate::types::{AccountId, Balance, EpochId, Gas, Nonce};
use borsh::{BorshDeserialize, BorshSerialize};
use unc_crypto::PublicKey;
use unc_primitives_core::types::{BlockHeight, ProtocolVersion};
use unc_rpc_error_macro::RpcError;
use std::fmt::{Debug, Display};
#[derive(
BorshSerialize,
BorshDeserialize,
Debug,
Clone,
PartialEq,
Eq,
RpcError,
serde::Deserialize,
serde::Serialize,
)]
pub enum TxExecutionError {
ActionError(ActionError),
InvalidTxError(InvalidTxError),
}
impl std::error::Error for TxExecutionError {}
impl Display for TxExecutionError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
match self {
TxExecutionError::ActionError(e) => write!(f, "{}", e),
TxExecutionError::InvalidTxError(e) => write!(f, "{}", e),
}
}
}
impl From<ActionError> for TxExecutionError {
fn from(error: ActionError) -> Self {
TxExecutionError::ActionError(error)
}
}
impl From<InvalidTxError> for TxExecutionError {
fn from(error: InvalidTxError) -> Self {
TxExecutionError::InvalidTxError(error)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RuntimeError {
UnexpectedIntegerOverflow,
InvalidTxError(InvalidTxError),
StorageError(StorageError),
BalanceMismatchError(Box<BalanceMismatchError>),
ReceiptValidationError(ReceiptValidationError),
ValidatorError(EpochError),
}
impl std::fmt::Display for RuntimeError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
f.write_str(&format!("{:?}", self))
}
}
impl std::error::Error for RuntimeError {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum MissingTrieValueContext {
TrieIterator,
TriePrefetchingStorage,
TrieMemoryPartialStorage,
TrieStorage,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum StorageError {
StorageInternalError,
MissingTrieValue(MissingTrieValueContext, CryptoHash),
UnexpectedTrieValue,
StorageInconsistentState(String),
FlatStorageBlockNotSupported(String),
MemTrieLoadingError(String),
}
impl std::fmt::Display for StorageError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
f.write_str(&format!("{:?}", self))
}
}
impl std::error::Error for StorageError {}
#[derive(
BorshSerialize,
BorshDeserialize,
Debug,
Clone,
PartialEq,
Eq,
RpcError,
serde::Deserialize,
serde::Serialize,
)]
pub enum InvalidTxError {
InvalidAccessKeyError(InvalidAccessKeyError),
InvalidSignerId { signer_id: String },
SignerDoesNotExist { signer_id: AccountId },
InvalidNonce { tx_nonce: Nonce, ak_nonce: Nonce },
NonceTooLarge { tx_nonce: Nonce, upper_bound: Nonce },
InvalidReceiverId { receiver_id: String },
InvalidSignature,
NotEnoughBalance {
signer_id: AccountId,
#[serde(with = "dec_format")]
balance: Balance,
#[serde(with = "dec_format")]
cost: Balance,
},
LackBalanceForState {
signer_id: AccountId,
#[serde(with = "dec_format")]
amount: Balance,
},
CostOverflow,
InvalidChain,
Expired,
ActionsValidation(ActionsValidationError),
TransactionSizeExceeded { size: u64, limit: u64 },
}
impl std::error::Error for InvalidTxError {}
#[derive(
BorshSerialize,
BorshDeserialize,
Debug,
Clone,
PartialEq,
Eq,
RpcError,
serde::Deserialize,
serde::Serialize,
)]
pub enum InvalidAccessKeyError {
AccessKeyNotFound { account_id: AccountId, public_key: Box<PublicKey> },
ReceiverMismatch { tx_receiver: AccountId, ak_receiver: String },
MethodNameMismatch { method_name: String },
RequiresFullAccess,
NotEnoughAllowance {
account_id: AccountId,
public_key: Box<PublicKey>,
#[serde(with = "dec_format")]
allowance: Balance,
#[serde(with = "dec_format")]
cost: Balance,
},
DepositWithFunctionCall,
}
#[derive(
BorshSerialize,
BorshDeserialize,
Debug,
Clone,
PartialEq,
Eq,
RpcError,
serde::Serialize,
serde::Deserialize,
)]
pub enum ActionsValidationError {
DeleteActionMustBeFinal,
TotalPrepaidGasExceeded { total_prepaid_gas: Gas, limit: Gas },
TotalNumberOfActionsExceeded { total_number_of_actions: u64, limit: u64 },
AddKeyMethodNamesNumberOfBytesExceeded { total_number_of_bytes: u64, limit: u64 },
AddKeyMethodNameLengthExceeded { length: u64, limit: u64 },
IntegerOverflow,
InvalidAccountId { account_id: String },
ContractSizeExceeded { size: u64, limit: u64 },
FunctionCallMethodNameLengthExceeded { length: u64, limit: u64 },
FunctionCallArgumentsLengthExceeded { length: u64, limit: u64 },
UnsuitableStakingKey { public_key: Box<PublicKey> },
FunctionCallZeroAttachedGas,
DelegateActionMustBeOnlyOne,
UnsupportedProtocolFeature { protocol_feature: String, version: ProtocolVersion },
}
#[derive(
BorshSerialize,
BorshDeserialize,
Debug,
Clone,
PartialEq,
Eq,
RpcError,
serde::Serialize,
serde::Deserialize,
)]
pub enum ReceiptValidationError {
InvalidPredecessorId { account_id: String },
InvalidReceiverId { account_id: String },
InvalidSignerId { account_id: String },
InvalidDataReceiverId { account_id: String },
ReturnedValueLengthExceeded { length: u64, limit: u64 },
NumberInputDataDependenciesExceeded { number_of_input_data_dependencies: u64, limit: u64 },
ActionsValidation(ActionsValidationError),
}
impl Display for ReceiptValidationError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
match self {
ReceiptValidationError::InvalidPredecessorId { account_id } => {
write!(f, "The predecessor_id `{}` of a Receipt is not valid.", account_id)
}
ReceiptValidationError::InvalidReceiverId { account_id } => {
write!(f, "The receiver_id `{}` of a Receipt is not valid.", account_id)
}
ReceiptValidationError::InvalidSignerId { account_id } => {
write!(f, "The signer_id `{}` of an ActionReceipt is not valid.", account_id)
}
ReceiptValidationError::InvalidDataReceiverId { account_id } => write!(
f,
"The receiver_id `{}` of a DataReceiver within an ActionReceipt is not valid.",
account_id
),
ReceiptValidationError::ReturnedValueLengthExceeded { length, limit } => write!(
f,
"The length of the returned data {} exceeded the limit {} in a DataReceipt",
length, limit
),
ReceiptValidationError::NumberInputDataDependenciesExceeded { number_of_input_data_dependencies, limit } => write!(
f,
"The number of input data dependencies {} exceeded the limit {} in an ActionReceipt",
number_of_input_data_dependencies, limit
),
ReceiptValidationError::ActionsValidation(e) => write!(f, "{}", e),
}
}
}
impl std::error::Error for ReceiptValidationError {}
impl Display for ActionsValidationError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
match self {
ActionsValidationError::DeleteActionMustBeFinal => {
write!(f, "The delete action must be the last action in transaction")
}
ActionsValidationError::TotalPrepaidGasExceeded { total_prepaid_gas, limit } => {
write!(f, "The total prepaid gas {} exceeds the limit {}", total_prepaid_gas, limit)
}
ActionsValidationError::TotalNumberOfActionsExceeded {total_number_of_actions, limit } => {
write!(
f,
"The total number of actions {} exceeds the limit {}",
total_number_of_actions, limit
)
}
ActionsValidationError::AddKeyMethodNamesNumberOfBytesExceeded { total_number_of_bytes, limit } => write!(
f,
"The total number of bytes in allowed method names {} exceeds the maximum allowed number {} in a AddKey action",
total_number_of_bytes, limit
),
ActionsValidationError::AddKeyMethodNameLengthExceeded { length, limit } => write!(
f,
"The length of some method name {} exceeds the maximum allowed length {} in a AddKey action",
length, limit
),
ActionsValidationError::IntegerOverflow => write!(
f,
"Integer overflow during a compute",
),
ActionsValidationError::InvalidAccountId { account_id } => write!(
f,
"Invalid account ID `{}`",
account_id
),
ActionsValidationError::ContractSizeExceeded { size, limit } => write!(
f,
"The length of the contract size {} exceeds the maximum allowed size {} in a DeployContract action",
size, limit
),
ActionsValidationError::FunctionCallMethodNameLengthExceeded { length, limit } => write!(
f,
"The length of the method name {} exceeds the maximum allowed length {} in a FunctionCall action",
length, limit
),
ActionsValidationError::FunctionCallArgumentsLengthExceeded { length, limit } => write!(
f,
"The length of the arguments {} exceeds the maximum allowed length {} in a FunctionCall action",
length, limit
),
ActionsValidationError::UnsuitableStakingKey { public_key } => write!(
f,
"The staking key must be ristretto compatible ED25519 key. {} is provided instead.",
public_key,
),
ActionsValidationError::FunctionCallZeroAttachedGas => write!(
f,
"The attached amount of gas in a FunctionCall action has to be a positive number",
),
ActionsValidationError::DelegateActionMustBeOnlyOne => write!(
f,
"The actions can contain the ony one DelegateAction"
),
ActionsValidationError::UnsupportedProtocolFeature { protocol_feature, version } => write!(
f,
"Transaction requires protocol feature {} / version {} which is not supported by the current protocol version",
protocol_feature,
version,
),
}
}
}
impl std::error::Error for ActionsValidationError {}
#[derive(
BorshSerialize,
BorshDeserialize,
Debug,
Clone,
PartialEq,
Eq,
RpcError,
serde::Deserialize,
serde::Serialize,
)]
pub struct ActionError {
pub index: Option<u64>,
pub kind: ActionErrorKind,
}
impl std::error::Error for ActionError {}
#[derive(
BorshSerialize,
BorshDeserialize,
Debug,
Clone,
PartialEq,
Eq,
RpcError,
serde::Deserialize,
serde::Serialize,
)]
pub enum ActionErrorKind {
AccountAlreadyExists { account_id: AccountId },
AccountDoesNotExist { account_id: AccountId },
CreateAccountOnlyByRegistrar {
account_id: AccountId,
registrar_account_id: AccountId,
predecessor_id: AccountId,
},
CreateAccountNotAllowed { account_id: AccountId, predecessor_id: AccountId },
ActorNoPermission { account_id: AccountId, actor_id: AccountId },
DeleteKeyDoesNotExist { account_id: AccountId, public_key: Box<PublicKey> },
AddKeyAlreadyExists { account_id: AccountId, public_key: Box<PublicKey> },
DeleteAccountStaking { account_id: AccountId },
LackBalanceForState {
account_id: AccountId,
#[serde(with = "dec_format")]
amount: Balance,
},
TriesToUnpledge { account_id: AccountId },
TriesToPledge {
account_id: AccountId,
#[serde(with = "dec_format")]
pledge: Balance,
#[serde(with = "dec_format")]
pledging: Balance,
#[serde(with = "dec_format")]
balance: Balance,
},
InsufficientPledge {
account_id: AccountId,
#[serde(with = "dec_format")]
pledge: Balance,
#[serde(with = "dec_format")]
minimum_pledge: Balance,
},
FunctionCallError(FunctionCallError),
NewReceiptValidationError(ReceiptValidationError),
OnlyImplicitAccountCreationAllowed { account_id: AccountId },
DeleteAccountWithLargeState { account_id: AccountId },
DelegateActionInvalidSignature,
DelegateActionSenderDoesNotMatchTxReceiver { sender_id: AccountId, receiver_id: AccountId },
DelegateActionExpired,
DelegateActionAccessKeyError(InvalidAccessKeyError),
DelegateActionInvalidNonce { delegate_nonce: Nonce, ak_nonce: Nonce },
DelegateActionNonceTooLarge { delegate_nonce: Nonce, upper_bound: Nonce },
RsaKeysNotFound { account_id: AccountId, public_key: Box<PublicKey> },
}
impl From<ActionErrorKind> for ActionError {
fn from(e: ActionErrorKind) -> ActionError {
ActionError { index: None, kind: e }
}
}
impl Display for InvalidTxError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
match self {
InvalidTxError::InvalidSignerId { signer_id } => {
write!(f, "Invalid signer account ID {:?} according to requirements", signer_id)
}
InvalidTxError::SignerDoesNotExist { signer_id } => {
write!(f, "Signer {:?} does not exist", signer_id)
}
InvalidTxError::InvalidAccessKeyError(access_key_error) => {
Display::fmt(&access_key_error, f)
}
InvalidTxError::InvalidNonce { tx_nonce, ak_nonce } => write!(
f,
"Transaction nonce {} must be larger than nonce of the used access key {}",
tx_nonce, ak_nonce
),
InvalidTxError::InvalidReceiverId { receiver_id } => {
write!(f, "Invalid receiver account ID {:?} according to requirements", receiver_id)
}
InvalidTxError::InvalidSignature => {
write!(f, "Transaction is not signed with the given public key")
}
InvalidTxError::NotEnoughBalance { signer_id, balance, cost } => write!(
f,
"Sender {:?} does not have enough balance {} for operation costing {}",
signer_id, balance, cost
),
InvalidTxError::LackBalanceForState { signer_id, amount } => {
write!(f, "Failed to execute, because the account {:?} wouldn't have enough balance to cover storage, required to have {} yoctoUNC more", signer_id, amount)
}
InvalidTxError::CostOverflow => {
write!(f, "Transaction gas or balance cost is too high")
}
InvalidTxError::InvalidChain => {
write!(f, "Transaction parent block hash doesn't belong to the current chain")
}
InvalidTxError::Expired => {
write!(f, "Transaction has expired")
}
InvalidTxError::ActionsValidation(error) => {
write!(f, "Transaction actions validation error: {}", error)
}
InvalidTxError::NonceTooLarge { tx_nonce, upper_bound } => {
write!(
f,
"Transaction nonce {} must be smaller than the access key nonce upper bound {}",
tx_nonce, upper_bound
)
}
InvalidTxError::TransactionSizeExceeded { size, limit } => {
write!(f, "Size of serialized transaction {} exceeded the limit {}", size, limit)
}
}
}
}
impl From<InvalidAccessKeyError> for InvalidTxError {
fn from(error: InvalidAccessKeyError) -> Self {
InvalidTxError::InvalidAccessKeyError(error)
}
}
impl Display for InvalidAccessKeyError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
match self {
InvalidAccessKeyError::AccessKeyNotFound { account_id, public_key } => write!(
f,
"Signer {:?} doesn't have access key with the given public_key {}",
account_id, public_key
),
InvalidAccessKeyError::ReceiverMismatch { tx_receiver, ak_receiver } => write!(
f,
"Transaction receiver_id {:?} doesn't match the access key receiver_id {:?}",
tx_receiver, ak_receiver
),
InvalidAccessKeyError::MethodNameMismatch { method_name } => write!(
f,
"Transaction method name {:?} isn't allowed by the access key",
method_name
),
InvalidAccessKeyError::RequiresFullAccess => {
write!(f, "Invalid access key type. Full-access keys are required for transactions that have multiple or non-function-call actions")
}
InvalidAccessKeyError::NotEnoughAllowance {
account_id,
public_key,
allowance,
cost,
} => write!(
f,
"Access Key {:?}:{} does not have enough balance {} for transaction costing {}",
account_id, public_key, allowance, cost
),
InvalidAccessKeyError::DepositWithFunctionCall => {
write!(f, "Having a deposit with a function call action is not allowed with a function call access key.")
}
}
}
}
impl std::error::Error for InvalidAccessKeyError {}
#[derive(
BorshSerialize,
BorshDeserialize,
Debug,
Clone,
PartialEq,
Eq,
RpcError,
serde::Deserialize,
serde::Serialize,
)]
pub struct BalanceMismatchError {
#[serde(with = "dec_format")]
pub incoming_validator_rewards: Balance,
#[serde(with = "dec_format")]
pub initial_accounts_balance: Balance,
#[serde(with = "dec_format")]
pub incoming_receipts_balance: Balance,
#[serde(with = "dec_format")]
pub processed_delayed_receipts_balance: Balance,
#[serde(with = "dec_format")]
pub initial_postponed_receipts_balance: Balance,
#[serde(with = "dec_format")]
pub final_accounts_balance: Balance,
#[serde(with = "dec_format")]
pub outgoing_receipts_balance: Balance,
#[serde(with = "dec_format")]
pub new_delayed_receipts_balance: Balance,
#[serde(with = "dec_format")]
pub final_postponed_receipts_balance: Balance,
#[serde(with = "dec_format")]
pub tx_burnt_amount: Balance,
#[serde(with = "dec_format")]
pub slashed_burnt_amount: Balance,
#[serde(with = "dec_format")]
pub other_burnt_amount: Balance,
}
impl Display for BalanceMismatchError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
let initial_balance = self
.incoming_validator_rewards
.saturating_add(self.initial_accounts_balance)
.saturating_add(self.incoming_receipts_balance)
.saturating_add(self.processed_delayed_receipts_balance)
.saturating_add(self.initial_postponed_receipts_balance);
let final_balance = self
.final_accounts_balance
.saturating_add(self.outgoing_receipts_balance)
.saturating_add(self.new_delayed_receipts_balance)
.saturating_add(self.final_postponed_receipts_balance)
.saturating_add(self.tx_burnt_amount)
.saturating_add(self.slashed_burnt_amount)
.saturating_add(self.other_burnt_amount);
write!(
f,
"Balance Mismatch Error. The input balance {} doesn't match output balance {}\n\
Inputs:\n\
\tIncoming validator rewards sum: {}\n\
\tInitial accounts balance sum: {}\n\
\tIncoming receipts balance sum: {}\n\
\tProcessed delayed receipts balance sum: {}\n\
\tInitial postponed receipts balance sum: {}\n\
Outputs:\n\
\tFinal accounts balance sum: {}\n\
\tOutgoing receipts balance sum: {}\n\
\tNew delayed receipts balance sum: {}\n\
\tFinal postponed receipts balance sum: {}\n\
\tTx fees burnt amount: {}\n\
\tSlashed amount: {}\n\
\tOther burnt amount: {}",
initial_balance,
final_balance,
self.incoming_validator_rewards,
self.initial_accounts_balance,
self.incoming_receipts_balance,
self.processed_delayed_receipts_balance,
self.initial_postponed_receipts_balance,
self.final_accounts_balance,
self.outgoing_receipts_balance,
self.new_delayed_receipts_balance,
self.final_postponed_receipts_balance,
self.tx_burnt_amount,
self.slashed_burnt_amount,
self.other_burnt_amount,
)
}
}
impl std::error::Error for BalanceMismatchError {}
#[derive(BorshSerialize, BorshDeserialize, Debug, Clone, PartialEq, Eq)]
pub struct IntegerOverflowError;
impl std::fmt::Display for IntegerOverflowError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
f.write_str(&format!("{:?}", self))
}
}
impl std::error::Error for IntegerOverflowError {}
impl From<IntegerOverflowError> for InvalidTxError {
fn from(_: IntegerOverflowError) -> Self {
InvalidTxError::CostOverflow
}
}
impl From<IntegerOverflowError> for RuntimeError {
fn from(_: IntegerOverflowError) -> Self {
RuntimeError::UnexpectedIntegerOverflow
}
}
impl From<StorageError> for RuntimeError {
fn from(e: StorageError) -> Self {
RuntimeError::StorageError(e)
}
}
impl From<BalanceMismatchError> for RuntimeError {
fn from(e: BalanceMismatchError) -> Self {
RuntimeError::BalanceMismatchError(Box::new(e))
}
}
impl From<InvalidTxError> for RuntimeError {
fn from(e: InvalidTxError) -> Self {
RuntimeError::InvalidTxError(e)
}
}
impl From<EpochError> for RuntimeError {
fn from(e: EpochError) -> Self {
RuntimeError::ValidatorError(e)
}
}
impl Display for ActionError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
write!(f, "Action #{}: {}", self.index.unwrap_or_default(), self.kind)
}
}
impl Display for ActionErrorKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
match self {
ActionErrorKind::AccountAlreadyExists { account_id } => {
write!(f, "Can't create a new account {:?}, because it already exists", account_id)
}
ActionErrorKind::AccountDoesNotExist { account_id } => write!(
f,
"Can't complete the action because account {:?} doesn't exist",
account_id
),
ActionErrorKind::ActorNoPermission { actor_id, account_id } => write!(
f,
"Actor {:?} doesn't have permission to account {:?} to complete the action",
actor_id, account_id
),
ActionErrorKind::LackBalanceForState { account_id, amount } => write!(
f,
"The account {} wouldn't have enough balance to cover storage, required to have {} yoctoUNC more",
account_id, amount
),
ActionErrorKind::TriesToUnpledge { account_id } => {
write!(f, "Account {:?} is not yet pledging, but tries to unpledge", account_id)
}
ActionErrorKind::TriesToPledge { account_id, pledge, pledging, balance } => write!(
f,
"Account {:?} tries to pledge {}, but has pledging {} and only has {}",
account_id, pledge, pledging, balance
),
ActionErrorKind::CreateAccountOnlyByRegistrar { account_id, registrar_account_id, predecessor_id } => write!(
f,
"A top-level account ID {:?} can't be created by {:?}, short top-level account IDs can only be created by {:?}",
account_id, predecessor_id, registrar_account_id,
),
ActionErrorKind::CreateAccountNotAllowed { account_id, predecessor_id } => write!(
f,
"A sub-account ID {:?} can't be created by account {:?}",
account_id, predecessor_id,
),
ActionErrorKind::DeleteKeyDoesNotExist { account_id, .. } => write!(
f,
"Account {:?} tries to remove an access key that doesn't exist",
account_id
),
ActionErrorKind::AddKeyAlreadyExists { public_key, .. } => write!(
f,
"The public key {:?} is already used for an existing access key",
public_key
),
ActionErrorKind::DeleteAccountStaking { account_id } => {
write!(f, "Account {:?} is staking and can not be deleted", account_id)
}
ActionErrorKind::FunctionCallError(s) => write!(f, "{:?}", s),
ActionErrorKind::NewReceiptValidationError(e) => {
write!(f, "An new action receipt created during a FunctionCall is not valid: {}", e)
}
ActionErrorKind::InsufficientPledge { account_id, pledge, minimum_pledge } => write!(f, "Account {} tries to pledge {} but minimum required pledge is {}", account_id, pledge, minimum_pledge),
ActionErrorKind::OnlyImplicitAccountCreationAllowed { account_id } => write!(f, "CreateAccount action is called on hex-characters account of length 64 {}", account_id),
ActionErrorKind::DeleteAccountWithLargeState { account_id } => write!(f, "The state of account {} is too large and therefore cannot be deleted", account_id),
ActionErrorKind::DelegateActionInvalidSignature => write!(f, "DelegateAction is not signed with the given public key"),
ActionErrorKind::DelegateActionSenderDoesNotMatchTxReceiver { sender_id, receiver_id } => write!(f, "Transaction receiver {} doesn't match DelegateAction sender {}", receiver_id, sender_id),
ActionErrorKind::DelegateActionExpired => write!(f, "DelegateAction has expired"),
ActionErrorKind::DelegateActionAccessKeyError(access_key_error) => Display::fmt(&access_key_error, f),
ActionErrorKind::DelegateActionInvalidNonce { delegate_nonce, ak_nonce } => write!(f, "DelegateAction nonce {} must be larger than nonce of the used access key {}", delegate_nonce, ak_nonce),
ActionErrorKind::DelegateActionNonceTooLarge { delegate_nonce, upper_bound } => write!(f, "DelegateAction nonce {} must be smaller than the access key nonce upper bound {}", delegate_nonce, upper_bound),
ActionErrorKind::RsaKeysNotFound { public_key, .. } => write!(
f,
"The public key {:?} is doesn't exist rsa key",
public_key
),
}
}
}
#[derive(Eq, PartialEq, Clone)]
pub enum BlockError {
ThresholdError {
pledge_sum: Balance,
num_seats: u64,
},
BlockOutOfBounds(CryptoHash),
MissingBlock(CryptoHash),
IOErr(String),
NotAValidator(AccountId, BlockHeight),
ShardingError(String),
NotEnoughValidators {
num_validators: u64,
num_shards: u64,
},
ChunkValidatorSelectionError(String),
ValidatorTotalPowerError(String),
NoAvailableValidator(String),
}
impl std::error::Error for crate::errors::BlockError {}
impl Display for crate::errors::BlockError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
crate::errors::BlockError::ThresholdError { pledge_sum, num_seats } => write!(
f,
"Total pledge {} must be higher than the number of seats {}",
pledge_sum, num_seats
),
crate::errors::BlockError::BlockOutOfBounds(block_height) => {
write!(f, "Block {:?} is out of bounds", block_height)
}
crate::errors::BlockError::MissingBlock(hash) => write!(f, "Missing block {}", hash),
crate::errors::BlockError::IOErr(err) => write!(f, "IO: {}", err),
crate::errors::BlockError::NotAValidator(account_id, block_height) => {
write!(f, "{} is not a validator in epoch {:?}", account_id, block_height)
}
crate::errors::BlockError::ShardingError(err) => write!(f, "Sharding Error: {}", err),
crate::errors::BlockError::NotEnoughValidators { num_shards, num_validators } => {
write!(f, "There were not enough validator proposals to fill all shards. num_proposals: {}, num_shards: {}", num_validators, num_shards)
}
crate::errors::BlockError::ChunkValidatorSelectionError(err) => {
write!(f, "Error selecting validators for a chunk: {}", err)
}
crate::errors::BlockError::ValidatorTotalPowerError(err) => {
write!(f, "Error when computing total power: {}", err)
}
crate::errors::BlockError::NoAvailableValidator(err) => {
write!(f, "Error selecting produce: {}", err)
}
}
}
}
impl Debug for crate::errors::BlockError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
crate::errors::BlockError::ThresholdError { pledge_sum, num_seats } => {
write!(f, "ThresholdError({}, {})", pledge_sum, num_seats)
}
crate::errors::BlockError::BlockOutOfBounds(block_height) => write!(f, "EpochOutOfBounds({:?})", block_height),
crate::errors::BlockError::MissingBlock(hash) => write!(f, "MissingBlock({})", hash),
crate::errors::BlockError::IOErr(err) => write!(f, "IOErr({})", err),
crate::errors::BlockError::NotAValidator(account_id, block_height) => {
write!(f, "NotAValidator({}, {:?})", account_id, block_height)
}
crate::errors::BlockError::ShardingError(err) => write!(f, "ShardingError({})", err),
crate::errors::BlockError::NotEnoughValidators { num_shards, num_validators } => {
write!(f, "NotEnoughValidators({}, {})", num_validators, num_shards)
}
crate::errors::BlockError::ChunkValidatorSelectionError(err) => {
write!(f, "ChunkValidatorSelectionError({})", err)
}
crate::errors::BlockError::ValidatorTotalPowerError(err) => {
write!(f, "Error when computing total power: {}", err)
}
crate::errors::BlockError::NoAvailableValidator(err) => {
write!(f, "Error selecting produce: {}", err)
}
}
}
}
impl From<std::io::Error> for crate::errors::BlockError {
fn from(error: std::io::Error) -> Self {
crate::errors::BlockError::IOErr(error.to_string())
}
}
impl From<EpochError> for BlockError {
fn from(error: EpochError) -> Self {
match error {
EpochError::IOErr(..) => {
BlockError::IOErr(error.to_string())
},
EpochError::ChunkValidatorSelectionError(..) => {
BlockError::ChunkValidatorSelectionError(error.to_string())
},
EpochError::EpochOutOfBounds(..) => {
BlockError::BlockOutOfBounds(CryptoHash::default())
},
EpochError::MissingBlock(block_hash) => {
BlockError::MissingBlock(block_hash)
},
EpochError::NotAValidator(account_id, _hash) => {
BlockError::NotAValidator(account_id, 0)
},
EpochError::NotEnoughValidators{ num_validators: x, num_shards: y } => {
BlockError::NotEnoughValidators{ num_validators: x, num_shards: y }
},
EpochError::ShardingError(..) => {
BlockError::ShardingError(error.to_string())
},
EpochError::ThresholdError{
pledge_sum: pledge,
num_seats: seats,
} => {
BlockError::ThresholdError{
pledge_sum: pledge,
num_seats: seats,
}
}
}
}
}
#[derive(Eq, PartialEq, Clone)]
pub enum EpochError {
ThresholdError {
pledge_sum: Balance,
num_seats: u64,
},
EpochOutOfBounds(EpochId),
MissingBlock(CryptoHash),
IOErr(String),
NotAValidator(AccountId, EpochId),
ShardingError(String),
NotEnoughValidators {
num_validators: u64,
num_shards: u64,
},
ChunkValidatorSelectionError(String),
}
impl std::error::Error for EpochError {}
impl Display for EpochError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
EpochError::ThresholdError { pledge_sum, num_seats } => write!(
f,
"Total pledge {} must be higher than the number of seats {}",
pledge_sum, num_seats
),
EpochError::EpochOutOfBounds(epoch_id) => {
write!(f, "Epoch {:?} is out of bounds", epoch_id)
}
EpochError::MissingBlock(hash) => write!(f, "Missing block {}", hash),
EpochError::IOErr(err) => write!(f, "IO: {}", err),
EpochError::NotAValidator(account_id, epoch_id) => {
write!(f, "{} is not a validator in epoch {:?}", account_id, epoch_id)
}
EpochError::ShardingError(err) => write!(f, "Sharding Error: {}", err),
EpochError::NotEnoughValidators { num_shards, num_validators } => {
write!(f, "There were not enough validator proposals to fill all shards. num_proposals: {}, num_shards: {}", num_validators, num_shards)
}
EpochError::ChunkValidatorSelectionError(err) => {
write!(f, "Error selecting validators for a chunk: {}", err)
}
}
}
}
impl Debug for EpochError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
EpochError::ThresholdError { pledge_sum, num_seats } => {
write!(f, "ThresholdError({}, {})", pledge_sum, num_seats)
}
EpochError::EpochOutOfBounds(epoch_id) => write!(f, "EpochOutOfBounds({:?})", epoch_id),
EpochError::MissingBlock(hash) => write!(f, "MissingBlock({})", hash),
EpochError::IOErr(err) => write!(f, "IOErr({})", err),
EpochError::NotAValidator(account_id, epoch_id) => {
write!(f, "NotAValidator({}, {:?})", account_id, epoch_id)
}
EpochError::ShardingError(err) => write!(f, "ShardingError({})", err),
EpochError::NotEnoughValidators { num_shards, num_validators } => {
write!(f, "NotEnoughValidators({}, {})", num_validators, num_shards)
}
EpochError::ChunkValidatorSelectionError(err) => {
write!(f, "ChunkValidatorSelectionError({})", err)
}
}
}
}
impl From<std::io::Error> for EpochError {
fn from(error: std::io::Error) -> Self {
EpochError::IOErr(error.to_string())
}
}
impl From<BlockError> for EpochError {
fn from(error: BlockError) -> Self {
match error {
BlockError::IOErr(..) => {
EpochError::IOErr(error.to_string())
},
BlockError::ChunkValidatorSelectionError(..) => {
EpochError::ChunkValidatorSelectionError(error.to_string())
},
BlockError::BlockOutOfBounds(..) => {
EpochError::EpochOutOfBounds(EpochId::default())
},
BlockError::MissingBlock(block_hash) => {
EpochError::MissingBlock(block_hash)
},
BlockError::NotAValidator(account_id, _block_height) => {
EpochError::NotAValidator(account_id, EpochId::default())
},
BlockError::NotEnoughValidators{ num_validators: x, num_shards: y } => {
EpochError::NotEnoughValidators{ num_validators: x, num_shards: y }
},
BlockError::ShardingError(..) => {
EpochError::ShardingError(error.to_string())
},
BlockError::ThresholdError{
pledge_sum: pledge,
num_seats: seats,
} => {
EpochError::ThresholdError{
pledge_sum: pledge,
num_seats: seats,
}
},
BlockError::ValidatorTotalPowerError(..) => {
EpochError::IOErr(error.to_string())
},
BlockError::NoAvailableValidator(..) => {
EpochError::IOErr(error.to_string())
}
}
}
}
#[derive(
Debug,
Clone,
PartialEq,
Eq,
BorshDeserialize,
BorshSerialize,
RpcError,
serde::Deserialize,
serde::Serialize,
)]
pub enum PrepareError {
Serialization,
Deserialization,
InternalMemoryDeclared,
GasInstrumentation,
StackHeightInstrumentation,
Instantiate,
Memory,
TooManyFunctions,
TooManyLocals,
}
#[derive(
Debug,
Clone,
PartialEq,
Eq,
BorshDeserialize,
BorshSerialize,
RpcError,
serde::Deserialize,
serde::Serialize,
strum::IntoStaticStr,
)]
pub enum WasmTrap {
Unreachable,
IncorrectCallIndirectSignature,
MemoryOutOfBounds,
CallIndirectOOB,
IllegalArithmetic,
MisalignedAtomicAccess,
IndirectCallToNull,
StackOverflow,
GenericTrap,
}
#[derive(
Debug,
Clone,
PartialEq,
Eq,
BorshDeserialize,
BorshSerialize,
RpcError,
serde::Deserialize,
serde::Serialize,
strum::IntoStaticStr,
)]
pub enum HostError {
BadUTF16,
BadUTF8,
GasExceeded,
GasLimitExceeded,
BalanceExceeded,
EmptyMethodName,
GuestPanic { panic_msg: String },
IntegerOverflow,
InvalidPromiseIndex { promise_idx: u64 },
CannotAppendActionToJointPromise,
CannotReturnJointPromise,
InvalidPromiseResultIndex { result_idx: u64 },
InvalidRegisterId { register_id: u64 },
IteratorWasInvalidated { iterator_index: u64 },
MemoryAccessViolation,
InvalidReceiptIndex { receipt_index: u64 },
InvalidIteratorIndex { iterator_index: u64 },
InvalidAccountId,
InvalidMethodName,
InvalidPublicKey,
ProhibitedInView { method_name: String },
NumberOfLogsExceeded { limit: u64 },
KeyLengthExceeded { length: u64, limit: u64 },
ValueLengthExceeded { length: u64, limit: u64 },
TotalLogLengthExceeded { length: u64, limit: u64 },
NumberPromisesExceeded { number_of_promises: u64, limit: u64 },
NumberInputDataDependenciesExceeded { number_of_input_data_dependencies: u64, limit: u64 },
ReturnedValueLengthExceeded { length: u64, limit: u64 },
ContractSizeExceeded { size: u64, limit: u64 },
Deprecated { method_name: String },
ECRecoverError { msg: String },
AltBn128InvalidInput { msg: String },
Ed25519VerifyInvalidInput { msg: String },
}
#[derive(
Debug,
Clone,
PartialEq,
Eq,
BorshDeserialize,
BorshSerialize,
RpcError,
serde::Deserialize,
serde::Serialize,
strum::IntoStaticStr,
)]
pub enum MethodResolveError {
MethodEmptyName,
MethodNotFound,
MethodInvalidSignature,
}
#[derive(
Debug,
Clone,
PartialEq,
Eq,
BorshDeserialize,
BorshSerialize,
RpcError,
serde::Deserialize,
serde::Serialize,
strum::IntoStaticStr,
)]
pub enum CompilationError {
CodeDoesNotExist {
account_id: AccountId,
},
PrepareError(PrepareError),
WasmerCompileError {
msg: String,
},
}
#[derive(
Debug,
Clone,
PartialEq,
Eq,
BorshDeserialize,
BorshSerialize,
serde::Serialize,
serde::Deserialize,
)]
pub enum FunctionCallError {
CompilationError(CompilationError),
LinkError {
msg: String,
},
MethodResolveError(MethodResolveError),
WasmTrap(WasmTrap),
WasmUnknownError,
HostError(HostError),
_EVMError,
ExecutionError(String),
}
impl From<unc_vm_runner::logic::errors::MethodResolveError> for MethodResolveError {
fn from(outer_err: unc_vm_runner::logic::errors::MethodResolveError) -> Self {
use unc_vm_runner::logic::errors::MethodResolveError as MRE;
match outer_err {
MRE::MethodEmptyName => Self::MethodEmptyName,
MRE::MethodNotFound => Self::MethodNotFound,
MRE::MethodInvalidSignature => Self::MethodInvalidSignature,
}
}
}
impl From<unc_vm_runner::logic::errors::PrepareError> for PrepareError {
fn from(outer_err: unc_vm_runner::logic::errors::PrepareError) -> Self {
use unc_vm_runner::logic::errors::PrepareError as PE;
match outer_err {
PE::Serialization => Self::Serialization,
PE::Deserialization => Self::Deserialization,
PE::InternalMemoryDeclared => Self::InternalMemoryDeclared,
PE::GasInstrumentation => Self::GasInstrumentation,
PE::StackHeightInstrumentation => Self::StackHeightInstrumentation,
PE::Instantiate => Self::Instantiate,
PE::Memory => Self::Memory,
PE::TooManyFunctions => Self::TooManyFunctions,
PE::TooManyLocals => Self::TooManyLocals,
}
}
}
impl From<unc_vm_runner::logic::errors::CompilationError> for CompilationError {
fn from(outer_err: unc_vm_runner::logic::errors::CompilationError) -> Self {
use unc_vm_runner::logic::errors::CompilationError as CE;
match outer_err {
CE::CodeDoesNotExist { account_id } => Self::CodeDoesNotExist {
account_id: account_id.parse().expect("account_id in error must be valid"),
},
CE::PrepareError(pe) => Self::PrepareError(pe.into()),
CE::WasmerCompileError { msg } => Self::WasmerCompileError { msg },
}
}
}
impl From<unc_vm_runner::logic::errors::FunctionCallError> for FunctionCallError {
fn from(outer_err: unc_vm_runner::logic::errors::FunctionCallError) -> Self {
use unc_vm_runner::logic::errors::FunctionCallError as FCE;
match outer_err {
FCE::CompilationError(e) => Self::CompilationError(e.into()),
FCE::MethodResolveError(e) => Self::MethodResolveError(e.into()),
FCE::HostError(ref _e) => Self::ExecutionError(outer_err.to_string()),
FCE::LinkError { msg } => Self::ExecutionError(format!("Link Error: {}", msg)),
FCE::WasmTrap(ref _e) => Self::ExecutionError(outer_err.to_string()),
}
}
}
#[cfg(feature = "new_epoch_sync")]
pub mod epoch_sync {
use unc_primitives_core::hash::CryptoHash;
use unc_primitives_core::types::EpochHeight;
use std::fmt::Debug;
#[derive(Eq, PartialEq, Clone, strum::Display, Debug)]
pub enum EpochSyncHashType {
LastEpochBlock,
LastFinalBlock,
FirstEpochBlock,
NextEpochFirstBlock,
Other,
BlockToSave,
}
#[derive(Eq, PartialEq, Clone, thiserror::Error, Debug)]
pub enum EpochSyncInfoError {
#[error("{hash_type} hash {hash:?} not a part of EpochSyncInfo for epoch {epoch_height}")]
HashNotFound { hash: CryptoHash, hash_type: EpochSyncHashType, epoch_height: EpochHeight },
#[error("all_block_hashes.len() < 2 for epoch {epoch_height}")]
ShortEpoch { epoch_height: EpochHeight },
}
}