use crate::action::GlobalContractIdentifier;
use crate::hash::CryptoHash;
use crate::shard_layout::ShardLayoutError;
use crate::sharding::ChunkHash;
use crate::types::{AccountId, Balance, EpochId, Nonce, SpiceChunkId};
use borsh::{BorshDeserialize, BorshSerialize};
use near_crypto::PublicKey;
pub use near_primitives_core::errors::IntegerOverflowError;
use near_primitives_core::types::Gas;
use near_primitives_core::types::{BlockHeight, NonceIndex, ProtocolVersion, ShardId};
use near_schema_checker_lib::ProtocolSchema;
use std::fmt::{Debug, Display};
use std::io;
#[derive(
BorshSerialize,
BorshDeserialize,
Debug,
Clone,
PartialEq,
Eq,
serde::Deserialize,
serde::Serialize,
ProtocolSchema,
)]
#[borsh(use_discriminant = true)]
#[repr(u8)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum TxExecutionError {
ActionError(ActionError) = 0,
InvalidTxError(InvalidTxError) = 1,
}
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(String),
InvalidTxError(InvalidTxError),
StorageError(StorageError),
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,
serde::Deserialize,
serde::Serialize,
BorshSerialize,
BorshDeserialize,
ProtocolSchema,
)]
#[borsh(use_discriminant = true)]
#[repr(u8)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum MissingTrieValueContext {
TrieIterator = 0,
TriePrefetchingStorage = 1,
TrieMemoryPartialStorage = 2,
TrieStorage = 3,
}
impl MissingTrieValueContext {
pub fn metrics_label(&self) -> &str {
match self {
Self::TrieIterator => "trie_iterator",
Self::TriePrefetchingStorage => "trie_prefetching_storage",
Self::TrieMemoryPartialStorage => "trie_memory_partial_storage",
Self::TrieStorage => "trie_storage",
}
}
}
#[derive(
Debug,
Clone,
PartialEq,
Eq,
serde::Deserialize,
serde::Serialize,
BorshSerialize,
BorshDeserialize,
ProtocolSchema,
)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct MissingTrieValue {
pub context: MissingTrieValueContext,
pub hash: CryptoHash,
}
#[derive(
Debug,
Clone,
PartialEq,
Eq,
serde::Deserialize,
serde::Serialize,
BorshSerialize,
BorshDeserialize,
ProtocolSchema,
)]
#[borsh(use_discriminant = true)]
#[repr(u8)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum StorageError {
StorageInternalError = 0,
MissingTrieValue(MissingTrieValue) = 1,
UnexpectedTrieValue = 2,
StorageInconsistentState(String) = 3,
FlatStorageBlockNotSupported(String) = 4,
MemTrieLoadingError(String) = 5,
}
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,
serde::Deserialize,
serde::Serialize,
ProtocolSchema,
)]
#[borsh(use_discriminant = true)]
#[repr(u8)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum DepositCostFailureReason {
NotEnoughBalance = 0,
LackBalanceForState = 1,
}
#[derive(
BorshSerialize,
BorshDeserialize,
Debug,
Clone,
PartialEq,
Eq,
serde::Deserialize,
serde::Serialize,
ProtocolSchema,
)]
#[borsh(use_discriminant = true)]
#[repr(u8)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum InvalidTxError {
InvalidAccessKeyError(InvalidAccessKeyError) = 0,
InvalidSignerId {
signer_id: String,
} = 1,
SignerDoesNotExist {
signer_id: AccountId,
} = 2,
InvalidNonce {
tx_nonce: Nonce,
ak_nonce: Nonce,
} = 3,
NonceTooLarge {
tx_nonce: Nonce,
upper_bound: Nonce,
} = 4,
InvalidReceiverId {
receiver_id: String,
} = 5,
InvalidSignature = 6,
NotEnoughBalance {
signer_id: AccountId,
balance: Balance,
cost: Balance,
} = 7,
LackBalanceForState {
signer_id: AccountId,
amount: Balance,
} = 8,
CostOverflow = 9,
InvalidChain = 10,
Expired = 11,
ActionsValidation(ActionsValidationError) = 12,
TransactionSizeExceeded {
size: u64,
limit: u64,
} = 13,
InvalidTransactionVersion = 14,
StorageError(StorageError) = 15,
ShardCongested {
shard_id: u32,
#[cfg_attr(feature = "schemars", schemars(with = "f64"))]
congestion_level: ordered_float::NotNan<f64>,
} = 16,
ShardStuck {
shard_id: u32,
missed_chunks: u64,
} = 17,
InvalidNonceIndex {
tx_nonce_index: Option<NonceIndex>,
num_nonces: NonceIndex,
} = 18,
NotEnoughGasKeyBalance {
signer_id: AccountId,
balance: Balance,
cost: Balance,
} = 19,
NotEnoughBalanceForDeposit {
signer_id: AccountId,
balance: Balance,
cost: Balance,
reason: DepositCostFailureReason,
} = 20,
}
impl From<StorageError> for InvalidTxError {
fn from(error: StorageError) -> Self {
InvalidTxError::StorageError(error)
}
}
impl std::error::Error for InvalidTxError {}
#[derive(
BorshSerialize,
BorshDeserialize,
Debug,
Clone,
PartialEq,
Eq,
serde::Deserialize,
serde::Serialize,
ProtocolSchema,
)]
#[borsh(use_discriminant = true)]
#[repr(u8)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum InvalidAccessKeyError {
AccessKeyNotFound { account_id: AccountId, public_key: Box<PublicKey> } = 0,
ReceiverMismatch { tx_receiver: AccountId, ak_receiver: String } = 1,
MethodNameMismatch { method_name: String } = 2,
RequiresFullAccess = 3,
NotEnoughAllowance {
account_id: AccountId,
public_key: Box<PublicKey>,
allowance: Balance,
cost: Balance,
} = 4,
DepositWithFunctionCall = 5,
}
#[derive(
BorshSerialize,
BorshDeserialize,
Debug,
Clone,
PartialEq,
Eq,
serde::Serialize,
serde::Deserialize,
ProtocolSchema,
)]
#[borsh(use_discriminant = true)]
#[repr(u8)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum ActionsValidationError {
DeleteActionMustBeFinal = 0,
TotalPrepaidGasExceeded {
total_prepaid_gas: Gas,
limit: Gas,
} = 1,
TotalNumberOfActionsExceeded {
total_number_of_actions: u64,
limit: u64,
} = 2,
AddKeyMethodNamesNumberOfBytesExceeded {
total_number_of_bytes: u64,
limit: u64,
} = 3,
AddKeyMethodNameLengthExceeded {
length: u64,
limit: u64,
} = 4,
IntegerOverflow = 5,
InvalidAccountId {
account_id: String,
} = 6,
ContractSizeExceeded {
size: u64,
limit: u64,
} = 7,
FunctionCallMethodNameLengthExceeded {
length: u64,
limit: u64,
} = 8,
FunctionCallArgumentsLengthExceeded {
length: u64,
limit: u64,
} = 9,
UnsuitableStakingKey {
public_key: Box<PublicKey>,
} = 10,
FunctionCallZeroAttachedGas = 11,
DelegateActionMustBeOnlyOne = 12,
UnsupportedProtocolFeature {
protocol_feature: String,
version: ProtocolVersion,
} = 13,
InvalidDeterministicStateInitReceiver {
receiver_id: AccountId,
derived_id: AccountId,
} = 14,
DeterministicStateInitKeyLengthExceeded {
length: u64,
limit: u64,
} = 15,
DeterministicStateInitValueLengthExceeded {
length: u64,
limit: u64,
} = 16,
GasKeyInvalidNumNonces {
requested_nonces: NonceIndex,
limit: NonceIndex,
} = 17,
AddGasKeyWithNonZeroBalance {
balance: Balance,
} = 18,
GasKeyFunctionCallAllowanceNotAllowed = 19,
}
#[derive(
BorshSerialize,
BorshDeserialize,
Debug,
Clone,
PartialEq,
Eq,
serde::Serialize,
serde::Deserialize,
ProtocolSchema,
)]
#[borsh(use_discriminant = true)]
#[repr(u8)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum ReceiptValidationError {
InvalidPredecessorId { account_id: String } = 0,
InvalidReceiverId { account_id: String } = 1,
InvalidSignerId { account_id: String } = 2,
InvalidDataReceiverId { account_id: String } = 3,
ReturnedValueLengthExceeded { length: u64, limit: u64 } = 4,
NumberInputDataDependenciesExceeded { number_of_input_data_dependencies: u64, limit: u64 } = 5,
ActionsValidation(ActionsValidationError) = 6,
ReceiptSizeExceeded { size: u64, limit: u64 } = 7,
InvalidRefundTo { account_id: String } = 8,
}
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),
ReceiptValidationError::ReceiptSizeExceeded { size, limit } => {
write!(f, "The size of the receipt exceeded the limit: {} > {}", size, limit)
}
ReceiptValidationError::InvalidRefundTo { account_id } => {
write!(f, "The refund_to `{}` of an ActionReceipt is not valid.", account_id)
}
}
}
}
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,
)
}
ActionsValidationError::InvalidDeterministicStateInitReceiver {
receiver_id,
derived_id,
} => {
write!(
f,
"DeterministicStateInit action payload is invalid for account {receiver_id}, derived id is {derived_id}",
)
}
ActionsValidationError::DeterministicStateInitKeyLengthExceeded { length, limit } => {
write!(
f,
"DeterministicStateInit contains key of length {length} but at most {limit} is allowed",
)
}
ActionsValidationError::DeterministicStateInitValueLengthExceeded { length, limit } => {
write!(
f,
"DeterministicStateInit contains value of length {length} but at most {limit} is allowed",
)
}
ActionsValidationError::GasKeyInvalidNumNonces { requested_nonces, limit } => {
write!(
f,
"gas key requested invalid number of nonces: {} (must be between 1 and {})",
requested_nonces, limit
)
}
ActionsValidationError::AddGasKeyWithNonZeroBalance { balance } => {
write!(
f,
"Adding a gas key with non-zero balance is not allowed: balance = {}",
balance
)
}
ActionsValidationError::GasKeyFunctionCallAllowanceNotAllowed => {
write!(f, "Gas keys with FunctionCall permission cannot have an allowance set")
}
}
}
}
impl std::error::Error for ActionsValidationError {}
#[derive(
BorshSerialize,
BorshDeserialize,
Debug,
Clone,
PartialEq,
Eq,
serde::Deserialize,
serde::Serialize,
ProtocolSchema,
)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct ActionError {
pub index: Option<u64>,
pub kind: ActionErrorKind,
}
impl std::error::Error for ActionError {}
#[derive(
BorshSerialize,
BorshDeserialize,
Debug,
Clone,
PartialEq,
Eq,
serde::Deserialize,
serde::Serialize,
ProtocolSchema,
)]
#[borsh(use_discriminant = true)]
#[repr(u8)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum ActionErrorKind {
AccountAlreadyExists {
account_id: AccountId,
} = 0,
AccountDoesNotExist {
account_id: AccountId,
} = 1,
CreateAccountOnlyByRegistrar {
account_id: AccountId,
registrar_account_id: AccountId,
predecessor_id: AccountId,
} = 2,
CreateAccountNotAllowed {
account_id: AccountId,
predecessor_id: AccountId,
} = 3,
ActorNoPermission {
account_id: AccountId,
actor_id: AccountId,
} = 4,
DeleteKeyDoesNotExist {
account_id: AccountId,
public_key: Box<PublicKey>,
} = 5,
AddKeyAlreadyExists {
account_id: AccountId,
public_key: Box<PublicKey>,
} = 6,
DeleteAccountStaking {
account_id: AccountId,
} = 7,
LackBalanceForState {
account_id: AccountId,
amount: Balance,
} = 8,
TriesToUnstake {
account_id: AccountId,
} = 9,
TriesToStake {
account_id: AccountId,
stake: Balance,
locked: Balance,
balance: Balance,
} = 10,
InsufficientStake {
account_id: AccountId,
stake: Balance,
minimum_stake: Balance,
} = 11,
FunctionCallError(FunctionCallError) = 12,
NewReceiptValidationError(ReceiptValidationError) = 13,
OnlyImplicitAccountCreationAllowed {
account_id: AccountId,
} = 14,
DeleteAccountWithLargeState {
account_id: AccountId,
} = 15,
DelegateActionInvalidSignature = 16,
DelegateActionSenderDoesNotMatchTxReceiver {
sender_id: AccountId,
receiver_id: AccountId,
} = 17,
DelegateActionExpired = 18,
DelegateActionAccessKeyError(InvalidAccessKeyError) = 19,
DelegateActionInvalidNonce {
delegate_nonce: Nonce,
ak_nonce: Nonce,
} = 20,
DelegateActionNonceTooLarge {
delegate_nonce: Nonce,
upper_bound: Nonce,
} = 21,
GlobalContractDoesNotExist {
identifier: GlobalContractIdentifier,
} = 22,
GasKeyDoesNotExist {
account_id: AccountId,
public_key: Box<PublicKey>,
} = 23,
InsufficientGasKeyBalance {
account_id: AccountId,
public_key: Box<PublicKey>,
balance: Balance,
required: Balance,
} = 24,
GasKeyBalanceTooHigh {
account_id: AccountId,
public_key: Option<Box<PublicKey>>,
balance: Balance,
} = 25,
}
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 {} yoctoNEAR 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)
}
InvalidTxError::InvalidTransactionVersion => {
write!(f, "Transaction version is invalid")
}
InvalidTxError::StorageError(error) => {
write!(f, "Storage error: {}", error)
}
InvalidTxError::ShardCongested { shard_id, congestion_level } => {
write!(
f,
"Shard {shard_id} is currently at congestion level {congestion_level:.3} and rejects new transactions."
)
}
InvalidTxError::ShardStuck { shard_id, missed_chunks } => {
write!(
f,
"Shard {shard_id} missed {missed_chunks} chunks and rejects new transactions."
)
}
InvalidTxError::InvalidNonceIndex { tx_nonce_index, num_nonces } => {
write!(f, "Invalid nonce_index {tx_nonce_index:?} for key with {num_nonces} nonces")
}
InvalidTxError::NotEnoughGasKeyBalance { signer_id, balance, cost } => write!(
f,
"Gas key for {:?} does not have enough balance {} for gas cost {}",
signer_id, balance, cost
),
InvalidTxError::NotEnoughBalanceForDeposit { signer_id, balance, cost, reason } => {
match reason {
DepositCostFailureReason::NotEnoughBalance => write!(
f,
"Sender {:?} does not have enough balance {} to cover deposit cost {}",
signer_id, balance, cost
),
DepositCostFailureReason::LackBalanceForState => write!(
f,
"Sender {:?} would not have enough balance for storage after covering deposit (required {} more)",
signer_id, cost
),
}
}
}
}
}
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 {}
impl From<IntegerOverflowError> for InvalidTxError {
fn from(_: IntegerOverflowError) -> Self {
InvalidTxError::CostOverflow
}
}
impl From<IntegerOverflowError> for RuntimeError {
fn from(err: IntegerOverflowError) -> Self {
RuntimeError::UnexpectedIntegerOverflow(err.to_string())
}
}
impl From<StorageError> for RuntimeError {
fn from(e: StorageError) -> Self {
RuntimeError::StorageError(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 {} yoctoNEAR more",
account_id, amount
),
ActionErrorKind::TriesToUnstake { account_id } => {
write!(f, "Account {:?} is not yet staked, but tries to unstake", account_id)
}
ActionErrorKind::TriesToStake { account_id, stake, locked, balance } => write!(
f,
"Account {:?} tries to stake {}, but has staked {} and only has {}",
account_id, stake, locked, 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::InsufficientStake { account_id, stake, minimum_stake } => write!(
f,
"Account {} tries to stake {} but minimum required stake is {}",
account_id, stake, minimum_stake
),
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::GlobalContractDoesNotExist { identifier } => {
write!(f, "Global contract identifier {:?} not found", identifier)
}
ActionErrorKind::GasKeyDoesNotExist { account_id, public_key } => {
write!(f, "Gas key {} does not exist for account {}", public_key, account_id)
}
ActionErrorKind::InsufficientGasKeyBalance {
account_id,
public_key,
balance,
required,
} => {
write!(
f,
"Gas key {} for account {} has insufficient balance: {} available, {} required",
public_key, account_id, balance, required
)
}
ActionErrorKind::GasKeyBalanceTooHigh { account_id, public_key, balance } => {
if let Some(pk) = public_key {
write!(
f,
"Gas key {} for account {} has balance {} which is too high to burn on deletion",
pk, account_id, balance
)
} else {
write!(
f,
"Account {} has total gas key balance {} which is too high to burn on deletion",
account_id, balance
)
}
}
}
}
}
#[derive(Eq, PartialEq, Clone)]
pub enum EpochError {
ThresholdError {
stake_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),
ChunkProducerSelectionError(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 { stake_sum, num_seats } => write!(
f,
"Total stake {} must be higher than the number of seats {}",
stake_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)
}
EpochError::ChunkProducerSelectionError(err) => {
write!(f, "Error selecting chunk producer: {}", err)
}
}
}
}
impl Debug for EpochError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
EpochError::ThresholdError { stake_sum, num_seats } => {
write!(f, "ThresholdError({}, {})", stake_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)
}
EpochError::ChunkProducerSelectionError(err) => {
write!(f, "ChunkProducerSelectionError({})", err)
}
}
}
}
impl From<std::io::Error> for EpochError {
fn from(error: std::io::Error) -> Self {
EpochError::IOErr(error.to_string())
}
}
impl From<ShardLayoutError> for EpochError {
fn from(error: ShardLayoutError) -> Self {
EpochError::ShardingError(error.to_string())
}
}
#[derive(
Debug,
Clone,
PartialEq,
Eq,
BorshDeserialize,
BorshSerialize,
serde::Deserialize,
serde::Serialize,
ProtocolSchema,
)]
#[borsh(use_discriminant = true)]
#[repr(u8)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum PrepareError {
Serialization = 0,
Deserialization = 1,
InternalMemoryDeclared = 2,
GasInstrumentation = 3,
StackHeightInstrumentation = 4,
Instantiate = 5,
Memory = 6,
TooManyFunctions = 7,
TooManyLocals = 8,
TooManyTables = 9,
TooManyTableElements = 10,
}
#[derive(
Debug,
Clone,
PartialEq,
Eq,
BorshDeserialize,
BorshSerialize,
serde::Deserialize,
serde::Serialize,
strum::IntoStaticStr,
ProtocolSchema,
)]
#[borsh(use_discriminant = true)]
#[repr(u8)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum WasmTrap {
Unreachable = 0,
IncorrectCallIndirectSignature = 1,
MemoryOutOfBounds = 2,
CallIndirectOOB = 3,
IllegalArithmetic = 4,
MisalignedAtomicAccess = 5,
IndirectCallToNull = 6,
StackOverflow = 7,
GenericTrap = 8,
}
#[derive(
Debug,
Clone,
PartialEq,
Eq,
BorshDeserialize,
BorshSerialize,
serde::Deserialize,
serde::Serialize,
strum::IntoStaticStr,
ProtocolSchema,
)]
#[borsh(use_discriminant = true)]
#[repr(u8)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum HostError {
BadUTF16 = 0,
BadUTF8 = 1,
GasExceeded = 2,
GasLimitExceeded = 3,
BalanceExceeded = 4,
EmptyMethodName = 5,
GuestPanic { panic_msg: String } = 6,
IntegerOverflow = 7,
InvalidPromiseIndex { promise_idx: u64 } = 8,
CannotAppendActionToJointPromise = 9,
CannotReturnJointPromise = 10,
InvalidPromiseResultIndex { result_idx: u64 } = 11,
InvalidRegisterId { register_id: u64 } = 12,
IteratorWasInvalidated { iterator_index: u64 } = 13,
MemoryAccessViolation = 14,
InvalidReceiptIndex { receipt_index: u64 } = 15,
InvalidIteratorIndex { iterator_index: u64 } = 16,
InvalidAccountId = 17,
InvalidMethodName = 18,
InvalidPublicKey = 19,
ProhibitedInView { method_name: String } = 20,
NumberOfLogsExceeded { limit: u64 } = 21,
KeyLengthExceeded { length: u64, limit: u64 } = 22,
ValueLengthExceeded { length: u64, limit: u64 } = 23,
TotalLogLengthExceeded { length: u64, limit: u64 } = 24,
NumberPromisesExceeded { number_of_promises: u64, limit: u64 } = 25,
NumberInputDataDependenciesExceeded { number_of_input_data_dependencies: u64, limit: u64 } = 26,
ReturnedValueLengthExceeded { length: u64, limit: u64 } = 27,
ContractSizeExceeded { size: u64, limit: u64 } = 28,
Deprecated { method_name: String } = 29,
ECRecoverError { msg: String } = 30,
AltBn128InvalidInput { msg: String } = 31,
Ed25519VerifyInvalidInput { msg: String } = 32,
}
#[derive(
Debug,
Clone,
PartialEq,
Eq,
BorshDeserialize,
BorshSerialize,
serde::Deserialize,
serde::Serialize,
strum::IntoStaticStr,
ProtocolSchema,
)]
#[borsh(use_discriminant = true)]
#[repr(u8)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum MethodResolveError {
MethodEmptyName = 0,
MethodNotFound = 1,
MethodInvalidSignature = 2,
}
#[derive(
Debug,
Clone,
PartialEq,
Eq,
BorshDeserialize,
BorshSerialize,
serde::Deserialize,
serde::Serialize,
strum::IntoStaticStr,
ProtocolSchema,
)]
#[borsh(use_discriminant = true)]
#[repr(u8)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum CompilationError {
CodeDoesNotExist {
account_id: AccountId,
} = 0,
PrepareError(PrepareError) = 1,
WasmerCompileError {
msg: String,
} = 2,
}
#[derive(
Debug,
Clone,
PartialEq,
Eq,
BorshDeserialize,
BorshSerialize,
serde::Serialize,
serde::Deserialize,
ProtocolSchema,
)]
#[borsh(use_discriminant = true)]
#[repr(u8)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum FunctionCallError {
CompilationError(CompilationError) = 0,
LinkError {
msg: String,
} = 1,
MethodResolveError(MethodResolveError) = 2,
WasmTrap(WasmTrap) = 3,
WasmUnknownError = 4,
HostError(HostError) = 5,
_EVMError = 6,
ExecutionError(String) = 7,
}
#[derive(Debug)]
pub enum ChunkAccessError {
ChunkMissing(ChunkHash),
}
impl std::fmt::Display for ChunkAccessError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
f.write_str(&format!("{:?}", self))
}
}
impl std::error::Error for ChunkAccessError {}
#[derive(Debug)]
pub enum InvalidSpiceCoreStatementsError {
NoPrevUncertifiedChunks,
NoShardIdsForEpochId { index: usize, error: EpochError },
InvalidCoreStatement { index: usize, reason: &'static str },
SkippedExecutionResult { chunk_id: SpiceChunkId },
NoValidatorAssignments {
shard_id: ShardId,
epoch_id: EpochId,
height_created: BlockHeight,
error: EpochError,
},
NoExecutionResultForEndorsedChunk { chunk_id: SpiceChunkId },
UnknownBlock { block_hash: CryptoHash },
IoError { error: io::Error },
}
impl std::fmt::Display for InvalidSpiceCoreStatementsError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
f.write_str(&format!(" {:?}", self))
}
}
impl std::error::Error for InvalidSpiceCoreStatementsError {}