Skip to content

Commit 58c9057

Browse files
Squashed commit of the following:
commit 85aa5fa Author: Jochem Brouwer <[email protected]> Date: Mon Feb 24 05:57:39 2025 +0100 lint: add rule to disallow `new Error` throwing commit 1e97567 Merge: a8cd9e1 bd77a74 Author: Jochem Brouwer <[email protected]> Date: Mon Feb 24 05:44:30 2025 +0100 Merge branch 'master' into evm-error-handling commit a8cd9e1 Author: Jochem Brouwer <[email protected]> Date: Mon Feb 24 05:44:21 2025 +0100 util: introduce new temp error with unset error code commit aa3702b Author: Jochem Brouwer <[email protected]> Date: Mon Feb 10 16:04:41 2025 +0100 vm/client: fix build commit 16d1b38 Author: Jochem Brouwer <[email protected]> Date: Mon Feb 10 15:40:57 2025 +0100 evm/util: update to new, simpler error format commit ec01f1b Author: Jochem Brouwer <[email protected]> Date: Mon Feb 10 14:37:24 2025 +0100 util: update base error class commit 70b2df5 Merge: 293f4cc 1774df6 Author: Jochem Brouwer <[email protected]> Date: Mon Feb 10 14:22:35 2025 +0100 Merge branch 'master' into evm-error-handling commit 293f4cc Merge: b4458d7 99cfdd6 Author: Jochem Brouwer <[email protected]> Date: Tue Jan 14 03:04:15 2025 +0100 Merge branch 'master' into evm-error-handling commit b4458d7 Merge: 71e77dc 100d77d Author: Jochem Brouwer <[email protected]> Date: Fri Dec 13 17:50:26 2024 +0100 Merge branch 'master' into evm-error-handling commit 71e77dc Author: Jochem Brouwer <[email protected]> Date: Tue Oct 1 13:57:38 2024 +0200 evm: fix err handling commit d00b7bf Author: Jochem Brouwer <[email protected]> Date: Tue Oct 1 13:46:08 2024 +0200 evm/util: error overhaul
1 parent 8585be6 commit 58c9057

26 files changed

+627
-184
lines changed

packages/client/src/rpc/modules/eth.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -521,7 +521,7 @@ export class Eth {
521521
throw {
522522
code: 3,
523523
data: bytesToHex(execResult.returnValue),
524-
message: execResult.exceptionError.error,
524+
message: execResult.exceptionError.type.code,
525525
}
526526
}
527527
return bytesToHex(execResult.returnValue)

