Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Block err handling #3713

Draft
wants to merge 9 commits into
base: master
Choose a base branch
from
31 changes: 23 additions & 8 deletions packages/block/src/block/block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ import { Blob4844Tx, Capability } from '@ethereumjs/tx'
import {
BIGINT_0,
CLRequestType,
ErrorCode,
KECCAK256_RLP,
KECCAK256_RLP_ARRAY,
UsageError,
ValueError,
bytesToHex,
equalsBytes,
} from '@ethereumjs/util'
Expand Down Expand Up @@ -133,38 +136,50 @@ export class Block {
const msg = this._errorMsg(
'Block initialization with uncleHeaders on a PoA network is not allowed',
)
throw new Error(msg)
throw new UsageError(msg, ErrorCode.INVALID_OPTION_USAGE)
}
if (this.common.consensusType() === ConsensusType.ProofOfStake) {
const msg = this._errorMsg(
'Block initialization with uncleHeaders on a PoS network is not allowed',
)
throw new Error(msg)
throw new UsageError(msg, ErrorCode.INVALID_OPTION_USAGE)
}
}

if (!this.common.isActivatedEIP(4895) && withdrawals !== undefined) {
throw new Error('Cannot have a withdrawals field if EIP 4895 is not active')
throw new UsageError(
'Cannot have a withdrawals field if EIP 4895 is not active',
ErrorCode.EIP_NOT_ACTIVATED,
)
}

if (
!this.common.isActivatedEIP(6800) &&
executionWitness !== undefined &&
executionWitness !== null
) {
throw new Error(`Cannot have executionWitness field if EIP 6800 is not active `)
throw new UsageError(
`Cannot have executionWitness field if EIP 6800 is not active `,
ErrorCode.EIP_NOT_ACTIVATED,
)
}

if (!this.common.isActivatedEIP(7685) && requests !== undefined) {
throw new Error(`Cannot have requests field if EIP 7685 is not active`)
throw new UsageError(
`Cannot have requests field if EIP 7685 is not active`,
ErrorCode.EIP_NOT_ACTIVATED,
)
}

// Requests should be sorted in monotonically ascending order based on type
// and whatever internal sorting logic is defined by each request type
if (requests !== undefined && requests.length > 1) {
for (let x = 1; x < requests.length; x++) {
if (requests[x].type < requests[x - 1].type)
throw new Error('requests are not sorted in ascending order')
throw new ValueError(
'requests are not sorted in ascending order',
ErrorCode.INVALID_VALUE,
)
}
}
const freeze = opts?.freeze ?? true
Expand Down Expand Up @@ -250,7 +265,7 @@ export class Block {

async requestsTrieIsValid(requestsInput?: CLRequest<CLRequestType>[]): Promise<boolean> {
if (!this.common.isActivatedEIP(7685)) {
throw new Error('EIP 7685 is not activated')
throw new UsageError('EIP 7685 is not activated', ErrorCode.EIP_NOT_ACTIVATED)
}

const requests = requestsInput ?? this.requests!
Expand Down Expand Up @@ -459,7 +474,7 @@ export class Block {
*/
async withdrawalsTrieIsValid(): Promise<boolean> {
if (!this.common.isActivatedEIP(4895)) {
throw new Error('EIP 4895 is not activated')
throw new UsageError('EIP 4895 is not activated', ErrorCode.EIP_NOT_ACTIVATED)
}

let result
Expand Down
6 changes: 4 additions & 2 deletions packages/block/src/consensus/clique.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import {
Address,
BIGINT_0,
BIGINT_27,
ErrorCode,
UsageError,
bigIntToBytes,
bytesToBigInt,
concatBytes,
Expand All @@ -28,7 +30,7 @@ export function requireClique(header: BlockHeader, name: string) {
const msg = header['_errorMsg'](
`BlockHeader.${name}() call only supported for clique PoA networks`,
)
throw new Error(msg)
throw new UsageError(msg, ErrorCode.INVALID_METHOD_CALL)
}
}

Expand Down Expand Up @@ -84,7 +86,7 @@ export function cliqueEpochTransitionSigners(header: BlockHeader): Address[] {
requireClique(header, 'cliqueEpochTransitionSigners')
if (!cliqueIsEpochTransition(header)) {
const msg = header['_errorMsg']('Signers are only included in epoch transition blocks (clique)')
throw new Error(msg)
throw new UsageError(msg, ErrorCode.INVALID_METHOD_CALL)
}

const start = CLIQUE_EXTRA_VANITY
Expand Down
26 changes: 19 additions & 7 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 @@ -34,22 +34,34 @@ export function createBlockHeaderFromBytesArray(values: BlockHeaderBytes, opts:
eip1559ActivationBlock !== undefined &&
equalsBytes(eip1559ActivationBlock, number as Uint8Array)
) {
throw new Error('invalid header. baseFeePerGas should be provided')
throw new ValueError(
'invalid header. baseFeePerGas should be provided',
ErrorCode.INVALID_VALUE,
)
}
}
if (header.common.isActivatedEIP(4844)) {
if (excessBlobGas === undefined) {
throw new Error('invalid header. excessBlobGas should be provided')
throw new ValueError(
'invalid header. excessBlobGas should be provided',
ErrorCode.INVALID_VALUE,
)
} else if (blobGasUsed === undefined) {
throw new Error('invalid header. blobGasUsed should be provided')
throw new ValueError(
'invalid header. blobGasUsed should be provided',
ErrorCode.INVALID_VALUE,
)
}
}
if (header.common.isActivatedEIP(4788) && parentBeaconBlockRoot === undefined) {
throw new Error('invalid header. parentBeaconBlockRoot should be provided')
throw new ValueError(
'invalid header. parentBeaconBlockRoot should be provided',
ErrorCode.INVALID_VALUE,
)
}

if (header.common.isActivatedEIP(7685) && requestsRoot === undefined) {
throw new Error('invalid header. requestsRoot should be provided')
throw new ValueError('invalid header. requestsRoot should be provided', ErrorCode.INVALID_VALUE)
}
return header
}
Expand All @@ -66,7 +78,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
76 changes: 51 additions & 25 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 Down Expand Up @@ -75,10 +78,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 @@ -179,7 +185,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 @@ -258,33 +267,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 msg = this._errorMsg(
`transactionsTrie must be 32 bytes, received ${transactionsTrie.length} bytes`,
)
throw new Error(msg)
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 @@ -429,8 +446,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 @@ -659,14 +677,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
Loading
Loading