diff --git a/packages/block/src/block.ts b/packages/block/src/block.ts index 579d1daa33..e4426e3fbc 100644 --- a/packages/block/src/block.ts +++ b/packages/block/src/block.ts @@ -2,7 +2,7 @@ import { ConsensusType } from '@ethereumjs/common' import { RLP } from '@ethereumjs/rlp' import { Trie } from '@ethereumjs/trie' import { Capability, TransactionFactory } from '@ethereumjs/tx' -import { KECCAK256_RLP, arrToBufArr, bufArrToArr, bufferToHex, isTruthy } from '@ethereumjs/util' +import { KECCAK256_RLP, arrToBufArr, bufArrToArr, bufferToHex } from '@ethereumjs/util' import { keccak256 } from 'ethereum-cryptography/keccak' import { BlockHeader } from './header' @@ -104,7 +104,7 @@ export class Block { // parse transactions const transactions = [] - for (const txData of isTruthy(txsData) ? txsData : []) { + for (const txData of txsData ?? []) { transactions.push( TransactionFactory.fromBlockBodyData(txData, { ...opts, @@ -130,7 +130,7 @@ export class Block { if (opts?.hardforkByTTD !== undefined) { uncleOpts.hardforkByBlockNumber = true } - for (const uncleHeaderData of isTruthy(uhsData) ? uhsData : []) { + for (const uncleHeaderData of uhsData ?? []) { uncleHeaders.push(BlockHeader.fromValuesArray(uncleHeaderData, uncleOpts)) } diff --git a/packages/block/src/from-rpc.ts b/packages/block/src/from-rpc.ts index e6fc4841a7..cc4178f276 100644 --- a/packages/block/src/from-rpc.ts +++ b/packages/block/src/from-rpc.ts @@ -1,12 +1,12 @@ import { TransactionFactory } from '@ethereumjs/tx' -import { isTruthy, setLengthLeft, toBuffer } from '@ethereumjs/util' +import { setLengthLeft, toBuffer } from '@ethereumjs/util' import { blockHeaderFromRpc } from './header-from-rpc' import { numberToHex } from './helpers' import { Block } from './index' -import type { BlockOptions } from './index' +import type { BlockOptions, JsonRpcBlock } from './index' import type { TxData, TypedTransaction } from '@ethereumjs/tx' function normalizeTxParams(_txParams: any) { @@ -20,7 +20,10 @@ function normalizeTxParams(_txParams: any) { txParams.value = numberToHex(txParams.value) // strict byte length checking - txParams.to = isTruthy(txParams.to) ? setLengthLeft(toBuffer(txParams.to), 20) : null + txParams.to = + txParams.to !== null && txParams.to !== undefined + ? setLengthLeft(toBuffer(txParams.to), 20) + : null // v as raw signature value {0,1} // v is the recovery bit and can be either {0,1} or {27,28}. @@ -38,17 +41,19 @@ function normalizeTxParams(_txParams: any) { * @param uncles - Optional list of Ethereum JSON RPC of uncles (eth_getUncleByBlockHashAndIndex) * @param options - An object describing the blockchain */ -export function blockFromRpc(blockParams: any, uncles: any[] = [], options?: BlockOptions) { +export function blockFromRpc( + blockParams: JsonRpcBlock, + uncles: any[] = [], + options?: BlockOptions +) { const header = blockHeaderFromRpc(blockParams, options) const transactions: TypedTransaction[] = [] - if (isTruthy(blockParams.transactions)) { - const opts = { common: header._common } - for (const _txParams of blockParams.transactions) { - const txParams = normalizeTxParams(_txParams) - const tx = TransactionFactory.fromTxData(txParams as TxData, opts) - transactions.push(tx) - } + const opts = { common: header._common } + for (const _txParams of blockParams.transactions) { + const txParams = normalizeTxParams(_txParams) + const tx = TransactionFactory.fromTxData(txParams as TxData, opts) + transactions.push(tx) } const uncleHeaders = uncles.map((uh) => blockHeaderFromRpc(uh, options)) diff --git a/packages/block/src/header-from-rpc.ts b/packages/block/src/header-from-rpc.ts index 5c005bd858..070befc301 100644 --- a/packages/block/src/header-from-rpc.ts +++ b/packages/block/src/header-from-rpc.ts @@ -1,7 +1,7 @@ import { BlockHeader } from './header' import { numberToHex } from './helpers' -import type { BlockOptions } from './types' +import type { BlockOptions, JsonRpcBlock } from './types' /** * Creates a new block header object from Ethereum JSON RPC. @@ -9,7 +9,7 @@ import type { BlockOptions } from './types' * @param blockParams - Ethereum JSON RPC of block (eth_getBlockByNumber) * @param options - An object describing the blockchain */ -export function blockHeaderFromRpc(blockParams: any, options?: BlockOptions) { +export function blockHeaderFromRpc(blockParams: JsonRpcBlock, options?: BlockOptions) { const { parentHash, sha3Uncles, diff --git a/packages/block/src/header.ts b/packages/block/src/header.ts index b7bd067973..f99e584208 100644 --- a/packages/block/src/header.ts +++ b/packages/block/src/header.ts @@ -14,8 +14,6 @@ import { bufferToHex, ecrecover, ecsign, - isFalsy, - isTruthy, toType, zeros, } from '@ethereumjs/util' @@ -160,9 +158,9 @@ export class BlockHeader { const parentHash = toType(headerData.parentHash, TypeOutput.Buffer) ?? defaults.parentHash const uncleHash = toType(headerData.uncleHash, TypeOutput.Buffer) ?? defaults.uncleHash - const coinbase = isTruthy(headerData.coinbase) - ? new Address(toType(headerData.coinbase, TypeOutput.Buffer)) - : defaults.coinbase + const coinbase = new Address( + toType(headerData.coinbase ?? defaults.coinbase, TypeOutput.Buffer) + ) const stateRoot = toType(headerData.stateRoot, TypeOutput.Buffer) ?? defaults.stateRoot const transactionsTrie = toType(headerData.transactionsTrie, TypeOutput.Buffer) ?? defaults.transactionsTrie @@ -300,9 +298,13 @@ export class BlockHeader { throw new Error(msg) } const londonHfBlock = this._common.hardforkBlock(Hardfork.London) - if (isTruthy(londonHfBlock) && this.number === londonHfBlock) { + if ( + typeof londonHfBlock === 'bigint' && + londonHfBlock !== BigInt(0) && + this.number === londonHfBlock + ) { const initialBaseFee = this._common.param('gasConfig', 'initialBaseFee') - if (this.baseFeePerGas! !== initialBaseFee) { + if (this.baseFeePerGas !== initialBaseFee) { const msg = this._errorMsg('Initial EIP1559 block does not have initial base fee') throw new Error(msg) } @@ -404,7 +406,11 @@ export class BlockHeader { // EIP-1559: assume double the parent gas limit on fork block // to adopt to the new gas target centered logic const londonHardforkBlock = this._common.hardforkBlock(Hardfork.London) - if (isTruthy(londonHardforkBlock) && this.number === londonHardforkBlock) { + if ( + typeof londonHardforkBlock === 'bigint' && + londonHardforkBlock !== BigInt(0) && + this.number === londonHardforkBlock + ) { const elasticity = this._common.param('gasConfig', 'elasticityMultiplier') parentGasLimit = parentGasLimit * elasticity } @@ -774,7 +780,7 @@ export class BlockHeader { return } const DAOActivationBlock = this._common.hardforkBlock(Hardfork.Dao) - if (isFalsy(DAOActivationBlock) || this.number < DAOActivationBlock) { + if (DAOActivationBlock === null || this.number < DAOActivationBlock) { return } const DAO_ExtraData = Buffer.from('64616f2d686172642d666f726b', 'hex') diff --git a/packages/block/src/helpers.ts b/packages/block/src/helpers.ts index 353e313dce..1c05c39494 100644 --- a/packages/block/src/helpers.ts +++ b/packages/block/src/helpers.ts @@ -1,4 +1,4 @@ -import { TypeOutput, isFalsy, isHexString, toType } from '@ethereumjs/util' +import { TypeOutput, isHexString, toType } from '@ethereumjs/util' import type { BlockHeaderBuffer, HeaderData } from './types' @@ -7,7 +7,7 @@ import type { BlockHeaderBuffer, HeaderData } from './types' * @param {string} input string to check, convert, and return */ export const numberToHex = function (input?: string) { - if (isFalsy(input)) return undefined + if (input === undefined) return undefined if (!isHexString(input)) { const regex = new RegExp(/^\d+$/) // test to make sure input contains only digits if (!regex.test(input)) { diff --git a/packages/block/src/types.ts b/packages/block/src/types.ts index 3365efd46a..cf9b078042 100644 --- a/packages/block/src/types.ts +++ b/packages/block/src/types.ts @@ -3,6 +3,7 @@ import type { Common } from '@ethereumjs/common' import type { AccessListEIP2930TxData, FeeMarketEIP1559TxData, + JsonRpcTx, JsonTx, TxData, } from '@ethereumjs/tx' @@ -150,3 +151,30 @@ export interface JsonHeader { nonce?: string baseFeePerGas?: string } + +/* + * Based on https://eth.wiki/json-rpc/API + */ +export interface JsonRpcBlock { + number: string // the block number. null when pending block. + hash: string // hash of the block. null when pending block. + parentHash: string // hash of the parent block. + mixHash?: string // bit hash which proves combined with the nonce that a sufficient amount of computation has been carried out on this block. + nonce: string // hash of the generated proof-of-work. null when pending block. + sha3Uncles: string // SHA3 of the uncles data in the block. + logsBloom: string // the bloom filter for the logs of the block. null when pending block. + transactionsRoot: string // the root of the transaction trie of the block. + stateRoot: string // the root of the final state trie of the block. + receiptsRoot: string // the root of the receipts trie of the block. + miner: string // the address of the beneficiary to whom the mining rewards were given. + difficulty: string // integer of the difficulty for this block. + totalDifficulty: string // integer of the total difficulty of the chain until this block. + extraData: string // the “extra data” field of this block. + size: string // integer the size of this block in bytes. + gasLimit: string // the maximum gas allowed in this block. + gasUsed: string // the total used gas by all transactions in this block. + timestamp: string // the unix timestamp for when the block was collated. + transactions: Array // Array of transaction objects, or 32 Bytes transaction hashes depending on the last given parameter. + uncles: string[] // Array of uncle hashes + baseFeePerGas?: string // If EIP-1559 is enabled for this block, returns the base fee per gas +} diff --git a/packages/block/test/block.spec.ts b/packages/block/test/block.spec.ts index 60ba7e802b..520f0c22cd 100644 --- a/packages/block/test/block.spec.ts +++ b/packages/block/test/block.spec.ts @@ -15,7 +15,7 @@ import * as testDataPreLondon2 from './testdata/testdata_pre-london-2.json' import * as testDataPreLondon from './testdata/testdata_pre-london.json' import * as testnetMerge from './testdata/testnetMerge.json' -import type { BlockBuffer } from '../src' +import type { BlockBuffer, JsonRpcBlock } from '../src' import type { NestedUint8Array } from '@ethereumjs/util' tape('[Block]: block functions', function (t) { @@ -176,7 +176,7 @@ tape('[Block]: block functions', function (t) { const common = new Common({ chain: Chain.Goerli, hardfork: Hardfork.Chainstart }) try { - blockFromRpc(testDataFromRpcGoerli, [], { common }) + blockFromRpc(testDataFromRpcGoerli as unknown as JsonRpcBlock, [], { common }) st.pass('does not throw') } catch (error: any) { st.fail('error thrown') diff --git a/packages/block/test/from-rpc.spec.ts b/packages/block/test/from-rpc.spec.ts index 7cba2bfda0..8d97ccf770 100644 --- a/packages/block/test/from-rpc.spec.ts +++ b/packages/block/test/from-rpc.spec.ts @@ -10,20 +10,21 @@ import * as blockDataWithUncles from './testdata/testdata-from-rpc-with-uncles.j import * as uncleBlockData from './testdata/testdata-from-rpc-with-uncles_uncle-block-data.json' import * as blockData from './testdata/testdata-from-rpc.json' +import type { JsonRpcBlock } from '../src/types' import type { Transaction } from '@ethereumjs/tx' tape('[fromRPC]: block #2924874', function (t) { const common = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Istanbul }) t.test('should create a block with transactions with valid signatures', function (st) { - const block = blockFromRpc(blockData, [], { common }) + const block = blockFromRpc(blockData as unknown as JsonRpcBlock, [], { common }) const allValid = block.transactions.every((tx) => tx.verifySignature()) st.equal(allValid, true, 'all transaction signatures are valid') st.end() }) t.test('should create a block header with the correct hash', function (st) { - const block = blockHeaderFromRpc(blockData, { common }) + const block = blockHeaderFromRpc(blockData as unknown as JsonRpcBlock, { common }) const hash = Buffer.from(blockData.hash.slice(2), 'hex') st.ok(block.hash().equals(hash)) st.end() @@ -45,7 +46,7 @@ tape('[fromRPC]:', function (t) { const blockDataTransactionValueAsInteger = blockData blockDataTransactionValueAsInteger.transactions[0].value = valueAsIntegerString const blockFromTransactionValueAsInteger = blockFromRpc( - blockDataTransactionValueAsInteger, + blockDataTransactionValueAsInteger as unknown as JsonRpcBlock, undefined, { common } ) @@ -66,7 +67,7 @@ tape('[fromRPC]:', function (t) { const blockDataTransactionGasPriceAsInteger = blockData blockDataTransactionGasPriceAsInteger.transactions[0].gasPrice = gasPriceAsIntegerString const blockFromTransactionGasPriceAsInteger = blockFromRpc( - blockDataTransactionGasPriceAsInteger, + blockDataTransactionGasPriceAsInteger as unknown as JsonRpcBlock, undefined, { common } ) @@ -83,9 +84,13 @@ tape('[fromRPC]:', function (t) { 'should create a block given json data that includes a difficulty parameter of type integer string', function (st) { const common = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.London }) - const blockDifficultyAsInteger = blockFromRpc(blockDataDifficultyAsInteger, undefined, { - common, - }) + const blockDifficultyAsInteger = blockFromRpc( + blockDataDifficultyAsInteger as unknown as JsonRpcBlock, + undefined, + { + common, + } + ) st.equal( blockDifficultyAsInteger.header.difficulty.toString(), blockDataDifficultyAsInteger.difficulty diff --git a/packages/block/test/util.ts b/packages/block/test/util.ts index e3f7fcb23e..7f4f0c9b91 100644 --- a/packages/block/test/util.ts +++ b/packages/block/test/util.ts @@ -1,6 +1,6 @@ import { Chain, Common, Hardfork } from '@ethereumjs/common' import { RLP } from '@ethereumjs/rlp' -import { bufArrToArr, isTruthy } from '@ethereumjs/util' +import { bufArrToArr } from '@ethereumjs/util' import { keccak256 } from 'ethereum-cryptography/keccak' import { Block } from '../src' @@ -33,7 +33,7 @@ function createBlock( const londonHfBlock = common.hardforkBlock(Hardfork.London) const baseFeePerGas = - isTruthy(londonHfBlock) && number > londonHfBlock + typeof londonHfBlock === 'bigint' && londonHfBlock !== BigInt(0) && number > londonHfBlock ? parentBlock.header.calcNextBaseFee() : undefined