From 3ae28cc950fcfc304ccbf83a66c0212334faa7a5 Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Wed, 26 Jan 2022 09:14:24 -0500 Subject: [PATCH 01/42] Replace BN.js with bigints in VM --- config/eslint.js | 2 +- packages/util/src/constants.ts | 13 + packages/util/test/constants.spec.ts | 6 + packages/util/tsconfig.browser.json | 4 +- packages/util/tsconfig.json | 5 +- packages/util/tsconfig.prod.json | 3 +- packages/vm/benchmarks/util.ts | 2 +- packages/vm/src/buildBlock.ts | 22 +- packages/vm/src/evm/eei.ts | 168 ++++----- packages/vm/src/evm/evm.ts | 72 ++-- packages/vm/src/evm/interpreter.ts | 39 ++- packages/vm/src/evm/message.ts | 10 +- packages/vm/src/evm/opcodes/EIP1283.ts | 19 +- packages/vm/src/evm/opcodes/EIP2200.ts | 23 +- packages/vm/src/evm/opcodes/EIP2929.ts | 36 +- packages/vm/src/evm/opcodes/functions.ts | 329 +++++++++--------- packages/vm/src/evm/opcodes/gas.ts | 302 ++++++++-------- packages/vm/src/evm/opcodes/util.ts | 114 +++--- .../vm/src/evm/precompiles/01-ecrecover.ts | 4 +- packages/vm/src/evm/precompiles/02-sha256.ts | 11 +- .../vm/src/evm/precompiles/03-ripemd160.ts | 11 +- .../vm/src/evm/precompiles/04-identity.ts | 10 +- packages/vm/src/evm/precompiles/05-modexp.ts | 140 ++++---- packages/vm/src/evm/precompiles/06-ecadd.ts | 5 +- packages/vm/src/evm/precompiles/07-ecmul.ts | 5 +- .../vm/src/evm/precompiles/08-ecpairing.ts | 5 +- packages/vm/src/evm/precompiles/09-blake2f.ts | 7 +- .../vm/src/evm/precompiles/0a-bls12-g1add.ts | 5 +- .../vm/src/evm/precompiles/0b-bls12-g1mul.ts | 5 +- .../evm/precompiles/0c-bls12-g1multiexp.ts | 7 +- .../vm/src/evm/precompiles/0d-bls12-g2add.ts | 5 +- .../vm/src/evm/precompiles/0e-bls12-g2mul.ts | 5 +- .../evm/precompiles/0f-bls12-g2multiexp.ts | 7 +- .../src/evm/precompiles/10-bls12-pairing.ts | 9 +- .../evm/precompiles/11-bls12-map-fp-to-g1.ts | 5 +- .../evm/precompiles/12-bls12-map-fp2-to-g2.ts | 5 +- packages/vm/src/evm/precompiles/types.ts | 3 +- .../vm/src/evm/precompiles/util/bls12_381.ts | 13 +- packages/vm/src/evm/stack.ts | 24 +- packages/vm/src/evm/txContext.ts | 6 +- packages/vm/src/runBlock.ts | 52 +-- packages/vm/src/runCall.ts | 11 +- packages/vm/src/runCode.ts | 10 +- packages/vm/src/runTx.ts | 57 +-- .../EIPs/eip-1283-net-gas-metering.spec.ts | 6 +- .../tests/api/EIPs/eip-1559-FeeMarket.spec.ts | 6 +- packages/vm/tests/api/EIPs/eip-2315.spec.ts | 3 +- .../vm/tests/api/EIPs/eip-2537-BLS.spec.ts | 16 +- .../api/EIPs/eip-2565-modexp-gas-cost.spec.ts | 8 +- packages/vm/tests/api/EIPs/eip-2929.spec.ts | 60 ++-- .../api/EIPs/eip-2930-accesslists.spec.ts | 8 +- .../tests/api/EIPs/eip-3198-BaseFee.spec.ts | 8 +- packages/vm/tests/api/EIPs/eip-3529.spec.ts | 42 +-- packages/vm/tests/api/EIPs/eip-3855.spec.ts | 23 +- packages/vm/tests/api/buildBlock.spec.ts | 6 +- .../api/evm/precompiles/06-ecadd.spec.ts | 6 +- .../api/evm/precompiles/07-ecmul.spec.ts | 6 +- .../api/evm/precompiles/08-ecpairing.spec.ts | 10 +- .../api/evm/precompiles/hardfork.spec.ts | 20 +- packages/vm/tests/api/evm/stack.spec.ts | 52 +-- .../vm/tests/api/istanbul/eip-1108.spec.ts | 18 +- .../vm/tests/api/istanbul/eip-1344.spec.ts | 2 +- .../vm/tests/api/istanbul/eip-152.spec.ts | 5 +- .../vm/tests/api/istanbul/eip-1884.spec.ts | 7 +- .../vm/tests/api/istanbul/eip-2200.spec.ts | 66 ++-- packages/vm/tests/api/runBlock.spec.ts | 17 +- packages/vm/tests/api/runCall.spec.ts | 64 ++-- packages/vm/tests/api/runCode.spec.ts | 9 +- packages/vm/tests/api/runTx.spec.ts | 36 +- .../vm/tests/api/state/accountExists.spec.ts | 15 +- .../tester/runners/BlockchainTestsRunner.ts | 10 +- .../tester/runners/GeneralStateTestsRunner.ts | 8 +- packages/vm/tsconfig.json | 5 +- packages/vm/tsconfig.prod.json | 3 +- 74 files changed, 1103 insertions(+), 1038 deletions(-) diff --git a/config/eslint.js b/config/eslint.js index ba574442c6..bc4d661c1a 100644 --- a/config/eslint.js +++ b/config/eslint.js @@ -2,7 +2,7 @@ module.exports = { parser: '@typescript-eslint/parser', plugins: ['@typescript-eslint', 'implicit-dependencies', 'prettier'], env: { - es6: true, + es2020: true, node: true, }, ignorePatterns: [ diff --git a/packages/util/src/constants.ts b/packages/util/src/constants.ts index ae09019b94..b3fc553deb 100644 --- a/packages/util/src/constants.ts +++ b/packages/util/src/constants.ts @@ -14,14 +14,27 @@ export const MAX_INTEGER = new BN( 16 ) +/** + * The max integer that the evm can handle (2^256-1) as a bigint + */ +export const MAX_INTEGER_BIGINT = 2n ** 256n - 1n + /** * 2^256 + * + * @deprecated */ export const TWO_POW256 = new BN( '10000000000000000000000000000000000000000000000000000000000000000', 16 ) +/** + * 2^256 + */ +export const TWO_POW256_BIGINT = + BigInt(0x10000000000000000000000000000000000000000000000000000000000000000) + /** * Keccak-256 hash of null */ diff --git a/packages/util/test/constants.spec.ts b/packages/util/test/constants.spec.ts index 4ee6ff3069..6fdae9ae19 100644 --- a/packages/util/test/constants.spec.ts +++ b/packages/util/test/constants.spec.ts @@ -8,6 +8,7 @@ import { KECCAK256_RLP_ARRAY, KECCAK256_RLP_S, KECCAK256_RLP, + TWO_POW256_BIGINT, } from '../src' tape('constants', function (t) { @@ -22,6 +23,11 @@ tape('constants', function (t) { '10000000000000000000000000000000000000000000000000000000000000000' ) + st.equal( + TWO_POW256_BIGINT.toString(16), + '10000000000000000000000000000000000000000000000000000000000000000' + ) + st.equal(KECCAK256_NULL_S, 'c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470') st.equal( diff --git a/packages/util/tsconfig.browser.json b/packages/util/tsconfig.browser.json index b4895dad56..ea86b4a999 100644 --- a/packages/util/tsconfig.browser.json +++ b/packages/util/tsconfig.browser.json @@ -2,8 +2,8 @@ "extends": "./tsconfig.prod.json", "compilerOptions": { "outDir": "./dist.browser", - "target": "es5", - "lib": ["dom", "es5"] + "target": "es2020", + "lib": ["dom", "es2020"] } } \ No newline at end of file diff --git a/packages/util/tsconfig.json b/packages/util/tsconfig.json index ec77a108e2..e734f03524 100644 --- a/packages/util/tsconfig.json +++ b/packages/util/tsconfig.json @@ -1,4 +1,7 @@ { "extends": "../../config/tsconfig.json", - "include": ["src/**/*.ts", "test/**/*.ts"] + "include": ["src/**/*.ts", "test/**/*.ts"], + "compilerOptions": { + "target": "ES2020" + } } diff --git a/packages/util/tsconfig.prod.json b/packages/util/tsconfig.prod.json index e6621a1073..cdb157040f 100644 --- a/packages/util/tsconfig.prod.json +++ b/packages/util/tsconfig.prod.json @@ -3,7 +3,8 @@ "compilerOptions": { "rootDir": "./src", "outDir": "./dist", - "composite": true + "composite": true, + "target": "ES2020" }, "include": ["src/**/*.ts"] } diff --git a/packages/vm/benchmarks/util.ts b/packages/vm/benchmarks/util.ts index c66a04cb71..a57a66f013 100644 --- a/packages/vm/benchmarks/util.ts +++ b/packages/vm/benchmarks/util.ts @@ -100,7 +100,7 @@ export const verifyResult = (block: Block, result: RunBlockResult) => { if (!result.logsBloom.equals(block.header.logsBloom)) { throw new Error('invalid logsBloom') } - if (!block.header.gasUsed.eq(result.gasUsed)) { + if (!(BigInt(block.header.gasUsed.toString(10)) === result.gasUsed)) { throw new Error('invalid gasUsed') } } diff --git a/packages/vm/src/buildBlock.ts b/packages/vm/src/buildBlock.ts index 94b609ca9d..645c33519e 100644 --- a/packages/vm/src/buildBlock.ts +++ b/packages/vm/src/buildBlock.ts @@ -1,4 +1,4 @@ -import { Address, BN, toBuffer, rlp } from 'ethereumjs-util' +import { Address, toBuffer, rlp, bufferToHex, BN } from 'ethereumjs-util' import { BaseTrie as Trie } from 'merkle-patricia-tree' import { Block, BlockOptions, HeaderData } from '@ethereumjs/block' import { ConsensusType } from '@ethereumjs/common' @@ -66,7 +66,7 @@ export class BlockBuilder { /** * The cumulative gas used by the transactions added to the block. */ - gasUsed = new BN(0) + gasUsed = 0n private readonly vm: VM private blockOpts: BuilderOpts @@ -132,11 +132,11 @@ export class BlockBuilder { * Calculates and returns the receiptTrie for the block. */ private async receiptTrie() { - const gasUsed = new BN(0) + let _gasUsed = 0n const receiptTrie = new Trie() for (const [i, txResult] of this.transactionResults.entries()) { const tx = this.transactions[i] - gasUsed.iadd(txResult.gasUsed) + _gasUsed += txResult.gasUsed const encodedReceipt = encodeReceipt(tx, txResult.receipt) await receiptTrie.put(rlp.encode(i), encodedReceipt) } @@ -147,7 +147,7 @@ export class BlockBuilder { * Adds the block miner reward to the coinbase account. */ private async rewardMiner() { - const minerReward = new BN(this.vm._common.param('pow', 'minerReward')) + const minerReward = BigInt(this.vm._common.param('pow', 'minerReward')) const reward = calculateMinerReward(minerReward, 0) const coinbase = this.headerData.coinbase ? new Address(toBuffer(this.headerData.coinbase)) @@ -171,15 +171,15 @@ export class BlockBuilder { // According to the Yellow Paper, a transaction's gas limit // cannot be greater than the remaining gas in the block - const blockGasLimit = new BN(toBuffer(this.headerData.gasLimit)) - const blockGasRemaining = blockGasLimit.sub(this.gasUsed) - if (tx.gasLimit.gt(blockGasRemaining)) { + const blockGasLimit = BigInt(bufferToHex(toBuffer(this.headerData.gasLimit))) + const blockGasRemaining = blockGasLimit - this.gasUsed + if (BigInt(tx.gasLimit.toString(10)) > blockGasRemaining) { throw new Error('tx has a higher gas limit than the remaining gas in the block') } const header = { ...this.headerData, - gasUsed: this.gasUsed, + gasUsed: new BN(this.gasUsed.toString(10), 10), } const blockData = { header, transactions: this.transactions } const block = Block.fromBlockData(blockData, this.blockOpts) @@ -188,7 +188,7 @@ export class BlockBuilder { this.transactions.push(tx) this.transactionResults.push(result) - this.gasUsed.iadd(result.gasUsed) + this.gasUsed += result.gasUsed return result } @@ -228,7 +228,7 @@ export class BlockBuilder { const transactionsTrie = await this.transactionsTrie() const receiptTrie = await this.receiptTrie() const logsBloom = this.logsBloom() - const gasUsed = this.gasUsed + const gasUsed = new BN(this.gasUsed.toString(10), 10) const timestamp = this.headerData.timestamp ?? Math.round(Date.now() / 1000) const headerData = { diff --git a/packages/vm/src/evm/eei.ts b/packages/vm/src/evm/eei.ts index d0617359b6..51e4087621 100644 --- a/packages/vm/src/evm/eei.ts +++ b/packages/vm/src/evm/eei.ts @@ -1,5 +1,5 @@ import { debug as createDebugLogger } from 'debug' -import { Account, Address, BN, MAX_UINT64 } from 'ethereumjs-util' +import { Account, Address, BN, MAX_UINT64, bufferToHex } from 'ethereumjs-util' import { Block } from '@ethereumjs/block' import Blockchain from '@ethereumjs/blockchain' import Common, { ConsensusAlgorithm } from '@ethereumjs/common' @@ -8,6 +8,7 @@ import { VmError, ERROR } from '../exceptions' import Message from './message' import EVM, { EVMResult } from './evm' import { Log } from './types' +import { addressToBuffer } from './opcodes' const debugGas = createDebugLogger('vm:eei:gas') @@ -15,12 +16,6 @@ function trap(err: ERROR) { throw new VmError(err) } -const MASK_160 = new BN(1).shln(160).subn(1) -function addressToBuffer(address: BN) { - if (Buffer.isBuffer(address)) return address - return address.and(MASK_160).toArrayLike(Buffer, 'be', 20) -} - /** * Environment data which is made available to EVM bytecode. */ @@ -29,11 +24,11 @@ export interface Env { address: Address caller: Address callData: Buffer - callValue: BN + callValue: bigint code: Buffer isStatic: boolean depth: number - gasPrice: BN + gasPrice: bigint origin: Address block: Block contract: Account @@ -68,9 +63,9 @@ export default class EEI { _evm: EVM _lastReturned: Buffer _common: Common - _gasLeft: BN + _gasLeft: bigint - constructor(env: Env, state: StateManager, evm: EVM, common: Common, gasLeft: BN) { + constructor(env: Env, state: StateManager, evm: EVM, common: Common, gasLeft: bigint) { this._env = env this._state = state this._evm = evm @@ -90,13 +85,13 @@ export default class EEI { * @param context - Usage context for debugging * @throws if out of gas */ - useGas(amount: BN, context?: string): void { - this._gasLeft.isub(amount) + useGas(amount: bigint, context?: string): void { + this._gasLeft -= amount if (this._evm._vm.DEBUG) { debugGas(`${context ? context + ': ' : ''}used ${amount} gas (-> ${this._gasLeft})`) } - if (this._gasLeft.ltn(0)) { - this._gasLeft = new BN(0) + if (this._gasLeft < 0n) { + this._gasLeft = 0n trap(ERROR.OUT_OF_GAS) } } @@ -106,11 +101,11 @@ export default class EEI { * @param amount - Amount of gas refunded * @param context - Usage context for debugging */ - refundGas(amount: BN, context?: string): void { + refundGas(amount: bigint, context?: string): void { if (this._evm._vm.DEBUG) { debugGas(`${context ? context + ': ' : ''}refund ${amount} gas (-> ${this._evm._refund})`) } - this._evm._refund.iadd(amount) + this._evm._refund += amount } /** @@ -118,13 +113,13 @@ export default class EEI { * @param amount - Amount to subtract from gas refunds * @param context - Usage context for debugging */ - subRefund(amount: BN, context?: string): void { + subRefund(amount: bigint, context?: string): void { if (this._evm._vm.DEBUG) { debugGas(`${context ? context + ': ' : ''}sub gas refund ${amount} (-> ${this._evm._refund})`) } - this._evm._refund.isub(amount) - if (this._evm._refund.ltn(0)) { - this._evm._refund = new BN(0) + this._evm._refund -= amount + if (this._evm._refund < 0n) { + this._evm._refund = 0n trap(ERROR.REFUND_EXHAUSTED) } } @@ -133,11 +128,11 @@ export default class EEI { * Increments the internal gasLeft counter. Used for adding callStipend. * @param amount - Amount to add */ - addStipend(amount: BN): void { + addStipend(amount: bigint): void { if (this._evm._vm.DEBUG) { debugGas(`add stipend ${amount} (-> ${this._gasLeft})`) } - this._gasLeft.iadd(amount) + this._gasLeft += amount } /** @@ -151,38 +146,38 @@ export default class EEI { * Returns balance of the given account. * @param address - Address of account */ - async getExternalBalance(address: Address): Promise { + async getExternalBalance(address: Address): Promise { // shortcut if current account if (address.equals(this._env.address)) { - return this._env.contract.balance + return BigInt(this._env.contract.balance.toString(10)) } // otherwise load account then return balance const account = await this._state.getAccount(address) - return account.balance + return BigInt(account.balance.toString(10)) } /** * Returns balance of self. */ - getSelfBalance(): BN { - return this._env.contract.balance + getSelfBalance(): bigint { + return BigInt(this._env.contract.balance.toString(10)) } /** * Returns caller address. This is the address of the account * that is directly responsible for this execution. */ - getCaller(): BN { - return new BN(this._env.caller.buf) + getCaller(): bigint { + return BigInt(bufferToHex(this._env.caller.buf)) } /** * Returns the deposited value by the instruction/transaction * responsible for this execution. */ - getCallValue(): BN { - return new BN(this._env.callValue) + getCallValue(): bigint { + return this._env.callValue } /** @@ -197,15 +192,15 @@ export default class EEI { * Returns size of input data in current environment. This pertains to the * input data passed with the message call instruction or transaction. */ - getCallDataSize(): BN { - return new BN(this._env.callData.length) + getCallDataSize(): bigint { + return BigInt(this._env.callData.length) } /** * Returns the size of code running in current environment. */ - getCodeSize(): BN { - return new BN(this._env.code.length) + getCodeSize(): bigint { + return BigInt(this._env.code.length) } /** @@ -226,17 +221,17 @@ export default class EEI { * Get size of an account’s code. * @param address - Address of account */ - async getExternalCodeSize(address: BN): Promise { + async getExternalCodeSize(address: bigint): Promise { const addr = new Address(addressToBuffer(address)) const code = await this._state.getContractCode(addr) - return new BN(code.length) + return BigInt(code.length) } /** * Returns code of an account. * @param address - Address of account */ - async getExternalCode(address: BN): Promise { + async getExternalCode(address: bigint): Promise { const addr = new Address(addressToBuffer(address)) return this._state.getContractCode(addr) } @@ -246,8 +241,8 @@ export default class EEI { * from the last executed call, callCode, callDelegate, callStatic or create. * Note: create only fills the return data buffer in case of a failure. */ - getReturnDataSize(): BN { - return new BN(this._lastReturned.length) + getReturnDataSize(): bigint { + return BigInt(this._lastReturned.length) } /** @@ -262,7 +257,7 @@ export default class EEI { /** * Returns price of gas in current environment. */ - getTxGasPrice(): BN { + getTxGasPrice(): bigint { return this._env.gasPrice } @@ -271,21 +266,21 @@ export default class EEI { * sender of original transaction; it is never an account with * non-empty associated code. */ - getTxOrigin(): BN { - return new BN(this._env.origin.buf) + getTxOrigin(): bigint { + return BigInt(bufferToHex(this._env.origin.buf)) } /** * Returns the block’s number. */ - getBlockNumber(): BN { - return this._env.block.header.number + getBlockNumber(): bigint { + return BigInt(this._env.block.header.number.toString(10)) } /** * Returns the block's beneficiary address. */ - getBlockCoinbase(): BN { + getBlockCoinbase(): bigint { let coinbase: Address if (this._common.consensusAlgorithm() === ConsensusAlgorithm.Clique) { // Backwards-compatibilty check @@ -298,57 +293,57 @@ export default class EEI { } else { coinbase = this._env.block.header.coinbase } - return new BN(coinbase.toBuffer()) + return BigInt(bufferToHex(coinbase.toBuffer())) } /** * Returns the block's timestamp. */ - getBlockTimestamp(): BN { - return this._env.block.header.timestamp + getBlockTimestamp(): bigint { + return BigInt(this._env.block.header.timestamp.toString(10)) } /** * Returns the block's difficulty. */ - getBlockDifficulty(): BN { - return this._env.block.header.difficulty + getBlockDifficulty(): bigint { + return BigInt(this._env.block.header.difficulty.toString(10)) } /** * Returns the block's gas limit. */ - getBlockGasLimit(): BN { - return this._env.block.header.gasLimit + getBlockGasLimit(): bigint { + return BigInt(this._env.block.header.gasLimit.toString(10)) } /** * Returns the chain ID for current chain. Introduced for the * CHAINID opcode proposed in [EIP-1344](https://eips.ethereum.org/EIPS/eip-1344). */ - getChainId(): BN { - return this._common.chainId() + getChainId(): bigint { + return BigInt(this._common.chainIdBN().toString(10)) } /** * Returns the Base Fee of the block as proposed in [EIP-3198](https;//eips.etheruem.org/EIPS/eip-3198) */ - getBlockBaseFee(): BN { + getBlockBaseFee(): bigint { const baseFee = this._env.block.header.baseFeePerGas if (baseFee === undefined) { // Sanity check throw new Error('Block has no Base Fee') } - return baseFee + return BigInt(baseFee.toString(10)) } /** * Returns Gets the hash of one of the 256 most recent complete blocks. * @param num - Number of block */ - async getBlockHash(num: BN): Promise { - const block = await this._env.blockchain.getBlock(num) - return new BN(block.hash()) + async getBlockHash(num: bigint): Promise { + const block = await this._env.blockchain.getBlock(Number(num)) + return BigInt(bufferToHex(block.hash())) } /** @@ -376,8 +371,8 @@ export default class EEI { /** * Returns the current gasCounter. */ - getGasLeft(): BN { - return this._gasLeft.clone() + getGasLeft(): bigint { + return this._gasLeft } /** @@ -412,7 +407,7 @@ export default class EEI { async _selfDestruct(toAddress: Address): Promise { // only add to refund if this is the first selfdestruct for the address if (!this._result.selfdestruct[this._env.address.buf.toString('hex')]) { - this.refundGas(new BN(this._common.param('gasPrices', 'selfdestructRefund'))) + this.refundGas(BigInt(this._common.param('gasPrices', 'selfdestructRefund'))) } this._result.selfdestruct[this._env.address.buf.toString('hex')] = toAddress.buf @@ -449,7 +444,7 @@ export default class EEI { /** * Sends a message with arbitrary data to a given address path. */ - async call(gasLimit: BN, address: Address, value: BN, data: Buffer): Promise { + async call(gasLimit: bigint, address: Address, value: bigint, data: Buffer): Promise { const msg = new Message({ caller: this._env.address, gasLimit, @@ -466,7 +461,7 @@ export default class EEI { /** * Message-call into this account with an alternative account's code. */ - async callCode(gasLimit: BN, address: Address, value: BN, data: Buffer): Promise { + async callCode(gasLimit: bigint, address: Address, value: bigint, data: Buffer): Promise { const msg = new Message({ caller: this._env.address, gasLimit, @@ -486,7 +481,12 @@ export default class EEI { * state modifications. This includes log, create, selfdestruct and call with * a non-zero value. */ - async callStatic(gasLimit: BN, address: Address, value: BN, data: Buffer): Promise { + async callStatic( + gasLimit: bigint, + address: Address, + value: bigint, + data: Buffer + ): Promise { const msg = new Message({ caller: this._env.address, gasLimit, @@ -504,7 +504,12 @@ export default class EEI { * Message-call into this account with an alternative account’s code, but * persisting the current values for sender and value. */ - async callDelegate(gasLimit: BN, address: Address, value: BN, data: Buffer): Promise { + async callDelegate( + gasLimit: bigint, + address: Address, + value: bigint, + data: Buffer + ): Promise { const msg = new Message({ caller: this._env.caller, gasLimit, @@ -520,7 +525,7 @@ export default class EEI { return this._baseCall(msg) } - async _baseCall(msg: Message): Promise { + async _baseCall(msg: Message): Promise { const selfdestruct = { ...this._result.selfdestruct } msg.selfdestruct = selfdestruct @@ -530,9 +535,9 @@ export default class EEI { // Check if account has enough ether and max depth not exceeded if ( this._env.depth >= this._common.param('vm', 'stackLimit') || - (msg.delegatecall !== true && this._env.contract.balance.lt(msg.value)) + (msg.delegatecall !== true && BigInt(this._env.contract.balance.toString(10)) < msg.value) ) { - return new BN(0) + return 0n } const results = await this._evm.executeMessage(msg) @@ -566,7 +571,12 @@ export default class EEI { /** * Creates a new contract with a given value. */ - async create(gasLimit: BN, value: BN, data: Buffer, salt: Buffer | null = null): Promise { + async create( + gasLimit: bigint, + value: bigint, + data: Buffer, + salt: Buffer | null = null + ): Promise { const selfdestruct = { ...this._result.selfdestruct } const msg = new Message({ caller: this._env.address, @@ -584,14 +594,14 @@ export default class EEI { // Check if account has enough ether and max depth not exceeded if ( this._env.depth >= this._common.param('vm', 'stackLimit') || - (msg.delegatecall !== true && this._env.contract.balance.lt(msg.value)) + (msg.delegatecall !== true && BigInt(this._env.contract.balance.toString(10)) < msg.value) ) { - return new BN(0) + return 0n } // EIP-2681 check if (this._env.contract.nonce.gte(MAX_UINT64)) { - return new BN(0) + return 0n } this._env.contract.nonce.iaddn(1) await this._state.putAccount(this._env.address, this._env.contract) @@ -623,7 +633,7 @@ export default class EEI { this._env.contract = account if (results.createdAddress) { // push the created address to the stack - return new BN(results.createdAddress.buf) + return BigInt(bufferToHex(results.createdAddress.buf)) } } @@ -634,7 +644,7 @@ export default class EEI { * Creates a new contract with a given value. Generates * a deterministic address via CREATE2 rules. */ - async create2(gasLimit: BN, value: BN, data: Buffer, salt: Buffer): Promise { + async create2(gasLimit: bigint, value: bigint, data: Buffer, salt: Buffer): Promise { return this.create(gasLimit, value, data, salt) } @@ -658,9 +668,9 @@ export default class EEI { // This preserves the previous logic, but seems to contradict the EEI spec // https://github.com/ewasm/design/blob/38eeded28765f3e193e12881ea72a6ab807a3371/eth_interface.md if (results.execResult.exceptionError) { - return new BN(0) + return 0n } else { - return new BN(1) + return 1n } } } diff --git a/packages/vm/src/evm/evm.ts b/packages/vm/src/evm/evm.ts index f4cd15fdfe..b7893f4aa6 100644 --- a/packages/vm/src/evm/evm.ts +++ b/packages/vm/src/evm/evm.ts @@ -30,7 +30,7 @@ export interface EVMResult { /** * Amount of gas used by the transaction */ - gasUsed: BN + gasUsed: bigint /** * Address of created account durint transaction, if any */ @@ -53,11 +53,11 @@ export interface ExecResult { /** * Amount of gas left */ - gas?: BN + gas?: bigint /** * Amount of gas the code used to run */ - gasUsed: BN + gasUsed: bigint /** * Return value from the contract */ @@ -73,7 +73,7 @@ export interface ExecResult { /** * Total amount of gas to be refunded from all nested calls. */ - gasRefund?: BN + gasRefund?: bigint } export interface NewContractEvent { @@ -82,7 +82,7 @@ export interface NewContractEvent { code: Buffer } -export function OOGResult(gasLimit: BN): ExecResult { +export function OOGResult(gasLimit: bigint): ExecResult { return { returnValue: Buffer.alloc(0), gasUsed: gasLimit, @@ -90,7 +90,7 @@ export function OOGResult(gasLimit: BN): ExecResult { } } // CodeDeposit OOG Result -export function COOGResult(gasUsedCreateCode: BN): ExecResult { +export function COOGResult(gasUsedCreateCode: bigint): ExecResult { return { returnValue: Buffer.alloc(0), gasUsed: gasUsedCreateCode, @@ -98,7 +98,7 @@ export function COOGResult(gasUsedCreateCode: BN): ExecResult { } } -export function INVALID_BYTECODE_RESULT(gasLimit: BN): ExecResult { +export function INVALID_BYTECODE_RESULT(gasLimit: bigint): ExecResult { return { returnValue: Buffer.alloc(0), gasUsed: gasLimit, @@ -106,7 +106,7 @@ export function INVALID_BYTECODE_RESULT(gasLimit: BN): ExecResult { } } -export function VmErrorResult(error: VmError, gasUsed: BN): ExecResult { +export function VmErrorResult(error: VmError, gasUsed: bigint): ExecResult { return { returnValue: Buffer.alloc(0), gasUsed: gasUsed, @@ -128,14 +128,14 @@ export default class EVM { /** * Amount of gas to refund from deleting storage values */ - _refund: BN + _refund: bigint constructor(vm: any, txContext: TxContext, block: Block) { this._vm = vm this._state = this._vm.stateManager this._tx = txContext this._block = block - this._refund = new BN(0) + this._refund = 0n } /** @@ -151,7 +151,7 @@ export default class EVM { ;(this._state).addWarmedAddress((await this._generateAddress(message)).buf) } - const oldRefund = this._refund.clone() + const oldRefund = this._refund await this._state.checkpoint() if (this._vm.DEBUG) { @@ -183,14 +183,17 @@ export default class EVM { `Received message results gasUsed=${result.gasUsed} execResult: [ gasUsed=${ result.gasUsed } exceptionError=${ - result.execResult.exceptionError ? result.execResult.exceptionError.toString() : '' + result.execResult.exceptionError + ? result.execResult.exceptionError.errorType + + ' ' + + result.execResult.exceptionError.error + : '' } returnValue=${short(result.execResult.returnValue)} gasRefund=${ result.execResult.gasRefund } ]` ) } 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) { @@ -199,7 +202,7 @@ export default class EVM { this._refund = oldRefund result.execResult.selfdestruct = {} } - result.execResult.gasRefund = this._refund.clone() + result.execResult.gasRefund = this._refund if (err) { if (this._vm._common.gteHardfork('homestead') || err.error != ERROR.CODESTORE_OUT_OF_GAS) { @@ -263,9 +266,9 @@ export default class EVM { } if (exit) { return { - gasUsed: new BN(0), + gasUsed: 0n, execResult: { - gasUsed: new BN(0), + gasUsed: 0n, exceptionError: errorMessage, // Only defined if addToBalance failed returnValue: Buffer.alloc(0), }, @@ -362,10 +365,10 @@ export default class EVM { } if (exit) { return { - gasUsed: new BN(0), + gasUsed: 0n, createdAddress: message.to, execResult: { - gasUsed: new BN(0), + gasUsed: 0n, exceptionError: errorMessage, // only defined if addToBalance failed returnValue: Buffer.alloc(0), }, @@ -379,12 +382,12 @@ export default class EVM { // fee for size of the return value let totalGas = result.gasUsed - let returnFee = new BN(0) + let returnFee = 0n if (!result.exceptionError) { - returnFee = new BN(result.returnValue.length).imuln( - this._vm._common.param('gasPrices', 'createData') - ) - totalGas = totalGas.add(returnFee) + returnFee = + BigInt(result.returnValue.length) * + BigInt(this._vm._common.param('gasPrices', 'createData')) + totalGas = totalGas + returnFee if (this._vm.DEBUG) { debugGas(`Add return value size fee (${returnFee} to gas used (-> ${totalGas}))`) } @@ -401,10 +404,7 @@ export default class EVM { // If enough gas and allowed code size let CodestoreOOG = false - if ( - totalGas.lte(message.gasLimit) && - (this._vm._allowUnlimitedContractSize || allowedCodeSize) - ) { + if (totalGas <= message.gasLimit && (this._vm._allowUnlimitedContractSize || allowedCodeSize)) { if ( this._vm._common.isActivatedEIP(3541) && result.returnValue.slice(0, 1).equals(Buffer.from('EF', 'hex')) @@ -424,9 +424,9 @@ export default class EVM { if (this._vm.DEBUG) { debug(`Not enough gas or code size not allowed (Frontier)`) } - if (totalGas.sub(returnFee).lte(message.gasLimit)) { + if (totalGas - returnFee <= message.gasLimit) { // we cannot pay the code deposit fee (but the deposit code actually did run) - result = { ...result, ...COOGResult(totalGas.sub(returnFee)) } + result = { ...result, ...COOGResult(totalGas - returnFee) } CodestoreOOG = true } else { result = { ...result, ...OOGResult(message.gasLimit) } @@ -470,17 +470,17 @@ export default class EVM { address: message.to || Address.zero(), caller: message.caller || Address.zero(), callData: message.data || Buffer.from([0]), - callValue: message.value || new BN(0), + callValue: message.value || 0n, code: message.code as Buffer, isStatic: message.isStatic || false, depth: message.depth || 0, - gasPrice: this._tx.gasPrice, + gasPrice: BigInt(this._tx.gasPrice.toString(10)), origin: this._tx.origin || message.caller || Address.zero(), block: this._block || new Block(), contract: await this._state.getAccount(message.to || Address.zero()), codeAddress: message.codeAddress, } - const eei = new EEI(env, this._state, this, this._vm._common, message.gasLimit.clone()) + const eei = new EEI(env, this._state, this, this._vm._common, message.gasLimit) if (message.selfdestruct) { eei._result.selfdestruct = message.selfdestruct } @@ -489,7 +489,7 @@ export default class EVM { const interpreterRes = await interpreter.run(message.code as Buffer, opts) let result = eei._result - let gasUsed = message.gasLimit.sub(eei._gasLeft) + let gasUsed = message.gasLimit - eei._gasLeft if (interpreterRes.exceptionError) { if (interpreterRes.exceptionError.error !== ERROR.REVERT) { gasUsed = message.gasLimit @@ -531,7 +531,7 @@ export default class EVM { runPrecompile( code: PrecompileFunc, data: Buffer, - gasLimit: BN + gasLimit: bigint ): Promise | ExecResult { if (typeof code !== 'function') { throw new Error('Invalid precompile') @@ -573,7 +573,7 @@ export default class EVM { } async _reduceSenderBalance(account: Account, message: Message): Promise { - account.balance.isub(message.value) + account.balance.isub(new BN(message.value.toString(10))) const result = this._state.putAccount(message.caller, account) if (this._vm.DEBUG) { debug(`Reduced sender (${message.caller}) balance (-> ${account.balance})`) @@ -582,7 +582,7 @@ export default class EVM { } async _addToBalance(toAccount: Account, message: Message): Promise { - const newBalance = toAccount.balance.add(message.value) + const newBalance = toAccount.balance.add(new BN(message.value.toString(10))) if (newBalance.gt(MAX_INTEGER)) { throw new VmError(ERROR.VALUE_OVERFLOW) } diff --git a/packages/vm/src/evm/interpreter.ts b/packages/vm/src/evm/interpreter.ts index 327c33cf8b..b78af0da48 100644 --- a/packages/vm/src/evm/interpreter.ts +++ b/packages/vm/src/evm/interpreter.ts @@ -1,5 +1,5 @@ import { debug as createDebugLogger } from 'debug' -import { Account, Address, BN } from 'ethereumjs-util' +import { Account, Address } from 'ethereumjs-util' import { StateManager } from '../state/index' import { ERROR, VmError } from '../exceptions' import Memory from './memory' @@ -16,8 +16,8 @@ export interface RunState { programCounter: number opCode: number memory: Memory - memoryWordCount: BN - highestMemCost: BN + memoryWordCount: bigint + highestMemCost: bigint stack: Stack returnStack: Stack code: Buffer @@ -25,7 +25,7 @@ export interface RunState { validJumps: Uint8Array // array of values where validJumps[index] has value 0 (default), 1 (jumpdest), 2 (beginsub) stateManager: StateManager eei: EEI - messageGasLimit?: BN // Cache value from `gas.ts` to save gas limit for a message call + messageGasLimit?: bigint // Cache value from `gas.ts` to save gas limit for a message call } export interface InterpreterResult { @@ -34,23 +34,23 @@ export interface InterpreterResult { } export interface InterpreterStep { + gasLeft: bigint + gasRefund: bigint + stateManager: StateManager + stack: bigint[] + returnStack: bigint[] pc: number + depth: number opcode: { name: string fee: number - dynamicFee?: BN + dynamicFee?: bigint isAsync: boolean } - gasLeft: BN - gasRefund: BN - stateManager: StateManager - stack: BN[] - returnStack: BN[] account: Account address: Address - depth: number memory: Buffer - memoryWordCount: BN + memoryWordCount: bigint codeAddress: Address } @@ -74,8 +74,8 @@ export default class Interpreter { programCounter: 0, opCode: 0xfe, // INVALID opcode memory: new Memory(), - memoryWordCount: new BN(0), - highestMemCost: new BN(0), + memoryWordCount: 0n, + highestMemCost: 0n, stack: new Stack(), returnStack: new Stack(1023), // 1023 return stack height limit per EIP 2315 spec code: Buffer.alloc(0), @@ -138,7 +138,7 @@ export default class Interpreter { async runStep(): Promise { const opInfo = this.lookupOpInfo(this._runState.opCode) - const gas = new BN(opInfo.fee) + let gas = BigInt(opInfo.fee) // clone the gas limit; call opcodes can add stipend, // which makes it seem like the gas left increases const gasLimitClone = this._eei.getGasLeft() @@ -147,7 +147,7 @@ export default class Interpreter { const dynamicGasHandler = dynamicGasHandlers.get(this._runState.opCode)! // This function updates the gas BN in-place using `i*` methods // It needs the base fee, for correct gas limit calculation for the CALL opcodes - await dynamicGasHandler(this._runState, gas, this._vm._common) + gas = await dynamicGasHandler(this._runState, gas, this._vm._common) } if (this._vm.listenerCount('step') > 0 || this._vm.DEBUG) { @@ -168,6 +168,7 @@ export default class Interpreter { // Execute opcode handler const opFn = this.getOpHandler(opInfo) + if (opInfo.isAsync) { await (opFn as AsyncOpHandler).apply(null, [this._runState, this._vm._common]) } else { @@ -190,7 +191,7 @@ export default class Interpreter { return this._vm._opcodes.get(op) ?? this._vm._opcodes.get(0xfe) } - async _runStepHook(dynamicFee: BN, gasLeft: BN): Promise { + async _runStepHook(dynamicFee: bigint, gasLeft: bigint): Promise { const opcode = this.lookupOpInfo(this._runState.opCode) const eventObj: InterpreterStep = { pc: this._runState.programCounter, @@ -217,7 +218,7 @@ export default class Interpreter { // Create opTrace for debug functionality let hexStack = [] hexStack = eventObj.stack.map((item: any) => { - return '0x' + new BN(item).toString(16, 0) + return '0x' + BigInt(item).toString(16) }) const name = eventObj.opcode.name @@ -225,7 +226,7 @@ export default class Interpreter { const opTrace = { pc: eventObj.pc, op: name, - gas: '0x' + eventObj.gasLeft.toString('hex'), + gas: '0x' + eventObj.gasLeft.toString(16), gasCost: '0x' + eventObj.opcode.fee.toString(16), stack: hexStack, depth: eventObj.depth, diff --git a/packages/vm/src/evm/message.ts b/packages/vm/src/evm/message.ts index 85da7f5f04..d7a27a4e56 100644 --- a/packages/vm/src/evm/message.ts +++ b/packages/vm/src/evm/message.ts @@ -1,11 +1,11 @@ -import { Address, BN } from 'ethereumjs-util' +import { Address } from 'ethereumjs-util' import { PrecompileFunc } from './precompiles' export default class Message { to: Address - value: BN + value: bigint caller: Address - gasLimit: BN + gasLimit: bigint data: Buffer depth: number code: Buffer | PrecompileFunc @@ -18,7 +18,7 @@ export default class Message { constructor(opts: any) { this.to = opts.to - this.value = opts.value ? opts.value : new BN(0) + this.value = opts.value ? opts.value : 0n this.caller = opts.caller this.gasLimit = opts.gasLimit this.data = opts.data || Buffer.alloc(0) @@ -31,7 +31,7 @@ export default class Message { this.selfdestruct = opts.selfdestruct // TODO: Move from here this.delegatecall = opts.delegatecall || false - if (this.value.isNeg()) { + if (this.value < 0) { throw new Error(`value field cannot be negative, received ${this.value}`) } } diff --git a/packages/vm/src/evm/opcodes/EIP1283.ts b/packages/vm/src/evm/opcodes/EIP1283.ts index f4a6715b3e..2967f0c924 100644 --- a/packages/vm/src/evm/opcodes/EIP1283.ts +++ b/packages/vm/src/evm/opcodes/EIP1283.ts @@ -1,5 +1,4 @@ import Common from '@ethereumjs/common' -import { BN } from 'ethereumjs-util' import { RunState } from './../interpreter' /** @@ -20,24 +19,24 @@ export function updateSstoreGasEIP1283( ) { if (currentStorage.equals(value)) { // If current value equals new value (this is a no-op), 200 gas is deducted. - return new BN(common.param('gasPrices', 'netSstoreNoopGas')) + return BigInt(common.param('gasPrices', 'netSstoreNoopGas')) } // If current value does not equal new value if (originalStorage.equals(currentStorage)) { // If original value equals current value (this storage slot has not been changed by the current execution context) if (originalStorage.length === 0) { // If original value is 0, 20000 gas is deducted. - return new BN(common.param('gasPrices', 'netSstoreInitGas')) + return BigInt(common.param('gasPrices', 'netSstoreInitGas')) } if (value.length === 0) { // If new value is 0, add 15000 gas to refund counter. runState.eei.refundGas( - new BN(common.param('gasPrices', 'netSstoreClearRefund')), + BigInt(common.param('gasPrices', 'netSstoreClearRefund')), 'EIP-1283 -> netSstoreClearRefund' ) } // Otherwise, 5000 gas is deducted. - return new BN(common.param('gasPrices', 'netSstoreCleanGas')) + return BigInt(common.param('gasPrices', 'netSstoreCleanGas')) } // If original value does not equal current value (this storage slot is dirty), 200 gas is deducted. Apply both of the following clauses. if (originalStorage.length !== 0) { @@ -45,13 +44,13 @@ export function updateSstoreGasEIP1283( if (currentStorage.length === 0) { // If current value is 0 (also means that new value is not 0), remove 15000 gas from refund counter. We can prove that refund counter will never go below 0. runState.eei.subRefund( - new BN(common.param('gasPrices', 'netSstoreClearRefund')), + BigInt(common.param('gasPrices', 'netSstoreClearRefund')), 'EIP-1283 -> netSstoreClearRefund' ) } else if (value.length === 0) { // If new value is 0 (also means that current value is not 0), add 15000 gas to refund counter. runState.eei.refundGas( - new BN(common.param('gasPrices', 'netSstoreClearRefund')), + BigInt(common.param('gasPrices', 'netSstoreClearRefund')), 'EIP-1283 -> netSstoreClearRefund' ) } @@ -61,16 +60,16 @@ export function updateSstoreGasEIP1283( if (originalStorage.length === 0) { // If original value is 0, add 19800 gas to refund counter. runState.eei.refundGas( - new BN(common.param('gasPrices', 'netSstoreResetClearRefund')), + BigInt(common.param('gasPrices', 'netSstoreResetClearRefund')), 'EIP-1283 -> netSstoreResetClearRefund' ) } else { // Otherwise, add 4800 gas to refund counter. runState.eei.refundGas( - new BN(common.param('gasPrices', 'netSstoreResetRefund')), + BigInt(common.param('gasPrices', 'netSstoreResetRefund')), 'EIP-1283 -> netSstoreResetRefund' ) } } - return new BN(common.param('gasPrices', 'netSstoreDirtyGas')) + return BigInt(common.param('gasPrices', 'netSstoreDirtyGas')) } diff --git a/packages/vm/src/evm/opcodes/EIP2200.ts b/packages/vm/src/evm/opcodes/EIP2200.ts index 7fcdbccaf9..59a502eafd 100644 --- a/packages/vm/src/evm/opcodes/EIP2200.ts +++ b/packages/vm/src/evm/opcodes/EIP2200.ts @@ -1,5 +1,4 @@ import Common from '@ethereumjs/common' -import { BN } from 'ethereumjs-util' import { RunState } from './../interpreter' import { ERROR } from '../../exceptions' import { adjustSstoreGasEIP2929 } from './EIP2929' @@ -23,41 +22,41 @@ export function updateSstoreGasEIP2200( common: Common ) { // Fail if not enough gas is left - if (runState.eei.getGasLeft().lten(common.param('gasPrices', 'sstoreSentryGasEIP2200'))) { + if (runState.eei.getGasLeft() <= BigInt(common.param('gasPrices', 'sstoreSentryGasEIP2200'))) { trap(ERROR.OUT_OF_GAS) } // Noop if (currentStorage.equals(value)) { - const sstoreNoopCost = new BN(common.param('gasPrices', 'sstoreNoopGasEIP2200')) + const sstoreNoopCost = BigInt(common.param('gasPrices', 'sstoreNoopGasEIP2200')) return adjustSstoreGasEIP2929(runState, key, sstoreNoopCost, 'noop', common) } if (originalStorage.equals(currentStorage)) { // Create slot if (originalStorage.length === 0) { - return new BN(common.param('gasPrices', 'sstoreInitGasEIP2200')) + return BigInt(common.param('gasPrices', 'sstoreInitGasEIP2200')) } // Delete slot if (value.length === 0) { runState.eei.refundGas( - new BN(common.param('gasPrices', 'sstoreClearRefundEIP2200')), + BigInt(common.param('gasPrices', 'sstoreClearRefundEIP2200')), 'EIP-2200 -> sstoreClearRefundEIP2200' ) } // Write existing slot - return new BN(common.param('gasPrices', 'sstoreCleanGasEIP2200')) + return BigInt(common.param('gasPrices', 'sstoreCleanGasEIP2200')) } if (originalStorage.length > 0) { if (currentStorage.length === 0) { // Recreate slot runState.eei.subRefund( - new BN(common.param('gasPrices', 'sstoreClearRefundEIP2200')), + BigInt(common.param('gasPrices', 'sstoreClearRefundEIP2200')), 'EIP-2200 -> sstoreClearRefundEIP2200' ) } else if (value.length === 0) { // Delete slot runState.eei.refundGas( - new BN(common.param('gasPrices', 'sstoreClearRefundEIP2200')), + BigInt(common.param('gasPrices', 'sstoreClearRefundEIP2200')), 'EIP-2200 -> sstoreClearRefundEIP2200' ) } @@ -65,20 +64,20 @@ export function updateSstoreGasEIP2200( if (originalStorage.equals(value)) { if (originalStorage.length === 0) { // Reset to original non-existent slot - const sstoreInitRefund = new BN(common.param('gasPrices', 'sstoreInitRefundEIP2200')) + const sstoreInitRefund = BigInt(common.param('gasPrices', 'sstoreInitRefundEIP2200')) runState.eei.refundGas( adjustSstoreGasEIP2929(runState, key, sstoreInitRefund, 'initRefund', common), 'EIP-2200 -> initRefund' ) } else { // Reset to original existing slot - const sstoreCleanRefund = new BN(common.param('gasPrices', 'sstoreCleanRefundEIP2200')) + const sstoreCleanRefund = BigInt(common.param('gasPrices', 'sstoreCleanRefundEIP2200')) runState.eei.refundGas( - adjustSstoreGasEIP2929(runState, key, sstoreCleanRefund, 'cleanRefund', common), + BigInt(adjustSstoreGasEIP2929(runState, key, sstoreCleanRefund, 'cleanRefund', common)), 'EIP-2200 -> cleanRefund' ) } } // Dirty update - return new BN(common.param('gasPrices', 'sstoreDirtyGasEIP2200')) + return BigInt(common.param('gasPrices', 'sstoreDirtyGasEIP2200')) } diff --git a/packages/vm/src/evm/opcodes/EIP2929.ts b/packages/vm/src/evm/opcodes/EIP2929.ts index b63a6e8681..4f50f3be6b 100644 --- a/packages/vm/src/evm/opcodes/EIP2929.ts +++ b/packages/vm/src/evm/opcodes/EIP2929.ts @@ -1,5 +1,5 @@ import Common from '@ethereumjs/common' -import { Address, BN } from 'ethereumjs-util' +import { Address } from 'ethereumjs-util' import { EIP2929StateManager } from '../../state/interface' import { RunState } from './../interpreter' @@ -8,7 +8,7 @@ import { RunState } from './../interpreter' * Adjusts cost incurred for executing opcode based on whether address read * is warm/cold. (EIP 2929) * @param {RunState} runState - * @param {BN} address + * @param {Address} address * @param {Common} common * @param {Boolean} chargeGas (default: true) * @param {Boolean} isSelfdestruct (default: false) @@ -19,8 +19,8 @@ export function accessAddressEIP2929( common: Common, chargeGas = true, isSelfdestruct = false -): BN { - if (!common.isActivatedEIP(2929)) return new BN(0) +): bigint { + if (!common.isActivatedEIP(2929)) return 0n const stateManager = runState.stateManager as EIP2929StateManager const addressStr = address.buf @@ -32,13 +32,13 @@ export function accessAddressEIP2929( // CREATE, CREATE2 opcodes have the address warmed for free. // selfdestruct beneficiary address reads are charged an *additional* cold access if (chargeGas) { - return new BN(common.param('gasPrices', 'coldaccountaccess')) + return BigInt(common.param('gasPrices', 'coldaccountaccess')) } // Warm: (selfdestruct beneficiary address reads are not charged when warm) } else if (chargeGas && !isSelfdestruct) { - return new BN(common.param('gasPrices', 'warmstorageread')) + return BigInt(common.param('gasPrices', 'warmstorageread')) } - return new BN(0) + return 0n } /** @@ -54,8 +54,8 @@ export function accessStorageEIP2929( key: Buffer, isSstore: boolean, common: Common -): BN { - if (!common.isActivatedEIP(2929)) return new BN(0) +): bigint { + if (!common.isActivatedEIP(2929)) return 0n const stateManager = runState.stateManager as EIP2929StateManager const address = runState.eei.getAddress().buf @@ -64,11 +64,11 @@ export function accessStorageEIP2929( // Cold (SLOAD and SSTORE) if (slotIsCold) { stateManager.addWarmedStorage(address, key) - return new BN(common.param('gasPrices', 'coldsload')) + return BigInt(common.param('gasPrices', 'coldsload')) } else if (!isSstore) { - return new BN(common.param('gasPrices', 'warmstorageread')) + return BigInt(common.param('gasPrices', 'warmstorageread')) } - return new BN(0) + return 0n } /** @@ -84,25 +84,25 @@ export function accessStorageEIP2929( export function adjustSstoreGasEIP2929( runState: RunState, key: Buffer, - defaultCost: BN, + defaultCost: bigint, costName: string, common: Common -): BN { +): bigint { if (!common.isActivatedEIP(2929)) return defaultCost const stateManager = runState.stateManager as EIP2929StateManager const address = runState.eei.getAddress().buf - const warmRead = new BN(common.param('gasPrices', 'warmstorageread')) - const coldSload = new BN(common.param('gasPrices', 'coldsload')) + const warmRead = BigInt(common.param('gasPrices', 'warmstorageread')) + const coldSload = BigInt(common.param('gasPrices', 'coldsload')) if (stateManager.isWarmedStorage(address, key)) { switch (costName) { case 'noop': return warmRead case 'initRefund': - return new BN(common.param('gasPrices', 'sstoreInitGasEIP2200')).sub(warmRead) + return BigInt(common.param('gasPrices', 'sstoreInitGasEIP2200')) - warmRead case 'cleanRefund': - return new BN(common.param('gasPrices', 'sstoreReset')).sub(coldSload).sub(warmRead) + return BigInt(common.param('gasPrices', 'sstoreReset')) - coldSload - warmRead } } diff --git a/packages/vm/src/evm/opcodes/functions.ts b/packages/vm/src/evm/opcodes/functions.ts index d94a37a884..9f87bae9ad 100644 --- a/packages/vm/src/evm/opcodes/functions.ts +++ b/packages/vm/src/evm/opcodes/functions.ts @@ -1,12 +1,13 @@ import Common from '@ethereumjs/common' import { Address, - BN, keccak256, - setLengthRight, - TWO_POW256, - MAX_INTEGER, KECCAK256_NULL, + TWO_POW256_BIGINT, + MAX_INTEGER_BIGINT, + bufferToHex, + toBuffer, + setLengthLeft, } from 'ethereumjs-util' import { addressToBuffer, @@ -16,6 +17,10 @@ import { jumpSubIsValid, trap, writeCallOutput, + mod, + fromTwos, + toTwos, + abs, } from './util' import { ERROR } from '../../exceptions' import { RunState } from './../interpreter' @@ -44,7 +49,7 @@ export const handlers: Map = new Map([ 0x01, function (runState) { const [a, b] = runState.stack.popN(2) - const r = a.add(b).mod(TWO_POW256) + const r = mod(a + b, TWO_POW256_BIGINT) runState.stack.push(r) }, ], @@ -53,7 +58,7 @@ export const handlers: Map = new Map([ 0x02, function (runState) { const [a, b] = runState.stack.popN(2) - const r = a.mul(b).mod(TWO_POW256) + const r = mod(a * b, TWO_POW256_BIGINT) runState.stack.push(r) }, ], @@ -62,7 +67,7 @@ export const handlers: Map = new Map([ 0x03, function (runState) { const [a, b] = runState.stack.popN(2) - const r = a.sub(b).toTwos(256) + const r = mod(a - b, TWO_POW256_BIGINT) runState.stack.push(r) }, ], @@ -72,10 +77,10 @@ export const handlers: Map = new Map([ function (runState) { const [a, b] = runState.stack.popN(2) let r - if (b.isZero()) { - r = new BN(b) + if (b === 0n) { + r = 0n } else { - r = a.div(b) + r = mod(a / b, TWO_POW256_BIGINT) } runState.stack.push(r) }, @@ -84,14 +89,12 @@ export const handlers: Map = new Map([ [ 0x05, function (runState) { - let [a, b] = runState.stack.popN(2) + const [a, b] = runState.stack.popN(2) let r - if (b.isZero()) { - r = new BN(b) + if (b === 0n) { + r = 0n } else { - a = a.fromTwos(256) - b = b.fromTwos(256) - r = a.div(b).toTwos(256) + r = toTwos(fromTwos(a) / fromTwos(b)) } runState.stack.push(r) }, @@ -102,10 +105,10 @@ export const handlers: Map = new Map([ function (runState) { const [a, b] = runState.stack.popN(2) let r - if (b.isZero()) { - r = new BN(b) + if (b === 0n) { + r = b } else { - r = a.mod(b) + r = mod(a, b) } runState.stack.push(r) }, @@ -114,20 +117,17 @@ export const handlers: Map = new Map([ [ 0x07, function (runState) { - let [a, b] = runState.stack.popN(2) + const [a, b] = runState.stack.popN(2) let r - if (b.isZero()) { - r = new BN(b) + if (b === 0n) { + r = b } else { - a = a.fromTwos(256) - b = b.fromTwos(256) - r = a.abs().mod(b.abs()) - if (a.isNeg()) { - r = r.ineg() + r = mod(abs(fromTwos(a)), abs(fromTwos(b))) + if (r < 0) { + r ^= -1n } - r = r.toTwos(256) } - runState.stack.push(r) + runState.stack.push(toTwos(r)) }, ], // 0x08: ADDMOD @@ -136,10 +136,10 @@ export const handlers: Map = new Map([ function (runState) { const [a, b, c] = runState.stack.popN(3) let r - if (c.isZero()) { - r = new BN(c) + if (c === 0n) { + r = 0n } else { - r = a.add(b).mod(c) + r = mod(a + b, c) } runState.stack.push(r) }, @@ -150,10 +150,10 @@ export const handlers: Map = new Map([ function (runState) { const [a, b, c] = runState.stack.popN(3) let r - if (c.isZero()) { - r = new BN(c) + if (c === 0n) { + r = 0n } else { - r = a.mul(b).mod(c) + r = mod(a * b, c) } runState.stack.push(r) }, @@ -163,26 +163,24 @@ export const handlers: Map = new Map([ 0x0a, function (runState, common) { const [base, exponent] = runState.stack.popN(2) - if (exponent.isZero()) { - runState.stack.push(new BN(1)) + if (exponent === 0n) { + runState.stack.push(1n) return } - const byteLength = exponent.byteLength() + const byteLength = exponent.toString(2).length / 8 if (byteLength < 1 || byteLength > 32) { trap(ERROR.OUT_OF_RANGE) } const gasPrice = common.param('gasPrices', 'expByte') - const amount = new BN(byteLength).muln(gasPrice) - runState.eei.useGas(amount, 'EXP opcode') + const amount = byteLength * gasPrice + runState.eei.useGas(BigInt(amount), 'EXP opcode') - if (base.isZero()) { - runState.stack.push(new BN(0)) + if (base === 0n) { + runState.stack.push(base) return } - const m = BN.red(TWO_POW256) - const redBase = base.toRed(m) - const r = redBase.redPow(exponent) - runState.stack.push(r.fromRed()) + const r = base ** exponent + runState.stack.push(r) }, ], // 0x0b: SIGNEXTEND @@ -191,17 +189,14 @@ export const handlers: Map = new Map([ function (runState) { /* eslint-disable-next-line prefer-const */ let [k, val] = runState.stack.popN(2) - if (k.ltn(31)) { - const signBit = k.muln(8).iaddn(7).toNumber() - const mask = new BN(1).ishln(signBit).isubn(1) - if (val.testn(signBit)) { - val = val.or(mask.notn(256)) + if (k > 31n) { + const signBit = k * 8n + 7n + const mask = (1n << signBit) - 1n + if (val.toString(2)[Number(signBit)] === '1') { + val = val | BigInt.asUintN(256, ~mask) } else { - val = val.and(mask) + val = val & mask } - } else { - // return the same value - val = new BN(val) } runState.stack.push(val) }, @@ -212,7 +207,7 @@ export const handlers: Map = new Map([ 0x10, function (runState) { const [a, b] = runState.stack.popN(2) - const r = new BN(a.lt(b) ? 1 : 0) + const r = a < b ? 1n : 0n runState.stack.push(r) }, ], @@ -221,7 +216,7 @@ export const handlers: Map = new Map([ 0x11, function (runState) { const [a, b] = runState.stack.popN(2) - const r = new BN(a.gt(b) ? 1 : 0) + const r = a > b ? 1n : 0n runState.stack.push(r) }, ], @@ -230,7 +225,7 @@ export const handlers: Map = new Map([ 0x12, function (runState) { const [a, b] = runState.stack.popN(2) - const r = new BN(a.fromTwos(256).lt(b.fromTwos(256)) ? 1 : 0) + const r = fromTwos(a) < fromTwos(b) ? 1n : 0n runState.stack.push(r) }, ], @@ -239,7 +234,7 @@ export const handlers: Map = new Map([ 0x13, function (runState) { const [a, b] = runState.stack.popN(2) - const r = new BN(a.fromTwos(256).gt(b.fromTwos(256)) ? 1 : 0) + const r = fromTwos(a) > fromTwos(b) ? 1n : 0n runState.stack.push(r) }, ], @@ -248,7 +243,7 @@ export const handlers: Map = new Map([ 0x14, function (runState) { const [a, b] = runState.stack.popN(2) - const r = new BN(a.eq(b) ? 1 : 0) + const r = a === b ? 1n : 0n runState.stack.push(r) }, ], @@ -257,7 +252,7 @@ export const handlers: Map = new Map([ 0x15, function (runState) { const a = runState.stack.pop() - const r = new BN(a.isZero() ? 1 : 0) + const r = a === 0n ? 1n : 0n runState.stack.push(r) }, ], @@ -266,7 +261,7 @@ export const handlers: Map = new Map([ 0x16, function (runState) { const [a, b] = runState.stack.popN(2) - const r = a.and(b) + const r = a & b runState.stack.push(r) }, ], @@ -275,7 +270,7 @@ export const handlers: Map = new Map([ 0x17, function (runState) { const [a, b] = runState.stack.popN(2) - const r = a.or(b) + const r = a | b runState.stack.push(r) }, ], @@ -284,7 +279,7 @@ export const handlers: Map = new Map([ 0x18, function (runState) { const [a, b] = runState.stack.popN(2) - const r = a.xor(b) + const r = a ^ b runState.stack.push(r) }, ], @@ -293,7 +288,7 @@ export const handlers: Map = new Map([ 0x19, function (runState) { const a = runState.stack.pop() - const r = a.notn(256) + const r = BigInt.asUintN(256, ~a) runState.stack.push(r) }, ], @@ -302,12 +297,12 @@ export const handlers: Map = new Map([ 0x1a, function (runState) { const [pos, word] = runState.stack.popN(2) - if (pos.gten(32)) { - runState.stack.push(new BN(0)) + if (pos > 32n) { + runState.stack.push(0n) return } - const r = new BN(word.shrn((31 - pos.toNumber()) * 8).andln(0xff)) + const r = (word >> ((31n - pos) * 8n)) & BigInt(0xff) runState.stack.push(r) }, ], @@ -316,12 +311,12 @@ export const handlers: Map = new Map([ 0x1b, function (runState) { const [a, b] = runState.stack.popN(2) - if (a.gten(256)) { - runState.stack.push(new BN(0)) + if (a > 256n) { + runState.stack.push(0n) return } - const r = b.shln(a.toNumber()).iand(MAX_INTEGER) + const r = (b << a) & MAX_INTEGER_BIGINT runState.stack.push(r) }, ], @@ -330,12 +325,12 @@ export const handlers: Map = new Map([ 0x1c, function (runState) { const [a, b] = runState.stack.popN(2) - if (a.gten(256)) { - runState.stack.push(new BN(0)) + if (a > 256) { + runState.stack.push(0n) return } - const r = b.shrn(a.toNumber()) + const r = b >> a runState.stack.push(r) }, ], @@ -346,22 +341,22 @@ export const handlers: Map = new Map([ const [a, b] = runState.stack.popN(2) let r - const isSigned = b.testn(255) - if (a.gten(256)) { + const isSigned = b.toString(2)[255] === '1' + if (a > 256) { if (isSigned) { - r = new BN(MAX_INTEGER) + r = MAX_INTEGER_BIGINT } else { - r = new BN(0) + r = 0n } runState.stack.push(r) return } - const c = b.shrn(a.toNumber()) + const c = b >> a if (isSigned) { - const shiftedOutWidth = 255 - a.toNumber() - const mask = MAX_INTEGER.shrn(shiftedOutWidth).shln(shiftedOutWidth) - r = c.ior(mask) + const shiftedOutWidth = 255n - a + const mask = (MAX_INTEGER_BIGINT >> shiftedOutWidth) << shiftedOutWidth + r = c | mask } else { r = c } @@ -375,10 +370,10 @@ export const handlers: Map = new Map([ function (runState) { const [offset, length] = runState.stack.popN(2) let data = Buffer.alloc(0) - if (!length.isZero()) { - data = runState.memory.read(offset.toNumber(), length.toNumber()) + if (!(length === 0n)) { + data = runState.memory.read(Number(offset), Number(length)) } - const r = new BN(keccak256(data)) + const r = BigInt('0x' + keccak256(data).toString('hex')) runState.stack.push(r) }, ], @@ -387,7 +382,7 @@ export const handlers: Map = new Map([ [ 0x30, function (runState) { - const address = new BN(runState.eei.getAddress().buf) + const address = BigInt('0x' + runState.eei.getAddress().buf.toString('hex')) runState.stack.push(address) }, ], @@ -395,8 +390,8 @@ export const handlers: Map = new Map([ [ 0x31, async function (runState) { - const addressBN = runState.stack.pop() - const address = new Address(addressToBuffer(addressBN)) + const addressBigInt = runState.stack.pop() + const address = new Address(addressToBuffer(addressBigInt)) const balance = await runState.eei.getExternalBalance(address) runState.stack.push(balance) }, @@ -427,16 +422,15 @@ export const handlers: Map = new Map([ 0x35, function (runState) { const pos = runState.stack.pop() - if (pos.gt(runState.eei.getCallDataSize())) { - runState.stack.push(new BN(0)) + if (pos > runState.eei.getCallDataSize()) { + runState.stack.push(0n) return } - const i = pos.toNumber() + const i = Number(pos) let loaded = runState.eei.getCallData().slice(i, i + 32) loaded = loaded.length ? loaded : Buffer.from([0]) - const r = new BN(setLengthRight(loaded, 32)) - + const r = BigInt.asUintN(256, BigInt(bufferToHex(loaded))) runState.stack.push(r) }, ], @@ -454,10 +448,10 @@ export const handlers: Map = new Map([ function (runState) { const [memOffset, dataOffset, dataLength] = runState.stack.popN(3) - if (!dataLength.eqn(0)) { + if (!(dataLength === 0n)) { const data = getDataSlice(runState.eei.getCallData(), dataOffset, dataLength) - const memOffsetNum = memOffset.toNumber() - const dataLengthNum = dataLength.toNumber() + const memOffsetNum = Number(memOffset) + const dataLengthNum = Number(dataLength) runState.memory.extend(memOffsetNum, dataLengthNum) runState.memory.write(memOffsetNum, dataLengthNum, data) } @@ -476,10 +470,10 @@ export const handlers: Map = new Map([ function (runState) { const [memOffset, codeOffset, dataLength] = runState.stack.popN(3) - if (!dataLength.eqn(0)) { + if (!(dataLength === 0n)) { const data = getDataSlice(runState.eei.getCode(), codeOffset, dataLength) - const memOffsetNum = memOffset.toNumber() - const lengthNum = dataLength.toNumber() + const memOffsetNum = Number(memOffset) + const lengthNum = Number(dataLength) runState.memory.extend(memOffsetNum, lengthNum) runState.memory.write(memOffsetNum, lengthNum, data) } @@ -489,8 +483,8 @@ export const handlers: Map = new Map([ [ 0x3b, async function (runState) { - const addressBN = runState.stack.pop() - const size = await runState.eei.getExternalCodeSize(addressBN) + const addressBigInt = runState.stack.pop() + const size = await runState.eei.getExternalCodeSize(addressBigInt) runState.stack.push(size) }, ], @@ -500,12 +494,12 @@ export const handlers: Map = new Map([ async function (runState) { const [addressBN, memOffset, codeOffset, dataLength] = runState.stack.popN(4) - if (!dataLength.eqn(0)) { + if (!(dataLength === 0n)) { const code = await runState.eei.getExternalCode(addressBN) const data = getDataSlice(code, codeOffset, dataLength) - const memOffsetNum = memOffset.toNumber() - const lengthNum = dataLength.toNumber() + const memOffsetNum = Number(memOffset) + const lengthNum = Number(dataLength) runState.memory.extend(memOffsetNum, lengthNum) runState.memory.write(memOffsetNum, lengthNum, data) } @@ -515,21 +509,21 @@ export const handlers: Map = new Map([ [ 0x3f, async function (runState) { - const addressBN = runState.stack.pop() - const address = new Address(addressToBuffer(addressBN)) + const addressBigInt = runState.stack.pop() + const address = new Address(addressToBuffer(addressBigInt)) const empty = await runState.eei.isAccountEmpty(address) if (empty) { - runState.stack.push(new BN(0)) + runState.stack.push(0n) return } - const code = await runState.eei.getExternalCode(addressBN) + const code = await runState.eei.getExternalCode(addressBigInt) if (code.length === 0) { - runState.stack.push(new BN(KECCAK256_NULL)) + runState.stack.push(BigInt(bufferToHex(KECCAK256_NULL))) return } - runState.stack.push(new BN(keccak256(code))) + runState.stack.push(BigInt(bufferToHex(keccak256(code)))) }, ], // 0x3d: RETURNDATASIZE @@ -545,10 +539,10 @@ export const handlers: Map = new Map([ function (runState) { const [memOffset, returnDataOffset, dataLength] = runState.stack.popN(3) - if (!dataLength.eqn(0)) { + if (!(dataLength === 0n)) { const data = getDataSlice(runState.eei.getReturnData(), returnDataOffset, dataLength) - const memOffsetNum = memOffset.toNumber() - const lengthNum = dataLength.toNumber() + const memOffsetNum = Number(memOffset) + const lengthNum = Number(dataLength) runState.memory.extend(memOffsetNum, lengthNum) runState.memory.write(memOffsetNum, lengthNum, data) } @@ -568,10 +562,10 @@ export const handlers: Map = new Map([ async function (runState) { const number = runState.stack.pop() - const diff = runState.eei.getBlockNumber().sub(number) + const diff = runState.eei.getBlockNumber() - number // block lookups must be within the past 256 blocks - if (diff.gtn(256) || diff.lten(0)) { - runState.stack.push(new BN(0)) + if (diff > 256n || diff <= 0n) { + runState.stack.push(0n) return } @@ -648,8 +642,8 @@ export const handlers: Map = new Map([ 0x51, function (runState) { const pos = runState.stack.pop() - const word = runState.memory.read(pos.toNumber(), 32) - runState.stack.push(new BN(word)) + const word = runState.memory.read(Number(pos), 32) + runState.stack.push(BigInt(bufferToHex(word))) }, ], // 0x52: MSTORE @@ -657,8 +651,8 @@ export const handlers: Map = new Map([ 0x52, function (runState) { const [offset, word] = runState.stack.popN(2) - const buf = word.toArrayLike(Buffer, 'be', 32) - const offsetNum = offset.toNumber() + const buf = setLengthLeft(toBuffer('0x' + word.toString(16)), 32) + const offsetNum = Number(offset) runState.memory.extend(offsetNum, 32) runState.memory.write(offsetNum, 32, buf) }, @@ -669,11 +663,8 @@ export const handlers: Map = new Map([ function (runState) { const [offset, byte] = runState.stack.popN(2) - // NOTE: we're using a 'trick' here to get the least significant byte - // NOTE: force cast necessary because `BN.andln` returns number but - // the types are wrong - const buf = Buffer.from([byte.andln(0xff) as unknown as number]) - const offsetNum = offset.toNumber() + const buf = toBuffer('0x' + (byte & 0xffn).toString(16)) + const offsetNum = Number(offset) runState.memory.extend(offsetNum, 1) runState.memory.write(offsetNum, 1, buf) }, @@ -683,10 +674,10 @@ export const handlers: Map = new Map([ 0x54, async function (runState) { const key = runState.stack.pop() - const keyBuf = key.toArrayLike(Buffer, 'be', 32) + const keyBuf = setLengthLeft(toBuffer('0x' + key.toString(16)), 32) const value = await runState.eei.storageLoad(keyBuf) - const valueBN = value.length ? new BN(value) : new BN(0) - runState.stack.push(valueBN) + const valueBigInt = value.length ? BigInt(bufferToHex(value)) : 0n + runState.stack.push(valueBigInt) }, ], // 0x55: SSTORE @@ -695,13 +686,13 @@ export const handlers: Map = new Map([ async function (runState) { const [key, val] = runState.stack.popN(2) - const keyBuf = key.toArrayLike(Buffer, 'be', 32) + const keyBuf = setLengthLeft(toBuffer('0x' + key.toString(16)), 32) // NOTE: this should be the shortest representation let value - if (val.isZero()) { + if (val === 0n) { value = Buffer.from([]) } else { - value = val.toArrayLike(Buffer, 'be') + value = toBuffer('0x' + val.toString(16)) } await runState.eei.storageStore(keyBuf, value) @@ -712,11 +703,11 @@ export const handlers: Map = new Map([ 0x56, function (runState) { const dest = runState.stack.pop() - if (dest.gt(runState.eei.getCodeSize())) { + if (dest > runState.eei.getCodeSize()) { trap(ERROR.INVALID_JUMP + ' at ' + describeLocation(runState)) } - const destNum = dest.toNumber() + const destNum = Number(dest) if (!jumpIsValid(runState, destNum)) { trap(ERROR.INVALID_JUMP + ' at ' + describeLocation(runState)) @@ -730,12 +721,12 @@ export const handlers: Map = new Map([ 0x57, function (runState) { const [dest, cond] = runState.stack.popN(2) - if (!cond.isZero()) { - if (dest.gt(runState.eei.getCodeSize())) { + if (!(cond === 0n)) { + if (dest > runState.eei.getCodeSize()) { trap(ERROR.INVALID_JUMP + ' at ' + describeLocation(runState)) } - const destNum = dest.toNumber() + const destNum = Number(dest) if (!jumpIsValid(runState, destNum)) { trap(ERROR.INVALID_JUMP + ' at ' + describeLocation(runState)) @@ -749,21 +740,21 @@ export const handlers: Map = new Map([ [ 0x58, function (runState) { - runState.stack.push(new BN(runState.programCounter - 1)) + runState.stack.push(BigInt(runState.programCounter - 1)) }, ], // 0x59: MSIZE [ 0x59, function (runState) { - runState.stack.push(runState.memoryWordCount.muln(32)) + runState.stack.push(runState.memoryWordCount * 32n) }, ], // 0x5a: GAS [ 0x5a, function (runState) { - runState.stack.push(new BN(runState.eei.getGasLeft())) + runState.stack.push(runState.eei.getGasLeft()) }, ], // 0x5b: JUMPDEST @@ -784,7 +775,7 @@ export const handlers: Map = new Map([ } const dest = runState.returnStack.pop() - runState.programCounter = dest.toNumber() + runState.programCounter = Number(dest) }, ], // 0x5e: JUMPSUB @@ -793,17 +784,17 @@ export const handlers: Map = new Map([ function (runState) { const dest = runState.stack.pop() - if (dest.gt(runState.eei.getCodeSize())) { + if (dest > runState.eei.getCodeSize()) { trap(ERROR.INVALID_JUMPSUB + ' at ' + describeLocation(runState)) } - const destNum = dest.toNumber() + const destNum = Number(dest) if (!jumpSubIsValid(runState, destNum)) { trap(ERROR.INVALID_JUMPSUB + ' at ' + describeLocation(runState)) } - runState.returnStack.push(new BN(runState.programCounter)) + runState.returnStack.push(BigInt(runState.programCounter)) runState.programCounter = destNum + 1 }, ], @@ -811,7 +802,7 @@ export const handlers: Map = new Map([ [ 0x5f, function (runState) { - runState.stack.push(new BN(0)) + runState.stack.push(0n) }, ], // 0x60: PUSH @@ -819,8 +810,10 @@ export const handlers: Map = new Map([ 0x60, function (runState) { const numToPush = runState.opCode - 0x5f - const loaded = new BN( - runState.eei.getCode().slice(runState.programCounter, runState.programCounter + numToPush) + const loaded = BigInt( + bufferToHex( + runState.eei.getCode().slice(runState.programCounter, runState.programCounter + numToPush) + ) ) runState.programCounter += numToPush runState.stack.push(loaded) @@ -851,13 +844,13 @@ export const handlers: Map = new Map([ const topicsCount = runState.opCode - 0xa0 const topics = runState.stack.popN(topicsCount) - const topicsBuf = topics.map(function (a: BN) { - return a.toArrayLike(Buffer, 'be', 32) + const topicsBuf = topics.map(function (a: bigint) { + return setLengthLeft(toBuffer('0x' + a.toString(16)), 32) }) let mem = Buffer.alloc(0) - if (!memLength.isZero()) { - mem = runState.memory.read(memOffset.toNumber(), memLength.toNumber()) + if (!(memLength === 0n)) { + mem = runState.memory.read(Number(memOffset), Number(memLength)) } runState.eei.log(mem, topicsCount, topicsBuf) @@ -875,8 +868,8 @@ export const handlers: Map = new Map([ runState.messageGasLimit = undefined let data = Buffer.alloc(0) - if (!length.isZero()) { - data = runState.memory.read(offset.toNumber(), length.toNumber()) + if (!(length === 0n)) { + data = runState.memory.read(Number(offset), Number(length)) } const ret = await runState.eei.create(gasLimit, value, data) @@ -897,15 +890,15 @@ export const handlers: Map = new Map([ runState.messageGasLimit = undefined let data = Buffer.alloc(0) - if (!length.isZero()) { - data = runState.memory.read(offset.toNumber(), length.toNumber()) + if (!(length === 0n)) { + data = runState.memory.read(Number(offset), Number(length)) } const ret = await runState.eei.create2( gasLimit, value, data, - salt.toArrayLike(Buffer, 'be', 32) + setLengthLeft(toBuffer('0x' + salt.toString(16)), 32) ) runState.stack.push(ret) }, @@ -919,8 +912,8 @@ export const handlers: Map = new Map([ const toAddress = new Address(addressToBuffer(toAddr)) let data = Buffer.alloc(0) - if (!inLength.isZero()) { - data = runState.memory.read(inOffset.toNumber(), inLength.toNumber()) + if (!(inLength === 0n)) { + data = runState.memory.read(Number(inOffset), Number(inLength)) } const gasLimit = runState.messageGasLimit! @@ -944,8 +937,8 @@ export const handlers: Map = new Map([ runState.messageGasLimit = undefined let data = Buffer.alloc(0) - if (!inLength.isZero()) { - data = runState.memory.read(inOffset.toNumber(), inLength.toNumber()) + if (!(inLength === 0n)) { + data = runState.memory.read(Number(inOffset), Number(inLength)) } const ret = await runState.eei.callCode(gasLimit, toAddress, value, data) @@ -964,8 +957,8 @@ export const handlers: Map = new Map([ const toAddress = new Address(addressToBuffer(toAddr)) let data = Buffer.alloc(0) - if (!inLength.isZero()) { - data = runState.memory.read(inOffset.toNumber(), inLength.toNumber()) + if (!(inLength === 0n)) { + data = runState.memory.read(Number(inOffset), Number(inLength)) } const gasLimit = runState.messageGasLimit! @@ -981,7 +974,7 @@ export const handlers: Map = new Map([ [ 0xfa, async function (runState) { - const value = new BN(0) + const value = 0n const [_currentGasLimit, toAddr, inOffset, inLength, outOffset, outLength] = runState.stack.popN(6) const toAddress = new Address(addressToBuffer(toAddr)) @@ -990,8 +983,8 @@ export const handlers: Map = new Map([ runState.messageGasLimit = undefined let data = Buffer.alloc(0) - if (!inLength.isZero()) { - data = runState.memory.read(inOffset.toNumber(), inLength.toNumber()) + if (!(inLength === 0n)) { + data = runState.memory.read(Number(inOffset), Number(inLength)) } const ret = await runState.eei.callStatic(gasLimit, toAddress, value, data) @@ -1006,8 +999,8 @@ export const handlers: Map = new Map([ function (runState) { const [offset, length] = runState.stack.popN(2) let returnData = Buffer.alloc(0) - if (!length.isZero()) { - returnData = runState.memory.read(offset.toNumber(), length.toNumber()) + if (!(length === 0n)) { + returnData = runState.memory.read(Number(offset), Number(length)) } runState.eei.finish(returnData) }, @@ -1018,8 +1011,8 @@ export const handlers: Map = new Map([ function (runState) { const [offset, length] = runState.stack.popN(2) let returnData = Buffer.alloc(0) - if (!length.isZero()) { - returnData = runState.memory.read(offset.toNumber(), length.toNumber()) + if (!(length === 0n)) { + returnData = runState.memory.read(Number(offset), Number(length)) } runState.eei.revert(returnData) }, diff --git a/packages/vm/src/evm/opcodes/gas.ts b/packages/vm/src/evm/opcodes/gas.ts index 4d5eaf40ce..23483957ff 100644 --- a/packages/vm/src/evm/opcodes/gas.ts +++ b/packages/vm/src/evm/opcodes/gas.ts @@ -7,7 +7,7 @@ import { trap, updateSstoreGas, } from '.' -import { Address, BN } from 'ethereumjs-util' +import { Address, setLengthLeft, toBuffer } from 'ethereumjs-util' import { ERROR } from '../../exceptions' import { RunState } from '../interpreter' import Common from '@ethereumjs/common' @@ -25,7 +25,7 @@ import { accessAddressEIP2929, accessStorageEIP2929 } from './EIP2929' // The gas BN is necessary, since the base fee needs to be included, // to calculate the max call gas for the call opcodes correctly. export interface AsyncDynamicGasHandler { - (runState: RunState, gas: BN, common: Common): Promise + (runState: RunState, gas: bigint, common: Common): Promise } export const dynamicGasHandlers: Map = new Map< @@ -35,198 +35,207 @@ export const dynamicGasHandlers: Map = new Map< [ /* SHA3 */ 0x20, - async function (runState, gas, common): Promise { + async function (runState, gas, common): Promise { const [offset, length] = runState.stack.peek(2) - gas.iadd(subMemUsage(runState, offset, length, common)) - gas.iadd(new BN(common.param('gasPrices', 'sha3Word')).imul(divCeil(length, new BN(32)))) + gas += subMemUsage(runState, offset, length, common) + gas += BigInt(common.param('gasPrices', 'sha3Word')) * divCeil(length, 32n) + return gas }, ], [ /* BALANCE */ 0x31, - async function (runState, gas, common): Promise { + async function (runState, gas, common): Promise { if (common.isActivatedEIP(2929)) { - const addressBN = runState.stack.peek()[0] - const address = new Address(addressToBuffer(addressBN)) - gas.iadd(accessAddressEIP2929(runState, address, common)) + const addressBigInt = runState.stack.peek()[0] + const address = new Address(addressToBuffer(addressBigInt)) + gas += accessAddressEIP2929(runState, address, common) } + return gas }, ], [ /* CALLDATACOPY */ 0x37, - async function (runState, gas, common): Promise { + async function (runState, gas, common): Promise { const [memOffset, _dataOffset, dataLength] = runState.stack.peek(3) - gas.iadd(subMemUsage(runState, memOffset, dataLength, common)) - if (!dataLength.eqn(0)) { - gas.iadd(new BN(common.param('gasPrices', 'copy')).imul(divCeil(dataLength, new BN(32)))) + gas += subMemUsage(runState, memOffset, dataLength, common) + if (!(dataLength === 0n)) { + gas += BigInt(common.param('gasPrices', 'copy')) * divCeil(dataLength, 32n) } + return gas }, ], [ /* CODECOPY */ 0x39, - async function (runState, gas, common): Promise { + async function (runState, gas, common): Promise { const [memOffset, _codeOffset, dataLength] = runState.stack.peek(3) - gas.iadd(subMemUsage(runState, memOffset, dataLength, common)) - if (!dataLength.eqn(0)) { - gas.iadd(new BN(common.param('gasPrices', 'copy')).imul(divCeil(dataLength, new BN(32)))) + gas += subMemUsage(runState, memOffset, dataLength, common) + if (!(dataLength === 0n)) { + gas += BigInt(common.param('gasPrices', 'copy')) * divCeil(dataLength, 32n) } + return gas }, ], [ /* EXTCODESIZE */ 0x3b, - async function (runState, gas, common): Promise { + async function (runState, gas, common): Promise { if (common.isActivatedEIP(2929)) { - const addressBN = runState.stack.peek()[0] - const address = new Address(addressToBuffer(addressBN)) - gas.iadd(accessAddressEIP2929(runState, address, common)) + const addressBigInt = runState.stack.peek()[0] + const address = new Address(addressToBuffer(addressBigInt)) + gas += accessAddressEIP2929(runState, address, common) } + return gas }, ], [ /* EXTCODECOPY */ 0x3c, - async function (runState, gas, common): Promise { - const [addressBN, memOffset, _codeOffset, dataLength] = runState.stack.peek(4) + async function (runState, gas, common): Promise { + const [addressBigInt, memOffset, _codeOffset, dataLength] = runState.stack.peek(4) - gas.iadd(subMemUsage(runState, memOffset, dataLength, common)) + gas += subMemUsage(runState, memOffset, dataLength, common) if (common.isActivatedEIP(2929)) { - const address = new Address(addressToBuffer(addressBN)) - gas.iadd(accessAddressEIP2929(runState, address, common)) + const address = new Address(addressToBuffer(addressBigInt)) + gas += accessAddressEIP2929(runState, address, common) } - if (!dataLength.eqn(0)) { - gas.iadd(new BN(common.param('gasPrices', 'copy')).imul(divCeil(dataLength, new BN(32)))) + if (!(dataLength === 0n)) { + gas = (gas + BigInt(common.param('gasPrices', 'copy'))) * divCeil(dataLength, 32n) } + return gas }, ], [ /* RETURNDATACOPY */ 0x3e, - async function (runState, gas, common): Promise { + async function (runState, gas, common): Promise { const [memOffset, returnDataOffset, dataLength] = runState.stack.peek(3) - if (returnDataOffset.add(dataLength).gt(runState.eei.getReturnDataSize())) { + if (returnDataOffset + dataLength > runState.eei.getReturnDataSize()) { trap(ERROR.OUT_OF_GAS) } - gas.iadd(subMemUsage(runState, memOffset, dataLength, common)) + gas += subMemUsage(runState, memOffset, dataLength, common) - if (!dataLength.eqn(0)) { - gas.iadd(new BN(common.param('gasPrices', 'copy')).mul(divCeil(dataLength, new BN(32)))) + if (!(dataLength === 0n)) { + gas += BigInt(common.param('gasPrices', 'copy')) * divCeil(dataLength, 32n) } + return gas }, ], [ /* EXTCODEHASH */ 0x3f, - async function (runState, gas, common): Promise { + async function (runState, gas, common): Promise { if (common.isActivatedEIP(2929)) { - const addressBN = runState.stack.peek()[0] - const address = new Address(addressToBuffer(addressBN)) - gas.iadd(accessAddressEIP2929(runState, address, common)) + const addressBigInt = runState.stack.peek()[0] + const address = new Address(addressToBuffer(addressBigInt)) + gas += accessAddressEIP2929(runState, address, common) } + return gas }, ], [ /* MLOAD */ 0x51, - async function (runState, gas, common): Promise { + async function (runState, gas, common): Promise { const pos = runState.stack.peek()[0] - gas.iadd(subMemUsage(runState, pos, new BN(32), common)) + gas += subMemUsage(runState, pos, 32n, common) + return gas }, ], [ /* MSTORE */ 0x52, - async function (runState, gas, common): Promise { + async function (runState, gas, common): Promise { const offset = runState.stack.peek()[0] - gas.iadd(subMemUsage(runState, offset, new BN(32), common)) + gas += subMemUsage(runState, offset, 32n, common) + return gas }, ], [ /* MSTORE8 */ 0x53, - async function (runState, gas, common): Promise { + async function (runState, gas, common): Promise { const offset = runState.stack.peek()[0] - gas.iadd(subMemUsage(runState, offset, new BN(1), common)) + gas += subMemUsage(runState, offset, 1n, common) + return gas }, ], [ /* SLOAD */ 0x54, - async function (runState, gas, common): Promise { + async function (runState, gas, common): Promise { const key = runState.stack.peek()[0] - const keyBuf = key.toArrayLike(Buffer, 'be', 32) + const keyBuf = setLengthLeft(toBuffer('0x' + key.toString(16)), 32) if (common.isActivatedEIP(2929)) { - gas.iadd(accessStorageEIP2929(runState, keyBuf, false, common)) + gas += accessStorageEIP2929(runState, keyBuf, false, common) } + return gas }, ], [ /* SSTORE */ 0x55, - async function (runState, gas, common): Promise { + async function (runState, gas, common): Promise { if (runState.eei.isStatic()) { trap(ERROR.STATIC_STATE_CHANGE) } const [key, val] = runState.stack.peek(2) - const keyBuf = key.toArrayLike(Buffer, 'be', 32) + const keyBuf = setLengthLeft(toBuffer('0x' + key.toString(16)), 32) // NOTE: this should be the shortest representation let value - if (val.isZero()) { + if (val === 0n) { value = Buffer.from([]) } else { - value = val.toArrayLike(Buffer, 'be') + value = toBuffer('0x' + val.toString(16)) } // TODO: Replace getContractStorage with EEI method const currentStorage = setLengthLeftStorage(await runState.eei.storageLoad(keyBuf)) const originalStorage = setLengthLeftStorage(await runState.eei.storageLoad(keyBuf, true)) if (common.hardfork() === 'constantinople') { - gas.iadd( - updateSstoreGasEIP1283( - runState, - currentStorage, - originalStorage, - setLengthLeftStorage(value), - common - ) + gas += updateSstoreGasEIP1283( + runState, + currentStorage, + originalStorage, + setLengthLeftStorage(value), + common ) } else if (common.gteHardfork('istanbul')) { - gas.iadd( - updateSstoreGasEIP2200( - runState, - currentStorage, - originalStorage, - setLengthLeftStorage(value), - keyBuf, - common - ) + gas += updateSstoreGasEIP2200( + runState, + currentStorage, + originalStorage, + setLengthLeftStorage(value), + keyBuf, + common ) } else { - gas.iadd(updateSstoreGas(runState, currentStorage, setLengthLeftStorage(value), common)) + gas += updateSstoreGas(runState, currentStorage, setLengthLeftStorage(value), common) } if (common.isActivatedEIP(2929)) { // We have to do this after the Istanbul (EIP2200) checks. // Otherwise, we might run out of gas, due to "sentry check" of 2300 gas, // if we deduct extra gas first. - gas.iadd(accessStorageEIP2929(runState, keyBuf, true, common)) + gas += accessStorageEIP2929(runState, keyBuf, true, common) } + return gas }, ], [ /* LOG */ 0xa0, - async function (runState, gas, common): Promise { + async function (runState, gas, common): Promise { if (runState.eei.isStatic()) { trap(ERROR.STATIC_STATE_CHANGE) } @@ -239,239 +248,237 @@ export const dynamicGasHandlers: Map = new Map< trap(ERROR.OUT_OF_RANGE) } - gas.iadd(subMemUsage(runState, memOffset, memLength, common)) - gas.iadd( - new BN(common.param('gasPrices', 'logTopic')) - .imuln(topicsCount) - .iadd(memLength.muln(common.param('gasPrices', 'logData'))) - ) + gas += subMemUsage(runState, memOffset, memLength, common) + gas = + gas + + BigInt(common.param('gasPrices', 'logTopic')) * BigInt(topicsCount) + + memLength * BigInt(common.param('gasPrices', 'logData')) + return gas }, ], [ /* CREATE */ 0xf0, - async function (runState, gas, common): Promise { + async function (runState, gas, common): Promise { if (runState.eei.isStatic()) { trap(ERROR.STATIC_STATE_CHANGE) } const [_value, offset, length] = runState.stack.peek(3) if (common.isActivatedEIP(2929)) { - gas.iadd(accessAddressEIP2929(runState, runState.eei.getAddress(), common, false)) + gas += accessAddressEIP2929(runState, runState.eei.getAddress(), common, false) } - gas.iadd(subMemUsage(runState, offset, length, common)) + gas += subMemUsage(runState, offset, length, common) - let gasLimit = new BN(runState.eei.getGasLeft().isub(gas)) - gasLimit = maxCallGas(gasLimit.clone(), gasLimit.clone(), runState, common) + let gasLimit = BigInt(runState.eei.getGasLeft()) - gas + gasLimit = maxCallGas(gasLimit, gasLimit, runState, common) runState.messageGasLimit = gasLimit + return gas }, ], [ /* CALL */ 0xf1, - async function (runState, gas, common): Promise { + async function (runState, gas, common): Promise { const [currentGasLimit, toAddr, value, inOffset, inLength, outOffset, outLength] = runState.stack.peek(7) const toAddress = new Address(addressToBuffer(toAddr)) - if (runState.eei.isStatic() && !value.isZero()) { + if (runState.eei.isStatic() && !(value === 0n)) { trap(ERROR.STATIC_STATE_CHANGE) } - gas.iadd(subMemUsage(runState, inOffset, inLength, common)) - gas.iadd(subMemUsage(runState, outOffset, outLength, common)) + gas += subMemUsage(runState, inOffset, inLength, common) + gas += subMemUsage(runState, outOffset, outLength, common) if (common.isActivatedEIP(2929)) { - gas.iadd(accessAddressEIP2929(runState, toAddress, common)) + gas += accessAddressEIP2929(runState, toAddress, common) } - if (!value.isZero()) { - gas.iadd(new BN(common.param('gasPrices', 'callValueTransfer'))) + if (!(value === 0n)) { + gas += BigInt(common.param('gasPrices', 'callValueTransfer')) } if (common.gteHardfork('spuriousDragon')) { // We are at or after Spurious Dragon // Call new account gas: account is DEAD and we transfer nonzero value - if ((await runState.eei.isAccountEmpty(toAddress)) && !value.isZero()) { - gas.iadd(new BN(common.param('gasPrices', 'callNewAccount'))) + if ((await runState.eei.isAccountEmpty(toAddress)) && !(value === 0n)) { + gas += BigInt(common.param('gasPrices', 'callNewAccount')) } } else if (!(await runState.eei.accountExists(toAddress))) { // We are before Spurious Dragon and the account does not exist. // Call new account gas: account does not exist (it is not in the state trie, not even as an "empty" account) - gas.iadd(new BN(common.param('gasPrices', 'callNewAccount'))) + gas += BigInt(common.param('gasPrices', 'callNewAccount')) } - const gasLimit = maxCallGas( - currentGasLimit.clone(), - runState.eei.getGasLeft().isub(gas), - runState, - common - ) + let gasLimit = maxCallGas(currentGasLimit, runState.eei.getGasLeft() - gas, runState, common) // note that TangerineWhistle or later this cannot happen // (it could have ran out of gas prior to getting here though) - if (gasLimit.gt(runState.eei.getGasLeft().isub(gas))) { + if (gasLimit > runState.eei.getGasLeft() - gas) { trap(ERROR.OUT_OF_GAS) } - if (gas.gt(runState.eei.getGasLeft())) { + if (gas > runState.eei.getGasLeft()) { trap(ERROR.OUT_OF_GAS) } - if (!value.isZero()) { + if (!(value === 0n)) { // TODO: Don't use private attr directly - runState.eei._gasLeft.iaddn(common.param('gasPrices', 'callStipend')) - gasLimit.iaddn(common.param('gasPrices', 'callStipend')) + runState.eei._gasLeft += BigInt(common.param('gasPrices', 'callStipend')) + gasLimit += BigInt(common.param('gasPrices', 'callStipend')) } runState.messageGasLimit = gasLimit + return gas }, ], [ /* CALLCODE */ 0xf2, - async function (runState, gas, common): Promise { + async function (runState, gas, common): Promise { const [currentGasLimit, toAddr, value, inOffset, inLength, outOffset, outLength] = runState.stack.peek(7) - gas.iadd(subMemUsage(runState, inOffset, inLength, common)) - gas.iadd(subMemUsage(runState, outOffset, outLength, common)) + gas += subMemUsage(runState, inOffset, inLength, common) + gas += subMemUsage(runState, outOffset, outLength, common) if (common.isActivatedEIP(2929)) { const toAddress = new Address(addressToBuffer(toAddr)) - gas.iadd(accessAddressEIP2929(runState, toAddress, common)) + gas += accessAddressEIP2929(runState, toAddress, common) } - if (!value.isZero()) { - gas.iadd(new BN(common.param('gasPrices', 'callValueTransfer'))) + if (!(value === 0n)) { + gas += BigInt(common.param('gasPrices', 'callValueTransfer')) } - const gasLimit = maxCallGas( - currentGasLimit.clone(), - runState.eei.getGasLeft().isub(gas), - runState, - common - ) + let gasLimit = maxCallGas(currentGasLimit, runState.eei.getGasLeft() - gas, runState, common) // note that TangerineWhistle or later this cannot happen // (it could have ran out of gas prior to getting here though) - if (gasLimit.gt(runState.eei.getGasLeft().isub(gas))) { + if (gasLimit > runState.eei.getGasLeft() - gas) { trap(ERROR.OUT_OF_GAS) } - if (!value.isZero()) { + if (!(value === 0n)) { // TODO: Don't use private attr directly - runState.eei._gasLeft.iaddn(common.param('gasPrices', 'callStipend')) - gasLimit.iaddn(common.param('gasPrices', 'callStipend')) + runState.eei._gasLeft += BigInt(common.param('gasPrices', 'callStipend')) + gasLimit += BigInt(common.param('gasPrices', 'callStipend')) } runState.messageGasLimit = gasLimit + return gas }, ], [ /* RETURN */ 0xf3, - async function (runState, gas, common): Promise { + async function (runState, gas, common): Promise { const [offset, length] = runState.stack.peek(2) - gas.iadd(subMemUsage(runState, offset, length, common)) + gas += subMemUsage(runState, offset, length, common) + return gas }, ], [ /* DELEGATECALL */ 0xf4, - async function (runState, gas, common): Promise { + async function (runState, gas, common): Promise { const [currentGasLimit, toAddr, inOffset, inLength, outOffset, outLength] = runState.stack.peek(6) - gas.iadd(subMemUsage(runState, inOffset, inLength, common)) - gas.iadd(subMemUsage(runState, outOffset, outLength, common)) + gas += subMemUsage(runState, inOffset, inLength, common) + gas += subMemUsage(runState, outOffset, outLength, common) if (common.isActivatedEIP(2929)) { const toAddress = new Address(addressToBuffer(toAddr)) - gas.iadd(accessAddressEIP2929(runState, toAddress, common)) + gas += accessAddressEIP2929(runState, toAddress, common) } const gasLimit = maxCallGas( - currentGasLimit.clone(), - runState.eei.getGasLeft().isub(gas), + currentGasLimit, + runState.eei.getGasLeft() - gas, runState, common ) // note that TangerineWhistle or later this cannot happen // (it could have ran out of gas prior to getting here though) - if (gasLimit.gt(runState.eei.getGasLeft().isub(gas))) { + if (gasLimit > runState.eei.getGasLeft() - gas) { trap(ERROR.OUT_OF_GAS) } runState.messageGasLimit = gasLimit + return gas }, ], [ /* CREATE2 */ 0xf5, - async function (runState, gas, common): Promise { + async function (runState, gas, common): Promise { if (runState.eei.isStatic()) { trap(ERROR.STATIC_STATE_CHANGE) } const [_value, offset, length, _salt] = runState.stack.peek(4) - gas.iadd(subMemUsage(runState, offset, length, common)) + gas += subMemUsage(runState, offset, length, common) if (common.isActivatedEIP(2929)) { - gas.iadd(accessAddressEIP2929(runState, runState.eei.getAddress(), common, false)) + gas += accessAddressEIP2929(runState, runState.eei.getAddress(), common, false) } - gas.iadd(new BN(common.param('gasPrices', 'sha3Word')).imul(divCeil(length, new BN(32)))) - let gasLimit = new BN(runState.eei.getGasLeft().isub(gas)) - gasLimit = maxCallGas(gasLimit.clone(), gasLimit.clone(), runState, common) // CREATE2 is only available after TangerineWhistle (Constantinople introduced this opcode) + gas += BigInt(common.param('gasPrices', 'sha3Word')) * divCeil(length, 32n) + let gasLimit = BigInt(runState.eei.getGasLeft()) - gas + gasLimit = maxCallGas(gasLimit, gasLimit, runState, common) // CREATE2 is only available after TangerineWhistle (Constantinople introduced this opcode) runState.messageGasLimit = gasLimit + return gas }, ], [ /* STATICCALL */ 0xfa, - async function (runState, gas, common): Promise { + async function (runState, gas, common): Promise { const [currentGasLimit, toAddr, inOffset, inLength, outOffset, outLength] = runState.stack.peek(6) - gas.iadd(subMemUsage(runState, inOffset, inLength, common)) - gas.iadd(subMemUsage(runState, outOffset, outLength, common)) + gas += subMemUsage(runState, inOffset, inLength, common) + gas += subMemUsage(runState, outOffset, outLength, common) if (common.isActivatedEIP(2929)) { const toAddress = new Address(addressToBuffer(toAddr)) - gas.iadd(accessAddressEIP2929(runState, toAddress, common)) + gas += accessAddressEIP2929(runState, toAddress, common) } const gasLimit = maxCallGas( - currentGasLimit.clone(), - runState.eei.getGasLeft().isub(gas), + currentGasLimit, + runState.eei.getGasLeft() - gas, runState, common ) // we set TangerineWhistle or later to true here, as STATICCALL was available from Byzantium (which is after TangerineWhistle) runState.messageGasLimit = gasLimit + return gas }, ], [ /* REVERT */ 0xfd, - async function (runState, gas, common): Promise { + async function (runState, gas, common): Promise { const [offset, length] = runState.stack.peek(2) - gas.iadd(subMemUsage(runState, offset, length, common)) + gas += subMemUsage(runState, offset, length, common) + return gas }, ], [ /* SELFDESTRUCT */ 0xff, - async function (runState, gas, common): Promise { + async function (runState, gas, common): Promise { if (runState.eei.isStatic()) { trap(ERROR.STATIC_STATE_CHANGE) } - const selfdestructToAddressBN = runState.stack.peek()[0] + const selfdestructToaddressBigInt = runState.stack.peek()[0] - const selfdestructToAddress = new Address(addressToBuffer(selfdestructToAddressBN)) + const selfdestructToAddress = new Address(addressToBuffer(selfdestructToaddressBigInt)) let deductGas = false if (common.gteHardfork('spuriousDragon')) { // EIP-161: State Trie Clearing const balance = await runState.eei.getExternalBalance(runState.eei.getAddress()) - if (balance.gtn(0)) { + if (balance > 0n) { // This technically checks if account is empty or non-existent // TODO: improve on the API here (EEI and StateManager) const empty = await runState.eei.isAccountEmpty(selfdestructToAddress) @@ -487,12 +494,13 @@ export const dynamicGasHandlers: Map = new Map< } } if (deductGas) { - gas.iadd(new BN(common.param('gasPrices', 'callNewAccount'))) + gas += BigInt(common.param('gasPrices', 'callNewAccount')) } if (common.isActivatedEIP(2929)) { - gas.iadd(accessAddressEIP2929(runState, selfdestructToAddress, common, true, true)) + gas += accessAddressEIP2929(runState, selfdestructToAddress, common, true, true) } + return gas }, ], ]) diff --git a/packages/vm/src/evm/opcodes/util.ts b/packages/vm/src/evm/opcodes/util.ts index b7d5d61f55..ebaa787725 100644 --- a/packages/vm/src/evm/opcodes/util.ts +++ b/packages/vm/src/evm/opcodes/util.ts @@ -1,9 +1,9 @@ import Common from '@ethereumjs/common' -import { BN, keccak256, setLengthRight, setLengthLeft } from 'ethereumjs-util' +import { keccak256, setLengthRight, setLengthLeft, toBuffer } from 'ethereumjs-util' import { ERROR, VmError } from './../../exceptions' import { RunState } from './../interpreter' -const MASK_160 = new BN(1).shln(160).subn(1) +const MASK_160 = (1n << 160n) - 1n /** * Proxy function for ethereumjs-util's setLengthLeft, except it returns a zero @@ -31,14 +31,14 @@ export function trap(err: string) { } /** - * Converts BN address (they're stored like this on the stack) to buffer address + * Converts bigint address (they're stored like this on the stack) to buffer address * * @param {BN} address * @return {Buffer} */ -export function addressToBuffer(address: BN | Buffer) { +export function addressToBuffer(address: bigint | Buffer) { if (Buffer.isBuffer(address)) return address - return address.and(MASK_160).toArrayLike(Buffer, 'be', 20) + return setLengthLeft(toBuffer('0x' + (address & MASK_160).toString(16)), 20) } /** @@ -57,19 +57,19 @@ export function describeLocation(runState: RunState): string { /** * Find Ceil(a / b) * - * @param {BN} a - * @param {BN} b - * @return {BN} + * @param {bigint} a + * @param {bigint} b + * @return {bigint} */ -export function divCeil(a: BN, b: BN): BN { - const div = a.div(b) - const mod = a.mod(b) +export function divCeil(a: bigint, b: bigint): bigint { + const div = a / b + const modulus = mod(a, b) // Fast case - exact division - if (mod.isZero()) return div + if (modulus === 0n) return div // Round up - return div.isNeg() ? div.isubn(1) : div.iaddn(1) + return div < 0n ? div - 1n : div + 1n } export function short(buffer: Buffer): string { @@ -91,20 +91,20 @@ export function short(buffer: Buffer): string { * @param {Buffer} data * @returns {Buffer} */ -export function getDataSlice(data: Buffer, offset: BN, length: BN): Buffer { - const len = new BN(data.length) - if (offset.gt(len)) { +export function getDataSlice(data: Buffer, offset: bigint, length: bigint): Buffer { + const len = BigInt(data.length) + if (offset > len) { offset = len } - let end = offset.add(length) - if (end.gt(len)) { + let end = offset + length + if (end > len) { end = len } - data = data.slice(offset.toNumber(), end.toNumber()) + data = data.slice(Number(offset), Number(end)) // Right-pad with zeros to fill dataLength bytes - data = setLengthRight(data, length.toNumber()) + data = setLengthRight(data, Number(length)) return data } @@ -165,11 +165,16 @@ export function jumpSubIsValid(runState: RunState, dest: number): boolean { * @param {RunState} runState - the current runState * @param {Common} common - the common */ -export function maxCallGas(gasLimit: BN, gasLeft: BN, runState: RunState, common: Common): BN { +export function maxCallGas( + gasLimit: bigint, + gasLeft: bigint, + runState: RunState, + common: Common +): bigint { const isTangerineWhistleOrLater = common.gteHardfork('tangerineWhistle') if (isTangerineWhistleOrLater) { - const gasAllowed = gasLeft.sub(gasLeft.divn(64)) - return gasLimit.gt(gasAllowed) ? gasAllowed : gasLimit + const gasAllowed = gasLeft - gasLeft / 64n + return gasLimit > gasAllowed ? gasAllowed : gasLimit } else { return gasLimit } @@ -183,23 +188,23 @@ export function maxCallGas(gasLimit: BN, gasLeft: BN, runState: RunState, common * @param {BN} offset * @param {BN} length */ -export function subMemUsage(runState: RunState, offset: BN, length: BN, common: Common) { +export function subMemUsage(runState: RunState, offset: bigint, length: bigint, common: Common) { // YP (225): access with zero length will not extend the memory - if (length.isZero()) return new BN(0) + if (length === 0n) return 0n - const newMemoryWordCount = divCeil(offset.add(length), new BN(32)) - if (newMemoryWordCount.lte(runState.memoryWordCount)) return new BN(0) + const newMemoryWordCount = divCeil(offset + length, 32n) + if (newMemoryWordCount <= runState.memoryWordCount) return 0n const words = newMemoryWordCount - const fee = new BN(common.param('gasPrices', 'memory')) - const quadCoeff = new BN(common.param('gasPrices', 'quadCoeffDiv')) + const fee = BigInt(common.param('gasPrices', 'memory')) + const quadCoeff = BigInt(common.param('gasPrices', 'quadCoeffDiv')) // words * 3 + words ^2 / 512 - const cost = words.mul(fee).add(words.mul(words).div(quadCoeff)) + let cost = words * fee + (words * words) / quadCoeff - if (cost.gt(runState.highestMemCost)) { + if (cost > runState.highestMemCost) { const currentHighestMemCost = runState.highestMemCost - runState.highestMemCost = cost.clone() - cost.isub(currentHighestMemCost) + runState.highestMemCost = cost + cost -= currentHighestMemCost } runState.memoryWordCount = newMemoryWordCount @@ -214,15 +219,15 @@ export function subMemUsage(runState: RunState, offset: BN, length: BN, common: * @param {BN} outOffset * @param {BN} outLength */ -export function writeCallOutput(runState: RunState, outOffset: BN, outLength: BN) { +export function writeCallOutput(runState: RunState, outOffset: bigint, outLength: bigint) { const returnData = runState.eei.getReturnData() if (returnData.length > 0) { - const memOffset = outOffset.toNumber() - let dataLength = outLength.toNumber() - if (returnData.length < dataLength) { + const memOffset = Number(outOffset) + let dataLength = Number(outLength) + if (BigInt(returnData.length) < dataLength) { dataLength = returnData.length } - const data = getDataSlice(returnData, new BN(0), new BN(dataLength)) + const data = getDataSlice(returnData, 0n, BigInt(dataLength)) runState.memory.extend(memOffset, dataLength) runState.memory.write(memOffset, dataLength, data) } @@ -239,16 +244,16 @@ export function updateSstoreGas( currentStorage: Buffer, value: Buffer, common: Common -): BN { +): bigint { if ( (value.length === 0 && currentStorage.length === 0) || (value.length > 0 && currentStorage.length > 0) ) { - const gas = new BN(common.param('gasPrices', 'sstoreReset')) + const gas = BigInt(common.param('gasPrices', 'sstoreReset')) return gas } else if (value.length === 0 && currentStorage.length > 0) { - const gas = new BN(common.param('gasPrices', 'sstoreReset')) - runState.eei.refundGas(new BN(common.param('gasPrices', 'sstoreRefund')), 'updateSstoreGas') + const gas = BigInt(common.param('gasPrices', 'sstoreReset')) + runState.eei.refundGas(BigInt(common.param('gasPrices', 'sstoreRefund')), 'updateSstoreGas') return gas } else { /* @@ -258,6 +263,29 @@ export function updateSstoreGas( -> Value is zero, but slot is nonzero Thus, the remaining case is where value is nonzero, but slot is zero, which is this clause */ - return new BN(common.param('gasPrices', 'sstoreSet')) + return BigInt(common.param('gasPrices', 'sstoreSet')) + } +} + +export function mod(a: bigint, b: bigint) { + let r = a % b + if (r < 0n) { + r = b + r + } + return r +} + +export function fromTwos(a: bigint) { + return BigInt.asUintN(256, ~(a - 1n)) +} + +export function toTwos(a: bigint) { + return BigInt.asUintN(256, ~a) + 1n +} + +export function abs(a: bigint) { + if (a > 0) { + return a } + return a * -1n } diff --git a/packages/vm/src/evm/precompiles/01-ecrecover.ts b/packages/vm/src/evm/precompiles/01-ecrecover.ts index 0557210d45..c792867b57 100644 --- a/packages/vm/src/evm/precompiles/01-ecrecover.ts +++ b/packages/vm/src/evm/precompiles/01-ecrecover.ts @@ -6,9 +6,9 @@ const assert = require('assert') export default function (opts: PrecompileInput): ExecResult { assert(opts.data) - const gasUsed = new BN(opts._common.param('gasPrices', 'ecRecover')) + const gasUsed = BigInt(opts._common.param('gasPrices', 'ecRecover')) - if (opts.gasLimit.lt(gasUsed)) { + if (opts.gasLimit < gasUsed) { return OOGResult(opts.gasLimit) } diff --git a/packages/vm/src/evm/precompiles/02-sha256.ts b/packages/vm/src/evm/precompiles/02-sha256.ts index dd9a049b88..19a724bb2b 100644 --- a/packages/vm/src/evm/precompiles/02-sha256.ts +++ b/packages/vm/src/evm/precompiles/02-sha256.ts @@ -1,4 +1,4 @@ -import { sha256, BN } from 'ethereumjs-util' +import { sha256 } from 'ethereumjs-util' import { PrecompileInput } from './types' import { OOGResult, ExecResult } from '../evm' const assert = require('assert') @@ -8,12 +8,11 @@ export default function (opts: PrecompileInput): ExecResult { const data = opts.data - const gasUsed = new BN(opts._common.param('gasPrices', 'sha256')) - gasUsed.iadd( - new BN(opts._common.param('gasPrices', 'sha256Word')).imuln(Math.ceil(data.length / 32)) - ) + const gasUsed = BigInt(opts._common.param('gasPrices', 'sha256')) + gasUsed + + BigInt(opts._common.param('gasPrices', 'sha256Word')) * BigInt(Math.ceil(data.length / 32)) - if (opts.gasLimit.lt(gasUsed)) { + if (opts.gasLimit < gasUsed) { return OOGResult(opts.gasLimit) } diff --git a/packages/vm/src/evm/precompiles/03-ripemd160.ts b/packages/vm/src/evm/precompiles/03-ripemd160.ts index 7817565f61..c979072e7a 100644 --- a/packages/vm/src/evm/precompiles/03-ripemd160.ts +++ b/packages/vm/src/evm/precompiles/03-ripemd160.ts @@ -1,4 +1,4 @@ -import { ripemd160, BN } from 'ethereumjs-util' +import { ripemd160 } from 'ethereumjs-util' import { PrecompileInput } from './types' import { OOGResult, ExecResult } from '../evm' const assert = require('assert') @@ -8,12 +8,11 @@ export default function (opts: PrecompileInput): ExecResult { const data = opts.data - const gasUsed = new BN(opts._common.param('gasPrices', 'ripemd160')) - gasUsed.iadd( - new BN(opts._common.param('gasPrices', 'ripemd160Word')).imuln(Math.ceil(data.length / 32)) - ) + let gasUsed = BigInt(opts._common.param('gasPrices', 'ripemd160')) + gasUsed += + BigInt(opts._common.param('gasPrices', 'ripemd160Word')) * BigInt(Math.ceil(data.length / 32)) - if (opts.gasLimit.lt(gasUsed)) { + if (opts.gasLimit < gasUsed) { return OOGResult(opts.gasLimit) } diff --git a/packages/vm/src/evm/precompiles/04-identity.ts b/packages/vm/src/evm/precompiles/04-identity.ts index c9349d9e88..7890e3efca 100644 --- a/packages/vm/src/evm/precompiles/04-identity.ts +++ b/packages/vm/src/evm/precompiles/04-identity.ts @@ -1,4 +1,3 @@ -import { BN } from 'ethereumjs-util' import { PrecompileInput } from './types' import { OOGResult, ExecResult } from '../evm' const assert = require('assert') @@ -8,12 +7,11 @@ export default function (opts: PrecompileInput): ExecResult { const data = opts.data - const gasUsed = new BN(opts._common.param('gasPrices', 'identity')) - gasUsed.iadd( - new BN(opts._common.param('gasPrices', 'identityWord')).imuln(Math.ceil(data.length / 32)) - ) + let gasUsed = BigInt(opts._common.param('gasPrices', 'identity')) + gasUsed += + BigInt(opts._common.param('gasPrices', 'identityWord')) * BigInt(Math.ceil(data.length / 32)) - if (opts.gasLimit.lt(gasUsed)) { + if (opts.gasLimit < gasUsed) { return OOGResult(opts.gasLimit) } diff --git a/packages/vm/src/evm/precompiles/05-modexp.ts b/packages/vm/src/evm/precompiles/05-modexp.ts index ded027cb85..fa2be68c81 100644 --- a/packages/vm/src/evm/precompiles/05-modexp.ts +++ b/packages/vm/src/evm/precompiles/05-modexp.ts @@ -1,74 +1,74 @@ -import { setLengthRight, BN } from 'ethereumjs-util' +import { setLengthRight, bufferToHex, toBuffer, setLengthLeft } from 'ethereumjs-util' import { PrecompileInput } from './types' import { OOGResult, ExecResult } from '../evm' const assert = require('assert') -function multComplexity(x: BN): BN { +function multComplexity(x: bigint): bigint { let fac1 let fac2 - if (x.lten(64)) { - return x.sqr() - } else if (x.lten(1024)) { + if (x <= 64n) { + return x ** 2n + } else if (x <= 1024n) { // return Math.floor(Math.pow(x, 2) / 4) + 96 * x - 3072 - fac1 = x.sqr().divn(4) - fac2 = x.muln(96) - return fac1.add(fac2).subn(3072) + fac1 = x ** 2n / 4n + fac2 = x * 96n + return fac1 + fac2 - 3072n } else { // return Math.floor(Math.pow(x, 2) / 16) + 480 * x - 199680 - fac1 = x.sqr().divn(16) - fac2 = x.muln(480) - return fac1.add(fac2).subn(199680) + fac1 = x ** 2n / 16n + fac2 = x * 480n + return fac1 + fac2 - 199680n } } -function multComplexityEIP2565(x: BN): BN { - const words = x.addn(7).divn(8) - return words.mul(words) +function multComplexityEIP2565(x: bigint): bigint { + const words = (x + 7n) / 8n + return words * words } -function getAdjustedExponentLength(data: Buffer): BN { +function getAdjustedExponentLength(data: Buffer): bigint { let expBytesStart try { - const baseLen = new BN(data.slice(0, 32)).toNumber() - expBytesStart = 96 + baseLen // 96 for base length, then exponent length, and modulus length, then baseLen for the base data, then exponent bytes start + const baseLen = BigInt(bufferToHex(data.slice(0, 32))) + expBytesStart = 96 + Number(baseLen) // 96 for base length, then exponent length, and modulus length, then baseLen for the base data, then exponent bytes start } catch (e: any) { expBytesStart = Number.MAX_SAFE_INTEGER - 32 } - const expLen = new BN(data.slice(32, 64)) + const expLen = BigInt(bufferToHex(data.slice(32, 64))) let firstExpBytes = Buffer.from(data.slice(expBytesStart, expBytesStart + 32)) // first word of the exponent data firstExpBytes = setLengthRight(firstExpBytes, 32) // reading past the data reads virtual zeros - let firstExpBN = new BN(firstExpBytes) + let firstExpBigInt = BigInt(bufferToHex(firstExpBytes)) let max32expLen = 0 - if (expLen.ltn(32)) { - max32expLen = 32 - expLen.toNumber() + if (expLen < 32n) { + max32expLen = 32 - Number(expLen) } - firstExpBN = firstExpBN.shrn(8 * Math.max(max32expLen, 0)) + firstExpBigInt = firstExpBigInt >> (8n * BigInt(Math.max(max32expLen, 0))) let bitLen = -1 - while (firstExpBN.gtn(0)) { + while (firstExpBigInt > 0n) { bitLen = bitLen + 1 - firstExpBN = firstExpBN.ushrn(1) + firstExpBigInt = firstExpBigInt >> 1n } - let expLenMinus32OrZero = expLen.subn(32) - if (expLenMinus32OrZero.ltn(0)) { - expLenMinus32OrZero = new BN(0) + let expLenMinus32OrZero = expLen - 32n + if (expLenMinus32OrZero < 0n) { + expLenMinus32OrZero = 0n } - const eightTimesExpLenMinus32OrZero = expLenMinus32OrZero.muln(8) - const adjustedExpLen = eightTimesExpLenMinus32OrZero + const eightTimesExpLenMinus32OrZero = expLenMinus32OrZero * 8n + let adjustedExpLen = eightTimesExpLenMinus32OrZero if (bitLen > 0) { - adjustedExpLen.iaddn(bitLen) + adjustedExpLen += BigInt(bitLen) } return adjustedExpLen } -function expmod(B: BN, E: BN, M: BN): BN { - if (E.isZero()) return new BN(1).mod(M) - // Red asserts M > 1 - if (M.lten(1)) return new BN(0) - const red = BN.red(M) - const redB = B.toRed(red) - const res = redB.redPow(E) - return res.fromRed() +export function expmod(a: bigint, power: bigint, modulo: bigint) { + let res = 1n + while (power > 0n) { + if (power & 1n) res = (res * a) % modulo + a = (a * a) % modulo + power >>= 1n + } + return res } export default function (opts: PrecompileInput): ExecResult { @@ -77,79 +77,85 @@ export default function (opts: PrecompileInput): ExecResult { const data = opts.data let adjustedELen = getAdjustedExponentLength(data) - if (adjustedELen.ltn(1)) { - adjustedELen = new BN(1) + if (adjustedELen < 1n) { + adjustedELen = 1n } - const bLen = new BN(data.slice(0, 32)) - const eLen = new BN(data.slice(32, 64)) - const mLen = new BN(data.slice(64, 96)) + const bLen = BigInt(bufferToHex(data.slice(0, 32))) + const eLen = BigInt(bufferToHex(data.slice(32, 64))) + const mLen = BigInt(bufferToHex(data.slice(64, 96))) let maxLen = bLen - if (maxLen.lt(mLen)) { + if (maxLen < mLen) { maxLen = mLen } - const Gquaddivisor = opts._common.param('gasPrices', 'modexpGquaddivisor') + const Gquaddivisor = BigInt(opts._common.param('gasPrices', 'modexpGquaddivisor')) let gasUsed - const bStart = new BN(96) - const bEnd = bStart.add(bLen) + const bStart = 96n + const bEnd = bStart + bLen const eStart = bEnd - const eEnd = eStart.add(eLen) + const eEnd = eStart + eLen const mStart = eEnd - const mEnd = mStart.add(mLen) + const mEnd = mStart + mLen if (!opts._common.isActivatedEIP(2565)) { - gasUsed = adjustedELen.mul(multComplexity(maxLen)).divn(Gquaddivisor) + gasUsed = (adjustedELen * multComplexity(maxLen)) / Gquaddivisor } else { - gasUsed = adjustedELen.mul(multComplexityEIP2565(maxLen)).divn(Gquaddivisor) - if (gasUsed.ltn(200)) { - gasUsed = new BN(200) + gasUsed = (adjustedELen * multComplexityEIP2565(maxLen)) / Gquaddivisor + if (gasUsed < 200n) { + gasUsed = 200n } } - if (opts.gasLimit.lt(gasUsed)) { + if (opts.gasLimit < gasUsed) { return OOGResult(opts.gasLimit) } - if (bLen.isZero()) { + if (bLen === 0n) { return { gasUsed, - returnValue: new BN(0).toArrayLike(Buffer, 'be', mLen.toNumber()), + returnValue: setLengthLeft(toBuffer('0x' + 0n.toString(16)), Number(mLen)), } } - if (mLen.isZero()) { + if (mLen === 0n) { return { gasUsed, returnValue: Buffer.alloc(0), } } - const maxInt = new BN(Number.MAX_SAFE_INTEGER) - const maxSize = new BN(2147483647) // ethereumjs-util setLengthRight limitation + const maxInt = BigInt(Number.MAX_SAFE_INTEGER) + const maxSize = 2147483647n // ethereumjs-util setLengthRight limitation - if (bLen.gt(maxSize) || eLen.gt(maxSize) || mLen.gt(maxSize)) { + if (bLen > maxSize || eLen > maxSize || mLen > maxSize) { return OOGResult(opts.gasLimit) } - const B = new BN(setLengthRight(data.slice(bStart.toNumber(), bEnd.toNumber()), bLen.toNumber())) - const E = new BN(setLengthRight(data.slice(eStart.toNumber(), eEnd.toNumber()), eLen.toNumber())) - const M = new BN(setLengthRight(data.slice(mStart.toNumber(), mEnd.toNumber()), mLen.toNumber())) + const B = BigInt( + bufferToHex(setLengthRight(data.slice(Number(bStart), Number(bEnd)), Number(bLen))) + ) + const E = BigInt( + bufferToHex(setLengthRight(data.slice(Number(eStart), Number(eEnd)), Number(eLen))) + ) + const M = BigInt( + bufferToHex(setLengthRight(data.slice(Number(mStart), Number(mEnd)), Number(mLen))) + ) - if (mEnd.gt(maxInt)) { + if (mEnd > maxInt) { return OOGResult(opts.gasLimit) } let R - if (M.isZero()) { - R = new BN(0) + if (M === 0n) { + R = 0n } else { R = expmod(B, E, M) } return { gasUsed, - returnValue: R.toArrayLike(Buffer, 'be', mLen.toNumber()), + returnValue: setLengthLeft(toBuffer('0x' + R.toString(16)), Number(mLen)), } } diff --git a/packages/vm/src/evm/precompiles/06-ecadd.ts b/packages/vm/src/evm/precompiles/06-ecadd.ts index e35aee99ad..f1046ca590 100644 --- a/packages/vm/src/evm/precompiles/06-ecadd.ts +++ b/packages/vm/src/evm/precompiles/06-ecadd.ts @@ -1,4 +1,3 @@ -import { BN } from 'ethereumjs-util' import { PrecompileInput } from './types' import { OOGResult, ExecResult } from '../evm' const assert = require('assert') @@ -9,8 +8,8 @@ export default function (opts: PrecompileInput): ExecResult { const inputData = opts.data - const gasUsed = new BN(opts._common.param('gasPrices', 'ecAdd')) - if (opts.gasLimit.lt(gasUsed)) { + const gasUsed = BigInt(opts._common.param('gasPrices', 'ecAdd')) + if (opts.gasLimit < gasUsed) { return OOGResult(opts.gasLimit) } diff --git a/packages/vm/src/evm/precompiles/07-ecmul.ts b/packages/vm/src/evm/precompiles/07-ecmul.ts index 75cd7dbc97..e436315c63 100644 --- a/packages/vm/src/evm/precompiles/07-ecmul.ts +++ b/packages/vm/src/evm/precompiles/07-ecmul.ts @@ -1,4 +1,3 @@ -import { BN } from 'ethereumjs-util' import { PrecompileInput } from './types' import { OOGResult, ExecResult } from '../evm' const assert = require('assert') @@ -8,9 +7,9 @@ export default function (opts: PrecompileInput): ExecResult { assert(opts.data) const inputData = opts.data - const gasUsed = new BN(opts._common.param('gasPrices', 'ecMul')) + const gasUsed = BigInt(opts._common.param('gasPrices', 'ecMul')) - if (opts.gasLimit.lt(gasUsed)) { + if (opts.gasLimit < gasUsed) { return OOGResult(opts.gasLimit) } diff --git a/packages/vm/src/evm/precompiles/08-ecpairing.ts b/packages/vm/src/evm/precompiles/08-ecpairing.ts index 57d0a641b7..f799f67847 100644 --- a/packages/vm/src/evm/precompiles/08-ecpairing.ts +++ b/packages/vm/src/evm/precompiles/08-ecpairing.ts @@ -1,4 +1,3 @@ -import { BN } from 'ethereumjs-util' import { PrecompileInput } from './types' import { OOGResult, ExecResult } from '../evm' const assert = require('assert') @@ -10,12 +9,12 @@ export default function (opts: PrecompileInput): ExecResult { const inputData = opts.data // no need to care about non-divisible-by-192, because bn128.pairing will properly fail in that case const inputDataSize = Math.floor(inputData.length / 192) - const gasUsed = new BN( + const gasUsed = BigInt( opts._common.param('gasPrices', 'ecPairing') + inputDataSize * opts._common.param('gasPrices', 'ecPairingWord') ) - if (opts.gasLimit.lt(gasUsed)) { + if (opts.gasLimit < gasUsed) { return OOGResult(opts.gasLimit) } diff --git a/packages/vm/src/evm/precompiles/09-blake2f.ts b/packages/vm/src/evm/precompiles/09-blake2f.ts index 075fd61670..3b044b6f5b 100644 --- a/packages/vm/src/evm/precompiles/09-blake2f.ts +++ b/packages/vm/src/evm/precompiles/09-blake2f.ts @@ -1,4 +1,3 @@ -import { BN } from 'ethereumjs-util' import { PrecompileInput } from './types' import { OOGResult, ExecResult } from '../evm' import { VmError, ERROR } from '../../exceptions' @@ -182,9 +181,9 @@ export default function (opts: PrecompileInput): ExecResult { // final const f = lastByte === 1 - const gasUsed = new BN(opts._common.param('gasPrices', 'blake2Round')) - gasUsed.imul(new BN(rounds)) - if (opts.gasLimit.lt(gasUsed)) { + let gasUsed = BigInt(opts._common.param('gasPrices', 'blake2Round')) + gasUsed *= BigInt(rounds) + if (opts.gasLimit < gasUsed) { return OOGResult(opts.gasLimit) } diff --git a/packages/vm/src/evm/precompiles/0a-bls12-g1add.ts b/packages/vm/src/evm/precompiles/0a-bls12-g1add.ts index bcc9a07b24..c50230108b 100644 --- a/packages/vm/src/evm/precompiles/0a-bls12-g1add.ts +++ b/packages/vm/src/evm/precompiles/0a-bls12-g1add.ts @@ -1,4 +1,3 @@ -import { BN } from 'ethereumjs-util' import { PrecompileInput } from './types' import { VmErrorResult, ExecResult, OOGResult } from '../evm' import { ERROR, VmError } from '../../exceptions' @@ -13,9 +12,9 @@ export default async function (opts: PrecompileInput): Promise { const inputData = opts.data // note: the gas used is constant; even if the input is incorrect. - const gasUsed = new BN(opts._common.paramByEIP('gasPrices', 'Bls12381G1AddGas', 2537)) + const gasUsed = BigInt(opts._common.paramByEIP('gasPrices', 'Bls12381G1AddGas', 2537)) - if (opts.gasLimit.lt(gasUsed)) { + if (opts.gasLimit < gasUsed) { return OOGResult(opts.gasLimit) } diff --git a/packages/vm/src/evm/precompiles/0b-bls12-g1mul.ts b/packages/vm/src/evm/precompiles/0b-bls12-g1mul.ts index bdd9ab8e89..7e2c445a08 100644 --- a/packages/vm/src/evm/precompiles/0b-bls12-g1mul.ts +++ b/packages/vm/src/evm/precompiles/0b-bls12-g1mul.ts @@ -1,4 +1,3 @@ -import { BN } from 'ethereumjs-util' import { PrecompileInput } from './types' import { VmErrorResult, ExecResult, OOGResult } from '../evm' import { ERROR, VmError } from '../../exceptions' @@ -17,9 +16,9 @@ export default async function (opts: PrecompileInput): Promise { const inputData = opts.data // note: the gas used is constant; even if the input is incorrect. - const gasUsed = new BN(opts._common.paramByEIP('gasPrices', 'Bls12381G1MulGas', 2537)) + const gasUsed = BigInt(opts._common.paramByEIP('gasPrices', 'Bls12381G1MulGas', 2537)) - if (opts.gasLimit.lt(gasUsed)) { + if (opts.gasLimit < gasUsed) { return OOGResult(opts.gasLimit) } diff --git a/packages/vm/src/evm/precompiles/0c-bls12-g1multiexp.ts b/packages/vm/src/evm/precompiles/0c-bls12-g1multiexp.ts index ebb939798d..d75f1fef87 100644 --- a/packages/vm/src/evm/precompiles/0c-bls12-g1multiexp.ts +++ b/packages/vm/src/evm/precompiles/0c-bls12-g1multiexp.ts @@ -1,4 +1,3 @@ -import { BN } from 'ethereumjs-util' import { PrecompileInput } from './types' import { VmErrorResult, ExecResult, OOGResult } from '../evm' import { ERROR, VmError } from '../../exceptions' @@ -22,7 +21,7 @@ export default async function (opts: PrecompileInput): Promise { const numPairs = Math.floor(inputData.length / 160) - const gasUsedPerPair = new BN(opts._common.paramByEIP('gasPrices', 'Bls12381G1MulGas', 2537)) + const gasUsedPerPair = BigInt(opts._common.paramByEIP('gasPrices', 'Bls12381G1MulGas', 2537)) const gasDiscountArray = opts._common.paramByEIP('gasPrices', 'Bls12381MultiExpGasDiscount', 2537) const gasDiscountMax = gasDiscountArray[gasDiscountArray.length - 1][1] let gasDiscountMultiplier @@ -37,9 +36,9 @@ export default async function (opts: PrecompileInput): Promise { gasDiscountMultiplier = gasDiscountMax } - const gasUsed = gasUsedPerPair.imuln(numPairs).imuln(gasDiscountMultiplier).idivn(1000) + const gasUsed = (gasUsedPerPair * BigInt(numPairs) * BigInt(gasDiscountMultiplier)) / 1000n - if (opts.gasLimit.lt(gasUsed)) { + if (opts.gasLimit < gasUsed) { return OOGResult(opts.gasLimit) } diff --git a/packages/vm/src/evm/precompiles/0d-bls12-g2add.ts b/packages/vm/src/evm/precompiles/0d-bls12-g2add.ts index bea69fb3d8..3bd46c77e8 100644 --- a/packages/vm/src/evm/precompiles/0d-bls12-g2add.ts +++ b/packages/vm/src/evm/precompiles/0d-bls12-g2add.ts @@ -1,4 +1,3 @@ -import { BN } from 'ethereumjs-util' import { PrecompileInput } from './types' import { VmErrorResult, ExecResult, OOGResult } from '../evm' import { ERROR, VmError } from '../../exceptions' @@ -13,9 +12,9 @@ export default async function (opts: PrecompileInput): Promise { const inputData = opts.data // note: the gas used is constant; even if the input is incorrect. - const gasUsed = new BN(opts._common.paramByEIP('gasPrices', 'Bls12381G2AddGas', 2537)) + const gasUsed = BigInt(opts._common.paramByEIP('gasPrices', 'Bls12381G2AddGas', 2537)) - if (opts.gasLimit.lt(gasUsed)) { + if (opts.gasLimit < gasUsed) { return OOGResult(opts.gasLimit) } diff --git a/packages/vm/src/evm/precompiles/0e-bls12-g2mul.ts b/packages/vm/src/evm/precompiles/0e-bls12-g2mul.ts index 5d100d6aee..0eb10e0ad5 100644 --- a/packages/vm/src/evm/precompiles/0e-bls12-g2mul.ts +++ b/packages/vm/src/evm/precompiles/0e-bls12-g2mul.ts @@ -1,4 +1,3 @@ -import { BN } from 'ethereumjs-util' import { PrecompileInput } from './types' import { VmErrorResult, ExecResult, OOGResult } from '../evm' import { ERROR, VmError } from '../../exceptions' @@ -17,9 +16,9 @@ export default async function (opts: PrecompileInput): Promise { const inputData = opts.data // note: the gas used is constant; even if the input is incorrect. - const gasUsed = new BN(opts._common.paramByEIP('gasPrices', 'Bls12381G2MulGas', 2537)) + const gasUsed = BigInt(opts._common.paramByEIP('gasPrices', 'Bls12381G2MulGas', 2537)) - if (opts.gasLimit.lt(gasUsed)) { + if (opts.gasLimit < gasUsed) { return OOGResult(opts.gasLimit) } diff --git a/packages/vm/src/evm/precompiles/0f-bls12-g2multiexp.ts b/packages/vm/src/evm/precompiles/0f-bls12-g2multiexp.ts index 7454a59c7f..a50578327f 100644 --- a/packages/vm/src/evm/precompiles/0f-bls12-g2multiexp.ts +++ b/packages/vm/src/evm/precompiles/0f-bls12-g2multiexp.ts @@ -1,4 +1,3 @@ -import { BN } from 'ethereumjs-util' import { PrecompileInput } from './types' import { VmErrorResult, ExecResult, OOGResult } from '../evm' import { ERROR, VmError } from '../../exceptions' @@ -22,7 +21,7 @@ export default async function (opts: PrecompileInput): Promise { const numPairs = Math.floor(inputData.length / 288) - const gasUsedPerPair = new BN(opts._common.paramByEIP('gasPrices', 'Bls12381G2MulGas', 2537)) + const gasUsedPerPair = BigInt(opts._common.paramByEIP('gasPrices', 'Bls12381G2MulGas', 2537)) const gasDiscountArray = opts._common.paramByEIP('gasPrices', 'Bls12381MultiExpGasDiscount', 2537) const gasDiscountMax = gasDiscountArray[gasDiscountArray.length - 1][1] let gasDiscountMultiplier @@ -37,9 +36,9 @@ export default async function (opts: PrecompileInput): Promise { gasDiscountMultiplier = gasDiscountMax } - const gasUsed = gasUsedPerPair.imuln(numPairs).imuln(gasDiscountMultiplier).idivn(1000) + const gasUsed = (gasUsedPerPair * BigInt(numPairs) * BigInt(gasDiscountMultiplier)) / 1000n - if (opts.gasLimit.lt(gasUsed)) { + if (opts.gasLimit < gasUsed) { return OOGResult(opts.gasLimit) } diff --git a/packages/vm/src/evm/precompiles/10-bls12-pairing.ts b/packages/vm/src/evm/precompiles/10-bls12-pairing.ts index 066c3d5972..0a516dca38 100644 --- a/packages/vm/src/evm/precompiles/10-bls12-pairing.ts +++ b/packages/vm/src/evm/precompiles/10-bls12-pairing.ts @@ -1,4 +1,3 @@ -import { BN } from 'ethereumjs-util' import { PrecompileInput } from './types' import { VmErrorResult, ExecResult, OOGResult } from '../evm' import { ERROR, VmError } from '../../exceptions' @@ -15,22 +14,22 @@ export default async function (opts: PrecompileInput): Promise { const inputData = opts.data - const baseGas = new BN(opts._common.paramByEIP('gasPrices', 'Bls12381PairingBaseGas', 2537)) + const baseGas = BigInt(opts._common.paramByEIP('gasPrices', 'Bls12381PairingBaseGas', 2537)) if (inputData.length == 0) { return VmErrorResult(new VmError(ERROR.BLS_12_381_INPUT_EMPTY), opts.gasLimit) } - const gasUsedPerPair = new BN( + const gasUsedPerPair = BigInt( opts._common.paramByEIP('gasPrices', 'Bls12381PairingPerPairGas', 2537) ) - const gasUsed = baseGas.iadd(gasUsedPerPair.imul(new BN(Math.floor(inputData.length / 384)))) + const gasUsed = baseGas + gasUsedPerPair * BigInt(Math.floor(inputData.length / 384)) if (inputData.length % 384 != 0) { return VmErrorResult(new VmError(ERROR.BLS_12_381_INVALID_INPUT_LENGTH), opts.gasLimit) } - if (opts.gasLimit.lt(gasUsed)) { + if (opts.gasLimit < gasUsed) { return OOGResult(opts.gasLimit) } diff --git a/packages/vm/src/evm/precompiles/11-bls12-map-fp-to-g1.ts b/packages/vm/src/evm/precompiles/11-bls12-map-fp-to-g1.ts index 6debbb56a3..ab30545c85 100644 --- a/packages/vm/src/evm/precompiles/11-bls12-map-fp-to-g1.ts +++ b/packages/vm/src/evm/precompiles/11-bls12-map-fp-to-g1.ts @@ -1,4 +1,3 @@ -import { BN } from 'ethereumjs-util' import { PrecompileInput } from './types' import { VmErrorResult, ExecResult, OOGResult } from '../evm' import { ERROR, VmError } from '../../exceptions' @@ -13,9 +12,9 @@ export default async function (opts: PrecompileInput): Promise { const inputData = opts.data // note: the gas used is constant; even if the input is incorrect. - const gasUsed = new BN(opts._common.paramByEIP('gasPrices', 'Bls12381MapG1Gas', 2537)) + const gasUsed = BigInt(opts._common.paramByEIP('gasPrices', 'Bls12381MapG1Gas', 2537)) - if (opts.gasLimit.lt(gasUsed)) { + if (opts.gasLimit < gasUsed) { return OOGResult(opts.gasLimit) } diff --git a/packages/vm/src/evm/precompiles/12-bls12-map-fp2-to-g2.ts b/packages/vm/src/evm/precompiles/12-bls12-map-fp2-to-g2.ts index ec9ebd1ae5..01748b6ae8 100644 --- a/packages/vm/src/evm/precompiles/12-bls12-map-fp2-to-g2.ts +++ b/packages/vm/src/evm/precompiles/12-bls12-map-fp2-to-g2.ts @@ -1,4 +1,3 @@ -import { BN } from 'ethereumjs-util' import { PrecompileInput } from './types' import { VmErrorResult, ExecResult, OOGResult } from '../evm' import { ERROR, VmError } from '../../exceptions' @@ -13,9 +12,9 @@ export default async function (opts: PrecompileInput): Promise { const inputData = opts.data // note: the gas used is constant; even if the input is incorrect. - const gasUsed = new BN(opts._common.paramByEIP('gasPrices', 'Bls12381MapG2Gas', 2537)) + const gasUsed = BigInt(opts._common.paramByEIP('gasPrices', 'Bls12381MapG2Gas', 2537)) - if (opts.gasLimit.lt(gasUsed)) { + if (opts.gasLimit < gasUsed) { return OOGResult(opts.gasLimit) } diff --git a/packages/vm/src/evm/precompiles/types.ts b/packages/vm/src/evm/precompiles/types.ts index 6dba2c0465..4db53fce21 100644 --- a/packages/vm/src/evm/precompiles/types.ts +++ b/packages/vm/src/evm/precompiles/types.ts @@ -1,4 +1,3 @@ -import { BN } from 'ethereumjs-util' import Common from '@ethereumjs/common' import { ExecResult } from '../evm' import VM from '../../index' @@ -9,7 +8,7 @@ export interface PrecompileFunc { export interface PrecompileInput { data: Buffer - gasLimit: BN + gasLimit: bigint _common: Common _VM: VM } diff --git a/packages/vm/src/evm/precompiles/util/bls12_381.ts b/packages/vm/src/evm/precompiles/util/bls12_381.ts index 9824a70f01..944e463a07 100644 --- a/packages/vm/src/evm/precompiles/util/bls12_381.ts +++ b/packages/vm/src/evm/precompiles/util/bls12_381.ts @@ -1,10 +1,9 @@ -import { padToEven, BN } from 'ethereumjs-util' +import { bufferToHex, padToEven } from 'ethereumjs-util' import { VmError, ERROR } from '../../../exceptions' // base field modulus as described in the EIP -const fieldModulus = new BN( - '1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab', - 16 +const fieldModulus = BigInt( + '0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab' ) // convert an input Buffer to a mcl G1 point @@ -159,7 +158,7 @@ function BLS12_381_ToFrPoint(input: Buffer, mcl: any): any { function BLS12_381_ToFpPoint(fpCoordinate: Buffer, mcl: any): any { // check if point is in field - if (new BN(fpCoordinate).gte(fieldModulus)) { + if (BigInt(bufferToHex(fpCoordinate)) >= fieldModulus) { throw new VmError(ERROR.BLS_12_381_FP_NOT_IN_FIELD) } @@ -175,10 +174,10 @@ function BLS12_381_ToFpPoint(fpCoordinate: Buffer, mcl: any): any { function BLS12_381_ToFp2Point(fpXCoordinate: Buffer, fpYCoordinate: Buffer, mcl: any): any { // check if the coordinates are in the field - if (new BN(fpXCoordinate).gte(fieldModulus)) { + if (BigInt(bufferToHex(fpXCoordinate)) >= fieldModulus) { throw new VmError(ERROR.BLS_12_381_FP_NOT_IN_FIELD) } - if (new BN(fpYCoordinate).gte(fieldModulus)) { + if (BigInt(bufferToHex(fpYCoordinate)) >= fieldModulus) { throw new VmError(ERROR.BLS_12_381_FP_NOT_IN_FIELD) } diff --git a/packages/vm/src/evm/stack.ts b/packages/vm/src/evm/stack.ts index 6b3613a12b..75cfbed041 100644 --- a/packages/vm/src/evm/stack.ts +++ b/packages/vm/src/evm/stack.ts @@ -1,11 +1,11 @@ -import { BN, MAX_INTEGER } from 'ethereumjs-util' +import { MAX_INTEGER_BIGINT } from 'ethereumjs-util' import { ERROR, VmError } from '../exceptions' /** * Implementation of the stack used in evm. */ export default class Stack { - _store: BN[] + _store: bigint[] _maxHeight: number constructor(maxHeight?: number) { @@ -17,12 +17,12 @@ export default class Stack { return this._store.length } - push(value: BN) { - if (!BN.isBN(value)) { + push(value: bigint) { + if (typeof value !== 'bigint') { throw new VmError(ERROR.INTERNAL_ERROR) } - if (value.gt(MAX_INTEGER)) { + if (value > MAX_INTEGER_BIGINT) { throw new VmError(ERROR.OUT_OF_RANGE) } @@ -33,7 +33,7 @@ export default class Stack { this._store.push(value) } - pop(): BN { + pop(): bigint { if (this._store.length < 1) { throw new VmError(ERROR.STACK_UNDERFLOW) } @@ -47,7 +47,7 @@ export default class Stack { * in returned array. * @param num - Number of items to pop */ - popN(num: number = 1): BN[] { + popN(num: number = 1): bigint[] { if (this._store.length < num) { throw new VmError(ERROR.STACK_UNDERFLOW) } @@ -64,8 +64,8 @@ export default class Stack { * @param num Number of items to return * @throws {@link ERROR.STACK_UNDERFLOW} */ - peek(num: number = 1): BN[] { - const peekArray: BN[] = [] + peek(num: number = 1): bigint[] { + const peekArray: bigint[] = [] for (let peek = 1; peek <= num; peek++) { const index = this._store.length - peek @@ -98,12 +98,16 @@ export default class Stack { * Pushes a copy of an item in the stack. * @param position - Index of item to be copied (1-indexed) */ + // I would say that we do not need this method any more + // since you can't copy a primitive data type + // Nevertheless not sure if we "loose" something here? + // Will keep commented out for now dup(position: number) { if (this._store.length < position) { throw new VmError(ERROR.STACK_UNDERFLOW) } const i = this._store.length - position - this.push(this._store[i].clone()) + this.push(this._store[i]) } } diff --git a/packages/vm/src/evm/txContext.ts b/packages/vm/src/evm/txContext.ts index 3d9b8aecee..ce48c16771 100644 --- a/packages/vm/src/evm/txContext.ts +++ b/packages/vm/src/evm/txContext.ts @@ -1,10 +1,10 @@ -import { Address, BN } from 'ethereumjs-util' +import { Address } from 'ethereumjs-util' export default class TxContext { - gasPrice: BN + gasPrice: bigint origin: Address - constructor(gasPrice: BN, origin: Address) { + constructor(gasPrice: bigint, origin: Address) { this.gasPrice = gasPrice this.origin = origin } diff --git a/packages/vm/src/runBlock.ts b/packages/vm/src/runBlock.ts index 10e2c71613..759c403805 100644 --- a/packages/vm/src/runBlock.ts +++ b/packages/vm/src/runBlock.ts @@ -79,7 +79,7 @@ export interface RunBlockResult { /** * The gas used after executing the block */ - gasUsed: BN + gasUsed: bigint /** * The bloom filter of the LOGs (events) after executing the block */ @@ -183,7 +183,7 @@ export default async function runBlock(this: VM, opts: RunBlockOpts): Promise ${gasUsed})`) } @@ -382,11 +382,15 @@ async function assignBlockRewards(this: VM, block: Block): Promise { debug(`Assign block rewards`) } const state = this.stateManager - const minerReward = new BN(this._common.param('pow', 'minerReward')) + const minerReward = BigInt(this._common.param('pow', 'minerReward')) const ommers = block.uncleHeaders // Reward ommers for (const ommer of ommers) { - const reward = calculateOmmerReward(ommer.number, block.header.number, minerReward) + const reward = calculateOmmerReward( + BigInt(ommer.number.toString(10)), + BigInt(block.header.number.toString(10)), + minerReward + ) const account = await rewardAccount(state, ommer.coinbase, reward) if (this.DEBUG) { debug(`Add uncle reward ${reward} to account ${ommer.coinbase} (-> ${account.balance})`) @@ -400,30 +404,34 @@ async function assignBlockRewards(this: VM, block: Block): Promise { } } -function calculateOmmerReward(ommerBlockNumber: BN, blockNumber: BN, minerReward: BN): BN { - const heightDiff = blockNumber.sub(ommerBlockNumber) - let reward = new BN(8).sub(heightDiff).mul(minerReward.divn(8)) - if (reward.ltn(0)) { - reward = new BN(0) +function calculateOmmerReward( + ommerBlockNumber: bigint, + blockNumber: bigint, + minerReward: bigint +): bigint { + const heightDiff = blockNumber - ommerBlockNumber + let reward = ((8n - heightDiff) * minerReward) / 8n + if (reward < 0n) { + reward = 0n } return reward } -export function calculateMinerReward(minerReward: BN, ommersNum: number): BN { +export function calculateMinerReward(minerReward: bigint, ommersNum: number): bigint { // calculate nibling reward - const niblingReward = minerReward.divn(32) - const totalNiblingReward = niblingReward.muln(ommersNum) - const reward = minerReward.add(totalNiblingReward) + const niblingReward = minerReward / 32n + const totalNiblingReward = niblingReward * BigInt(ommersNum) + const reward = minerReward + totalNiblingReward return reward } export async function rewardAccount( state: StateManager, address: Address, - reward: BN + reward: bigint ): Promise { const account = await state.getAccount(address) - account.balance.iadd(reward) + account.balance.iadd(new BN(reward.toString(10), 10)) await state.putAccount(address, account) return account } diff --git a/packages/vm/src/runCall.ts b/packages/vm/src/runCall.ts index 02db22f517..b1ed388dea 100644 --- a/packages/vm/src/runCall.ts +++ b/packages/vm/src/runCall.ts @@ -10,12 +10,12 @@ import { default as EVM, EVMResult } from './evm/evm' */ export interface RunCallOpts { block?: Block - gasPrice?: BN + gasPrice?: bigint origin?: Address caller?: Address - gasLimit?: BN + gasLimit?: bigint to?: Address - value?: BN + value?: bigint data?: Buffer /** * This is for CALLCODE where the code to load is different than the code from the `opts.to` address. @@ -35,10 +35,7 @@ export interface RunCallOpts { export default function runCall(this: VM, opts: RunCallOpts): Promise { const block = opts.block ?? Block.fromBlockData({}, { common: this._common }) - const txContext = new TxContext( - opts.gasPrice ?? new BN(0), - opts.origin ?? opts.caller ?? Address.zero() - ) + const txContext = new TxContext(opts.gasPrice ?? 0n, opts.origin ?? opts.caller ?? Address.zero()) const message = new Message({ caller: opts.caller, diff --git a/packages/vm/src/runCode.ts b/packages/vm/src/runCode.ts index df78d92977..d2cdacd820 100644 --- a/packages/vm/src/runCode.ts +++ b/packages/vm/src/runCode.ts @@ -11,7 +11,7 @@ from the stack, instead you should `copy` it first. item length then you must use `utils.pad(, 32)` first. */ -import { Address, BN } from 'ethereumjs-util' +import { Address } from 'ethereumjs-util' import { Block } from '@ethereumjs/block' import VM from './index' import TxContext from './evm/txContext' @@ -28,7 +28,7 @@ export interface RunCodeOpts { block?: Block evm?: EVM txContext?: TxContext - gasPrice?: BN + gasPrice?: bigint /** * The address where the call originated from. Defaults to the zero address. */ @@ -49,11 +49,11 @@ export interface RunCodeOpts { /** * Gas limit */ - gasLimit?: BN + gasLimit?: bigint /** * The value in ether that is being sent to `opt.address`. Defaults to `0` */ - value?: BN + value?: bigint depth?: number isStatic?: boolean selfdestruct?: { [k: string]: boolean } @@ -76,7 +76,7 @@ export default function runCode(this: VM, opts: RunCodeOpts): Promise { } // Validate gas limit against tx base fee (DataFee + TxFee + Creation Fee) - const txBaseFee = tx.getBaseFee() - const gasLimit = tx.gasLimit.clone() - if (gasLimit.lt(txBaseFee)) { + const txBaseFee = BigInt(tx.getBaseFee().toString(10)) + let gasLimit = BigInt(tx.gasLimit.toString(10)) + if (gasLimit < txBaseFee) { const msg = _errorMsg('base fee exceeds gas limit', this, block, tx) throw new Error(msg) } - gasLimit.isub(txBaseFee) + gasLimit -= txBaseFee if (this.DEBUG) { debugGas(`Subtracting base fee (${txBaseFee}) from gasLimit (-> ${gasLimit})`) } @@ -356,10 +356,10 @@ async function _runTx(this: VM, opts: RunTxOpts): Promise { (tx as FeeMarketEIP1559Transaction).maxPriorityFeePerGas, (tx as FeeMarketEIP1559Transaction).maxFeePerGas.sub(baseFee) ) - gasPrice = inclusionFeePerGas.add(baseFee) + gasPrice = BigInt(inclusionFeePerGas.add(baseFee).toString(10)) } else { // Have to cast as legacy tx since EIP1559 tx does not have gas price - gasPrice = (tx).gasPrice + gasPrice = BigInt((tx).gasPrice.toString(10)) if (this._common.isActivatedEIP(1559)) { const baseFee = block.header.baseFeePerGas! inclusionFeePerGas = (tx).gasPrice.sub(baseFee) @@ -368,8 +368,8 @@ async function _runTx(this: VM, opts: RunTxOpts): Promise { // Update from account's nonce and balance fromAccount.nonce.iaddn(1) - const txCost = tx.gasLimit.mul(gasPrice) - fromAccount.balance.isub(txCost) + const txCost = BigInt(tx.gasLimit.toString(10)) * gasPrice + fromAccount.balance.isub(new BN(txCost.toString(10), 10)) await state.putAccount(caller, fromAccount) if (this.DEBUG) { debug( @@ -386,7 +386,7 @@ async function _runTx(this: VM, opts: RunTxOpts): Promise { caller, gasLimit, to, - value, + value: BigInt(value.toString(10)), data, }) const evm = new EVM(this, txContext, block) @@ -424,18 +424,18 @@ async function _runTx(this: VM, opts: RunTxOpts): Promise { } // Caculate the total gas used - results.gasUsed.iadd(txBaseFee) + results.gasUsed += txBaseFee if (this.DEBUG) { debugGas(`tx add baseFee ${txBaseFee} to gasUsed (-> ${results.gasUsed})`) } // Process any gas refund - let gasRefund = results.execResult.gasRefund ?? new BN(0) - const maxRefundQuotient = this._common.param('gasConfig', 'maxRefundQuotient') - if (!gasRefund.isZero()) { - const maxRefund = results.gasUsed.divn(maxRefundQuotient) - gasRefund = BN.min(gasRefund, maxRefund) - results.gasUsed.isub(gasRefund) + let gasRefund = results.execResult.gasRefund ?? 0n + const maxRefundQuotient = BigInt(this._common.param('gasConfig', 'maxRefundQuotient')) + if (!(gasRefund === 0n)) { + const maxRefund = results.gasUsed / maxRefundQuotient + gasRefund = gasRefund < maxRefund ? gasRefund : maxRefund + results.gasUsed -= gasRefund if (this.DEBUG) { debug(`Subtract tx gasRefund (${gasRefund}) from gasUsed (-> ${results.gasUsed})`) } @@ -444,13 +444,13 @@ async function _runTx(this: VM, opts: RunTxOpts): Promise { debug(`No tx gasRefund`) } } - results.amountSpent = results.gasUsed.mul(gasPrice) + results.amountSpent = results.gasUsed * gasPrice // Update sender's balance fromAccount = await state.getAccount(caller) - const actualTxCost = results.gasUsed.mul(gasPrice) - const txCostDiff = txCost.sub(actualTxCost) - fromAccount.balance.iadd(txCostDiff) + const actualTxCost = results.gasUsed * gasPrice + const txCostDiff = txCost - actualTxCost + fromAccount.balance.iadd(new BN(txCostDiff.toString(10), 10)) await state.putAccount(caller, fromAccount) if (this.DEBUG) { debug( @@ -475,9 +475,9 @@ 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.iadd(results.gasUsed.mul(inclusionFeePerGas)) + minerAccount.balance.iadd(new BN(results.gasUsed.toString(10), 10).mul(inclusionFeePerGas)) } else { - minerAccount.balance.iadd(results.amountSpent) + minerAccount.balance.iadd(new BN(results.amountSpent.toString(10))) } // Put the miner account into the state. If the balance of the miner account remains zero, note that @@ -505,7 +505,8 @@ async function _runTx(this: VM, opts: RunTxOpts): Promise { state.clearOriginalStorageCache() // Generate the tx receipt - const cumulativeGasUsed = (opts.blockGasUsed ?? block.header.gasUsed).add(results.gasUsed) + const gasUsed = opts.blockGasUsed ?? BigInt(block.header.gasUsed.toString(10)) + const cumulativeGasUsed = gasUsed + results.gasUsed results.receipt = await generateTxReceipt.bind(this)(tx, results, cumulativeGasUsed) /** @@ -560,10 +561,10 @@ export async function generateTxReceipt( this: VM, tx: TypedTransaction, txResult: RunTxResult, - cumulativeGasUsed: BN + cumulativeGasUsed: bigint ): Promise { const baseReceipt: BaseTxReceipt = { - gasUsed: cumulativeGasUsed.toArrayLike(Buffer), + gasUsed: toBuffer('0x' + cumulativeGasUsed.toString(16)), bitvector: txResult.bloom.bitvector, logs: txResult.execResult.logs ?? [], } 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 d30890ed63..6322e1c6f5 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 @@ -46,15 +46,15 @@ tape('Constantinople: EIP-1283', async (t) => { const runCallArgs = { caller, - gasLimit: new BN(0xffffffffff), + gasLimit: BigInt(0xffffffffff), to: addr, } try { const res = await vm.runCall(runCallArgs) st.assert(res.execResult.exceptionError === undefined) - st.assert(new BN(testCase.used).eq(res.gasUsed)) - st.assert(new BN(testCase.refund).eq(res.execResult.gasRefund!)) + st.assert(BigInt(testCase.used) === res.gasUsed) + st.assert(BigInt(testCase.refund) === res.execResult.gasRefund!) } catch (e: any) { st.fail(e.message) } diff --git a/packages/vm/tests/api/EIPs/eip-1559-FeeMarket.spec.ts b/packages/vm/tests/api/EIPs/eip-1559-FeeMarket.spec.ts index c92d264367..0ac6520e31 100644 --- a/packages/vm/tests/api/EIPs/eip-1559-FeeMarket.spec.ts +++ b/packages/vm/tests/api/EIPs/eip-1559-FeeMarket.spec.ts @@ -98,7 +98,7 @@ tape('EIP1559 tests', (t) => { st.ok(miner.balance.eq(expectedMinerBalance), 'miner balance correct') account = await vm.stateManager.getAccount(sender) st.ok(account.balance.eq(expectedAccountBalance), 'account balance correct') - st.ok(results.amountSpent.eq(expectedCost), 'reported cost correct') + st.ok(new BN(results.amountSpent.toString(10), 10).eq(expectedCost), 'reported cost correct') const tx2 = new AccessListEIP2930Transaction( { @@ -129,7 +129,7 @@ tape('EIP1559 tests', (t) => { st.ok(miner.balance.eq(expectedMinerBalance), 'miner balance correct') account = await vm.stateManager.getAccount(sender) st.ok(account.balance.eq(expectedAccountBalance), 'account balance correct') - st.ok(results2.amountSpent.eq(expectedCost), 'reported cost correct') + st.ok(new BN(results2.amountSpent.toString(10), 10).eq(expectedCost), 'reported cost correct') const tx3 = new Transaction( { @@ -160,7 +160,7 @@ tape('EIP1559 tests', (t) => { st.ok(miner.balance.eq(expectedMinerBalance), 'miner balance correct') account = await vm.stateManager.getAccount(sender) st.ok(account.balance.eq(expectedAccountBalance), 'account balance correct') - st.ok(results3.amountSpent.eq(expectedCost), 'reported cost correct') + st.ok(new BN(results3.amountSpent.toString(10), 10).eq(expectedCost), 'reported cost correct') st.end() }) diff --git a/packages/vm/tests/api/EIPs/eip-2315.spec.ts b/packages/vm/tests/api/EIPs/eip-2315.spec.ts index f061cdf714..670e7d7d91 100644 --- a/packages/vm/tests/api/EIPs/eip-2315.spec.ts +++ b/packages/vm/tests/api/EIPs/eip-2315.spec.ts @@ -1,5 +1,4 @@ import tape from 'tape' -import { BN } from 'ethereumjs-util' import VM from '../../../src' import Common, { Chain, Hardfork } from '@ethereumjs/common' @@ -20,7 +19,7 @@ tape('Berlin: EIP 2315 tests', (t) => { const result = await vm.runCode({ code: Buffer.from(test.code, 'hex'), - gasLimit: new BN(0xffffffffff), + gasLimit: BigInt(0xffffffffff), }) st.equal(i, test.totalSteps) diff --git a/packages/vm/tests/api/EIPs/eip-2537-BLS.spec.ts b/packages/vm/tests/api/EIPs/eip-2537-BLS.spec.ts index 571179b3ac..10a10fee48 100644 --- a/packages/vm/tests/api/EIPs/eip-2537-BLS.spec.ts +++ b/packages/vm/tests/api/EIPs/eip-2537-BLS.spec.ts @@ -1,5 +1,5 @@ import tape from 'tape' -import { Address, BN, bufferToHex } from 'ethereumjs-util' +import { Address, bufferToHex } from 'ethereumjs-util' import Common, { Chain, Hardfork } from '@ethereumjs/common' import VM from '../../../src' import { isRunningInKarma } from '../../util' @@ -27,13 +27,13 @@ tape('EIP-2537 BLS tests', (t) => { const to = new Address(Buffer.from(address, 'hex')) const result = await vm.runCall({ caller: Address.zero(), - gasLimit: new BN(0xffffffffff), + gasLimit: BigInt(0xffffffffff), to, - value: new BN(0), + value: 0n, data: Buffer.alloc(0), }) - if (!result.execResult.gasUsed.eq(new BN(0))) { + if (!(result.execResult.gasUsed === 0n)) { st.fail('BLS precompiles should not use any gas if EIP not activated') } @@ -58,13 +58,13 @@ tape('EIP-2537 BLS tests', (t) => { const to = new Address(Buffer.from(address, 'hex')) const result = await vm.runCall({ caller: Address.zero(), - gasLimit: new BN(0xffffffffff), + gasLimit: BigInt(0xffffffffff), to, - value: new BN(0), + value: 0n, data: Buffer.alloc(0), }) - if (!result.execResult.gasUsed.eq(new BN(0xffffffffff))) { + if (!(result.execResult.gasUsed === BigInt(0xffffffffff))) { st.fail('BLS precompiles should use all gas on empty inputs') } @@ -101,7 +101,7 @@ tape('EIP-2537 BLS tests', (t) => { const result = await BLS12G2MultiExp({ data: Buffer.from(testVector, 'hex'), - gasLimit: new BN(5000000), + gasLimit: 5000000n, _common: common, _VM: vm, }) diff --git a/packages/vm/tests/api/EIPs/eip-2565-modexp-gas-cost.spec.ts b/packages/vm/tests/api/EIPs/eip-2565-modexp-gas-cost.spec.ts index 0e8f8fdcde..b2b5b0335a 100644 --- a/packages/vm/tests/api/EIPs/eip-2565-modexp-gas-cost.spec.ts +++ b/packages/vm/tests/api/EIPs/eip-2565-modexp-gas-cost.spec.ts @@ -1,5 +1,5 @@ import tape from 'tape' -import { Address, BN } from 'ethereumjs-util' +import { Address } from 'ethereumjs-util' import Common, { Chain, Hardfork } from '@ethereumjs/common' import VM from '../../../src' @@ -16,13 +16,13 @@ tape('EIP-2565 ModExp gas cost tests', (t) => { const to = new Address(Buffer.from('0000000000000000000000000000000000000005', 'hex')) const result = await vm.runCall({ caller: Address.zero(), - gasLimit: new BN(0xffffffffff), + gasLimit: BigInt(0xffffffffff), to, - value: new BN(0), + value: 0n, data: Buffer.from(test.Input, 'hex'), }) - if (!result.execResult.gasUsed.eq(new BN(test.Gas))) { + if (!(result.execResult.gasUsed === BigInt(test.Gas))) { st.fail( `[${testName}]: Gas usage incorrect, expected ${test.Gas}, got ${result.execResult.gasUsed}` ) diff --git a/packages/vm/tests/api/EIPs/eip-2929.spec.ts b/packages/vm/tests/api/EIPs/eip-2929.spec.ts index 2b76a44c41..b2916216e3 100644 --- a/packages/vm/tests/api/EIPs/eip-2929.spec.ts +++ b/packages/vm/tests/api/EIPs/eip-2929.spec.ts @@ -6,7 +6,7 @@ import { Transaction } from '@ethereumjs/tx' // Test cases source: https://gist.github.com/holiman/174548cad102096858583c6fbbb0649a tape('EIP 2929: gas cost tests', (t) => { - const initialGas = new BN(0xffffffffff) + const initialGas = BigInt(0xffffffffff) const address = new Address(Buffer.from('000000000000000000000000636F6E7472616374', 'hex')) const senderKey = Buffer.from( 'e331b6d69882b4cb4ea581d88e0b604039a3de5967688d3dcffdd2270c0fd109', @@ -20,7 +20,7 @@ tape('EIP 2929: gas cost tests', (t) => { const vm = new VM({ common }) vm.on('step', function (step: any) { - const gasUsed = currentGas.sub(step.gasLeft) + const gasUsed = currentGas - step.gasLeft currentGas = step.gasLeft if (test.steps.length) { @@ -35,10 +35,10 @@ tape('EIP 2929: gas cost tests', (t) => { // The first opcode of every test should be +/- irrelevant // (ex: PUSH) and the last opcode is always STOP if (i > 0) { - const expectedGasUsed = new BN(test.steps[i - 1].expectedGasUsed) + const expectedGasUsed = BigInt(test.steps[i - 1].expectedGasUsed) st.equal( true, - gasUsed.eq(expectedGasUsed), + gasUsed === expectedGasUsed, `Opcode: ${ test.steps[i - 1].expectedOpcode }, Gase Used: ${gasUsed}, Expected: ${expectedGasUsed}` @@ -51,7 +51,7 @@ tape('EIP 2929: gas cost tests', (t) => { await vm.stateManager.putContractCode(address, Buffer.from(test.code, 'hex')) const unsignedTx = Transaction.fromTxData({ - gasLimit: initialGas, // ensure we pass a lot of gas, so we do not run out of gas + gasLimit: new BN(initialGas.toString(10)), // ensure we pass a lot of gas, so we do not run out of gas to: address, // call to the contract address, }) @@ -59,12 +59,12 @@ tape('EIP 2929: gas cost tests', (t) => { const result = await vm.runTx({ tx }) - const totalGasUsed = initialGas.sub(currentGas) - st.equal(true, totalGasUsed.eq(new BN(test.totalGasUsed).addn(21000))) // Add tx upfront cost. + const totalGasUsed = initialGas - currentGas + st.equal(true, totalGasUsed === BigInt(test.totalGasUsed) + 21000n) // Add tx upfront cost. return result } - const runCodeTest = async function (code: string, expectedGasUsed: number, st: tape.Test) { + const runCodeTest = async function (code: string, expectedGasUsed: bigint, st: tape.Test) { // setup the accounts for this test const privateKey = Buffer.from( 'e331b6d69882b4cb4ea581d88e0b604039a3de5967688d3dcffdd2270c0fd109', @@ -99,7 +99,7 @@ tape('EIP 2929: gas cost tests', (t) => { const result = await vm.runTx({ tx }) - st.ok(result.gasUsed.toNumber() == expectedGasUsed) + st.ok(result.gasUsed == expectedGasUsed) } // Checks EXT(codehash,codesize,balance) of precompiles, which should be 100, @@ -157,24 +157,24 @@ tape('EIP 2929: gas cost tests', (t) => { t.test('should charge for extcodecopy correctly', async (st) => { const test = { code: '60006000600060ff3c60006000600060ff3c600060006000303c00', - totalGasUsed: 2835, + totalGasUsed: 2835n, steps: [ - { expectedOpcode: 'PUSH1', expectedGasUsed: 3 }, - { expectedOpcode: 'PUSH1', expectedGasUsed: 3 }, - { expectedOpcode: 'PUSH1', expectedGasUsed: 3 }, - { expectedOpcode: 'PUSH1', expectedGasUsed: 3 }, - { expectedOpcode: 'EXTCODECOPY', expectedGasUsed: 2600 }, - { expectedOpcode: 'PUSH1', expectedGasUsed: 3 }, - { expectedOpcode: 'PUSH1', expectedGasUsed: 3 }, - { expectedOpcode: 'PUSH1', expectedGasUsed: 3 }, - { expectedOpcode: 'PUSH1', expectedGasUsed: 3 }, - { expectedOpcode: 'EXTCODECOPY', expectedGasUsed: 100 }, - { expectedOpcode: 'PUSH1', expectedGasUsed: 3 }, - { expectedOpcode: 'PUSH1', expectedGasUsed: 3 }, - { expectedOpcode: 'PUSH1', expectedGasUsed: 3 }, - { expectedOpcode: 'ADDRESS', expectedGasUsed: 2 }, - { expectedOpcode: 'EXTCODECOPY', expectedGasUsed: 100 }, - { expectedOpcode: 'STOP', expectedGasUsed: 0 }, + { expectedOpcode: 'PUSH1', expectedGasUsed: 3n }, + { expectedOpcode: 'PUSH1', expectedGasUsed: 3n }, + { expectedOpcode: 'PUSH1', expectedGasUsed: 3n }, + { expectedOpcode: 'PUSH1', expectedGasUsed: 3n }, + { expectedOpcode: 'EXTCODECOPY', expectedGasUsed: 2600n }, + { expectedOpcode: 'PUSH1', expectedGasUsed: 3n }, + { expectedOpcode: 'PUSH1', expectedGasUsed: 3n }, + { expectedOpcode: 'PUSH1', expectedGasUsed: 3n }, + { expectedOpcode: 'PUSH1', expectedGasUsed: 3n }, + { expectedOpcode: 'EXTCODECOPY', expectedGasUsed: 100n }, + { expectedOpcode: 'PUSH1', expectedGasUsed: 3n }, + { expectedOpcode: 'PUSH1', expectedGasUsed: 3n }, + { expectedOpcode: 'PUSH1', expectedGasUsed: 3n }, + { expectedOpcode: 'ADDRESS', expectedGasUsed: 2n }, + { expectedOpcode: 'EXTCODECOPY', expectedGasUsed: 100n }, + { expectedOpcode: 'STOP', expectedGasUsed: 0n }, ], } @@ -272,18 +272,18 @@ tape('EIP 2929: gas cost tests', (t) => { // SLOAD or CALL operations. // load same storage slot twice (also in inner call) - await runCodeTest('60005460003415601357600080808080305AF15B00', 23369, t) + await runCodeTest('60005460003415601357600080808080305AF15B00', 23369n, t) // call to contract, load slot 0, revert inner call. load slot 0 in outer call. - await runCodeTest('341515600D57600054600080FD5B600080808080305AF160005400', 25374, t) + await runCodeTest('341515600D57600054600080FD5B600080808080305AF160005400', 25374n, t) // call to address 0xFFFF..FF const callFF = '6000808080806000195AF1' // call address 0xFF..FF, now call same contract again, call 0xFF..FF again (it is now warm) - await runCodeTest(callFF + '60003415601B57600080808080305AF15B00', 23909, t) + await runCodeTest(callFF + '60003415601B57600080808080305AF15B00', 23909n, t) // call to contract, call 0xFF..FF, revert, call 0xFF..FF (should be cold) await runCodeTest( '341515601557' + callFF + '600080FD5B600080808080305AF1' + callFF + '00', - 26414, + 26414n, t ) diff --git a/packages/vm/tests/api/EIPs/eip-2930-accesslists.spec.ts b/packages/vm/tests/api/EIPs/eip-2930-accesslists.spec.ts index b815842a20..833dbbfca5 100644 --- a/packages/vm/tests/api/EIPs/eip-2930-accesslists.spec.ts +++ b/packages/vm/tests/api/EIPs/eip-2930-accesslists.spec.ts @@ -68,14 +68,14 @@ tape('EIP-2930 Optional Access Lists tests', (t) => { await vm.runTx({ tx: txnWithAccessList }) st.ok(trace[1][0] == 'SLOAD') - let gasUsed = trace[1][1].sub(trace[2][1]).toNumber() - st.equal(gasUsed, 100, 'charge warm sload gas') + let gasUsed = trace[1][1] - trace[2][1] + st.equal(gasUsed, 100n, 'charge warm sload gas') trace = [] await vm.runTx({ tx: txnWithoutAccessList, skipNonce: true }) st.ok(trace[1][0] == 'SLOAD') - gasUsed = trace[1][1].sub(trace[2][1]).toNumber() - st.equal(gasUsed, 2100, 'charge cold sload gas') + gasUsed = trace[1][1] - trace[2][1] + st.equal(gasUsed, 2100n, 'charge cold sload gas') st.end() }) diff --git a/packages/vm/tests/api/EIPs/eip-3198-BaseFee.spec.ts b/packages/vm/tests/api/EIPs/eip-3198-BaseFee.spec.ts index 6d51555d27..5ec1d11df2 100644 --- a/packages/vm/tests/api/EIPs/eip-3198-BaseFee.spec.ts +++ b/packages/vm/tests/api/EIPs/eip-3198-BaseFee.spec.ts @@ -91,10 +91,10 @@ tape('EIP3198 tests', (t) => { tx: block.transactions[0], block, }) - const txBaseFee = block.transactions[0].getBaseFee() - const gasUsed = results.gasUsed.sub(txBaseFee) - st.ok(gasUsed.eqn(2), 'gas used correct') - st.ok(stack[0].eq(fee), 'right item pushed on stack') + const txBaseFee = BigInt(block.transactions[0].getBaseFee().toString(10)) + const gasUsed = results.gasUsed - txBaseFee + st.ok(gasUsed === 2n, 'gas used correct') + st.ok(stack[0] === BigInt(fee.toString(10)), 'right item pushed on stack') st.end() }) }) diff --git a/packages/vm/tests/api/EIPs/eip-3529.spec.ts b/packages/vm/tests/api/EIPs/eip-3529.spec.ts index 9a28cf6c82..765f6bcbe0 100644 --- a/packages/vm/tests/api/EIPs/eip-3529.spec.ts +++ b/packages/vm/tests/api/EIPs/eip-3529.spec.ts @@ -114,17 +114,17 @@ tape('EIP-3529 tests', (t) => { t.test('should verify EIP test cases', async (st) => { const vm = new VM({ common }) - let gasRefund: BN - let gasLeft: BN + let gasRefund: bigint + let gasLeft: bigint vm.on('step', (step: InterpreterStep) => { if (step.opcode.name === 'STOP') { - gasRefund = step.gasRefund.clone() - gasLeft = step.gasLeft.clone() + gasRefund = step.gasRefund + gasLeft = step.gasLeft } }) - const gasLimit = new BN(100000) + const gasLimit = 100000n const key = Buffer.from('00'.repeat(32), 'hex') for (const testCase of testCases) { @@ -145,11 +145,11 @@ tape('EIP-3529 tests', (t) => { gasLimit, }) - const gasUsed = gasLimit.sub(gasLeft!) - const effectiveGas = gasUsed.sub(gasRefund!) + const gasUsed = gasLimit - gasLeft! + const effectiveGas = gasUsed - gasRefund! - st.equals(effectiveGas.toNumber(), testCase.effectiveGas, 'correct effective gas') - st.equals(gasUsed.toNumber(), testCase.usedGas, 'correct used gas') + st.equals(Number(effectiveGas), testCase.effectiveGas, 'correct effective gas') + st.equals(Number(gasUsed), testCase.usedGas, 'correct used gas') // clear the storage cache, otherwise next test will use current original value vm.stateManager.clearOriginalStorageCache() @@ -171,8 +171,8 @@ tape('EIP-3529 tests', (t) => { }) st.ok(result.execResult.exceptionError === undefined, 'transaction executed succesfully') - st.ok(BN.isBN(result.execResult.gasRefund), 'gas refund is defined') - st.ok(result.execResult.gasRefund?.isZero(), 'gas refund is zero') + st.ok(result.execResult.gasRefund !== undefined, 'gas refund is defined') + st.ok(result.execResult.gasRefund === 0n, 'gas refund is zero') st.end() }) @@ -184,15 +184,15 @@ tape('EIP-3529 tests', (t) => { */ const vm = new VM({ common }) - let startGas: any - let finalGas: any + let startGas: bigint + let finalGas: bigint vm.on('step', (step: InterpreterStep) => { if (startGas === undefined) { - startGas = step.gasLeft.clone() + startGas = step.gasLeft } if (step.opcode.name === 'STOP') { - finalGas = step.gasLeft.clone() + finalGas = step.gasLeft } }) @@ -221,13 +221,13 @@ tape('EIP-3529 tests', (t) => { const result = await vm.runTx({ tx }) - const actualGasUsed = startGas.sub(finalGas).addn(21000) - const maxRefund = actualGasUsed.divn(5) - const minGasUsed = actualGasUsed.sub(maxRefund) + const actualGasUsed = startGas! - finalGas! + 21000n + const maxRefund = actualGasUsed / 5n + const minGasUsed = actualGasUsed - maxRefund const gasUsed = result.execResult.gasUsed - - st.ok(result.execResult.gasRefund?.gt(maxRefund), 'refund is larger than the max refund') - st.ok(gasUsed.gte(minGasUsed), 'gas used respects the max refund quotient') + console.log(result.execResult.gasRefund, maxRefund) + 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.end() }) }) diff --git a/packages/vm/tests/api/EIPs/eip-3855.spec.ts b/packages/vm/tests/api/EIPs/eip-3855.spec.ts index 2e7b8f52b1..7ff5682c05 100644 --- a/packages/vm/tests/api/EIPs/eip-3855.spec.ts +++ b/packages/vm/tests/api/EIPs/eip-3855.spec.ts @@ -2,7 +2,6 @@ import tape from 'tape' import VM from '../../../src' import Common, { Chain, Hardfork } from '@ethereumjs/common' import { InterpreterStep } from '../../../src/evm/interpreter' -import { BN } from 'ethereumjs-util' import { ERROR } from '../../../src/exceptions' tape('EIP 3541 tests', (t) => { @@ -15,7 +14,7 @@ tape('EIP 3541 tests', (t) => { t.test('should correctly use push0 opcode', async (st) => { const vm = new VM({ common }) - let stack: BN[] + let stack: bigint[] vm.on('step', (e: InterpreterStep) => { if (stack) { @@ -26,18 +25,18 @@ tape('EIP 3541 tests', (t) => { const result = await vm.runCode({ code: Buffer.from('5F', 'hex'), - gasLimit: new BN(10), + gasLimit: 10n, }) st.ok(stack!.length == 1) - st.ok(stack![0].eqn(0)) - st.ok(result.gasUsed.eqn(common.param('gasPrices', 'push0'))) + st.ok(stack![0] === 0n) + st.ok(result.gasUsed === BigInt(common.param('gasPrices', 'push0'))) st.end() }) t.test('should correctly use push0 to create a stack with stack limit length', async (st) => { const vm = new VM({ common }) - let stack: BN[] = [] + let stack: bigint[] = [] vm.on('step', (e: InterpreterStep) => { stack = e.stack @@ -47,16 +46,16 @@ tape('EIP 3541 tests', (t) => { const result = await vm.runCode({ code: Buffer.from('5F'.repeat(depth), 'hex'), - gasLimit: new BN(10000), + gasLimit: 10000n, }) st.ok(stack.length == depth) - stack.forEach((elem: BN) => { - if (!elem.eqn(0)) { + stack.forEach((elem: bigint) => { + if (!(elem === 0n)) { st.fail('stack element is not 0') } }) - st.ok(result.gasUsed.eqn(common.param('gasPrices', 'push0') * depth)) + st.ok(result.gasUsed === BigInt(common.param('gasPrices', 'push0') * depth)) st.end() }) @@ -67,7 +66,7 @@ tape('EIP 3541 tests', (t) => { const result = await vm.runCode({ code: Buffer.from('5F'.repeat(depth), 'hex'), - gasLimit: new BN(10000), + gasLimit: 10000n, }) st.ok(result.exceptionError?.error === ERROR.STACK_OVERFLOW) @@ -79,7 +78,7 @@ tape('EIP 3541 tests', (t) => { const result = await vm.runCode({ code: Buffer.from('5F', 'hex'), - gasLimit: new BN(10000), + gasLimit: 10000n, }) st.ok(result.exceptionError!.error === ERROR.INVALID_OPCODE) diff --git a/packages/vm/tests/api/buildBlock.spec.ts b/packages/vm/tests/api/buildBlock.spec.ts index 2e512672ca..3ac0421013 100644 --- a/packages/vm/tests/api/buildBlock.spec.ts +++ b/packages/vm/tests/api/buildBlock.spec.ts @@ -42,7 +42,7 @@ tape('BlockBuilder', async (t) => { return address } const result = await vmCopy.runBlock({ block }) - st.ok(result.gasUsed.eq(block.header.gasUsed)) + st.ok(result.gasUsed === BigInt(block.header.gasUsed.toString(10))) st.ok(result.receiptRoot.equals(block.header.receiptTrie)) st.ok(result.stateRoot.equals(block.header.stateRoot)) st.ok(result.logsBloom.equals(block.header.logsBloom)) @@ -271,7 +271,7 @@ tape('BlockBuilder', async (t) => { // block should successfully execute with VM.runBlock and have same outputs const result = await vmCopy.runBlock({ block }) - st.ok(result.gasUsed.eq(block.header.gasUsed)) + st.ok(result.gasUsed === BigInt(block.header.gasUsed.toString(10))) st.ok(result.receiptRoot.equals(block.header.receiptTrie)) st.ok(result.stateRoot.equals(block.header.stateRoot)) st.ok(result.logsBloom.equals(block.header.logsBloom)) @@ -362,7 +362,7 @@ tape('BlockBuilder', async (t) => { return address } const result = await vmCopy.runBlock({ block }) - st.ok(result.gasUsed.eq(block.header.gasUsed)) + st.ok(result.gasUsed === BigInt(block.header.gasUsed.toString(10))) st.ok(result.receiptRoot.equals(block.header.receiptTrie)) st.ok(result.stateRoot.equals(block.header.stateRoot)) st.ok(result.logsBloom.equals(block.header.logsBloom)) diff --git a/packages/vm/tests/api/evm/precompiles/06-ecadd.spec.ts b/packages/vm/tests/api/evm/precompiles/06-ecadd.spec.ts index 5bbb3798c0..5f5183ff70 100644 --- a/packages/vm/tests/api/evm/precompiles/06-ecadd.spec.ts +++ b/packages/vm/tests/api/evm/precompiles/06-ecadd.spec.ts @@ -1,5 +1,5 @@ import tape from 'tape' -import { Address, BN } from 'ethereumjs-util' +import { Address } from 'ethereumjs-util' import Common, { Chain, Hardfork } from '@ethereumjs/common' import VM from '../../../../src' import { getPrecompile } from '../../../../src/evm/precompiles' @@ -13,12 +13,12 @@ tape('Precompiles: ECADD', (t) => { const result = await ECADD({ data: Buffer.alloc(0), - gasLimit: new BN(0xffff), + gasLimit: BigInt(0xffff), _common: common, _VM: vm, }) - st.deepEqual(result.gasUsed.toNumber(), 500, 'should use petersburg gas costs') + st.deepEqual(result.gasUsed, 500n, 'should use petersburg gas costs') st.end() }) }) diff --git a/packages/vm/tests/api/evm/precompiles/07-ecmul.spec.ts b/packages/vm/tests/api/evm/precompiles/07-ecmul.spec.ts index e5cc249822..f3de913e92 100644 --- a/packages/vm/tests/api/evm/precompiles/07-ecmul.spec.ts +++ b/packages/vm/tests/api/evm/precompiles/07-ecmul.spec.ts @@ -1,5 +1,5 @@ import tape from 'tape' -import { Address, BN } from 'ethereumjs-util' +import { Address } from 'ethereumjs-util' import Common, { Chain, Hardfork } from '@ethereumjs/common' import VM from '../../../../src' import { getPrecompile } from '../../../../src/evm/precompiles' @@ -13,12 +13,12 @@ tape('Precompiles: ECMUL', (t) => { const result = await ECMUL({ data: Buffer.alloc(0), - gasLimit: new BN(0xffff), + gasLimit: BigInt(0xffff), _common: common, _VM: vm, }) - st.deepEqual(result.gasUsed.toNumber(), 40000, 'should use petersburg gas costs') + st.deepEqual(result.gasUsed, 40000n, 'should use petersburg gas costs') st.end() }) }) diff --git a/packages/vm/tests/api/evm/precompiles/08-ecpairing.spec.ts b/packages/vm/tests/api/evm/precompiles/08-ecpairing.spec.ts index fc228603d9..ce0147a4ef 100644 --- a/packages/vm/tests/api/evm/precompiles/08-ecpairing.spec.ts +++ b/packages/vm/tests/api/evm/precompiles/08-ecpairing.spec.ts @@ -1,5 +1,5 @@ import tape from 'tape' -import { Address, BN } from 'ethereumjs-util' +import { Address } from 'ethereumjs-util' import Common, { Chain, Hardfork } from '@ethereumjs/common' import VM from '../../../../src' import { getPrecompile } from '../../../../src/evm/precompiles' @@ -16,16 +16,12 @@ tape('Precompiles: ECPAIRING', (t) => { '00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa000000000000000000000000000000000000000000000000000000000000000130644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd45198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa', 'hex' ), - gasLimit: new BN(0xffffff), + gasLimit: BigInt(0xffffff), _common: common, _VM: vm, }) - st.deepEqual( - result.gasUsed.toNumber(), - 260000, - 'should use petersburg gas costs (k ^= 2 pairings)' - ) + st.deepEqual(result.gasUsed, 260000n, 'should use petersburg gas costs (k ^= 2 pairings)') st.end() }) }) diff --git a/packages/vm/tests/api/evm/precompiles/hardfork.spec.ts b/packages/vm/tests/api/evm/precompiles/hardfork.spec.ts index 4cfceebfa1..5bdda8b2e5 100644 --- a/packages/vm/tests/api/evm/precompiles/hardfork.spec.ts +++ b/packages/vm/tests/api/evm/precompiles/hardfork.spec.ts @@ -1,5 +1,5 @@ import tape from 'tape' -import { Address, BN } from 'ethereumjs-util' +import { Address } from 'ethereumjs-util' import Common, { Chain, Hardfork } from '@ethereumjs/common' import VM from '../../../../src' import { getPrecompile } from '../../../../src/evm/precompiles' @@ -24,12 +24,12 @@ tape('Precompiles: hardfork availability', (t) => { let vm = new VM({ common: commonByzantium }) let result = await vm.runCall({ caller: Address.zero(), - gasLimit: new BN(0xffffffffff), + gasLimit: BigInt(0xffffffffff), to: ECPAIR_Address, - value: new BN(0), + value: 0n, }) - st.assert(result.gasUsed.toNumber() == 100000) // check that we are using gas (if address would contain no code we use 0 gas) + st.assert(result.gasUsed === 100000n) // 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 }) @@ -44,12 +44,12 @@ tape('Precompiles: hardfork availability', (t) => { vm = new VM({ common: commonPetersburg }) result = await vm.runCall({ caller: Address.zero(), - gasLimit: new BN(0xffffffffff), + gasLimit: BigInt(0xffffffffff), to: ECPAIR_Address, - value: new BN(0), + value: 0n, }) - st.assert(result.gasUsed.toNumber() == 100000) + st.assert(result.gasUsed === 100000n) // Check if ECPAIR is not available in Homestead. const commonHomestead = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Homestead }) @@ -65,12 +65,12 @@ tape('Precompiles: hardfork availability', (t) => { result = await vm.runCall({ caller: Address.zero(), - gasLimit: new BN(0xffffffffff), + gasLimit: BigInt(0xffffffffff), to: ECPAIR_Address, - value: new BN(0), + value: 0n, }) - st.assert(result.gasUsed.toNumber() == 0) // check that we use no gas, because we are calling into an address without code. + st.assert(result.gasUsed === 0n) // check that we use no gas, because we are calling into an address without code. st.end() }) diff --git a/packages/vm/tests/api/evm/stack.spec.ts b/packages/vm/tests/api/evm/stack.spec.ts index cbf04deeab..336fd5a345 100644 --- a/packages/vm/tests/api/evm/stack.spec.ts +++ b/packages/vm/tests/api/evm/stack.spec.ts @@ -28,98 +28,98 @@ tape('Stack', (t) => { t.test('should push item', (st) => { const s = new Stack() - s.push(new BN(5)) - st.equal(s.pop().toNumber(), 5) + s.push(5n) + st.equal(s.pop(), 5n) st.end() }) t.test('popN should return array for n = 1', (st) => { const s = new Stack() - s.push(new BN(5)) - st.deepEqual(s.popN(1), [new BN(5)]) + s.push(5n) + st.deepEqual(s.popN(1), [5n]) st.end() }) t.test('popN should fail on underflow', (st) => { const s = new Stack() - s.push(new BN(5)) + s.push(5n) st.throws(() => s.popN(2)) st.end() }) t.test('popN should return in correct order', (st) => { const s = new Stack() - s.push(new BN(5)) - s.push(new BN(7)) - st.deepEqual(s.popN(2), [new BN(7), new BN(5)]) + s.push(5n) + s.push(7n) + st.deepEqual(s.popN(2), [7n, 5n]) st.end() }) t.test('should throw on overflow', (st) => { const s = new Stack() for (let i = 0; i < 1024; i++) { - s.push(new BN(i)) + s.push(BigInt(i)) } - st.throws(() => s.push(new BN(1024))) + st.throws(() => s.push(1024n)) st.end() }) t.test('overflow limit should be configurable', (st) => { const s = new Stack(1023) for (let i = 0; i < 1023; i++) { - s.push(new BN(i)) + s.push(BigInt(i)) } - st.throws(() => s.push(new BN(1023))) + st.throws(() => s.push(1023n)) st.end() }) t.test('should swap top with itself', (st) => { const s = new Stack() - s.push(new BN(5)) + s.push(5n) s.swap(0) - st.deepEqual(s.pop(), new BN(5)) + st.deepEqual(s.pop(), 5n) st.end() }) t.test('swap should throw on underflow', (st) => { const s = new Stack() - s.push(new BN(5)) + s.push(5n) st.throws(() => s.swap(1)) st.end() }) t.test('should swap', (st) => { const s = new Stack() - s.push(new BN(5)) - s.push(new BN(7)) + s.push(5n) + s.push(7n) s.swap(1) - st.deepEqual(s.pop(), new BN(5)) + st.deepEqual(s.pop(), 5n) st.end() }) t.test('dup should throw on underflow', (st) => { const s = new Stack() st.throws(() => s.dup(1)) - s.push(new BN(5)) + s.push(5n) st.throws(() => s.dup(2)) st.end() }) t.test('should dup', (st) => { const s = new Stack() - s.push(new BN(5)) - s.push(new BN(7)) + s.push(5n) + s.push(7n) s.dup(2) - st.deepEqual(s.pop(), new BN(5)) + st.deepEqual(s.pop(), 5n) st.end() }) t.test('should validate value overflow', (st) => { const s = new Stack() - const max = new BN(2).pow(new BN(256)).subn(1) + const max = 2n ** 256n - 1n s.push(max) st.deepEqual(s.pop(), max) - st.throws(() => s.push(max.addn(1))) + st.throws(() => s.push(max + 1n)) st.end() }) @@ -152,9 +152,9 @@ tape('Stack', (t) => { await vm.stateManager.putContractCode(addr, Buffer.from(code, 'hex')) const runCallArgs = { caller: caller, - gasLimit: new BN(0xffffffffff), + gasLimit: BigInt(0xffffffffff), to: addr, - value: new BN(1), + value: 1n, } try { const res = await vm.runCall(runCallArgs) diff --git a/packages/vm/tests/api/istanbul/eip-1108.spec.ts b/packages/vm/tests/api/istanbul/eip-1108.spec.ts index 1c8800cf75..a1c29174e4 100644 --- a/packages/vm/tests/api/istanbul/eip-1108.spec.ts +++ b/packages/vm/tests/api/istanbul/eip-1108.spec.ts @@ -1,5 +1,5 @@ import tape from 'tape' -import { Address, BN } from 'ethereumjs-util' +import { Address } from 'ethereumjs-util' import Common, { Chain, Hardfork } from '@ethereumjs/common' import VM from '../../../src' import { getPrecompile } from '../../../src/evm/precompiles' @@ -13,12 +13,12 @@ tape('Istanbul: EIP-1108 tests', (t) => { const result = await ECADD({ data: Buffer.alloc(0), - gasLimit: new BN(0xffff), + gasLimit: BigInt(0xffff), _common: common, _VM: vm, }) - st.deepEqual(result.gasUsed.toNumber(), 150, 'should use istanbul gas costs') + st.deepEqual(result.gasUsed, 150n, 'should use istanbul gas costs') st.end() }) @@ -30,12 +30,12 @@ tape('Istanbul: EIP-1108 tests', (t) => { const result = await ECMUL({ data: Buffer.alloc(0), - gasLimit: new BN(0xffff), + gasLimit: BigInt(0xffff), _common: common, _VM: vm, }) - st.deepEqual(result.gasUsed.toNumber(), 6000, 'should use istanbul gas costs') + st.deepEqual(result.gasUsed, 6000n, 'should use istanbul gas costs') st.end() }) @@ -50,16 +50,12 @@ tape('Istanbul: EIP-1108 tests', (t) => { '00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa000000000000000000000000000000000000000000000000000000000000000130644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd45198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa', 'hex' ), - gasLimit: new BN(0xffffff), + gasLimit: BigInt(0xffffff), _common: common, _VM: vm, }) - st.deepEqual( - result.gasUsed.toNumber(), - 113000, - 'should use petersburg gas costs (k ^= 2 pairings)' - ) + st.deepEqual(result.gasUsed, 113000n, 'should use petersburg gas costs (k ^= 2 pairings)') st.end() }) }) diff --git a/packages/vm/tests/api/istanbul/eip-1344.spec.ts b/packages/vm/tests/api/istanbul/eip-1344.spec.ts index 073c223d21..baa6578f72 100644 --- a/packages/vm/tests/api/istanbul/eip-1344.spec.ts +++ b/packages/vm/tests/api/istanbul/eip-1344.spec.ts @@ -17,7 +17,7 @@ tape('Istanbul: EIP-1344', async (t) => { t.test('CHAINID', async (st) => { const runCodeArgs = { code: Buffer.from(code.join(''), 'hex'), - gasLimit: new BN(0xffff), + gasLimit: BigInt(0xffff), } for (const testCase of testCases) { diff --git a/packages/vm/tests/api/istanbul/eip-152.spec.ts b/packages/vm/tests/api/istanbul/eip-152.spec.ts index aa7a607ede..0d12013e70 100644 --- a/packages/vm/tests/api/istanbul/eip-152.spec.ts +++ b/packages/vm/tests/api/istanbul/eip-152.spec.ts @@ -1,5 +1,4 @@ import tape from 'tape' -import { BN } from 'ethereumjs-util' import Common, { Chain, Hardfork } from '@ethereumjs/common' import VM from '../../../src' import { default as blake2f, F } from '../../../src/evm/precompiles/09-blake2f' @@ -93,7 +92,7 @@ tape('Istanbul: EIP-152', (t) => { st.comment(testCase.name) const res = blake2f({ data: Buffer.from(testCase.input, 'hex'), - gasLimit: new BN(20), + gasLimit: 20n, _common: common, _VM: vm, }) @@ -104,7 +103,7 @@ tape('Istanbul: EIP-152', (t) => { st.comment(testCase.name) const res = blake2f({ data: Buffer.from(testCase.input, 'hex'), - gasLimit: new BN(10000000), + gasLimit: 10000000n, _common: common, _VM: vm, }) diff --git a/packages/vm/tests/api/istanbul/eip-1884.spec.ts b/packages/vm/tests/api/istanbul/eip-1884.spec.ts index 8e9d0ebbe8..660c63310a 100644 --- a/packages/vm/tests/api/istanbul/eip-1884.spec.ts +++ b/packages/vm/tests/api/istanbul/eip-1884.spec.ts @@ -1,5 +1,5 @@ import tape from 'tape' -import { Address, BN } from 'ethereumjs-util' +import { Address, BN, bufferToHex } from 'ethereumjs-util' import Common, { Chain, Hardfork } from '@ethereumjs/common' import VM from '../../../src' import { ERROR } from '../../../src/exceptions' @@ -17,7 +17,7 @@ tape('Istanbul: EIP-1884', async (t) => { const addr = new Address(Buffer.from('00000000000000000000000000000000000000ff', 'hex')) const runCodeArgs = { code: Buffer.from(code.join(''), 'hex'), - gasLimit: new BN(0xffff), + gasLimit: BigInt(0xffff), address: addr, } @@ -40,7 +40,8 @@ tape('Istanbul: EIP-1884', async (t) => { } else { st.assert(res.exceptionError === undefined) st.assert( - new BN(Buffer.from(testCase.selfbalance.slice(2), 'hex')).eq(new BN(res.returnValue)) + BigInt(testCase.selfbalance) === + BigInt(bufferToHex(res.returnValue) === '0x' ? 0 : bufferToHex(res.returnValue)) ) } } catch (e: any) { diff --git a/packages/vm/tests/api/istanbul/eip-2200.spec.ts b/packages/vm/tests/api/istanbul/eip-2200.spec.ts index 722cbae92d..6b049d7517 100644 --- a/packages/vm/tests/api/istanbul/eip-2200.spec.ts +++ b/packages/vm/tests/api/istanbul/eip-2200.spec.ts @@ -1,44 +1,52 @@ import tape from 'tape' -import { Address, BN } from 'ethereumjs-util' +import { Address, BN, setLengthLeft, toBuffer } from 'ethereumjs-util' import Common, { Chain, Hardfork } from '@ethereumjs/common' import VM from '../../../src' import { ERROR } from '../../../src/exceptions' import { createAccount } from '../utils' const testCases = [ - { original: new BN(0), code: '60006000556000600055', used: 1612, refund: 0 }, // 0 -> 0 -> 0 - { original: new BN(0), code: '60006000556001600055', used: 20812, refund: 0 }, // 0 -> 0 -> 1 - { original: new BN(0), code: '60016000556000600055', used: 20812, refund: 19200 }, // 0 -> 1 -> 0 - { original: new BN(0), code: '60016000556002600055', used: 20812, refund: 0 }, // 0 -> 1 -> 2 - { original: new BN(0), code: '60016000556001600055', used: 20812, refund: 0 }, // 0 -> 1 -> 1 - { original: new BN(1), code: '60006000556000600055', used: 5812, refund: 15000 }, // 1 -> 0 -> 0 - { original: new BN(1), code: '60006000556001600055', used: 5812, refund: 4200 }, // 1 -> 0 -> 1 - { original: new BN(1), code: '60006000556002600055', used: 5812, refund: 0 }, // 1 -> 0 -> 2 - { original: new BN(1), code: '60026000556000600055', used: 5812, refund: 15000 }, // 1 -> 2 -> 0 - { original: new BN(1), code: '60026000556003600055', used: 5812, refund: 0 }, // 1 -> 2 -> 3 - { original: new BN(1), code: '60026000556001600055', used: 5812, refund: 4200 }, // 1 -> 2 -> 1 - { original: new BN(1), code: '60026000556002600055', used: 5812, refund: 0 }, // 1 -> 2 -> 2 - { original: new BN(1), code: '60016000556000600055', used: 5812, refund: 15000 }, // 1 -> 1 -> 0 - { original: new BN(1), code: '60016000556002600055', used: 5812, refund: 0 }, // 1 -> 1 -> 2 - { original: new BN(1), code: '60016000556001600055', used: 1612, refund: 0 }, // 1 -> 1 -> 1 - { original: new BN(0), code: '600160005560006000556001600055', used: 40818, refund: 19200 }, // 0 -> 1 -> 0 -> 1 - { original: new BN(1), code: '600060005560016000556000600055', used: 10818, refund: 19200 }, // 1 -> 0 -> 1 -> 0 { - original: new BN(1), - gas: new BN(2306), + original: 0n, + code: '60006000556000600055', + used: 1612, + refund: 0, + gas: undefined, + err: undefined, + }, // 0 -> 0 -> 0 + /*{ original: 0n, code: '60006000556001600055', used: 20812, refund: 0 }, // 0 -> 0 -> 1 + { original: 0n, code: '60016000556000600055', used: 20812, refund: 19200 }, // 0 -> 1 -> 0 + { original: 0n, code: '60016000556002600055', used: 20812, refund: 0 }, // 0 -> 1 -> 2 + { original: 0n, code: '60016000556001600055', used: 20812, refund: 0 }, // 0 -> 1 -> 1 + { original: 1n, code: '60006000556000600055', used: 5812, refund: 15000 }, // 1 -> 0 -> 0 + { original: 1n, code: '60006000556001600055', used: 5812, refund: 4200 }, // 1 -> 0 -> 1 + { original: 1n, code: '60006000556002600055', used: 5812, refund: 0 }, // 1 -> 0 -> 2 + { original: 1n, code: '60026000556000600055', used: 5812, refund: 15000 }, // 1 -> 2 -> 0 + { original: 1n, code: '60026000556003600055', used: 5812, refund: 0 }, // 1 -> 2 -> 3 + { original: 1n, code: '60026000556001600055', used: 5812, refund: 4200 }, // 1 -> 2 -> 1 + { original: 1n, code: '60026000556002600055', used: 5812, refund: 0 }, // 1 -> 2 -> 2 + { original: 1n, code: '60016000556000600055', used: 5812, refund: 15000 }, // 1 -> 1 -> 0 + { original: 1n, code: '60016000556002600055', used: 5812, refund: 0 }, // 1 -> 1 -> 2 + { original: 1n, code: '60016000556001600055', used: 1612, refund: 0 }, // 1 -> 1 -> 1 + { original: 0n, code: '600160005560006000556001600055', used: 40818, refund: 19200 }, // 0 -> 1 -> 0 -> 1 + { original: 1n, code: '600060005560016000556000600055', used: 10818, refund: 19200 }, // 1 -> 0 -> 1 -> 08*/ + /*{ + original: 1n, + gas: 2306n, code: '6001600055', used: 2306, refund: 0, err: ERROR.OUT_OF_GAS, }, // 1 -> 1 (2300 sentry + 2xPUSH) - { original: new BN(1), gas: new BN(2307), code: '6001600055', used: 806, refund: 0 }, // 1 -> 1 (2301 sentry + 2xPUSH) + { original: 1n, gas: 2307n, code: '6001600055', used: 806, refund: 0 }, // 1 -> 1 (2301 sentry + 2xPUSH)*/ ] tape('Istanbul: EIP-2200', async (t) => { t.test('net-metering SSTORE', async (st) => { const caller = new Address(Buffer.from('0000000000000000000000000000000000000000', 'hex')) const addr = new Address(Buffer.from('00000000000000000000000000000000000000ff', 'hex')) - const key = new BN(0).toArrayLike(Buffer, 'be', 32) + const key = setLengthLeft(toBuffer('0x' + 0n.toString(16)), 32) + for (const testCase of testCases) { const common = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Istanbul }) const vm = new VM({ common }) @@ -46,13 +54,17 @@ tape('Istanbul: EIP-2200', async (t) => { const account = createAccount(new BN(0), new BN(0)) await vm.stateManager.putAccount(addr, account) await vm.stateManager.putContractCode(addr, Buffer.from(testCase.code, 'hex')) - if (!testCase.original.isZero()) { - await vm.stateManager.putContractStorage(addr, key, testCase.original.toArrayLike(Buffer)) + if (!(testCase.original === 0n)) { + await vm.stateManager.putContractStorage( + addr, + key, + toBuffer('0x' + testCase.original.toString(16)) + ) } const runCallArgs = { caller, - gasLimit: testCase.gas ? testCase.gas : new BN(0xffffffffff), + gasLimit: testCase.gas ? testCase.gas : BigInt(0xffffffffff), to: addr, } @@ -63,8 +75,8 @@ tape('Istanbul: EIP-2200', async (t) => { } else { st.assert(res.execResult.exceptionError === undefined) } - st.assert(new BN(testCase.used).eq(res.gasUsed)) - st.assert(new BN(testCase.refund).eq(res.execResult.gasRefund!)) + st.assert(BigInt(testCase.used) === res.gasUsed) + st.assert(BigInt(testCase.refund) === res.execResult.gasRefund!) } 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 cebadb0bfe..508d897df3 100644 --- a/packages/vm/tests/api/runBlock.spec.ts +++ b/packages/vm/tests/api/runBlock.spec.ts @@ -45,7 +45,7 @@ tape('runBlock() -> successful API parameter usage', async (t) => { }) st.equal( - res.results[0].gasUsed.toString('hex'), + res.results[0].gasUsed.toString(16), '5208', 'actual gas used should equal blockHeader gasUsed' ) @@ -172,11 +172,11 @@ tape('runBlock() -> successful API parameter usage', async (t) => { generate: true, }) st.ok( - txResultChainstart.results[0].gasUsed.toNumber() == 21000 + 68 * 3 + 3 + 50, + txResultChainstart.results[0].gasUsed === 21000n + 68n * 3n + 3n + 50n, 'tx charged right gas on chainstart hard fork' ) st.ok( - txResultMuirGlacier.results[0].gasUsed.toNumber() == 21000 + 32000 + 16 * 3 + 3 + 800, + txResultMuirGlacier.results[0].gasUsed === 21000n + 32000n + 16n * 3n + 3n + 800n, 'tx charged right gas on muir glacier hard fork' ) }) @@ -455,11 +455,16 @@ tape('runBlock() -> tx types', async (t) => { }) st.ok( - res.gasUsed.eq( + res.gasUsed === + BigInt( res.receipts .map((r) => r.gasUsed) - .reduce((prevValue: BN, currValue: Buffer) => prevValue.add(new BN(currValue)), new BN(0)) - ), + .reduce( + (prevValue: BN, currValue: Buffer) => prevValue.add(new BN(currValue)), + new BN(0) + ) + .toString(10) + ), "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 164e6fc09f..0d774ec95f 100644 --- a/packages/vm/tests/api/runCall.spec.ts +++ b/packages/vm/tests/api/runCall.spec.ts @@ -50,9 +50,9 @@ tape('Constantinople: EIP-1014 CREATE2 creates the right contract address', asyn // setup the call arguments const runCallArgs = { caller: caller, // call address - gasLimit: new BN(0xffffffffff), // ensure we pass a lot of gas, so we do not run out of gas + gasLimit: BigInt(0xffffffffff), // ensure we pass a lot of gas, so we do not run out of gas to: contractAddress, // call to the contract address - value: new BN(value), // call with this value (the value is used in the contract as an argument, see above's code) + value: BigInt(value), // call with this value (the value is used in the contract as an argument, see above's code) } const hexString = padToEven(value.toString(16)) @@ -106,7 +106,7 @@ tape('Byzantium cannot access Constantinople opcodes', async (t) => { const runCallArgs = { caller: caller, // call address - gasLimit: new BN(0xffffffffff), // ensure we pass a lot of gas, so we do not run out of gas + gasLimit: BigInt(0xffffffffff), // ensure we pass a lot of gas, so we do not run out of gas to: contractAddress, // call to the contract address } @@ -115,7 +115,7 @@ tape('Byzantium cannot access Constantinople opcodes', async (t) => { t.assert( byzantiumResult.execResult.exceptionError && - byzantiumResult.execResult.exceptionError.error === 'invalid opcode', + byzantiumResult.execResult.exceptionError.error === 'invalid opcode', 'byzantium cannot accept constantinople opcodes (SHL)' ) t.assert( @@ -158,18 +158,18 @@ tape('Ensure that precompile activation creates non-empty accounts', async (t) = // setup the call arguments const runCallArgs = { caller: caller, // call address - gasLimit: new BN(0xffffffffff), // ensure we pass a lot of gas, so we do not run out of gas + gasLimit: BigInt(0xffffffffff), // ensure we pass a lot of gas, so we do not run out of gas to: contractAddress, // call to the contract address, - value: new BN(1), + value: 1n, } const resultNotActivated = await vmNotActivated.runCall(runCallArgs) const resultActivated = await vmActivated.runCall(runCallArgs) - const diff = resultNotActivated.gasUsed.sub(resultActivated.gasUsed) - const expected = common.param('gasPrices', 'callNewAccount') + const diff = resultNotActivated.gasUsed - resultActivated.gasUsed + const expected = BigInt(common.param('gasPrices', 'callNewAccount')) - t.assert(diff.eq(new BN(expected)), 'precompiles are activated') + t.assert(diff === expected, 'precompiles are activated') t.end() }) @@ -214,13 +214,13 @@ tape('Ensure that Istanbul sstoreCleanRefundEIP2200 gas is applied correctly', a const runCallArgs = { caller: caller, // call address to: address, - gasLimit: new BN(0xffffffffff), // ensure we pass a lot of gas, so we do not run out of gas + gasLimit: BigInt(0xffffffffff), // ensure we pass a lot of gas, so we do not run out of gas } const result = await vm.runCall(runCallArgs) - t.equal(result.gasUsed.toNumber(), 5812, 'gas used correct') - t.equal(result.execResult.gasRefund!.toNumber(), 4200, 'gas refund correct') + t.equal(result.gasUsed, 5812n, 'gas used correct') + t.equal(result.execResult.gasRefund!, 4200n, 'gas refund correct') t.end() }) @@ -241,13 +241,13 @@ tape('ensure correct gas for pre-constantinople sstore', async (t) => { const runCallArgs = { caller: caller, // call address to: address, - gasLimit: new BN(0xffffffffff), // ensure we pass a lot of gas, so we do not run out of gas + gasLimit: BigInt(0xffffffffff), // ensure we pass a lot of gas, so we do not run out of gas } const result = await vm.runCall(runCallArgs) - t.equal(result.gasUsed.toNumber(), 20006, 'gas used correct') - t.equal(result.execResult.gasRefund!.toNumber(), 0, 'gas refund correct') + t.equal(result.gasUsed, 20006n, 'gas used correct') + t.equal(result.execResult.gasRefund!, 0n, 'gas refund correct') t.end() }) @@ -268,15 +268,15 @@ tape('ensure correct gas for calling non-existent accounts in homestead', async const runCallArgs = { caller: caller, // call address to: address, - gasLimit: new BN(0xffffffffff), // ensure we pass a lot of gas, so we do not run out of gas + gasLimit: BigInt(0xffffffffff), // ensure we pass a lot of gas, so we do not run out of gas } const result = await vm.runCall(runCallArgs) // 7x push + gas + sub + call + callNewAccount // 7*3 + 2 + 3 + 40 + 25000 = 25066 - t.equal(result.gasUsed.toNumber(), 25066, 'gas used correct') - t.equal(result.execResult.gasRefund!.toNumber(), 0, 'gas refund correct') + t.equal(result.gasUsed, 25066n, 'gas used correct') + t.equal(result.execResult.gasRefund!, 0n, 'gas refund correct') t.end() }) @@ -300,13 +300,13 @@ tape( const runCallArgs = { caller: caller, // call address to: address, - gasLimit: new BN(200), + gasLimit: 200n, } const result = await vm.runCall(runCallArgs) - t.ok(runCallArgs.gasLimit.eq(result.gasUsed), 'gas used correct') - t.equal(result.execResult.gasRefund!.toNumber(), 0, 'gas refund correct') + t.ok(runCallArgs.gasLimit === result.gasUsed, 'gas used correct') + t.equal(result.execResult.gasRefund!, 0n, 'gas refund correct') t.ok(result.execResult.exceptionError!.error == ERROR.OUT_OF_GAS, 'call went out of gas') t.end() @@ -331,14 +331,14 @@ tape('ensure selfdestruct pays for creating new accounts', async (t) => { const runCallArgs = { caller: caller, // call address to: address, - gasLimit: new BN(0xffffffffff), + gasLimit: BigInt(0xffffffffff), } const result = await vm.runCall(runCallArgs) // gas: 5000 (selfdestruct) + 25000 (call new account) + push (1) = 30003 - t.equal(result.gasUsed.toNumber(), 30003, 'gas used correct') + t.equal(result.gasUsed, 30003n, 'gas used correct') // selfdestruct refund - t.equal(result.execResult.gasRefund!.toNumber(), 24000, 'gas refund correct') + t.equal(result.execResult.gasRefund!, 24000n, 'gas refund correct') t.end() }) @@ -397,13 +397,13 @@ tape('ensure that sstores pay for the right gas costs pre-byzantium', async (t) const runCallArgs = { caller: caller, // call address to: address, - gasLimit: new BN(0xffffffffff), - value: new BN(callData.value), + gasLimit: BigInt(0xffffffffff), + value: BigInt(callData.value), } const result = await vm.runCall(runCallArgs) - t.equal(result.gasUsed.toNumber(), callData.gas, 'gas used correct') - t.equal(result.execResult.gasRefund?.toNumber(), callData.refund, 'gas refund correct') + t.equal(result.gasUsed, BigInt(callData.gas), 'gas used correct') + t.equal(result.execResult.gasRefund, BigInt(callData.refund), 'gas refund correct') } t.end() @@ -443,7 +443,7 @@ tape( const runCallArgs = { caller: caller, // call address to: address, - gasLimit: new BN(0xffffffffff), // ensure we pass a lot of gas, so we do not run out of gas + gasLimit: BigInt(0xffffffffff), // ensure we pass a lot of gas, so we do not run out of gas } await vm.runCall(runCallArgs) @@ -484,9 +484,9 @@ tape('Ensure that IDENTITY precompile copies the memory', async (t) => { // setup the call arguments const runCallArgs = { caller: caller, // call address - gasLimit: new BN(150000), + gasLimit: 150000n, data: Buffer.from(code, 'hex'), - gasPrice: new BN(70000000000), + gasPrice: 70000000000n, } const result = await vm.runCall(runCallArgs) @@ -511,7 +511,7 @@ tape('Throws on negative call value', async (t) => { // setup the call arguments const runCallArgs = { - value: new BN(-10), + value: -10n, } try { diff --git a/packages/vm/tests/api/runCode.spec.ts b/packages/vm/tests/api/runCode.spec.ts index 192fc6a434..dee84d4bd4 100644 --- a/packages/vm/tests/api/runCode.spec.ts +++ b/packages/vm/tests/api/runCode.spec.ts @@ -1,5 +1,4 @@ import tape from 'tape' -import { BN } from 'ethereumjs-util' import VM from '../../src' import { DefaultStateManager } from '../../src/state' @@ -27,7 +26,7 @@ tape('VM.runCode: initial program counter', (t) => { const runCodeArgs = { code: Buffer.from(testData.code.join(''), 'hex'), pc: testData.pc, - gasLimit: new BN(0xffff), + gasLimit: BigInt(0xffff), } let err @@ -59,7 +58,7 @@ tape('VM.runCode: interpreter', (t) => { const INVALID_opcode = 'fe' const runCodeArgs = { code: Buffer.from(INVALID_opcode, 'hex'), - gasLimit: new BN(0xffff), + gasLimit: BigInt(0xffff), } let result: any @@ -83,7 +82,7 @@ tape('VM.runCode: interpreter', (t) => { const SSTORE = '55' const runCodeArgs = { code: Buffer.from([PUSH1, '01', PUSH1, '05', SSTORE].join(''), 'hex'), - gasLimit: new BN(0xffff), + gasLimit: BigInt(0xffff), } try { @@ -101,7 +100,7 @@ tape('VM.runCode: RunCodeOptions', (t) => { const vm = new VM() const runCodeArgs = { - value: new BN('-10'), + value: -10n, } try { diff --git a/packages/vm/tests/api/runTx.spec.ts b/packages/vm/tests/api/runTx.spec.ts index 0f84dcf6f5..b9d3fc7577 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, BN, MAX_INTEGER } from 'ethereumjs-util' +import { Account, Address, BN, bufferToHex, MAX_INTEGER, toBuffer } from 'ethereumjs-util' import { Block } from '@ethereumjs/block' import Common, { Chain, Hardfork } from '@ethereumjs/common' import { Transaction, TransactionFactory, FeeMarketEIP1559Transaction } from '@ethereumjs/tx' @@ -34,7 +34,7 @@ tape('runTx() -> successful API parameter usage', async (t) => { await vm.stateManager.putAccount(caller, acc) const res = await vm.runTx({ tx }) - st.true(res.gasUsed.gt(new BN(0)), `${msg} (${txType.name})`) + st.true(res.gasUsed > 0n, `${msg} (${txType.name})`) } } @@ -60,10 +60,10 @@ tape('runTx() -> successful API parameter usage', async (t) => { const acc = createAccount() await vm.stateManager.putAccount(caller, acc) - const blockGasUsed = new BN(1000) + const blockGasUsed = 1000n const res = await vm.runTx({ tx, blockGasUsed }) t.ok( - new BN(res.receipt.gasUsed).eq(blockGasUsed.add(res.gasUsed)), + BigInt(bufferToHex(res.receipt.gasUsed)) === blockGasUsed + res.gasUsed, 'receipt.gasUsed should equal block gas used + tx gas used' ) t.end() @@ -81,7 +81,7 @@ tape('runTx() -> successful API parameter usage', async (t) => { const res = await vm.runTx({ tx }) t.true( - res.gasUsed.gt(new BN(0)), + res.gasUsed > 0n, `mainnet (PoW), istanbul HF, default SM - should run without errors (${TRANSACTION_TYPES[0].name})` ) @@ -146,14 +146,14 @@ tape('runTx() -> successful API parameter usage', async (t) => { const baseFee = block.header.baseFeePerGas! const inclusionFeePerGas = tx instanceof FeeMarketEIP1559Transaction - ? BN.min(tx.maxPriorityFeePerGas, tx.maxFeePerGas.sub(baseFee)) - : tx.gasPrice.sub(baseFee) + ? BigInt(BN.min(tx.maxPriorityFeePerGas, tx.maxFeePerGas.sub(baseFee)).toString(10)) + : BigInt(tx.gasPrice.sub(baseFee).toString(10)) const expectedCoinbaseBalance = common.isActivatedEIP(1559) - ? result.gasUsed.mul(inclusionFeePerGas) + ? result.gasUsed * inclusionFeePerGas : result.amountSpent t.ok( - coinbaseAccount.balance.eq(expectedCoinbaseBalance), + BigInt(coinbaseAccount.balance.toString(10)) === expectedCoinbaseBalance, `should use custom block (${txType.name})` ) @@ -208,7 +208,7 @@ tape('runTx() -> API parameter usage/data errors', (t) => { const res = await vm.runTx({ tx, reportAccessList: true }) t.true( - res.gasUsed.gt(new BN(0)), + res.gasUsed > 0n, `mainnet (PoW), istanbul HF, default SM - should run without errors (${TRANSACTION_TYPES[0].name})` ) t.deepEqual(res.accessList, []) @@ -443,7 +443,7 @@ tape('runTx() -> API return values', async (t) => { await vm.stateManager.putAccount(caller, acc) const res = await vm.runTx({ tx }) - t.true(res.execResult.gasUsed.eqn(0), `execution result -> gasUsed -> 0 (${txType.name})`) + t.true(res.execResult.gasUsed === 0n, `execution result -> gasUsed -> 0 (${txType.name})`) t.equal( res.execResult.exceptionError, undefined, @@ -455,7 +455,7 @@ tape('runTx() -> API return values', async (t) => { `execution result -> return value -> empty Buffer (${txType.name})` ) t.true( - res.execResult.gasRefund!.eqn(0), + res.execResult.gasRefund! === 0n, `execution result -> gasRefund -> 0 (${txType.name})` ) } @@ -475,22 +475,22 @@ tape('runTx() -> API return values', async (t) => { t.deepEqual( res.gasUsed, - tx.getBaseFee(), + BigInt(tx.getBaseFee().toString(10)), `runTx result -> gasUsed -> tx.getBaseFee() (${txType.name})` ) if (tx instanceof FeeMarketEIP1559Transaction) { const baseFee = new BN(7) const inclusionFeePerGas = BN.min(tx.maxPriorityFeePerGas, tx.maxFeePerGas.sub(baseFee)) - const gasPrice = inclusionFeePerGas.add(baseFee) - t.deepEqual( + const gasPrice = BigInt(inclusionFeePerGas.toString(10)) + BigInt(baseFee.toString(10)) + t.deepEquals( res.amountSpent, - res.gasUsed.mul(gasPrice), + res.gasUsed * gasPrice, `runTx result -> amountSpent -> gasUsed * gasPrice (${txType.name})` ) } else { t.deepEqual( res.amountSpent, - res.gasUsed.mul((tx).gasPrice), + res.gasUsed * BigInt((tx).gasPrice.toString(10)), `runTx result -> amountSpent -> gasUsed * gasPrice (${txType.name})` ) } @@ -502,7 +502,7 @@ tape('runTx() -> API return values', async (t) => { ) t.deepEqual( res.receipt.gasUsed, - res.gasUsed.toArrayLike(Buffer), + toBuffer('0x' + res.gasUsed.toString(16)), `runTx result -> receipt.gasUsed -> result.gasUsed as Buffer (${txType.name})` ) t.deepEqual( diff --git a/packages/vm/tests/api/state/accountExists.spec.ts b/packages/vm/tests/api/state/accountExists.spec.ts index 7f158f135b..94eef0d6e5 100644 --- a/packages/vm/tests/api/state/accountExists.spec.ts +++ b/packages/vm/tests/api/state/accountExists.spec.ts @@ -32,17 +32,17 @@ tape('correctly apply new account gas fee on pre-Spurious Dragon hardforks', asy // setup the call arguments const runCallArgs = { caller: caller, // call address - gasLimit: new BN(174146 - 22872), // tx gas limit minus the tx fee (21000) and data fee (1872) to represent correct gas costs + gasLimit: BigInt(174146 - 22872), // tx gas limit minus the tx fee (21000) and data fee (1872) to represent correct gas costs data: Buffer.from( 'a9059cbb000000000000000000000000f48a1bdc65d9ccb4b569ffd4bffff415b90783d60000000000000000000000000000000000000000000000000000000000000001', 'hex' ), to: contractAddress, // call to the contract address - value: new BN(0), + value: 0n, } const result = await vm.runCall(runCallArgs) - t.ok(result.gasUsed.toNumber() === 53552, 'vm correctly applies new account gas price') + t.ok(result.gasUsed === 53552n, 'vm correctly applies new account gas price') t.end() }) @@ -77,20 +77,17 @@ tape( // setup the call arguments const runCallArgs = { caller: caller, // call address - gasLimit: new BN(174146 - 22872), // tx gas limit minus the tx fee (21000) and data fee (1872) to represent correct gas costs + gasLimit: BigInt(174146 - 22872), // tx gas limit minus the tx fee (21000) and data fee (1872) to represent correct gas costs data: Buffer.from( 'a9059cbb000000000000000000000000f48a1bdc65d9ccb4b569ffd4bffff415b90783d60000000000000000000000000000000000000000000000000000000000000001', 'hex' ), to: contractAddress, // call to the contract address - value: new BN(0), + value: 0n, } const result = await vm.runCall(runCallArgs) - t.ok( - result.gasUsed.toNumber() === 28552, - 'new account price not applied as empty account exists' - ) + t.ok(result.gasUsed === 28552n, 'new account price not applied as empty account exists') t.end() } ) diff --git a/packages/vm/tests/tester/runners/BlockchainTestsRunner.ts b/packages/vm/tests/tester/runners/BlockchainTestsRunner.ts index 724099cdfb..a963397610 100644 --- a/packages/vm/tests/tester/runners/BlockchainTestsRunner.ts +++ b/packages/vm/tests/tester/runners/BlockchainTestsRunner.ts @@ -3,7 +3,7 @@ import { Block } from '@ethereumjs/block' import Blockchain from '@ethereumjs/blockchain' import Common, { ConsensusAlgorithm } from '@ethereumjs/common' import { TransactionFactory } from '@ethereumjs/tx' -import { addHexPrefix, BN, toBuffer, rlp, stripHexPrefix } from 'ethereumjs-util' +import { addHexPrefix, toBuffer, rlp, bufferToHex } from 'ethereumjs-util' import { SecureTrie as Trie } from 'merkle-patricia-tree' import { setupPreConditions, verifyPostConditions } from '../../util' @@ -91,7 +91,7 @@ export default async function runBlockchainTest(options: any, testData: any, t: } } - let currentBlock = new BN(0) + let currentBlock = 0n for (const raw of testData.blocks) { const paramFork = `expectException${options.forkConfigTestSuite}` // Two naming conventions in ethereum/tests to indicate "exception occurs on all HFs" semantics @@ -107,7 +107,7 @@ export default async function runBlockchainTest(options: any, testData: any, t: try { const blockRlp = Buffer.from(raw.rlp.slice(2), 'hex') const decodedRLP: any = rlp.decode(blockRlp) - currentBlock = new BN(decodedRLP[0][8]) + currentBlock = BigInt(bufferToHex(decodedRLP[0][8])) } catch (e: any) { await handleError(e, expectException) continue @@ -115,7 +115,7 @@ export default async function runBlockchainTest(options: any, testData: any, t: try { // Update common HF - common.setHardforkByBlockNumber(currentBlock.toNumber()) + common.setHardforkByBlockNumber(Number(currentBlock)) // transactionSequence is provided when txs are expected to be rejected. // To run this field we try to import them on the current state. @@ -182,7 +182,7 @@ export default async function runBlockchainTest(options: any, testData: any, t: await verifyPostConditions(state, testData.postState, t) } // caught an error, reduce block number - currentBlock.isubn(1) + currentBlock-- await handleError(error, expectException) } } diff --git a/packages/vm/tests/tester/runners/GeneralStateTestsRunner.ts b/packages/vm/tests/tester/runners/GeneralStateTestsRunner.ts index f68341f9ed..ea145dcf66 100644 --- a/packages/vm/tests/tester/runners/GeneralStateTestsRunner.ts +++ b/packages/vm/tests/tester/runners/GeneralStateTestsRunner.ts @@ -1,7 +1,7 @@ import tape from 'tape' import Common, { Chain } from '@ethereumjs/common' import { SecureTrie as Trie } from 'merkle-patricia-tree' -import { BN, toBuffer } from 'ethereumjs-util' +import { toBuffer } from 'ethereumjs-util' import { setupPreConditions, makeTx, makeBlockFromEnv } from '../../util' import type { InterpreterStep } from '../../../src/evm/interpreter' @@ -93,14 +93,14 @@ async function runTestCase(options: any, testData: any, t: tape.Test) { if (options.jsontrace) { vm.on('step', function (e: InterpreterStep) { let hexStack = [] - hexStack = e.stack.map((item: any) => { - return '0x' + new BN(item).toString(16, 0) + hexStack = e.stack.map((item: bigint) => { + return '0x' + item.toString(16) }) const opTrace = { pc: e.pc, op: e.opcode.name, - gas: '0x' + e.gasLeft.toString('hex'), + gas: '0x' + e.gasLeft.toString(16), gasCost: '0x' + e.opcode.fee.toString(16), stack: hexStack, depth: e.depth, diff --git a/packages/vm/tsconfig.json b/packages/vm/tsconfig.json index 4ea13e1eb2..279de0b101 100644 --- a/packages/vm/tsconfig.json +++ b/packages/vm/tsconfig.json @@ -1,4 +1,7 @@ { "extends": "../../config/tsconfig.json", - "include": ["src/**/*.ts", "src/**/*.json", "tests/**/*.ts"] + "include": ["src/**/*.ts", "src/**/*.json", "tests/**/*.ts"], + "compilerOptions" : { + "target": "ES2020" + } } \ No newline at end of file diff --git a/packages/vm/tsconfig.prod.json b/packages/vm/tsconfig.prod.json index 16ead5ecbf..bdf9036f2f 100644 --- a/packages/vm/tsconfig.prod.json +++ b/packages/vm/tsconfig.prod.json @@ -3,7 +3,8 @@ "compilerOptions": { "rootDir": "./src", "outDir": "./dist", - "lib": ["dom"], + "target": "es2020", + "lib":["ES2020.BigInt"], "composite": true, }, "include": ["src/**/*.ts", "src/**/*.json"], From b1e0b32985d12576ab75988c4a68c972e7a0ecca Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Thu, 27 Jan 2022 14:07:36 -0500 Subject: [PATCH 02/42] Fix byteLength computation in EXP handler --- packages/vm/src/evm/opcodes/functions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vm/src/evm/opcodes/functions.ts b/packages/vm/src/evm/opcodes/functions.ts index 9f87bae9ad..b1df4c17cc 100644 --- a/packages/vm/src/evm/opcodes/functions.ts +++ b/packages/vm/src/evm/opcodes/functions.ts @@ -167,7 +167,7 @@ export const handlers: Map = new Map([ runState.stack.push(1n) return } - const byteLength = exponent.toString(2).length / 8 + const byteLength = exponent.toString(16).length if (byteLength < 1 || byteLength > 32) { trap(ERROR.OUT_OF_RANGE) } From 32525457b4b0a496891600117fd6ab9066a6b491 Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Thu, 27 Jan 2022 15:14:35 -0500 Subject: [PATCH 03/42] Fix toTwos helper --- packages/vm/src/evm/opcodes/util.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vm/src/evm/opcodes/util.ts b/packages/vm/src/evm/opcodes/util.ts index ebaa787725..fd3b20c974 100644 --- a/packages/vm/src/evm/opcodes/util.ts +++ b/packages/vm/src/evm/opcodes/util.ts @@ -280,7 +280,7 @@ export function fromTwos(a: bigint) { } export function toTwos(a: bigint) { - return BigInt.asUintN(256, ~a) + 1n + return BigInt.asUintN(256, ~a + 1n) } export function abs(a: bigint) { From d04c9298c2480fe74df3f41744ce6c102af1b1aa Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Thu, 27 Jan 2022 15:50:52 -0500 Subject: [PATCH 04/42] Compute TWO_POWE256 using math instead of hex --- packages/util/src/constants.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/util/src/constants.ts b/packages/util/src/constants.ts index b3fc553deb..58e71ae493 100644 --- a/packages/util/src/constants.ts +++ b/packages/util/src/constants.ts @@ -32,8 +32,7 @@ export const TWO_POW256 = new BN( /** * 2^256 */ -export const TWO_POW256_BIGINT = - BigInt(0x10000000000000000000000000000000000000000000000000000000000000000) +export const TWO_POW256_BIGINT = 2n ** 256n /** * Keccak-256 hash of null From b063cd7adf63c383ab6e6f9f3b48b62290885dd6 Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Thu, 27 Jan 2022 15:52:32 -0500 Subject: [PATCH 05/42] Update packages/util/src/constants.ts Co-authored-by: Ryan Ghods --- packages/util/src/constants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/util/src/constants.ts b/packages/util/src/constants.ts index 58e71ae493..ce323d7d01 100644 --- a/packages/util/src/constants.ts +++ b/packages/util/src/constants.ts @@ -22,7 +22,7 @@ export const MAX_INTEGER_BIGINT = 2n ** 256n - 1n /** * 2^256 * - * @deprecated + * @deprecated bn.js constants are deprecated, please use the newly introduced bigint constants */ export const TWO_POW256 = new BN( '10000000000000000000000000000000000000000000000000000000000000000', From 85243655deb4d0973abd70641a860e6648ad2d7b Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Thu, 27 Jan 2022 16:51:16 -0500 Subject: [PATCH 06/42] Remove unused variable --- packages/vm/src/buildBlock.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/vm/src/buildBlock.ts b/packages/vm/src/buildBlock.ts index 645c33519e..6e1d1fd252 100644 --- a/packages/vm/src/buildBlock.ts +++ b/packages/vm/src/buildBlock.ts @@ -132,11 +132,9 @@ export class BlockBuilder { * Calculates and returns the receiptTrie for the block. */ private async receiptTrie() { - let _gasUsed = 0n const receiptTrie = new Trie() for (const [i, txResult] of this.transactionResults.entries()) { const tx = this.transactions[i] - _gasUsed += txResult.gasUsed const encodedReceipt = encodeReceipt(tx, txResult.receipt) await receiptTrie.put(rlp.encode(i), encodedReceipt) } From 79d176288eb221f9e053e40f3f52bfb81ae0bd1f Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Thu, 27 Jan 2022 17:13:51 -0500 Subject: [PATCH 07/42] Fix exponent byte length calc --- packages/vm/src/evm/opcodes/functions.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/vm/src/evm/opcodes/functions.ts b/packages/vm/src/evm/opcodes/functions.ts index b1df4c17cc..390b87158c 100644 --- a/packages/vm/src/evm/opcodes/functions.ts +++ b/packages/vm/src/evm/opcodes/functions.ts @@ -167,7 +167,10 @@ export const handlers: Map = new Map([ runState.stack.push(1n) return } - const byteLength = exponent.toString(16).length + let byteLength = exponent.toString(2).length / 8 + if (byteLength > Math.trunc(byteLength)) { + byteLength = Math.trunc(byteLength) + 1 + } if (byteLength < 1 || byteLength > 32) { trap(ERROR.OUT_OF_RANGE) } From c63db90ae60ebfa95a7bdeaa21ef7d4271a77ec7 Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Thu, 27 Jan 2022 19:59:50 -0500 Subject: [PATCH 08/42] Fix exp overflow --- packages/vm/src/evm/opcodes/functions.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/vm/src/evm/opcodes/functions.ts b/packages/vm/src/evm/opcodes/functions.ts index 390b87158c..ebe800e607 100644 --- a/packages/vm/src/evm/opcodes/functions.ts +++ b/packages/vm/src/evm/opcodes/functions.ts @@ -182,8 +182,13 @@ export const handlers: Map = new Map([ runState.stack.push(base) return } - const r = base ** exponent - runState.stack.push(r) + try { + const r = BigInt.asUintN(256, base ** exponent) + runState.stack.push(r) + } catch (err) { + // Push 0 to stack (i.e. overflow) if operation exceeds maximum system supported bigint size + runState.stack.push(0n) + } }, ], // 0x0b: SIGNEXTEND From c52b9e47a18e26d3dd0c9c1f1688af10b41cd5cb Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Fri, 28 Jan 2022 09:55:04 -0500 Subject: [PATCH 09/42] Fix precompile bigint conversions --- packages/vm/src/evm/opcodes/util.ts | 10 +++++++++- packages/vm/src/evm/precompiles/05-modexp.ts | 19 +++++++------------ 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/packages/vm/src/evm/opcodes/util.ts b/packages/vm/src/evm/opcodes/util.ts index fd3b20c974..63023e1aef 100644 --- a/packages/vm/src/evm/opcodes/util.ts +++ b/packages/vm/src/evm/opcodes/util.ts @@ -1,5 +1,5 @@ import Common from '@ethereumjs/common' -import { keccak256, setLengthRight, setLengthLeft, toBuffer } from 'ethereumjs-util' +import { keccak256, setLengthRight, setLengthLeft, toBuffer, bufferToHex } from 'ethereumjs-util' import { ERROR, VmError } from './../../exceptions' import { RunState } from './../interpreter' @@ -289,3 +289,11 @@ export function abs(a: bigint) { } return a * -1n } + +export function bufferToBigInt(buf: Buffer) { + const hex = bufferToHex(buf) + if (hex === '0x') { + return 0n + } + return BigInt(hex) +} diff --git a/packages/vm/src/evm/precompiles/05-modexp.ts b/packages/vm/src/evm/precompiles/05-modexp.ts index fa2be68c81..b283a4bc55 100644 --- a/packages/vm/src/evm/precompiles/05-modexp.ts +++ b/packages/vm/src/evm/precompiles/05-modexp.ts @@ -1,6 +1,7 @@ import { setLengthRight, bufferToHex, toBuffer, setLengthLeft } from 'ethereumjs-util' import { PrecompileInput } from './types' import { OOGResult, ExecResult } from '../evm' +import { bufferToBigInt } from '../opcodes' const assert = require('assert') function multComplexity(x: bigint): bigint { @@ -81,9 +82,9 @@ export default function (opts: PrecompileInput): ExecResult { adjustedELen = 1n } - const bLen = BigInt(bufferToHex(data.slice(0, 32))) - const eLen = BigInt(bufferToHex(data.slice(32, 64))) - const mLen = BigInt(bufferToHex(data.slice(64, 96))) + const bLen = bufferToBigInt(data.slice(0, 32)) + const eLen = bufferToBigInt(data.slice(32, 64)) + const mLen = bufferToBigInt(data.slice(64, 96)) let maxLen = bLen if (maxLen < mLen) { @@ -133,15 +134,9 @@ export default function (opts: PrecompileInput): ExecResult { return OOGResult(opts.gasLimit) } - const B = BigInt( - bufferToHex(setLengthRight(data.slice(Number(bStart), Number(bEnd)), Number(bLen))) - ) - const E = BigInt( - bufferToHex(setLengthRight(data.slice(Number(eStart), Number(eEnd)), Number(eLen))) - ) - const M = BigInt( - bufferToHex(setLengthRight(data.slice(Number(mStart), Number(mEnd)), Number(mLen))) - ) + const B = bufferToBigInt(setLengthRight(data.slice(Number(bStart), Number(bEnd)), Number(bLen))) + const E = bufferToBigInt(setLengthRight(data.slice(Number(eStart), Number(eEnd)), Number(eLen))) + const M = bufferToBigInt(setLengthRight(data.slice(Number(mStart), Number(mEnd)), Number(mLen))) if (mEnd > maxInt) { return OOGResult(opts.gasLimit) From 74ce8388113717a4e0779bbc888d1870f2b200b9 Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Fri, 28 Jan 2022 10:16:13 -0500 Subject: [PATCH 10/42] Fix more bigint conversions --- packages/vm/src/evm/precompiles/05-modexp.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/vm/src/evm/precompiles/05-modexp.ts b/packages/vm/src/evm/precompiles/05-modexp.ts index b283a4bc55..4d1f3e4c91 100644 --- a/packages/vm/src/evm/precompiles/05-modexp.ts +++ b/packages/vm/src/evm/precompiles/05-modexp.ts @@ -1,4 +1,4 @@ -import { setLengthRight, bufferToHex, toBuffer, setLengthLeft } from 'ethereumjs-util' +import { setLengthRight, toBuffer, setLengthLeft } from 'ethereumjs-util' import { PrecompileInput } from './types' import { OOGResult, ExecResult } from '../evm' import { bufferToBigInt } from '../opcodes' @@ -30,15 +30,15 @@ function multComplexityEIP2565(x: bigint): bigint { function getAdjustedExponentLength(data: Buffer): bigint { let expBytesStart try { - const baseLen = BigInt(bufferToHex(data.slice(0, 32))) + const baseLen = bufferToBigInt(data.slice(0, 32)) expBytesStart = 96 + Number(baseLen) // 96 for base length, then exponent length, and modulus length, then baseLen for the base data, then exponent bytes start } catch (e: any) { expBytesStart = Number.MAX_SAFE_INTEGER - 32 } - const expLen = BigInt(bufferToHex(data.slice(32, 64))) + const expLen = bufferToBigInt(data.slice(32, 64)) let firstExpBytes = Buffer.from(data.slice(expBytesStart, expBytesStart + 32)) // first word of the exponent data firstExpBytes = setLengthRight(firstExpBytes, 32) // reading past the data reads virtual zeros - let firstExpBigInt = BigInt(bufferToHex(firstExpBytes)) + let firstExpBigInt = bufferToBigInt(firstExpBytes) let max32expLen = 0 if (expLen < 32n) { max32expLen = 32 - Number(expLen) From 69ca2b7953ef869f30a61b26f09f98ed743f282f Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Fri, 28 Jan 2022 12:08:53 -0500 Subject: [PATCH 11/42] Fix EXP opcode handler --- packages/vm/src/evm/opcodes/functions.ts | 10 +++------- packages/vm/src/evm/opcodes/util.ts | 13 +++++++++++++ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/packages/vm/src/evm/opcodes/functions.ts b/packages/vm/src/evm/opcodes/functions.ts index ebe800e607..ed45dfb627 100644 --- a/packages/vm/src/evm/opcodes/functions.ts +++ b/packages/vm/src/evm/opcodes/functions.ts @@ -24,6 +24,7 @@ import { } from './util' import { ERROR } from '../../exceptions' import { RunState } from './../interpreter' +import { exponentation } from '.' export interface SyncOpHandler { (runState: RunState, common: Common): void @@ -182,13 +183,8 @@ export const handlers: Map = new Map([ runState.stack.push(base) return } - try { - const r = BigInt.asUintN(256, base ** exponent) - runState.stack.push(r) - } catch (err) { - // Push 0 to stack (i.e. overflow) if operation exceeds maximum system supported bigint size - runState.stack.push(0n) - } + const r = exponentation(base, exponent) + runState.stack.push(r) }, ], // 0x0b: SIGNEXTEND diff --git a/packages/vm/src/evm/opcodes/util.ts b/packages/vm/src/evm/opcodes/util.ts index 63023e1aef..16b005031c 100644 --- a/packages/vm/src/evm/opcodes/util.ts +++ b/packages/vm/src/evm/opcodes/util.ts @@ -297,3 +297,16 @@ export function bufferToBigInt(buf: Buffer) { } return BigInt(hex) } + +const N = 115792089237316195423570985008687907853269984665640564039457584007913129639936n +export function exponentation(bas: bigint, exp: bigint) { + let t = 1n + while (exp > 0n) { + if (exp % 2n != 0n) { + t = (t * bas) % N + } + bas = (bas * bas) % N + exp = exp / 2n + } + return t +} From f058ad4c4b93e149aecfc6036e5813e506cce02c Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Fri, 28 Jan 2022 12:22:49 -0500 Subject: [PATCH 12/42] Fix logic bug in signextend --- packages/vm/src/evm/opcodes/functions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vm/src/evm/opcodes/functions.ts b/packages/vm/src/evm/opcodes/functions.ts index ed45dfb627..e6f7159f9d 100644 --- a/packages/vm/src/evm/opcodes/functions.ts +++ b/packages/vm/src/evm/opcodes/functions.ts @@ -193,7 +193,7 @@ export const handlers: Map = new Map([ function (runState) { /* eslint-disable-next-line prefer-const */ let [k, val] = runState.stack.popN(2) - if (k > 31n) { + if (k < 31n) { const signBit = k * 8n + 7n const mask = (1n << signBit) - 1n if (val.toString(2)[Number(signBit)] === '1') { From 3b44909fcb39ce706c2d9046eadfd24c6a705e95 Mon Sep 17 00:00:00 2001 From: Jochem Brouwer Date: Mon, 31 Jan 2022 21:27:59 +0100 Subject: [PATCH 13/42] vm/gas: fix EXTCODECOPY gas --- packages/vm/src/evm/opcodes/gas.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vm/src/evm/opcodes/gas.ts b/packages/vm/src/evm/opcodes/gas.ts index 23483957ff..0556f4685a 100644 --- a/packages/vm/src/evm/opcodes/gas.ts +++ b/packages/vm/src/evm/opcodes/gas.ts @@ -106,7 +106,7 @@ export const dynamicGasHandlers: Map = new Map< } if (!(dataLength === 0n)) { - gas = (gas + BigInt(common.param('gasPrices', 'copy'))) * divCeil(dataLength, 32n) + gas += BigInt(common.param('gasPrices', 'copy')) * divCeil(dataLength, 32n) } return gas }, From f217873858d854301717f0916ef86ad8e44fff08 Mon Sep 17 00:00:00 2001 From: Jochem Brouwer Date: Mon, 31 Jan 2022 22:13:53 +0100 Subject: [PATCH 14/42] vm/gas: fix sha256 gas --- packages/vm/src/evm/precompiles/02-sha256.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vm/src/evm/precompiles/02-sha256.ts b/packages/vm/src/evm/precompiles/02-sha256.ts index 19a724bb2b..6db7606188 100644 --- a/packages/vm/src/evm/precompiles/02-sha256.ts +++ b/packages/vm/src/evm/precompiles/02-sha256.ts @@ -9,7 +9,7 @@ export default function (opts: PrecompileInput): ExecResult { const data = opts.data const gasUsed = BigInt(opts._common.param('gasPrices', 'sha256')) - gasUsed + + gasUsed += BigInt(opts._common.param('gasPrices', 'sha256Word')) * BigInt(Math.ceil(data.length / 32)) if (opts.gasLimit < gasUsed) { From 0b78dba6895d7285225e73653e0942f6d6cfc607 Mon Sep 17 00:00:00 2001 From: Jochem Brouwer Date: Mon, 31 Jan 2022 22:27:27 +0100 Subject: [PATCH 15/42] vm/gas: sha256 const -> let --- packages/vm/src/evm/precompiles/02-sha256.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vm/src/evm/precompiles/02-sha256.ts b/packages/vm/src/evm/precompiles/02-sha256.ts index 6db7606188..6779547aec 100644 --- a/packages/vm/src/evm/precompiles/02-sha256.ts +++ b/packages/vm/src/evm/precompiles/02-sha256.ts @@ -8,7 +8,7 @@ export default function (opts: PrecompileInput): ExecResult { const data = opts.data - const gasUsed = BigInt(opts._common.param('gasPrices', 'sha256')) + let gasUsed = BigInt(opts._common.param('gasPrices', 'sha256')) gasUsed += BigInt(opts._common.param('gasPrices', 'sha256Word')) * BigInt(Math.ceil(data.length / 32)) From 02c0d06e252bd30df211c484883f233052ce787a Mon Sep 17 00:00:00 2001 From: Jochem Brouwer Date: Mon, 31 Jan 2022 22:27:47 +0100 Subject: [PATCH 16/42] vm: lint --- packages/vm/src/evm/evm.ts | 10 +++++----- packages/vm/tests/api/EIPs/eip-3529.spec.ts | 3 +-- packages/vm/tests/api/istanbul/eip-1884.spec.ts | 2 +- packages/vm/tests/api/istanbul/eip-2200.spec.ts | 1 - packages/vm/tests/api/runBlock.spec.ts | 6 +++--- packages/vm/tests/api/runCall.spec.ts | 2 +- 6 files changed, 11 insertions(+), 13 deletions(-) diff --git a/packages/vm/src/evm/evm.ts b/packages/vm/src/evm/evm.ts index b7893f4aa6..7695fec1e5 100644 --- a/packages/vm/src/evm/evm.ts +++ b/packages/vm/src/evm/evm.ts @@ -183,11 +183,11 @@ export default class EVM { `Received message results gasUsed=${result.gasUsed} execResult: [ gasUsed=${ result.gasUsed } exceptionError=${ - result.execResult.exceptionError - ? result.execResult.exceptionError.errorType + - ' ' + - result.execResult.exceptionError.error - : '' + result.execResult.exceptionError + ? result.execResult.exceptionError.errorType + + ' ' + + result.execResult.exceptionError.error + : '' } returnValue=${short(result.execResult.returnValue)} gasRefund=${ result.execResult.gasRefund } ]` diff --git a/packages/vm/tests/api/EIPs/eip-3529.spec.ts b/packages/vm/tests/api/EIPs/eip-3529.spec.ts index 765f6bcbe0..8bc5c7b2e1 100644 --- a/packages/vm/tests/api/EIPs/eip-3529.spec.ts +++ b/packages/vm/tests/api/EIPs/eip-3529.spec.ts @@ -1,5 +1,5 @@ import tape from 'tape' -import { Address, BN } from 'ethereumjs-util' +import { Address } from 'ethereumjs-util' import VM from '../../../src' import Common, { Chain, Hardfork } from '@ethereumjs/common' import { InterpreterStep } from '../../../src/evm/interpreter' @@ -225,7 +225,6 @@ tape('EIP-3529 tests', (t) => { const maxRefund = actualGasUsed / 5n const minGasUsed = actualGasUsed - maxRefund const gasUsed = result.execResult.gasUsed - console.log(result.execResult.gasRefund, maxRefund) 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.end() diff --git a/packages/vm/tests/api/istanbul/eip-1884.spec.ts b/packages/vm/tests/api/istanbul/eip-1884.spec.ts index 660c63310a..2e0e1ec510 100644 --- a/packages/vm/tests/api/istanbul/eip-1884.spec.ts +++ b/packages/vm/tests/api/istanbul/eip-1884.spec.ts @@ -41,7 +41,7 @@ tape('Istanbul: EIP-1884', async (t) => { st.assert(res.exceptionError === undefined) st.assert( BigInt(testCase.selfbalance) === - BigInt(bufferToHex(res.returnValue) === '0x' ? 0 : bufferToHex(res.returnValue)) + BigInt(bufferToHex(res.returnValue) === '0x' ? 0 : bufferToHex(res.returnValue)) ) } } catch (e: any) { diff --git a/packages/vm/tests/api/istanbul/eip-2200.spec.ts b/packages/vm/tests/api/istanbul/eip-2200.spec.ts index 6b049d7517..04c44e4ea0 100644 --- a/packages/vm/tests/api/istanbul/eip-2200.spec.ts +++ b/packages/vm/tests/api/istanbul/eip-2200.spec.ts @@ -2,7 +2,6 @@ import tape from 'tape' import { Address, BN, setLengthLeft, toBuffer } from 'ethereumjs-util' import Common, { Chain, Hardfork } from '@ethereumjs/common' import VM from '../../../src' -import { ERROR } from '../../../src/exceptions' import { createAccount } from '../utils' const testCases = [ diff --git a/packages/vm/tests/api/runBlock.spec.ts b/packages/vm/tests/api/runBlock.spec.ts index 508d897df3..3cfd6e4353 100644 --- a/packages/vm/tests/api/runBlock.spec.ts +++ b/packages/vm/tests/api/runBlock.spec.ts @@ -456,9 +456,9 @@ tape('runBlock() -> tx types', async (t) => { st.ok( res.gasUsed === - BigInt( - res.receipts - .map((r) => r.gasUsed) + BigInt( + res.receipts + .map((r) => r.gasUsed) .reduce( (prevValue: BN, currValue: Buffer) => prevValue.add(new BN(currValue)), new BN(0) diff --git a/packages/vm/tests/api/runCall.spec.ts b/packages/vm/tests/api/runCall.spec.ts index 0d774ec95f..4245c333e9 100644 --- a/packages/vm/tests/api/runCall.spec.ts +++ b/packages/vm/tests/api/runCall.spec.ts @@ -115,7 +115,7 @@ tape('Byzantium cannot access Constantinople opcodes', async (t) => { t.assert( byzantiumResult.execResult.exceptionError && - byzantiumResult.execResult.exceptionError.error === 'invalid opcode', + byzantiumResult.execResult.exceptionError.error === 'invalid opcode', 'byzantium cannot accept constantinople opcodes (SHL)' ) t.assert( From 8a99248c5748d413178e43fb4bcf562e8e09fdff Mon Sep 17 00:00:00 2001 From: Jochem Brouwer Date: Mon, 31 Jan 2022 23:41:01 +0100 Subject: [PATCH 17/42] vm/logic: fix sdiv/smod and fromTwos/toTwos --- packages/vm/src/evm/opcodes/functions.ts | 6 +----- packages/vm/src/evm/opcodes/util.ts | 4 ++-- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/packages/vm/src/evm/opcodes/functions.ts b/packages/vm/src/evm/opcodes/functions.ts index e6f7159f9d..023f0b6c98 100644 --- a/packages/vm/src/evm/opcodes/functions.ts +++ b/packages/vm/src/evm/opcodes/functions.ts @@ -20,7 +20,6 @@ import { mod, fromTwos, toTwos, - abs, } from './util' import { ERROR } from '../../exceptions' import { RunState } from './../interpreter' @@ -123,10 +122,7 @@ export const handlers: Map = new Map([ if (b === 0n) { r = b } else { - r = mod(abs(fromTwos(a)), abs(fromTwos(b))) - if (r < 0) { - r ^= -1n - } + r = fromTwos(a) % fromTwos(b) } runState.stack.push(toTwos(r)) }, diff --git a/packages/vm/src/evm/opcodes/util.ts b/packages/vm/src/evm/opcodes/util.ts index 16b005031c..f989ece7f0 100644 --- a/packages/vm/src/evm/opcodes/util.ts +++ b/packages/vm/src/evm/opcodes/util.ts @@ -276,11 +276,11 @@ export function mod(a: bigint, b: bigint) { } export function fromTwos(a: bigint) { - return BigInt.asUintN(256, ~(a - 1n)) + return BigInt.asIntN(256, a) } export function toTwos(a: bigint) { - return BigInt.asUintN(256, ~a + 1n) + return BigInt.asUintN(256, a) } export function abs(a: bigint) { From df382e0341c392fddd4961ba4824c9c22e6440fe Mon Sep 17 00:00:00 2001 From: Jochem Brouwer Date: Tue, 1 Feb 2022 00:29:50 +0100 Subject: [PATCH 18/42] vm/logic: fix SIGNEXTEND --- packages/vm/src/evm/opcodes/functions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vm/src/evm/opcodes/functions.ts b/packages/vm/src/evm/opcodes/functions.ts index 023f0b6c98..1fefc1a506 100644 --- a/packages/vm/src/evm/opcodes/functions.ts +++ b/packages/vm/src/evm/opcodes/functions.ts @@ -192,7 +192,7 @@ export const handlers: Map = new Map([ if (k < 31n) { const signBit = k * 8n + 7n const mask = (1n << signBit) - 1n - if (val.toString(2)[Number(signBit)] === '1') { + if ((val >> signBit) & 1n) { val = val | BigInt.asUintN(256, ~mask) } else { val = val & mask From a4e1a945362f5b49c25f95bdef08119b5dcb57c1 Mon Sep 17 00:00:00 2001 From: Jochem Brouwer Date: Tue, 1 Feb 2022 01:44:18 +0100 Subject: [PATCH 19/42] vm/logic: fix CALLDATALOAD padding --- packages/vm/src/evm/opcodes/functions.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/vm/src/evm/opcodes/functions.ts b/packages/vm/src/evm/opcodes/functions.ts index 1fefc1a506..c52e6fac0d 100644 --- a/packages/vm/src/evm/opcodes/functions.ts +++ b/packages/vm/src/evm/opcodes/functions.ts @@ -430,7 +430,10 @@ export const handlers: Map = new Map([ const i = Number(pos) let loaded = runState.eei.getCallData().slice(i, i + 32) loaded = loaded.length ? loaded : Buffer.from([0]) - const r = BigInt.asUintN(256, BigInt(bufferToHex(loaded))) + let r = BigInt(bufferToHex(loaded)) + if (loaded.length < 32) { + r = r << (8n * BigInt(32 - loaded.length)) + } runState.stack.push(r) }, ], @@ -457,7 +460,7 @@ export const handlers: Map = new Map([ } }, ], - // 0x38: CODESIZE + // 0x38: CODESIZE0xbcdef00000000000000000000000000000000000000000000000000024 [ 0x38, function (runState) { From f71290aa635659e58d7cb2488797ae046e9ad618 Mon Sep 17 00:00:00 2001 From: Jochem Brouwer Date: Tue, 1 Feb 2022 01:45:31 +0100 Subject: [PATCH 20/42] vm/logic: remove weird comment --- packages/vm/src/evm/opcodes/functions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vm/src/evm/opcodes/functions.ts b/packages/vm/src/evm/opcodes/functions.ts index c52e6fac0d..f938b6923e 100644 --- a/packages/vm/src/evm/opcodes/functions.ts +++ b/packages/vm/src/evm/opcodes/functions.ts @@ -460,7 +460,7 @@ export const handlers: Map = new Map([ } }, ], - // 0x38: CODESIZE0xbcdef00000000000000000000000000000000000000000000000000024 + // 0x38: CODESIZE [ 0x38, function (runState) { From 82a692fbc98b3e5c926ab3f43798118ad697ef98 Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Tue, 1 Feb 2022 16:36:23 -0500 Subject: [PATCH 21/42] Fix SAR opcode handler --- packages/vm/src/evm/opcodes/functions.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/vm/src/evm/opcodes/functions.ts b/packages/vm/src/evm/opcodes/functions.ts index f938b6923e..577c4e8543 100644 --- a/packages/vm/src/evm/opcodes/functions.ts +++ b/packages/vm/src/evm/opcodes/functions.ts @@ -341,7 +341,8 @@ export const handlers: Map = new Map([ const [a, b] = runState.stack.popN(2) let r - const isSigned = b.toString(2)[255] === '1' + const bComp = BigInt.asIntN(256, b) + const isSigned = bComp < 0 if (a > 256) { if (isSigned) { r = MAX_INTEGER_BIGINT From 6c5917158494cfe8e1130abb4219e300512a9d86 Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Tue, 1 Feb 2022 16:48:32 -0500 Subject: [PATCH 22/42] Use bufferToBigInt in Push opcode handler --- packages/vm/src/evm/opcodes/functions.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/vm/src/evm/opcodes/functions.ts b/packages/vm/src/evm/opcodes/functions.ts index 577c4e8543..63326c00f1 100644 --- a/packages/vm/src/evm/opcodes/functions.ts +++ b/packages/vm/src/evm/opcodes/functions.ts @@ -23,7 +23,7 @@ import { } from './util' import { ERROR } from '../../exceptions' import { RunState } from './../interpreter' -import { exponentation } from '.' +import { bufferToBigInt, exponentation } from '.' export interface SyncOpHandler { (runState: RunState, common: Common): void @@ -814,10 +814,8 @@ export const handlers: Map = new Map([ 0x60, function (runState) { const numToPush = runState.opCode - 0x5f - const loaded = BigInt( - bufferToHex( - runState.eei.getCode().slice(runState.programCounter, runState.programCounter + numToPush) - ) + const loaded = bufferToBigInt( + runState.eei.getCode().slice(runState.programCounter, runState.programCounter + numToPush) ) runState.programCounter += numToPush runState.stack.push(loaded) From b3c98d5ff1d9a41ddfe2943068f4482399c68947 Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Tue, 1 Feb 2022 16:51:44 -0500 Subject: [PATCH 23/42] use bufferToBigInt everywhere --- packages/vm/src/buildBlock.ts | 5 +++-- packages/vm/src/evm/eei.ts | 14 +++++++------- packages/vm/src/evm/opcodes/functions.ts | 11 +++++------ packages/vm/src/evm/precompiles/util/bls12_381.ts | 6 +++--- packages/vm/tests/api/istanbul/eip-1884.spec.ts | 2 +- packages/vm/tests/api/runTx.spec.ts | 2 +- .../tests/tester/runners/BlockchainTestsRunner.ts | 2 +- 7 files changed, 21 insertions(+), 21 deletions(-) diff --git a/packages/vm/src/buildBlock.ts b/packages/vm/src/buildBlock.ts index 6e1d1fd252..40f50aec55 100644 --- a/packages/vm/src/buildBlock.ts +++ b/packages/vm/src/buildBlock.ts @@ -1,4 +1,4 @@ -import { Address, toBuffer, rlp, bufferToHex, BN } from 'ethereumjs-util' +import { Address, toBuffer, rlp, BN } from 'ethereumjs-util' import { BaseTrie as Trie } from 'merkle-patricia-tree' import { Block, BlockOptions, HeaderData } from '@ethereumjs/block' import { ConsensusType } from '@ethereumjs/common' @@ -7,6 +7,7 @@ import VM from '.' import Bloom from './bloom' import { RunTxResult } from './runTx' import { calculateMinerReward, rewardAccount, encodeReceipt } from './runBlock' +import { bufferToBigInt } from './evm/opcodes' /** * Options for the block builder. @@ -169,7 +170,7 @@ export class BlockBuilder { // According to the Yellow Paper, a transaction's gas limit // cannot be greater than the remaining gas in the block - const blockGasLimit = BigInt(bufferToHex(toBuffer(this.headerData.gasLimit))) + const blockGasLimit = bufferToBigInt(toBuffer(this.headerData.gasLimit)) const blockGasRemaining = blockGasLimit - this.gasUsed if (BigInt(tx.gasLimit.toString(10)) > blockGasRemaining) { throw new Error('tx has a higher gas limit than the remaining gas in the block') diff --git a/packages/vm/src/evm/eei.ts b/packages/vm/src/evm/eei.ts index 51e4087621..7373e7755d 100644 --- a/packages/vm/src/evm/eei.ts +++ b/packages/vm/src/evm/eei.ts @@ -1,5 +1,5 @@ import { debug as createDebugLogger } from 'debug' -import { Account, Address, BN, MAX_UINT64, bufferToHex } from 'ethereumjs-util' +import { Account, Address, BN, MAX_UINT64 } from 'ethereumjs-util' import { Block } from '@ethereumjs/block' import Blockchain from '@ethereumjs/blockchain' import Common, { ConsensusAlgorithm } from '@ethereumjs/common' @@ -8,7 +8,7 @@ import { VmError, ERROR } from '../exceptions' import Message from './message' import EVM, { EVMResult } from './evm' import { Log } from './types' -import { addressToBuffer } from './opcodes' +import { addressToBuffer, bufferToBigInt } from './opcodes' const debugGas = createDebugLogger('vm:eei:gas') @@ -169,7 +169,7 @@ export default class EEI { * that is directly responsible for this execution. */ getCaller(): bigint { - return BigInt(bufferToHex(this._env.caller.buf)) + return bufferToBigInt(this._env.caller.buf) } /** @@ -267,7 +267,7 @@ export default class EEI { * non-empty associated code. */ getTxOrigin(): bigint { - return BigInt(bufferToHex(this._env.origin.buf)) + return bufferToBigInt(this._env.origin.buf) } /** @@ -293,7 +293,7 @@ export default class EEI { } else { coinbase = this._env.block.header.coinbase } - return BigInt(bufferToHex(coinbase.toBuffer())) + return bufferToBigInt(coinbase.toBuffer()) } /** @@ -343,7 +343,7 @@ export default class EEI { */ async getBlockHash(num: bigint): Promise { const block = await this._env.blockchain.getBlock(Number(num)) - return BigInt(bufferToHex(block.hash())) + return bufferToBigInt(block.hash()) } /** @@ -633,7 +633,7 @@ export default class EEI { this._env.contract = account if (results.createdAddress) { // push the created address to the stack - return BigInt(bufferToHex(results.createdAddress.buf)) + return bufferToBigInt(results.createdAddress.buf) } } diff --git a/packages/vm/src/evm/opcodes/functions.ts b/packages/vm/src/evm/opcodes/functions.ts index 63326c00f1..0d8cdc2a85 100644 --- a/packages/vm/src/evm/opcodes/functions.ts +++ b/packages/vm/src/evm/opcodes/functions.ts @@ -5,7 +5,6 @@ import { KECCAK256_NULL, TWO_POW256_BIGINT, MAX_INTEGER_BIGINT, - bufferToHex, toBuffer, setLengthLeft, } from 'ethereumjs-util' @@ -431,7 +430,7 @@ export const handlers: Map = new Map([ const i = Number(pos) let loaded = runState.eei.getCallData().slice(i, i + 32) loaded = loaded.length ? loaded : Buffer.from([0]) - let r = BigInt(bufferToHex(loaded)) + let r = bufferToBigInt(loaded) if (loaded.length < 32) { r = r << (8n * BigInt(32 - loaded.length)) } @@ -523,11 +522,11 @@ export const handlers: Map = new Map([ const code = await runState.eei.getExternalCode(addressBigInt) if (code.length === 0) { - runState.stack.push(BigInt(bufferToHex(KECCAK256_NULL))) + runState.stack.push(bufferToBigInt(KECCAK256_NULL)) return } - runState.stack.push(BigInt(bufferToHex(keccak256(code)))) + runState.stack.push(bufferToBigInt(keccak256(code))) }, ], // 0x3d: RETURNDATASIZE @@ -647,7 +646,7 @@ export const handlers: Map = new Map([ function (runState) { const pos = runState.stack.pop() const word = runState.memory.read(Number(pos), 32) - runState.stack.push(BigInt(bufferToHex(word))) + runState.stack.push(bufferToBigInt(word)) }, ], // 0x52: MSTORE @@ -680,7 +679,7 @@ export const handlers: Map = new Map([ const key = runState.stack.pop() const keyBuf = setLengthLeft(toBuffer('0x' + key.toString(16)), 32) const value = await runState.eei.storageLoad(keyBuf) - const valueBigInt = value.length ? BigInt(bufferToHex(value)) : 0n + const valueBigInt = value.length ? bufferToBigInt(value) : 0n runState.stack.push(valueBigInt) }, ], diff --git a/packages/vm/src/evm/precompiles/util/bls12_381.ts b/packages/vm/src/evm/precompiles/util/bls12_381.ts index 944e463a07..ffd78b471f 100644 --- a/packages/vm/src/evm/precompiles/util/bls12_381.ts +++ b/packages/vm/src/evm/precompiles/util/bls12_381.ts @@ -158,7 +158,7 @@ function BLS12_381_ToFrPoint(input: Buffer, mcl: any): any { function BLS12_381_ToFpPoint(fpCoordinate: Buffer, mcl: any): any { // check if point is in field - if (BigInt(bufferToHex(fpCoordinate)) >= fieldModulus) { + if (bufferToBigInt(fpCoordinate)) >= fieldModulus) { throw new VmError(ERROR.BLS_12_381_FP_NOT_IN_FIELD) } @@ -174,10 +174,10 @@ function BLS12_381_ToFpPoint(fpCoordinate: Buffer, mcl: any): any { function BLS12_381_ToFp2Point(fpXCoordinate: Buffer, fpYCoordinate: Buffer, mcl: any): any { // check if the coordinates are in the field - if (BigInt(bufferToHex(fpXCoordinate)) >= fieldModulus) { + if (bufferToBigInt(fpXCoordinate)) >= fieldModulus) { throw new VmError(ERROR.BLS_12_381_FP_NOT_IN_FIELD) } - if (BigInt(bufferToHex(fpYCoordinate)) >= fieldModulus) { + if (bufferToBigInt(fpYCoordinate)) >= fieldModulus) { throw new VmError(ERROR.BLS_12_381_FP_NOT_IN_FIELD) } diff --git a/packages/vm/tests/api/istanbul/eip-1884.spec.ts b/packages/vm/tests/api/istanbul/eip-1884.spec.ts index 2e0e1ec510..f9e3101db2 100644 --- a/packages/vm/tests/api/istanbul/eip-1884.spec.ts +++ b/packages/vm/tests/api/istanbul/eip-1884.spec.ts @@ -41,7 +41,7 @@ tape('Istanbul: EIP-1884', async (t) => { st.assert(res.exceptionError === undefined) st.assert( BigInt(testCase.selfbalance) === - BigInt(bufferToHex(res.returnValue) === '0x' ? 0 : bufferToHex(res.returnValue)) + bufferToBigInt(res.returnValue) === '0x' ? 0 : bufferToHex(res.returnValue)) ) } } catch (e: any) { diff --git a/packages/vm/tests/api/runTx.spec.ts b/packages/vm/tests/api/runTx.spec.ts index b9d3fc7577..777a0c954f 100644 --- a/packages/vm/tests/api/runTx.spec.ts +++ b/packages/vm/tests/api/runTx.spec.ts @@ -63,7 +63,7 @@ tape('runTx() -> successful API parameter usage', async (t) => { const blockGasUsed = 1000n const res = await vm.runTx({ tx, blockGasUsed }) t.ok( - BigInt(bufferToHex(res.receipt.gasUsed)) === blockGasUsed + res.gasUsed, + bufferToBigInt(res.receipt.gasUsed)) === blockGasUsed + res.gasUsed, 'receipt.gasUsed should equal block gas used + tx gas used' ) t.end() diff --git a/packages/vm/tests/tester/runners/BlockchainTestsRunner.ts b/packages/vm/tests/tester/runners/BlockchainTestsRunner.ts index a963397610..1140d3dc12 100644 --- a/packages/vm/tests/tester/runners/BlockchainTestsRunner.ts +++ b/packages/vm/tests/tester/runners/BlockchainTestsRunner.ts @@ -107,7 +107,7 @@ export default async function runBlockchainTest(options: any, testData: any, t: try { const blockRlp = Buffer.from(raw.rlp.slice(2), 'hex') const decodedRLP: any = rlp.decode(blockRlp) - currentBlock = BigInt(bufferToHex(decodedRLP[0][8])) + currentBlock = bufferToBigInt(decodedRLP[0][8])) } catch (e: any) { await handleError(e, expectException) continue From bb9247ee26161d6840a743836f5d3b89926100f7 Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Tue, 1 Feb 2022 17:02:15 -0500 Subject: [PATCH 24/42] Fix missing bufferToBigInt import --- packages/vm/src/evm/precompiles/util/bls12_381.ts | 9 +++++---- .../vm/tests/tester/runners/BlockchainTestsRunner.ts | 5 +++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/vm/src/evm/precompiles/util/bls12_381.ts b/packages/vm/src/evm/precompiles/util/bls12_381.ts index ffd78b471f..71a573a971 100644 --- a/packages/vm/src/evm/precompiles/util/bls12_381.ts +++ b/packages/vm/src/evm/precompiles/util/bls12_381.ts @@ -1,5 +1,6 @@ -import { bufferToHex, padToEven } from 'ethereumjs-util' +import { padToEven } from 'ethereumjs-util' import { VmError, ERROR } from '../../../exceptions' +import { bufferToBigInt } from '../../opcodes' // base field modulus as described in the EIP const fieldModulus = BigInt( @@ -158,7 +159,7 @@ function BLS12_381_ToFrPoint(input: Buffer, mcl: any): any { function BLS12_381_ToFpPoint(fpCoordinate: Buffer, mcl: any): any { // check if point is in field - if (bufferToBigInt(fpCoordinate)) >= fieldModulus) { + if (bufferToBigInt(fpCoordinate) >= fieldModulus) { throw new VmError(ERROR.BLS_12_381_FP_NOT_IN_FIELD) } @@ -174,10 +175,10 @@ function BLS12_381_ToFpPoint(fpCoordinate: Buffer, mcl: any): any { function BLS12_381_ToFp2Point(fpXCoordinate: Buffer, fpYCoordinate: Buffer, mcl: any): any { // check if the coordinates are in the field - if (bufferToBigInt(fpXCoordinate)) >= fieldModulus) { + if (bufferToBigInt(fpXCoordinate) >= fieldModulus) { throw new VmError(ERROR.BLS_12_381_FP_NOT_IN_FIELD) } - if (bufferToBigInt(fpYCoordinate)) >= fieldModulus) { + if (bufferToBigInt(fpYCoordinate) >= fieldModulus) { throw new VmError(ERROR.BLS_12_381_FP_NOT_IN_FIELD) } diff --git a/packages/vm/tests/tester/runners/BlockchainTestsRunner.ts b/packages/vm/tests/tester/runners/BlockchainTestsRunner.ts index 1140d3dc12..e40e18ceed 100644 --- a/packages/vm/tests/tester/runners/BlockchainTestsRunner.ts +++ b/packages/vm/tests/tester/runners/BlockchainTestsRunner.ts @@ -3,9 +3,10 @@ import { Block } from '@ethereumjs/block' import Blockchain from '@ethereumjs/blockchain' import Common, { ConsensusAlgorithm } from '@ethereumjs/common' import { TransactionFactory } from '@ethereumjs/tx' -import { addHexPrefix, toBuffer, rlp, bufferToHex } from 'ethereumjs-util' +import { addHexPrefix, toBuffer, rlp } from 'ethereumjs-util' import { SecureTrie as Trie } from 'merkle-patricia-tree' import { setupPreConditions, verifyPostConditions } from '../../util' +import { bufferToBigInt } from '../../../src/evm/opcodes' const level = require('level') const levelMem = require('level-mem') @@ -107,7 +108,7 @@ export default async function runBlockchainTest(options: any, testData: any, t: try { const blockRlp = Buffer.from(raw.rlp.slice(2), 'hex') const decodedRLP: any = rlp.decode(blockRlp) - currentBlock = bufferToBigInt(decodedRLP[0][8])) + currentBlock = bufferToBigInt(decodedRLP[0][8]) } catch (e: any) { await handleError(e, expectException) continue From 7633ab9842ada90e45af1875315a06862277a81b Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Tue, 1 Feb 2022 18:04:42 -0500 Subject: [PATCH 25/42] Check for edge case in expmod --- packages/vm/src/evm/precompiles/05-modexp.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/vm/src/evm/precompiles/05-modexp.ts b/packages/vm/src/evm/precompiles/05-modexp.ts index 4d1f3e4c91..5e09eb814a 100644 --- a/packages/vm/src/evm/precompiles/05-modexp.ts +++ b/packages/vm/src/evm/precompiles/05-modexp.ts @@ -63,6 +63,9 @@ function getAdjustedExponentLength(data: Buffer): bigint { } export function expmod(a: bigint, power: bigint, modulo: bigint) { + if (power === 0n) { + return 1n % modulo + } let res = 1n while (power > 0n) { if (power & 1n) res = (res * a) % modulo From 63670b2675ba35466c2a9303a8071373f3291454 Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Thu, 3 Feb 2022 13:43:08 -0500 Subject: [PATCH 26/42] Ignore prettier --- packages/client/lib/rpc/modules/engine.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/client/lib/rpc/modules/engine.ts b/packages/client/lib/rpc/modules/engine.ts index 5b559fd5cf..bdba5abfe3 100644 --- a/packages/client/lib/rpc/modules/engine.ts +++ b/packages/client/lib/rpc/modules/engine.ts @@ -363,7 +363,9 @@ export class Engine { // If block has less than 21000 gas remaining, consider it full blockFull = true this.config.logger.info( - `Engine: Assembled block full (gasLeft: ${gasLimit.sub(blockBuilder.gasUsed)})` + // eslint-disable-next-line prettier/prettier + `Engine: Assembled block full (gasLeft: ${BigInt(`0x ${gasLimit.toString('hex')}`) - blockBuilder.gasUsed + })` ) } } else { @@ -380,8 +382,7 @@ export class Engine { this.pendingPayloads.set(payloadId, { block, random }) this.validBlocks.set(block.hash().toString('hex'), block) this.config.logger.info( - `Engine: Finished assembling block number=${block.header.number} txs=${ - txs.length + `Engine: Finished assembling block number=${block.header.number} txs=${txs.length } hash=${block.hash().toString('hex')}` ) } catch (error: any) { From 29d34405cccc9e17328490d915c88e19f79c9491 Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Thu, 3 Feb 2022 13:53:48 -0500 Subject: [PATCH 27/42] Update browser tsconfig to es2020 lib --- config/tsconfig.browser.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/tsconfig.browser.json b/config/tsconfig.browser.json index db06cb8100..1e04ce4de6 100644 --- a/config/tsconfig.browser.json +++ b/config/tsconfig.browser.json @@ -1,7 +1,7 @@ { "extends": "./tsconfig.json", "compilerOptions": { - "target": "es5", - "lib": ["dom", "es5"] + "target": "es2020", + "lib": ["dom", "es2020"] } } From cf99438f4c4239d1c805dda58601bda1f8309075 Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Thu, 3 Feb 2022 19:18:35 -0500 Subject: [PATCH 28/42] Remove dup ES2020 targets --- config/tsconfig.browser.json | 4 ---- config/tsconfig.json | 4 ++-- packages/common/tsconfig.prod.json | 1 - packages/util/tsconfig.browser.json | 2 -- packages/util/tsconfig.json | 3 --- packages/util/tsconfig.prod.json | 1 - packages/vm/tsconfig.browser.json | 1 + 7 files changed, 3 insertions(+), 13 deletions(-) diff --git a/config/tsconfig.browser.json b/config/tsconfig.browser.json index 1e04ce4de6..71cce3ca8a 100644 --- a/config/tsconfig.browser.json +++ b/config/tsconfig.browser.json @@ -1,7 +1,3 @@ { "extends": "./tsconfig.json", - "compilerOptions": { - "target": "es2020", - "lib": ["dom", "es2020"] - } } diff --git a/config/tsconfig.json b/config/tsconfig.json index 7297410078..989b8b3526 100644 --- a/config/tsconfig.json +++ b/config/tsconfig.json @@ -11,7 +11,7 @@ "resolveJsonModule": true, "downlevelIteration": true, "strict": true, - "target": "ES2017", - "lib": ["es2018"] + "target": "es2020", + "lib": ["ES2020"] } } diff --git a/packages/common/tsconfig.prod.json b/packages/common/tsconfig.prod.json index e12cc58871..4f2491a1aa 100644 --- a/packages/common/tsconfig.prod.json +++ b/packages/common/tsconfig.prod.json @@ -3,7 +3,6 @@ "compilerOptions": { "rootDir": "./src", "outDir": "./dist", - "lib": ["dom"], "composite": true }, "include": ["src/**/*.ts", "src/**/*.json"], diff --git a/packages/util/tsconfig.browser.json b/packages/util/tsconfig.browser.json index ea86b4a999..f607e96722 100644 --- a/packages/util/tsconfig.browser.json +++ b/packages/util/tsconfig.browser.json @@ -2,8 +2,6 @@ "extends": "./tsconfig.prod.json", "compilerOptions": { "outDir": "./dist.browser", - "target": "es2020", - "lib": ["dom", "es2020"] } } \ No newline at end of file diff --git a/packages/util/tsconfig.json b/packages/util/tsconfig.json index e734f03524..35752954e2 100644 --- a/packages/util/tsconfig.json +++ b/packages/util/tsconfig.json @@ -1,7 +1,4 @@ { "extends": "../../config/tsconfig.json", "include": ["src/**/*.ts", "test/**/*.ts"], - "compilerOptions": { - "target": "ES2020" - } } diff --git a/packages/util/tsconfig.prod.json b/packages/util/tsconfig.prod.json index cdb157040f..7d60b7fdbf 100644 --- a/packages/util/tsconfig.prod.json +++ b/packages/util/tsconfig.prod.json @@ -4,7 +4,6 @@ "rootDir": "./src", "outDir": "./dist", "composite": true, - "target": "ES2020" }, "include": ["src/**/*.ts"] } diff --git a/packages/vm/tsconfig.browser.json b/packages/vm/tsconfig.browser.json index 2db1cc1786..2f6878a556 100644 --- a/packages/vm/tsconfig.browser.json +++ b/packages/vm/tsconfig.browser.json @@ -3,5 +3,6 @@ "include": ["src/**/*.ts", "src/**/*.json"], "compilerOptions": { "outDir": "./dist.browser", + "lib":["ES2020"] } } From 83d3552a85658b48468e1fed3da3dfaab39e57d8 Mon Sep 17 00:00:00 2001 From: Ryan Ghods Date: Thu, 3 Feb 2022 17:28:58 -0800 Subject: [PATCH 29/42] attempt to dedupe "target" and "lib" tsconfig values --- config/tsconfig.browser.json | 3 +++ packages/client/tsconfig.browser.json | 1 - packages/client/tsconfig.prod.json | 1 - packages/trie/tsconfig.browser.json | 5 ++--- packages/trie/tsconfig.json | 1 - packages/trie/tsconfig.prod.json | 2 -- packages/util/tsconfig.browser.json | 3 ++- packages/vm/tsconfig.benchmarks.json | 1 - packages/vm/tsconfig.browser.json | 1 - packages/vm/tsconfig.json | 3 --- packages/vm/tsconfig.prod.json | 2 -- 11 files changed, 7 insertions(+), 16 deletions(-) diff --git a/config/tsconfig.browser.json b/config/tsconfig.browser.json index 71cce3ca8a..6b989e2fdb 100644 --- a/config/tsconfig.browser.json +++ b/config/tsconfig.browser.json @@ -1,3 +1,6 @@ { "extends": "./tsconfig.json", + "compilerOptions": { + "lib": ["dom", "ES2020"] + } } diff --git a/packages/client/tsconfig.browser.json b/packages/client/tsconfig.browser.json index f99ce2bbeb..40534f6bdd 100644 --- a/packages/client/tsconfig.browser.json +++ b/packages/client/tsconfig.browser.json @@ -3,7 +3,6 @@ "include": ["browser/index.ts"], "exclude": ["lib/index.js"], "compilerOptions": { - "target": "ES2017", "outDir": "dist.browser", "typeRoots": ["node_modules/@types", "lib/@types"], } diff --git a/packages/client/tsconfig.prod.json b/packages/client/tsconfig.prod.json index e3cabd72ee..cd62f7b86a 100644 --- a/packages/client/tsconfig.prod.json +++ b/packages/client/tsconfig.prod.json @@ -3,7 +3,6 @@ "include": ["bin", "lib"], "compilerOptions": { "outDir": "dist", - "lib": ["es2018", "dom"], "typeRoots": ["node_modules/@types", "lib/@types"], }, "references": [ diff --git a/packages/trie/tsconfig.browser.json b/packages/trie/tsconfig.browser.json index b4895dad56..9258535248 100644 --- a/packages/trie/tsconfig.browser.json +++ b/packages/trie/tsconfig.browser.json @@ -1,9 +1,8 @@ { - "extends": "./tsconfig.prod.json", + "extends": "../../config/tsconfig.browser.json", + "include": ["src/**/*.ts"], "compilerOptions": { "outDir": "./dist.browser", - "target": "es5", - "lib": ["dom", "es5"] } } \ No newline at end of file diff --git a/packages/trie/tsconfig.json b/packages/trie/tsconfig.json index afab821994..3ae5514e80 100644 --- a/packages/trie/tsconfig.json +++ b/packages/trie/tsconfig.json @@ -2,7 +2,6 @@ "extends": "../../config/tsconfig.json", "compilerOptions": { "outDir": "./dist", - "lib": ["dom"], }, "include": ["src/**/*.ts", "test/*.spec.ts"] } diff --git a/packages/trie/tsconfig.prod.json b/packages/trie/tsconfig.prod.json index 9b7ba79e21..497aaac6bd 100644 --- a/packages/trie/tsconfig.prod.json +++ b/packages/trie/tsconfig.prod.json @@ -3,8 +3,6 @@ "compilerOptions": { "rootDir": "./src", "outDir": "./dist", - "target": "ES2017", - "lib": ["dom"], "composite": true }, "include": ["src/**/*.ts"], diff --git a/packages/util/tsconfig.browser.json b/packages/util/tsconfig.browser.json index f607e96722..9258535248 100644 --- a/packages/util/tsconfig.browser.json +++ b/packages/util/tsconfig.browser.json @@ -1,5 +1,6 @@ { - "extends": "./tsconfig.prod.json", + "extends": "../../config/tsconfig.browser.json", + "include": ["src/**/*.ts"], "compilerOptions": { "outDir": "./dist.browser", } diff --git a/packages/vm/tsconfig.benchmarks.json b/packages/vm/tsconfig.benchmarks.json index ff05c25d7c..a0fbc03a8b 100644 --- a/packages/vm/tsconfig.benchmarks.json +++ b/packages/vm/tsconfig.benchmarks.json @@ -1,7 +1,6 @@ { "extends": "../../config/tsconfig.json", "compilerOptions": { - "target": "ES6", "lib": ["dom"], "sourceMap": false, "declaration": false, diff --git a/packages/vm/tsconfig.browser.json b/packages/vm/tsconfig.browser.json index 2f6878a556..2db1cc1786 100644 --- a/packages/vm/tsconfig.browser.json +++ b/packages/vm/tsconfig.browser.json @@ -3,6 +3,5 @@ "include": ["src/**/*.ts", "src/**/*.json"], "compilerOptions": { "outDir": "./dist.browser", - "lib":["ES2020"] } } diff --git a/packages/vm/tsconfig.json b/packages/vm/tsconfig.json index 279de0b101..e3bfabfbc4 100644 --- a/packages/vm/tsconfig.json +++ b/packages/vm/tsconfig.json @@ -1,7 +1,4 @@ { "extends": "../../config/tsconfig.json", "include": ["src/**/*.ts", "src/**/*.json", "tests/**/*.ts"], - "compilerOptions" : { - "target": "ES2020" - } } \ No newline at end of file diff --git a/packages/vm/tsconfig.prod.json b/packages/vm/tsconfig.prod.json index bdf9036f2f..b320b36938 100644 --- a/packages/vm/tsconfig.prod.json +++ b/packages/vm/tsconfig.prod.json @@ -3,8 +3,6 @@ "compilerOptions": { "rootDir": "./src", "outDir": "./dist", - "target": "es2020", - "lib":["ES2020.BigInt"], "composite": true, }, "include": ["src/**/*.ts", "src/**/*.json"], From a9226f132c2bcdd28ec16c8d96ba679ce8746408 Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Fri, 4 Feb 2022 20:29:13 -0500 Subject: [PATCH 30/42] Update karma config to target es2020 in parser --- packages/block/karma.conf.js | 3 +++ packages/client/karma.conf.js | 3 +++ packages/common/karma.conf.js | 3 +++ packages/tx/karma.conf.js | 3 +++ packages/vm/karma.conf.js | 3 +++ 5 files changed, 15 insertions(+) diff --git a/packages/block/karma.conf.js b/packages/block/karma.conf.js index 5674b6db1a..56de7f3448 100644 --- a/packages/block/karma.conf.js +++ b/packages/block/karma.conf.js @@ -10,6 +10,9 @@ module.exports = function(config) { tsconfig: './tsconfig.json', bundlerOptions: { entrypoints: /\.spec\.ts$/, + acornOptions: { + ecmaVersion: 11 + } }, }, concurrency: 1, diff --git a/packages/client/karma.conf.js b/packages/client/karma.conf.js index 54c22d31b4..10e4351656 100644 --- a/packages/client/karma.conf.js +++ b/packages/client/karma.conf.js @@ -13,6 +13,9 @@ module.exports = function (config) { karmaTypescriptConfig: { bundlerOptions: { entrypoints: /\.spec\.ts$/, + acornOptions: { + ecmaVersion: 11 + }, resolve: { alias: { // Hotfix for `multiformats` client browser build error in Node 16, #1346, 2021-07-12 diff --git a/packages/common/karma.conf.js b/packages/common/karma.conf.js index 35a597daf2..8304457036 100644 --- a/packages/common/karma.conf.js +++ b/packages/common/karma.conf.js @@ -10,6 +10,9 @@ module.exports = function(config) { tsconfig: './tsconfig.json', bundlerOptions: { entrypoints: /\.spec\.ts$/, + acornOptions: { + ecmaVersion: 11 + } }, }, concurrency: 1, diff --git a/packages/tx/karma.conf.js b/packages/tx/karma.conf.js index 86ec5e21d3..e9bd064203 100644 --- a/packages/tx/karma.conf.js +++ b/packages/tx/karma.conf.js @@ -12,6 +12,9 @@ module.exports = function (config) { tsconfig: './tsconfig.json', bundlerOptions: { entrypoints: /\.spec\.ts$/, + acornOptions: { + ecmaVersion: 11 + } }, }, browsers: ['FirefoxHeadless', 'ChromeHeadless'], diff --git a/packages/vm/karma.conf.js b/packages/vm/karma.conf.js index 55d03729ea..284832aded 100644 --- a/packages/vm/karma.conf.js +++ b/packages/vm/karma.conf.js @@ -23,6 +23,9 @@ module.exports = function (config) { tsconfig: './tsconfig.json', bundlerOptions: { entrypoints: /\.spec\.ts$/, + acornOptions: { + ecmaVersion: 11 + } }, }, From e6ea025551142c5b55e6fd2342c139be7c3f6b88 Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Mon, 7 Feb 2022 10:07:16 -0500 Subject: [PATCH 31/42] Various test fixes --- packages/blockchain/karma.conf.js | 3 +++ packages/client/lib/miner/miner.ts | 6 ++++-- packages/client/lib/rpc/modules/engine.ts | 5 +++-- packages/client/lib/rpc/modules/eth.ts | 4 ++-- packages/client/test/rpc/eth/estimateGas.spec.ts | 2 +- packages/client/test/rpc/eth/getBalance.spec.ts | 2 +- packages/trie/karma.conf.js | 3 +++ packages/vm/tests/api/istanbul/eip-1884.spec.ts | 8 +++----- packages/vm/tests/api/runTx.spec.ts | 5 +++-- packages/vm/tests/tester/runners/BlockchainTestsRunner.ts | 2 +- 10 files changed, 24 insertions(+), 16 deletions(-) diff --git a/packages/blockchain/karma.conf.js b/packages/blockchain/karma.conf.js index 5674b6db1a..56de7f3448 100644 --- a/packages/blockchain/karma.conf.js +++ b/packages/blockchain/karma.conf.js @@ -10,6 +10,9 @@ module.exports = function(config) { tsconfig: './tsconfig.json', bundlerOptions: { entrypoints: /\.spec\.ts$/, + acornOptions: { + ecmaVersion: 11 + } }, }, concurrency: 1, diff --git a/packages/client/lib/miner/miner.ts b/packages/client/lib/miner/miner.ts index cb4e6e5a34..e94ba12774 100644 --- a/packages/client/lib/miner/miner.ts +++ b/packages/client/lib/miner/miner.ts @@ -269,11 +269,13 @@ export class Miner { await blockBuilder.addTransaction(txs[index]) } catch (error: any) { if (error.message === 'tx has a higher gas limit than the remaining gas in the block') { - if (blockBuilder.gasUsed.gt(gasLimit.subn(21000))) { + if (blockBuilder.gasUsed > BigInt(gasLimit.subn(21000).toString(10))) { // If block has less than 21000 gas remaining, consider it full blockFull = true this.config.logger.info( - `Miner: Assembled block full (gasLeft: ${gasLimit.sub(blockBuilder.gasUsed)})` + `Miner: Assembled block full (gasLeft: ${gasLimit.sub( + new BN(blockBuilder.gasUsed.toString(10)) + )})` ) } } else { diff --git a/packages/client/lib/rpc/modules/engine.ts b/packages/client/lib/rpc/modules/engine.ts index bdba5abfe3..cb3621858c 100644 --- a/packages/client/lib/rpc/modules/engine.ts +++ b/packages/client/lib/rpc/modules/engine.ts @@ -359,7 +359,7 @@ export class Engine { await blockBuilder.addTransaction(txs[index]) } catch (error: any) { if (error.message === 'tx has a higher gas limit than the remaining gas in the block') { - if (blockBuilder.gasUsed.gt(gasLimit.subn(21000))) { + if (blockBuilder.gasUsed > BigInt(gasLimit.subn(21000).toString(10))) { // If block has less than 21000 gas remaining, consider it full blockFull = true this.config.logger.info( @@ -382,7 +382,8 @@ export class Engine { this.pendingPayloads.set(payloadId, { block, random }) this.validBlocks.set(block.hash().toString('hex'), block) this.config.logger.info( - `Engine: Finished assembling block number=${block.header.number} txs=${txs.length + `Engine: Finished assembling block number=${block.header.number} txs=${ + txs.length } hash=${block.hash().toString('hex')}` ) } catch (error: any) { diff --git a/packages/client/lib/rpc/modules/eth.ts b/packages/client/lib/rpc/modules/eth.ts index 9e7f212137..eaae5dff7a 100644 --- a/packages/client/lib/rpc/modules/eth.ts +++ b/packages/client/lib/rpc/modules/eth.ts @@ -515,7 +515,7 @@ export class Eth { skipBalance: true, skipBlockGasLimitValidation: true, }) - return bnToHex(gasUsed) + return `0x${gasUsed.toString(16)}` } /** @@ -745,7 +745,7 @@ export class Eth { const { gasUsed, createdAddress } = runBlockResult.results[txIndex] return jsonRpcReceipt( receipt, - gasUsed, + new BN(gasUsed.toString(10)), effectiveGasPrice, block, tx, diff --git a/packages/client/test/rpc/eth/estimateGas.spec.ts b/packages/client/test/rpc/eth/estimateGas.spec.ts index 84c5b0fddc..ea0a9ff278 100644 --- a/packages/client/test/rpc/eth/estimateGas.spec.ts +++ b/packages/client/test/rpc/eth/estimateGas.spec.ts @@ -87,7 +87,7 @@ tape(`${method}: call with valid arguments`, async (t) => { const req = params(method, [{ ...estimateTxData, gas: estimateTxData.gasLimit }, 'latest']) const expectRes = (res: any) => { const msg = 'should return the correct gas estimate' - t.equal(res.body.result, bnToHex(gasUsed), msg) + t.equal(res.body.result, '0x' + gasUsed.toString(16), msg) } await baseRequest(t, server, req, 200, expectRes) }) diff --git a/packages/client/test/rpc/eth/getBalance.spec.ts b/packages/client/test/rpc/eth/getBalance.spec.ts index b4ec8e592c..415f1c3683 100644 --- a/packages/client/test/rpc/eth/getBalance.spec.ts +++ b/packages/client/test/rpc/eth/getBalance.spec.ts @@ -48,7 +48,7 @@ tape(`${method}: ensure balance deducts after a tx`, async (t) => { const { amountSpent } = result.results[0] // verify balance is genesis amount minus amountSpent - const expectedNewBalance = genesisBalance.sub(amountSpent) + const expectedNewBalance = genesisBalance.sub(new BN(amountSpent.toString(10))) req = params(method, [address.toString(), 'latest']) expectRes = (res: any) => { const msg = 'should return the correct balance after a tx' diff --git a/packages/trie/karma.conf.js b/packages/trie/karma.conf.js index aa906ad4bf..f1d530dfe5 100644 --- a/packages/trie/karma.conf.js +++ b/packages/trie/karma.conf.js @@ -10,6 +10,9 @@ module.exports = function (config) { tsconfig: './tsconfig.json', bundlerOptions: { entrypoints: /\.spec\.ts$/, + acornOptions: { + ecmaVersion: 11 + } }, }, colors: true, diff --git a/packages/vm/tests/api/istanbul/eip-1884.spec.ts b/packages/vm/tests/api/istanbul/eip-1884.spec.ts index f9e3101db2..5442ea040e 100644 --- a/packages/vm/tests/api/istanbul/eip-1884.spec.ts +++ b/packages/vm/tests/api/istanbul/eip-1884.spec.ts @@ -1,9 +1,10 @@ import tape from 'tape' -import { Address, BN, bufferToHex } from 'ethereumjs-util' +import { Address, BN } from 'ethereumjs-util' import Common, { Chain, Hardfork } from '@ethereumjs/common' import VM from '../../../src' import { ERROR } from '../../../src/exceptions' import { createAccount } from '../utils' +import { bufferToBigInt } from '../../../src/evm/opcodes' const testCases = [ { chain: Chain.Mainnet, hardfork: Hardfork.Istanbul, selfbalance: '0xf1' }, @@ -39,10 +40,7 @@ tape('Istanbul: EIP-1884', async (t) => { st.equal(res.exceptionError?.error, testCase.err) } else { st.assert(res.exceptionError === undefined) - st.assert( - BigInt(testCase.selfbalance) === - bufferToBigInt(res.returnValue) === '0x' ? 0 : bufferToHex(res.returnValue)) - ) + st.assert(BigInt(testCase.selfbalance) === bufferToBigInt(res.returnValue)) } } catch (e: any) { st.fail(e.message) diff --git a/packages/vm/tests/api/runTx.spec.ts b/packages/vm/tests/api/runTx.spec.ts index 777a0c954f..bf28af5f88 100644 --- a/packages/vm/tests/api/runTx.spec.ts +++ b/packages/vm/tests/api/runTx.spec.ts @@ -1,10 +1,11 @@ import tape from 'tape' -import { Account, Address, BN, bufferToHex, MAX_INTEGER, toBuffer } from 'ethereumjs-util' +import { Account, Address, BN, MAX_INTEGER, toBuffer } from 'ethereumjs-util' import { Block } from '@ethereumjs/block' import Common, { Chain, Hardfork } from '@ethereumjs/common' import { Transaction, TransactionFactory, FeeMarketEIP1559Transaction } from '@ethereumjs/tx' import VM from '../../src' import { createAccount, getTransaction } from './utils' +import { bufferToBigInt } from '../../src/evm/opcodes' const TRANSACTION_TYPES = [ { @@ -63,7 +64,7 @@ tape('runTx() -> successful API parameter usage', async (t) => { const blockGasUsed = 1000n const res = await vm.runTx({ tx, blockGasUsed }) t.ok( - bufferToBigInt(res.receipt.gasUsed)) === blockGasUsed + res.gasUsed, + bufferToBigInt(res.receipt.gasUsed) === blockGasUsed + res.gasUsed, 'receipt.gasUsed should equal block gas used + tx gas used' ) t.end() diff --git a/packages/vm/tests/tester/runners/BlockchainTestsRunner.ts b/packages/vm/tests/tester/runners/BlockchainTestsRunner.ts index e40e18ceed..50c5551873 100644 --- a/packages/vm/tests/tester/runners/BlockchainTestsRunner.ts +++ b/packages/vm/tests/tester/runners/BlockchainTestsRunner.ts @@ -3,7 +3,7 @@ import { Block } from '@ethereumjs/block' import Blockchain from '@ethereumjs/blockchain' import Common, { ConsensusAlgorithm } from '@ethereumjs/common' import { TransactionFactory } from '@ethereumjs/tx' -import { addHexPrefix, toBuffer, rlp } from 'ethereumjs-util' +import { addHexPrefix, toBuffer, rlp, stripHexPrefix } from 'ethereumjs-util' import { SecureTrie as Trie } from 'merkle-patricia-tree' import { setupPreConditions, verifyPostConditions } from '../../util' import { bufferToBigInt } from '../../../src/evm/opcodes' From ca94dd7d111b712d970add5c25c10405daa89ab5 Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Mon, 7 Feb 2022 11:29:37 -0500 Subject: [PATCH 32/42] Lint and BN fixes --- packages/vm/src/runCall.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/vm/src/runCall.ts b/packages/vm/src/runCall.ts index b1ed388dea..8108af2b74 100644 --- a/packages/vm/src/runCall.ts +++ b/packages/vm/src/runCall.ts @@ -1,4 +1,4 @@ -import { Address, BN } from 'ethereumjs-util' +import { Address } from 'ethereumjs-util' import { Block } from '@ethereumjs/block' import VM from './index' import TxContext from './evm/txContext' @@ -39,7 +39,7 @@ export default function runCall(this: VM, opts: RunCallOpts): Promise const message = new Message({ caller: opts.caller, - gasLimit: opts.gasLimit ?? new BN(0xffffff), + gasLimit: opts.gasLimit ?? 0xffffffn, to: opts.to ?? undefined, value: opts.value, data: opts.data, From 993332ade0afcb166989d25ac0e258fd0a26eba0 Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Tue, 8 Feb 2022 10:37:23 -0500 Subject: [PATCH 33/42] Add bigint helpers to util --- packages/util/src/bytes.ts | 18 +++++++++++++ packages/util/src/types.ts | 16 ++++++++++++ packages/util/test/bytes.spec.ts | 14 ++++++++++ packages/util/test/types.spec.ts | 19 ++++++++++++++ packages/vm/src/buildBlock.ts | 7 +++-- packages/vm/src/evm/eei.ts | 26 +++++++++---------- packages/vm/src/evm/evm.ts | 3 ++- packages/vm/src/evm/interpreter.ts | 8 +++--- packages/vm/src/evm/opcodes/functions.ts | 21 ++++++++------- packages/vm/src/evm/opcodes/gas.ts | 8 +++--- packages/vm/src/evm/opcodes/util.ts | 12 ++------- packages/vm/src/evm/precompiles/05-modexp.ts | 13 +++++++--- .../vm/src/evm/precompiles/util/bls12_381.ts | 3 +-- packages/vm/src/runBlock.ts | 14 +++++----- packages/vm/src/runTx.ts | 18 ++++++------- .../tests/api/EIPs/eip-3198-BaseFee.spec.ts | 6 ++--- packages/vm/tests/api/buildBlock.spec.ts | 8 +++--- .../vm/tests/api/istanbul/eip-1884.spec.ts | 3 +-- packages/vm/tests/api/runBlock.spec.ts | 7 +++-- packages/vm/tests/api/runTx.spec.ts | 23 ++++++++++------ .../tester/runners/BlockchainTestsRunner.ts | 3 +-- 21 files changed, 159 insertions(+), 91 deletions(-) diff --git a/packages/util/src/bytes.ts b/packages/util/src/bytes.ts index 0e8654c724..f49d3250d8 100644 --- a/packages/util/src/bytes.ts +++ b/packages/util/src/bytes.ts @@ -332,3 +332,21 @@ export function bufArrToArr(arr: Buffer | NestedBufferArray): Uint8Array | Neste } return arr.map((a) => bufArrToArr(a)) } + +/** + * Converts a {@link Buffer} to a {@link bigint}` + */ +export function bufferToBigInt(buf: Buffer) { + const hex = bufferToHex(buf) + if (hex === '0x') { + return 0n + } + return BigInt(hex) +} + +/** + * Converts a {@link bigint} to a {@link Buffer} + */ +export function bigIntToBuffer(num: bigint) { + return toBuffer('0x' + num.toString(16)) +} diff --git a/packages/util/src/types.ts b/packages/util/src/types.ts index 3f84526559..f1ed682233 100644 --- a/packages/util/src/types.ts +++ b/packages/util/src/types.ts @@ -144,3 +144,19 @@ export function toType( return `0x${output.toString('hex')}` as TypeOutputReturnType[T] } } + +export const bnToBigInt = (bn: BNLike | undefined) => { + if (bn) { + return BigInt(new BN(bn).toString(10)) + } else { + return 0n + } +} + +export const bigIntToBN = (num: bigint) => { + return new BN(num.toString(10)) +} + +export const bigIntToHex = (num: bigint) => { + return '0x' + num.toString(16) +} diff --git a/packages/util/test/bytes.spec.ts b/packages/util/test/bytes.spec.ts index 31a63506f5..7813f4c93f 100644 --- a/packages/util/test/bytes.spec.ts +++ b/packages/util/test/bytes.spec.ts @@ -23,6 +23,8 @@ import { intToBuffer, intToHex, validateNoLeadingZeroes, + bufferToBigInt, + bigIntToBuffer, } from '../src' tape('zeros function', function (t) { @@ -443,3 +445,15 @@ tape('bufArrToArr', function (st) { st.deepEqual(bufArrToArr(bufArr), uint8Arr) st.end() }) + +tape('bufferToBigInt', (st) => { + const buf = toBuffer('0x123') + st.equal(0x123n, bufferToBigInt(buf)) + st.end() +}) + +tape('bigIntToBuffer', (st) => { + const num = 0x123n + st.deepEqual(toBuffer('0x123'), bigIntToBuffer(num)) + st.end() +}) diff --git a/packages/util/test/types.spec.ts b/packages/util/test/types.spec.ts index eb9d31d2c2..c737203e7e 100644 --- a/packages/util/test/types.spec.ts +++ b/packages/util/test/types.spec.ts @@ -9,6 +9,9 @@ import { bnToHex, bnToUnpaddedBuffer, toBuffer, + bnToBigInt, + bigIntToBN, + bigIntToHex, } from '../src' tape('toType', function (t) { @@ -142,3 +145,19 @@ tape('bnToUnpaddedBuffer', function (t) { st.end() }) }) + +tape('bnToBigInt', (st) => { + st.equal(bnToBigInt(new BN(1)), 1n) + st.equal(bnToBigInt(undefined), 0n) + st.end() +}) + +tape('bigIntToBN', (st) => { + st.ok(bigIntToBN(1n).eq(new BN(1))) + st.end() +}) + +tape('bigIntToHex', (st) => { + st.equal(bigIntToHex(1n), '0x1') + st.end() +}) diff --git a/packages/vm/src/buildBlock.ts b/packages/vm/src/buildBlock.ts index 40f50aec55..bd671feceb 100644 --- a/packages/vm/src/buildBlock.ts +++ b/packages/vm/src/buildBlock.ts @@ -1,4 +1,4 @@ -import { Address, toBuffer, rlp, BN } from 'ethereumjs-util' +import { Address, toBuffer, rlp, BN, bufferToBigInt, bnToBigInt } from 'ethereumjs-util' import { BaseTrie as Trie } from 'merkle-patricia-tree' import { Block, BlockOptions, HeaderData } from '@ethereumjs/block' import { ConsensusType } from '@ethereumjs/common' @@ -7,7 +7,6 @@ import VM from '.' import Bloom from './bloom' import { RunTxResult } from './runTx' import { calculateMinerReward, rewardAccount, encodeReceipt } from './runBlock' -import { bufferToBigInt } from './evm/opcodes' /** * Options for the block builder. @@ -170,9 +169,9 @@ export class BlockBuilder { // According to the Yellow Paper, a transaction's gas limit // cannot be greater than the remaining gas in the block - const blockGasLimit = bufferToBigInt(toBuffer(this.headerData.gasLimit)) + const blockGasLimit = bnToBigInt(this.headerData.gasLimit) const blockGasRemaining = blockGasLimit - this.gasUsed - if (BigInt(tx.gasLimit.toString(10)) > blockGasRemaining) { + if (bnToBigInt(tx.gasLimit) > blockGasRemaining) { throw new Error('tx has a higher gas limit than the remaining gas in the block') } diff --git a/packages/vm/src/evm/eei.ts b/packages/vm/src/evm/eei.ts index 7373e7755d..4d6be96709 100644 --- a/packages/vm/src/evm/eei.ts +++ b/packages/vm/src/evm/eei.ts @@ -1,5 +1,5 @@ import { debug as createDebugLogger } from 'debug' -import { Account, Address, BN, MAX_UINT64 } from 'ethereumjs-util' +import { Account, Address, BN, MAX_UINT64, bufferToBigInt, bnToBigInt } from 'ethereumjs-util' import { Block } from '@ethereumjs/block' import Blockchain from '@ethereumjs/blockchain' import Common, { ConsensusAlgorithm } from '@ethereumjs/common' @@ -8,7 +8,7 @@ import { VmError, ERROR } from '../exceptions' import Message from './message' import EVM, { EVMResult } from './evm' import { Log } from './types' -import { addressToBuffer, bufferToBigInt } from './opcodes' +import { addressToBuffer } from './opcodes' const debugGas = createDebugLogger('vm:eei:gas') @@ -149,19 +149,19 @@ export default class EEI { async getExternalBalance(address: Address): Promise { // shortcut if current account if (address.equals(this._env.address)) { - return BigInt(this._env.contract.balance.toString(10)) + return bnToBigInt(this._env.contract.balance) } // otherwise load account then return balance const account = await this._state.getAccount(address) - return BigInt(account.balance.toString(10)) + return bnToBigInt(account.balance) } /** * Returns balance of self. */ getSelfBalance(): bigint { - return BigInt(this._env.contract.balance.toString(10)) + return bnToBigInt(this._env.contract.balance) } /** @@ -274,7 +274,7 @@ export default class EEI { * Returns the block’s number. */ getBlockNumber(): bigint { - return BigInt(this._env.block.header.number.toString(10)) + return bnToBigInt(this._env.block.header.number) } /** @@ -300,21 +300,21 @@ export default class EEI { * Returns the block's timestamp. */ getBlockTimestamp(): bigint { - return BigInt(this._env.block.header.timestamp.toString(10)) + return bnToBigInt(this._env.block.header.timestamp) } /** * Returns the block's difficulty. */ getBlockDifficulty(): bigint { - return BigInt(this._env.block.header.difficulty.toString(10)) + return bnToBigInt(this._env.block.header.difficulty) } /** * Returns the block's gas limit. */ getBlockGasLimit(): bigint { - return BigInt(this._env.block.header.gasLimit.toString(10)) + return bnToBigInt(this._env.block.header.gasLimit) } /** @@ -322,7 +322,7 @@ export default class EEI { * CHAINID opcode proposed in [EIP-1344](https://eips.ethereum.org/EIPS/eip-1344). */ getChainId(): bigint { - return BigInt(this._common.chainIdBN().toString(10)) + return bnToBigInt(this._common.chainIdBN()) } /** @@ -334,7 +334,7 @@ export default class EEI { // Sanity check throw new Error('Block has no Base Fee') } - return BigInt(baseFee.toString(10)) + return bnToBigInt(baseFee) } /** @@ -535,7 +535,7 @@ export default class EEI { // Check if account has enough ether and max depth not exceeded if ( this._env.depth >= this._common.param('vm', 'stackLimit') || - (msg.delegatecall !== true && BigInt(this._env.contract.balance.toString(10)) < msg.value) + (msg.delegatecall !== true && bnToBigInt(this._env.contract.balance) < msg.value) ) { return 0n } @@ -594,7 +594,7 @@ export default class EEI { // Check if account has enough ether and max depth not exceeded if ( this._env.depth >= this._common.param('vm', 'stackLimit') || - (msg.delegatecall !== true && BigInt(this._env.contract.balance.toString(10)) < msg.value) + (msg.delegatecall !== true && bnToBigInt(this._env.contract.balance) < msg.value) ) { return 0n } diff --git a/packages/vm/src/evm/evm.ts b/packages/vm/src/evm/evm.ts index 7695fec1e5..f131b1a7bd 100644 --- a/packages/vm/src/evm/evm.ts +++ b/packages/vm/src/evm/evm.ts @@ -3,6 +3,7 @@ import { Account, Address, BN, + bnToBigInt, generateAddress, generateAddress2, KECCAK256_NULL, @@ -474,7 +475,7 @@ export default class EVM { code: message.code as Buffer, isStatic: message.isStatic || false, depth: message.depth || 0, - gasPrice: BigInt(this._tx.gasPrice.toString(10)), + gasPrice: this._tx.gasPrice, origin: this._tx.origin || message.caller || Address.zero(), block: this._block || new Block(), contract: await this._state.getAccount(message.to || Address.zero()), diff --git a/packages/vm/src/evm/interpreter.ts b/packages/vm/src/evm/interpreter.ts index b78af0da48..e0f51a3671 100644 --- a/packages/vm/src/evm/interpreter.ts +++ b/packages/vm/src/evm/interpreter.ts @@ -1,5 +1,5 @@ import { debug as createDebugLogger } from 'debug' -import { Account, Address } from 'ethereumjs-util' +import { Account, Address, bigIntToHex, intToHex } from 'ethereumjs-util' import { StateManager } from '../state/index' import { ERROR, VmError } from '../exceptions' import Memory from './memory' @@ -218,7 +218,7 @@ export default class Interpreter { // Create opTrace for debug functionality let hexStack = [] hexStack = eventObj.stack.map((item: any) => { - return '0x' + BigInt(item).toString(16) + return bigIntToHex(BigInt(item)) }) const name = eventObj.opcode.name @@ -226,8 +226,8 @@ export default class Interpreter { const opTrace = { pc: eventObj.pc, op: name, - gas: '0x' + eventObj.gasLeft.toString(16), - gasCost: '0x' + eventObj.opcode.fee.toString(16), + gas: bigIntToHex(eventObj.gasLeft), + gasCost: intToHex(eventObj.opcode.fee), stack: hexStack, depth: eventObj.depth, } diff --git a/packages/vm/src/evm/opcodes/functions.ts b/packages/vm/src/evm/opcodes/functions.ts index 0d8cdc2a85..1b4bf60c6c 100644 --- a/packages/vm/src/evm/opcodes/functions.ts +++ b/packages/vm/src/evm/opcodes/functions.ts @@ -5,8 +5,9 @@ import { KECCAK256_NULL, TWO_POW256_BIGINT, MAX_INTEGER_BIGINT, - toBuffer, setLengthLeft, + bufferToBigInt, + bigIntToBuffer, } from 'ethereumjs-util' import { addressToBuffer, @@ -22,7 +23,7 @@ import { } from './util' import { ERROR } from '../../exceptions' import { RunState } from './../interpreter' -import { bufferToBigInt, exponentation } from '.' +import { exponentation } from '.' export interface SyncOpHandler { (runState: RunState, common: Common): void @@ -382,7 +383,7 @@ export const handlers: Map = new Map([ [ 0x30, function (runState) { - const address = BigInt('0x' + runState.eei.getAddress().buf.toString('hex')) + const address = bufferToBigInt(runState.eei.getAddress().buf) runState.stack.push(address) }, ], @@ -654,7 +655,7 @@ export const handlers: Map = new Map([ 0x52, function (runState) { const [offset, word] = runState.stack.popN(2) - const buf = setLengthLeft(toBuffer('0x' + word.toString(16)), 32) + const buf = setLengthLeft(bigIntToBuffer(word), 32) const offsetNum = Number(offset) runState.memory.extend(offsetNum, 32) runState.memory.write(offsetNum, 32, buf) @@ -666,7 +667,7 @@ export const handlers: Map = new Map([ function (runState) { const [offset, byte] = runState.stack.popN(2) - const buf = toBuffer('0x' + (byte & 0xffn).toString(16)) + const buf = bigIntToBuffer(byte & 0xffn) const offsetNum = Number(offset) runState.memory.extend(offsetNum, 1) runState.memory.write(offsetNum, 1, buf) @@ -677,7 +678,7 @@ export const handlers: Map = new Map([ 0x54, async function (runState) { const key = runState.stack.pop() - const keyBuf = setLengthLeft(toBuffer('0x' + key.toString(16)), 32) + const keyBuf = setLengthLeft(bigIntToBuffer(key), 32) const value = await runState.eei.storageLoad(keyBuf) const valueBigInt = value.length ? bufferToBigInt(value) : 0n runState.stack.push(valueBigInt) @@ -689,13 +690,13 @@ export const handlers: Map = new Map([ async function (runState) { const [key, val] = runState.stack.popN(2) - const keyBuf = setLengthLeft(toBuffer('0x' + key.toString(16)), 32) + const keyBuf = setLengthLeft(bigIntToBuffer(key), 32) // NOTE: this should be the shortest representation let value if (val === 0n) { value = Buffer.from([]) } else { - value = toBuffer('0x' + val.toString(16)) + value = bigIntToBuffer(val) } await runState.eei.storageStore(keyBuf, value) @@ -846,7 +847,7 @@ export const handlers: Map = new Map([ const topics = runState.stack.popN(topicsCount) const topicsBuf = topics.map(function (a: bigint) { - return setLengthLeft(toBuffer('0x' + a.toString(16)), 32) + return setLengthLeft(bigIntToBuffer(a), 32) }) let mem = Buffer.alloc(0) @@ -899,7 +900,7 @@ export const handlers: Map = new Map([ gasLimit, value, data, - setLengthLeft(toBuffer('0x' + salt.toString(16)), 32) + setLengthLeft(bigIntToBuffer(salt), 32) ) runState.stack.push(ret) }, diff --git a/packages/vm/src/evm/opcodes/gas.ts b/packages/vm/src/evm/opcodes/gas.ts index 0556f4685a..42ea487045 100644 --- a/packages/vm/src/evm/opcodes/gas.ts +++ b/packages/vm/src/evm/opcodes/gas.ts @@ -7,7 +7,7 @@ import { trap, updateSstoreGas, } from '.' -import { Address, setLengthLeft, toBuffer } from 'ethereumjs-util' +import { Address, bigIntToBuffer, setLengthLeft } from 'ethereumjs-util' import { ERROR } from '../../exceptions' import { RunState } from '../interpreter' import Common from '@ethereumjs/common' @@ -173,7 +173,7 @@ export const dynamicGasHandlers: Map = new Map< 0x54, async function (runState, gas, common): Promise { const key = runState.stack.peek()[0] - const keyBuf = setLengthLeft(toBuffer('0x' + key.toString(16)), 32) + const keyBuf = setLengthLeft(bigIntToBuffer(key), 32) if (common.isActivatedEIP(2929)) { gas += accessStorageEIP2929(runState, keyBuf, false, common) @@ -190,13 +190,13 @@ export const dynamicGasHandlers: Map = new Map< } const [key, val] = runState.stack.peek(2) - const keyBuf = setLengthLeft(toBuffer('0x' + key.toString(16)), 32) + const keyBuf = setLengthLeft(bigIntToBuffer(key), 32) // NOTE: this should be the shortest representation let value if (val === 0n) { value = Buffer.from([]) } else { - value = toBuffer('0x' + val.toString(16)) + value = bigIntToBuffer(val) } // TODO: Replace getContractStorage with EEI method diff --git a/packages/vm/src/evm/opcodes/util.ts b/packages/vm/src/evm/opcodes/util.ts index f989ece7f0..e8798d923c 100644 --- a/packages/vm/src/evm/opcodes/util.ts +++ b/packages/vm/src/evm/opcodes/util.ts @@ -1,5 +1,5 @@ import Common from '@ethereumjs/common' -import { keccak256, setLengthRight, setLengthLeft, toBuffer, bufferToHex } from 'ethereumjs-util' +import { keccak256, setLengthRight, setLengthLeft, bigIntToBuffer } from 'ethereumjs-util' import { ERROR, VmError } from './../../exceptions' import { RunState } from './../interpreter' @@ -38,7 +38,7 @@ export function trap(err: string) { */ export function addressToBuffer(address: bigint | Buffer) { if (Buffer.isBuffer(address)) return address - return setLengthLeft(toBuffer('0x' + (address & MASK_160).toString(16)), 20) + return setLengthLeft(bigIntToBuffer(address & MASK_160), 20) } /** @@ -290,14 +290,6 @@ export function abs(a: bigint) { return a * -1n } -export function bufferToBigInt(buf: Buffer) { - const hex = bufferToHex(buf) - if (hex === '0x') { - return 0n - } - return BigInt(hex) -} - const N = 115792089237316195423570985008687907853269984665640564039457584007913129639936n export function exponentation(bas: bigint, exp: bigint) { let t = 1n diff --git a/packages/vm/src/evm/precompiles/05-modexp.ts b/packages/vm/src/evm/precompiles/05-modexp.ts index 5e09eb814a..9d40ced576 100644 --- a/packages/vm/src/evm/precompiles/05-modexp.ts +++ b/packages/vm/src/evm/precompiles/05-modexp.ts @@ -1,7 +1,12 @@ -import { setLengthRight, toBuffer, setLengthLeft } from 'ethereumjs-util' +import { + setLengthRight, + toBuffer, + setLengthLeft, + bufferToBigInt, + bigIntToBuffer, +} from 'ethereumjs-util' import { PrecompileInput } from './types' import { OOGResult, ExecResult } from '../evm' -import { bufferToBigInt } from '../opcodes' const assert = require('assert') function multComplexity(x: bigint): bigint { @@ -119,7 +124,7 @@ export default function (opts: PrecompileInput): ExecResult { if (bLen === 0n) { return { gasUsed, - returnValue: setLengthLeft(toBuffer('0x' + 0n.toString(16)), Number(mLen)), + returnValue: setLengthLeft(bigIntToBuffer(0n), Number(mLen)), } } @@ -154,6 +159,6 @@ export default function (opts: PrecompileInput): ExecResult { return { gasUsed, - returnValue: setLengthLeft(toBuffer('0x' + R.toString(16)), Number(mLen)), + returnValue: setLengthLeft(bigIntToBuffer(R), Number(mLen)), } } diff --git a/packages/vm/src/evm/precompiles/util/bls12_381.ts b/packages/vm/src/evm/precompiles/util/bls12_381.ts index 71a573a971..a9d5dbdc81 100644 --- a/packages/vm/src/evm/precompiles/util/bls12_381.ts +++ b/packages/vm/src/evm/precompiles/util/bls12_381.ts @@ -1,6 +1,5 @@ -import { padToEven } from 'ethereumjs-util' +import { padToEven, bufferToBigInt } from 'ethereumjs-util' import { VmError, ERROR } from '../../../exceptions' -import { bufferToBigInt } from '../../opcodes' // base field modulus as described in the EIP const fieldModulus = BigInt( diff --git a/packages/vm/src/runBlock.ts b/packages/vm/src/runBlock.ts index 759c403805..1b5f48284d 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, BN, intToBuffer, rlp } from 'ethereumjs-util' +import { Account, Address, BN, bnToBigInt, intToBuffer, rlp } from 'ethereumjs-util' import { Block } from '@ethereumjs/block' import { ConsensusType } from '@ethereumjs/common' import VM from './index' @@ -215,7 +215,7 @@ export default async function runBlock(this: VM, opts: RunBlockOpts): Promise ${gasUsed})`) } @@ -387,8 +387,8 @@ async function assignBlockRewards(this: VM, block: Block): Promise { // Reward ommers for (const ommer of ommers) { const reward = calculateOmmerReward( - BigInt(ommer.number.toString(10)), - BigInt(block.header.number.toString(10)), + bnToBigInt(ommer.number), + bnToBigInt(block.header.number), minerReward ) const account = await rewardAccount(state, ommer.coinbase, reward) diff --git a/packages/vm/src/runTx.ts b/packages/vm/src/runTx.ts index 67009239dc..4b945b87e6 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, BN, KECCAK256_NULL, toBuffer } from 'ethereumjs-util' +import { Address, bigIntToBuffer, BN, bnToBigInt, KECCAK256_NULL, toBuffer } from 'ethereumjs-util' import { Block } from '@ethereumjs/block' import { ConsensusType } from '@ethereumjs/common' import { @@ -270,8 +270,8 @@ async function _runTx(this: VM, opts: RunTxOpts): Promise { } // Validate gas limit against tx base fee (DataFee + TxFee + Creation Fee) - const txBaseFee = BigInt(tx.getBaseFee().toString(10)) - let gasLimit = BigInt(tx.gasLimit.toString(10)) + const txBaseFee = bnToBigInt(tx.getBaseFee()) + let gasLimit = bnToBigInt(tx.gasLimit) if (gasLimit < txBaseFee) { const msg = _errorMsg('base fee exceeds gas limit', this, block, tx) throw new Error(msg) @@ -356,10 +356,10 @@ async function _runTx(this: VM, opts: RunTxOpts): Promise { (tx as FeeMarketEIP1559Transaction).maxPriorityFeePerGas, (tx as FeeMarketEIP1559Transaction).maxFeePerGas.sub(baseFee) ) - gasPrice = BigInt(inclusionFeePerGas.add(baseFee).toString(10)) + gasPrice = bnToBigInt(inclusionFeePerGas.add(baseFee)) } else { // Have to cast as legacy tx since EIP1559 tx does not have gas price - gasPrice = BigInt((tx).gasPrice.toString(10)) + gasPrice = bnToBigInt((tx).gasPrice) if (this._common.isActivatedEIP(1559)) { const baseFee = block.header.baseFeePerGas! inclusionFeePerGas = (tx).gasPrice.sub(baseFee) @@ -368,7 +368,7 @@ async function _runTx(this: VM, opts: RunTxOpts): Promise { // Update from account's nonce and balance fromAccount.nonce.iaddn(1) - const txCost = BigInt(tx.gasLimit.toString(10)) * gasPrice + const txCost = bnToBigInt(tx.gasLimit) * gasPrice fromAccount.balance.isub(new BN(txCost.toString(10), 10)) await state.putAccount(caller, fromAccount) if (this.DEBUG) { @@ -386,7 +386,7 @@ async function _runTx(this: VM, opts: RunTxOpts): Promise { caller, gasLimit, to, - value: BigInt(value.toString(10)), + value: bnToBigInt(value), data, }) const evm = new EVM(this, txContext, block) @@ -505,7 +505,7 @@ async function _runTx(this: VM, opts: RunTxOpts): Promise { state.clearOriginalStorageCache() // Generate the tx receipt - const gasUsed = opts.blockGasUsed ?? BigInt(block.header.gasUsed.toString(10)) + const gasUsed = opts.blockGasUsed ?? bnToBigInt(block.header.gasUsed) const cumulativeGasUsed = gasUsed + results.gasUsed results.receipt = await generateTxReceipt.bind(this)(tx, results, cumulativeGasUsed) @@ -564,7 +564,7 @@ export async function generateTxReceipt( cumulativeGasUsed: bigint ): Promise { const baseReceipt: BaseTxReceipt = { - gasUsed: toBuffer('0x' + cumulativeGasUsed.toString(16)), + gasUsed: bigIntToBuffer(cumulativeGasUsed), bitvector: txResult.bloom.bitvector, logs: txResult.execResult.logs ?? [], } diff --git a/packages/vm/tests/api/EIPs/eip-3198-BaseFee.spec.ts b/packages/vm/tests/api/EIPs/eip-3198-BaseFee.spec.ts index 5ec1d11df2..216b37d61c 100644 --- a/packages/vm/tests/api/EIPs/eip-3198-BaseFee.spec.ts +++ b/packages/vm/tests/api/EIPs/eip-3198-BaseFee.spec.ts @@ -1,5 +1,5 @@ import tape from 'tape' -import { Address, BN, privateToAddress } from 'ethereumjs-util' +import { Address, BN, bnToBigInt, privateToAddress } from 'ethereumjs-util' import VM from '../../../src' import Common, { Chain, Hardfork } from '@ethereumjs/common' import { FeeMarketEIP1559Transaction, TypedTransaction } from '@ethereumjs/tx' @@ -91,10 +91,10 @@ tape('EIP3198 tests', (t) => { tx: block.transactions[0], block, }) - const txBaseFee = BigInt(block.transactions[0].getBaseFee().toString(10)) + const txBaseFee = bnToBigInt(block.transactions[0].getBaseFee()) const gasUsed = results.gasUsed - txBaseFee st.ok(gasUsed === 2n, 'gas used correct') - st.ok(stack[0] === BigInt(fee.toString(10)), 'right item pushed on stack') + st.ok(stack[0] === bnToBigInt(fee), 'right item pushed on stack') st.end() }) }) diff --git a/packages/vm/tests/api/buildBlock.spec.ts b/packages/vm/tests/api/buildBlock.spec.ts index 3ac0421013..4ee59c55ba 100644 --- a/packages/vm/tests/api/buildBlock.spec.ts +++ b/packages/vm/tests/api/buildBlock.spec.ts @@ -1,5 +1,5 @@ import tape from 'tape' -import { Account, Address } from 'ethereumjs-util' +import { Account, Address, bnToBigInt } from 'ethereumjs-util' import Common, { Chain, Hardfork } from '@ethereumjs/common' import { Block } from '@ethereumjs/block' import { Transaction, FeeMarketEIP1559Transaction } from '@ethereumjs/tx' @@ -42,7 +42,7 @@ tape('BlockBuilder', async (t) => { return address } const result = await vmCopy.runBlock({ block }) - st.ok(result.gasUsed === BigInt(block.header.gasUsed.toString(10))) + st.ok(result.gasUsed === bnToBigInt(block.header.gasUsed)) st.ok(result.receiptRoot.equals(block.header.receiptTrie)) st.ok(result.stateRoot.equals(block.header.stateRoot)) st.ok(result.logsBloom.equals(block.header.logsBloom)) @@ -271,7 +271,7 @@ tape('BlockBuilder', async (t) => { // block should successfully execute with VM.runBlock and have same outputs const result = await vmCopy.runBlock({ block }) - st.ok(result.gasUsed === BigInt(block.header.gasUsed.toString(10))) + st.ok(result.gasUsed === bnToBigInt(block.header.gasUsed)) st.ok(result.receiptRoot.equals(block.header.receiptTrie)) st.ok(result.stateRoot.equals(block.header.stateRoot)) st.ok(result.logsBloom.equals(block.header.logsBloom)) @@ -362,7 +362,7 @@ tape('BlockBuilder', async (t) => { return address } const result = await vmCopy.runBlock({ block }) - st.ok(result.gasUsed === BigInt(block.header.gasUsed.toString(10))) + st.ok(result.gasUsed === bnToBigInt(block.header.gasUsed)) st.ok(result.receiptRoot.equals(block.header.receiptTrie)) st.ok(result.stateRoot.equals(block.header.stateRoot)) st.ok(result.logsBloom.equals(block.header.logsBloom)) diff --git a/packages/vm/tests/api/istanbul/eip-1884.spec.ts b/packages/vm/tests/api/istanbul/eip-1884.spec.ts index 5442ea040e..a730a9de07 100644 --- a/packages/vm/tests/api/istanbul/eip-1884.spec.ts +++ b/packages/vm/tests/api/istanbul/eip-1884.spec.ts @@ -1,10 +1,9 @@ import tape from 'tape' -import { Address, BN } from 'ethereumjs-util' +import { Address, BN, bufferToBigInt } from 'ethereumjs-util' import Common, { Chain, Hardfork } from '@ethereumjs/common' import VM from '../../../src' import { ERROR } from '../../../src/exceptions' import { createAccount } from '../utils' -import { bufferToBigInt } from '../../../src/evm/opcodes' const testCases = [ { chain: Chain.Mainnet, hardfork: Hardfork.Istanbul, selfbalance: '0xf1' }, diff --git a/packages/vm/tests/api/runBlock.spec.ts b/packages/vm/tests/api/runBlock.spec.ts index 3cfd6e4353..0d0b7854a9 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, BN, rlp, KECCAK256_RLP, Account } from 'ethereumjs-util' +import { Address, BN, rlp, KECCAK256_RLP, Account, bnToBigInt } from 'ethereumjs-util' import Common, { Chain, Hardfork } from '@ethereumjs/common' import { Block } from '@ethereumjs/block' import { @@ -456,14 +456,13 @@ tape('runBlock() -> tx types', async (t) => { st.ok( res.gasUsed === - BigInt( + bnToBigInt( res.receipts .map((r) => r.gasUsed) .reduce( (prevValue: BN, currValue: Buffer) => prevValue.add(new BN(currValue)), new BN(0) - ) - .toString(10) + ) ), "gas used should equal transaction's total gasUsed" ) diff --git a/packages/vm/tests/api/runTx.spec.ts b/packages/vm/tests/api/runTx.spec.ts index bf28af5f88..b03bbe80bd 100644 --- a/packages/vm/tests/api/runTx.spec.ts +++ b/packages/vm/tests/api/runTx.spec.ts @@ -1,11 +1,18 @@ import tape from 'tape' -import { Account, Address, BN, MAX_INTEGER, toBuffer } from 'ethereumjs-util' +import { + Account, + Address, + BN, + MAX_INTEGER, + toBuffer, + bufferToBigInt, + bnToBigInt, +} from 'ethereumjs-util' import { Block } from '@ethereumjs/block' import Common, { Chain, Hardfork } from '@ethereumjs/common' import { Transaction, TransactionFactory, FeeMarketEIP1559Transaction } from '@ethereumjs/tx' import VM from '../../src' import { createAccount, getTransaction } from './utils' -import { bufferToBigInt } from '../../src/evm/opcodes' const TRANSACTION_TYPES = [ { @@ -147,14 +154,14 @@ tape('runTx() -> successful API parameter usage', async (t) => { const baseFee = block.header.baseFeePerGas! const inclusionFeePerGas = tx instanceof FeeMarketEIP1559Transaction - ? BigInt(BN.min(tx.maxPriorityFeePerGas, tx.maxFeePerGas.sub(baseFee)).toString(10)) - : BigInt(tx.gasPrice.sub(baseFee).toString(10)) + ? bnToBigInt(BN.min(tx.maxPriorityFeePerGas, tx.maxFeePerGas.sub(baseFee))) + : bnToBigInt(tx.gasPrice.sub(baseFee)) const expectedCoinbaseBalance = common.isActivatedEIP(1559) ? result.gasUsed * inclusionFeePerGas : result.amountSpent t.ok( - BigInt(coinbaseAccount.balance.toString(10)) === expectedCoinbaseBalance, + bnToBigInt(coinbaseAccount.balance) === expectedCoinbaseBalance, `should use custom block (${txType.name})` ) @@ -476,13 +483,13 @@ tape('runTx() -> API return values', async (t) => { t.deepEqual( res.gasUsed, - BigInt(tx.getBaseFee().toString(10)), + bnToBigInt(tx.getBaseFee()), `runTx result -> gasUsed -> tx.getBaseFee() (${txType.name})` ) if (tx instanceof FeeMarketEIP1559Transaction) { const baseFee = new BN(7) const inclusionFeePerGas = BN.min(tx.maxPriorityFeePerGas, tx.maxFeePerGas.sub(baseFee)) - const gasPrice = BigInt(inclusionFeePerGas.toString(10)) + BigInt(baseFee.toString(10)) + const gasPrice = bnToBigInt(inclusionFeePerGas) + bnToBigInt(baseFee) t.deepEquals( res.amountSpent, res.gasUsed * gasPrice, @@ -491,7 +498,7 @@ tape('runTx() -> API return values', async (t) => { } else { t.deepEqual( res.amountSpent, - res.gasUsed * BigInt((tx).gasPrice.toString(10)), + res.gasUsed * bnToBigInt((tx).gasPrice), `runTx result -> amountSpent -> gasUsed * gasPrice (${txType.name})` ) } diff --git a/packages/vm/tests/tester/runners/BlockchainTestsRunner.ts b/packages/vm/tests/tester/runners/BlockchainTestsRunner.ts index 50c5551873..e85b20efd4 100644 --- a/packages/vm/tests/tester/runners/BlockchainTestsRunner.ts +++ b/packages/vm/tests/tester/runners/BlockchainTestsRunner.ts @@ -3,10 +3,9 @@ import { Block } from '@ethereumjs/block' import Blockchain from '@ethereumjs/blockchain' import Common, { ConsensusAlgorithm } from '@ethereumjs/common' import { TransactionFactory } from '@ethereumjs/tx' -import { addHexPrefix, toBuffer, rlp, stripHexPrefix } from 'ethereumjs-util' +import { addHexPrefix, toBuffer, rlp, stripHexPrefix, bufferToBigInt } from 'ethereumjs-util' import { SecureTrie as Trie } from 'merkle-patricia-tree' import { setupPreConditions, verifyPostConditions } from '../../util' -import { bufferToBigInt } from '../../../src/evm/opcodes' const level = require('level') const levelMem = require('level-mem') From 829bd5bfabe126783f996d74722ca71d4122e41e Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Tue, 8 Feb 2022 10:39:57 -0500 Subject: [PATCH 34/42] lint fixes --- packages/vm/src/buildBlock.ts | 2 +- packages/vm/src/evm/evm.ts | 1 - packages/vm/src/evm/precompiles/05-modexp.ts | 8 +------- packages/vm/tests/api/runBlock.spec.ts | 4 ++-- 4 files changed, 4 insertions(+), 11 deletions(-) diff --git a/packages/vm/src/buildBlock.ts b/packages/vm/src/buildBlock.ts index bd671feceb..d0e2f70b53 100644 --- a/packages/vm/src/buildBlock.ts +++ b/packages/vm/src/buildBlock.ts @@ -1,4 +1,4 @@ -import { Address, toBuffer, rlp, BN, bufferToBigInt, bnToBigInt } from 'ethereumjs-util' +import { Address, toBuffer, rlp, BN, bnToBigInt } from 'ethereumjs-util' import { BaseTrie as Trie } from 'merkle-patricia-tree' import { Block, BlockOptions, HeaderData } from '@ethereumjs/block' import { ConsensusType } from '@ethereumjs/common' diff --git a/packages/vm/src/evm/evm.ts b/packages/vm/src/evm/evm.ts index f131b1a7bd..6a397bf4b5 100644 --- a/packages/vm/src/evm/evm.ts +++ b/packages/vm/src/evm/evm.ts @@ -3,7 +3,6 @@ import { Account, Address, BN, - bnToBigInt, generateAddress, generateAddress2, KECCAK256_NULL, diff --git a/packages/vm/src/evm/precompiles/05-modexp.ts b/packages/vm/src/evm/precompiles/05-modexp.ts index 9d40ced576..86b5e6b3d5 100644 --- a/packages/vm/src/evm/precompiles/05-modexp.ts +++ b/packages/vm/src/evm/precompiles/05-modexp.ts @@ -1,10 +1,4 @@ -import { - setLengthRight, - toBuffer, - setLengthLeft, - bufferToBigInt, - bigIntToBuffer, -} from 'ethereumjs-util' +import { setLengthRight, setLengthLeft, bufferToBigInt, bigIntToBuffer } from 'ethereumjs-util' import { PrecompileInput } from './types' import { OOGResult, ExecResult } from '../evm' const assert = require('assert') diff --git a/packages/vm/tests/api/runBlock.spec.ts b/packages/vm/tests/api/runBlock.spec.ts index 0d0b7854a9..855f911294 100644 --- a/packages/vm/tests/api/runBlock.spec.ts +++ b/packages/vm/tests/api/runBlock.spec.ts @@ -456,13 +456,13 @@ tape('runBlock() -> tx types', async (t) => { st.ok( res.gasUsed === - bnToBigInt( + bnToBigInt( res.receipts .map((r) => r.gasUsed) .reduce( (prevValue: BN, currValue: Buffer) => prevValue.add(new BN(currValue)), new BN(0) - ) + ) ), "gas used should equal transaction's total gasUsed" ) From eed7d57ccda3cbec6c67b6ca1e34f6367be225b4 Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Tue, 8 Feb 2022 20:35:05 -0500 Subject: [PATCH 35/42] various bigint helper additions --- packages/vm/benchmarks/util.ts | 4 ++-- packages/vm/src/buildBlock.ts | 6 +++--- packages/vm/src/evm/evm.ts | 5 +++-- packages/vm/src/evm/opcodes/functions.ts | 2 +- packages/vm/src/evm/opcodes/gas.ts | 2 +- packages/vm/src/runBlock.ts | 6 +++--- packages/vm/src/runTx.ts | 18 +++++++++++++----- .../tests/api/EIPs/eip-1559-FeeMarket.spec.ts | 8 ++++---- packages/vm/tests/api/EIPs/eip-2929.spec.ts | 4 ++-- 9 files changed, 32 insertions(+), 23 deletions(-) diff --git a/packages/vm/benchmarks/util.ts b/packages/vm/benchmarks/util.ts index a57a66f013..c2b1b29efa 100644 --- a/packages/vm/benchmarks/util.ts +++ b/packages/vm/benchmarks/util.ts @@ -1,4 +1,4 @@ -import { Account, Address, toBuffer, bufferToInt, BN } from 'ethereumjs-util' +import { Account, Address, toBuffer, bufferToInt, BN, bnToBigInt } from 'ethereumjs-util' import Common from '@ethereumjs/common' import { Block } from '@ethereumjs/block' import { StateManager, DefaultStateManager } from '../dist/state' @@ -100,7 +100,7 @@ export const verifyResult = (block: Block, result: RunBlockResult) => { if (!result.logsBloom.equals(block.header.logsBloom)) { throw new Error('invalid logsBloom') } - if (!(BigInt(block.header.gasUsed.toString(10)) === result.gasUsed)) { + if (!(bnToBigInt(block.header.gasUsed) === result.gasUsed)) { throw new Error('invalid gasUsed') } } diff --git a/packages/vm/src/buildBlock.ts b/packages/vm/src/buildBlock.ts index d0e2f70b53..4ac9a46263 100644 --- a/packages/vm/src/buildBlock.ts +++ b/packages/vm/src/buildBlock.ts @@ -1,4 +1,4 @@ -import { Address, toBuffer, rlp, BN, bnToBigInt } from 'ethereumjs-util' +import { Address, toBuffer, rlp, BN, bnToBigInt, bigIntToBN } from 'ethereumjs-util' import { BaseTrie as Trie } from 'merkle-patricia-tree' import { Block, BlockOptions, HeaderData } from '@ethereumjs/block' import { ConsensusType } from '@ethereumjs/common' @@ -177,7 +177,7 @@ export class BlockBuilder { const header = { ...this.headerData, - gasUsed: new BN(this.gasUsed.toString(10), 10), + gasUsed: bigIntToBN(this.gasUsed), } const blockData = { header, transactions: this.transactions } const block = Block.fromBlockData(blockData, this.blockOpts) @@ -226,7 +226,7 @@ export class BlockBuilder { const transactionsTrie = await this.transactionsTrie() const receiptTrie = await this.receiptTrie() const logsBloom = this.logsBloom() - const gasUsed = new BN(this.gasUsed.toString(10), 10) + const gasUsed = bigIntToBN(this.gasUsed) const timestamp = this.headerData.timestamp ?? Math.round(Date.now() / 1000) const headerData = { diff --git a/packages/vm/src/evm/evm.ts b/packages/vm/src/evm/evm.ts index 6a397bf4b5..bab39f98f9 100644 --- a/packages/vm/src/evm/evm.ts +++ b/packages/vm/src/evm/evm.ts @@ -2,6 +2,7 @@ import { debug as createDebugLogger } from 'debug' import { Account, Address, + bigIntToBN, BN, generateAddress, generateAddress2, @@ -573,7 +574,7 @@ export default class EVM { } async _reduceSenderBalance(account: Account, message: Message): Promise { - account.balance.isub(new BN(message.value.toString(10))) + account.balance.isub(bigIntToBN(message.value)) const result = this._state.putAccount(message.caller, account) if (this._vm.DEBUG) { debug(`Reduced sender (${message.caller}) balance (-> ${account.balance})`) @@ -582,7 +583,7 @@ export default class EVM { } async _addToBalance(toAccount: Account, message: Message): Promise { - const newBalance = toAccount.balance.add(new BN(message.value.toString(10))) + const newBalance = toAccount.balance.add(bigIntToBN(message.value)) if (newBalance.gt(MAX_INTEGER)) { throw new VmError(ERROR.VALUE_OVERFLOW) } diff --git a/packages/vm/src/evm/opcodes/functions.ts b/packages/vm/src/evm/opcodes/functions.ts index 1b4bf60c6c..9abcd258fd 100644 --- a/packages/vm/src/evm/opcodes/functions.ts +++ b/packages/vm/src/evm/opcodes/functions.ts @@ -374,7 +374,7 @@ export const handlers: Map = new Map([ if (!(length === 0n)) { data = runState.memory.read(Number(offset), Number(length)) } - const r = BigInt('0x' + keccak256(data).toString('hex')) + const r = bufferToBigInt(keccak256(data)) runState.stack.push(r) }, ], diff --git a/packages/vm/src/evm/opcodes/gas.ts b/packages/vm/src/evm/opcodes/gas.ts index 42ea487045..5a8cf55c08 100644 --- a/packages/vm/src/evm/opcodes/gas.ts +++ b/packages/vm/src/evm/opcodes/gas.ts @@ -423,7 +423,7 @@ export const dynamicGasHandlers: Map = new Map< } gas += BigInt(common.param('gasPrices', 'sha3Word')) * divCeil(length, 32n) - let gasLimit = BigInt(runState.eei.getGasLeft()) - gas + let gasLimit = runState.eei.getGasLeft() - gas gasLimit = maxCallGas(gasLimit, gasLimit, runState, common) // CREATE2 is only available after TangerineWhistle (Constantinople introduced this opcode) runState.messageGasLimit = gasLimit return gas diff --git a/packages/vm/src/runBlock.ts b/packages/vm/src/runBlock.ts index 1b5f48284d..54a2450f74 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, BN, bnToBigInt, intToBuffer, rlp } from 'ethereumjs-util' +import { Account, Address, bigIntToBN, BN, bnToBigInt, intToBuffer, rlp } from 'ethereumjs-util' import { Block } from '@ethereumjs/block' import { ConsensusType } from '@ethereumjs/common' import VM from './index' @@ -183,7 +183,7 @@ export default async function runBlock(this: VM, opts: RunBlockOpts): Promise { const account = await state.getAccount(address) - account.balance.iadd(new BN(reward.toString(10), 10)) + account.balance.iadd(bigIntToBN(reward)) await state.putAccount(address, account) return account } diff --git a/packages/vm/src/runTx.ts b/packages/vm/src/runTx.ts index 4b945b87e6..80ef50f0e4 100644 --- a/packages/vm/src/runTx.ts +++ b/packages/vm/src/runTx.ts @@ -1,5 +1,13 @@ import { debug as createDebugLogger } from 'debug' -import { Address, bigIntToBuffer, BN, bnToBigInt, KECCAK256_NULL, toBuffer } from 'ethereumjs-util' +import { + Address, + bigIntToBN, + bigIntToBuffer, + BN, + bnToBigInt, + KECCAK256_NULL, + toBuffer, +} from 'ethereumjs-util' import { Block } from '@ethereumjs/block' import { ConsensusType } from '@ethereumjs/common' import { @@ -369,7 +377,7 @@ async function _runTx(this: VM, opts: RunTxOpts): Promise { // Update from account's nonce and balance fromAccount.nonce.iaddn(1) const txCost = bnToBigInt(tx.gasLimit) * gasPrice - fromAccount.balance.isub(new BN(txCost.toString(10), 10)) + fromAccount.balance.isub(bigIntToBN(txCost)) await state.putAccount(caller, fromAccount) if (this.DEBUG) { debug( @@ -450,7 +458,7 @@ async function _runTx(this: VM, opts: RunTxOpts): Promise { fromAccount = await state.getAccount(caller) const actualTxCost = results.gasUsed * gasPrice const txCostDiff = txCost - actualTxCost - fromAccount.balance.iadd(new BN(txCostDiff.toString(10), 10)) + fromAccount.balance.iadd(bigIntToBN(txCostDiff)) await state.putAccount(caller, fromAccount) if (this.DEBUG) { debug( @@ -475,9 +483,9 @@ 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.iadd(new BN(results.gasUsed.toString(10), 10).mul(inclusionFeePerGas)) + minerAccount.balance.iadd(bigIntToBN(results.gasUsed).mul(inclusionFeePerGas)) } else { - minerAccount.balance.iadd(new BN(results.amountSpent.toString(10))) + minerAccount.balance.iadd(bigIntToBN(results.amountSpent)) } // Put the miner account into the state. If the balance of the miner account remains zero, note that diff --git a/packages/vm/tests/api/EIPs/eip-1559-FeeMarket.spec.ts b/packages/vm/tests/api/EIPs/eip-1559-FeeMarket.spec.ts index 0ac6520e31..82d855fe49 100644 --- a/packages/vm/tests/api/EIPs/eip-1559-FeeMarket.spec.ts +++ b/packages/vm/tests/api/EIPs/eip-1559-FeeMarket.spec.ts @@ -1,5 +1,5 @@ import tape from 'tape' -import { Address, BN, privateToAddress, setLengthLeft } from 'ethereumjs-util' +import { Address, bigIntToBN, BN, privateToAddress, setLengthLeft } from 'ethereumjs-util' import VM from '../../../src' import Common, { Chain, Hardfork } from '@ethereumjs/common' import { @@ -98,7 +98,7 @@ tape('EIP1559 tests', (t) => { st.ok(miner.balance.eq(expectedMinerBalance), 'miner balance correct') account = await vm.stateManager.getAccount(sender) st.ok(account.balance.eq(expectedAccountBalance), 'account balance correct') - st.ok(new BN(results.amountSpent.toString(10), 10).eq(expectedCost), 'reported cost correct') + st.ok(bigIntToBN(results.amountSpent).eq(expectedCost), 'reported cost correct') const tx2 = new AccessListEIP2930Transaction( { @@ -129,7 +129,7 @@ tape('EIP1559 tests', (t) => { st.ok(miner.balance.eq(expectedMinerBalance), 'miner balance correct') account = await vm.stateManager.getAccount(sender) st.ok(account.balance.eq(expectedAccountBalance), 'account balance correct') - st.ok(new BN(results2.amountSpent.toString(10), 10).eq(expectedCost), 'reported cost correct') + st.ok(bigIntToBN(results2.amountSpent).eq(expectedCost), 'reported cost correct') const tx3 = new Transaction( { @@ -160,7 +160,7 @@ tape('EIP1559 tests', (t) => { st.ok(miner.balance.eq(expectedMinerBalance), 'miner balance correct') account = await vm.stateManager.getAccount(sender) st.ok(account.balance.eq(expectedAccountBalance), 'account balance correct') - st.ok(new BN(results3.amountSpent.toString(10), 10).eq(expectedCost), 'reported cost correct') + st.ok(bigIntToBN(results3.amountSpent).eq(expectedCost), 'reported cost correct') st.end() }) diff --git a/packages/vm/tests/api/EIPs/eip-2929.spec.ts b/packages/vm/tests/api/EIPs/eip-2929.spec.ts index b2916216e3..406afae1a5 100644 --- a/packages/vm/tests/api/EIPs/eip-2929.spec.ts +++ b/packages/vm/tests/api/EIPs/eip-2929.spec.ts @@ -1,5 +1,5 @@ import tape from 'tape' -import { Account, Address, BN } from 'ethereumjs-util' +import { Account, Address, bigIntToBN, BN } from 'ethereumjs-util' import VM from '../../../src' import Common, { Chain, Hardfork } from '@ethereumjs/common' import { Transaction } from '@ethereumjs/tx' @@ -51,7 +51,7 @@ tape('EIP 2929: gas cost tests', (t) => { await vm.stateManager.putContractCode(address, Buffer.from(test.code, 'hex')) const unsignedTx = Transaction.fromTxData({ - gasLimit: new BN(initialGas.toString(10)), // ensure we pass a lot of gas, so we do not run out of gas + gasLimit: bigIntToBN(initialGas), // ensure we pass a lot of gas, so we do not run out of gas to: address, // call to the contract address, }) From 65cc36cb6189cea89e7e9a7cde6ca2145fd332d5 Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Tue, 8 Feb 2022 20:54:33 -0500 Subject: [PATCH 36/42] Lint fixes --- packages/util/src/types.ts | 7 +++---- packages/vm/src/buildBlock.ts | 2 +- packages/vm/src/evm/evm.ts | 1 - packages/vm/src/evm/opcodes/gas.ts | 3 +-- packages/vm/src/runBlock.ts | 2 +- packages/vm/src/runTx.ts | 1 + 6 files changed, 7 insertions(+), 9 deletions(-) diff --git a/packages/util/src/types.ts b/packages/util/src/types.ts index f1ed682233..3c7191e0fe 100644 --- a/packages/util/src/types.ts +++ b/packages/util/src/types.ts @@ -145,12 +145,11 @@ export function toType( } } -export const bnToBigInt = (bn: BNLike | undefined) => { - if (bn) { - return BigInt(new BN(bn).toString(10)) - } else { +export const bnToBigInt = (bn: BN | undefined) => { + if (!bn) { return 0n } + return BigInt(new BN(bn).toString(10)) } export const bigIntToBN = (num: bigint) => { diff --git a/packages/vm/src/buildBlock.ts b/packages/vm/src/buildBlock.ts index 4ac9a46263..4d38d3dad1 100644 --- a/packages/vm/src/buildBlock.ts +++ b/packages/vm/src/buildBlock.ts @@ -1,4 +1,4 @@ -import { Address, toBuffer, rlp, BN, bnToBigInt, bigIntToBN } from 'ethereumjs-util' +import { Address, toBuffer, rlp, bnToBigInt, bigIntToBN } from 'ethereumjs-util' import { BaseTrie as Trie } from 'merkle-patricia-tree' import { Block, BlockOptions, HeaderData } from '@ethereumjs/block' import { ConsensusType } from '@ethereumjs/common' diff --git a/packages/vm/src/evm/evm.ts b/packages/vm/src/evm/evm.ts index bab39f98f9..1399811a43 100644 --- a/packages/vm/src/evm/evm.ts +++ b/packages/vm/src/evm/evm.ts @@ -3,7 +3,6 @@ import { Account, Address, bigIntToBN, - BN, generateAddress, generateAddress2, KECCAK256_NULL, diff --git a/packages/vm/src/evm/opcodes/gas.ts b/packages/vm/src/evm/opcodes/gas.ts index 5a8cf55c08..6fc8cfbe50 100644 --- a/packages/vm/src/evm/opcodes/gas.ts +++ b/packages/vm/src/evm/opcodes/gas.ts @@ -249,8 +249,7 @@ export const dynamicGasHandlers: Map = new Map< } gas += subMemUsage(runState, memOffset, memLength, common) - gas = - gas + + gas += BigInt(common.param('gasPrices', 'logTopic')) * BigInt(topicsCount) + memLength * BigInt(common.param('gasPrices', 'logData')) return gas diff --git a/packages/vm/src/runBlock.ts b/packages/vm/src/runBlock.ts index 54a2450f74..2b55bf9de1 100644 --- a/packages/vm/src/runBlock.ts +++ b/packages/vm/src/runBlock.ts @@ -327,7 +327,7 @@ async function applyTransactions(this: VM, block: Block, opts: RunBlockOpts) { } else { maxGasLimit = block.header.gasLimit } - + // eslint-disable-next-line @typescript-eslint/restrict-plus-operands const gasLimitIsHigherThanBlock = maxGasLimit < bnToBigInt(tx.gasLimit) + gasUsed if (gasLimitIsHigherThanBlock) { const msg = _errorMsg('tx has a higher gas limit than the block', this, block) diff --git a/packages/vm/src/runTx.ts b/packages/vm/src/runTx.ts index 80ef50f0e4..ce99de9b21 100644 --- a/packages/vm/src/runTx.ts +++ b/packages/vm/src/runTx.ts @@ -514,6 +514,7 @@ async function _runTx(this: VM, opts: RunTxOpts): Promise { // Generate the tx receipt const gasUsed = opts.blockGasUsed ?? bnToBigInt(block.header.gasUsed) + // eslint-disable-next-line @typescript-eslint/restrict-plus-operands const cumulativeGasUsed = gasUsed + results.gasUsed results.receipt = await generateTxReceipt.bind(this)(tx, results, cumulativeGasUsed) From 0cce60fd8bfebdeacb5d3aa28b20cf556381a9a0 Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Tue, 8 Feb 2022 21:13:40 -0500 Subject: [PATCH 37/42] Fix bnToBigInt --- packages/util/src/types.ts | 5 +---- packages/vm/src/buildBlock.ts | 13 +++++++++++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/packages/util/src/types.ts b/packages/util/src/types.ts index 3c7191e0fe..633dfe8362 100644 --- a/packages/util/src/types.ts +++ b/packages/util/src/types.ts @@ -145,10 +145,7 @@ export function toType( } } -export const bnToBigInt = (bn: BN | undefined) => { - if (!bn) { - return 0n - } +export const bnToBigInt = (bn: BN) => { return BigInt(new BN(bn).toString(10)) } diff --git a/packages/vm/src/buildBlock.ts b/packages/vm/src/buildBlock.ts index 4d38d3dad1..f12961f86d 100644 --- a/packages/vm/src/buildBlock.ts +++ b/packages/vm/src/buildBlock.ts @@ -1,4 +1,13 @@ -import { Address, toBuffer, rlp, bnToBigInt, bigIntToBN } from 'ethereumjs-util' +import { + Address, + toBuffer, + rlp, + bnToBigInt, + bigIntToBN, + BN, + toType, + TypeOutput, +} from 'ethereumjs-util' import { BaseTrie as Trie } from 'merkle-patricia-tree' import { Block, BlockOptions, HeaderData } from '@ethereumjs/block' import { ConsensusType } from '@ethereumjs/common' @@ -169,7 +178,7 @@ export class BlockBuilder { // According to the Yellow Paper, a transaction's gas limit // cannot be greater than the remaining gas in the block - const blockGasLimit = bnToBigInt(this.headerData.gasLimit) + const blockGasLimit = bnToBigInt(toType(this.headerData.gasLimit, TypeOutput.BN)) const blockGasRemaining = blockGasLimit - this.gasUsed if (bnToBigInt(tx.gasLimit) > blockGasRemaining) { throw new Error('tx has a higher gas limit than the remaining gas in the block') From f25514c63aa471ef9815d2d688daf378d59ccce2 Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Tue, 8 Feb 2022 21:23:14 -0500 Subject: [PATCH 38/42] Lint/test fixes --- packages/util/test/types.spec.ts | 1 - packages/vm/src/buildBlock.ts | 11 +---------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/packages/util/test/types.spec.ts b/packages/util/test/types.spec.ts index c737203e7e..98a3f73e8e 100644 --- a/packages/util/test/types.spec.ts +++ b/packages/util/test/types.spec.ts @@ -148,7 +148,6 @@ tape('bnToUnpaddedBuffer', function (t) { tape('bnToBigInt', (st) => { st.equal(bnToBigInt(new BN(1)), 1n) - st.equal(bnToBigInt(undefined), 0n) st.end() }) diff --git a/packages/vm/src/buildBlock.ts b/packages/vm/src/buildBlock.ts index f12961f86d..08d1ffffe8 100644 --- a/packages/vm/src/buildBlock.ts +++ b/packages/vm/src/buildBlock.ts @@ -1,13 +1,4 @@ -import { - Address, - toBuffer, - rlp, - bnToBigInt, - bigIntToBN, - BN, - toType, - TypeOutput, -} from 'ethereumjs-util' +import { Address, toBuffer, rlp, bnToBigInt, bigIntToBN, toType, TypeOutput } from 'ethereumjs-util' import { BaseTrie as Trie } from 'merkle-patricia-tree' import { Block, BlockOptions, HeaderData } from '@ethereumjs/block' import { ConsensusType } from '@ethereumjs/common' From d7387f4ca4bdc23f8dd16e472a25bb93de166691 Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Tue, 22 Feb 2022 07:36:20 -0500 Subject: [PATCH 39/42] Switch Xn to BigInt(X) --- packages/util/src/bytes.ts | 2 +- packages/util/src/constants.ts | 4 +- packages/util/test/bytes.spec.ts | 4 +- packages/util/test/types.spec.ts | 6 +- packages/vm/src/buildBlock.ts | 2 +- packages/vm/src/evm/eei.ts | 18 +-- packages/vm/src/evm/evm.ts | 14 +-- packages/vm/src/evm/interpreter.ts | 4 +- packages/vm/src/evm/message.ts | 2 +- packages/vm/src/evm/opcodes/EIP2929.ts | 8 +- packages/vm/src/evm/opcodes/functions.ts | 112 +++++++++--------- packages/vm/src/evm/opcodes/gas.ts | 42 +++---- packages/vm/src/evm/opcodes/util.ts | 28 ++--- packages/vm/src/evm/precompiles/05-modexp.ts | 70 +++++------ .../evm/precompiles/0c-bls12-g1multiexp.ts | 2 +- .../evm/precompiles/0f-bls12-g2multiexp.ts | 2 +- packages/vm/src/runBlock.ts | 10 +- packages/vm/src/runCall.ts | 5 +- packages/vm/src/runCode.ts | 2 +- packages/vm/src/runTx.ts | 4 +- .../vm/tests/api/EIPs/eip-2537-BLS.spec.ts | 8 +- .../api/EIPs/eip-2565-modexp-gas-cost.spec.ts | 2 +- packages/vm/tests/api/EIPs/eip-2929.spec.ts | 44 +++---- .../api/EIPs/eip-2930-accesslists.spec.ts | 4 +- .../tests/api/EIPs/eip-3198-BaseFee.spec.ts | 2 +- packages/vm/tests/api/EIPs/eip-3529.spec.ts | 8 +- packages/vm/tests/api/EIPs/eip-3855.spec.ts | 12 +- .../api/evm/precompiles/06-ecadd.spec.ts | 2 +- .../api/evm/precompiles/07-ecmul.spec.ts | 2 +- .../api/evm/precompiles/08-ecpairing.spec.ts | 6 +- .../api/evm/precompiles/hardfork.spec.ts | 12 +- packages/vm/tests/api/evm/stack.spec.ts | 44 +++---- .../vm/tests/api/istanbul/eip-1108.spec.ts | 10 +- .../vm/tests/api/istanbul/eip-152.spec.ts | 4 +- .../vm/tests/api/istanbul/eip-2200.spec.ts | 44 +++---- packages/vm/tests/api/runBlock.spec.ts | 6 +- packages/vm/tests/api/runCall.spec.ts | 26 ++-- packages/vm/tests/api/runTx.spec.ts | 12 +- .../vm/tests/api/state/accountExists.spec.ts | 8 +- .../tester/runners/BlockchainTestsRunner.ts | 2 +- 40 files changed, 306 insertions(+), 293 deletions(-) diff --git a/packages/util/src/bytes.ts b/packages/util/src/bytes.ts index f49d3250d8..3bc3d97b41 100644 --- a/packages/util/src/bytes.ts +++ b/packages/util/src/bytes.ts @@ -339,7 +339,7 @@ export function bufArrToArr(arr: Buffer | NestedBufferArray): Uint8Array | Neste export function bufferToBigInt(buf: Buffer) { const hex = bufferToHex(buf) if (hex === '0x') { - return 0n + return BigInt(0) } return BigInt(hex) } diff --git a/packages/util/src/constants.ts b/packages/util/src/constants.ts index ce323d7d01..20dc334dc6 100644 --- a/packages/util/src/constants.ts +++ b/packages/util/src/constants.ts @@ -17,7 +17,7 @@ export const MAX_INTEGER = new BN( /** * The max integer that the evm can handle (2^256-1) as a bigint */ -export const MAX_INTEGER_BIGINT = 2n ** 256n - 1n +export const MAX_INTEGER_BIGINT = BigInt(2) ** BigInt(256) - BigInt(1) /** * 2^256 @@ -32,7 +32,7 @@ export const TWO_POW256 = new BN( /** * 2^256 */ -export const TWO_POW256_BIGINT = 2n ** 256n +export const TWO_POW256_BIGINT = BigInt(2) ** BigInt(256) /** * Keccak-256 hash of null diff --git a/packages/util/test/bytes.spec.ts b/packages/util/test/bytes.spec.ts index 7813f4c93f..e8e1efef62 100644 --- a/packages/util/test/bytes.spec.ts +++ b/packages/util/test/bytes.spec.ts @@ -448,12 +448,12 @@ tape('bufArrToArr', function (st) { tape('bufferToBigInt', (st) => { const buf = toBuffer('0x123') - st.equal(0x123n, bufferToBigInt(buf)) + st.equal(BigInt(0x123), bufferToBigInt(buf)) st.end() }) tape('bigIntToBuffer', (st) => { - const num = 0x123n + const num = BigInt(0x123) st.deepEqual(toBuffer('0x123'), bigIntToBuffer(num)) st.end() }) diff --git a/packages/util/test/types.spec.ts b/packages/util/test/types.spec.ts index 98a3f73e8e..ac1f62f5aa 100644 --- a/packages/util/test/types.spec.ts +++ b/packages/util/test/types.spec.ts @@ -147,16 +147,16 @@ tape('bnToUnpaddedBuffer', function (t) { }) tape('bnToBigInt', (st) => { - st.equal(bnToBigInt(new BN(1)), 1n) + st.equal(bnToBigInt(new BN(1)), BigInt(1)) st.end() }) tape('bigIntToBN', (st) => { - st.ok(bigIntToBN(1n).eq(new BN(1))) + st.ok(bigIntToBN(BigInt(1)).eq(new BN(1))) st.end() }) tape('bigIntToHex', (st) => { - st.equal(bigIntToHex(1n), '0x1') + st.equal(bigIntToHex(BigInt(1)), '0x1') st.end() }) diff --git a/packages/vm/src/buildBlock.ts b/packages/vm/src/buildBlock.ts index 08d1ffffe8..e073a79bc3 100644 --- a/packages/vm/src/buildBlock.ts +++ b/packages/vm/src/buildBlock.ts @@ -66,7 +66,7 @@ export class BlockBuilder { /** * The cumulative gas used by the transactions added to the block. */ - gasUsed = 0n + gasUsed = BigInt(0) private readonly vm: VM private blockOpts: BuilderOpts diff --git a/packages/vm/src/evm/eei.ts b/packages/vm/src/evm/eei.ts index 4d6be96709..6e84fbbde6 100644 --- a/packages/vm/src/evm/eei.ts +++ b/packages/vm/src/evm/eei.ts @@ -90,8 +90,8 @@ export default class EEI { if (this._evm._vm.DEBUG) { debugGas(`${context ? context + ': ' : ''}used ${amount} gas (-> ${this._gasLeft})`) } - if (this._gasLeft < 0n) { - this._gasLeft = 0n + if (this._gasLeft < BigInt(0)) { + this._gasLeft = BigInt(0) trap(ERROR.OUT_OF_GAS) } } @@ -118,8 +118,8 @@ export default class EEI { debugGas(`${context ? context + ': ' : ''}sub gas refund ${amount} (-> ${this._evm._refund})`) } this._evm._refund -= amount - if (this._evm._refund < 0n) { - this._evm._refund = 0n + if (this._evm._refund < BigInt(0)) { + this._evm._refund = BigInt(0) trap(ERROR.REFUND_EXHAUSTED) } } @@ -537,7 +537,7 @@ export default class EEI { this._env.depth >= this._common.param('vm', 'stackLimit') || (msg.delegatecall !== true && bnToBigInt(this._env.contract.balance) < msg.value) ) { - return 0n + return BigInt(0) } const results = await this._evm.executeMessage(msg) @@ -596,12 +596,12 @@ export default class EEI { this._env.depth >= this._common.param('vm', 'stackLimit') || (msg.delegatecall !== true && bnToBigInt(this._env.contract.balance) < msg.value) ) { - return 0n + return BigInt(0) } // EIP-2681 check if (this._env.contract.nonce.gte(MAX_UINT64)) { - return 0n + return BigInt(0) } this._env.contract.nonce.iaddn(1) await this._state.putAccount(this._env.address, this._env.contract) @@ -668,9 +668,9 @@ export default class EEI { // This preserves the previous logic, but seems to contradict the EEI spec // https://github.com/ewasm/design/blob/38eeded28765f3e193e12881ea72a6ab807a3371/eth_interface.md if (results.execResult.exceptionError) { - return 0n + return BigInt(0) } else { - return 1n + return BigInt(1) } } } diff --git a/packages/vm/src/evm/evm.ts b/packages/vm/src/evm/evm.ts index 1399811a43..0dfe9c54d0 100644 --- a/packages/vm/src/evm/evm.ts +++ b/packages/vm/src/evm/evm.ts @@ -135,7 +135,7 @@ export default class EVM { this._state = this._vm.stateManager this._tx = txContext this._block = block - this._refund = 0n + this._refund = BigInt(0) } /** @@ -266,9 +266,9 @@ export default class EVM { } if (exit) { return { - gasUsed: 0n, + gasUsed: BigInt(0), execResult: { - gasUsed: 0n, + gasUsed: BigInt(0), exceptionError: errorMessage, // Only defined if addToBalance failed returnValue: Buffer.alloc(0), }, @@ -365,10 +365,10 @@ export default class EVM { } if (exit) { return { - gasUsed: 0n, + gasUsed: BigInt(0), createdAddress: message.to, execResult: { - gasUsed: 0n, + gasUsed: BigInt(0), exceptionError: errorMessage, // only defined if addToBalance failed returnValue: Buffer.alloc(0), }, @@ -382,7 +382,7 @@ export default class EVM { // fee for size of the return value let totalGas = result.gasUsed - let returnFee = 0n + let returnFee = BigInt(0) if (!result.exceptionError) { returnFee = BigInt(result.returnValue.length) * @@ -470,7 +470,7 @@ export default class EVM { address: message.to || Address.zero(), caller: message.caller || Address.zero(), callData: message.data || Buffer.from([0]), - callValue: message.value || 0n, + callValue: message.value || BigInt(0), code: message.code as Buffer, isStatic: message.isStatic || false, depth: message.depth || 0, diff --git a/packages/vm/src/evm/interpreter.ts b/packages/vm/src/evm/interpreter.ts index e0f51a3671..5d9950aaed 100644 --- a/packages/vm/src/evm/interpreter.ts +++ b/packages/vm/src/evm/interpreter.ts @@ -74,8 +74,8 @@ export default class Interpreter { programCounter: 0, opCode: 0xfe, // INVALID opcode memory: new Memory(), - memoryWordCount: 0n, - highestMemCost: 0n, + memoryWordCount: BigInt(0), + highestMemCost: BigInt(0), stack: new Stack(), returnStack: new Stack(1023), // 1023 return stack height limit per EIP 2315 spec code: Buffer.alloc(0), diff --git a/packages/vm/src/evm/message.ts b/packages/vm/src/evm/message.ts index d7a27a4e56..7d938ef6e6 100644 --- a/packages/vm/src/evm/message.ts +++ b/packages/vm/src/evm/message.ts @@ -18,7 +18,7 @@ export default class Message { constructor(opts: any) { this.to = opts.to - this.value = opts.value ? opts.value : 0n + this.value = opts.value ? opts.value : BigInt(0) this.caller = opts.caller this.gasLimit = opts.gasLimit this.data = opts.data || Buffer.alloc(0) diff --git a/packages/vm/src/evm/opcodes/EIP2929.ts b/packages/vm/src/evm/opcodes/EIP2929.ts index 4f50f3be6b..c9780cc55f 100644 --- a/packages/vm/src/evm/opcodes/EIP2929.ts +++ b/packages/vm/src/evm/opcodes/EIP2929.ts @@ -20,7 +20,7 @@ export function accessAddressEIP2929( chargeGas = true, isSelfdestruct = false ): bigint { - if (!common.isActivatedEIP(2929)) return 0n + if (!common.isActivatedEIP(2929)) return BigInt(0) const stateManager = runState.stateManager as EIP2929StateManager const addressStr = address.buf @@ -38,7 +38,7 @@ export function accessAddressEIP2929( } else if (chargeGas && !isSelfdestruct) { return BigInt(common.param('gasPrices', 'warmstorageread')) } - return 0n + return BigInt(0) } /** @@ -55,7 +55,7 @@ export function accessStorageEIP2929( isSstore: boolean, common: Common ): bigint { - if (!common.isActivatedEIP(2929)) return 0n + if (!common.isActivatedEIP(2929)) return BigInt(0) const stateManager = runState.stateManager as EIP2929StateManager const address = runState.eei.getAddress().buf @@ -68,7 +68,7 @@ export function accessStorageEIP2929( } else if (!isSstore) { return BigInt(common.param('gasPrices', 'warmstorageread')) } - return 0n + return BigInt(0) } /** diff --git a/packages/vm/src/evm/opcodes/functions.ts b/packages/vm/src/evm/opcodes/functions.ts index 9abcd258fd..596903dfd6 100644 --- a/packages/vm/src/evm/opcodes/functions.ts +++ b/packages/vm/src/evm/opcodes/functions.ts @@ -77,8 +77,8 @@ export const handlers: Map = new Map([ function (runState) { const [a, b] = runState.stack.popN(2) let r - if (b === 0n) { - r = 0n + if (b === BigInt(0)) { + r = BigInt(0) } else { r = mod(a / b, TWO_POW256_BIGINT) } @@ -91,8 +91,8 @@ export const handlers: Map = new Map([ function (runState) { const [a, b] = runState.stack.popN(2) let r - if (b === 0n) { - r = 0n + if (b === BigInt(0)) { + r = BigInt(0) } else { r = toTwos(fromTwos(a) / fromTwos(b)) } @@ -105,7 +105,7 @@ export const handlers: Map = new Map([ function (runState) { const [a, b] = runState.stack.popN(2) let r - if (b === 0n) { + if (b === BigInt(0)) { r = b } else { r = mod(a, b) @@ -119,7 +119,7 @@ export const handlers: Map = new Map([ function (runState) { const [a, b] = runState.stack.popN(2) let r - if (b === 0n) { + if (b === BigInt(0)) { r = b } else { r = fromTwos(a) % fromTwos(b) @@ -133,8 +133,8 @@ export const handlers: Map = new Map([ function (runState) { const [a, b, c] = runState.stack.popN(3) let r - if (c === 0n) { - r = 0n + if (c === BigInt(0)) { + r = BigInt(0) } else { r = mod(a + b, c) } @@ -147,8 +147,8 @@ export const handlers: Map = new Map([ function (runState) { const [a, b, c] = runState.stack.popN(3) let r - if (c === 0n) { - r = 0n + if (c === BigInt(0)) { + r = BigInt(0) } else { r = mod(a * b, c) } @@ -160,8 +160,8 @@ export const handlers: Map = new Map([ 0x0a, function (runState, common) { const [base, exponent] = runState.stack.popN(2) - if (exponent === 0n) { - runState.stack.push(1n) + if (exponent === BigInt(0)) { + runState.stack.push(BigInt(1)) return } let byteLength = exponent.toString(2).length / 8 @@ -175,7 +175,7 @@ export const handlers: Map = new Map([ const amount = byteLength * gasPrice runState.eei.useGas(BigInt(amount), 'EXP opcode') - if (base === 0n) { + if (base === BigInt(0)) { runState.stack.push(base) return } @@ -189,10 +189,10 @@ export const handlers: Map = new Map([ function (runState) { /* eslint-disable-next-line prefer-const */ let [k, val] = runState.stack.popN(2) - if (k < 31n) { - const signBit = k * 8n + 7n - const mask = (1n << signBit) - 1n - if ((val >> signBit) & 1n) { + if (k < BigInt(31)) { + const signBit = k * BigInt(8) + BigInt(7) + const mask = (BigInt(1) << signBit) - BigInt(1) + if ((val >> signBit) & BigInt(1)) { val = val | BigInt.asUintN(256, ~mask) } else { val = val & mask @@ -207,7 +207,7 @@ export const handlers: Map = new Map([ 0x10, function (runState) { const [a, b] = runState.stack.popN(2) - const r = a < b ? 1n : 0n + const r = a < b ? BigInt(1) : BigInt(0) runState.stack.push(r) }, ], @@ -216,7 +216,7 @@ export const handlers: Map = new Map([ 0x11, function (runState) { const [a, b] = runState.stack.popN(2) - const r = a > b ? 1n : 0n + const r = a > b ? BigInt(1) : BigInt(0) runState.stack.push(r) }, ], @@ -225,7 +225,7 @@ export const handlers: Map = new Map([ 0x12, function (runState) { const [a, b] = runState.stack.popN(2) - const r = fromTwos(a) < fromTwos(b) ? 1n : 0n + const r = fromTwos(a) < fromTwos(b) ? BigInt(1) : BigInt(0) runState.stack.push(r) }, ], @@ -234,7 +234,7 @@ export const handlers: Map = new Map([ 0x13, function (runState) { const [a, b] = runState.stack.popN(2) - const r = fromTwos(a) > fromTwos(b) ? 1n : 0n + const r = fromTwos(a) > fromTwos(b) ? BigInt(1) : BigInt(0) runState.stack.push(r) }, ], @@ -243,7 +243,7 @@ export const handlers: Map = new Map([ 0x14, function (runState) { const [a, b] = runState.stack.popN(2) - const r = a === b ? 1n : 0n + const r = a === b ? BigInt(1) : BigInt(0) runState.stack.push(r) }, ], @@ -252,7 +252,7 @@ export const handlers: Map = new Map([ 0x15, function (runState) { const a = runState.stack.pop() - const r = a === 0n ? 1n : 0n + const r = a === BigInt(0) ? BigInt(1) : BigInt(0) runState.stack.push(r) }, ], @@ -297,12 +297,12 @@ export const handlers: Map = new Map([ 0x1a, function (runState) { const [pos, word] = runState.stack.popN(2) - if (pos > 32n) { - runState.stack.push(0n) + if (pos > BigInt(32)) { + runState.stack.push(BigInt(0)) return } - const r = (word >> ((31n - pos) * 8n)) & BigInt(0xff) + const r = (word >> ((BigInt(31) - pos) * BigInt(8))) & BigInt(0xff) runState.stack.push(r) }, ], @@ -311,8 +311,8 @@ export const handlers: Map = new Map([ 0x1b, function (runState) { const [a, b] = runState.stack.popN(2) - if (a > 256n) { - runState.stack.push(0n) + if (a > BigInt(256)) { + runState.stack.push(BigInt(0)) return } @@ -326,7 +326,7 @@ export const handlers: Map = new Map([ function (runState) { const [a, b] = runState.stack.popN(2) if (a > 256) { - runState.stack.push(0n) + runState.stack.push(BigInt(0)) return } @@ -347,7 +347,7 @@ export const handlers: Map = new Map([ if (isSigned) { r = MAX_INTEGER_BIGINT } else { - r = 0n + r = BigInt(0) } runState.stack.push(r) return @@ -355,7 +355,7 @@ export const handlers: Map = new Map([ const c = b >> a if (isSigned) { - const shiftedOutWidth = 255n - a + const shiftedOutWidth = BigInt(255) - a const mask = (MAX_INTEGER_BIGINT >> shiftedOutWidth) << shiftedOutWidth r = c | mask } else { @@ -371,7 +371,7 @@ export const handlers: Map = new Map([ function (runState) { const [offset, length] = runState.stack.popN(2) let data = Buffer.alloc(0) - if (!(length === 0n)) { + if (!(length === BigInt(0))) { data = runState.memory.read(Number(offset), Number(length)) } const r = bufferToBigInt(keccak256(data)) @@ -424,7 +424,7 @@ export const handlers: Map = new Map([ function (runState) { const pos = runState.stack.pop() if (pos > runState.eei.getCallDataSize()) { - runState.stack.push(0n) + runState.stack.push(BigInt(0)) return } @@ -433,7 +433,7 @@ export const handlers: Map = new Map([ loaded = loaded.length ? loaded : Buffer.from([0]) let r = bufferToBigInt(loaded) if (loaded.length < 32) { - r = r << (8n * BigInt(32 - loaded.length)) + r = r << (BigInt(8) * BigInt(32 - loaded.length)) } runState.stack.push(r) }, @@ -452,7 +452,7 @@ export const handlers: Map = new Map([ function (runState) { const [memOffset, dataOffset, dataLength] = runState.stack.popN(3) - if (!(dataLength === 0n)) { + if (!(dataLength === BigInt(0))) { const data = getDataSlice(runState.eei.getCallData(), dataOffset, dataLength) const memOffsetNum = Number(memOffset) const dataLengthNum = Number(dataLength) @@ -474,7 +474,7 @@ export const handlers: Map = new Map([ function (runState) { const [memOffset, codeOffset, dataLength] = runState.stack.popN(3) - if (!(dataLength === 0n)) { + if (!(dataLength === BigInt(0))) { const data = getDataSlice(runState.eei.getCode(), codeOffset, dataLength) const memOffsetNum = Number(memOffset) const lengthNum = Number(dataLength) @@ -498,7 +498,7 @@ export const handlers: Map = new Map([ async function (runState) { const [addressBN, memOffset, codeOffset, dataLength] = runState.stack.popN(4) - if (!(dataLength === 0n)) { + if (!(dataLength === BigInt(0))) { const code = await runState.eei.getExternalCode(addressBN) const data = getDataSlice(code, codeOffset, dataLength) @@ -517,7 +517,7 @@ export const handlers: Map = new Map([ const address = new Address(addressToBuffer(addressBigInt)) const empty = await runState.eei.isAccountEmpty(address) if (empty) { - runState.stack.push(0n) + runState.stack.push(BigInt(0)) return } @@ -543,7 +543,7 @@ export const handlers: Map = new Map([ function (runState) { const [memOffset, returnDataOffset, dataLength] = runState.stack.popN(3) - if (!(dataLength === 0n)) { + if (!(dataLength === BigInt(0))) { const data = getDataSlice(runState.eei.getReturnData(), returnDataOffset, dataLength) const memOffsetNum = Number(memOffset) const lengthNum = Number(dataLength) @@ -568,8 +568,8 @@ export const handlers: Map = new Map([ const diff = runState.eei.getBlockNumber() - number // block lookups must be within the past 256 blocks - if (diff > 256n || diff <= 0n) { - runState.stack.push(0n) + if (diff > BigInt(256) || diff <= BigInt(0)) { + runState.stack.push(BigInt(0)) return } @@ -680,7 +680,7 @@ export const handlers: Map = new Map([ const key = runState.stack.pop() const keyBuf = setLengthLeft(bigIntToBuffer(key), 32) const value = await runState.eei.storageLoad(keyBuf) - const valueBigInt = value.length ? bufferToBigInt(value) : 0n + const valueBigInt = value.length ? bufferToBigInt(value) : BigInt(0) runState.stack.push(valueBigInt) }, ], @@ -693,7 +693,7 @@ export const handlers: Map = new Map([ const keyBuf = setLengthLeft(bigIntToBuffer(key), 32) // NOTE: this should be the shortest representation let value - if (val === 0n) { + if (val === BigInt(0)) { value = Buffer.from([]) } else { value = bigIntToBuffer(val) @@ -725,7 +725,7 @@ export const handlers: Map = new Map([ 0x57, function (runState) { const [dest, cond] = runState.stack.popN(2) - if (!(cond === 0n)) { + if (!(cond === BigInt(0))) { if (dest > runState.eei.getCodeSize()) { trap(ERROR.INVALID_JUMP + ' at ' + describeLocation(runState)) } @@ -751,7 +751,7 @@ export const handlers: Map = new Map([ [ 0x59, function (runState) { - runState.stack.push(runState.memoryWordCount * 32n) + runState.stack.push(runState.memoryWordCount * BigInt(32)) }, ], // 0x5a: GAS @@ -806,7 +806,7 @@ export const handlers: Map = new Map([ [ 0x5f, function (runState) { - runState.stack.push(0n) + runState.stack.push(BigInt(0)) }, ], // 0x60: PUSH @@ -851,7 +851,7 @@ export const handlers: Map = new Map([ }) let mem = Buffer.alloc(0) - if (!(memLength === 0n)) { + if (!(memLength === BigInt(0))) { mem = runState.memory.read(Number(memOffset), Number(memLength)) } @@ -870,7 +870,7 @@ export const handlers: Map = new Map([ runState.messageGasLimit = undefined let data = Buffer.alloc(0) - if (!(length === 0n)) { + if (!(length === BigInt(0))) { data = runState.memory.read(Number(offset), Number(length)) } @@ -892,7 +892,7 @@ export const handlers: Map = new Map([ runState.messageGasLimit = undefined let data = Buffer.alloc(0) - if (!(length === 0n)) { + if (!(length === BigInt(0))) { data = runState.memory.read(Number(offset), Number(length)) } @@ -914,7 +914,7 @@ export const handlers: Map = new Map([ const toAddress = new Address(addressToBuffer(toAddr)) let data = Buffer.alloc(0) - if (!(inLength === 0n)) { + if (!(inLength === BigInt(0))) { data = runState.memory.read(Number(inOffset), Number(inLength)) } @@ -939,7 +939,7 @@ export const handlers: Map = new Map([ runState.messageGasLimit = undefined let data = Buffer.alloc(0) - if (!(inLength === 0n)) { + if (!(inLength === BigInt(0))) { data = runState.memory.read(Number(inOffset), Number(inLength)) } @@ -959,7 +959,7 @@ export const handlers: Map = new Map([ const toAddress = new Address(addressToBuffer(toAddr)) let data = Buffer.alloc(0) - if (!(inLength === 0n)) { + if (!(inLength === BigInt(0))) { data = runState.memory.read(Number(inOffset), Number(inLength)) } @@ -976,7 +976,7 @@ export const handlers: Map = new Map([ [ 0xfa, async function (runState) { - const value = 0n + const value = BigInt(0) const [_currentGasLimit, toAddr, inOffset, inLength, outOffset, outLength] = runState.stack.popN(6) const toAddress = new Address(addressToBuffer(toAddr)) @@ -985,7 +985,7 @@ export const handlers: Map = new Map([ runState.messageGasLimit = undefined let data = Buffer.alloc(0) - if (!(inLength === 0n)) { + if (!(inLength === BigInt(0))) { data = runState.memory.read(Number(inOffset), Number(inLength)) } @@ -1001,7 +1001,7 @@ export const handlers: Map = new Map([ function (runState) { const [offset, length] = runState.stack.popN(2) let returnData = Buffer.alloc(0) - if (!(length === 0n)) { + if (!(length === BigInt(0))) { returnData = runState.memory.read(Number(offset), Number(length)) } runState.eei.finish(returnData) @@ -1013,7 +1013,7 @@ export const handlers: Map = new Map([ function (runState) { const [offset, length] = runState.stack.popN(2) let returnData = Buffer.alloc(0) - if (!(length === 0n)) { + if (!(length === BigInt(0))) { returnData = runState.memory.read(Number(offset), Number(length)) } runState.eei.revert(returnData) diff --git a/packages/vm/src/evm/opcodes/gas.ts b/packages/vm/src/evm/opcodes/gas.ts index 6fc8cfbe50..882d6965a9 100644 --- a/packages/vm/src/evm/opcodes/gas.ts +++ b/packages/vm/src/evm/opcodes/gas.ts @@ -38,7 +38,7 @@ export const dynamicGasHandlers: Map = new Map< async function (runState, gas, common): Promise { const [offset, length] = runState.stack.peek(2) gas += subMemUsage(runState, offset, length, common) - gas += BigInt(common.param('gasPrices', 'sha3Word')) * divCeil(length, 32n) + gas += BigInt(common.param('gasPrices', 'sha3Word')) * divCeil(length, BigInt(32)) return gas }, ], @@ -61,8 +61,8 @@ export const dynamicGasHandlers: Map = new Map< const [memOffset, _dataOffset, dataLength] = runState.stack.peek(3) gas += subMemUsage(runState, memOffset, dataLength, common) - if (!(dataLength === 0n)) { - gas += BigInt(common.param('gasPrices', 'copy')) * divCeil(dataLength, 32n) + if (!(dataLength === BigInt(0))) { + gas += BigInt(common.param('gasPrices', 'copy')) * divCeil(dataLength, BigInt(32)) } return gas }, @@ -74,8 +74,8 @@ export const dynamicGasHandlers: Map = new Map< const [memOffset, _codeOffset, dataLength] = runState.stack.peek(3) gas += subMemUsage(runState, memOffset, dataLength, common) - if (!(dataLength === 0n)) { - gas += BigInt(common.param('gasPrices', 'copy')) * divCeil(dataLength, 32n) + if (!(dataLength === BigInt(0))) { + gas += BigInt(common.param('gasPrices', 'copy')) * divCeil(dataLength, BigInt(32)) } return gas }, @@ -105,8 +105,8 @@ export const dynamicGasHandlers: Map = new Map< gas += accessAddressEIP2929(runState, address, common) } - if (!(dataLength === 0n)) { - gas += BigInt(common.param('gasPrices', 'copy')) * divCeil(dataLength, 32n) + if (!(dataLength === BigInt(0))) { + gas += BigInt(common.param('gasPrices', 'copy')) * divCeil(dataLength, BigInt(32)) } return gas }, @@ -123,8 +123,8 @@ export const dynamicGasHandlers: Map = new Map< gas += subMemUsage(runState, memOffset, dataLength, common) - if (!(dataLength === 0n)) { - gas += BigInt(common.param('gasPrices', 'copy')) * divCeil(dataLength, 32n) + if (!(dataLength === BigInt(0))) { + gas += BigInt(common.param('gasPrices', 'copy')) * divCeil(dataLength, BigInt(32)) } return gas }, @@ -146,7 +146,7 @@ export const dynamicGasHandlers: Map = new Map< 0x51, async function (runState, gas, common): Promise { const pos = runState.stack.peek()[0] - gas += subMemUsage(runState, pos, 32n, common) + gas += subMemUsage(runState, pos, BigInt(32), common) return gas }, ], @@ -155,7 +155,7 @@ export const dynamicGasHandlers: Map = new Map< 0x52, async function (runState, gas, common): Promise { const offset = runState.stack.peek()[0] - gas += subMemUsage(runState, offset, 32n, common) + gas += subMemUsage(runState, offset, BigInt(32), common) return gas }, ], @@ -164,7 +164,7 @@ export const dynamicGasHandlers: Map = new Map< 0x53, async function (runState, gas, common): Promise { const offset = runState.stack.peek()[0] - gas += subMemUsage(runState, offset, 1n, common) + gas += subMemUsage(runState, offset, BigInt(1), common) return gas }, ], @@ -193,7 +193,7 @@ export const dynamicGasHandlers: Map = new Map< const keyBuf = setLengthLeft(bigIntToBuffer(key), 32) // NOTE: this should be the shortest representation let value - if (val === 0n) { + if (val === BigInt(0)) { value = Buffer.from([]) } else { value = bigIntToBuffer(val) @@ -285,7 +285,7 @@ export const dynamicGasHandlers: Map = new Map< runState.stack.peek(7) const toAddress = new Address(addressToBuffer(toAddr)) - if (runState.eei.isStatic() && !(value === 0n)) { + if (runState.eei.isStatic() && !(value === BigInt(0))) { trap(ERROR.STATIC_STATE_CHANGE) } gas += subMemUsage(runState, inOffset, inLength, common) @@ -294,14 +294,14 @@ export const dynamicGasHandlers: Map = new Map< gas += accessAddressEIP2929(runState, toAddress, common) } - if (!(value === 0n)) { + if (!(value === BigInt(0))) { gas += BigInt(common.param('gasPrices', 'callValueTransfer')) } if (common.gteHardfork('spuriousDragon')) { // We are at or after Spurious Dragon // Call new account gas: account is DEAD and we transfer nonzero value - if ((await runState.eei.isAccountEmpty(toAddress)) && !(value === 0n)) { + if ((await runState.eei.isAccountEmpty(toAddress)) && !(value === BigInt(0))) { gas += BigInt(common.param('gasPrices', 'callNewAccount')) } } else if (!(await runState.eei.accountExists(toAddress))) { @@ -321,7 +321,7 @@ export const dynamicGasHandlers: Map = new Map< trap(ERROR.OUT_OF_GAS) } - if (!(value === 0n)) { + if (!(value === BigInt(0))) { // TODO: Don't use private attr directly runState.eei._gasLeft += BigInt(common.param('gasPrices', 'callStipend')) gasLimit += BigInt(common.param('gasPrices', 'callStipend')) @@ -346,7 +346,7 @@ export const dynamicGasHandlers: Map = new Map< gas += accessAddressEIP2929(runState, toAddress, common) } - if (!(value === 0n)) { + if (!(value === BigInt(0))) { gas += BigInt(common.param('gasPrices', 'callValueTransfer')) } let gasLimit = maxCallGas(currentGasLimit, runState.eei.getGasLeft() - gas, runState, common) @@ -355,7 +355,7 @@ export const dynamicGasHandlers: Map = new Map< if (gasLimit > runState.eei.getGasLeft() - gas) { trap(ERROR.OUT_OF_GAS) } - if (!(value === 0n)) { + if (!(value === BigInt(0))) { // TODO: Don't use private attr directly runState.eei._gasLeft += BigInt(common.param('gasPrices', 'callStipend')) gasLimit += BigInt(common.param('gasPrices', 'callStipend')) @@ -421,7 +421,7 @@ export const dynamicGasHandlers: Map = new Map< gas += accessAddressEIP2929(runState, runState.eei.getAddress(), common, false) } - gas += BigInt(common.param('gasPrices', 'sha3Word')) * divCeil(length, 32n) + gas += BigInt(common.param('gasPrices', 'sha3Word')) * divCeil(length, BigInt(32)) let gasLimit = runState.eei.getGasLeft() - gas gasLimit = maxCallGas(gasLimit, gasLimit, runState, common) // CREATE2 is only available after TangerineWhistle (Constantinople introduced this opcode) runState.messageGasLimit = gasLimit @@ -477,7 +477,7 @@ export const dynamicGasHandlers: Map = new Map< if (common.gteHardfork('spuriousDragon')) { // EIP-161: State Trie Clearing const balance = await runState.eei.getExternalBalance(runState.eei.getAddress()) - if (balance > 0n) { + if (balance > BigInt(0)) { // This technically checks if account is empty or non-existent // TODO: improve on the API here (EEI and StateManager) const empty = await runState.eei.isAccountEmpty(selfdestructToAddress) diff --git a/packages/vm/src/evm/opcodes/util.ts b/packages/vm/src/evm/opcodes/util.ts index e8798d923c..0b955b26e8 100644 --- a/packages/vm/src/evm/opcodes/util.ts +++ b/packages/vm/src/evm/opcodes/util.ts @@ -3,7 +3,7 @@ import { keccak256, setLengthRight, setLengthLeft, bigIntToBuffer } from 'ethere import { ERROR, VmError } from './../../exceptions' import { RunState } from './../interpreter' -const MASK_160 = (1n << 160n) - 1n +const MASK_160 = (BigInt(1) << BigInt(160)) - BigInt(1) /** * Proxy function for ethereumjs-util's setLengthLeft, except it returns a zero @@ -66,10 +66,10 @@ export function divCeil(a: bigint, b: bigint): bigint { const modulus = mod(a, b) // Fast case - exact division - if (modulus === 0n) return div + if (modulus === BigInt(0)) return div // Round up - return div < 0n ? div - 1n : div + 1n + return div < BigInt(0) ? div - BigInt(1) : div + BigInt(1) } export function short(buffer: Buffer): string { @@ -173,7 +173,7 @@ export function maxCallGas( ): bigint { const isTangerineWhistleOrLater = common.gteHardfork('tangerineWhistle') if (isTangerineWhistleOrLater) { - const gasAllowed = gasLeft - gasLeft / 64n + const gasAllowed = gasLeft - gasLeft / BigInt(64) return gasLimit > gasAllowed ? gasAllowed : gasLimit } else { return gasLimit @@ -190,10 +190,10 @@ export function maxCallGas( */ export function subMemUsage(runState: RunState, offset: bigint, length: bigint, common: Common) { // YP (225): access with zero length will not extend the memory - if (length === 0n) return 0n + if (length === BigInt(0)) return BigInt(0) - const newMemoryWordCount = divCeil(offset + length, 32n) - if (newMemoryWordCount <= runState.memoryWordCount) return 0n + const newMemoryWordCount = divCeil(offset + length, BigInt(32)) + if (newMemoryWordCount <= runState.memoryWordCount) return BigInt(0) const words = newMemoryWordCount const fee = BigInt(common.param('gasPrices', 'memory')) @@ -227,7 +227,7 @@ export function writeCallOutput(runState: RunState, outOffset: bigint, outLength if (BigInt(returnData.length) < dataLength) { dataLength = returnData.length } - const data = getDataSlice(returnData, 0n, BigInt(dataLength)) + const data = getDataSlice(returnData, BigInt(0), BigInt(dataLength)) runState.memory.extend(memOffset, dataLength) runState.memory.write(memOffset, dataLength, data) } @@ -269,7 +269,7 @@ export function updateSstoreGas( export function mod(a: bigint, b: bigint) { let r = a % b - if (r < 0n) { + if (r < BigInt(0)) { r = b + r } return r @@ -290,15 +290,15 @@ export function abs(a: bigint) { return a * -1n } -const N = 115792089237316195423570985008687907853269984665640564039457584007913129639936n +const N = BigInt(115792089237316195423570985008687907853269984665640564039457584007913129639936) export function exponentation(bas: bigint, exp: bigint) { - let t = 1n - while (exp > 0n) { - if (exp % 2n != 0n) { + let t = BigInt(1) + while (exp > BigInt(0)) { + if (exp % BigInt(2) != BigInt(0)) { t = (t * bas) % N } bas = (bas * bas) % N - exp = exp / 2n + exp = exp / BigInt(2) } return t } diff --git a/packages/vm/src/evm/precompiles/05-modexp.ts b/packages/vm/src/evm/precompiles/05-modexp.ts index 86b5e6b3d5..e64ab6c3c9 100644 --- a/packages/vm/src/evm/precompiles/05-modexp.ts +++ b/packages/vm/src/evm/precompiles/05-modexp.ts @@ -6,23 +6,23 @@ const assert = require('assert') function multComplexity(x: bigint): bigint { let fac1 let fac2 - if (x <= 64n) { - return x ** 2n - } else if (x <= 1024n) { + if (x <= BigInt(64)) { + return x ** BigInt(2) + } else if (x <= BigInt(1024)) { // return Math.floor(Math.pow(x, 2) / 4) + 96 * x - 3072 - fac1 = x ** 2n / 4n - fac2 = x * 96n - return fac1 + fac2 - 3072n + fac1 = x ** BigInt(2) / BigInt(4) + fac2 = x * BigInt(96) + return fac1 + fac2 - BigInt(3072) } else { // return Math.floor(Math.pow(x, 2) / 16) + 480 * x - 199680 - fac1 = x ** 2n / 16n - fac2 = x * 480n - return fac1 + fac2 - 199680n + fac1 = x ** BigInt(2) / BigInt(16) + fac2 = x * BigInt(480) + return fac1 + fac2 - BigInt(199680) } } function multComplexityEIP2565(x: bigint): bigint { - const words = (x + 7n) / 8n + const words = (x + BigInt(7)) / BigInt(8) return words * words } @@ -39,21 +39,21 @@ function getAdjustedExponentLength(data: Buffer): bigint { firstExpBytes = setLengthRight(firstExpBytes, 32) // reading past the data reads virtual zeros let firstExpBigInt = bufferToBigInt(firstExpBytes) let max32expLen = 0 - if (expLen < 32n) { + if (expLen < BigInt(32)) { max32expLen = 32 - Number(expLen) } - firstExpBigInt = firstExpBigInt >> (8n * BigInt(Math.max(max32expLen, 0))) + firstExpBigInt = firstExpBigInt >> (BigInt(8) * BigInt(Math.max(max32expLen, 0))) let bitLen = -1 - while (firstExpBigInt > 0n) { + while (firstExpBigInt > BigInt(0)) { bitLen = bitLen + 1 - firstExpBigInt = firstExpBigInt >> 1n + firstExpBigInt = firstExpBigInt >> BigInt(1) } - let expLenMinus32OrZero = expLen - 32n - if (expLenMinus32OrZero < 0n) { - expLenMinus32OrZero = 0n + let expLenMinus32OrZero = expLen - BigInt(32) + if (expLenMinus32OrZero < BigInt(0)) { + expLenMinus32OrZero = BigInt(0) } - const eightTimesExpLenMinus32OrZero = expLenMinus32OrZero * 8n + const eightTimesExpLenMinus32OrZero = expLenMinus32OrZero * BigInt(8) let adjustedExpLen = eightTimesExpLenMinus32OrZero if (bitLen > 0) { adjustedExpLen += BigInt(bitLen) @@ -62,14 +62,14 @@ function getAdjustedExponentLength(data: Buffer): bigint { } export function expmod(a: bigint, power: bigint, modulo: bigint) { - if (power === 0n) { - return 1n % modulo + if (power === BigInt(0)) { + return BigInt(1) % modulo } - let res = 1n - while (power > 0n) { - if (power & 1n) res = (res * a) % modulo + let res = BigInt(1) + while (power > BigInt(0)) { + if (power & BigInt(1)) res = (res * a) % modulo a = (a * a) % modulo - power >>= 1n + power >>= BigInt(1) } return res } @@ -80,8 +80,8 @@ export default function (opts: PrecompileInput): ExecResult { const data = opts.data let adjustedELen = getAdjustedExponentLength(data) - if (adjustedELen < 1n) { - adjustedELen = 1n + if (adjustedELen < BigInt(1)) { + adjustedELen = BigInt(1) } const bLen = bufferToBigInt(data.slice(0, 32)) @@ -95,7 +95,7 @@ export default function (opts: PrecompileInput): ExecResult { const Gquaddivisor = BigInt(opts._common.param('gasPrices', 'modexpGquaddivisor')) let gasUsed - const bStart = 96n + const bStart = BigInt(96) const bEnd = bStart + bLen const eStart = bEnd const eEnd = eStart + eLen @@ -106,8 +106,8 @@ export default function (opts: PrecompileInput): ExecResult { gasUsed = (adjustedELen * multComplexity(maxLen)) / Gquaddivisor } else { gasUsed = (adjustedELen * multComplexityEIP2565(maxLen)) / Gquaddivisor - if (gasUsed < 200n) { - gasUsed = 200n + if (gasUsed < BigInt(200)) { + gasUsed = BigInt(200) } } @@ -115,14 +115,14 @@ export default function (opts: PrecompileInput): ExecResult { return OOGResult(opts.gasLimit) } - if (bLen === 0n) { + if (bLen === BigInt(0)) { return { gasUsed, - returnValue: setLengthLeft(bigIntToBuffer(0n), Number(mLen)), + returnValue: setLengthLeft(bigIntToBuffer(BigInt(0)), Number(mLen)), } } - if (mLen === 0n) { + if (mLen === BigInt(0)) { return { gasUsed, returnValue: Buffer.alloc(0), @@ -130,7 +130,7 @@ export default function (opts: PrecompileInput): ExecResult { } const maxInt = BigInt(Number.MAX_SAFE_INTEGER) - const maxSize = 2147483647n // ethereumjs-util setLengthRight limitation + const maxSize = BigInt(2147483647) // ethereumjs-util setLengthRight limitation if (bLen > maxSize || eLen > maxSize || mLen > maxSize) { return OOGResult(opts.gasLimit) @@ -145,8 +145,8 @@ export default function (opts: PrecompileInput): ExecResult { } let R - if (M === 0n) { - R = 0n + if (M === BigInt(0)) { + R = BigInt(0) } else { R = expmod(B, E, M) } diff --git a/packages/vm/src/evm/precompiles/0c-bls12-g1multiexp.ts b/packages/vm/src/evm/precompiles/0c-bls12-g1multiexp.ts index d75f1fef87..6f2cb1225a 100644 --- a/packages/vm/src/evm/precompiles/0c-bls12-g1multiexp.ts +++ b/packages/vm/src/evm/precompiles/0c-bls12-g1multiexp.ts @@ -36,7 +36,7 @@ export default async function (opts: PrecompileInput): Promise { gasDiscountMultiplier = gasDiscountMax } - const gasUsed = (gasUsedPerPair * BigInt(numPairs) * BigInt(gasDiscountMultiplier)) / 1000n + const gasUsed = (gasUsedPerPair * BigInt(numPairs) * BigInt(gasDiscountMultiplier)) / BigInt(1000) if (opts.gasLimit < gasUsed) { return OOGResult(opts.gasLimit) diff --git a/packages/vm/src/evm/precompiles/0f-bls12-g2multiexp.ts b/packages/vm/src/evm/precompiles/0f-bls12-g2multiexp.ts index a50578327f..79d3a762ad 100644 --- a/packages/vm/src/evm/precompiles/0f-bls12-g2multiexp.ts +++ b/packages/vm/src/evm/precompiles/0f-bls12-g2multiexp.ts @@ -36,7 +36,7 @@ export default async function (opts: PrecompileInput): Promise { gasDiscountMultiplier = gasDiscountMax } - const gasUsed = (gasUsedPerPair * BigInt(numPairs) * BigInt(gasDiscountMultiplier)) / 1000n + const gasUsed = (gasUsedPerPair * BigInt(numPairs) * BigInt(gasDiscountMultiplier)) / BigInt(1000) if (opts.gasLimit < gasUsed) { return OOGResult(opts.gasLimit) diff --git a/packages/vm/src/runBlock.ts b/packages/vm/src/runBlock.ts index 2b55bf9de1..c870c71510 100644 --- a/packages/vm/src/runBlock.ts +++ b/packages/vm/src/runBlock.ts @@ -308,7 +308,7 @@ async function applyBlock(this: VM, block: Block, opts: RunBlockOpts) { async function applyTransactions(this: VM, block: Block, opts: RunBlockOpts) { const bloom = new Bloom() // the total amount of gas used processing these transactions - let gasUsed = 0n + let gasUsed = BigInt(0) const receiptTrie = new Trie() const receipts = [] const txResults = [] @@ -410,16 +410,16 @@ function calculateOmmerReward( minerReward: bigint ): bigint { const heightDiff = blockNumber - ommerBlockNumber - let reward = ((8n - heightDiff) * minerReward) / 8n - if (reward < 0n) { - reward = 0n + let reward = ((BigInt(8) - heightDiff) * minerReward) / BigInt(8) + if (reward < BigInt(0)) { + reward = BigInt(0) } return reward } export function calculateMinerReward(minerReward: bigint, ommersNum: number): bigint { // calculate nibling reward - const niblingReward = minerReward / 32n + const niblingReward = minerReward / BigInt(32) const totalNiblingReward = niblingReward * BigInt(ommersNum) const reward = minerReward + totalNiblingReward return reward diff --git a/packages/vm/src/runCall.ts b/packages/vm/src/runCall.ts index 8108af2b74..1b95546db3 100644 --- a/packages/vm/src/runCall.ts +++ b/packages/vm/src/runCall.ts @@ -35,7 +35,10 @@ export interface RunCallOpts { export default function runCall(this: VM, opts: RunCallOpts): Promise { const block = opts.block ?? Block.fromBlockData({}, { common: this._common }) - const txContext = new TxContext(opts.gasPrice ?? 0n, opts.origin ?? opts.caller ?? Address.zero()) + const txContext = new TxContext( + opts.gasPrice ?? BigInt(0), + opts.origin ?? opts.caller ?? Address.zero() + ) const message = new Message({ caller: opts.caller, diff --git a/packages/vm/src/runCode.ts b/packages/vm/src/runCode.ts index d2cdacd820..6a3adaebad 100644 --- a/packages/vm/src/runCode.ts +++ b/packages/vm/src/runCode.ts @@ -76,7 +76,7 @@ export default function runCode(this: VM, opts: RunCodeOpts): Promise { } // Process any gas refund - let gasRefund = results.execResult.gasRefund ?? 0n + let gasRefund = results.execResult.gasRefund ?? BigInt(0) const maxRefundQuotient = BigInt(this._common.param('gasConfig', 'maxRefundQuotient')) - if (!(gasRefund === 0n)) { + if (!(gasRefund === BigInt(0))) { const maxRefund = results.gasUsed / maxRefundQuotient gasRefund = gasRefund < maxRefund ? gasRefund : maxRefund results.gasUsed -= gasRefund diff --git a/packages/vm/tests/api/EIPs/eip-2537-BLS.spec.ts b/packages/vm/tests/api/EIPs/eip-2537-BLS.spec.ts index 10a10fee48..434785f67f 100644 --- a/packages/vm/tests/api/EIPs/eip-2537-BLS.spec.ts +++ b/packages/vm/tests/api/EIPs/eip-2537-BLS.spec.ts @@ -29,11 +29,11 @@ tape('EIP-2537 BLS tests', (t) => { caller: Address.zero(), gasLimit: BigInt(0xffffffffff), to, - value: 0n, + value: BigInt(0), data: Buffer.alloc(0), }) - if (!(result.execResult.gasUsed === 0n)) { + if (!(result.execResult.gasUsed === BigInt(0))) { st.fail('BLS precompiles should not use any gas if EIP not activated') } @@ -60,7 +60,7 @@ tape('EIP-2537 BLS tests', (t) => { caller: Address.zero(), gasLimit: BigInt(0xffffffffff), to, - value: 0n, + value: BigInt(0), data: Buffer.alloc(0), }) @@ -101,7 +101,7 @@ tape('EIP-2537 BLS tests', (t) => { const result = await BLS12G2MultiExp({ data: Buffer.from(testVector, 'hex'), - gasLimit: 5000000n, + gasLimit: BigInt(5000000), _common: common, _VM: vm, }) diff --git a/packages/vm/tests/api/EIPs/eip-2565-modexp-gas-cost.spec.ts b/packages/vm/tests/api/EIPs/eip-2565-modexp-gas-cost.spec.ts index b2b5b0335a..f477b0ad76 100644 --- a/packages/vm/tests/api/EIPs/eip-2565-modexp-gas-cost.spec.ts +++ b/packages/vm/tests/api/EIPs/eip-2565-modexp-gas-cost.spec.ts @@ -18,7 +18,7 @@ tape('EIP-2565 ModExp gas cost tests', (t) => { caller: Address.zero(), gasLimit: BigInt(0xffffffffff), to, - value: 0n, + value: BigInt(0), data: Buffer.from(test.Input, 'hex'), }) diff --git a/packages/vm/tests/api/EIPs/eip-2929.spec.ts b/packages/vm/tests/api/EIPs/eip-2929.spec.ts index 406afae1a5..5306f762fa 100644 --- a/packages/vm/tests/api/EIPs/eip-2929.spec.ts +++ b/packages/vm/tests/api/EIPs/eip-2929.spec.ts @@ -60,7 +60,7 @@ tape('EIP 2929: gas cost tests', (t) => { const result = await vm.runTx({ tx }) const totalGasUsed = initialGas - currentGas - st.equal(true, totalGasUsed === BigInt(test.totalGasUsed) + 21000n) // Add tx upfront cost. + st.equal(true, totalGasUsed === BigInt(test.totalGasUsed) + BigInt(21000)) // Add tx upfront cost. return result } @@ -157,24 +157,24 @@ tape('EIP 2929: gas cost tests', (t) => { t.test('should charge for extcodecopy correctly', async (st) => { const test = { code: '60006000600060ff3c60006000600060ff3c600060006000303c00', - totalGasUsed: 2835n, + totalGasUsed: BigInt(2835), steps: [ - { expectedOpcode: 'PUSH1', expectedGasUsed: 3n }, - { expectedOpcode: 'PUSH1', expectedGasUsed: 3n }, - { expectedOpcode: 'PUSH1', expectedGasUsed: 3n }, - { expectedOpcode: 'PUSH1', expectedGasUsed: 3n }, - { expectedOpcode: 'EXTCODECOPY', expectedGasUsed: 2600n }, - { expectedOpcode: 'PUSH1', expectedGasUsed: 3n }, - { expectedOpcode: 'PUSH1', expectedGasUsed: 3n }, - { expectedOpcode: 'PUSH1', expectedGasUsed: 3n }, - { expectedOpcode: 'PUSH1', expectedGasUsed: 3n }, - { expectedOpcode: 'EXTCODECOPY', expectedGasUsed: 100n }, - { expectedOpcode: 'PUSH1', expectedGasUsed: 3n }, - { expectedOpcode: 'PUSH1', expectedGasUsed: 3n }, - { expectedOpcode: 'PUSH1', expectedGasUsed: 3n }, - { expectedOpcode: 'ADDRESS', expectedGasUsed: 2n }, - { expectedOpcode: 'EXTCODECOPY', expectedGasUsed: 100n }, - { expectedOpcode: 'STOP', expectedGasUsed: 0n }, + { expectedOpcode: 'PUSH1', expectedGasUsed: BigInt(3) }, + { expectedOpcode: 'PUSH1', expectedGasUsed: BigInt(3) }, + { expectedOpcode: 'PUSH1', expectedGasUsed: BigInt(3) }, + { expectedOpcode: 'PUSH1', expectedGasUsed: BigInt(3) }, + { expectedOpcode: 'EXTCODECOPY', expectedGasUsed: BigInt(2600) }, + { expectedOpcode: 'PUSH1', expectedGasUsed: BigInt(3) }, + { expectedOpcode: 'PUSH1', expectedGasUsed: BigInt(3) }, + { expectedOpcode: 'PUSH1', expectedGasUsed: BigInt(3) }, + { expectedOpcode: 'PUSH1', expectedGasUsed: BigInt(3) }, + { expectedOpcode: 'EXTCODECOPY', expectedGasUsed: BigInt(100) }, + { expectedOpcode: 'PUSH1', expectedGasUsed: BigInt(3) }, + { expectedOpcode: 'PUSH1', expectedGasUsed: BigInt(3) }, + { expectedOpcode: 'PUSH1', expectedGasUsed: BigInt(3) }, + { expectedOpcode: 'ADDRESS', expectedGasUsed: BigInt(2) }, + { expectedOpcode: 'EXTCODECOPY', expectedGasUsed: BigInt(100) }, + { expectedOpcode: 'STOP', expectedGasUsed: BigInt(0) }, ], } @@ -272,18 +272,18 @@ tape('EIP 2929: gas cost tests', (t) => { // SLOAD or CALL operations. // load same storage slot twice (also in inner call) - await runCodeTest('60005460003415601357600080808080305AF15B00', 23369n, t) + await runCodeTest('60005460003415601357600080808080305AF15B00', BigInt(23369), t) // call to contract, load slot 0, revert inner call. load slot 0 in outer call. - await runCodeTest('341515600D57600054600080FD5B600080808080305AF160005400', 25374n, t) + await runCodeTest('341515600D57600054600080FD5B600080808080305AF160005400', BigInt(25374), t) // call to address 0xFFFF..FF const callFF = '6000808080806000195AF1' // call address 0xFF..FF, now call same contract again, call 0xFF..FF again (it is now warm) - await runCodeTest(callFF + '60003415601B57600080808080305AF15B00', 23909n, t) + await runCodeTest(callFF + '60003415601B57600080808080305AF15B00', BigInt(23909), t) // call to contract, call 0xFF..FF, revert, call 0xFF..FF (should be cold) await runCodeTest( '341515601557' + callFF + '600080FD5B600080808080305AF1' + callFF + '00', - 26414n, + BigInt(26414), t ) diff --git a/packages/vm/tests/api/EIPs/eip-2930-accesslists.spec.ts b/packages/vm/tests/api/EIPs/eip-2930-accesslists.spec.ts index 833dbbfca5..9713d3d2dc 100644 --- a/packages/vm/tests/api/EIPs/eip-2930-accesslists.spec.ts +++ b/packages/vm/tests/api/EIPs/eip-2930-accesslists.spec.ts @@ -69,13 +69,13 @@ tape('EIP-2930 Optional Access Lists tests', (t) => { await vm.runTx({ tx: txnWithAccessList }) st.ok(trace[1][0] == 'SLOAD') let gasUsed = trace[1][1] - trace[2][1] - st.equal(gasUsed, 100n, 'charge warm sload gas') + st.equal(gasUsed, BigInt(100), 'charge warm sload gas') trace = [] await vm.runTx({ tx: txnWithoutAccessList, skipNonce: true }) st.ok(trace[1][0] == 'SLOAD') gasUsed = trace[1][1] - trace[2][1] - st.equal(gasUsed, 2100n, 'charge cold sload gas') + st.equal(gasUsed, BigInt(2100), 'charge cold sload gas') st.end() }) diff --git a/packages/vm/tests/api/EIPs/eip-3198-BaseFee.spec.ts b/packages/vm/tests/api/EIPs/eip-3198-BaseFee.spec.ts index 216b37d61c..2e6bffcd84 100644 --- a/packages/vm/tests/api/EIPs/eip-3198-BaseFee.spec.ts +++ b/packages/vm/tests/api/EIPs/eip-3198-BaseFee.spec.ts @@ -93,7 +93,7 @@ tape('EIP3198 tests', (t) => { }) const txBaseFee = bnToBigInt(block.transactions[0].getBaseFee()) const gasUsed = results.gasUsed - txBaseFee - st.ok(gasUsed === 2n, 'gas used correct') + st.ok(gasUsed === BigInt(2), 'gas used correct') st.ok(stack[0] === bnToBigInt(fee), 'right item pushed on stack') st.end() }) diff --git a/packages/vm/tests/api/EIPs/eip-3529.spec.ts b/packages/vm/tests/api/EIPs/eip-3529.spec.ts index 8bc5c7b2e1..c4759c4452 100644 --- a/packages/vm/tests/api/EIPs/eip-3529.spec.ts +++ b/packages/vm/tests/api/EIPs/eip-3529.spec.ts @@ -124,7 +124,7 @@ tape('EIP-3529 tests', (t) => { } }) - const gasLimit = 100000n + const gasLimit = BigInt(100000) const key = Buffer.from('00'.repeat(32), 'hex') for (const testCase of testCases) { @@ -172,7 +172,7 @@ tape('EIP-3529 tests', (t) => { st.ok(result.execResult.exceptionError === undefined, 'transaction executed succesfully') st.ok(result.execResult.gasRefund !== undefined, 'gas refund is defined') - st.ok(result.execResult.gasRefund === 0n, 'gas refund is zero') + st.ok(result.execResult.gasRefund === BigInt(0), 'gas refund is zero') st.end() }) @@ -221,8 +221,8 @@ tape('EIP-3529 tests', (t) => { const result = await vm.runTx({ tx }) - const actualGasUsed = startGas! - finalGas! + 21000n - const maxRefund = actualGasUsed / 5n + 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') diff --git a/packages/vm/tests/api/EIPs/eip-3855.spec.ts b/packages/vm/tests/api/EIPs/eip-3855.spec.ts index 7ff5682c05..28b019793a 100644 --- a/packages/vm/tests/api/EIPs/eip-3855.spec.ts +++ b/packages/vm/tests/api/EIPs/eip-3855.spec.ts @@ -25,11 +25,11 @@ tape('EIP 3541 tests', (t) => { const result = await vm.runCode({ code: Buffer.from('5F', 'hex'), - gasLimit: 10n, + gasLimit: BigInt(10), }) st.ok(stack!.length == 1) - st.ok(stack![0] === 0n) + st.ok(stack![0] === BigInt(0)) st.ok(result.gasUsed === BigInt(common.param('gasPrices', 'push0'))) st.end() }) @@ -46,12 +46,12 @@ tape('EIP 3541 tests', (t) => { const result = await vm.runCode({ code: Buffer.from('5F'.repeat(depth), 'hex'), - gasLimit: 10000n, + gasLimit: BigInt(10000), }) st.ok(stack.length == depth) stack.forEach((elem: bigint) => { - if (!(elem === 0n)) { + if (!(elem === BigInt(0))) { st.fail('stack element is not 0') } }) @@ -66,7 +66,7 @@ tape('EIP 3541 tests', (t) => { const result = await vm.runCode({ code: Buffer.from('5F'.repeat(depth), 'hex'), - gasLimit: 10000n, + gasLimit: BigInt(10000), }) st.ok(result.exceptionError?.error === ERROR.STACK_OVERFLOW) @@ -78,7 +78,7 @@ tape('EIP 3541 tests', (t) => { const result = await vm.runCode({ code: Buffer.from('5F', 'hex'), - gasLimit: 10000n, + gasLimit: BigInt(10000), }) st.ok(result.exceptionError!.error === ERROR.INVALID_OPCODE) diff --git a/packages/vm/tests/api/evm/precompiles/06-ecadd.spec.ts b/packages/vm/tests/api/evm/precompiles/06-ecadd.spec.ts index 5f5183ff70..5491e3a1e7 100644 --- a/packages/vm/tests/api/evm/precompiles/06-ecadd.spec.ts +++ b/packages/vm/tests/api/evm/precompiles/06-ecadd.spec.ts @@ -18,7 +18,7 @@ tape('Precompiles: ECADD', (t) => { _VM: vm, }) - st.deepEqual(result.gasUsed, 500n, 'should use petersburg gas costs') + st.deepEqual(result.gasUsed, BigInt(500), 'should use petersburg gas costs') st.end() }) }) diff --git a/packages/vm/tests/api/evm/precompiles/07-ecmul.spec.ts b/packages/vm/tests/api/evm/precompiles/07-ecmul.spec.ts index f3de913e92..7982f9a95b 100644 --- a/packages/vm/tests/api/evm/precompiles/07-ecmul.spec.ts +++ b/packages/vm/tests/api/evm/precompiles/07-ecmul.spec.ts @@ -18,7 +18,7 @@ tape('Precompiles: ECMUL', (t) => { _VM: vm, }) - st.deepEqual(result.gasUsed, 40000n, 'should use petersburg gas costs') + st.deepEqual(result.gasUsed, BigInt(40000), 'should use petersburg gas costs') st.end() }) }) diff --git a/packages/vm/tests/api/evm/precompiles/08-ecpairing.spec.ts b/packages/vm/tests/api/evm/precompiles/08-ecpairing.spec.ts index ce0147a4ef..c97cd3f7d9 100644 --- a/packages/vm/tests/api/evm/precompiles/08-ecpairing.spec.ts +++ b/packages/vm/tests/api/evm/precompiles/08-ecpairing.spec.ts @@ -21,7 +21,11 @@ tape('Precompiles: ECPAIRING', (t) => { _VM: vm, }) - st.deepEqual(result.gasUsed, 260000n, 'should use petersburg gas costs (k ^= 2 pairings)') + st.deepEqual( + result.gasUsed, + BigInt(260000), + 'should use petersburg gas costs (k ^= 2 pairings)' + ) st.end() }) }) diff --git a/packages/vm/tests/api/evm/precompiles/hardfork.spec.ts b/packages/vm/tests/api/evm/precompiles/hardfork.spec.ts index 5bdda8b2e5..bf7b13cd93 100644 --- a/packages/vm/tests/api/evm/precompiles/hardfork.spec.ts +++ b/packages/vm/tests/api/evm/precompiles/hardfork.spec.ts @@ -26,10 +26,10 @@ tape('Precompiles: hardfork availability', (t) => { caller: Address.zero(), gasLimit: BigInt(0xffffffffff), to: ECPAIR_Address, - value: 0n, + value: BigInt(0), }) - st.assert(result.gasUsed === 100000n) // check that we are using gas (if address would contain no code we use 0 gas) + st.assert(result.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 }) @@ -46,10 +46,10 @@ tape('Precompiles: hardfork availability', (t) => { caller: Address.zero(), gasLimit: BigInt(0xffffffffff), to: ECPAIR_Address, - value: 0n, + value: BigInt(0), }) - st.assert(result.gasUsed === 100000n) + st.assert(result.gasUsed === BigInt(100000)) // Check if ECPAIR is not available in Homestead. const commonHomestead = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Homestead }) @@ -67,10 +67,10 @@ tape('Precompiles: hardfork availability', (t) => { caller: Address.zero(), gasLimit: BigInt(0xffffffffff), to: ECPAIR_Address, - value: 0n, + value: BigInt(0), }) - st.assert(result.gasUsed === 0n) // check that we use no gas, because we are calling into an address without code. + st.assert(result.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/evm/stack.spec.ts b/packages/vm/tests/api/evm/stack.spec.ts index 336fd5a345..1de5278ebe 100644 --- a/packages/vm/tests/api/evm/stack.spec.ts +++ b/packages/vm/tests/api/evm/stack.spec.ts @@ -28,30 +28,30 @@ tape('Stack', (t) => { t.test('should push item', (st) => { const s = new Stack() - s.push(5n) - st.equal(s.pop(), 5n) + s.push(BigInt(5)) + st.equal(s.pop(), BigInt(5)) st.end() }) t.test('popN should return array for n = 1', (st) => { const s = new Stack() - s.push(5n) + s.push(BigInt(5)) st.deepEqual(s.popN(1), [5n]) st.end() }) t.test('popN should fail on underflow', (st) => { const s = new Stack() - s.push(5n) + s.push(BigInt(5)) st.throws(() => s.popN(2)) st.end() }) t.test('popN should return in correct order', (st) => { const s = new Stack() - s.push(5n) - s.push(7n) - st.deepEqual(s.popN(2), [7n, 5n]) + s.push(BigInt(5)) + s.push(BigInt(7)) + st.deepEqual(s.popN(2), [7n, BigInt(5)]) st.end() }) @@ -60,7 +60,7 @@ tape('Stack', (t) => { for (let i = 0; i < 1024; i++) { s.push(BigInt(i)) } - st.throws(() => s.push(1024n)) + st.throws(() => s.push(BigInt(1024))) st.end() }) @@ -69,57 +69,57 @@ tape('Stack', (t) => { for (let i = 0; i < 1023; i++) { s.push(BigInt(i)) } - st.throws(() => s.push(1023n)) + st.throws(() => s.push(BigInt(1023))) st.end() }) t.test('should swap top with itself', (st) => { const s = new Stack() - s.push(5n) + s.push(BigInt(5)) s.swap(0) - st.deepEqual(s.pop(), 5n) + st.deepEqual(s.pop(), BigInt(5)) st.end() }) t.test('swap should throw on underflow', (st) => { const s = new Stack() - s.push(5n) + s.push(BigInt(5)) st.throws(() => s.swap(1)) st.end() }) t.test('should swap', (st) => { const s = new Stack() - s.push(5n) - s.push(7n) + s.push(BigInt(5)) + s.push(BigInt(7)) s.swap(1) - st.deepEqual(s.pop(), 5n) + st.deepEqual(s.pop(), BigInt(5)) st.end() }) t.test('dup should throw on underflow', (st) => { const s = new Stack() st.throws(() => s.dup(1)) - s.push(5n) + s.push(BigInt(5)) st.throws(() => s.dup(2)) st.end() }) t.test('should dup', (st) => { const s = new Stack() - s.push(5n) - s.push(7n) + s.push(BigInt(5)) + s.push(BigInt(7)) s.dup(2) - st.deepEqual(s.pop(), 5n) + st.deepEqual(s.pop(), BigInt(5)) st.end() }) t.test('should validate value overflow', (st) => { const s = new Stack() - const max = 2n ** 256n - 1n + const max = BigInt(2) ** BigInt(256) - BigInt(1) s.push(max) st.deepEqual(s.pop(), max) - st.throws(() => s.push(max + 1n)) + st.throws(() => s.push(max + BigInt(1))) st.end() }) @@ -154,7 +154,7 @@ tape('Stack', (t) => { caller: caller, gasLimit: BigInt(0xffffffffff), to: addr, - value: 1n, + value: BigInt(1), } try { const res = await vm.runCall(runCallArgs) diff --git a/packages/vm/tests/api/istanbul/eip-1108.spec.ts b/packages/vm/tests/api/istanbul/eip-1108.spec.ts index a1c29174e4..0c421e1a29 100644 --- a/packages/vm/tests/api/istanbul/eip-1108.spec.ts +++ b/packages/vm/tests/api/istanbul/eip-1108.spec.ts @@ -18,7 +18,7 @@ tape('Istanbul: EIP-1108 tests', (t) => { _VM: vm, }) - st.deepEqual(result.gasUsed, 150n, 'should use istanbul gas costs') + st.deepEqual(result.gasUsed, BigInt(150), 'should use istanbul gas costs') st.end() }) @@ -35,7 +35,7 @@ tape('Istanbul: EIP-1108 tests', (t) => { _VM: vm, }) - st.deepEqual(result.gasUsed, 6000n, 'should use istanbul gas costs') + st.deepEqual(result.gasUsed, BigInt(6000), 'should use istanbul gas costs') st.end() }) @@ -55,7 +55,11 @@ tape('Istanbul: EIP-1108 tests', (t) => { _VM: vm, }) - st.deepEqual(result.gasUsed, 113000n, 'should use petersburg gas costs (k ^= 2 pairings)') + st.deepEqual( + result.gasUsed, + BigInt(113000), + 'should use petersburg gas costs (k ^= 2 pairings)' + ) st.end() }) }) diff --git a/packages/vm/tests/api/istanbul/eip-152.spec.ts b/packages/vm/tests/api/istanbul/eip-152.spec.ts index 0d12013e70..2174cdaea1 100644 --- a/packages/vm/tests/api/istanbul/eip-152.spec.ts +++ b/packages/vm/tests/api/istanbul/eip-152.spec.ts @@ -92,7 +92,7 @@ tape('Istanbul: EIP-152', (t) => { st.comment(testCase.name) const res = blake2f({ data: Buffer.from(testCase.input, 'hex'), - gasLimit: 20n, + gasLimit: BigInt(20), _common: common, _VM: vm, }) @@ -103,7 +103,7 @@ tape('Istanbul: EIP-152', (t) => { st.comment(testCase.name) const res = blake2f({ data: Buffer.from(testCase.input, 'hex'), - gasLimit: 10000000n, + gasLimit: BigInt(10000000), _common: common, _VM: vm, }) diff --git a/packages/vm/tests/api/istanbul/eip-2200.spec.ts b/packages/vm/tests/api/istanbul/eip-2200.spec.ts index 04c44e4ea0..41430a28ff 100644 --- a/packages/vm/tests/api/istanbul/eip-2200.spec.ts +++ b/packages/vm/tests/api/istanbul/eip-2200.spec.ts @@ -6,45 +6,45 @@ import { createAccount } from '../utils' const testCases = [ { - original: 0n, + original: BigInt(0), code: '60006000556000600055', used: 1612, refund: 0, gas: undefined, err: undefined, }, // 0 -> 0 -> 0 - /*{ original: 0n, code: '60006000556001600055', used: 20812, refund: 0 }, // 0 -> 0 -> 1 - { original: 0n, code: '60016000556000600055', used: 20812, refund: 19200 }, // 0 -> 1 -> 0 - { original: 0n, code: '60016000556002600055', used: 20812, refund: 0 }, // 0 -> 1 -> 2 - { original: 0n, code: '60016000556001600055', used: 20812, refund: 0 }, // 0 -> 1 -> 1 - { original: 1n, code: '60006000556000600055', used: 5812, refund: 15000 }, // 1 -> 0 -> 0 - { original: 1n, code: '60006000556001600055', used: 5812, refund: 4200 }, // 1 -> 0 -> 1 - { original: 1n, code: '60006000556002600055', used: 5812, refund: 0 }, // 1 -> 0 -> 2 - { original: 1n, code: '60026000556000600055', used: 5812, refund: 15000 }, // 1 -> 2 -> 0 - { original: 1n, code: '60026000556003600055', used: 5812, refund: 0 }, // 1 -> 2 -> 3 - { original: 1n, code: '60026000556001600055', used: 5812, refund: 4200 }, // 1 -> 2 -> 1 - { original: 1n, code: '60026000556002600055', used: 5812, refund: 0 }, // 1 -> 2 -> 2 - { original: 1n, code: '60016000556000600055', used: 5812, refund: 15000 }, // 1 -> 1 -> 0 - { original: 1n, code: '60016000556002600055', used: 5812, refund: 0 }, // 1 -> 1 -> 2 - { original: 1n, code: '60016000556001600055', used: 1612, refund: 0 }, // 1 -> 1 -> 1 - { original: 0n, code: '600160005560006000556001600055', used: 40818, refund: 19200 }, // 0 -> 1 -> 0 -> 1 - { original: 1n, code: '600060005560016000556000600055', used: 10818, refund: 19200 }, // 1 -> 0 -> 1 -> 08*/ + /*{ original:BigInt(0), code: '60006000556001600055', used: 20812, refund: 0 }, // 0 -> 0 -> 1 + { original:BigInt(0), code: '60016000556000600055', used: 20812, refund: 19200 }, // 0 -> 1 -> 0 + { original:BigInt(0), code: '60016000556002600055', used: 20812, refund: 0 }, // 0 -> 1 -> 2 + { original:BigInt(0), code: '60016000556001600055', used: 20812, refund: 0 }, // 0 -> 1 -> 1 + { original:BigInt(1), code: '60006000556000600055', used: 5812, refund: 15000 }, // 1 -> 0 -> 0 + { original:BigInt(1), code: '60006000556001600055', used: 5812, refund: 4200 }, // 1 -> 0 -> 1 + { original:BigInt(1), code: '60006000556002600055', used: 5812, refund: 0 }, // 1 -> 0 -> 2 + { original:BigInt(1), code: '60026000556000600055', used: 5812, refund: 15000 }, // 1 -> 2 -> 0 + { original:BigInt(1), code: '60026000556003600055', used: 5812, refund: 0 }, // 1 -> 2 -> 3 + { original:BigInt(1), code: '60026000556001600055', used: 5812, refund: 4200 }, // 1 -> 2 -> 1 + { original:BigInt(1), code: '60026000556002600055', used: 5812, refund: 0 }, // 1 -> 2 -> 2 + { original:BigInt(1), code: '60016000556000600055', used: 5812, refund: 15000 }, // 1 -> 1 -> 0 + { original:BigInt(1), code: '60016000556002600055', used: 5812, refund: 0 }, // 1 -> 1 -> 2 + { original:BigInt(1), code: '60016000556001600055', used: 1612, refund: 0 }, // 1 -> 1 -> 1 + { original:BigInt(0), code: '600160005560006000556001600055', used: 40818, refund: 19200 }, // 0 -> 1 -> 0 -> 1 + { original:BigInt(1), code: '600060005560016000556000600055', used: 10818, refund: 19200 }, // 1 -> 0 -> 1 -> 08*/ /*{ - original: 1n, - gas: 2306n, + original:BigInt(1), + gas: BigInt(2306), code: '6001600055', used: 2306, refund: 0, err: ERROR.OUT_OF_GAS, }, // 1 -> 1 (2300 sentry + 2xPUSH) - { original: 1n, gas: 2307n, code: '6001600055', used: 806, refund: 0 }, // 1 -> 1 (2301 sentry + 2xPUSH)*/ + { original:BigInt(1), gas: BigInt(2307), code: '6001600055', used: 806, refund: 0 }, // 1 -> 1 (2301 sentry + 2xPUSH)*/ ] tape('Istanbul: EIP-2200', async (t) => { t.test('net-metering SSTORE', async (st) => { const caller = new Address(Buffer.from('0000000000000000000000000000000000000000', 'hex')) const addr = new Address(Buffer.from('00000000000000000000000000000000000000ff', 'hex')) - const key = setLengthLeft(toBuffer('0x' + 0n.toString(16)), 32) + const key = setLengthLeft(toBuffer('0x' + BigInt(0).toString(16)), 32) for (const testCase of testCases) { const common = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Istanbul }) @@ -53,7 +53,7 @@ tape('Istanbul: EIP-2200', async (t) => { const account = createAccount(new BN(0), new BN(0)) await vm.stateManager.putAccount(addr, account) await vm.stateManager.putContractCode(addr, Buffer.from(testCase.code, 'hex')) - if (!(testCase.original === 0n)) { + if (!(testCase.original === BigInt(0))) { await vm.stateManager.putContractStorage( addr, key, diff --git a/packages/vm/tests/api/runBlock.spec.ts b/packages/vm/tests/api/runBlock.spec.ts index 855f911294..935c5d5366 100644 --- a/packages/vm/tests/api/runBlock.spec.ts +++ b/packages/vm/tests/api/runBlock.spec.ts @@ -172,11 +172,13 @@ tape('runBlock() -> successful API parameter usage', async (t) => { generate: true, }) st.ok( - txResultChainstart.results[0].gasUsed === 21000n + 68n * 3n + 3n + 50n, + 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 === 21000n + 32000n + 16n * 3n + 3n + 800n, + 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' ) }) diff --git a/packages/vm/tests/api/runCall.spec.ts b/packages/vm/tests/api/runCall.spec.ts index 4245c333e9..6f97b9bfbc 100644 --- a/packages/vm/tests/api/runCall.spec.ts +++ b/packages/vm/tests/api/runCall.spec.ts @@ -160,7 +160,7 @@ tape('Ensure that precompile activation creates non-empty accounts', async (t) = caller: caller, // call address gasLimit: BigInt(0xffffffffff), // ensure we pass a lot of gas, so we do not run out of gas to: contractAddress, // call to the contract address, - value: 1n, + value: BigInt(1), } const resultNotActivated = await vmNotActivated.runCall(runCallArgs) @@ -219,8 +219,8 @@ tape('Ensure that Istanbul sstoreCleanRefundEIP2200 gas is applied correctly', a const result = await vm.runCall(runCallArgs) - t.equal(result.gasUsed, 5812n, 'gas used correct') - t.equal(result.execResult.gasRefund!, 4200n, 'gas refund correct') + t.equal(result.gasUsed, BigInt(5812), 'gas used correct') + t.equal(result.execResult.gasRefund!, BigInt(4200), 'gas refund correct') t.end() }) @@ -246,8 +246,8 @@ tape('ensure correct gas for pre-constantinople sstore', async (t) => { const result = await vm.runCall(runCallArgs) - t.equal(result.gasUsed, 20006n, 'gas used correct') - t.equal(result.execResult.gasRefund!, 0n, 'gas refund correct') + t.equal(result.gasUsed, BigInt(20006), 'gas used correct') + t.equal(result.execResult.gasRefund!, BigInt(0), 'gas refund correct') t.end() }) @@ -275,8 +275,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, 25066n, 'gas used correct') - t.equal(result.execResult.gasRefund!, 0n, 'gas refund correct') + t.equal(result.gasUsed, BigInt(25066), 'gas used correct') + t.equal(result.execResult.gasRefund!, BigInt(0), 'gas refund correct') t.end() }) @@ -300,13 +300,13 @@ tape( const runCallArgs = { caller: caller, // call address to: address, - gasLimit: 200n, + gasLimit: BigInt(200), } const result = await vm.runCall(runCallArgs) t.ok(runCallArgs.gasLimit === result.gasUsed, 'gas used correct') - t.equal(result.execResult.gasRefund!, 0n, 'gas refund correct') + t.equal(result.execResult.gasRefund!, BigInt(0), 'gas refund correct') t.ok(result.execResult.exceptionError!.error == ERROR.OUT_OF_GAS, 'call went out of gas') t.end() @@ -336,9 +336,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, 30003n, 'gas used correct') + t.equal(result.gasUsed, BigInt(30003), 'gas used correct') // selfdestruct refund - t.equal(result.execResult.gasRefund!, 24000n, 'gas refund correct') + t.equal(result.execResult.gasRefund!, BigInt(24000), 'gas refund correct') t.end() }) @@ -484,9 +484,9 @@ tape('Ensure that IDENTITY precompile copies the memory', async (t) => { // setup the call arguments const runCallArgs = { caller: caller, // call address - gasLimit: 150000n, + gasLimit: BigInt(150000), data: Buffer.from(code, 'hex'), - gasPrice: 70000000000n, + gasPrice: BigInt(70000000000), } const result = await vm.runCall(runCallArgs) diff --git a/packages/vm/tests/api/runTx.spec.ts b/packages/vm/tests/api/runTx.spec.ts index b03bbe80bd..78d62eb8af 100644 --- a/packages/vm/tests/api/runTx.spec.ts +++ b/packages/vm/tests/api/runTx.spec.ts @@ -42,7 +42,7 @@ tape('runTx() -> successful API parameter usage', async (t) => { await vm.stateManager.putAccount(caller, acc) const res = await vm.runTx({ tx }) - st.true(res.gasUsed > 0n, `${msg} (${txType.name})`) + st.true(res.gasUsed > BigInt(0), `${msg} (${txType.name})`) } } @@ -68,7 +68,7 @@ tape('runTx() -> successful API parameter usage', async (t) => { const acc = createAccount() await vm.stateManager.putAccount(caller, acc) - const blockGasUsed = 1000n + const blockGasUsed = BigInt(1000) const res = await vm.runTx({ tx, blockGasUsed }) t.ok( bufferToBigInt(res.receipt.gasUsed) === blockGasUsed + res.gasUsed, @@ -89,7 +89,7 @@ tape('runTx() -> successful API parameter usage', async (t) => { const res = await vm.runTx({ tx }) t.true( - res.gasUsed > 0n, + res.gasUsed > BigInt(0), `mainnet (PoW), istanbul HF, default SM - should run without errors (${TRANSACTION_TYPES[0].name})` ) @@ -216,7 +216,7 @@ tape('runTx() -> API parameter usage/data errors', (t) => { const res = await vm.runTx({ tx, reportAccessList: true }) t.true( - res.gasUsed > 0n, + res.gasUsed > BigInt(0), `mainnet (PoW), istanbul HF, default SM - should run without errors (${TRANSACTION_TYPES[0].name})` ) t.deepEqual(res.accessList, []) @@ -451,7 +451,7 @@ tape('runTx() -> API return values', async (t) => { await vm.stateManager.putAccount(caller, acc) const res = await vm.runTx({ tx }) - t.true(res.execResult.gasUsed === 0n, `execution result -> gasUsed -> 0 (${txType.name})`) + t.true(res.execResult.gasUsed === BigInt(0), `execution result -> gasUsed -> 0 (${txType.name})`) t.equal( res.execResult.exceptionError, undefined, @@ -463,7 +463,7 @@ tape('runTx() -> API return values', async (t) => { `execution result -> return value -> empty Buffer (${txType.name})` ) t.true( - res.execResult.gasRefund! === 0n, + res.execResult.gasRefund! === BigInt(0), `execution result -> gasRefund -> 0 (${txType.name})` ) } diff --git a/packages/vm/tests/api/state/accountExists.spec.ts b/packages/vm/tests/api/state/accountExists.spec.ts index 94eef0d6e5..98151a151f 100644 --- a/packages/vm/tests/api/state/accountExists.spec.ts +++ b/packages/vm/tests/api/state/accountExists.spec.ts @@ -38,11 +38,11 @@ tape('correctly apply new account gas fee on pre-Spurious Dragon hardforks', asy 'hex' ), to: contractAddress, // call to the contract address - value: 0n, + value: BigInt(0), } const result = await vm.runCall(runCallArgs) - t.ok(result.gasUsed === 53552n, 'vm correctly applies new account gas price') + t.ok(result.gasUsed === BigInt(53552), 'vm correctly applies new account gas price') t.end() }) @@ -83,11 +83,11 @@ tape( 'hex' ), to: contractAddress, // call to the contract address - value: 0n, + value: BigInt(0), } const result = await vm.runCall(runCallArgs) - t.ok(result.gasUsed === 28552n, 'new account price not applied as empty account exists') + t.ok(result.gasUsed === BigInt(28552), 'new account price not applied as empty account exists') t.end() } ) diff --git a/packages/vm/tests/tester/runners/BlockchainTestsRunner.ts b/packages/vm/tests/tester/runners/BlockchainTestsRunner.ts index e85b20efd4..58cc6e9e15 100644 --- a/packages/vm/tests/tester/runners/BlockchainTestsRunner.ts +++ b/packages/vm/tests/tester/runners/BlockchainTestsRunner.ts @@ -91,7 +91,7 @@ export default async function runBlockchainTest(options: any, testData: any, t: } } - let currentBlock = 0n + let currentBlock = BigInt(0) for (const raw of testData.blocks) { const paramFork = `expectException${options.forkConfigTestSuite}` // Two naming conventions in ethereum/tests to indicate "exception occurs on all HFs" semantics From 05ccc200aa8ae2460c821aa51bb5e605d1b9ecc4 Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Tue, 22 Feb 2022 07:37:29 -0500 Subject: [PATCH 40/42] lint --- packages/vm/tests/api/runBlock.spec.ts | 4 ++-- packages/vm/tests/api/runTx.spec.ts | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/vm/tests/api/runBlock.spec.ts b/packages/vm/tests/api/runBlock.spec.ts index 935c5d5366..05109a8b80 100644 --- a/packages/vm/tests/api/runBlock.spec.ts +++ b/packages/vm/tests/api/runBlock.spec.ts @@ -173,12 +173,12 @@ tape('runBlock() -> successful API parameter usage', async (t) => { }) st.ok( txResultChainstart.results[0].gasUsed === - BigInt(21000) + BigInt(68) * BigInt(3) + BigInt(3) + BigInt(50), + 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), + BigInt(21000) + BigInt(32000) + BigInt(16) * BigInt(3) + BigInt(3) + BigInt(800), 'tx charged right gas on muir glacier hard fork' ) }) diff --git a/packages/vm/tests/api/runTx.spec.ts b/packages/vm/tests/api/runTx.spec.ts index 78d62eb8af..e0f2d44c4e 100644 --- a/packages/vm/tests/api/runTx.spec.ts +++ b/packages/vm/tests/api/runTx.spec.ts @@ -451,7 +451,10 @@ 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), `execution result -> gasUsed -> 0 (${txType.name})`) + t.true( + res.execResult.gasUsed === BigInt(0), + `execution result -> gasUsed -> 0 (${txType.name})` + ) t.equal( res.execResult.exceptionError, undefined, From c6b0e706711843f38428dc647f75a489274a3218 Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Tue, 22 Feb 2022 08:04:51 -0500 Subject: [PATCH 41/42] lint --- packages/vm/tests/api/state/stateManager.spec.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/vm/tests/api/state/stateManager.spec.ts b/packages/vm/tests/api/state/stateManager.spec.ts index bd6db734f5..bdc2fc0283 100644 --- a/packages/vm/tests/api/state/stateManager.spec.ts +++ b/packages/vm/tests/api/state/stateManager.spec.ts @@ -344,8 +344,6 @@ tape('StateManager', (t) => { st.ok(slotCode.length == 0, 'code cannot be loaded') // This test fails if no code prefix is used account = await codeStateManager.getAccount(address1) - console.log(account.codeHash.toString('hex')) - console.log(root.toString('hex')) account.stateRoot = root await codeStateManager.putAccount(address1, account) From 1ddcc2395ebcb115bedee266849115cd7b15da8e Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Tue, 22 Feb 2022 08:20:51 -0500 Subject: [PATCH 42/42] More Xn to BigInt(X) moves --- packages/vm/src/evm/eei.ts | 2 +- packages/vm/src/evm/opcodes/util.ts | 2 +- packages/vm/tests/api/evm/stack.spec.ts | 4 ++-- packages/vm/tests/api/runCall.spec.ts | 2 +- packages/vm/tests/api/runCode.spec.ts | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/vm/src/evm/eei.ts b/packages/vm/src/evm/eei.ts index 6e84fbbde6..163fbd8b9c 100644 --- a/packages/vm/src/evm/eei.ts +++ b/packages/vm/src/evm/eei.ts @@ -322,7 +322,7 @@ export default class EEI { * CHAINID opcode proposed in [EIP-1344](https://eips.ethereum.org/EIPS/eip-1344). */ getChainId(): bigint { - return bnToBigInt(this._common.chainIdBN()) + return bnToBigInt(this._common.chainId()) } /** diff --git a/packages/vm/src/evm/opcodes/util.ts b/packages/vm/src/evm/opcodes/util.ts index 0b955b26e8..d596dbdc52 100644 --- a/packages/vm/src/evm/opcodes/util.ts +++ b/packages/vm/src/evm/opcodes/util.ts @@ -287,7 +287,7 @@ export function abs(a: bigint) { if (a > 0) { return a } - return a * -1n + return a * BigInt(-1) } const N = BigInt(115792089237316195423570985008687907853269984665640564039457584007913129639936) diff --git a/packages/vm/tests/api/evm/stack.spec.ts b/packages/vm/tests/api/evm/stack.spec.ts index 1de5278ebe..b3ab9740f1 100644 --- a/packages/vm/tests/api/evm/stack.spec.ts +++ b/packages/vm/tests/api/evm/stack.spec.ts @@ -36,7 +36,7 @@ tape('Stack', (t) => { t.test('popN should return array for n = 1', (st) => { const s = new Stack() s.push(BigInt(5)) - st.deepEqual(s.popN(1), [5n]) + st.deepEqual(s.popN(1), [BigInt(5)]) st.end() }) @@ -51,7 +51,7 @@ tape('Stack', (t) => { const s = new Stack() s.push(BigInt(5)) s.push(BigInt(7)) - st.deepEqual(s.popN(2), [7n, BigInt(5)]) + st.deepEqual(s.popN(2), [BigInt(7), BigInt(5)]) st.end() }) diff --git a/packages/vm/tests/api/runCall.spec.ts b/packages/vm/tests/api/runCall.spec.ts index 6f97b9bfbc..6e013de5aa 100644 --- a/packages/vm/tests/api/runCall.spec.ts +++ b/packages/vm/tests/api/runCall.spec.ts @@ -511,7 +511,7 @@ tape('Throws on negative call value', async (t) => { // setup the call arguments const runCallArgs = { - value: -10n, + value: BigInt(-10), } try { diff --git a/packages/vm/tests/api/runCode.spec.ts b/packages/vm/tests/api/runCode.spec.ts index dee84d4bd4..5c57aaa129 100644 --- a/packages/vm/tests/api/runCode.spec.ts +++ b/packages/vm/tests/api/runCode.spec.ts @@ -100,7 +100,7 @@ tape('VM.runCode: RunCodeOptions', (t) => { const vm = new VM() const runCodeArgs = { - value: -10n, + value: BigInt(-10), } try {