diff --git a/packages/client/lib/execution/receipt.ts b/packages/client/lib/execution/receipt.ts index f2c049c600..2b34fadb0a 100644 --- a/packages/client/lib/execution/receipt.ts +++ b/packages/client/lib/execution/receipt.ts @@ -2,7 +2,7 @@ import { PreByzantiumTxReceipt, PostByzantiumTxReceipt, TxReceipt } from '@ether import { Log } from '@ethereumjs/vm/dist/evm/types' import Bloom from '@ethereumjs/vm/dist/bloom' import { TypedTransaction } from '@ethereumjs/tx' -import { rlp, intToBuffer, bufferToInt } from 'ethereumjs-util' +import { rlp, intToBuffer, bufferToInt, bigIntToBuffer, bufferToBigInt } from 'ethereumjs-util' import { MetaDBManager, DBKey } from './metaDBManager' import type { Block } from '@ethereumjs/block' @@ -302,7 +302,7 @@ export class ReceiptsManager extends MetaDBManager { value.map((r) => [ (r as PreByzantiumTxReceipt).stateRoot ?? intToBuffer((r as PostByzantiumTxReceipt).status), - r.gasUsed, + bigIntToBuffer(r.gasUsed), this.rlp(RlpConvert.Encode, RlpType.Logs, r.logs), ]) ) @@ -315,14 +315,14 @@ export class ReceiptsManager extends MetaDBManager { // Pre-Byzantium Receipt return { stateRoot: r[0], - gasUsed, + gasUsed: bufferToBigInt(gasUsed), logs, } as PreByzantiumTxReceipt } else { // Post-Byzantium Receipt return { status: bufferToInt(r[0]), - gasUsed, + gasUsed: bufferToBigInt(gasUsed), logs, } as PostByzantiumTxReceipt } diff --git a/packages/client/lib/net/protocol/ethprotocol.ts b/packages/client/lib/net/protocol/ethprotocol.ts index d3907219b4..5b825b6cb9 100644 --- a/packages/client/lib/net/protocol/ethprotocol.ts +++ b/packages/client/lib/net/protocol/ethprotocol.ts @@ -233,7 +233,7 @@ export class EthProtocol extends Protocol { let encodedReceipt = rlp.encode([ (receipt as PreByzantiumTxReceipt).stateRoot ?? (receipt as PostByzantiumTxReceipt).status, - receipt.gasUsed, + bigIntToBuffer(receipt.gasUsed), receipt.bitvector, receipt.logs, ]) @@ -252,7 +252,11 @@ export class EthProtocol extends Protocol { // Legacy receipt if r[0] >= 0xc0, otherwise typed receipt with first byte as TransactionType const decoded = rlp.decode(r[0] >= 0xc0 ? r : r.slice(1)) as any const [stateRootOrStatus, cumulativeGasUsed, logsBloom, logs] = decoded - const receipt = { gasUsed: cumulativeGasUsed, bitvector: logsBloom, logs } as TxReceipt + const receipt = { + gasUsed: bufferToBigInt(cumulativeGasUsed), + bitvector: logsBloom, + logs, + } as TxReceipt if (stateRootOrStatus.length === 32) { ;(receipt as PreByzantiumTxReceipt).stateRoot = stateRootOrStatus } else { diff --git a/packages/client/lib/rpc/modules/eth.ts b/packages/client/lib/rpc/modules/eth.ts index 4714977888..67b52dd985 100644 --- a/packages/client/lib/rpc/modules/eth.ts +++ b/packages/client/lib/rpc/modules/eth.ts @@ -250,7 +250,7 @@ const jsonRpcReceipt = async ( blockNumber: bigIntToHex(block.header.number), from: tx.getSenderAddress().toString(), to: tx.to?.toString() ?? null, - cumulativeGasUsed: bufferToHex(receipt.gasUsed), + cumulativeGasUsed: bigIntToHex(receipt.gasUsed), effectiveGasPrice: bigIntToHex(effectiveGasPrice), gasUsed: bigIntToHex(gasUsed), contractAddress: contractAddress?.toString() ?? null, diff --git a/packages/client/lib/service/fullethereumservice.ts b/packages/client/lib/service/fullethereumservice.ts index 5c431f13cb..2b4290b14e 100644 --- a/packages/client/lib/service/fullethereumservice.ts +++ b/packages/client/lib/service/fullethereumservice.ts @@ -1,4 +1,5 @@ import { Hardfork } from '@ethereumjs/common' +import { bigIntToBuffer } from 'ethereumjs-util' import { EthereumService, EthereumServiceOptions } from './ethereumservice' import { TxPool } from './txpool' import { FullSynchronizer } from '../sync/fullsync' @@ -214,6 +215,7 @@ export class FullEthereumService extends EthereumService { let receiptsSize = 0 for (const hash of hashes) { const blockReceipts = await receiptsManager.getReceipts(hash, true, true) + blockReceipts.forEach((r) => (r.gasUsed = bigIntToBuffer(r.gasUsed) as any)) if (!blockReceipts) continue receipts.push(...blockReceipts) receiptsSize += Buffer.byteLength(JSON.stringify(blockReceipts)) diff --git a/packages/client/lib/util/debug.ts b/packages/client/lib/util/debug.ts index d9db31a7b5..c2c02b2487 100644 --- a/packages/client/lib/util/debug.ts +++ b/packages/client/lib/util/debug.ts @@ -43,7 +43,7 @@ const main = async () => { const stateManager = new DefaultStateManager({ trie, common }) // Ensure we run on the right root stateManager.setStateRoot(Buffer.from('${( - await execution.vm.stateManager.getStateRoot(true) + await execution.vm.stateManager.getStateRoot() ).toString('hex')}', 'hex')) diff --git a/packages/client/test/net/protocol/ethprotocol.spec.ts b/packages/client/test/net/protocol/ethprotocol.spec.ts index 03eae882f6..53d8338707 100644 --- a/packages/client/test/net/protocol/ethprotocol.spec.ts +++ b/packages/client/test/net/protocol/ethprotocol.spec.ts @@ -5,7 +5,7 @@ import { FeeMarketEIP1559Transaction } from '@ethereumjs/tx' import { Chain } from '../../../lib/blockchain/chain' import { Config } from '../../../lib/config' import { EthProtocol } from '../../../lib/net/protocol' -import { bigIntToBuffer, bufferToBigInt, intToBuffer } from 'ethereumjs-util' +import { bigIntToBuffer, bufferToBigInt } from 'ethereumjs-util' tape('[EthProtocol]', (t) => { t.test('should get properties', (t) => { @@ -151,14 +151,14 @@ tape('[EthProtocol]', (t) => { const receipts = [ { status: 1 as 0 | 1, - gasUsed: intToBuffer(100), + gasUsed: BigInt(100), bitvector: Buffer.alloc(256), logs: [[Buffer.alloc(20), [Buffer.alloc(32), Buffer.alloc(32, 1)], Buffer.alloc(10)]], txType: 2, }, { status: 0 as 0 | 1, - gasUsed: intToBuffer(1000), + gasUsed: BigInt(1000), bitvector: Buffer.alloc(256, 1), logs: [[Buffer.alloc(20, 1), [Buffer.alloc(32, 1), Buffer.alloc(32, 1)], Buffer.alloc(10)]], txType: 0, diff --git a/packages/client/test/service/fullethereumservice.spec.ts b/packages/client/test/service/fullethereumservice.spec.ts index 41d039dbe9..e227b8d696 100644 --- a/packages/client/test/service/fullethereumservice.spec.ts +++ b/packages/client/test/service/fullethereumservice.spec.ts @@ -1,7 +1,6 @@ import tape from 'tape' import td from 'testdouble' import { Log } from '@ethereumjs/vm/dist/evm/types' -import { intToBuffer } from 'ethereumjs-util' import { Config } from '../../lib/config' import { Event } from '../../lib/types' import { Chain } from '../../lib/blockchain' @@ -126,7 +125,7 @@ tape('[FullEthereumService]', async (t) => { const receipts = [ { status: 1 as 0 | 1, - gasUsed: intToBuffer(100), + gasUsed: BigInt(100), bitvector: Buffer.alloc(256), logs: [ [Buffer.alloc(20), [Buffer.alloc(32), Buffer.alloc(32, 1)], Buffer.alloc(10)], @@ -135,7 +134,7 @@ tape('[FullEthereumService]', async (t) => { }, { status: 0 as 0 | 1, - gasUsed: intToBuffer(1000), + gasUsed: BigInt(1000), bitvector: Buffer.alloc(256, 1), logs: [ [Buffer.alloc(20, 1), [Buffer.alloc(32, 1), Buffer.alloc(32, 1)], Buffer.alloc(10)], diff --git a/packages/vm/benchmarks/util.ts b/packages/vm/benchmarks/util.ts index 193df1a842..8c549aa6bd 100644 --- a/packages/vm/benchmarks/util.ts +++ b/packages/vm/benchmarks/util.ts @@ -68,10 +68,10 @@ export const verifyResult = (block: Block, result: RunBlockResult) => { // check if there are receipts const { receipts } = result if (receipts) { - let cumGasUsed = 0 + let cumGasUsed = BigInt(0) for (let index = 0; index < receipts.length; index++) { - let gasUsedExpected = parseInt(receipts[index].gasUsed.toString('hex'), 16) - let cumGasUsedActual = parseInt(receipts[index].gasUsed.toString('hex'), 16) + let gasUsedExpected = receipts[index].gasUsed + let cumGasUsedActual = receipts[index].gasUsed let gasUsed = cumGasUsedActual - cumGasUsed if (gasUsed !== gasUsedExpected) { console.log(`[DEBUG] diff --git a/packages/vm/src/buildBlock.ts b/packages/vm/src/buildBlock.ts index 3b055052b8..38bd04115b 100644 --- a/packages/vm/src/buildBlock.ts +++ b/packages/vm/src/buildBlock.ts @@ -226,7 +226,7 @@ export class BlockBuilder { await this.rewardMiner() } - const stateRoot = await this.vm.stateManager.getStateRoot(true) + const stateRoot = await this.vm.stateManager.getStateRoot() const transactionsTrie = await this.transactionsTrie() const receiptTrie = await this.receiptTrie() const logsBloom = this.logsBloom() diff --git a/packages/vm/src/evm/eei.ts b/packages/vm/src/evm/eei.ts index 9598dd0393..e0959a6e94 100644 --- a/packages/vm/src/evm/eei.ts +++ b/packages/vm/src/evm/eei.ts @@ -293,13 +293,7 @@ export default class EEI { getBlockCoinbase(): bigint { let coinbase: Address if (this._common.consensusAlgorithm() === ConsensusAlgorithm.Clique) { - // Backwards-compatibilty check - // TODO: can be removed along VM v5 release - if ('cliqueSigner' in this._env.block.header) { - coinbase = this._env.block.header.cliqueSigner() - } else { - coinbase = Address.zero() - } + coinbase = this._env.block.header.cliqueSigner() } else { coinbase = this._env.block.header.coinbase } @@ -581,7 +575,7 @@ export default class EEI { } // this should always be safe - this.useGas(results.gasUsed, 'CALL, STATICCALL, DELEGATECALL, CALLCODE') + this.useGas(results.execResult.gasUsed, 'CALL, STATICCALL, DELEGATECALL, CALLCODE') // Set return value if ( @@ -654,7 +648,7 @@ export default class EEI { } // this should always be safe - this.useGas(results.gasUsed, 'CREATE') + this.useGas(results.execResult.gasUsed, 'CREATE') // Set return buffer in case revert happened if ( diff --git a/packages/vm/src/evm/evm.ts b/packages/vm/src/evm/evm.ts index 6e4e79cc4a..2ac41dceea 100644 --- a/packages/vm/src/evm/evm.ts +++ b/packages/vm/src/evm/evm.ts @@ -9,6 +9,7 @@ import { MAX_INTEGER, } from 'ethereumjs-util' import { Block } from '@ethereumjs/block' +import { Hardfork } from '@ethereumjs/common' import { ERROR, VmError } from '../exceptions' import { StateManager } from '../state/index' import { PrecompileFunc } from './precompiles' @@ -31,17 +32,17 @@ const debugGas = createDebugLogger('vm:evm:gas') */ export interface EVMResult { /** - * Amount of gas used by the transaction - */ - gasUsed: bigint - /** - * Address of created account durint transaction, if any + * Address of created account during transaction, if any */ createdAddress?: Address /** * Contains the results from running the code, if any, as described in {@link runCode} */ execResult: ExecResult + /** + * Total amount of gas to be refunded from all nested calls. + */ + gasRefund?: bigint } /** @@ -50,7 +51,7 @@ export interface EVMResult { export interface ExecResult { runState?: RunState /** - * Description of the exception, if any occured + * Description of the exception, if any occurred */ exceptionError?: VmError /** @@ -58,7 +59,7 @@ export interface ExecResult { */ gas?: bigint /** - * Amount of gas the code used to run + * Amount of gas the transaction used to run */ gasUsed: bigint /** @@ -73,10 +74,6 @@ export interface ExecResult { * A map from the accounts that have self-destructed to the addresses to send their funds to */ selfdestruct?: { [k: string]: Buffer } - /** - * Total amount of gas to be refunded from all nested calls. - */ - gasRefund?: bigint } export interface NewContractEvent { @@ -195,26 +192,27 @@ export default class EVM { result = await this._executeCreate(message) } if (this._vm.DEBUG) { - const { gasUsed, exceptionError, returnValue, gasRefund } = result.execResult + const { gasUsed, exceptionError, returnValue } = result.execResult debug( `Received message execResult: [ gasUsed=${gasUsed} exceptionError=${ exceptionError ? `'${exceptionError.error}'` : 'none' - } returnValue=0x${short(returnValue)} gasRefund=${gasRefund ?? 0} ]` + } returnValue=0x${short(returnValue)} gasRefund=${result.gasRefund ?? 0} ]` ) } const err = result.execResult.exceptionError // This clause captures any error which happened during execution // If that is the case, then set the _refund tracker to the old refund value if (err) { - // TODO: Move `gasRefund` to a tx-level result object - // instead of `ExecResult`. this._refund = oldRefund result.execResult.selfdestruct = {} } - result.execResult.gasRefund = this._refund + result.gasRefund = this._refund if (err) { - if (this._vm._common.gteHardfork('homestead') || err.error != ERROR.CODESTORE_OUT_OF_GAS) { + if ( + this._vm._common.gteHardfork(Hardfork.Homestead) || + err.error != ERROR.CODESTORE_OUT_OF_GAS + ) { result.execResult.logs = [] await this._state.revert() this._transientStorage.revert() @@ -278,7 +276,6 @@ export default class EVM { } if (exit) { return { - gasUsed: BigInt(0), execResult: { gasUsed: BigInt(0), exceptionError: errorMessage, // Only defined if addToBalance failed @@ -305,7 +302,6 @@ export default class EVM { } return { - gasUsed: result.gasUsed, execResult: result, } } @@ -318,7 +314,6 @@ export default class EVM { if (this._vm._common.isActivatedEIP(3860)) { if (message.data.length > this._vm._common.param('vm', 'maxInitCodeSize')) { return { - gasUsed: message.gasLimit, createdAddress: message.to, execResult: { returnValue: Buffer.alloc(0), @@ -346,7 +341,6 @@ export default class EVM { debug(`Returning on address collision`) } return { - gasUsed: message.gasLimit, createdAddress: message.to, execResult: { returnValue: Buffer.alloc(0), @@ -367,7 +361,7 @@ export default class EVM { toAccount = await this._state.getAccount(message.to) // EIP-161 on account creation and CREATE execution - if (this._vm._common.gteHardfork('spuriousDragon')) { + if (this._vm._common.gteHardfork(Hardfork.SpuriousDragon)) { toAccount.nonce += BigInt(1) } @@ -394,7 +388,6 @@ export default class EVM { } if (exit) { return { - gasUsed: BigInt(0), createdAddress: message.to, execResult: { gasUsed: BigInt(0), @@ -426,7 +419,7 @@ export default class EVM { let allowedCodeSize = true if ( !result.exceptionError && - this._vm._common.gteHardfork('spuriousDragon') && + this._vm._common.gteHardfork(Hardfork.SpuriousDragon) && result.returnValue.length > this._vm._common.param('vm', 'maxCodeSize') ) { allowedCodeSize = false @@ -470,7 +463,7 @@ export default class EVM { result.gasUsed = totalGas } } else { - if (this._vm._common.gteHardfork('homestead')) { + if (this._vm._common.gteHardfork(Hardfork.Homestead)) { if (this._vm.DEBUG) { debug(`Not enough gas or code size not allowed (>= Homestead)`) } @@ -498,7 +491,7 @@ export default class EVM { } } else if (CodestoreOOG) { // This only happens at Frontier. But, let's do a sanity check; - if (!this._vm._common.gteHardfork('homestead')) { + if (!this._vm._common.gteHardfork(Hardfork.Homestead)) { // Pre-Homestead behavior; put an empty contract. // This contract would be considered "DEAD" in later hard forks. // It is thus an unecessary default item, which we have to save to dik @@ -510,7 +503,6 @@ export default class EVM { } return { - gasUsed: result.gasUsed, createdAddress: message.to, execResult: result, } diff --git a/packages/vm/src/index.ts b/packages/vm/src/index.ts index 7837698cdf..9fe69d8f2b 100644 --- a/packages/vm/src/index.ts +++ b/packages/vm/src/index.ts @@ -76,11 +76,6 @@ export interface VMOpts { * A {@link StateManager} instance to use as the state store (Beta API) */ stateManager?: StateManager - /** - * A {@link SecureTrie} instance for the state tree (ignored if stateManager is passed) - * @deprecated will be removed in next major version release - */ - state?: Trie /** * A {@link Blockchain} object for storing/retrieving blocks */ @@ -306,7 +301,7 @@ export default class VM extends AsyncEventEmitter { if (opts.stateManager) { this.stateManager = opts.stateManager } else { - const trie = opts.state ?? new Trie() + const trie = new Trie() this.stateManager = new DefaultStateManager({ trie, common: this._common, diff --git a/packages/vm/src/runBlock.ts b/packages/vm/src/runBlock.ts index faddd41677..576b84dfb4 100644 --- a/packages/vm/src/runBlock.ts +++ b/packages/vm/src/runBlock.ts @@ -1,6 +1,6 @@ import { debug as createDebugLogger } from 'debug' import { BaseTrie as Trie } from 'merkle-patricia-tree' -import { Account, Address, bigIntToBuffer, intToBuffer, rlp } from 'ethereumjs-util' +import { Account, Address, intToBuffer, rlp } from 'ethereumjs-util' import { Block } from '@ethereumjs/block' import { ConsensusType, Hardfork } from '@ethereumjs/common' import VM from './index' @@ -9,15 +9,8 @@ import { StateManager } from './state' import { short } from './evm/opcodes' import { Capability, TypedTransaction } from '@ethereumjs/tx' import type { RunTxResult } from './runTx' -import type { TxReceipt } from './types' -import * as DAOConfig from './config/dao_fork_accounts_config.json' - -// For backwards compatibility from v5.3.0, -// TxReceipts are exported. These exports are -// deprecated and may be removed soon, please -// update your imports to the new types file. -import { PreByzantiumTxReceipt, PostByzantiumTxReceipt, EIP2930Receipt } from './types' -export { PreByzantiumTxReceipt, PostByzantiumTxReceipt, EIP2930Receipt } +import type { TxReceipt, PreByzantiumTxReceipt, PostByzantiumTxReceipt } from './types' +import DAOConfig from './config/dao_fork_accounts_config.json' const debug = createDebugLogger('vm:block') @@ -184,7 +177,7 @@ export default async function runBlock(this: VM, opts: RunBlockOpts): Promise= Byzantium)` - } else { - // Pre-Byzantium - const stateRoot = await this.stateManager.getStateRoot(true) - txReceipt = { - stateRoot: stateRoot, - ...abstractTxReceipt, - } as PreByzantiumTxReceipt - receiptLog += ` stateRoot=${txReceipt.stateRoot.toString('hex')} (< Byzantium)` - } - encodedReceipt = rlp.encode(Object.values(txReceipt)) - } else { - // EIP2930 Transaction - txReceipt = { - status: txRes.execResult.exceptionError ? 0 : 1, - ...abstractTxReceipt, - } as PostByzantiumTxReceipt - encodedReceipt = Buffer.concat([intToBuffer(tx.type), rlp.encode(Object.values(txReceipt))]) - } - return { - txReceipt, - encodedReceipt, - receiptLog, - } -} - -// apply the DAO fork changes to the VM async function _applyDAOHardfork(state: StateManager) { const DAORefundContractAddress = new Address(Buffer.from(DAORefundContract, 'hex')) if (!state.accountExists(DAORefundContractAddress)) { diff --git a/packages/vm/src/runCode.ts b/packages/vm/src/runCode.ts index 6a3adaebad..27e9af4ebf 100644 --- a/packages/vm/src/runCode.ts +++ b/packages/vm/src/runCode.ts @@ -49,7 +49,7 @@ export interface RunCodeOpts { /** * Gas limit */ - gasLimit?: bigint + gasLimit: bigint /** * The value in ether that is being sent to `opt.address`. Defaults to `0` */ diff --git a/packages/vm/src/runTx.ts b/packages/vm/src/runTx.ts index 72b851b86f..56d21b5bd5 100644 --- a/packages/vm/src/runTx.ts +++ b/packages/vm/src/runTx.ts @@ -1,5 +1,5 @@ import { debug as createDebugLogger } from 'debug' -import { Address, bigIntToBuffer, KECCAK256_NULL, toBuffer } from 'ethereumjs-util' +import { Address, KECCAK256_NULL, toBuffer } from 'ethereumjs-util' import { Block } from '@ethereumjs/block' import { ConsensusType } from '@ethereumjs/common' import { @@ -93,6 +93,11 @@ export interface RunTxResult extends EVMResult { */ receipt: TxReceipt + /** + * The amount of gas used in this transaction + */ + gasUsed: bigint + /** * The amount of gas as that was refunded during the transaction (i.e. `gasUsed = totalGasConsumed - gasRefund`) */ @@ -352,8 +357,8 @@ async function _runTx(this: VM, opts: RunTxOpts): Promise { } } - let gasPrice - let inclusionFeePerGas + let gasPrice: bigint + let inclusionFeePerGas: bigint // EIP-1559 tx if (tx.supports(Capability.EIP1559FeeMarket)) { const baseFee = block.header.baseFeePerGas! @@ -412,12 +417,12 @@ async function _runTx(this: VM, opts: RunTxOpts): Promise { const results = (await evm.executeMessage(message)) as RunTxResult if (this.DEBUG) { - const { gasUsed, exceptionError, returnValue, gasRefund } = results.execResult + const { gasUsed, exceptionError, returnValue } = results.execResult debug('-'.repeat(100)) debug( `Received tx execResult: [ gasUsed=${gasUsed} exceptionError=${ exceptionError ? `'${exceptionError.error}'` : 'none' - } returnValue=0x${short(returnValue)} gasRefund=${gasRefund ?? 0} ]` + } returnValue=0x${short(returnValue)} gasRefund=${results.gasRefund ?? 0} ]` ) } @@ -430,14 +435,14 @@ async function _runTx(this: VM, opts: RunTxOpts): Promise { debug(`Generated tx bloom with logs=${results.execResult.logs?.length}`) } - // Caculate the total gas used - results.gasUsed += txBaseFee + // Calculate the total gas used + results.gasUsed = results.execResult.gasUsed + txBaseFee if (this.DEBUG) { debugGas(`tx add baseFee ${txBaseFee} to gasUsed (-> ${results.gasUsed})`) } // Process any gas refund - let gasRefund = results.execResult.gasRefund ?? BigInt(0) + let gasRefund = results.gasRefund ?? BigInt(0) const maxRefundQuotient = BigInt(this._common.param('gasConfig', 'maxRefundQuotient')) if (gasRefund !== BigInt(0)) { const maxRefund = results.gasUsed / maxRefundQuotient @@ -468,13 +473,7 @@ async function _runTx(this: VM, opts: RunTxOpts): Promise { // Update miner's balance let miner if (this._common.consensusType() === ConsensusType.ProofOfAuthority) { - // Backwards-compatibility check - // TODO: can be removed along VM v6 release - if ('cliqueSigner' in block.header) { - miner = block.header.cliqueSigner() - } else { - miner = Address.zero() - } + miner = block.header.cliqueSigner() } else { miner = block.header.coinbase } @@ -482,7 +481,7 @@ async function _runTx(this: VM, opts: RunTxOpts): Promise { const minerAccount = await state.getAccount(miner) // add the amount spent on gas to the miner's account if (this._common.isActivatedEIP(1559)) { - minerAccount.balance += results.gasUsed * inclusionFeePerGas + minerAccount.balance += results.gasUsed * inclusionFeePerGas! } else { minerAccount.balance += results.amountSpent } @@ -571,7 +570,7 @@ export async function generateTxReceipt( cumulativeGasUsed: bigint ): Promise { const baseReceipt: BaseTxReceipt = { - gasUsed: bigIntToBuffer(cumulativeGasUsed), + gasUsed: cumulativeGasUsed, bitvector: txResult.bloom.bitvector, logs: txResult.execResult.logs ?? [], } @@ -597,7 +596,7 @@ export async function generateTxReceipt( } as PostByzantiumTxReceipt } else { // Pre-Byzantium - const stateRoot = await this.stateManager.getStateRoot(true) + const stateRoot = await this.stateManager.getStateRoot() receipt = { stateRoot: stateRoot, ...baseReceipt, diff --git a/packages/vm/src/state/interface.ts b/packages/vm/src/state/interface.ts index 353e7f5d64..87db447487 100644 --- a/packages/vm/src/state/interface.ts +++ b/packages/vm/src/state/interface.ts @@ -27,7 +27,7 @@ export interface StateManager { checkpoint(): Promise commit(): Promise revert(): Promise - getStateRoot(force?: boolean): Promise + getStateRoot(): Promise setStateRoot(stateRoot: Buffer): Promise dumpStorage(address: Address): Promise hasGenesisState(): Promise diff --git a/packages/vm/src/types.ts b/packages/vm/src/types.ts index 92b62cddd1..0fdf8ca2a6 100644 --- a/packages/vm/src/types.ts +++ b/packages/vm/src/types.ts @@ -1,6 +1,6 @@ import { Log } from './evm/types' -export type TxReceipt = PreByzantiumTxReceipt | PostByzantiumTxReceipt | EIP2930Receipt +export type TxReceipt = PreByzantiumTxReceipt | PostByzantiumTxReceipt /** * Abstract interface with common transaction receipt fields @@ -9,7 +9,7 @@ export interface BaseTxReceipt { /** * Cumulative gas used in the block including this tx */ - gasUsed: Buffer + gasUsed: bigint /** * Bloom bitvector */ @@ -41,17 +41,3 @@ export interface PostByzantiumTxReceipt extends BaseTxReceipt { */ status: 0 | 1 } - -/** - * EIP2930Receipt, which has the same fields as PostByzantiumTxReceipt - * - * @deprecated Please use PostByzantiumTxReceipt instead - */ -export interface EIP2930Receipt extends PostByzantiumTxReceipt {} - -/** - * EIP1559Receipt, which has the same fields as PostByzantiumTxReceipt - * - * @deprecated Please use PostByzantiumTxReceipt instead - */ -export interface EIP1559Receipt extends PostByzantiumTxReceipt {} diff --git a/packages/vm/tests/api/EIPs/eip-1283-net-gas-metering.spec.ts b/packages/vm/tests/api/EIPs/eip-1283-net-gas-metering.spec.ts index 0af0902196..56f61d16cf 100644 --- a/packages/vm/tests/api/EIPs/eip-1283-net-gas-metering.spec.ts +++ b/packages/vm/tests/api/EIPs/eip-1283-net-gas-metering.spec.ts @@ -52,9 +52,9 @@ tape('Constantinople: EIP-1283', async (t) => { try { const res = await vm.runCall(runCallArgs) - st.assert(res.execResult.exceptionError === undefined) - st.assert(BigInt(testCase.used) === res.gasUsed) - st.assert(BigInt(testCase.refund) === res.execResult.gasRefund!) + st.equal(res.execResult.exceptionError, undefined) + st.equal(res.execResult.gasUsed, BigInt(testCase.used)) + st.equal(res.gasRefund, BigInt(testCase.refund)) } catch (e: any) { st.fail(e.message) } diff --git a/packages/vm/tests/api/EIPs/eip-2929.spec.ts b/packages/vm/tests/api/EIPs/eip-2929.spec.ts index a23aa2e6cf..5e7067d529 100644 --- a/packages/vm/tests/api/EIPs/eip-2929.spec.ts +++ b/packages/vm/tests/api/EIPs/eip-2929.spec.ts @@ -99,7 +99,7 @@ tape('EIP 2929: gas cost tests', (t) => { const result = await vm.runTx({ tx }) - st.ok(result.gasUsed == expectedGasUsed) + st.equal(result.gasUsed, expectedGasUsed) } // Checks EXT(codehash,codesize,balance) of precompiles, which should be 100, diff --git a/packages/vm/tests/api/EIPs/eip-3529.spec.ts b/packages/vm/tests/api/EIPs/eip-3529.spec.ts index 17c45918b3..1d9f78adf1 100644 --- a/packages/vm/tests/api/EIPs/eip-3529.spec.ts +++ b/packages/vm/tests/api/EIPs/eip-3529.spec.ts @@ -170,9 +170,8 @@ tape('EIP-3529 tests', (t) => { tx, }) - st.equal(result.execResult.exceptionError, undefined, 'transaction executed succesfully') - st.ok(result.execResult.gasRefund !== undefined, 'gas refund is defined') - st.equal(result.execResult.gasRefund, BigInt(0), 'gas refund is zero') + st.equal(result.execResult.exceptionError, undefined, 'transaction executed successfully') + st.equal(result.gasRefund, BigInt(0), 'gas refund is zero') st.end() }) @@ -224,9 +223,8 @@ tape('EIP-3529 tests', (t) => { const actualGasUsed = startGas! - finalGas! + BigInt(21000) const maxRefund = actualGasUsed / BigInt(5) const minGasUsed = actualGasUsed - maxRefund - const gasUsed = result.execResult.gasUsed - st.ok(result.execResult.gasRefund! > maxRefund, 'refund is larger than the max refund') - st.ok(gasUsed >= minGasUsed, 'gas used respects the max refund quotient') + st.ok(result.gasRefund! > maxRefund, 'refund is larger than the max refund') + st.ok(result.gasUsed >= minGasUsed, 'gas used respects the max refund quotient') st.end() }) }) diff --git a/packages/vm/tests/api/buildBlock.spec.ts b/packages/vm/tests/api/buildBlock.spec.ts index 588ec2cf73..597c4a3f5a 100644 --- a/packages/vm/tests/api/buildBlock.spec.ts +++ b/packages/vm/tests/api/buildBlock.spec.ts @@ -104,7 +104,7 @@ tape('BlockBuilder', async (t) => { await blockBuilder.addTransaction(tx) - const root1 = await vm.stateManager.getStateRoot(true) + const root1 = await vm.stateManager.getStateRoot() st.ok(!root0.equals(root1), 'state root should change after adding a tx') await blockBuilder.revert() diff --git a/packages/vm/tests/api/evm/precompiles/hardfork.spec.ts b/packages/vm/tests/api/evm/precompiles/hardfork.spec.ts index 5676b082bc..3a1460543c 100644 --- a/packages/vm/tests/api/evm/precompiles/hardfork.spec.ts +++ b/packages/vm/tests/api/evm/precompiles/hardfork.spec.ts @@ -28,7 +28,7 @@ tape('Precompiles: hardfork availability', (t) => { value: BigInt(0), }) - st.assert(result.gasUsed === BigInt(100000)) // check that we are using gas (if address would contain no code we use 0 gas) + st.equal(result.execResult.gasUsed, BigInt(100000)) // check that we are using gas (if address would contain no code we use 0 gas) // Check if ECPAIR is available in future hard forks. const commonPetersburg = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Petersburg }) @@ -47,7 +47,7 @@ tape('Precompiles: hardfork availability', (t) => { value: BigInt(0), }) - st.assert(result.gasUsed === BigInt(100000)) + st.equal(result.execResult.gasUsed, BigInt(100000)) // Check if ECPAIR is not available in Homestead. const commonHomestead = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Homestead }) @@ -68,7 +68,7 @@ tape('Precompiles: hardfork availability', (t) => { value: BigInt(0), }) - st.assert(result.gasUsed === BigInt(0)) // check that we use no gas, because we are calling into an address without code. + st.equal(result.execResult.gasUsed, BigInt(0)) // check that we use no gas, because we are calling into an address without code. st.end() }) diff --git a/packages/vm/tests/api/index.spec.ts b/packages/vm/tests/api/index.spec.ts index 70b1a47c94..c2ef8728da 100644 --- a/packages/vm/tests/api/index.spec.ts +++ b/packages/vm/tests/api/index.spec.ts @@ -1,6 +1,5 @@ import tape from 'tape' import { KECCAK256_RLP } from 'ethereumjs-util' -import { SecureTrie as Trie } from 'merkle-patricia-tree' import Common, { Chain, Hardfork } from '@ethereumjs/common' import { DefaultStateManager } from '../../src/state' import VM from '../../src' @@ -179,17 +178,6 @@ tape('VM -> hardforkByBlockNumber, hardforkByTD, state (deprecated), blockchain' st.end() }) - t.test('should work with trie (state) provided', async (st) => { - const trie = new Trie() - const vm = await VM.create({ state: trie, activatePrecompiles: true }) - st.notDeepEqual( - (vm.stateManager as DefaultStateManager)._trie.root, - KECCAK256_RLP, - 'it has different root' - ) - st.end() - }) - t.test('should instantiate', async (st) => { const vm = await setupVM() st.deepEqual( diff --git a/packages/vm/tests/api/istanbul/eip-2200.spec.ts b/packages/vm/tests/api/istanbul/eip-2200.spec.ts index 6d47e76a63..4c6b84b9a0 100644 --- a/packages/vm/tests/api/istanbul/eip-2200.spec.ts +++ b/packages/vm/tests/api/istanbul/eip-2200.spec.ts @@ -72,10 +72,10 @@ tape('Istanbul: EIP-2200', async (t) => { if (testCase.err) { st.equal(res.execResult.exceptionError?.error, testCase.err) } else { - st.assert(res.execResult.exceptionError === undefined) + st.equal(res.execResult.exceptionError, undefined) } - st.assert(BigInt(testCase.used) === res.gasUsed) - st.assert(BigInt(testCase.refund) === res.execResult.gasRefund!) + st.equal(res.execResult.gasUsed, BigInt(testCase.used)) + st.equal(res.gasRefund!, BigInt(testCase.refund)) } catch (e: any) { st.fail(e.message) } diff --git a/packages/vm/tests/api/runBlock.spec.ts b/packages/vm/tests/api/runBlock.spec.ts index afdc1cd84e..1d3530a9f9 100644 --- a/packages/vm/tests/api/runBlock.spec.ts +++ b/packages/vm/tests/api/runBlock.spec.ts @@ -1,5 +1,5 @@ import tape from 'tape' -import { Address, rlp, KECCAK256_RLP, Account, bufferToBigInt } from 'ethereumjs-util' +import { Address, rlp, KECCAK256_RLP, Account } from 'ethereumjs-util' import Common, { Chain, Hardfork } from '@ethereumjs/common' import { Block } from '@ethereumjs/block' import { @@ -171,14 +171,14 @@ tape('runBlock() -> successful API parameter usage', async (t) => { skipBlockValidation: true, generate: true, }) - st.ok( - txResultChainstart.results[0].gasUsed === - BigInt(21000) + BigInt(68) * BigInt(3) + BigInt(3) + BigInt(50), + st.equal( + txResultChainstart.results[0].gasUsed, + BigInt(21000) + BigInt(68) * BigInt(3) + BigInt(3) + BigInt(50), 'tx charged right gas on chainstart hard fork' ) - st.ok( - txResultMuirGlacier.results[0].gasUsed === - BigInt(21000) + BigInt(32000) + BigInt(16) * BigInt(3) + BigInt(3) + BigInt(800), + st.equal( + txResultMuirGlacier.results[0].gasUsed, + BigInt(21000) + BigInt(32000) + BigInt(16) * BigInt(3) + BigInt(3) + BigInt(800), 'tx charged right gas on muir glacier hard fork' ) }) @@ -302,7 +302,7 @@ tape('runBlock() -> runtime behavior', async (t) => { // verify that the refund account gets the summed balance of the original refund account + two child DAO accounts const msg = 'should transfer balance from DAO children to the Refund DAO account in the DAO fork' - t.ok(DAORefundAccount.balance === BigInt(0x7777), msg) + t.equal(DAORefundAccount.balance, BigInt(0x7777), msg) }) t.test('should allocate to correct clique beneficiary', async (t) => { @@ -393,7 +393,7 @@ tape('should correctly reflect generated fields', async (t) => { t.ok(results.block.header.receiptTrie.equals(KECCAK256_RLP)) t.ok(results.block.header.transactionsTrie.equals(KECCAK256_RLP)) - t.equals(results.block.header.gasUsed, BigInt(0)) + t.equal(results.block.header.gasUsed, BigInt(0)) }) async function runWithHf(hardfork: string) { @@ -457,14 +457,11 @@ tape('runBlock() -> tx types', async (t) => { generate: true, }) - st.ok( - res.gasUsed === - res.receipts - .map((r) => r.gasUsed) - .reduce( - (prevValue: bigint, currValue: Buffer) => prevValue + bufferToBigInt(currValue), - BigInt(0) - ), + st.equal( + res.gasUsed, + res.receipts + .map((r) => r.gasUsed) + .reduce((prevValue, currValue) => prevValue + currValue, BigInt(0)), "gas used should equal transaction's total gasUsed" ) } diff --git a/packages/vm/tests/api/runCall.spec.ts b/packages/vm/tests/api/runCall.spec.ts index 3487adebf9..fe5d73b911 100644 --- a/packages/vm/tests/api/runCall.spec.ts +++ b/packages/vm/tests/api/runCall.spec.ts @@ -167,7 +167,7 @@ tape('Ensure that precompile activation creates non-empty accounts', async (t) = const resultNotActivated = await vmNotActivated.runCall(runCallArgs) const resultActivated = await vmActivated.runCall(runCallArgs) - const diff = resultNotActivated.gasUsed - resultActivated.gasUsed + const diff = resultNotActivated.execResult.gasUsed - resultActivated.execResult.gasUsed const expected = BigInt(common.param('gasPrices', 'callNewAccount')) t.equal(diff, expected, 'precompiles are activated') @@ -220,8 +220,8 @@ tape('Ensure that Istanbul sstoreCleanRefundEIP2200 gas is applied correctly', a const result = await vm.runCall(runCallArgs) - t.equal(result.gasUsed, BigInt(5812), 'gas used correct') - t.equal(result.execResult.gasRefund!, BigInt(4200), 'gas refund correct') + t.equal(result.execResult.gasUsed, BigInt(5812), 'gas used correct') + t.equal(result.gasRefund, BigInt(4200), 'gas refund correct') t.end() }) @@ -247,8 +247,8 @@ tape('ensure correct gas for pre-constantinople sstore', async (t) => { const result = await vm.runCall(runCallArgs) - t.equal(result.gasUsed, BigInt(20006), 'gas used correct') - t.equal(result.execResult.gasRefund!, BigInt(0), 'gas refund correct') + t.equal(result.execResult.gasUsed, BigInt(20006), 'gas used correct') + t.equal(result.gasRefund, BigInt(0), 'gas refund correct') t.end() }) @@ -276,8 +276,8 @@ tape('ensure correct gas for calling non-existent accounts in homestead', async // 7x push + gas + sub + call + callNewAccount // 7*3 + 2 + 3 + 40 + 25000 = 25066 - t.equal(result.gasUsed, BigInt(25066), 'gas used correct') - t.equal(result.execResult.gasRefund!, BigInt(0), 'gas refund correct') + t.equal(result.execResult.gasUsed, BigInt(25066), 'gas used correct') + t.equal(result.gasRefund, BigInt(0), 'gas refund correct') t.end() }) @@ -306,8 +306,8 @@ tape( const result = await vm.runCall(runCallArgs) - t.ok(runCallArgs.gasLimit === result.gasUsed, 'gas used correct') - t.equal(result.execResult.gasRefund!, BigInt(0), 'gas refund correct') + t.equal(runCallArgs.gasLimit, result.execResult.gasUsed, 'gas used correct') + t.equal(result.gasRefund, BigInt(0), 'gas refund correct') t.ok(result.execResult.exceptionError!.error == ERROR.OUT_OF_GAS, 'call went out of gas') t.end() @@ -337,9 +337,9 @@ tape('ensure selfdestruct pays for creating new accounts', async (t) => { const result = await vm.runCall(runCallArgs) // gas: 5000 (selfdestruct) + 25000 (call new account) + push (1) = 30003 - t.equal(result.gasUsed, BigInt(30003), 'gas used correct') + t.equal(result.execResult.gasUsed, BigInt(30003), 'gas used correct') // selfdestruct refund - t.equal(result.execResult.gasRefund!, BigInt(24000), 'gas refund correct') + t.equal(result.gasRefund, BigInt(24000), 'gas refund correct') t.end() }) @@ -403,8 +403,8 @@ tape('ensure that sstores pay for the right gas costs pre-byzantium', async (t) } const result = await vm.runCall(runCallArgs) - t.equal(result.gasUsed, BigInt(callData.gas), 'gas used correct') - t.equal(result.execResult.gasRefund, BigInt(callData.refund), 'gas refund correct') + t.equal(result.execResult.gasUsed, BigInt(callData.gas), 'gas used correct') + t.equal(result.gasRefund, BigInt(callData.refund), 'gas refund correct') } t.end() diff --git a/packages/vm/tests/api/runCode.spec.ts b/packages/vm/tests/api/runCode.spec.ts index 0f4543f20d..aa1d208c3d 100644 --- a/packages/vm/tests/api/runCode.spec.ts +++ b/packages/vm/tests/api/runCode.spec.ts @@ -102,6 +102,7 @@ tape('VM.runCode: RunCodeOptions', (t) => { const runCodeArgs = { value: BigInt(-10), + gasLimit: BigInt(1000000), } try { diff --git a/packages/vm/tests/api/runTx.spec.ts b/packages/vm/tests/api/runTx.spec.ts index a477da6318..5908a899e8 100644 --- a/packages/vm/tests/api/runTx.spec.ts +++ b/packages/vm/tests/api/runTx.spec.ts @@ -1,5 +1,5 @@ import tape from 'tape' -import { Account, Address, MAX_INTEGER, toBuffer, bufferToBigInt } from 'ethereumjs-util' +import { Account, Address, MAX_INTEGER } from 'ethereumjs-util' import { Block } from '@ethereumjs/block' import Common, { Chain, Hardfork } from '@ethereumjs/common' import { @@ -67,8 +67,9 @@ tape('runTx() -> successful API parameter usage', async (t) => { const blockGasUsed = BigInt(1000) const res = await vm.runTx({ tx, blockGasUsed }) - t.ok( - bufferToBigInt(res.receipt.gasUsed) === blockGasUsed + res.gasUsed, + t.equal( + res.receipt.gasUsed, + blockGasUsed + res.gasUsed, 'receipt.gasUsed should equal block gas used + tx gas used' ) t.end() @@ -254,7 +255,7 @@ tape('runTx() -> API parameter usage/data errors', (t) => { let tx = getTransaction(vm._common, 2, true) as FeeMarketEIP1559Transaction const address = tx.getSenderAddress() tx = Object.create(tx) - const maxCost = tx.gasLimit * tx.maxFeePerGas + const maxCost: bigint = tx.gasLimit * tx.maxFeePerGas await vm.stateManager.putAccount(address, createAccount(BigInt(0), maxCost - BigInt(1))) try { await vm.runTx({ tx }) @@ -451,8 +452,9 @@ tape('runTx() -> API return values', async (t) => { await vm.stateManager.putAccount(caller, acc) const res = await vm.runTx({ tx }) - t.true( - res.execResult.gasUsed === BigInt(0), + t.equal( + res.execResult.gasUsed, + BigInt(0), `execution result -> gasUsed -> 0 (${txType.name})` ) t.equal( @@ -465,10 +467,7 @@ tape('runTx() -> API return values', async (t) => { Buffer.from([]), `execution result -> return value -> empty Buffer (${txType.name})` ) - t.true( - res.execResult.gasRefund! === BigInt(0), - `execution result -> gasRefund -> 0 (${txType.name})` - ) + t.equal(res.gasRefund, BigInt(0), `gasRefund -> 0 (${txType.name})`) } t.end() }) @@ -484,7 +483,7 @@ tape('runTx() -> API return values', async (t) => { const res = await vm.runTx({ tx }) - t.deepEqual( + t.equal( res.gasUsed, tx.getBaseFee(), `runTx result -> gasUsed -> tx.getBaseFee() (${txType.name})` @@ -496,13 +495,13 @@ tape('runTx() -> API return values', async (t) => { ? tx.maxPriorityFeePerGas : tx.maxFeePerGas - baseFee const gasPrice = inclusionFeePerGas + baseFee - t.deepEquals( + t.equal( res.amountSpent, res.gasUsed * gasPrice, `runTx result -> amountSpent -> gasUsed * gasPrice (${txType.name})` ) } else { - t.deepEqual( + t.equal( res.amountSpent, res.gasUsed * (tx).gasPrice, `runTx result -> amountSpent -> gasUsed * gasPrice (${txType.name})` @@ -514,10 +513,10 @@ tape('runTx() -> API return values', async (t) => { Buffer.from('00'.repeat(256), 'hex'), `runTx result -> bloom.bitvector -> should be empty (${txType.name})` ) - t.deepEqual( + t.equal( res.receipt.gasUsed, - toBuffer('0x' + res.gasUsed.toString(16)), - `runTx result -> receipt.gasUsed -> result.gasUsed as Buffer (${txType.name})` + res.gasUsed, + `runTx result -> receipt.gasUsed -> result.gasUsed (${txType.name})` ) t.deepEqual( res.receipt.bitvector, @@ -608,7 +607,7 @@ tape('runTx() -> consensus bugs', async (t) => { const block = Block.fromBlockData({ header: { baseFeePerGas: 0x0c } }, { common }) const result = await vm.runTx({ tx, block }) - t.ok(result.gasUsed === BigInt(66382), 'should use the right amount of gas and not consume all') + t.equal(result.gasUsed, BigInt(66382), 'should use the right amount of gas and not consume all') t.end() }) }) diff --git a/packages/vm/tests/api/state/accountExists.spec.ts b/packages/vm/tests/api/state/accountExists.spec.ts index 538d0932ee..8b3108e1c4 100644 --- a/packages/vm/tests/api/state/accountExists.spec.ts +++ b/packages/vm/tests/api/state/accountExists.spec.ts @@ -42,7 +42,7 @@ tape('correctly apply new account gas fee on pre-Spurious Dragon hardforks', asy } const result = await vm.runCall(runCallArgs) - t.ok(result.gasUsed === BigInt(53552), 'vm correctly applies new account gas price') + t.equal(result.execResult.gasUsed, BigInt(53552), 'vm correctly applies new account gas price') t.end() }) @@ -87,7 +87,11 @@ tape( } const result = await vm.runCall(runCallArgs) - t.ok(result.gasUsed === BigInt(28552), 'new account price not applied as empty account exists') + t.equal( + result.execResult.gasUsed, + BigInt(28552), + 'new account price not applied as empty account exists' + ) t.end() } )