diff --git a/packages/block/src/header.ts b/packages/block/src/header.ts index e9d6127d661..fb2d8ad6911 100644 --- a/packages/block/src/header.ts +++ b/packages/block/src/header.ts @@ -239,7 +239,7 @@ export class BlockHeader { const londonHfBlock = this._common.hardforkBlock(Hardfork.London) const isInitialEIP1559Block = londonHfBlock && number === londonHfBlock if (isInitialEIP1559Block) { - baseFeePerGas = BigInt(this._common.param('gasConfig', 'initialBaseFee')) + baseFeePerGas = this._common.param('gasConfig', 'initialBaseFee') } else { // Minimum possible value for baseFeePerGas is 7, // so we use it as the default if the field is missing. @@ -435,11 +435,9 @@ export class BlockHeader { const hardfork = this._common.hardfork() const blockTs = this.timestamp const { timestamp: parentTs, difficulty: parentDif } = parentBlockHeader - const minimumDifficulty = BigInt( - this._common.paramByHardfork('pow', 'minimumDifficulty', hardfork) - ) + const minimumDifficulty = this._common.paramByHardfork('pow', 'minimumDifficulty', hardfork) const offset = - parentDif / BigInt(this._common.paramByHardfork('pow', 'difficultyBoundDivisor', hardfork)) + parentDif / this._common.paramByHardfork('pow', 'difficultyBoundDivisor', hardfork) let num = this.number // We use a ! here as TS cannot follow this hardfork-dependent logic, but it always gets assigned @@ -459,7 +457,7 @@ export class BlockHeader { if (this._common.hardforkGteHardfork(hardfork, Hardfork.Byzantium)) { // Get delay as parameter from common - num = num - BigInt(this._common.param('pow', 'difficultyBombDelay')) + num = num - this._common.param('pow', 'difficultyBombDelay') if (num < BigInt(0)) { num = BigInt(0) } @@ -474,10 +472,7 @@ export class BlockHeader { dif = parentDif + offset * a } else { // pre-homestead - if ( - parentTs + BigInt(this._common.paramByHardfork('pow', 'durationLimit', hardfork)) > - blockTs - ) { + if (parentTs + this._common.paramByHardfork('pow', 'durationLimit', hardfork) > blockTs) { dif = offset + parentDif } else { dif = parentDif - offset @@ -552,22 +547,21 @@ export class BlockHeader { // to adopt to the new gas target centered logic const londonHardforkBlock = this._common.hardforkBlock(Hardfork.London) if (londonHardforkBlock && this.number === londonHardforkBlock) { - const elasticity = BigInt(this._common.param('gasConfig', 'elasticityMultiplier')) + const elasticity = this._common.param('gasConfig', 'elasticityMultiplier') parentGasLimit = parentGasLimit * elasticity } const gasLimit = this.gasLimit const hardfork = this._common.hardfork() const a = - parentGasLimit / - BigInt(this._common.paramByHardfork('gasConfig', 'gasLimitBoundDivisor', hardfork)) + parentGasLimit / this._common.paramByHardfork('gasConfig', 'gasLimitBoundDivisor', hardfork) const maxGasLimit = parentGasLimit + a const minGasLimit = parentGasLimit - a const result = gasLimit < maxGasLimit && gasLimit > minGasLimit && - gasLimit >= BigInt(this._common.paramByHardfork('gasConfig', 'minGasLimit', hardfork)) + gasLimit >= this._common.paramByHardfork('gasConfig', 'minGasLimit', hardfork) return result } @@ -703,7 +697,7 @@ export class BlockHeader { const londonHfBlock = this._common.hardforkBlock(Hardfork.London) const isInitialEIP1559Block = londonHfBlock && this.number === londonHfBlock if (isInitialEIP1559Block) { - const initialBaseFee = BigInt(this._common.param('gasConfig', 'initialBaseFee')) + const initialBaseFee = this._common.param('gasConfig', 'initialBaseFee') if (this.baseFeePerGas! !== initialBaseFee) { const msg = this._errorMsg('Initial EIP1559 block does not have initial base fee') throw new Error(msg) @@ -731,25 +725,29 @@ export class BlockHeader { throw new Error(msg) } let nextBaseFee: bigint - const elasticity = BigInt(this._common.param('gasConfig', 'elasticityMultiplier')) + const elasticity = this._common.param('gasConfig', 'elasticityMultiplier') const parentGasTarget = this.gasLimit / elasticity if (parentGasTarget === this.gasUsed) { nextBaseFee = this.baseFeePerGas! } else if (this.gasUsed > parentGasTarget) { const gasUsedDelta = this.gasUsed - parentGasTarget - const baseFeeMaxChangeDenominator = BigInt( - this._common.param('gasConfig', 'baseFeeMaxChangeDenominator') + const baseFeeMaxChangeDenominator = this._common.param( + 'gasConfig', + 'baseFeeMaxChangeDenominator' ) + const calculatedDelta = (this.baseFeePerGas! * gasUsedDelta) / parentGasTarget / baseFeeMaxChangeDenominator nextBaseFee = (calculatedDelta > BigInt(1) ? calculatedDelta : BigInt(1)) + this.baseFeePerGas! } else { const gasUsedDelta = parentGasTarget - this.gasUsed - const baseFeeMaxChangeDenominator = BigInt( - this._common.param('gasConfig', 'baseFeeMaxChangeDenominator') + const baseFeeMaxChangeDenominator = this._common.param( + 'gasConfig', + 'baseFeeMaxChangeDenominator' ) + const calculatedDelta = (this.baseFeePerGas! * gasUsedDelta) / parentGasTarget / baseFeeMaxChangeDenominator nextBaseFee = diff --git a/packages/block/test/eip1559block.spec.ts b/packages/block/test/eip1559block.spec.ts index a367ebb158c..b34f1d2ced8 100644 --- a/packages/block/test/eip1559block.spec.ts +++ b/packages/block/test/eip1559block.spec.ts @@ -131,7 +131,7 @@ tape('EIP1559 tests', function (t) { parentHash: genesis.hash(), gasLimit: genesis.header.gasLimit * BigInt(2), // Special case on EIP-1559 transition block timestamp: BigInt(1), - baseFeePerGas: BigInt(common.param('gasConfig', 'initialBaseFee')), + baseFeePerGas: common.param('gasConfig', 'initialBaseFee'), }, }, { @@ -202,9 +202,10 @@ tape('EIP1559 tests', function (t) { timestamp: BigInt(1), gasLimit: genesis.header.gasLimit * BigInt(2), // Special case on EIP-1559 transition block gasUsed: - genesis.header.gasLimit * BigInt(common.param('gasConfig', 'elasticityMultiplier')) + + genesis.header.gasLimit * + (common.param('gasConfig', 'elasticityMultiplier') ?? BigInt(0)) + BigInt(1), - baseFeePerGas: BigInt(common.param('gasConfig', 'initialBaseFee')), + baseFeePerGas: common.param('gasConfig', 'initialBaseFee'), }, { calcDifficultyFromHeader: genesis.header, @@ -229,7 +230,7 @@ tape('EIP1559 tests', function (t) { timestamp: BigInt(1), gasLimit: genesis.header.gasLimit * BigInt(2), // Special case on EIP-1559 transition block gasUsed: genesis.header.gasLimit * BigInt(2), - baseFeePerGas: BigInt(common.param('gasConfig', 'initialBaseFee')), + baseFeePerGas: common.param('gasConfig', 'initialBaseFee'), }, { calcDifficultyFromHeader: genesis.header, @@ -250,7 +251,7 @@ tape('EIP1559 tests', function (t) { parentHash: genesis.hash(), timestamp: BigInt(1), gasLimit: parentGasLimit + parentGasLimit / BigInt(1024) - BigInt(1), - baseFeePerGas: BigInt(common.param('gasConfig', 'initialBaseFee')), + baseFeePerGas: common.param('gasConfig', 'initialBaseFee'), }, { calcDifficultyFromHeader: genesis.header, @@ -266,7 +267,7 @@ tape('EIP1559 tests', function (t) { parentHash: genesis.hash(), timestamp: BigInt(1), gasLimit: parentGasLimit - parentGasLimit / BigInt(1024) + BigInt(1), - baseFeePerGas: BigInt(common.param('gasConfig', 'initialBaseFee')), + baseFeePerGas: common.param('gasConfig', 'initialBaseFee'), }, { calcDifficultyFromHeader: genesis.header, @@ -319,7 +320,7 @@ tape('EIP1559 tests', function (t) { parentHash: genesis.hash(), timestamp: BigInt(1), gasLimit: parentGasLimit + parentGasLimit / BigInt(1024), - baseFeePerGas: BigInt(common.param('gasConfig', 'initialBaseFee')), + baseFeePerGas: common.param('gasConfig', 'initialBaseFee'), }, { calcDifficultyFromHeader: genesis.header, @@ -370,7 +371,7 @@ tape('EIP1559 tests', function (t) { parentHash: genesis.hash(), timestamp: BigInt(1), gasLimit: parentGasLimit - parentGasLimit / BigInt(1024), - baseFeePerGas: BigInt(common.param('gasConfig', 'initialBaseFee')), + baseFeePerGas: common.param('gasConfig', 'initialBaseFee'), }, { calcDifficultyFromHeader: genesis.header, @@ -428,7 +429,7 @@ tape('EIP1559 tests', function (t) { parentHash: genesis.hash(), gasLimit: genesis.header.gasLimit * BigInt(2), // Special case on EIP-1559 transition block timestamp: BigInt(1), - baseFeePerGas: BigInt(common.param('gasConfig', 'initialBaseFee')), + baseFeePerGas: common.param('gasConfig', 'initialBaseFee'), }, transactions: [ { diff --git a/packages/client/lib/miner/miner.ts b/packages/client/lib/miner/miner.ts index 2f956963973..31b4383d075 100644 --- a/packages/client/lib/miner/miner.ts +++ b/packages/client/lib/miner/miner.ts @@ -228,9 +228,8 @@ export class Miner { const isInitialEIP1559Block = londonHardforkBlock && number === londonHardforkBlock if (isInitialEIP1559Block) { // Get baseFeePerGas from `paramByEIP` since 1559 not currently active on common - baseFeePerGas = BigInt( - this.config.chainCommon.paramByEIP('gasConfig', 'initialBaseFee', 1559) - ) + baseFeePerGas = + this.config.chainCommon.paramByEIP('gasConfig', 'initialBaseFee', 1559) ?? BigInt(0) // Set initial EIP1559 block gas limit to 2x parent gas limit per logic in `block.validateGasLimit` gasLimit = gasLimit * BigInt(2) } else if (this.config.chainCommon.isActivatedEIP(1559)) { diff --git a/packages/client/test/miner/miner.spec.ts b/packages/client/test/miner/miner.spec.ts index 34c74acf2d8..469680427c2 100644 --- a/packages/client/test/miner/miner.spec.ts +++ b/packages/client/test/miner/miner.spec.ts @@ -439,7 +439,7 @@ tape('[Miner]', async (t) => { blockHeader3.gasLimit, 'gas limit should be double previous block' ) - const initialBaseFee = BigInt(config.execCommon.paramByEIP('gasConfig', 'initialBaseFee', 1559)) + const initialBaseFee = config.execCommon.paramByEIP('gasConfig', 'initialBaseFee', 1559)! t.equal(blockHeader3.baseFeePerGas!, initialBaseFee, 'baseFee should be initial value') // block 4 diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts index 05932a25b67..b039f749f83 100644 --- a/packages/common/src/index.ts +++ b/packages/common/src/index.ts @@ -538,17 +538,15 @@ export default class Common extends EventEmitter { * * @param topic Parameter topic ('gasConfig', 'gasPrices', 'vm', 'pow') * @param name Parameter name (e.g. 'minGasLimit' for 'gasConfig' topic) - * @returns The value requested or `null` if not found + * @returns The value requested or `BigInt(0)` if not found */ - param(topic: string, name: string): any { + param(topic: string, name: string): bigint { // TODO: consider the case that different active EIPs // can change the same parameter - let value = null + let value for (const eip of this._eips) { value = this.paramByEIP(topic, name, eip) - if (value !== null) { - return value - } + if (value !== undefined) return value } return this.paramByHardfork(topic, name, this._hardfork) } @@ -558,9 +556,9 @@ export default class Common extends EventEmitter { * @param topic Parameter topic ('gasConfig', 'gasPrices', 'vm', 'pow') * @param name Parameter name (e.g. 'minGasLimit' for 'gasConfig' topic) * @param hardfork Hardfork name - * @returns The value requested or `null` if not found + * @returns The value requested or `BigInt(0)` if not found */ - paramByHardfork(topic: string, name: string, hardfork: string | Hardfork): any { + paramByHardfork(topic: string, name: string, hardfork: string | Hardfork): bigint { let value = null for (const hfChanges of HARDFORK_CHANGES) { // EIP-referencing HF file (e.g. berlin.json) @@ -568,7 +566,7 @@ export default class Common extends EventEmitter { const hfEIPs = hfChanges[1]['eips'] for (const eip of hfEIPs) { const valueEIP = this.paramByEIP(topic, name, eip) - value = valueEIP !== null ? valueEIP : value + value = valueEIP !== undefined ? valueEIP : value } // Paramater-inlining HF file (e.g. istanbul.json) } else { @@ -581,7 +579,8 @@ export default class Common extends EventEmitter { } if (hfChanges[0] === hardfork) break } - return value + if (!value) return BigInt(0) + return BigInt(value) } /** @@ -589,9 +588,9 @@ export default class Common extends EventEmitter { * @param topic Parameter topic ('gasConfig', 'gasPrices', 'vm', 'pow') * @param name Parameter name (e.g. 'minGasLimit' for 'gasConfig' topic) * @param eip Number of the EIP - * @returns The value requested or `null` if not found + * @returns The value requested or `undefined` if not found */ - paramByEIP(topic: string, name: string, eip: number): any { + paramByEIP(topic: string, name: string, eip: number): bigint | undefined { if (!(eip in EIPs)) { throw new Error(`${eip} not supported`) } @@ -601,10 +600,10 @@ export default class Common extends EventEmitter { throw new Error(`Topic ${topic} not defined`) } if (eipParams[topic][name] === undefined) { - return null + return undefined } const value = eipParams[topic][name].v - return value + return BigInt(value) } /** @@ -614,8 +613,9 @@ export default class Common extends EventEmitter { * @param name Parameter name * @param blockNumber Block number * @param td Total difficulty + * * @returns The value requested or `BigInt(0)` if not found */ - paramByBlock(topic: string, name: string, blockNumber: BigIntLike, td?: BigIntLike): any { + paramByBlock(topic: string, name: string, blockNumber: BigIntLike, td?: BigIntLike): bigint { const hardfork = this.getHardforkByBlockNumber(blockNumber, td) return this.paramByHardfork(topic, name, hardfork) } diff --git a/packages/common/tests/params.spec.ts b/packages/common/tests/params.spec.ts index d823dd3308f..85d2eac7271 100644 --- a/packages/common/tests/params.spec.ts +++ b/packages/common/tests/params.spec.ts @@ -5,19 +5,19 @@ tape('[Common]: Parameter access for param(), paramByHardfork()', function (t: t t.test('Basic usage', function (st: tape.Test) { const c = new Common({ chain: Chain.Mainnet, eips: [2537] }) let msg = 'Should return correct value when HF directly provided' - st.equal(c.paramByHardfork('gasPrices', 'ecAdd', 'byzantium'), 500, msg) + st.equal(c.paramByHardfork('gasPrices', 'ecAdd', 'byzantium'), BigInt(500), msg) msg = 'Should return correct value for HF set in class' c.setHardfork(Hardfork.Byzantium) - st.equal(c.param('gasPrices', 'ecAdd'), 500, msg) + st.equal(c.param('gasPrices', 'ecAdd'), BigInt(500), msg) c.setHardfork(Hardfork.Istanbul) - st.equal(c.param('gasPrices', 'ecAdd'), 150, msg) + st.equal(c.param('gasPrices', 'ecAdd'), BigInt(150), msg) c.setHardfork(Hardfork.MuirGlacier) - st.equal(c.param('gasPrices', 'ecAdd'), 150, msg) + st.equal(c.param('gasPrices', 'ecAdd'), BigInt(150), msg) - msg = 'Should return null for non-existing value' - st.equal(c.param('gasPrices', 'notexistingvalue'), null, msg) - st.equal(c.paramByHardfork('gasPrices', 'notexistingvalue', 'byzantium'), null, msg) + msg = 'Should return 0n for non-existing value' + st.equals(c.param('gasPrices', 'notexistingvalue'), BigInt(0), msg) + st.equals(c.paramByHardfork('gasPrices', 'notexistingvalue', 'byzantium'), BigInt(0), msg) /* // Manual test since no test triggering EIP config available @@ -41,7 +41,11 @@ tape('[Common]: Parameter access for param(), paramByHardfork()', function (t: t st.throws(f, /Topic gasPrizes not defined$/, msg) c.setHardfork(Hardfork.Byzantium) - st.equal(c.param('gasPrices', 'ecAdd'), 500, 'Should return correct value for HF set in class') + st.equal( + c.param('gasPrices', 'ecAdd'), + BigInt(500), + 'Should return correct value for HF set in class' + ) st.end() }) @@ -50,16 +54,20 @@ tape('[Common]: Parameter access for param(), paramByHardfork()', function (t: t const c = new Common({ chain: Chain.Mainnet }) let msg = 'Should return correct value for chain start' - st.equal(c.paramByHardfork('pow', 'minerReward', 'chainstart'), '5000000000000000000', msg) + st.equal( + c.paramByHardfork('pow', 'minerReward', 'chainstart'), + BigInt(5000000000000000000), + msg + ) msg = 'Should reflect HF update changes' - st.equal(c.paramByHardfork('pow', 'minerReward', 'byzantium'), '3000000000000000000', msg) + st.equal(c.paramByHardfork('pow', 'minerReward', 'byzantium'), BigInt(3000000000000000000), msg) msg = 'Should return updated sstore gas prices for constantinople' - st.equal(c.paramByHardfork('gasPrices', 'netSstoreNoopGas', 'constantinople'), 200, msg) + st.equal(c.paramByHardfork('gasPrices', 'netSstoreNoopGas', 'constantinople'), BigInt(200), msg) msg = 'Should nullify SSTORE related values for petersburg' - st.equal(c.paramByHardfork('gasPrices', 'netSstoreNoopGas', 'petersburg'), null, msg) + st.equals(c.paramByHardfork('gasPrices', 'netSstoreNoopGas', 'petersburg'), BigInt(0), msg) st.end() }) @@ -67,14 +75,14 @@ tape('[Common]: Parameter access for param(), paramByHardfork()', function (t: t t.test('Access by block number, paramByBlock()', function (st: tape.Test) { const c = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Byzantium }) let msg = 'Should correctly translate block numbers into HF states (updated value)' - st.equal(c.paramByBlock('pow', 'minerReward', 4370000), '3000000000000000000', msg) + st.equal(c.paramByBlock('pow', 'minerReward', 4370000), BigInt(3000000000000000000), msg) msg = 'Should correctly translate block numbers into HF states (original value)' - st.equal(c.paramByBlock('pow', 'minerReward', 4369999), '5000000000000000000', msg) + st.equal(c.paramByBlock('pow', 'minerReward', 4369999), BigInt(5000000000000000000), msg) msg = 'Should correctly translate total difficulty into HF states' const td = BigInt('1196768507891266117779') - st.equal(c.paramByBlock('pow', 'minerReward', 4370000, td), '3000000000000000000', msg) + st.equal(c.paramByBlock('pow', 'minerReward', 4370000, td), BigInt(3000000000000000000), msg) st.comment('-----------------------------------------------------------------') st.end() @@ -83,8 +91,8 @@ tape('[Common]: Parameter access for param(), paramByHardfork()', function (t: t t.test('EIP param access, paramByEIP()', function (st: tape.Test) { const c = new Common({ chain: Chain.Mainnet }) - let msg = 'Should return null for non-existing value' - st.equal(c.paramByEIP('gasPrices', 'notexistingvalue', 2537), null, msg) + let msg = 'Should return undefined for non-existing value' + st.equals(c.paramByEIP('gasPrices', 'notexistingvalue', 2537), undefined, msg) const UNSUPPORTED_EIP = 1000000 let f = function () { @@ -100,7 +108,7 @@ tape('[Common]: Parameter access for param(), paramByHardfork()', function (t: t st.throws(f, /not defined$/, msg) msg = 'Should return Bls12381G1AddGas gas price for EIP2537' - st.equal(c.paramByEIP('gasPrices', 'Bls12381G1AddGas', 2537), 600, msg) + st.equal(c.paramByEIP('gasPrices', 'Bls12381G1AddGas', 2537), BigInt(600), msg) st.end() }) @@ -108,10 +116,10 @@ tape('[Common]: Parameter access for param(), paramByHardfork()', function (t: t for (const fork of [Hardfork.MuirGlacier, Hardfork.Berlin]) { const c = new Common({ chain: Chain.Mainnet, hardfork: fork }) let delay = c.param('pow', 'difficultyBombDelay') - st.equal(delay, 9000000) + st.equal(delay, BigInt(9000000)) c.setEIPs([3554]) delay = c.param('pow', 'difficultyBombDelay') - st.equal(delay, 9500000) + st.equal(delay, BigInt(9500000)) } st.end() }) diff --git a/packages/tx/src/baseTransaction.ts b/packages/tx/src/baseTransaction.ts index b091686381b..0495b6b378e 100644 --- a/packages/tx/src/baseTransaction.ts +++ b/packages/tx/src/baseTransaction.ts @@ -187,9 +187,12 @@ export abstract class BaseTransaction { * The minimum amount of gas the tx must have (DataFee + TxFee + Creation Fee) */ getBaseFee(): bigint { - let fee = this.getDataFee() + BigInt(this.common.param('gasPrices', 'tx')) + const txFee = this.common.param('gasPrices', 'tx') + let fee = this.getDataFee() + if (txFee) fee += txFee if (this.common.gteHardfork('homestead') && this.toCreationAddress()) { - fee += BigInt(this.common.param('gasPrices', 'txCreation')) + const txCreationFee = this.common.param('gasPrices', 'txCreation') + if (txCreationFee) fee += txCreationFee } return fee } @@ -201,18 +204,18 @@ export abstract class BaseTransaction { const txDataZero = this.common.param('gasPrices', 'txDataZero') const txDataNonZero = this.common.param('gasPrices', 'txDataNonZero') - let cost = 0 + let cost = BigInt(0) for (let i = 0; i < this.data.length; i++) { this.data[i] === 0 ? (cost += txDataZero) : (cost += txDataNonZero) } if ((this.to === undefined || this.to === null) && this.common.isActivatedEIP(3860)) { - const dataLength = Math.ceil(this.data.length / 32) + const dataLength = BigInt(Math.ceil(this.data.length / 32)) const initCodeCost = this.common.param('gasPrices', 'initCodeWordCost') * dataLength cost += initCodeCost } - return BigInt(cost) + return cost } /** diff --git a/packages/tx/src/util.ts b/packages/tx/src/util.ts index 184d25cb5ca..adea93268a2 100644 --- a/packages/tx/src/util.ts +++ b/packages/tx/src/util.ts @@ -3,7 +3,8 @@ import { bufferToHex, setLengthLeft, toBuffer } from 'ethereumjs-util' import { AccessList, AccessListBuffer, AccessListItem, isAccessList } from './types' export function checkMaxInitCodeSize(common: Common, length: number) { - if (length > common.param('vm', 'maxInitCodeSize')) { + const maxInitCodeSize = common.param('vm', 'maxInitCodeSize') + if (maxInitCodeSize && BigInt(length) > maxInitCodeSize) { throw new Error( `the initcode size of this transaction is too large: it is ${length} while the max is ${common.param( 'vm', @@ -108,6 +109,6 @@ export class AccessLists { } const addresses = accessList.length - return addresses * accessListAddressCost + slots * accessListStorageKeyCost + return addresses * Number(accessListAddressCost) + slots * Number(accessListStorageKeyCost) } } diff --git a/packages/tx/test/typedTxsAndEIP2930.spec.ts b/packages/tx/test/typedTxsAndEIP2930.spec.ts index 68faa178013..e389313eb81 100644 --- a/packages/tx/test/typedTxsAndEIP2930.spec.ts +++ b/packages/tx/test/typedTxsAndEIP2930.spec.ts @@ -382,12 +382,14 @@ tape('[AccessListEIP2930Transaction] -> Class Specific Tests', function (t) { ) // Cost should be: // Base fee + 2*TxDataNonZero + TxDataZero + AccessListAddressCost + AccessListSlotCost - const txDataZero: number = common.param('gasPrices', 'txDataZero') - const txDataNonZero: number = common.param('gasPrices', 'txDataNonZero') - const accessListStorageKeyCost: number = common.param('gasPrices', 'accessListStorageKeyCost') - const accessListAddressCost: number = common.param('gasPrices', 'accessListAddressCost') - const baseFee: number = common.param('gasPrices', 'tx') - const creationFee: number = common.param('gasPrices', 'txCreation') + const txDataZero: number = Number(common.param('gasPrices', 'txDataZero')) + const txDataNonZero: number = Number(common.param('gasPrices', 'txDataNonZero')) + const accessListStorageKeyCost: number = Number( + common.param('gasPrices', 'accessListStorageKeyCost') + ) + const accessListAddressCost: number = Number(common.param('gasPrices', 'accessListAddressCost')) + const baseFee: number = Number(common.param('gasPrices', 'tx')) + const creationFee: number = Number(common.param('gasPrices', 'txCreation')) st.ok( tx.getBaseFee() === diff --git a/packages/vm/src/buildBlock.ts b/packages/vm/src/buildBlock.ts index 025c4be4240..7059227ea30 100644 --- a/packages/vm/src/buildBlock.ts +++ b/packages/vm/src/buildBlock.ts @@ -149,7 +149,7 @@ export class BlockBuilder { * Adds the block miner reward to the coinbase account. */ private async rewardMiner() { - const minerReward = BigInt(this.vm._common.param('pow', 'minerReward')) + const minerReward = this.vm._common.param('pow', 'minerReward') const reward = calculateMinerReward(minerReward, 0) const coinbase = this.headerData.coinbase ? new Address(toBuffer(this.headerData.coinbase)) diff --git a/packages/vm/src/evm/eei.ts b/packages/vm/src/evm/eei.ts index e525bac40f5..5c83e3e6d82 100644 --- a/packages/vm/src/evm/eei.ts +++ b/packages/vm/src/evm/eei.ts @@ -436,7 +436,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(BigInt(this._common.param('gasPrices', 'selfdestructRefund'))) + this.refundGas(this._common.param('gasPrices', 'selfdestructRefund')) } this._result.selfdestruct[this._env.address.buf.toString('hex')] = toAddress.buf @@ -581,7 +581,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') || + this._env.depth >= Number(this._common.param('vm', 'stackLimit')) || (msg.delegatecall !== true && this._env.contract.balance < msg.value) ) { return BigInt(0) @@ -640,7 +640,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') || + this._env.depth >= Number(this._common.param('vm', 'stackLimit')) || (msg.delegatecall !== true && this._env.contract.balance < msg.value) ) { return BigInt(0) @@ -655,7 +655,7 @@ export default class EEI { await this._state.putAccount(this._env.address, this._env.contract) if (this._common.isActivatedEIP(3860)) { - if (msg.data.length > this._common.param('vm', 'maxInitCodeSize')) { + if (msg.data.length > Number(this._common.param('vm', 'maxInitCodeSize'))) { return BigInt(0) } } diff --git a/packages/vm/src/evm/evm.ts b/packages/vm/src/evm/evm.ts index 7080d9c59cb..fd472a63dc4 100644 --- a/packages/vm/src/evm/evm.ts +++ b/packages/vm/src/evm/evm.ts @@ -317,7 +317,7 @@ export default class EVM { await this._reduceSenderBalance(account, message) if (this._vm._common.isActivatedEIP(3860)) { - if (message.data.length > this._vm._common.param('vm', 'maxInitCodeSize')) { + if (message.data.length > Number(this._vm._common.param('vm', 'maxInitCodeSize'))) { return { createdAddress: message.to, execResult: { @@ -412,8 +412,7 @@ export default class EVM { let returnFee = BigInt(0) if (!result.exceptionError) { returnFee = - BigInt(result.returnValue.length) * - BigInt(this._vm._common.param('gasPrices', 'createData')) + BigInt(result.returnValue.length) * this._vm._common.param('gasPrices', 'createData') totalGas = totalGas + returnFee if (this._vm.DEBUG) { debugGas(`Add return value size fee (${returnFee} to gas used (-> ${totalGas}))`) @@ -425,7 +424,7 @@ export default class EVM { if ( !result.exceptionError && this._vm._common.gteHardfork(Hardfork.SpuriousDragon) && - result.returnValue.length > this._vm._common.param('vm', 'maxCodeSize') + result.returnValue.length > Number(this._vm._common.param('vm', 'maxCodeSize')) ) { allowedCodeSize = false } diff --git a/packages/vm/src/evm/opcodes/EIP1283.ts b/packages/vm/src/evm/opcodes/EIP1283.ts index 2967f0c9243..d530db9c4ef 100644 --- a/packages/vm/src/evm/opcodes/EIP1283.ts +++ b/packages/vm/src/evm/opcodes/EIP1283.ts @@ -19,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 BigInt(common.param('gasPrices', 'netSstoreNoopGas')) + return 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 BigInt(common.param('gasPrices', 'netSstoreInitGas')) + return common.param('gasPrices', 'netSstoreInitGas') } if (value.length === 0) { // If new value is 0, add 15000 gas to refund counter. runState.eei.refundGas( - BigInt(common.param('gasPrices', 'netSstoreClearRefund')), + common.param('gasPrices', 'netSstoreClearRefund'), 'EIP-1283 -> netSstoreClearRefund' ) } // Otherwise, 5000 gas is deducted. - return BigInt(common.param('gasPrices', 'netSstoreCleanGas')) + return 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) { @@ -44,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( - BigInt(common.param('gasPrices', 'netSstoreClearRefund')), + 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( - BigInt(common.param('gasPrices', 'netSstoreClearRefund')), + common.param('gasPrices', 'netSstoreClearRefund'), 'EIP-1283 -> netSstoreClearRefund' ) } @@ -60,16 +60,16 @@ export function updateSstoreGasEIP1283( if (originalStorage.length === 0) { // If original value is 0, add 19800 gas to refund counter. runState.eei.refundGas( - BigInt(common.param('gasPrices', 'netSstoreResetClearRefund')), + common.param('gasPrices', 'netSstoreResetClearRefund'), 'EIP-1283 -> netSstoreResetClearRefund' ) } else { // Otherwise, add 4800 gas to refund counter. runState.eei.refundGas( - BigInt(common.param('gasPrices', 'netSstoreResetRefund')), + common.param('gasPrices', 'netSstoreResetRefund'), 'EIP-1283 -> netSstoreResetRefund' ) } } - return BigInt(common.param('gasPrices', 'netSstoreDirtyGas')) + return common.param('gasPrices', 'netSstoreDirtyGas') } diff --git a/packages/vm/src/evm/opcodes/EIP2200.ts b/packages/vm/src/evm/opcodes/EIP2200.ts index 59a502eafd0..6aecb0061a2 100644 --- a/packages/vm/src/evm/opcodes/EIP2200.ts +++ b/packages/vm/src/evm/opcodes/EIP2200.ts @@ -22,41 +22,41 @@ export function updateSstoreGasEIP2200( common: Common ) { // Fail if not enough gas is left - if (runState.eei.getGasLeft() <= BigInt(common.param('gasPrices', 'sstoreSentryGasEIP2200'))) { + if (runState.eei.getGasLeft() <= common.param('gasPrices', 'sstoreSentryGasEIP2200')) { trap(ERROR.OUT_OF_GAS) } // Noop if (currentStorage.equals(value)) { - const sstoreNoopCost = BigInt(common.param('gasPrices', 'sstoreNoopGasEIP2200')) + const sstoreNoopCost = common.param('gasPrices', 'sstoreNoopGasEIP2200') return adjustSstoreGasEIP2929(runState, key, sstoreNoopCost, 'noop', common) } if (originalStorage.equals(currentStorage)) { // Create slot if (originalStorage.length === 0) { - return BigInt(common.param('gasPrices', 'sstoreInitGasEIP2200')) + return common.param('gasPrices', 'sstoreInitGasEIP2200') } // Delete slot if (value.length === 0) { runState.eei.refundGas( - BigInt(common.param('gasPrices', 'sstoreClearRefundEIP2200')), + common.param('gasPrices', 'sstoreClearRefundEIP2200'), 'EIP-2200 -> sstoreClearRefundEIP2200' ) } // Write existing slot - return BigInt(common.param('gasPrices', 'sstoreCleanGasEIP2200')) + return common.param('gasPrices', 'sstoreCleanGasEIP2200') } if (originalStorage.length > 0) { if (currentStorage.length === 0) { // Recreate slot runState.eei.subRefund( - BigInt(common.param('gasPrices', 'sstoreClearRefundEIP2200')), + common.param('gasPrices', 'sstoreClearRefundEIP2200'), 'EIP-2200 -> sstoreClearRefundEIP2200' ) } else if (value.length === 0) { // Delete slot runState.eei.refundGas( - BigInt(common.param('gasPrices', 'sstoreClearRefundEIP2200')), + common.param('gasPrices', 'sstoreClearRefundEIP2200'), 'EIP-2200 -> sstoreClearRefundEIP2200' ) } @@ -64,14 +64,14 @@ export function updateSstoreGasEIP2200( if (originalStorage.equals(value)) { if (originalStorage.length === 0) { // Reset to original non-existent slot - const sstoreInitRefund = BigInt(common.param('gasPrices', 'sstoreInitRefundEIP2200')) + const sstoreInitRefund = common.param('gasPrices', 'sstoreInitRefundEIP2200') runState.eei.refundGas( adjustSstoreGasEIP2929(runState, key, sstoreInitRefund, 'initRefund', common), 'EIP-2200 -> initRefund' ) } else { // Reset to original existing slot - const sstoreCleanRefund = BigInt(common.param('gasPrices', 'sstoreCleanRefundEIP2200')) + const sstoreCleanRefund = common.param('gasPrices', 'sstoreCleanRefundEIP2200') runState.eei.refundGas( BigInt(adjustSstoreGasEIP2929(runState, key, sstoreCleanRefund, 'cleanRefund', common)), 'EIP-2200 -> cleanRefund' @@ -79,5 +79,5 @@ export function updateSstoreGasEIP2200( } } // Dirty update - return BigInt(common.param('gasPrices', 'sstoreDirtyGasEIP2200')) + return common.param('gasPrices', 'sstoreDirtyGasEIP2200') } diff --git a/packages/vm/src/evm/opcodes/EIP2929.ts b/packages/vm/src/evm/opcodes/EIP2929.ts index 353dcbe7ca6..57b228a2096 100644 --- a/packages/vm/src/evm/opcodes/EIP2929.ts +++ b/packages/vm/src/evm/opcodes/EIP2929.ts @@ -31,11 +31,11 @@ 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 BigInt(common.param('gasPrices', 'coldaccountaccess')) + return common.param('gasPrices', 'coldaccountaccess') } // Warm: (selfdestruct beneficiary address reads are not charged when warm) } else if (chargeGas && !isSelfdestructOrAuthcall) { - return BigInt(common.param('gasPrices', 'warmstorageread')) + return common.param('gasPrices', 'warmstorageread') } return BigInt(0) } @@ -63,9 +63,9 @@ export function accessStorageEIP2929( // Cold (SLOAD and SSTORE) if (slotIsCold) { vmState.addWarmedStorage(address, key) - return BigInt(common.param('gasPrices', 'coldsload')) + return common.param('gasPrices', 'coldsload') } else if (!isSstore) { - return BigInt(common.param('gasPrices', 'warmstorageread')) + return common.param('gasPrices', 'warmstorageread') } return BigInt(0) } @@ -91,17 +91,17 @@ export function adjustSstoreGasEIP2929( const vmState = runState.vmState const address = runState.eei.getAddress().buf - const warmRead = BigInt(common.param('gasPrices', 'warmstorageread')) - const coldSload = BigInt(common.param('gasPrices', 'coldsload')) + const warmRead = common.param('gasPrices', 'warmstorageread') + const coldSload = common.param('gasPrices', 'coldsload') if (vmState.isWarmedStorage(address, key)) { switch (costName) { case 'noop': return warmRead case 'initRefund': - return BigInt(common.param('gasPrices', 'sstoreInitGasEIP2200')) - warmRead + return common.param('gasPrices', 'sstoreInitGasEIP2200') - warmRead case 'cleanRefund': - return BigInt(common.param('gasPrices', 'sstoreReset')) - coldSload - warmRead + return common.param('gasPrices', 'sstoreReset') - coldSload - warmRead } } diff --git a/packages/vm/src/evm/opcodes/codes.ts b/packages/vm/src/evm/opcodes/codes.ts index 11d9c0d2387..01d1c1c498e 100644 --- a/packages/vm/src/evm/opcodes/codes.ts +++ b/packages/vm/src/evm/opcodes/codes.ts @@ -298,6 +298,7 @@ function createOpcodes(opcodes: OpcodeEntryFee): OpcodeList { const result: OpcodeList = new Map() for (const [key, value] of Object.entries(opcodes)) { const code = parseInt(key, 10) + if (isNaN(value.fee)) value.fee = 0 result.set( code, new Opcode({ @@ -341,12 +342,12 @@ export function getOpcodesForHF(common: Common, customOpcodes?: CustomOpcode[]): } for (const key in opcodeBuilder) { - const baseFee = common.param('gasPrices', opcodeBuilder[key].name.toLowerCase()) + const baseFee = Number(common.param('gasPrices', opcodeBuilder[key].name.toLowerCase())) // explicitly verify that we have defined a base fee if (baseFee === undefined) { throw new Error(`base fee not defined for: ${opcodeBuilder[key].name}`) } - opcodeBuilder[key].fee = common.param('gasPrices', opcodeBuilder[key].name.toLowerCase()) + opcodeBuilder[key].fee = baseFee } if (customOpcodes) { diff --git a/packages/vm/src/evm/opcodes/functions.ts b/packages/vm/src/evm/opcodes/functions.ts index f8b43737503..fe152dd83a6 100644 --- a/packages/vm/src/evm/opcodes/functions.ts +++ b/packages/vm/src/evm/opcodes/functions.ts @@ -179,8 +179,8 @@ export const handlers: Map = new Map([ trap(ERROR.OUT_OF_RANGE) } const gasPrice = common.param('gasPrices', 'expByte') - const amount = byteLength * gasPrice - runState.eei.useGas(BigInt(amount), 'EXP opcode') + const amount = BigInt(byteLength) * gasPrice + runState.eei.useGas(amount, 'EXP opcode') if (base === BigInt(0)) { runState.stack.push(base) diff --git a/packages/vm/src/evm/opcodes/gas.ts b/packages/vm/src/evm/opcodes/gas.ts index a73274d14c3..27d13c84122 100644 --- a/packages/vm/src/evm/opcodes/gas.ts +++ b/packages/vm/src/evm/opcodes/gas.ts @@ -40,7 +40,7 @@ export const dynamicGasHandlers: Map { const [offset, length] = runState.stack.peek(2) gas += subMemUsage(runState, offset, length, common) - gas += BigInt(common.param('gasPrices', 'sha3Word')) * divCeil(length, BigInt(32)) + gas += common.param('gasPrices', 'sha3Word') * divCeil(length, BigInt(32)) return gas }, ], @@ -64,7 +64,7 @@ export const dynamicGasHandlers: Map BigInt(0)) { - gas += BigInt(common.param('gasPrices', 'authcallValueTransfer')) + gas += common.param('gasPrices', 'authcallValueTransfer') const account = await runState.vmState.getAccount(toAddress) if (account.isEmpty()) { - gas += BigInt(common.param('gasPrices', 'callNewAccount')) + gas += common.param('gasPrices', 'callNewAccount') } } @@ -561,7 +561,7 @@ export const dynamicGasHandlers: Map 0 && currentStorage.length > 0) ) { - const gas = BigInt(common.param('gasPrices', 'sstoreReset')) + const gas = common.param('gasPrices', 'sstoreReset') return gas } else if (value.length === 0 && currentStorage.length > 0) { - const gas = BigInt(common.param('gasPrices', 'sstoreReset')) - runState.eei.refundGas(BigInt(common.param('gasPrices', 'sstoreRefund')), 'updateSstoreGas') + const gas = common.param('gasPrices', 'sstoreReset') + runState.eei.refundGas(common.param('gasPrices', 'sstoreRefund'), 'updateSstoreGas') return gas } else { /* @@ -219,7 +219,7 @@ 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 BigInt(common.param('gasPrices', 'sstoreSet')) + return common.param('gasPrices', 'sstoreSet') } } diff --git a/packages/vm/src/evm/precompiles/01-ecrecover.ts b/packages/vm/src/evm/precompiles/01-ecrecover.ts index 8d94ba6698c..1d965b873c5 100644 --- a/packages/vm/src/evm/precompiles/01-ecrecover.ts +++ b/packages/vm/src/evm/precompiles/01-ecrecover.ts @@ -12,7 +12,7 @@ const assert = require('assert') export default function (opts: PrecompileInput): ExecResult { assert(opts.data) - const gasUsed = BigInt(opts._common.param('gasPrices', 'ecRecover')) + const gasUsed = opts._common.param('gasPrices', 'ecRecover') 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 263f5af7b67..888268fae66 100644 --- a/packages/vm/src/evm/precompiles/02-sha256.ts +++ b/packages/vm/src/evm/precompiles/02-sha256.ts @@ -9,9 +9,8 @@ export default function (opts: PrecompileInput): ExecResult { const data = opts.data - let gasUsed = BigInt(opts._common.param('gasPrices', 'sha256')) - gasUsed += - BigInt(opts._common.param('gasPrices', 'sha256Word')) * BigInt(Math.ceil(data.length / 32)) + let gasUsed = opts._common.param('gasPrices', 'sha256') + gasUsed += opts._common.param('gasPrices', 'sha256Word') * BigInt(Math.ceil(data.length / 32)) 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 503820ba5af..f52c7f70646 100644 --- a/packages/vm/src/evm/precompiles/03-ripemd160.ts +++ b/packages/vm/src/evm/precompiles/03-ripemd160.ts @@ -9,9 +9,8 @@ export default function (opts: PrecompileInput): ExecResult { const data = opts.data - let gasUsed = BigInt(opts._common.param('gasPrices', 'ripemd160')) - gasUsed += - BigInt(opts._common.param('gasPrices', 'ripemd160Word')) * BigInt(Math.ceil(data.length / 32)) + let gasUsed = opts._common.param('gasPrices', 'ripemd160') + gasUsed += opts._common.param('gasPrices', 'ripemd160Word') * BigInt(Math.ceil(data.length / 32)) 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 7890e3efca2..0866bbee668 100644 --- a/packages/vm/src/evm/precompiles/04-identity.ts +++ b/packages/vm/src/evm/precompiles/04-identity.ts @@ -7,9 +7,8 @@ export default function (opts: PrecompileInput): ExecResult { const data = opts.data - let gasUsed = BigInt(opts._common.param('gasPrices', 'identity')) - gasUsed += - BigInt(opts._common.param('gasPrices', 'identityWord')) * BigInt(Math.ceil(data.length / 32)) + let gasUsed = opts._common.param('gasPrices', 'identity') + gasUsed += opts._common.param('gasPrices', 'identityWord') * BigInt(Math.ceil(data.length / 32)) 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 e64ab6c3c9a..23b57280202 100644 --- a/packages/vm/src/evm/precompiles/05-modexp.ts +++ b/packages/vm/src/evm/precompiles/05-modexp.ts @@ -92,7 +92,7 @@ export default function (opts: PrecompileInput): ExecResult { if (maxLen < mLen) { maxLen = mLen } - const Gquaddivisor = BigInt(opts._common.param('gasPrices', 'modexpGquaddivisor')) + const Gquaddivisor = opts._common.param('gasPrices', 'modexpGquaddivisor') let gasUsed const bStart = BigInt(96) diff --git a/packages/vm/src/evm/precompiles/06-ecadd.ts b/packages/vm/src/evm/precompiles/06-ecadd.ts index f1046ca5904..5307d503e94 100644 --- a/packages/vm/src/evm/precompiles/06-ecadd.ts +++ b/packages/vm/src/evm/precompiles/06-ecadd.ts @@ -8,7 +8,7 @@ export default function (opts: PrecompileInput): ExecResult { const inputData = opts.data - const gasUsed = BigInt(opts._common.param('gasPrices', 'ecAdd')) + const gasUsed = 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 e436315c638..34033d52061 100644 --- a/packages/vm/src/evm/precompiles/07-ecmul.ts +++ b/packages/vm/src/evm/precompiles/07-ecmul.ts @@ -7,7 +7,7 @@ export default function (opts: PrecompileInput): ExecResult { assert(opts.data) const inputData = opts.data - const gasUsed = BigInt(opts._common.param('gasPrices', 'ecMul')) + const gasUsed = opts._common.param('gasPrices', 'ecMul') 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 f799f67847d..641f494dc02 100644 --- a/packages/vm/src/evm/precompiles/08-ecpairing.ts +++ b/packages/vm/src/evm/precompiles/08-ecpairing.ts @@ -8,11 +8,10 @@ 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 = BigInt( - opts._common.param('gasPrices', 'ecPairing') + - inputDataSize * opts._common.param('gasPrices', 'ecPairingWord') - ) + const inputDataSize = BigInt(Math.floor(inputData.length / 192)) + const gasUsed = + opts._common.param('gasPrices', 'ecPairing') + + inputDataSize * opts._common.param('gasPrices', 'ecPairingWord') 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 3b044b6f5b9..0b13bfb73ad 100644 --- a/packages/vm/src/evm/precompiles/09-blake2f.ts +++ b/packages/vm/src/evm/precompiles/09-blake2f.ts @@ -181,7 +181,7 @@ export default function (opts: PrecompileInput): ExecResult { // final const f = lastByte === 1 - let gasUsed = BigInt(opts._common.param('gasPrices', 'blake2Round')) + let gasUsed = 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 c50230108b9..a69ccb131f3 100644 --- a/packages/vm/src/evm/precompiles/0a-bls12-g1add.ts +++ b/packages/vm/src/evm/precompiles/0a-bls12-g1add.ts @@ -12,7 +12,7 @@ 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 = BigInt(opts._common.paramByEIP('gasPrices', 'Bls12381G1AddGas', 2537)) + const gasUsed = opts._common.paramByEIP('gasPrices', 'Bls12381G1AddGas', 2537) ?? BigInt(0) 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 7e2c445a08c..619729840df 100644 --- a/packages/vm/src/evm/precompiles/0b-bls12-g1mul.ts +++ b/packages/vm/src/evm/precompiles/0b-bls12-g1mul.ts @@ -16,7 +16,7 @@ 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 = BigInt(opts._common.paramByEIP('gasPrices', 'Bls12381G1MulGas', 2537)) + const gasUsed = opts._common.paramByEIP('gasPrices', 'Bls12381G1MulGas', 2537) ?? BigInt(0) 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 6f2cb1225a4..1c217bdbbda 100644 --- a/packages/vm/src/evm/precompiles/0c-bls12-g1multiexp.ts +++ b/packages/vm/src/evm/precompiles/0c-bls12-g1multiexp.ts @@ -21,8 +21,12 @@ export default async function (opts: PrecompileInput): Promise { const numPairs = Math.floor(inputData.length / 160) - const gasUsedPerPair = BigInt(opts._common.paramByEIP('gasPrices', 'Bls12381G1MulGas', 2537)) - const gasDiscountArray = opts._common.paramByEIP('gasPrices', 'Bls12381MultiExpGasDiscount', 2537) + const gasUsedPerPair = opts._common.paramByEIP('gasPrices', 'Bls12381G1MulGas', 2537) ?? BigInt(0) + const gasDiscountArray = opts._common.paramByEIP( + 'gasPrices', + 'Bls12381MultiExpGasDiscount', + 2537 + ) as any const gasDiscountMax = gasDiscountArray[gasDiscountArray.length - 1][1] let gasDiscountMultiplier diff --git a/packages/vm/src/evm/precompiles/0d-bls12-g2add.ts b/packages/vm/src/evm/precompiles/0d-bls12-g2add.ts index 3bd46c77e81..8b1f5811530 100644 --- a/packages/vm/src/evm/precompiles/0d-bls12-g2add.ts +++ b/packages/vm/src/evm/precompiles/0d-bls12-g2add.ts @@ -12,7 +12,7 @@ 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 = BigInt(opts._common.paramByEIP('gasPrices', 'Bls12381G2AddGas', 2537)) + const gasUsed = opts._common.paramByEIP('gasPrices', 'Bls12381G2AddGas', 2537) ?? BigInt(0) 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 0eb10e0ad53..1e0aa4414fd 100644 --- a/packages/vm/src/evm/precompiles/0e-bls12-g2mul.ts +++ b/packages/vm/src/evm/precompiles/0e-bls12-g2mul.ts @@ -16,7 +16,7 @@ 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 = BigInt(opts._common.paramByEIP('gasPrices', 'Bls12381G2MulGas', 2537)) + const gasUsed = opts._common.paramByEIP('gasPrices', 'Bls12381G2MulGas', 2537) ?? BigInt(0) 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 79d3a762ad5..3d07e27752a 100644 --- a/packages/vm/src/evm/precompiles/0f-bls12-g2multiexp.ts +++ b/packages/vm/src/evm/precompiles/0f-bls12-g2multiexp.ts @@ -1,6 +1,7 @@ import { PrecompileInput } from './types' import { VmErrorResult, ExecResult, OOGResult } from '../evm' import { ERROR, VmError } from '../../exceptions' +import { gasDiscountPairs } from './util/bls12_381' const assert = require('assert') const { BLS12_381_ToG2Point, @@ -21,8 +22,8 @@ export default async function (opts: PrecompileInput): Promise { const numPairs = Math.floor(inputData.length / 288) - const gasUsedPerPair = BigInt(opts._common.paramByEIP('gasPrices', 'Bls12381G2MulGas', 2537)) - const gasDiscountArray = opts._common.paramByEIP('gasPrices', 'Bls12381MultiExpGasDiscount', 2537) + const gasUsedPerPair = opts._common.paramByEIP('gasPrices', 'Bls12381G2MulGas', 2537) ?? BigInt(0) + const gasDiscountArray = gasDiscountPairs const gasDiscountMax = gasDiscountArray[gasDiscountArray.length - 1][1] let gasDiscountMultiplier diff --git a/packages/vm/src/evm/precompiles/10-bls12-pairing.ts b/packages/vm/src/evm/precompiles/10-bls12-pairing.ts index 0a516dca389..7488af2eb9b 100644 --- a/packages/vm/src/evm/precompiles/10-bls12-pairing.ts +++ b/packages/vm/src/evm/precompiles/10-bls12-pairing.ts @@ -14,15 +14,15 @@ export default async function (opts: PrecompileInput): Promise { const inputData = opts.data - const baseGas = BigInt(opts._common.paramByEIP('gasPrices', 'Bls12381PairingBaseGas', 2537)) + const baseGas = opts._common.paramByEIP('gasPrices', 'Bls12381PairingBaseGas', 2537) ?? BigInt(0) if (inputData.length == 0) { return VmErrorResult(new VmError(ERROR.BLS_12_381_INPUT_EMPTY), opts.gasLimit) } - const gasUsedPerPair = BigInt( - opts._common.paramByEIP('gasPrices', 'Bls12381PairingPerPairGas', 2537) - ) + const gasUsedPerPair = + opts._common.paramByEIP('gasPrices', 'Bls12381PairingPerPairGas', 2537) ?? BigInt(0) + const gasUsed = baseGas + gasUsedPerPair * BigInt(Math.floor(inputData.length / 384)) if (inputData.length % 384 != 0) { 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 ab30545c853..b069643c210 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 @@ -12,7 +12,7 @@ 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 = BigInt(opts._common.paramByEIP('gasPrices', 'Bls12381MapG1Gas', 2537)) + const gasUsed = opts._common.paramByEIP('gasPrices', 'Bls12381MapG1Gas', 2537) ?? BigInt(0) 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 01748b6ae87..e321eb6c26e 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 @@ -12,7 +12,7 @@ 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 = BigInt(opts._common.paramByEIP('gasPrices', 'Bls12381MapG2Gas', 2537)) + const gasUsed = opts._common.paramByEIP('gasPrices', 'Bls12381MapG2Gas', 2537) ?? BigInt(0) if (opts.gasLimit < gasUsed) { return OOGResult(opts.gasLimit) diff --git a/packages/vm/src/evm/precompiles/util/bls12_381.ts b/packages/vm/src/evm/precompiles/util/bls12_381.ts index a9d5dbdc81d..c67daf25796 100644 --- a/packages/vm/src/evm/precompiles/util/bls12_381.ts +++ b/packages/vm/src/evm/precompiles/util/bls12_381.ts @@ -6,6 +6,137 @@ const fieldModulus = BigInt( '0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab' ) +// gas discount pairs taken from EIP-2537 `Bls12381MultiExpGasDiscount` parameter +export const gasDiscountPairs = [ + [1, 1200], + [2, 888], + [3, 764], + [4, 641], + [5, 594], + [6, 547], + [7, 500], + [8, 453], + [9, 438], + [10, 423], + [11, 408], + [12, 394], + [13, 379], + [14, 364], + [15, 349], + [16, 334], + [17, 330], + [18, 326], + [19, 322], + [20, 318], + [21, 314], + [22, 310], + [23, 306], + [24, 302], + [25, 298], + [26, 294], + [27, 289], + [28, 285], + [29, 281], + [30, 277], + [31, 273], + [32, 269], + [33, 268], + [34, 266], + [35, 265], + [36, 263], + [37, 262], + [38, 260], + [39, 259], + [40, 257], + [41, 256], + [42, 254], + [43, 253], + [44, 251], + [45, 250], + [46, 248], + [47, 247], + [48, 245], + [49, 244], + [50, 242], + [51, 241], + [52, 239], + [53, 238], + [54, 236], + [55, 235], + [56, 233], + [57, 232], + [58, 231], + [59, 229], + [60, 228], + [61, 226], + [62, 225], + [63, 223], + [64, 222], + [65, 221], + [66, 220], + [67, 219], + [68, 219], + [69, 218], + [70, 217], + [71, 216], + [72, 216], + [73, 215], + [74, 214], + [75, 213], + [76, 213], + [77, 212], + [78, 211], + [79, 211], + [80, 210], + [81, 209], + [82, 208], + [83, 208], + [84, 207], + [85, 206], + [86, 205], + [87, 205], + [88, 204], + [89, 203], + [90, 202], + [91, 202], + [92, 201], + [93, 200], + [94, 199], + [95, 199], + [96, 198], + [97, 197], + [98, 196], + [99, 196], + [100, 195], + [101, 194], + [102, 193], + [103, 193], + [104, 192], + [105, 191], + [106, 191], + [107, 190], + [108, 189], + [109, 188], + [110, 188], + [111, 187], + [112, 186], + [113, 185], + [114, 185], + [115, 184], + [116, 183], + [117, 182], + [118, 182], + [119, 181], + [120, 180], + [121, 179], + [122, 179], + [123, 178], + [124, 177], + [125, 176], + [126, 176], + [127, 175], + [128, 174], +] // convert an input Buffer to a mcl G1 point // this does /NOT/ do any input checks. the input Buffer needs to be of length 128 // it does raise an error if the point is not on the curve. diff --git a/packages/vm/src/runBlock.ts b/packages/vm/src/runBlock.ts index c2490f6d9ac..0cbc330f88c 100644 --- a/packages/vm/src/runBlock.ts +++ b/packages/vm/src/runBlock.ts @@ -320,8 +320,7 @@ async function applyTransactions(this: VM, block: Block, opts: RunBlockOpts) { let maxGasLimit if (this._common.isActivatedEIP(1559)) { - maxGasLimit = - block.header.gasLimit * BigInt(this._common.param('gasConfig', 'elasticityMultiplier')) + maxGasLimit = block.header.gasLimit * this._common.param('gasConfig', 'elasticityMultiplier') } else { maxGasLimit = block.header.gasLimit } @@ -379,7 +378,7 @@ async function assignBlockRewards(this: VM, block: Block): Promise { debug(`Assign block rewards`) } const state = this.vmState - const minerReward = BigInt(this._common.param('pow', 'minerReward')) + const minerReward = this._common.param('pow', 'minerReward') const ommers = block.uncleHeaders // Reward ommers for (const ommer of ommers) { diff --git a/packages/vm/src/runTx.ts b/packages/vm/src/runTx.ts index e529aaaf496..b77d287bf9f 100644 --- a/packages/vm/src/runTx.ts +++ b/packages/vm/src/runTx.ts @@ -439,7 +439,7 @@ async function _runTx(this: VM, opts: RunTxOpts): Promise { // Process any gas refund let gasRefund = results.gasRefund ?? BigInt(0) - const maxRefundQuotient = BigInt(this._common.param('gasConfig', 'maxRefundQuotient')) + const maxRefundQuotient = this._common.param('gasConfig', 'maxRefundQuotient') if (gasRefund !== BigInt(0)) { const maxRefund = results.gasUsed / maxRefundQuotient gasRefund = gasRefund < maxRefund ? gasRefund : maxRefund diff --git a/packages/vm/tests/api/EIPs/eip-2929.spec.ts b/packages/vm/tests/api/EIPs/eip-2929.spec.ts index 5e7067d5290..06c4dfc95dd 100644 --- a/packages/vm/tests/api/EIPs/eip-2929.spec.ts +++ b/packages/vm/tests/api/EIPs/eip-2929.spec.ts @@ -41,7 +41,7 @@ tape('EIP 2929: gas cost tests', (t) => { gasUsed === expectedGasUsed, `Opcode: ${ test.steps[i - 1].expectedOpcode - }, Gase Used: ${gasUsed}, Expected: ${expectedGasUsed}` + }, Gas Used: ${gasUsed}, Expected: ${expectedGasUsed}` ) } } @@ -258,7 +258,7 @@ tape('EIP 2929: gas cost tests', (t) => { st.end() }) - tape('ensure warm addresses/slots are tracked transaction-wide', async (t) => { + t.test('ensure warm addresses/slots are tracked transaction-wide', async (st) => { // Note: these tests were manually analyzed to check if these are correct. // The gas cost has been taken from these tests. @@ -272,21 +272,21 @@ tape('EIP 2929: gas cost tests', (t) => { // SLOAD or CALL operations. // load same storage slot twice (also in inner call) - await runCodeTest('60005460003415601357600080808080305AF15B00', BigInt(23369), t) + await runCodeTest('60005460003415601357600080808080305AF15B00', BigInt(23369), st) // call to contract, load slot 0, revert inner call. load slot 0 in outer call. - await runCodeTest('341515600D57600054600080FD5B600080808080305AF160005400', BigInt(25374), t) + await runCodeTest('341515600D57600054600080FD5B600080808080305AF160005400', BigInt(25374), st) // 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', BigInt(23909), t) + await runCodeTest(callFF + '60003415601B57600080808080305AF15B00', BigInt(23909), st) // call to contract, call 0xFF..FF, revert, call 0xFF..FF (should be cold) await runCodeTest( '341515601557' + callFF + '600080FD5B600080808080305AF1' + callFF + '00', BigInt(26414), - t + st ) - t.end() + st.end() }) }) diff --git a/packages/vm/tests/api/EIPs/eip-3074-authcall.spec.ts b/packages/vm/tests/api/EIPs/eip-3074-authcall.spec.ts index f027d4feb66..4c004895b97 100644 --- a/packages/vm/tests/api/EIPs/eip-3074-authcall.spec.ts +++ b/packages/vm/tests/api/EIPs/eip-3074-authcall.spec.ts @@ -348,8 +348,8 @@ tape('EIP-3074 AUTHCALL', (t) => { const gasBigInt = bufferToBigInt(gasUsed) const preGas = gas! - - BigInt(common.param('gasPrices', 'warmstorageread')) - - BigInt(common.param('gasPrices', 'coldaccountaccess')) + common.param('gasPrices', 'warmstorageread')! - + common.param('gasPrices', 'coldaccountaccess')! const expected = preGas - preGas / 64n - 2n st.equal(gasBigInt, expected, 'forwarded max call gas') }) @@ -390,7 +390,7 @@ tape('EIP-3074 AUTHCALL', (t) => { Buffer.from('00'.repeat(31) + '01', 'hex') ) const gasBigInt = bufferToBigInt(gasUsed) - const preGas = gas! - BigInt(common.param('gasPrices', 'warmstorageread')) + const preGas = gas! - common.param('gasPrices', 'warmstorageread')! const expected = preGas - preGas / 64n - 2n st.equal(gasBigInt, expected, 'forwarded max call gas') }) @@ -433,10 +433,10 @@ tape('EIP-3074 AUTHCALL', (t) => { const gasBigInt = gas! - gasAfterCall! const expected = - BigInt(common.param('gasPrices', 'coldaccountaccess')) + - BigInt(common.param('gasPrices', 'warmstorageread')) + - BigInt(common.param('gasPrices', 'callNewAccount')) + - BigInt(common.param('gasPrices', 'authcallValueTransfer')) + common.param('gasPrices', 'coldaccountaccess')! + + common.param('gasPrices', 'warmstorageread')! + + common.param('gasPrices', 'callNewAccount')! + + common.param('gasPrices', 'authcallValueTransfer')! st.equal(gasBigInt, expected, 'forwarded max call gas') } @@ -484,9 +484,9 @@ tape('EIP-3074 AUTHCALL', (t) => { const gasBigInt = bufferToBigInt(gasUsed) const preGas = gas! - - BigInt(common.param('gasPrices', 'warmstorageread')) - - BigInt(common.param('gasPrices', 'authcallValueTransfer')) - - BigInt(common.param('gasPrices', 'coldaccountaccess')) + common.param('gasPrices', 'warmstorageread')! - + common.param('gasPrices', 'authcallValueTransfer')! - + common.param('gasPrices', 'coldaccountaccess')! const expected = preGas - preGas / 64n - 2n st.equal(gasBigInt, expected, 'forwarded max call gas') diff --git a/packages/vm/tests/api/EIPs/eip-3651-warm-coinbase.spec.ts b/packages/vm/tests/api/EIPs/eip-3651-warm-coinbase.spec.ts index c442ca37db4..785744f0a10 100644 --- a/packages/vm/tests/api/EIPs/eip-3651-warm-coinbase.spec.ts +++ b/packages/vm/tests/api/EIPs/eip-3651-warm-coinbase.spec.ts @@ -65,8 +65,8 @@ tape('EIP 3651 tests', (t) => { const result2 = await vm2.runTx({ block, tx }) const expectedDiff = - BigInt(common.param('gasPrices', 'coldaccountaccess')) - - BigInt(common.param('gasPrices', 'warmstorageread')) + common.param('gasPrices', 'coldaccountaccess')! - + common.param('gasPrices', 'warmstorageread')! st.equal(result2.gasUsed - result.gasUsed, expectedDiff, 'gas difference is correct') }) }) diff --git a/packages/vm/tests/api/EIPs/eip-3855.spec.ts b/packages/vm/tests/api/EIPs/eip-3855.spec.ts index b493f86a4c7..7bc71823dc6 100644 --- a/packages/vm/tests/api/EIPs/eip-3855.spec.ts +++ b/packages/vm/tests/api/EIPs/eip-3855.spec.ts @@ -30,7 +30,7 @@ tape('EIP 3541 tests', (t) => { st.ok(stack!.length == 1) st.equal(stack![0], BigInt(0)) - st.equal(result.gasUsed, BigInt(common.param('gasPrices', 'push0'))) + st.equal(result.gasUsed, common.param('gasPrices', 'push0')) st.end() }) @@ -42,7 +42,7 @@ tape('EIP 3541 tests', (t) => { stack = e.stack }) - const depth = common.param('vm', 'stackLimit') + const depth = Number(common.param('vm', 'stackLimit')) const result = await vm.runCode({ code: Buffer.from('5F'.repeat(depth), 'hex'), @@ -55,14 +55,14 @@ tape('EIP 3541 tests', (t) => { st.fail('stack element is not 0') } }) - st.equal(result.gasUsed, BigInt(common.param('gasPrices', 'push0') * depth)) + st.equal(result.gasUsed, common.param('gasPrices', 'push0')! * BigInt(depth)) st.end() }) t.test('should correctly use push0 to create a stack with stack limit + 1 length', async (st) => { const vm = await VM.create({ common }) - const depth = common.param('vm', 'stackLimit') + 1 + const depth = Number(common.param('vm', 'stackLimit')!) + 1 const result = await vm.runCode({ code: Buffer.from('5F'.repeat(depth), 'hex'), diff --git a/packages/vm/tests/api/index.spec.ts b/packages/vm/tests/api/index.spec.ts index a8ee2ff7db8..902ecfdd29c 100644 --- a/packages/vm/tests/api/index.spec.ts +++ b/packages/vm/tests/api/index.spec.ts @@ -98,7 +98,10 @@ tape('VM -> common (chain, HFs, EIPs)', (t) => { t.test('should only accept valid chain and fork', async (st) => { let common = new Common({ chain: Chain.Ropsten, hardfork: Hardfork.Byzantium }) let vm = await VM.create({ common }) - st.equal((vm.stateManager as DefaultStateManager)._common.param('gasPrices', 'ecAdd'), 500) + st.equal( + (vm.stateManager as DefaultStateManager)._common.param('gasPrices', 'ecAdd'), + BigInt(500) + ) try { common = new Common({ chain: 'mainchain', hardfork: Hardfork.Homestead }) diff --git a/packages/vm/tests/api/runCall.spec.ts b/packages/vm/tests/api/runCall.spec.ts index 3425f557dec..8105ee57c83 100644 --- a/packages/vm/tests/api/runCall.spec.ts +++ b/packages/vm/tests/api/runCall.spec.ts @@ -169,7 +169,7 @@ tape('Ensure that precompile activation creates non-empty accounts', async (t) = const resultActivated = await vmActivated.runCall(runCallArgs) const diff = resultNotActivated.execResult.gasUsed - resultActivated.execResult.gasUsed - const expected = BigInt(common.param('gasPrices', 'callNewAccount')) + const expected = common.param('gasPrices', 'callNewAccount') t.equal(diff, expected, 'precompiles are activated')