From 51e5582ed8eced3255541905cf0a320c5f6e982a Mon Sep 17 00:00:00 2001 From: Jochem Brouwer Date: Fri, 27 May 2022 16:15:47 +0200 Subject: [PATCH] vm/evm: ensure exp dynamic gas calculated in gas.ts not functions.ts --- packages/vm/src/evm/evm.ts | 2 +- packages/vm/src/evm/opcodes/codes.ts | 2 +- packages/vm/src/evm/opcodes/functions.ts | 12 +----------- packages/vm/src/evm/opcodes/gas.ts | 20 ++++++++++++++++++++ 4 files changed, 23 insertions(+), 13 deletions(-) diff --git a/packages/vm/src/evm/evm.ts b/packages/vm/src/evm/evm.ts index c8b0b2f7b6..c0362e44a4 100644 --- a/packages/vm/src/evm/evm.ts +++ b/packages/vm/src/evm/evm.ts @@ -165,7 +165,7 @@ export interface ExecResult { /** * Amount of gas the code used to run */ - gasUsed: bigint + gasUsed: bigint //TODO misleading; does not cover upfront cost (does it cover callvalue?) /** * Return value from the contract */ diff --git a/packages/vm/src/evm/opcodes/codes.ts b/packages/vm/src/evm/opcodes/codes.ts index 01d1c1c498..d1274d244c 100644 --- a/packages/vm/src/evm/opcodes/codes.ts +++ b/packages/vm/src/evm/opcodes/codes.ts @@ -57,7 +57,7 @@ const opcodes: OpcodeEntry = { 0x07: { name: 'SMOD', isAsync: false, dynamicGas: false }, 0x08: { name: 'ADDMOD', isAsync: false, dynamicGas: false }, 0x09: { name: 'MULMOD', isAsync: false, dynamicGas: false }, - 0x0a: { name: 'EXP', isAsync: false, dynamicGas: false }, + 0x0a: { name: 'EXP', isAsync: false, dynamicGas: true }, 0x0b: { name: 'SIGNEXTEND', isAsync: false, dynamicGas: false }, // 0x10 range - bit ops diff --git a/packages/vm/src/evm/opcodes/functions.ts b/packages/vm/src/evm/opcodes/functions.ts index 22b775a0ba..1287940834 100644 --- a/packages/vm/src/evm/opcodes/functions.ts +++ b/packages/vm/src/evm/opcodes/functions.ts @@ -164,22 +164,12 @@ export const handlers: Map = new Map([ // 0x0a: EXP [ 0x0a, - function (runState, common) { + function (runState) { const [base, exponent] = runState.stack.popN(2) if (exponent === BigInt(0)) { runState.stack.push(BigInt(1)) return } - 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) - } - const gasPrice = common.param('gasPrices', 'expByte') - const amount = BigInt(byteLength) * gasPrice - runState.interpreter.useGas(amount, 'EXP opcode') // TODO Why is this not in gas.ts?? 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 0c6c5ea263..5fdb5120e1 100644 --- a/packages/vm/src/evm/opcodes/gas.ts +++ b/packages/vm/src/evm/opcodes/gas.ts @@ -34,6 +34,26 @@ export interface SyncDynamicGasHandler { export const dynamicGasHandlers: Map = new Map([ + [ + /* EXP */ + 0x0a, + async function (runState, gas, common): Promise { + const [_base, exponent] = runState.stack.peek(2) + if (exponent === BigInt(0)) { + return gas + } + 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) + } + const expPricePerByte = common.param('gasPrices', 'expByte') + gas += BigInt(byteLength) * expPricePerByte + return gas + }, + ], [ /* SHA3 */ 0x20,