Skip to content

Commit

Permalink
Util, Block: Removed 2-layer error structure, removed local package e…
Browse files Browse the repository at this point in the history
…rrors file, moved error codes to Util
  • Loading branch information
holgerd77 authored and jochem-brouwer committed Sep 30, 2024
1 parent 0c9ba5e commit 2f904ab
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 79 deletions.
33 changes: 0 additions & 33 deletions packages/block/src/errors.ts

This file was deleted.

4 changes: 2 additions & 2 deletions packages/block/src/header/constructors.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { RLP } from '@ethereumjs/rlp'
import { bigIntToBytes, equalsBytes } from '@ethereumjs/util'
import { ErrorCode, ValueError, bigIntToBytes, equalsBytes } from '@ethereumjs/util'

import { generateCliqueBlockExtraData } from '../consensus/clique.js'
import { numberToHex, valuesArrayToHeaderData } from '../helpers.js'
Expand Down Expand Up @@ -66,7 +66,7 @@ export function createBlockHeaderFromRLP(
) {
const values = RLP.decode(serializedHeaderData)
if (!Array.isArray(values)) {
throw new Error('Invalid serialized header input. Must be array')
throw new ValueError('Invalid serialized header input. Must be array', ErrorCode.INVALID_VALUE)
}
return createBlockHeaderFromBytesArray(values as Uint8Array[], opts)
}
Expand Down
82 changes: 51 additions & 31 deletions packages/block/src/header/header.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ import {
BIGINT_1,
BIGINT_2,
BIGINT_7,
ErrorCode,
KECCAK256_RLP,
KECCAK256_RLP_ARRAY,
TypeOutput,
UsageError,
ValueError,
bigIntToHex,
bigIntToUnpaddedBytes,
bytesToHex,
Expand All @@ -26,7 +29,6 @@ import {
CLIQUE_EXTRA_VANITY,
cliqueIsEpochTransition,
} from '../consensus/clique.js'
import { HeaderValidationError, ValidationErrorCode } from '../errors.js'
import { fakeExponential } from '../helpers.js'
import { paramsBlock } from '../params.js'

Expand Down Expand Up @@ -77,10 +79,13 @@ export class BlockHeader {
*/
get prevRandao() {
if (!this.common.isActivatedEIP(4399)) {
const msg = this._errorMsg(
throw new UsageError(
'The prevRandao parameter can only be accessed when EIP-4399 is activated',
ErrorCode.EIP_NOT_ACTIVATED,
{
objectContext: this.errorStr(),
},
)
throw new Error(msg)
}
return this.mixHash
}
Expand Down Expand Up @@ -181,7 +186,10 @@ export class BlockHeader {
toType(headerData.requestsRoot, TypeOutput.Uint8Array) ?? hardforkDefaults.requestsRoot

if (!this.common.isActivatedEIP(1559) && baseFeePerGas !== undefined) {
throw new Error('A base fee for a block can only be set with EIP1559 being activated')
throw new UsageError(
'A base fee for a block can only be set with EIP1559 being activated',
ErrorCode.EIP_NOT_ACTIVATED,
)
}

if (!this.common.isActivatedEIP(4895) && withdrawalsRoot !== undefined) {
Expand Down Expand Up @@ -260,38 +268,41 @@ export class BlockHeader {
const { parentHash, stateRoot, transactionsTrie, receiptTrie, mixHash, nonce } = this

if (parentHash.length !== 32) {
const msg = this._errorMsg(`parentHash must be 32 bytes, received ${parentHash.length} bytes`)
throw new Error(msg)
throw new ValueError(`parentHash must be 32 bytes`, ErrorCode.INVALID_VALUE_LENGTH, {
objectContext: this.errorStr(),
received: `${parentHash.length} bytes`,
})
}
if (stateRoot.length !== 32) {
const msg = this._errorMsg(`stateRoot must be 32 bytes, received ${stateRoot.length} bytes`)
throw new Error(msg)
throw new ValueError(`stateRoot must be 32 bytes`, ErrorCode.INVALID_VALUE_LENGTH, {
objectContext: this.errorStr(),
received: `${stateRoot.length} bytes`,
})
}
if (transactionsTrie.length !== 32) {
const e = new HeaderValidationError(
'transactionsTrie must be 32 bytes',
ValidationErrorCode.WRONG_TX_TRIE_LENGTH,
{
block: this.errorStr(),
received: `${bytesToHex(transactionsTrie)} (${transactionsTrie.length} bytes)`,
},
)
throw e
throw new ValueError('transactionsTrie must be 32 bytes', ErrorCode.INVALID_VALUE_LENGTH, {
objectContext: this.errorStr(),
received: `${bytesToHex(transactionsTrie)} (${transactionsTrie.length} bytes)`,
})
}
if (receiptTrie.length !== 32) {
const msg = this._errorMsg(
`receiptTrie must be 32 bytes, received ${receiptTrie.length} bytes`,
)
throw new Error(msg)
throw new ValueError('receiptTrie must be 32 bytes', ErrorCode.INVALID_VALUE_LENGTH, {
objectContext: this.errorStr(),
received: `${bytesToHex(receiptTrie)} (${receiptTrie.length} bytes)`,
})
}
if (mixHash.length !== 32) {
const msg = this._errorMsg(`mixHash must be 32 bytes, received ${mixHash.length} bytes`)
throw new Error(msg)
throw new ValueError('mixHash must be 32 bytes', ErrorCode.INVALID_VALUE_LENGTH, {
objectContext: this.errorStr(),
received: `${bytesToHex(mixHash)} (${mixHash.length} bytes)`,
})
}

if (nonce.length !== 8) {
const msg = this._errorMsg(`nonce must be 8 bytes, received ${nonce.length} bytes`)
throw new Error(msg)
throw new ValueError('nonce must be 8 bytes', ErrorCode.INVALID_VALUE_LENGTH, {
objectContext: this.errorStr(),
received: `${bytesToHex(nonce)} (${nonce.length} bytes)`,
})
}

// check if the block used too much gas
Expand Down Expand Up @@ -436,8 +447,9 @@ export class BlockHeader {
}
}
if (error) {
const msg = this._errorMsg(`Invalid PoS block: ${errorMsg}`)
throw new Error(msg)
throw new ValueError(`Invalid PoS block${errorMsg}`, ErrorCode.INVALID_OBJECT, {
objectContext: this.errorStr(),
})
}
}
}
Expand Down Expand Up @@ -666,14 +678,22 @@ export class BlockHeader {
*/
ethashCanonicalDifficulty(parentBlockHeader: BlockHeader): bigint {
if (this.common.consensusType() !== ConsensusType.ProofOfWork) {
const msg = this._errorMsg('difficulty calculation is only supported on PoW chains')
throw new Error(msg)
throw new UsageError(
'difficulty calculation is only supported on PoW chains',
ErrorCode.INVALID_METHOD_CALL,
{
objectContext: this.errorStr(),
},
)
}
if (this.common.consensusAlgorithm() !== ConsensusAlgorithm.Ethash) {
const msg = this._errorMsg(
throw new UsageError(
'difficulty calculation currently only supports the ethash algorithm',
ErrorCode.INVALID_METHOD_CALL,
{
objectContext: this.errorStr(),
},
)
throw new Error(msg)
}
const blockTs = this.timestamp
const { timestamp: parentTs, difficulty: parentDif } = parentBlockHeader
Expand Down
70 changes: 57 additions & 13 deletions packages/util/src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,45 +4,89 @@
* Kudos to https://github.com/ChainSafe/lodestar monorepo
* for the inspiration :-)
*/
export class EthereumJSError<T extends {}> extends Error {
type EthereumJSErrorType = {
objectContext: string
}

export class EthereumJSError<T> extends Error {
code: string
errorContext: T
context: T | {}

constructor(msg: string, code: string, errorContext: T) {
constructor(msg: string, code: string, context?: T) {
super(msg)
this.code = code
this.errorContext = errorContext
this.context = context ?? {}
}

getErrorContext(): Record<string, string | number | null> {
return { code: this.code, ...this.errorContext }
getContext(): Record<string, string | number | null> {
return { code: this.code, ...this.context }
}

/**
* Get the metadata and the stacktrace for the error.
*/
toObject(): Record<string, string | number | null> {
return {
...this.getErrorContext(),
...this.getContext(),
stack: this.stack ?? '',
}
}
}

export type ValidationErrorType = {
received: string
/**
* Error Codes
*/
export enum ErrorCode {
// Value Errors
INVALID_OBJECT = 'INVALID_OBJECT',
INVALID_VALUE = 'INVALID_VALUE',
INVALID_VALUE_LENGTH = 'INVALID_VALUE_LENGTH',
TOO_FEW_VALUES = 'TOO_FEW_VALUES',
TOO_MANY_VALUES = 'TOO_MANY_VALUES',

// Usage Errors
EIP_NOT_ACTIVATED = 'EIP_NOT_ACTIVATED',
INCOMPATIBLE_LIBRARY_VERSION = 'INCOMPATIBLE_LIBRARY_VERSION',
INVALID_OPTION_USAGE = 'INVALID_OPTION_USAGE',
INVALID_METHOD_CALL = 'INVALID_METHOD_CALL',
}

/**
* Error along Object Validation
* Generic error types
*/

/**
* Type flavors for ValueError
*/
export type ValueErrorType =
| {
received: string
}
| {
objectContext: string
received: string
}
| EthereumJSErrorType

/**
* Type flavors for UsageError
*/
export type UsageErrorType = EthereumJSErrorType

/**
* Generic Errors
*
* Use directly or in a subclassed context for error comparison (`e instanceof ValidationError`)
* Use directly or in a subclassed context for error comparison (`e instanceof ValueError`)
*/

/**
* Error along Object Value
*/
export class ValidationError<T extends ValidationErrorType> extends EthereumJSError<T> {}
export class ValueError extends EthereumJSError<ValueErrorType> {}

/**
* Error along API Usage
*
* Use directly or in a subclassed context for error comparison (`e instanceof UsageError`)
*/
export class UsageError<T extends {}> extends EthereumJSError<T> {}
export class UsageError extends EthereumJSError<UsageErrorType> {}

0 comments on commit 2f904ab

Please sign in to comment.