packages/evm/src/exceptions.ts renamed to packages/evm/src/errors.ts

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
export enum ERROR {
1+
import { EthereumJSError } from '@ethereumjs/util'
2+
3+
import type { EOFError } from './eof/errors.js'
4+
5+
// TODO: merge EOF errors in here
6+
export enum EVMErrorCode {
27
OUT_OF_GAS = 'out of gas',
38
CODESTORE_OUT_OF_GAS = 'code store out of gas',
49
CODESIZE_EXCEEDS_MAXIMUM = 'code size to deposit exceeds maximum code size',
@@ -15,13 +20,11 @@ export enum ERROR {
1520
REFUND_EXHAUSTED = 'refund exhausted',
1621
VALUE_OVERFLOW = 'value overflow',
1722
INSUFFICIENT_BALANCE = 'insufficient balance',
18-
INVALID_BEGINSUB = 'invalid BEGINSUB',
19-
INVALID_RETURNSUB = 'invalid RETURNSUB',
20-
INVALID_JUMPSUB = 'invalid JUMPSUB',
2123
INVALID_BYTECODE_RESULT = 'invalid bytecode deployed',
2224
INITCODE_SIZE_VIOLATION = 'initcode exceeds max initcode size',
2325
INVALID_INPUT_LENGTH = 'invalid input length',
2426
INVALID_EOF_FORMAT = 'invalid EOF format',
27+
INVALID_PRECOMPILE = 'invalid precompile',
2528

2629
// BLS errors
2730
BLS_12_381_INVALID_INPUT_LENGTH = 'invalid input length',
@@ -38,12 +41,16 @@ export enum ERROR {
3841
INVALID_PROOF = 'kzg proof invalid',
3942
}
4043

41-
export class EvmError {
42-
error: ERROR
43-
errorType: string
44+
type EVMErrorType =
45+
| {
46+
code: EVMErrorCode | EOFError
47+
}
48+
| { code: EVMErrorCode.REVERT; revertBytes: Uint8Array }
4449

45-
constructor(error: ERROR) {
46-
this.error = error
47-
this.errorType = 'EvmError'
50+
export class EVMError extends EthereumJSError<EVMErrorType> {
51+
constructor(type: EVMErrorType, message?: string) {
52+
super(type, message)
4853
}
54+
55+
// TODO: add helper method to format the error in a human readable way
4956
}

packages/evm/src/evm.ts

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import {
99
KECCAK256_NULL,
1010
KECCAK256_RLP,
1111
MAX_INTEGER,
12+
UsageError,
13+
UsageErrorType,
1214
bigIntToBytes,
1315
bytesToUnprefixedHex,
1416
createZeroAddress,
@@ -22,7 +24,7 @@ import { EventEmitter } from 'eventemitter3'
2224

2325
import { FORMAT } from './eof/constants.js'
2426
import { isEOF } from './eof/util.js'
25-
import { ERROR, EvmError } from './exceptions.js'
27+
import { EVMError, EVMErrorCode } from './errors.js'
2628
import { Interpreter } from './interpreter.js'
2729
import { Journal } from './journal.js'
2830
import { EVMPerformanceLogger } from './logger.js'
@@ -443,7 +445,9 @@ export class EVM implements EVMInterface {
443445
createdAddress: message.to,
444446
execResult: {
445447
returnValue: new Uint8Array(0),
446-
exceptionError: new EvmError(ERROR.INITCODE_SIZE_VIOLATION),
448+
exceptionError: new EVMError({
449+
code: EVMErrorCode.INITCODE_SIZE_VIOLATION,
450+
}),
447451
executionGasUsed: message.gasLimit,
448452
},
449453
}
@@ -502,7 +506,9 @@ export class EVM implements EVMInterface {
502506
createdAddress: message.to,
503507
execResult: {
504508
returnValue: new Uint8Array(0),
505-
exceptionError: new EvmError(ERROR.CREATE_COLLISION),
509+
exceptionError: new EVMError({
510+
code: EVMErrorCode.CREATE_COLLISION,
511+
}),
506512
executionGasUsed: message.gasLimit,
507513
},
508514
}
@@ -803,8 +809,8 @@ export class EVM implements EVMInterface {
803809
let gasUsed = message.gasLimit - interpreterRes.runState!.gasLeft
804810
if (interpreterRes.exceptionError) {
805811
if (
806-
interpreterRes.exceptionError.error !== ERROR.REVERT &&
807-
interpreterRes.exceptionError.error !== ERROR.INVALID_EOF_FORMAT
812+
interpreterRes.exceptionError.type.code !== EVMErrorCode.REVERT &&
813+
interpreterRes.exceptionError.type.code !== EVMErrorCode.INVALID_EOF_FORMAT
808814
) {
809815
gasUsed = message.gasLimit
810816
}
@@ -941,7 +947,7 @@ export class EVM implements EVMInterface {
941947
const { executionGasUsed, exceptionError, returnValue } = result.execResult
942948
debug(
943949
`Received message execResult: [ gasUsed=${executionGasUsed} exceptionError=${
944-
exceptionError ? `'${exceptionError.error}'` : 'none'
950+
exceptionError ? `'${exceptionError.type.code}'` : 'none'
945951
} returnValue=${short(returnValue)} gasRefund=${result.execResult.gasRefund ?? 0} ]`,
946952
)
947953
}
@@ -951,14 +957,17 @@ export class EVM implements EVMInterface {
951957
// There is one exception: if the CODESTORE_OUT_OF_GAS error is thrown
952958
// (this only happens the Frontier/Chainstart fork)
953959
// then the error is dismissed
954-
if (err && err.error !== ERROR.CODESTORE_OUT_OF_GAS) {
960+
if (err && err.type.code !== EVMErrorCode.CODESTORE_OUT_OF_GAS) {
955961
result.execResult.selfdestruct = new Set()
956962
result.execResult.createdAddresses = new Set()
957963
result.execResult.gasRefund = BIGINT_0
958964
}
959965
if (
960966
err &&
961-
!(this.common.hardfork() === Hardfork.Chainstart && err.error === ERROR.CODESTORE_OUT_OF_GAS)
967+
!(
968+
this.common.hardfork() === Hardfork.Chainstart &&
969+
err.type.code === EVMErrorCode.CODESTORE_OUT_OF_GAS
970+
)
962971
) {
963972
result.execResult.logs = []
964973
await this.journal.revert()
@@ -1028,7 +1037,9 @@ export class EVM implements EVMInterface {
10281037
gasLimit: bigint,
10291038
): Promise<ExecResult> | ExecResult {
10301039
if (typeof code !== 'function') {
1031-
throw EthereumJSErrorUnsetCode('Invalid precompile')
1040+
throw new EVMError({
1041+
code: EVMErrorCode.INVALID_PRECOMPILE,
1042+
})
10321043
}
10331044

10341045
const opts = {
@@ -1088,7 +1099,9 @@ export class EVM implements EVMInterface {
10881099
protected async _reduceSenderBalance(account: Account, message: Message): Promise<void> {
10891100
account.balance -= message.value
10901101
if (account.balance < BIGINT_0) {
1091-
throw new EvmError(ERROR.INSUFFICIENT_BALANCE)
1102+
throw new EVMError({
1103+
code: EVMErrorCode.INSUFFICIENT_BALANCE,
1104+
})
10921105
}
10931106
const result = this.journal.putAccount(message.caller, account)
10941107
if (this.DEBUG) {
@@ -1100,7 +1113,9 @@ export class EVM implements EVMInterface {
11001113
protected async _addToBalance(toAccount: Account, message: MessageWithTo): Promise<void> {
11011114
const newBalance = toAccount.balance + message.value
11021115
if (newBalance > MAX_INTEGER) {
1103-
throw new EvmError(ERROR.VALUE_OVERFLOW)
1116+
throw new EVMError({
1117+
code: EVMErrorCode.VALUE_OVERFLOW,
1118+
})
11041119
}
11051120
toAccount.balance = newBalance
11061121
// putAccount as the nonce may have changed for contract creation
@@ -1148,47 +1163,58 @@ export class EVM implements EVMInterface {
11481163
}
11491164
}
11501165

1166+
// TODO clean me up
11511167
export function OOGResult(gasLimit: bigint): ExecResult {
11521168
return {
11531169
returnValue: new Uint8Array(0),
11541170
executionGasUsed: gasLimit,
1155-
exceptionError: new EvmError(ERROR.OUT_OF_GAS),
1171+
exceptionError: new EVMError({
1172+
code: EVMErrorCode.OUT_OF_GAS,
1173+
}),
11561174
}
11571175
}
11581176
// CodeDeposit OOG Result
11591177
export function COOGResult(gasUsedCreateCode: bigint): ExecResult {
11601178
return {
11611179
returnValue: new Uint8Array(0),
11621180
executionGasUsed: gasUsedCreateCode,
1163-
exceptionError: new EvmError(ERROR.CODESTORE_OUT_OF_GAS),
1181+
exceptionError: new EVMError({
1182+
code: EVMErrorCode.OUT_OF_GAS,
1183+
}),
11641184
}
11651185
}
11661186

11671187
export function INVALID_BYTECODE_RESULT(gasLimit: bigint): ExecResult {
11681188
return {
11691189
returnValue: new Uint8Array(0),
11701190
executionGasUsed: gasLimit,
1171-
exceptionError: new EvmError(ERROR.INVALID_BYTECODE_RESULT),
1191+
exceptionError: new EVMError({
1192+
code: EVMErrorCode.INVALID_BYTECODE_RESULT,
1193+
}),
11721194
}
11731195
}
11741196

11751197
export function INVALID_EOF_RESULT(gasLimit: bigint): ExecResult {
11761198
return {
11771199
returnValue: new Uint8Array(0),
11781200
executionGasUsed: gasLimit,
1179-
exceptionError: new EvmError(ERROR.INVALID_EOF_FORMAT),
1201+
exceptionError: new EVMError({
1202+
code: EVMErrorCode.INVALID_EOF_FORMAT,
1203+
}),
11801204
}
11811205
}
11821206

11831207
export function CodesizeExceedsMaximumError(gasUsed: bigint): ExecResult {
11841208
return {
11851209
returnValue: new Uint8Array(0),
11861210
executionGasUsed: gasUsed,
1187-
exceptionError: new EvmError(ERROR.CODESIZE_EXCEEDS_MAXIMUM),
1211+
exceptionError: new EVMError({
1212+
code: EVMErrorCode.CODESIZE_EXCEEDS_MAXIMUM,
1213+
}),
11881214
}
11891215
}
11901216

1191-
export function EvmErrorResult(error: EvmError, gasUsed: bigint): ExecResult {
1217+
export function EvmErrorResult(error: EVMError, gasUsed: bigint): ExecResult {
11921218
return {
11931219
returnValue: new Uint8Array(0),
11941220
executionGasUsed: gasUsed,

packages/evm/src/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { EOFContainer, validateEOF } from './eof/container.js'
2+
import { EVMError, EVMErrorCode } from './errors.js'
23
import { EVM } from './evm.js'
3-
import { ERROR as EVMErrorMessage, EvmError } from './exceptions.js'
44
import { Message } from './message.js'
55
import { getOpcodesForHF } from './opcodes/index.js'
66
import {
@@ -46,8 +46,8 @@ export type {
4646
export {
4747
EOFContainer,
4848
EVM,
49-
EvmError,
50-
EVMErrorMessage,
49+
EVMError,
50+
EVMErrorCode,
5151
EVMMockBlockchain,
5252
getActivePrecompiles,
5353
getOpcodesForHF,

0 commit comments

Comments
 (0)