From 7096df0720d3db45bd8f39f8a66b98d816156570 Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Wed, 5 Apr 2023 15:26:59 -0400 Subject: [PATCH 01/10] add dataGasUsed to txReceipt and result --- packages/evm/src/evm.ts | 4 ++++ packages/vm/src/runTx.ts | 32 +++++++++++++++++++++++------- packages/vm/src/types.ts | 12 +++++++++++ packages/vm/test/api/runTx.spec.ts | 6 +++++- packages/vm/test/api/utils.ts | 13 +++++++++++- 5 files changed, 58 insertions(+), 9 deletions(-) diff --git a/packages/evm/src/evm.ts b/packages/evm/src/evm.ts index 5cd91707c0..38732ab754 100644 --- a/packages/evm/src/evm.ts +++ b/packages/evm/src/evm.ts @@ -1008,6 +1008,10 @@ export interface ExecResult { * The gas refund counter */ gasRefund?: bigint + /** + * Amount of data gas consumed by the transaction + */ + dataGasUsed?: bigint } export function OOGResult(gasLimit: bigint): ExecResult { diff --git a/packages/vm/src/runTx.ts b/packages/vm/src/runTx.ts index 279af37e77..303f6a2e5e 100644 --- a/packages/vm/src/runTx.ts +++ b/packages/vm/src/runTx.ts @@ -9,6 +9,7 @@ import { Bloom } from './bloom' import type { AfterTxEvent, BaseTxReceipt, + EIP4844BlobTxReceipt, PostByzantiumTxReceipt, PreByzantiumTxReceipt, RunTxOpts, @@ -309,6 +310,7 @@ async function _runTx(this: VM, opts: RunTxOpts): Promise { // the signer must be able to afford the transaction // assert signer(tx).balance >= tx.message.gas * tx.message.max_fee_per_gas + get_total_data_gas(tx) * tx.message.max_fee_per_data_gas const castTx = tx as BlobEIP4844Transaction + totalDataGas = castTx.common.param('gasConfig', 'dataGasPerBlob') * BigInt(castTx.numBlobs()) maxCost += totalDataGas * castTx.maxFeePerDataGas @@ -393,6 +395,7 @@ async function _runTx(this: VM, opts: RunTxOpts): Promise { // Update from account's balance const txCost = tx.gasLimit * gasPrice const dataGasCost = totalDataGas * dataGasPrice + fromAccount.balance -= txCost fromAccount.balance -= dataGasCost if (opts.skipBalance === true && fromAccount.balance < BigInt(0)) { @@ -448,6 +451,7 @@ async function _runTx(this: VM, opts: RunTxOpts): Promise { */ // Generate the bloom for the tx results.bloom = txLogsBloom(results.execResult.logs) + if (this.DEBUG) { debug(`Generated tx bloom with logs=${results.execResult.logs?.length}`) } @@ -458,6 +462,11 @@ async function _runTx(this: VM, opts: RunTxOpts): Promise { debugGas(`tx add baseFee ${txBaseFee} to totalGasSpent (-> ${results.totalGasSpent})`) } + // Add data gas used to result + if (tx.type === 5) { + results.dataGasUsed = totalDataGas + } + // Process any gas refund let gasRefund = results.execResult.gasRefund ?? BigInt(0) results.gasRefund = gasRefund @@ -532,7 +541,7 @@ async function _runTx(this: VM, opts: RunTxOpts): Promise { // Generate the tx receipt const gasUsed = opts.blockGasUsed !== undefined ? opts.blockGasUsed : block.header.gasUsed const cumulativeGasUsed = gasUsed + results.totalGasSpent - results.receipt = await generateTxReceipt.bind(this)(tx, results, cumulativeGasUsed) + results.receipt = await generateTxReceipt.bind(this)(tx, results, cumulativeGasUsed, totalDataGas) /** * The `afterTx` event @@ -581,12 +590,14 @@ function txLogsBloom(logs?: any[]): Bloom { * @param tx The transaction * @param txResult The tx result * @param cumulativeGasUsed The gas used in the block including this tx + * @param totalDataGas The data gas used in the tx */ export async function generateTxReceipt( this: VM, tx: TypedTransaction, txResult: RunTxResult, - cumulativeGasUsed: bigint + cumulativeGasUsed: bigint, + totalDataGas: bigint ): Promise { const baseReceipt: BaseTxReceipt = { cumulativeBlockGasUsed: cumulativeGasUsed, @@ -623,12 +634,19 @@ export async function generateTxReceipt( } } else { // Typed EIP-2718 Transaction - receipt = { - status: txResult.execResult.exceptionError ? 0 : 1, - ...baseReceipt, - } as PostByzantiumTxReceipt + if (tx.type === 5) { + receipt = { + dataGasUsed: totalDataGas, + status: txResult.execResult.exceptionError ? 0 : 1, + ...baseReceipt, + } as EIP4844BlobTxReceipt + } else { + receipt = { + status: txResult.execResult.exceptionError ? 0 : 1, + ...baseReceipt, + } as PostByzantiumTxReceipt + } } - return receipt } diff --git a/packages/vm/src/types.ts b/packages/vm/src/types.ts index 4af717c055..603da0d635 100644 --- a/packages/vm/src/types.ts +++ b/packages/vm/src/types.ts @@ -48,6 +48,13 @@ export interface PostByzantiumTxReceipt extends BaseTxReceipt { status: 0 | 1 } +export interface EIP4844BlobTxReceipt extends PostByzantiumTxReceipt { + /** + * Data gas consumed by a transaction + */ + dataGasUsed: bigint +} + export type VMEvents = { beforeBlock: (data: Block, resolve?: (result?: any) => void) => void afterBlock: (data: AfterBlockEvent, resolve?: (result?: any) => void) => void @@ -375,6 +382,11 @@ export interface RunTxResult extends EVMResult { * The value that accrues to the miner by this transaction */ minerValue: bigint + + /** + * This is the data gas units times the fee per data gas for 4844 transactions + */ + dataGasUsed?: bigint } export interface AfterTxEvent extends RunTxResult { diff --git a/packages/vm/test/api/runTx.spec.ts b/packages/vm/test/api/runTx.spec.ts index 9c7c76e4b9..fba36f4f9f 100644 --- a/packages/vm/test/api/runTx.spec.ts +++ b/packages/vm/test/api/runTx.spec.ts @@ -6,8 +6,10 @@ import { FeeMarketEIP1559Transaction, Transaction, TransactionFactory, + initKZG, } from '@ethereumjs/tx' import { Account, Address, KECCAK256_NULL, MAX_INTEGER } from '@ethereumjs/util' +import * as kzg from 'c-kzg' import * as tape from 'tape' import { VM } from '../../src/vm' @@ -882,6 +884,7 @@ tape( ) tape('EIP 4844 transaction tests', async (t) => { + initKZG(kzg, __dirname + '/../../../client/lib/trustedSetups/devnet4.txt') const genesisJson = require('../../../block/test/testdata/4844-hardfork.json') const common = Common.fromGethGenesis(genesisJson, { chain: 'customChain', @@ -915,7 +918,7 @@ tape('EIP 4844 transaction tests', async (t) => { const blockchain = await Blockchain.create({ validateBlocks: false, validateConsensus: false }) const vm = await VM.create({ common, blockchain }) - const tx = getTransaction(common, 5, true) + const tx = getTransaction(common, 5, true) as BlobEIP4844Transaction const block = Block.fromBlockData( { @@ -935,6 +938,7 @@ tape('EIP 4844 transaction tests', async (t) => { ) const res = await vm.runTx({ tx, block, skipBalance: true }) t.ok(res.execResult.exceptionError === undefined, 'simple blob tx run succeeds') + t.equal(res.dataGasUsed, 131072n, 'returns correct data gas used for 1 blob') Blockchain.prototype.getBlock = oldGetBlockFunction t.end() }) diff --git a/packages/vm/test/api/utils.ts b/packages/vm/test/api/utils.ts index 843793beda..d0a86e6441 100644 --- a/packages/vm/test/api/utils.ts +++ b/packages/vm/test/api/utils.ts @@ -1,5 +1,10 @@ import { Blockchain } from '@ethereumjs/blockchain' -import { TransactionFactory } from '@ethereumjs/tx' +import { TransactionFactory, kzg } from '@ethereumjs/tx' +import { + blobsToCommitments, + computeVersionedHash, + getBlobs, +} from '@ethereumjs/tx/dist/utils/blobHelpers' import { Account } from '@ethereumjs/util' import { MemoryLevel } from 'memory-level' @@ -93,6 +98,12 @@ export function getTransaction( txParams['maxFeePerGas'] = BigInt(1000000000) txParams['maxPriorityFeePerGas'] = BigInt(10) txParams['maxFeePerDataGas'] = BigInt(100) + txParams['blobs'] = getBlobs('hello world') + txParams['kzgCommitments'] = blobsToCommitments(txParams['blobs']) + txParams['kzgProof'] = kzg.computeAggregateKzgProof(txParams['blobs']) + txParams['versionedHashes'] = txParams['kzgCommitments'].map((commitment: Uint8Array) => + computeVersionedHash(commitment, 0x1) + ) } const tx = TransactionFactory.fromTxData(txParams, { common, freeze: false }) From b8fa90ba8d078b05e3b0ce4f5765ac12b89c3b69 Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Thu, 6 Apr 2023 10:19:25 -0400 Subject: [PATCH 02/10] Add tests --- .../rpc/eth/getTransactionReceipt.spec.ts | 86 ++++++++++++++++- packages/vm/test/api/runTx.spec.ts | 95 ++++++++++--------- 2 files changed, 136 insertions(+), 45 deletions(-) diff --git a/packages/client/test/rpc/eth/getTransactionReceipt.spec.ts b/packages/client/test/rpc/eth/getTransactionReceipt.spec.ts index f1b182870d..944d2a4930 100644 --- a/packages/client/test/rpc/eth/getTransactionReceipt.spec.ts +++ b/packages/client/test/rpc/eth/getTransactionReceipt.spec.ts @@ -1,9 +1,25 @@ -import { FeeMarketEIP1559Transaction, Transaction } from '@ethereumjs/tx' +import { BlockHeader } from '@ethereumjs/block' +import { Common, Hardfork } from '@ethereumjs/common' +import { DefaultStateManager } from '@ethereumjs/statemanager' +import { + BlobEIP4844Transaction, + FeeMarketEIP1559Transaction, + Transaction, + initKZG, +} from '@ethereumjs/tx' +import { + blobsToCommitments, + commitmentsToVersionedHashes, + getBlobs, +} from '@ethereumjs/tx/dist/utils/blobHelpers' import { bufferToHex } from '@ethereumjs/util' +import * as kzg from 'c-kzg' +import { randomBytes } from 'crypto' import * as tape from 'tape' import { baseRequest, + baseSetup, dummy, gethGenesisStartLondon, params, @@ -13,6 +29,8 @@ import { import pow = require('./../../testdata/geth-genesis/pow.json') +import type { FullEthereumService } from '../../../lib/service' + const method = 'eth_getTransactionReceipt' tape(`${method}: call with legacy tx`, async (t) => { @@ -78,3 +96,69 @@ tape(`${method}: call with unknown tx hash`, async (t) => { } await baseRequest(t, server, req, 200, expectRes) }) + +tape(`${method}: get dataGasUsed in blob tx receipt`, async (t) => { + // Disable stateroot validation in TxPool since valid state root isn't available + const originalSetStateRoot = DefaultStateManager.prototype.setStateRoot + DefaultStateManager.prototype.setStateRoot = (): any => {} + const originalStateManagerCopy = DefaultStateManager.prototype.copy + DefaultStateManager.prototype.copy = function () { + return this + } + // Disable block header consensus format validation + const consensusFormatValidation = BlockHeader.prototype._consensusFormatValidation + BlockHeader.prototype._consensusFormatValidation = (): any => {} + try { + kzg.freeTrustedSetup() + } catch { + // NOOP - just verifying KZG is ready if not already + } + initKZG(kzg, __dirname + '/../../../lib/trustedSetups/devnet4.txt') + const gethGenesis = require('../../../../block/test/testdata/4844-hardfork.json') + const common = Common.fromGethGenesis(gethGenesis, { + chain: 'customChain', + hardfork: Hardfork.ShardingForkDev, + }) + const { chain, execution, server } = await setupChain(gethGenesis, 'customChain') + common.setHardfork(Hardfork.ShardingForkDev) + + const blobs = getBlobs('hello world') + const commitments = blobsToCommitments(blobs) + const versionedHashes = commitmentsToVersionedHashes(commitments) + const proof = kzg.computeAggregateKzgProof(blobs.map((blob) => Uint8Array.from(blob))) + const bufferedHashes = versionedHashes.map((el) => Buffer.from(el)) + const pk = randomBytes(32) + const tx = BlobEIP4844Transaction.fromTxData( + { + versionedHashes: bufferedHashes, + blobs, + kzgCommitments: commitments, + kzgProof: proof, + maxFeePerDataGas: 1000000n, + gasLimit: 0xffffn, + maxFeePerGas: 10000000n, + maxPriorityFeePerGas: 1000000n, + to: randomBytes(20), + nonce: 0n, + }, + { common } + ).sign(pk) + + const vm = execution.vm + const account = await vm.stateManager.getAccount(tx.getSenderAddress()) + account.balance = BigInt(0xfffffffffffff) + await vm.stateManager.putAccount(tx.getSenderAddress(), account) + + await runBlockWithTxs(chain, execution, [tx], true) + + const req = params(method, ['0x' + tx.serializeNetworkWrapper().toString('hex')]) + const expectRes = (res: any) => { + t.ok(res.body.result.dataGasUsed !== undefined) + } + + await baseRequest(t, server, req, 200, expectRes) + // Restore stubbed out functionality + DefaultStateManager.prototype.setStateRoot = originalSetStateRoot + DefaultStateManager.prototype.copy = originalStateManagerCopy + BlockHeader.prototype._consensusFormatValidation = consensusFormatValidation +}) diff --git a/packages/vm/test/api/runTx.spec.ts b/packages/vm/test/api/runTx.spec.ts index fba36f4f9f..6d004db88b 100644 --- a/packages/vm/test/api/runTx.spec.ts +++ b/packages/vm/test/api/runTx.spec.ts @@ -884,24 +884,55 @@ tape( ) tape('EIP 4844 transaction tests', async (t) => { - initKZG(kzg, __dirname + '/../../../client/lib/trustedSetups/devnet4.txt') - const genesisJson = require('../../../block/test/testdata/4844-hardfork.json') - const common = Common.fromGethGenesis(genesisJson, { - chain: 'customChain', - hardfork: Hardfork.ShardingForkDev, - }) - common.setHardfork(Hardfork.ShardingForkDev) - const oldGetBlockFunction = Blockchain.prototype.getBlock + // Hack to detect if running in browser or not + const isBrowser = new Function('try {return this===window;}catch(e){ return false;}') + + if (isBrowser() === true) { + t.end() + } else { + initKZG(kzg, __dirname + '/../../../client/lib/trustedSetups/devnet4.txt') + const genesisJson = require('../../../block/test/testdata/4844-hardfork.json') + const common = Common.fromGethGenesis(genesisJson, { + chain: 'customChain', + hardfork: Hardfork.ShardingForkDev, + }) + common.setHardfork(Hardfork.ShardingForkDev) + const oldGetBlockFunction = Blockchain.prototype.getBlock + + // Stub getBlock to produce a valid parent header under EIP 4844 + Blockchain.prototype.getBlock = async () => { + return Block.fromBlockData( + { + header: BlockHeader.fromHeaderData( + { + excessDataGas: 0n, + number: 1, + parentHash: blockchain.genesisBlock.hash(), + }, + { + common, + skipConsensusFormatValidation: true, + } + ), + }, + { + common, + skipConsensusFormatValidation: true, + } + ) + } + const blockchain = await Blockchain.create({ validateBlocks: false, validateConsensus: false }) + const vm = await VM.create({ common, blockchain }) - // Stub getBlock to produce a valid parent header under EIP 4844 - Blockchain.prototype.getBlock = async () => { - return Block.fromBlockData( + const tx = getTransaction(common, 5, true) as BlobEIP4844Transaction + + const block = Block.fromBlockData( { header: BlockHeader.fromHeaderData( { - excessDataGas: 0n, - number: 1, - parentHash: blockchain.genesisBlock.hash(), + excessDataGas: 1n, + number: 2, + parentHash: (await blockchain.getBlock(1n)).hash(), // Faking parent hash with getBlock stub }, { common, @@ -909,36 +940,12 @@ tape('EIP 4844 transaction tests', async (t) => { } ), }, - { - common, - skipConsensusFormatValidation: true, - } + { common, skipConsensusFormatValidation: true } ) + const res = await vm.runTx({ tx, block, skipBalance: true }) + t.ok(res.execResult.exceptionError === undefined, 'simple blob tx run succeeds') + t.equal(res.dataGasUsed, 131072n, 'returns correct data gas used for 1 blob') + Blockchain.prototype.getBlock = oldGetBlockFunction + t.end() } - const blockchain = await Blockchain.create({ validateBlocks: false, validateConsensus: false }) - const vm = await VM.create({ common, blockchain }) - - const tx = getTransaction(common, 5, true) as BlobEIP4844Transaction - - const block = Block.fromBlockData( - { - header: BlockHeader.fromHeaderData( - { - excessDataGas: 1n, - number: 2, - parentHash: (await blockchain.getBlock(1n)).hash(), // Faking parent hash with getBlock stub - }, - { - common, - skipConsensusFormatValidation: true, - } - ), - }, - { common, skipConsensusFormatValidation: true } - ) - const res = await vm.runTx({ tx, block, skipBalance: true }) - t.ok(res.execResult.exceptionError === undefined, 'simple blob tx run succeeds') - t.equal(res.dataGasUsed, 131072n, 'returns correct data gas used for 1 blob') - Blockchain.prototype.getBlock = oldGetBlockFunction - t.end() }) From eaa76e7759a629272c1a7f535a529b997ed6df01 Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Thu, 6 Apr 2023 11:35:09 -0400 Subject: [PATCH 03/10] Add test for getTransactionReceipt --- .../block/test/testdata/4844-hardfork.json | 3 ++ packages/client/lib/rpc/modules/eth.ts | 12 +++++--- .../rpc/eth/getTransactionReceipt.spec.ts | 30 ++----------------- 3 files changed, 14 insertions(+), 31 deletions(-) diff --git a/packages/block/test/testdata/4844-hardfork.json b/packages/block/test/testdata/4844-hardfork.json index 8abe087a97..ac09973c93 100644 --- a/packages/block/test/testdata/4844-hardfork.json +++ b/packages/block/test/testdata/4844-hardfork.json @@ -36,6 +36,9 @@ "0x8A04d14125D0FDCDc742F4A05C051De07232EDa4": { "code": "0x60806040526004361061003f5760003560e01c806301ffc9a714610044578063228951181461008c578063621fd130146101a2578063c5f2892f1461022c575b600080fd5b34801561005057600080fd5b506100786004803603602081101561006757600080fd5b50356001600160e01b031916610253565b604080519115158252519081900360200190f35b6101a0600480360360808110156100a257600080fd5b8101906020810181356401000000008111156100bd57600080fd5b8201836020820111156100cf57600080fd5b803590602001918460018302840111640100000000831117156100f157600080fd5b91939092909160208101903564010000000081111561010f57600080fd5b82018360208201111561012157600080fd5b8035906020019184600183028401116401000000008311171561014357600080fd5b91939092909160208101903564010000000081111561016157600080fd5b82018360208201111561017357600080fd5b8035906020019184600183028401116401000000008311171561019557600080fd5b91935091503561028a565b005b3480156101ae57600080fd5b506101b7610ce6565b6040805160208082528351818301528351919283929083019185019080838360005b838110156101f15781810151838201526020016101d9565b50505050905090810190601f16801561021e5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561023857600080fd5b50610241610cf8565b60408051918252519081900360200190f35b60006001600160e01b031982166301ffc9a760e01b148061028457506001600160e01b03198216638564090760e01b145b92915050565b603086146102c95760405162461bcd60e51b81526004018080602001828103825260268152602001806112516026913960400191505060405180910390fd5b602084146103085760405162461bcd60e51b81526004018080602001828103825260368152602001806111e86036913960400191505060405180910390fd5b606082146103475760405162461bcd60e51b81526004018080602001828103825260298152602001806112c46029913960400191505060405180910390fd5b670de0b6b3a764000034101561038e5760405162461bcd60e51b815260040180806020018281038252602681526020018061129e6026913960400191505060405180910390fd5b633b9aca003406156103d15760405162461bcd60e51b815260040180806020018281038252603381526020018061121e6033913960400191505060405180910390fd5b633b9aca00340467ffffffffffffffff81111561041f5760405162461bcd60e51b81526004018080602001828103825260278152602001806112776027913960400191505060405180910390fd5b606061042a82610fc6565b90507f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c589898989858a8a61045f602054610fc6565b6040805160a0808252810189905290819060208201908201606083016080840160c085018e8e80828437600083820152601f01601f191690910187810386528c815260200190508c8c808284376000838201819052601f909101601f191690920188810386528c5181528c51602091820193918e019250908190849084905b838110156104f65781810151838201526020016104de565b50505050905090810190601f1680156105235780820380516001836020036101000a031916815260200191505b5086810383528881526020018989808284376000838201819052601f909101601f19169092018881038452895181528951602091820193918b019250908190849084905b8381101561057f578181015183820152602001610567565b50505050905090810190601f1680156105ac5780820380516001836020036101000a031916815260200191505b509d505050505050505050505050505060405180910390a1600060028a8a600060801b604051602001808484808284376fffffffffffffffffffffffffffffffff199094169190930190815260408051600f19818403018152601090920190819052815191955093508392506020850191508083835b602083106106415780518252601f199092019160209182019101610622565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa158015610680573d6000803e3d6000fd5b5050506040513d602081101561069557600080fd5b5051905060006002806106ab6040848a8c61114a565b6040516020018083838082843780830192505050925050506040516020818303038152906040526040518082805190602001908083835b602083106107015780518252601f1990920191602091820191016106e2565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa158015610740573d6000803e3d6000fd5b5050506040513d602081101561075557600080fd5b50516002610766896040818d61114a565b60405160009060200180848480828437919091019283525050604080518083038152602092830191829052805190945090925082918401908083835b602083106107c15780518252601f1990920191602091820191016107a2565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa158015610800573d6000803e3d6000fd5b5050506040513d602081101561081557600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b6020831061086b5780518252601f19909201916020918201910161084c565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa1580156108aa573d6000803e3d6000fd5b5050506040513d60208110156108bf57600080fd5b50516040805160208101858152929350600092600292839287928f928f92018383808284378083019250505093505050506040516020818303038152906040526040518082805190602001908083835b6020831061092e5780518252601f19909201916020918201910161090f565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa15801561096d573d6000803e3d6000fd5b5050506040513d602081101561098257600080fd5b50516040518651600291889160009188916020918201918291908601908083835b602083106109c25780518252601f1990920191602091820191016109a3565b6001836020036101000a0380198251168184511680821785525050505050509050018367ffffffffffffffff191667ffffffffffffffff1916815260180182815260200193505050506040516020818303038152906040526040518082805190602001908083835b60208310610a495780518252601f199092019160209182019101610a2a565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa158015610a88573d6000803e3d6000fd5b5050506040513d6020811015610a9d57600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610af35780518252601f199092019160209182019101610ad4565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa158015610b32573d6000803e3d6000fd5b5050506040513d6020811015610b4757600080fd5b50519050858114610b895760405162461bcd60e51b81526004018080602001828103825260548152602001806111946054913960600191505060405180910390fd5b60205463ffffffff11610bcd5760405162461bcd60e51b81526004018080602001828103825260218152602001806111736021913960400191505060405180910390fd5b602080546001019081905560005b6020811015610cda578160011660011415610c0d578260008260208110610bfe57fe5b015550610cdd95505050505050565b600260008260208110610c1c57fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b60208310610c745780518252601f199092019160209182019101610c55565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa158015610cb3573d6000803e3d6000fd5b5050506040513d6020811015610cc857600080fd5b50519250600282049150600101610bdb565b50fe5b50505050505050565b6060610cf3602054610fc6565b905090565b6020546000908190815b6020811015610ea9578160011660011415610ddb57600260008260208110610d2657fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b60208310610d7e5780518252601f199092019160209182019101610d5f565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa158015610dbd573d6000803e3d6000fd5b5050506040513d6020811015610dd257600080fd5b50519250610e9b565b60028360218360208110610deb57fe5b015460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b60208310610e425780518252601f199092019160209182019101610e23565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa158015610e81573d6000803e3d6000fd5b5050506040513d6020811015610e9657600080fd5b505192505b600282049150600101610d02565b50600282610eb8602054610fc6565b600060401b6040516020018084815260200183805190602001908083835b60208310610ef55780518252601f199092019160209182019101610ed6565b51815160209384036101000a600019018019909216911617905267ffffffffffffffff199590951692019182525060408051808303600719018152601890920190819052815191955093508392850191508083835b60208310610f695780518252601f199092019160209182019101610f4a565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa158015610fa8573d6000803e3d6000fd5b5050506040513d6020811015610fbd57600080fd5b50519250505090565b60408051600880825281830190925260609160208201818036833701905050905060c082901b8060071a60f81b8260008151811061100057fe5b60200101906001600160f81b031916908160001a9053508060061a60f81b8260018151811061102b57fe5b60200101906001600160f81b031916908160001a9053508060051a60f81b8260028151811061105657fe5b60200101906001600160f81b031916908160001a9053508060041a60f81b8260038151811061108157fe5b60200101906001600160f81b031916908160001a9053508060031a60f81b826004815181106110ac57fe5b60200101906001600160f81b031916908160001a9053508060021a60f81b826005815181106110d757fe5b60200101906001600160f81b031916908160001a9053508060011a60f81b8260068151811061110257fe5b60200101906001600160f81b031916908160001a9053508060001a60f81b8260078151811061112d57fe5b60200101906001600160f81b031916908160001a90535050919050565b60008085851115611159578182fd5b83861115611165578182fd5b505082019391909203915056fe4465706f736974436f6e74726163743a206d65726b6c6520747265652066756c6c4465706f736974436f6e74726163743a207265636f6e7374727563746564204465706f7369744461746120646f6573206e6f74206d6174636820737570706c696564206465706f7369745f646174615f726f6f744465706f736974436f6e74726163743a20696e76616c6964207769746864726177616c5f63726564656e7469616c73206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c7565206e6f74206d756c7469706c65206f6620677765694465706f736974436f6e74726163743a20696e76616c6964207075626b6579206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f20686967684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f206c6f774465706f736974436f6e74726163743a20696e76616c6964207369676e6174757265206c656e677468a164736f6c634300060b000a", "balance": "0x0" + }, + "0xcde098d93535445768e8a2345a2f869139f45641": { + "balance": "0x6d6172697573766477000000" } }, "number": "0x0", diff --git a/packages/client/lib/rpc/modules/eth.ts b/packages/client/lib/rpc/modules/eth.ts index 0ad46d3f0a..dad99319f3 100644 --- a/packages/client/lib/rpc/modules/eth.ts +++ b/packages/client/lib/rpc/modules/eth.ts @@ -57,6 +57,7 @@ type JsonRpcReceipt = { // It also returns either: root?: string // DATA, 32 bytes of post-transaction stateroot (pre Byzantium) status?: string // QUANTITY, either 1 (success) or 0 (failure) + dataGasUsed?: string // QUANTITY, data gas consumed by transaction (if blob transaction) } type JsonRpcLog = { removed: boolean // TAG - true when the log was removed, due to a chain reorganization. false if it's a valid log. @@ -152,7 +153,8 @@ const jsonRpcReceipt = async ( tx: TypedTransaction, txIndex: number, logIndex: number, - contractAddress?: Address + contractAddress?: Address, + dataGasUsed?: bigint ): Promise => ({ transactionHash: bufferToHex(tx.hash()), transactionIndex: intToHex(txIndex), @@ -174,6 +176,7 @@ const jsonRpcReceipt = async ( status: Buffer.isBuffer((receipt as PostByzantiumTxReceipt).status) ? intToHex((receipt as PostByzantiumTxReceipt).status) : undefined, + dataGasUsed: dataGasUsed !== undefined ? bigIntToHex(dataGasUsed) : undefined, }) /** @@ -729,10 +732,10 @@ export class Eth { */ async getTransactionReceipt(params: [string]) { const [txHash] = params - try { if (!this.receiptsManager) throw new Error('missing receiptsManager') const result = await this.receiptsManager.getReceiptByTxHash(toBuffer(txHash)) + if (!result) return null const [receipt, blockHash, txIndex, logIndex] = result const block = await this._chain.getBlock(blockHash) @@ -755,7 +758,7 @@ export class Eth { root: parentBlock.header.stateRoot, skipBlockValidation: true, }) - const { totalGasSpent, createdAddress } = runBlockResult.results[txIndex] + const { totalGasSpent, createdAddress, dataGasUsed } = runBlockResult.results[txIndex] return await jsonRpcReceipt( receipt, totalGasSpent, @@ -764,7 +767,8 @@ export class Eth { tx, txIndex, logIndex, - createdAddress + createdAddress, + dataGasUsed ) } catch (error: any) { throw { diff --git a/packages/client/test/rpc/eth/getTransactionReceipt.spec.ts b/packages/client/test/rpc/eth/getTransactionReceipt.spec.ts index 944d2a4930..8a73bc2070 100644 --- a/packages/client/test/rpc/eth/getTransactionReceipt.spec.ts +++ b/packages/client/test/rpc/eth/getTransactionReceipt.spec.ts @@ -1,6 +1,5 @@ import { BlockHeader } from '@ethereumjs/block' import { Common, Hardfork } from '@ethereumjs/common' -import { DefaultStateManager } from '@ethereumjs/statemanager' import { BlobEIP4844Transaction, FeeMarketEIP1559Transaction, @@ -19,7 +18,6 @@ import * as tape from 'tape' import { baseRequest, - baseSetup, dummy, gethGenesisStartLondon, params, @@ -29,8 +27,6 @@ import { import pow = require('./../../testdata/geth-genesis/pow.json') -import type { FullEthereumService } from '../../../lib/service' - const method = 'eth_getTransactionReceipt' tape(`${method}: call with legacy tx`, async (t) => { @@ -98,16 +94,6 @@ tape(`${method}: call with unknown tx hash`, async (t) => { }) tape(`${method}: get dataGasUsed in blob tx receipt`, async (t) => { - // Disable stateroot validation in TxPool since valid state root isn't available - const originalSetStateRoot = DefaultStateManager.prototype.setStateRoot - DefaultStateManager.prototype.setStateRoot = (): any => {} - const originalStateManagerCopy = DefaultStateManager.prototype.copy - DefaultStateManager.prototype.copy = function () { - return this - } - // Disable block header consensus format validation - const consensusFormatValidation = BlockHeader.prototype._consensusFormatValidation - BlockHeader.prototype._consensusFormatValidation = (): any => {} try { kzg.freeTrustedSetup() } catch { @@ -127,7 +113,6 @@ tape(`${method}: get dataGasUsed in blob tx receipt`, async (t) => { const versionedHashes = commitmentsToVersionedHashes(commitments) const proof = kzg.computeAggregateKzgProof(blobs.map((blob) => Uint8Array.from(blob))) const bufferedHashes = versionedHashes.map((el) => Buffer.from(el)) - const pk = randomBytes(32) const tx = BlobEIP4844Transaction.fromTxData( { versionedHashes: bufferedHashes, @@ -142,23 +127,14 @@ tape(`${method}: get dataGasUsed in blob tx receipt`, async (t) => { nonce: 0n, }, { common } - ).sign(pk) - - const vm = execution.vm - const account = await vm.stateManager.getAccount(tx.getSenderAddress()) - account.balance = BigInt(0xfffffffffffff) - await vm.stateManager.putAccount(tx.getSenderAddress(), account) + ).sign(dummy.privKey) await runBlockWithTxs(chain, execution, [tx], true) - const req = params(method, ['0x' + tx.serializeNetworkWrapper().toString('hex')]) + const req = params(method, ['0x' + tx.hash().toString('hex')]) const expectRes = (res: any) => { - t.ok(res.body.result.dataGasUsed !== undefined) + t.equal(res.body.result.dataGasUsed, '0x20000', 'receipt has correct data gas usage') } await baseRequest(t, server, req, 200, expectRes) - // Restore stubbed out functionality - DefaultStateManager.prototype.setStateRoot = originalSetStateRoot - DefaultStateManager.prototype.copy = originalStateManagerCopy - BlockHeader.prototype._consensusFormatValidation = consensusFormatValidation }) From d4ea1b1fa94304ba072b3f6b15e25c7f0b84929a Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Thu, 6 Apr 2023 11:52:46 -0400 Subject: [PATCH 04/10] lint --- packages/client/test/rpc/eth/getTransactionReceipt.spec.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/client/test/rpc/eth/getTransactionReceipt.spec.ts b/packages/client/test/rpc/eth/getTransactionReceipt.spec.ts index 8a73bc2070..cfd961d178 100644 --- a/packages/client/test/rpc/eth/getTransactionReceipt.spec.ts +++ b/packages/client/test/rpc/eth/getTransactionReceipt.spec.ts @@ -1,4 +1,3 @@ -import { BlockHeader } from '@ethereumjs/block' import { Common, Hardfork } from '@ethereumjs/common' import { BlobEIP4844Transaction, From ce9d6a277ae4b7075c3ca9bea80061b5eee1b472 Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Thu, 6 Apr 2023 12:22:34 -0400 Subject: [PATCH 05/10] Address feedback --- packages/vm/src/types.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/vm/src/types.ts b/packages/vm/src/types.ts index 603da0d635..6fbebf6f84 100644 --- a/packages/vm/src/types.ts +++ b/packages/vm/src/types.ts @@ -51,6 +51,9 @@ export interface PostByzantiumTxReceipt extends BaseTxReceipt { export interface EIP4844BlobTxReceipt extends PostByzantiumTxReceipt { /** * Data gas consumed by a transaction + * + * Note: This value is not included in the receiptRLP used for encoding the receiptsRoot in a block + * and is only provided as part of receipt metadata. */ dataGasUsed: bigint } From d8924bcd71ebeb8d4a4ad555d4acc5365e77dbc7 Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Thu, 13 Apr 2023 15:05:54 -0400 Subject: [PATCH 06/10] Remove buffer --- packages/client/test/rpc/eth/getTransactionReceipt.spec.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/client/test/rpc/eth/getTransactionReceipt.spec.ts b/packages/client/test/rpc/eth/getTransactionReceipt.spec.ts index cb07e05f38..76e5de4f2e 100644 --- a/packages/client/test/rpc/eth/getTransactionReceipt.spec.ts +++ b/packages/client/test/rpc/eth/getTransactionReceipt.spec.ts @@ -102,10 +102,9 @@ tape(`${method}: get dataGasUsed in blob tx receipt`, async (t) => { const commitments = blobsToCommitments(blobs) const versionedHashes = commitmentsToVersionedHashes(commitments) const proofs = blobs.map((blob, ctx) => kzg.computeBlobKzgProof(blob, commitments[ctx])) - const bufferedHashes = versionedHashes.map((el) => Buffer.from(el)) const tx = BlobEIP4844Transaction.fromTxData( { - versionedHashes: bufferedHashes, + versionedHashes, blobs, kzgCommitments: commitments, kzgProofs: proofs, From cc444a35270b619972aea5d4a49a4f3d1df3b312 Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Fri, 14 Apr 2023 10:37:20 -0400 Subject: [PATCH 07/10] Merge fixes and cleanup --- package-lock.json | 2 ++ packages/client/lib/rpc/modules/eth.ts | 21 +++++++++++++++++---- packages/vm/package.json | 1 + packages/vm/src/runTx.ts | 22 ++++++++++++++-------- packages/vm/src/types.ts | 7 +++++++ packages/vm/test/api/runTx.spec.ts | 3 +-- packages/vm/test/api/utils.ts | 14 ++++++-------- 7 files changed, 48 insertions(+), 22 deletions(-) diff --git a/package-lock.json b/package-lock.json index 659ee164f6..29e92707f4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18314,6 +18314,7 @@ "@types/minimist": "^1.2.2", "@types/node-dir": "^0.0.34", "benchmark": "^2.1.4", + "c-kzg": "^2.0.4", "level": "^8.0.0", "memory-level": "^1.0.0", "minimist": "^1.2.5", @@ -19903,6 +19904,7 @@ "@types/minimist": "^1.2.2", "@types/node-dir": "^0.0.34", "benchmark": "^2.1.4", + "c-kzg": "*", "debug": "^4.3.3", "ethereum-cryptography": "^1.1.2", "level": "^8.0.0", diff --git a/packages/client/lib/rpc/modules/eth.ts b/packages/client/lib/rpc/modules/eth.ts index 728479f281..bc6bceda02 100644 --- a/packages/client/lib/rpc/modules/eth.ts +++ b/packages/client/lib/rpc/modules/eth.ts @@ -26,7 +26,13 @@ import type { Block, JsonRpcBlock } from '@ethereumjs/block' import type { Log } from '@ethereumjs/evm' import type { Proof } from '@ethereumjs/statemanager' import type { FeeMarketEIP1559Transaction, Transaction, TypedTransaction } from '@ethereumjs/tx' -import type { PostByzantiumTxReceipt, PreByzantiumTxReceipt, TxReceipt, VM } from '@ethereumjs/vm' +import type { + EIP4844BlobTxReceipt, + PostByzantiumTxReceipt, + PreByzantiumTxReceipt, + TxReceipt, + VM, +} from '@ethereumjs/vm' type GetLogsParams = { fromBlock?: string // QUANTITY, block number or "earliest" or "latest" (default: "latest") @@ -58,6 +64,7 @@ type JsonRpcReceipt = { root?: string // DATA, 32 bytes of post-transaction stateroot (pre Byzantium) status?: string // QUANTITY, either 1 (success) or 0 (failure) dataGasUsed?: string // QUANTITY, data gas consumed by transaction (if blob transaction) + dataGasPrice?: string // QUAntity, data gas price for block including this transaction (if blob transaction) } type JsonRpcLog = { removed: boolean // TAG - true when the log was removed, due to a chain reorganization. false if it's a valid log. @@ -154,7 +161,8 @@ const jsonRpcReceipt = async ( txIndex: number, logIndex: number, contractAddress?: Address, - dataGasUsed?: bigint + dataGasUsed?: bigint, + dataGasPrice?: bigint ): Promise => ({ transactionHash: bytesToPrefixedHexString(tx.hash()), transactionIndex: intToHex(txIndex), @@ -178,6 +186,8 @@ const jsonRpcReceipt = async ( ((receipt as PostByzantiumTxReceipt).status as unknown) instanceof Uint8Array ? intToHex((receipt as PostByzantiumTxReceipt).status) : undefined, + dataGasUsed: dataGasUsed !== undefined ? '0x' + bigIntToHex(dataGasUsed) : undefined, + dataGasPrice: dataGasPrice !== undefined ? '0x' + bigIntToHex(dataGasPrice) : undefined, }) /** @@ -739,6 +749,7 @@ export class Eth { */ async getTransactionReceipt(params: [string]) { const [txHash] = params + try { if (!this.receiptsManager) throw new Error('missing receiptsManager') const result = await this.receiptsManager.getReceiptByTxHash(hexStringToBytes(txHash)) @@ -764,7 +775,8 @@ export class Eth { root: parentBlock.header.stateRoot, skipBlockValidation: true, }) - const { totalGasSpent, createdAddress, dataGasUsed } = runBlockResult.results[txIndex] + const { totalGasSpent, createdAddress } = runBlockResult.results[txIndex] + const { dataGasUsed, dataGasPrice } = receipt as EIP4844BlobTxReceipt return await jsonRpcReceipt( receipt, totalGasSpent, @@ -774,7 +786,8 @@ export class Eth { txIndex, logIndex, createdAddress, - dataGasUsed + dataGasUsed, + dataGasPrice ) } catch (error: any) { throw { diff --git a/packages/vm/package.json b/packages/vm/package.json index 2a0dbf5df1..29c0c0f7d8 100644 --- a/packages/vm/package.json +++ b/packages/vm/package.json @@ -78,6 +78,7 @@ "@types/minimist": "^1.2.2", "@types/node-dir": "^0.0.34", "benchmark": "^2.1.4", + "c-kzg": "^2.0.4", "level": "^8.0.0", "memory-level": "^1.0.0", "minimist": "^1.2.5", diff --git a/packages/vm/src/runTx.ts b/packages/vm/src/runTx.ts index fcc1691487..bd299744aa 100644 --- a/packages/vm/src/runTx.ts +++ b/packages/vm/src/runTx.ts @@ -326,7 +326,6 @@ async function _runTx(this: VM, opts: RunTxOpts): Promise { // the signer must be able to afford the transaction // assert signer(tx).balance >= tx.message.gas * tx.message.max_fee_per_gas + get_total_data_gas(tx) * tx.message.max_fee_per_data_gas const castTx = tx as BlobEIP4844Transaction - totalDataGas = castTx.common.param('gasConfig', 'dataGasPerBlob') * BigInt(castTx.numBlobs()) maxCost += totalDataGas * castTx.maxFeePerDataGas @@ -411,7 +410,6 @@ async function _runTx(this: VM, opts: RunTxOpts): Promise { // Update from account's balance const txCost = tx.gasLimit * gasPrice const dataGasCost = totalDataGas * dataGasPrice - fromAccount.balance -= txCost fromAccount.balance -= dataGasCost if (opts.skipBalance === true && fromAccount.balance < BigInt(0)) { @@ -467,7 +465,6 @@ async function _runTx(this: VM, opts: RunTxOpts): Promise { */ // Generate the bloom for the tx results.bloom = txLogsBloom(results.execResult.logs) - if (this.DEBUG) { debug(`Generated tx bloom with logs=${results.execResult.logs?.length}`) } @@ -479,7 +476,7 @@ async function _runTx(this: VM, opts: RunTxOpts): Promise { } // Add data gas used to result - if (tx.type === 5) { + if (tx.type === 3) { results.dataGasUsed = totalDataGas } @@ -563,7 +560,13 @@ async function _runTx(this: VM, opts: RunTxOpts): Promise { // Generate the tx receipt const gasUsed = opts.blockGasUsed !== undefined ? opts.blockGasUsed : block.header.gasUsed const cumulativeGasUsed = gasUsed + results.totalGasSpent - results.receipt = await generateTxReceipt.bind(this)(tx, results, cumulativeGasUsed, totalDataGas) + results.receipt = await generateTxReceipt.bind(this)( + tx, + results, + cumulativeGasUsed, + totalDataGas, + dataGasPrice + ) /** * The `afterTx` event @@ -612,14 +615,16 @@ function txLogsBloom(logs?: any[]): Bloom { * @param tx The transaction * @param txResult The tx result * @param cumulativeGasUsed The gas used in the block including this tx - * @param totalDataGas The data gas used in the tx + * @param dataGasUsed The data gas used in the tx + * @param dataGasPrice The data gas price for the block including this tx */ export async function generateTxReceipt( this: VM, tx: TypedTransaction, txResult: RunTxResult, cumulativeGasUsed: bigint, - totalDataGas: bigint + dataGasUsed?: bigint, + dataGasPrice?: bigint ): Promise { const baseReceipt: BaseTxReceipt = { cumulativeBlockGasUsed: cumulativeGasUsed, @@ -658,7 +663,8 @@ export async function generateTxReceipt( // Typed EIP-2718 Transaction if (tx.type === 5) { receipt = { - dataGasUsed: totalDataGas, + dataGasUsed, + dataGasPrice, status: txResult.execResult.exceptionError ? 0 : 1, ...baseReceipt, } as EIP4844BlobTxReceipt diff --git a/packages/vm/src/types.ts b/packages/vm/src/types.ts index 6a2cd542b6..c2f5a5c87b 100644 --- a/packages/vm/src/types.ts +++ b/packages/vm/src/types.ts @@ -56,6 +56,13 @@ export interface EIP4844BlobTxReceipt extends PostByzantiumTxReceipt { * and is only provided as part of receipt metadata. */ dataGasUsed: bigint + /** + * Data gas price for block transaction was included in + * + * Note: This valus is not included in the `receiptRLP` used for encoding the `receiptsRoot` in a block + * and is only provided as part of receipt metadata. + */ + dataGasPrice: bigint } export type VMEvents = { diff --git a/packages/vm/test/api/runTx.spec.ts b/packages/vm/test/api/runTx.spec.ts index 29e82869d5..7fa892e5fd 100644 --- a/packages/vm/test/api/runTx.spec.ts +++ b/packages/vm/test/api/runTx.spec.ts @@ -921,7 +921,7 @@ tape('EIP 4844 transaction tests', async (t) => { const blockchain = await Blockchain.create({ validateBlocks: false, validateConsensus: false }) const vm = await VM.create({ common, blockchain }) - const tx = getTransaction(common, 5, true) as BlobEIP4844Transaction + const tx = getTransaction(common, 3, true) as BlobEIP4844Transaction const block = Block.fromBlockData( { @@ -945,5 +945,4 @@ tape('EIP 4844 transaction tests', async (t) => { Blockchain.prototype.getBlock = oldGetBlockFunction t.end() } - t.end() }) diff --git a/packages/vm/test/api/utils.ts b/packages/vm/test/api/utils.ts index 676fccb84b..8e7c6c6afc 100644 --- a/packages/vm/test/api/utils.ts +++ b/packages/vm/test/api/utils.ts @@ -1,11 +1,7 @@ import { Blockchain } from '@ethereumjs/blockchain' -import { TransactionFactory, kzg } from '@ethereumjs/tx' -import { - blobsToCommitments, - computeVersionedHash, - getBlobs, -} from '@ethereumjs/tx/dist/utils/blobHelpers' -import { Account } from '@ethereumjs/util' +import { TransactionFactory } from '@ethereumjs/tx' +import { Account, blobsToCommitments, computeVersionedHash, getBlobs } from '@ethereumjs/util' +import * as kzg from 'c-kzg' import { hexToBytes } from 'ethereum-cryptography/utils' import { MemoryLevel } from 'memory-level' @@ -101,7 +97,9 @@ export function getTransaction( txParams['maxFeePerDataGas'] = BigInt(100) txParams['blobs'] = getBlobs('hello world') txParams['kzgCommitments'] = blobsToCommitments(txParams['blobs']) - txParams['kzgProof'] = kzg.computeAggregateKzgProof(txParams['blobs']) + txParams['kzgProofs'] = txParams['blobs'].map((blob: Uint8Array, ctx: number) => + kzg.computeBlobKzgProof(blob, txParams['kzgCommitments'][ctx] as Uint8Array) + ) txParams['versionedHashes'] = txParams['kzgCommitments'].map((commitment: Uint8Array) => computeVersionedHash(commitment, 0x1) ) From eb75fcf67497114623d0745d2478ede48228b302 Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Fri, 14 Apr 2023 10:56:09 -0400 Subject: [PATCH 08/10] add datagasprice to receipt --- packages/client/lib/rpc/modules/eth.ts | 7 ++++--- packages/client/test/rpc/eth/getTransactionReceipt.spec.ts | 3 ++- packages/vm/src/runTx.ts | 2 +- packages/vm/src/types.ts | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/client/lib/rpc/modules/eth.ts b/packages/client/lib/rpc/modules/eth.ts index bc6bceda02..37c2695433 100644 --- a/packages/client/lib/rpc/modules/eth.ts +++ b/packages/client/lib/rpc/modules/eth.ts @@ -186,8 +186,8 @@ const jsonRpcReceipt = async ( ((receipt as PostByzantiumTxReceipt).status as unknown) instanceof Uint8Array ? intToHex((receipt as PostByzantiumTxReceipt).status) : undefined, - dataGasUsed: dataGasUsed !== undefined ? '0x' + bigIntToHex(dataGasUsed) : undefined, - dataGasPrice: dataGasPrice !== undefined ? '0x' + bigIntToHex(dataGasPrice) : undefined, + dataGasUsed: dataGasUsed !== undefined ? bigIntToHex(dataGasUsed) : undefined, + dataGasPrice: dataGasPrice !== undefined ? bigIntToHex(dataGasPrice) : undefined, }) /** @@ -775,8 +775,9 @@ export class Eth { root: parentBlock.header.stateRoot, skipBlockValidation: true, }) + const { totalGasSpent, createdAddress } = runBlockResult.results[txIndex] - const { dataGasUsed, dataGasPrice } = receipt as EIP4844BlobTxReceipt + const { dataGasPrice, dataGasUsed } = runBlockResult.receipts[txIndex] as EIP4844BlobTxReceipt return await jsonRpcReceipt( receipt, totalGasSpent, diff --git a/packages/client/test/rpc/eth/getTransactionReceipt.spec.ts b/packages/client/test/rpc/eth/getTransactionReceipt.spec.ts index 76e5de4f2e..7ecd944ac1 100644 --- a/packages/client/test/rpc/eth/getTransactionReceipt.spec.ts +++ b/packages/client/test/rpc/eth/getTransactionReceipt.spec.ts @@ -88,7 +88,7 @@ tape(`${method}: call with unknown tx hash`, async (t) => { await baseRequest(t, server, req, 200, expectRes) }) -tape(`${method}: get dataGasUsed in blob tx receipt`, async (t) => { +tape(`${method}: get dataGasUsed/dataGasPrice in blob tx receipt`, async (t) => { initKZG(kzg, __dirname + '/../../../lib/trustedSetups/devnet4.txt') const gethGenesis = require('../../../../block/test/testdata/4844-hardfork.json') const common = Common.fromGethGenesis(gethGenesis, { @@ -123,6 +123,7 @@ tape(`${method}: get dataGasUsed in blob tx receipt`, async (t) => { const req = params(method, [bytesToPrefixedHexString(tx.hash())]) const expectRes = (res: any) => { t.equal(res.body.result.dataGasUsed, '0x20000', 'receipt has correct data gas usage') + t.equal(res.body.result.dataGasPrice, '0x1', 'receipt has correct data gas price') } await baseRequest(t, server, req, 200, expectRes) diff --git a/packages/vm/src/runTx.ts b/packages/vm/src/runTx.ts index bd299744aa..ec5d15b6d2 100644 --- a/packages/vm/src/runTx.ts +++ b/packages/vm/src/runTx.ts @@ -661,7 +661,7 @@ export async function generateTxReceipt( } } else { // Typed EIP-2718 Transaction - if (tx.type === 5) { + if (tx.type === 3) { receipt = { dataGasUsed, dataGasPrice, diff --git a/packages/vm/src/types.ts b/packages/vm/src/types.ts index c2f5a5c87b..4c949a3365 100644 --- a/packages/vm/src/types.ts +++ b/packages/vm/src/types.ts @@ -6,7 +6,7 @@ import type { EEIInterface, EVMInterface, EVMResult, Log } from '@ethereumjs/evm import type { StateManager } from '@ethereumjs/statemanager' import type { AccessList, TypedTransaction } from '@ethereumjs/tx' import type { BigIntLike, WithdrawalData } from '@ethereumjs/util' -export type TxReceipt = PreByzantiumTxReceipt | PostByzantiumTxReceipt +export type TxReceipt = PreByzantiumTxReceipt | PostByzantiumTxReceipt | EIP4844BlobTxReceipt /** * Abstract interface with common transaction receipt fields From 38a2e7d3b708c7e9c3c3b18a6fc9db7e8113321d Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Fri, 14 Apr 2023 13:34:47 -0400 Subject: [PATCH 09/10] fix tests --- packages/client/test/rpc/eth/getTransactionReceipt.spec.ts | 6 +++++- packages/util/src/kzg.ts | 1 - packages/vm/karma.conf.js | 1 + 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/client/test/rpc/eth/getTransactionReceipt.spec.ts b/packages/client/test/rpc/eth/getTransactionReceipt.spec.ts index 7ecd944ac1..88d8c04497 100644 --- a/packages/client/test/rpc/eth/getTransactionReceipt.spec.ts +++ b/packages/client/test/rpc/eth/getTransactionReceipt.spec.ts @@ -89,7 +89,11 @@ tape(`${method}: call with unknown tx hash`, async (t) => { }) tape(`${method}: get dataGasUsed/dataGasPrice in blob tx receipt`, async (t) => { - initKZG(kzg, __dirname + '/../../../lib/trustedSetups/devnet4.txt') + try { + // Verified KZG is loaded correctly -- NOOP if throws + initKZG(kzg, __dirname + '/../../../lib/trustedSetups/devnet4.txt') + //eslint-disable-next-line + } catch {} const gethGenesis = require('../../../../block/test/testdata/4844-hardfork.json') const common = Common.fromGethGenesis(gethGenesis, { chain: 'customChain', diff --git a/packages/util/src/kzg.ts b/packages/util/src/kzg.ts index 05c48fd5f9..f0929f872c 100644 --- a/packages/util/src/kzg.ts +++ b/packages/util/src/kzg.ts @@ -37,6 +37,5 @@ export let kzg: Kzg = { */ export function initKZG(kzgLib: Kzg, trustedSetupPath: string) { kzg = kzgLib - kzg.loadTrustedSetup(trustedSetupPath) } diff --git a/packages/vm/karma.conf.js b/packages/vm/karma.conf.js index 96b97bb756..537ee3eaec 100644 --- a/packages/vm/karma.conf.js +++ b/packages/vm/karma.conf.js @@ -34,6 +34,7 @@ module.exports = function (config) { '@chainsafe/as-sha256/hashObject': '../../node_modules/@chainsafe/as-sha256/lib/hashObject.js', }, + ignore: ['c-kzg', 'safer-buffer'], }, }, }, From e3480a1486e610cf54e6491e233341bc7a6ae0f9 Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Fri, 14 Apr 2023 14:02:11 -0400 Subject: [PATCH 10/10] Fix vm browser test config --- package-lock.json | 2 +- .../rpc/eth/getTransactionReceipt.spec.ts | 87 ++++++++++--------- packages/vm/karma.conf.js | 2 +- 3 files changed, 48 insertions(+), 43 deletions(-) diff --git a/package-lock.json b/package-lock.json index 29e92707f4..0e7b70dcdb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19904,7 +19904,7 @@ "@types/minimist": "^1.2.2", "@types/node-dir": "^0.0.34", "benchmark": "^2.1.4", - "c-kzg": "*", + "c-kzg": "^2.0.4", "debug": "^4.3.3", "ethereum-cryptography": "^1.1.2", "level": "^8.0.0", diff --git a/packages/client/test/rpc/eth/getTransactionReceipt.spec.ts b/packages/client/test/rpc/eth/getTransactionReceipt.spec.ts index 88d8c04497..f7c2a097af 100644 --- a/packages/client/test/rpc/eth/getTransactionReceipt.spec.ts +++ b/packages/client/test/rpc/eth/getTransactionReceipt.spec.ts @@ -89,46 +89,51 @@ tape(`${method}: call with unknown tx hash`, async (t) => { }) tape(`${method}: get dataGasUsed/dataGasPrice in blob tx receipt`, async (t) => { - try { - // Verified KZG is loaded correctly -- NOOP if throws - initKZG(kzg, __dirname + '/../../../lib/trustedSetups/devnet4.txt') - //eslint-disable-next-line - } catch {} - const gethGenesis = require('../../../../block/test/testdata/4844-hardfork.json') - const common = Common.fromGethGenesis(gethGenesis, { - chain: 'customChain', - hardfork: Hardfork.ShardingForkDev, - }) - const { chain, execution, server } = await setupChain(gethGenesis, 'customChain') - common.setHardfork(Hardfork.ShardingForkDev) - - const blobs = getBlobs('hello world') - const commitments = blobsToCommitments(blobs) - const versionedHashes = commitmentsToVersionedHashes(commitments) - const proofs = blobs.map((blob, ctx) => kzg.computeBlobKzgProof(blob, commitments[ctx])) - const tx = BlobEIP4844Transaction.fromTxData( - { - versionedHashes, - blobs, - kzgCommitments: commitments, - kzgProofs: proofs, - maxFeePerDataGas: 1000000n, - gasLimit: 0xffffn, - maxFeePerGas: 10000000n, - maxPriorityFeePerGas: 1000000n, - to: randomBytes(20), - nonce: 0n, - }, - { common } - ).sign(dummy.privKey) - - await runBlockWithTxs(chain, execution, [tx], true) - - const req = params(method, [bytesToPrefixedHexString(tx.hash())]) - const expectRes = (res: any) => { - t.equal(res.body.result.dataGasUsed, '0x20000', 'receipt has correct data gas usage') - t.equal(res.body.result.dataGasPrice, '0x1', 'receipt has correct data gas price') + const isBrowser = new Function('try {return this===window;}catch(e){ return false;}') + if (isBrowser() === true) { + t.end() + } else { + try { + // Verified KZG is loaded correctly -- NOOP if throws + initKZG(kzg, __dirname + '/../../../lib/trustedSetups/devnet4.txt') + //eslint-disable-next-line + } catch {} + const gethGenesis = require('../../../../block/test/testdata/4844-hardfork.json') + const common = Common.fromGethGenesis(gethGenesis, { + chain: 'customChain', + hardfork: Hardfork.ShardingForkDev, + }) + const { chain, execution, server } = await setupChain(gethGenesis, 'customChain') + common.setHardfork(Hardfork.ShardingForkDev) + + const blobs = getBlobs('hello world') + const commitments = blobsToCommitments(blobs) + const versionedHashes = commitmentsToVersionedHashes(commitments) + const proofs = blobs.map((blob, ctx) => kzg.computeBlobKzgProof(blob, commitments[ctx])) + const tx = BlobEIP4844Transaction.fromTxData( + { + versionedHashes, + blobs, + kzgCommitments: commitments, + kzgProofs: proofs, + maxFeePerDataGas: 1000000n, + gasLimit: 0xffffn, + maxFeePerGas: 10000000n, + maxPriorityFeePerGas: 1000000n, + to: randomBytes(20), + nonce: 0n, + }, + { common } + ).sign(dummy.privKey) + + await runBlockWithTxs(chain, execution, [tx], true) + + const req = params(method, [bytesToPrefixedHexString(tx.hash())]) + const expectRes = (res: any) => { + t.equal(res.body.result.dataGasUsed, '0x20000', 'receipt has correct data gas usage') + t.equal(res.body.result.dataGasPrice, '0x1', 'receipt has correct data gas price') + } + + await baseRequest(t, server, req, 200, expectRes) } - - await baseRequest(t, server, req, 200, expectRes) }) diff --git a/packages/vm/karma.conf.js b/packages/vm/karma.conf.js index 537ee3eaec..0e3ecd7941 100644 --- a/packages/vm/karma.conf.js +++ b/packages/vm/karma.conf.js @@ -34,8 +34,8 @@ module.exports = function (config) { '@chainsafe/as-sha256/hashObject': '../../node_modules/@chainsafe/as-sha256/lib/hashObject.js', }, - ignore: ['c-kzg', 'safer-buffer'], }, + ignore: ['c-kzg', 'safer-buffer'], }, },