1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
//! Error module for the bus-mapping crate
use core::fmt::{Display, Formatter, Result as FmtResult};
use eth_types::{evm_types::OpcodeId, Address, GethExecStep, Word, H256};
use ethers_providers::ProviderError;
use std::error::Error as StdError;
use crate::geth_errors::{
GETH_ERR_GAS_UINT_OVERFLOW, GETH_ERR_OUT_OF_GAS, GETH_ERR_STACK_OVERFLOW,
GETH_ERR_STACK_UNDERFLOW,
};
/// Error type for any BusMapping related failure.
#[derive(Debug)]
pub enum Error {
/// Serde de/serialization error.
SerdeError(serde_json::error::Error),
/// JSON-RPC related error.
JSONRpcError(ProviderError),
/// OpcodeId is not a call type.
OpcodeIdNotCallType,
/// Account not found in the StateDB
AccountNotFound(Address),
/// Storage key not found in the StateDB
StorageKeyNotFound(Address, Word),
/// Address not found in the CodeDB,
AddressNotFound(Address),
/// Code not found in the CodeDB
CodeNotFound(H256),
/// Unable to figure out error at a [`GethExecStep`]
UnexpectedExecStepError(&'static str, Box<GethExecStep>),
/// Invalid [`eth_types::GethExecTrace`] due to an invalid/unexpected value
/// in it.
InvalidGethExecTrace(&'static str),
/// Invalid [`GethExecStep`] due to an invalid/unexpected value in it.
InvalidGethExecStep(&'static str, Box<GethExecStep>),
/// Eth type related error.
EthTypeError(eth_types::Error),
/// EVM Execution error
ExecutionError(ExecError),
/// Internal Code error
InternalError(&'static str),
/// Rw number overflow
RwsNotEnough(usize, usize),
}
impl From<eth_types::Error> for Error {
fn from(err: eth_types::Error) -> Self {
Error::EthTypeError(err)
}
}
impl From<ProviderError> for Error {
fn from(err: ProviderError) -> Self {
Error::JSONRpcError(err)
}
}
impl Display for Error {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
write!(f, "{:?}", self)
}
}
impl StdError for Error {}
/// Out of Gas errors by opcode
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum OogError {
/// Out of Gas for opcodes which have non-zero constant gas cost
Constant,
/// Out of Gas for MLOAD, MSTORE, MSTORE8, which have static memory
/// expansion gas cost
StaticMemoryExpansion,
/// Out of Gas for CREATE, RETURN, REVERT, which have dynamic memory
/// expansion gas cost
DynamicMemoryExpansion,
/// Out of Gas for CALLDATACOPY, CODECOPY, EXTCODECOPY, RETURNDATACOPY,
/// which copy a specified chunk of memory
MemoryCopy,
/// Out of Gas for BALANCE, EXTCODESIZE, EXTCODEHASH, which possibly touch
/// an extra account
AccountAccess,
/// Out of Gas for RETURN which has code storing gas cost when it's is
/// creation
CodeStore,
/// Out of Gas for LOG0, LOG1, LOG2, LOG3, LOG4
Log,
/// Out of Gas for EXP
Exp,
/// Out of Gas for SHA3
Sha3,
/// Out of Gas for SLOAD and SSTORE
SloadSstore,
/// Out of Gas for CALL, CALLCODE, DELEGATECALL and STATICCALL
Call,
/// Out of Gas for Precompile.
/// ecrecover/ecadd/ecmul/ecpairing/identity oog should be handled by this.
/// modexp oog is handled inside modexp gadget.
/// disabled precompiles are handled by PrecompileFailedGadget.
Precompile,
/// Out of Gas for CREATE and CREATE2
Create,
/// Out of Gas for SELFDESTRUCT
SelfDestruct,
}
// Given OpCodeId, returns corresponding OogError.
impl From<&OpcodeId> for OogError {
fn from(op: &OpcodeId) -> Self {
match op {
OpcodeId::MLOAD | OpcodeId::MSTORE | OpcodeId::MSTORE8 => {
OogError::StaticMemoryExpansion
}
OpcodeId::RETURN | OpcodeId::REVERT => OogError::DynamicMemoryExpansion,
OpcodeId::CALLDATACOPY
| OpcodeId::CODECOPY
| OpcodeId::EXTCODECOPY
| OpcodeId::RETURNDATACOPY => OogError::MemoryCopy,
OpcodeId::BALANCE | OpcodeId::EXTCODESIZE | OpcodeId::EXTCODEHASH => {
OogError::AccountAccess
}
OpcodeId::LOG0 | OpcodeId::LOG1 | OpcodeId::LOG2 | OpcodeId::LOG3 | OpcodeId::LOG4 => {
OogError::Log
}
OpcodeId::EXP => OogError::Exp,
OpcodeId::SHA3 => OogError::Sha3,
OpcodeId::CALL | OpcodeId::CALLCODE | OpcodeId::DELEGATECALL | OpcodeId::STATICCALL => {
OogError::Call
}
OpcodeId::SLOAD | OpcodeId::SSTORE => OogError::SloadSstore,
OpcodeId::CREATE | OpcodeId::CREATE2 => OogError::Create,
OpcodeId::SELFDESTRUCT => OogError::SelfDestruct,
_ => OogError::Constant,
}
}
}
/// Insufficient balance errors by opcode/state.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum InsufficientBalanceError {
/// Insufficient balance during CALL/CALLCODE opcode.
Call,
/// Insufficient balance during CREATE opcode.
Create,
/// Insufficient balance during CREATE2 opcode.
Create2,
}
/// Nonce uint overflow errors by opcode/state.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum NonceUintOverflowError {
/// Nonce uint overflow during CREATE opcode.
Create,
/// Nonce uint overflow during CREATE2 opcode.
Create2,
}
/// Call depth errors by opcode/state.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum DepthError {
/// Call depth errors in CALL/CALLCODE opcode.
Call,
/// Call depth errors in CREATE opcode.
Create,
/// Call depth errors in CREATE2 opcode.
Create2,
}
/// EVM Execution Error
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ExecError {
/// Invalid Opcode
InvalidOpcode,
/// For opcodes who push more than pop
StackOverflow,
/// For opcodes which pop, DUP and SWAP, which peek deeper element directly
StackUnderflow,
/// Out of Gas
OutOfGas(OogError),
/// For SSTORE, LOG0, LOG1, LOG2, LOG3, LOG4, CREATE, CALL, CREATE2,
/// SELFDESTRUCT
WriteProtection,
/// For CALL, CALLCODE, DELEGATECALL, STATICCALL, CREATE, CREATE2
Depth(DepthError),
/// For CALL, CALLCODE, CREATE, CREATE2
InsufficientBalance(InsufficientBalanceError),
/// For CREATE2
ContractAddressCollision,
/// contract must not begin with 0xef due to EIP #3541 EVM Object Format
/// (EOF)
InvalidCreationCode,
/// For JUMP, JUMPI
InvalidJump,
/// For RETURNDATACOPY
ReturnDataOutOfBounds,
/// For RETURN in a CREATE, CREATE2
CodeStoreOutOfGas,
/// For RETURN in a CREATE, CREATE2
MaxCodeSizeExceeded,
/// For CALL, CALLCODE, DELEGATECALL, STATICCALL
UnimplementedPrecompiles,
/// For CREATE, CREATE2
NonceUintOverflow(NonceUintOverflowError),
}
// Returns a GethExecStep's error if present, else return the empty error.
impl TryFrom<&GethExecStep> for ExecError {
type Error = ();
fn try_from(step: &GethExecStep) -> Result<Self, Self::Error> {
Ok(match step.error.as_ref().ok_or(())?.as_str() {
GETH_ERR_OUT_OF_GAS | GETH_ERR_GAS_UINT_OVERFLOW => {
// NOTE: We report a GasUintOverflow error as an OutOfGas error
let oog_err = OogError::from(&step.op);
ExecError::OutOfGas(oog_err)
}
error => {
if error.starts_with(GETH_ERR_STACK_OVERFLOW) {
ExecError::StackOverflow
} else if error.starts_with(GETH_ERR_STACK_UNDERFLOW) {
ExecError::StackUnderflow
} else {
panic!("Unknown GethExecStep.error: {}", error);
}
}
})
}
}