From 4217ed683c362626e3dd07c5ceb73bb75ca66242 Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Mon, 16 May 2022 04:57:12 -0400 Subject: [PATCH] client: add missing tx fields to getBlockByHash (#1881) * client: add missing tx fields to getBlockByHash * Add test for "includeTransactions" * Fix test * numbers to hex * DRY Co-authored-by: Ryan Ghods --- packages/client/lib/rpc/modules/eth.ts | 79 ++++++++----------- .../test/rpc/eth/getBlockByHash.spec.ts | 23 ++++-- .../test/rpc/eth/getBlockByNumber.spec.ts | 41 +++------- packages/client/test/rpc/mockBlockchain.ts | 19 ++--- 4 files changed, 65 insertions(+), 97 deletions(-) diff --git a/packages/client/lib/rpc/modules/eth.ts b/packages/client/lib/rpc/modules/eth.ts index 5d6a7a6913..98c4953141 100644 --- a/packages/client/lib/rpc/modules/eth.ts +++ b/packages/client/lib/rpc/modules/eth.ts @@ -73,7 +73,7 @@ type JsonRpcBlock = { 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: JsonTx[] | string[] // Array of transaction objects, or 32 Bytes transaction hashes depending on the last given parameter. + 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 } @@ -129,6 +129,34 @@ type JsonRpcLog = { // (e.g. Deposit(address,bytes32,uint256)), except you declared the event with the anonymous specifier.) } +/** + * Returns tx formatted to the standard JSON-RPC fields + */ +const jsonRpcTx = (tx: TypedTransaction, block?: Block, txIndex?: number): JsonRpcTx => { + const txJSON = tx.toJSON() + return { + blockHash: block ? bufferToHex(block.hash()) : null, + blockNumber: block ? bnToHex(block.header.number) : null, + from: tx.getSenderAddress().toString(), + gas: txJSON.gasLimit!, + gasPrice: txJSON.gasPrice ?? txJSON.maxFeePerGas!, + maxFeePerGas: txJSON.maxFeePerGas, + maxPriorityFeePerGas: txJSON.maxPriorityFeePerGas, + type: intToHex(tx.type), + accessList: txJSON.accessList, + chainId: txJSON.chainId, + hash: bufferToHex(tx.hash()), + input: txJSON.data!, + nonce: txJSON.nonce!, + to: tx.to?.toString() ?? null, + transactionIndex: txIndex !== undefined ? intToHex(txIndex) : null, + value: txJSON.value!, + v: txJSON.v!, + r: txJSON.r!, + s: txJSON.s!, + } +} + /** * Returns block formatted to the standard JSON-RPC fields */ @@ -139,25 +167,10 @@ const jsonRpcBlock = async ( ): Promise => { const json = block.toJSON() const header = json!.header! - - let transactions - if (includeTransactions) { - transactions = block.transactions.map((tx) => { - const transaction = tx.toJSON() - const { gasLimit: gas, data: input, ...txData } = transaction - return { - ...txData, - // RPC specs specify `input` rather than `data`, and `gas` rather than `gasLimit` - input, - gas, - } - }) - } else { - transactions = block.transactions.map((tx) => bufferToHex(tx.hash())) - } - + const transactions = block.transactions.map((tx, txIndex) => + includeTransactions ? jsonRpcTx(tx, block, txIndex) : bufferToHex(tx.hash()) + ) const td = await chain.getTd(block.hash(), block.header.number) - return { number: header.number!, hash: bufferToHex(block.hash()), @@ -183,34 +196,6 @@ const jsonRpcBlock = async ( } } -/** - * Returns tx formatted to the standard JSON-RPC fields - */ -const jsonRpcTx = (tx: TypedTransaction, block?: Block, txIndex?: number): JsonRpcTx => { - const txJSON = tx.toJSON() - return { - blockHash: block ? bufferToHex(block.hash()) : null, - blockNumber: block ? bnToHex(block.header.number) : null, - from: tx.getSenderAddress().toString(), - gas: txJSON.gasLimit!, - gasPrice: txJSON.gasPrice ?? txJSON.maxFeePerGas!, - maxFeePerGas: txJSON.maxFeePerGas, - maxPriorityFeePerGas: txJSON.maxPriorityFeePerGas, - type: intToHex(tx.type), - accessList: txJSON.accessList, - chainId: txJSON.chainId, - hash: bufferToHex(tx.hash()), - input: txJSON.data!, - nonce: txJSON.nonce!, - to: tx.to?.toString() ?? null, - transactionIndex: txIndex !== undefined ? intToHex(txIndex) : null, - value: txJSON.value!, - v: txJSON.v!, - r: txJSON.r!, - s: txJSON.s!, - } -} - /** * Returns log formatted to the standard JSON-RPC fields */ diff --git a/packages/client/test/rpc/eth/getBlockByHash.spec.ts b/packages/client/test/rpc/eth/getBlockByHash.spec.ts index acd4897ea5..d0a22c148b 100644 --- a/packages/client/test/rpc/eth/getBlockByHash.spec.ts +++ b/packages/client/test/rpc/eth/getBlockByHash.spec.ts @@ -8,15 +8,22 @@ const method = 'eth_getBlockByHash' tape(`${method}: call with valid arguments`, async (t) => { const { server } = baseSetup() - const req = params(method, [ - '0x910abca1728c53e8d6df870dd7af5352e974357dc58205dea1676be17ba6becf', - false, - ]) - const expectRes = (res: any) => { - const msg = 'should return the correct number' - t.equal(res.body.result.number, '0x444444', msg) + const blockHash = '0x910abca1728c53e8d6df870dd7af5352e974357dc58205dea1676be17ba6becf' + let includeTransactions = false + let req = params(method, [blockHash, includeTransactions]) + let expectRes = (res: any) => { + t.equal(res.body.result.number, '0x444444', 'should return the correct number') + t.equal(typeof res.body.result.transactions[0], 'string', 'should only include tx hashes') } - await baseRequest(t, server, req, 200, expectRes) + await baseRequest(t, server, req, 200, expectRes, false) + + includeTransactions = true + req = params(method, [blockHash, includeTransactions]) + expectRes = (res: any) => { + t.equal(res.body.result.number, '0x444444', 'should return the correct number') + t.equal(typeof res.body.result.transactions[0], 'object', 'should include tx objects') + } + await baseRequest(t, server, req, 200, expectRes, true) // pass endOnFinish=true for last test }) tape(`${method}: call with false for second argument`, async (t) => { diff --git a/packages/client/test/rpc/eth/getBlockByNumber.spec.ts b/packages/client/test/rpc/eth/getBlockByNumber.spec.ts index e54eff2aa3..d3e22da12b 100644 --- a/packages/client/test/rpc/eth/getBlockByNumber.spec.ts +++ b/packages/client/test/rpc/eth/getBlockByNumber.spec.ts @@ -1,21 +1,13 @@ import { Block } from '@ethereumjs/block' -import { BN, bufferToHex } from 'ethereumjs-util' +import { Transaction } from '@ethereumjs/tx' +import { BN } from 'ethereumjs-util' import tape from 'tape' import { INVALID_PARAMS } from '../../../lib/rpc/error-code' -import { startRPC, createManager, createClient, params, baseRequest } from '../helpers' +import { startRPC, createManager, createClient, params, baseRequest, dummy } from '../helpers' import { checkError } from '../util' -const mockedTxData = { - nonce: '0x', - gasPrice: '0x', - gasLimit: '0x', - to: '0x', - value: '0x', - data: '0x', - v: '0x', - r: '0x', - s: '0x', -} +const mockedTx1 = Transaction.fromTxData({}).sign(dummy.privKey) +const mockedTx2 = Transaction.fromTxData({ nonce: 1 }).sign(dummy.privKey) function createChain() { const genesisBlockHash = Buffer.from( @@ -26,36 +18,28 @@ function createChain() { 'dcf93da321b27bca12087d6526d2c10540a4c8dc29db1b36610c3004e0e5d2d5', 'hex' ) - const txHash = Buffer.from( - 'c6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b', - 'hex' - ) - const txHash2 = Buffer.from( - 'a2285835057e8252ebd4980cf498f7538cedb3600dc183f1c523c6971b6889aa', - 'hex' - ) - - const transactions = [{ hash: bufferToHex(txHash) }] - const transactions2 = [{ hash: bufferToHex(txHash2) }] + const transactions = [mockedTx1] + const transactions2 = [mockedTx2] const genesisBlock = { hash: () => genesisBlockHash, header: { number: new BN(0), }, toJSON: () => ({ ...Block.fromBlockData({ header: { number: 0 } }).toJSON(), transactions }), - transactions: [{ hash: () => txHash }], + transactions, uncleHeaders: [], } const block = { hash: () => blockHash, header: { number: new BN(1), + hash: () => blockHash, }, toJSON: () => ({ ...Block.fromBlockData({ header: { number: 1 } }).toJSON(), transactions: transactions2, }), - transactions: [{ hash: () => txHash2, toJSON: () => mockedTxData }], + transactions: transactions2, uncleHeaders: [], } return { @@ -115,6 +99,7 @@ tape(`${method}: call with latest param`, async (t) => { const expectRes = (res: any) => { const msg = 'should return a block number' t.equal(res.body.result.number, '0x1', msg) + t.equal(typeof res.body.result.transactions[0], 'string', 'should only include tx hashes') } await baseRequest(t, server, req, 200, expectRes) }) @@ -176,9 +161,7 @@ tape(`${method}: call with transaction objects`, async (t) => { const req = params(method, ['latest', true]) const expectRes = (res: any) => { - const [transactionData] = res.body.result.transactions - const { gasLimit: gas, data: input, ...txData } = mockedTxData - t.deepEqual(transactionData, { ...txData, input, gas }) + t.equal(typeof res.body.result.transactions[0], 'object', 'should include tx objects') } await baseRequest(t, server, req, 200, expectRes) }) diff --git a/packages/client/test/rpc/mockBlockchain.ts b/packages/client/test/rpc/mockBlockchain.ts index 5b2d799538..1d0ab58421 100644 --- a/packages/client/test/rpc/mockBlockchain.ts +++ b/packages/client/test/rpc/mockBlockchain.ts @@ -1,14 +1,13 @@ import { Block } from '@ethereumjs/block' -import { BN, bufferToHex, toBuffer } from 'ethereumjs-util' +import { Transaction } from '@ethereumjs/tx' +import { BN, toBuffer } from 'ethereumjs-util' +import { dummy } from './helpers' export function mockBlockchain(options: any = {}) { const number = options.number ?? '0x444444' const blockHash = options.hash ?? '0x910abca1728c53e8d6df870dd7af5352e974357dc58205dea1676be17ba6becf' - const txHash = Buffer.from( - '0be3065cf288b071ccff922c1c601e2e5628d488b66e781c260ecee36054a2dc', - 'hex' - ) + const transactions = options.transactions ?? [Transaction.fromTxData({}).sign(dummy.privKey)] const block = { hash: () => toBuffer(blockHash), header: { @@ -17,15 +16,9 @@ export function mockBlockchain(options: any = {}) { toJSON: () => ({ ...Block.fromBlockData({ header: { number } }).toJSON(), hash: options.hash ?? blockHash, - transactions: options.transactions ?? [{ hash: bufferToHex(txHash) }], + transactions: transactions.map((t: Transaction) => t.toJSON()), }), - transactions: options.transactions ?? [ - { - hash: () => { - return txHash - }, - }, - ], + transactions, uncleHeaders: [], } return {