From 2bef38c9ee90690470295f1646edd416a87c8e66 Mon Sep 17 00:00:00 2001 From: Jochem Brouwer Date: Fri, 3 Jul 2020 22:58:20 +0200 Subject: [PATCH] [VM/Common] move gas base fees to Common [VM] remove unneeded opcode entries which only introduced gas changes [VM/Common] Add right fork base fees, remove STATICCALL from base opcodes [Common] remove STATICCALL from chainstart --- packages/common/src/hardforks/byzantium.json | 16 + packages/common/src/hardforks/chainstart.json | 266 ++++++++++++++- .../common/src/hardforks/constantinople.json | 20 ++ packages/common/src/hardforks/homestead.json | 7 +- packages/common/src/hardforks/istanbul.json | 20 ++ .../src/hardforks/tangerineWhistle.json | 24 ++ packages/vm/lib/evm/opFns.ts | 36 -- packages/vm/lib/evm/opcodes.ts | 323 +++++++++--------- 8 files changed, 499 insertions(+), 213 deletions(-) diff --git a/packages/common/src/hardforks/byzantium.json b/packages/common/src/hardforks/byzantium.json index 2ed7dd0fab..78e60a9d0b 100644 --- a/packages/common/src/hardforks/byzantium.json +++ b/packages/common/src/hardforks/byzantium.json @@ -26,6 +26,22 @@ "ecPairingWord": { "v": 80000, "d": "Gas costs regarding curve pairing precompile input length" + }, + "revert": { + "v": 0, + "d": "Base fee of the REVERT opcode" + }, + "staticcall": { + "v": 700, + "d": "Base fee of the STATICCALL opcode" + }, + "returndatasize": { + "v": 2, + "d": "Base fee of the RETURNDATASIZE opcode" + }, + "returndatacopy": { + "v": 3, + "d": "Base fee of the RETURNDATACOPY opcode" } }, "vm": {}, diff --git a/packages/common/src/hardforks/chainstart.json b/packages/common/src/hardforks/chainstart.json index 777761e148..a1b70e3b2d 100644 --- a/packages/common/src/hardforks/chainstart.json +++ b/packages/common/src/hardforks/chainstart.json @@ -22,21 +22,28 @@ "d": "Gas base cost, used e.g. for ChainID opcode (Istanbul)" }, "tierStep": { - "v": [0, 2, 3, 5, 8, 10, 20], + "v": [ + 0, + 2, + 3, + 5, + 8, + 10, + 20 + ], "d": "Once per operation, for a selection of them" }, "exp": { "v": 10, - "d": "Once per EXP instuction" + "d": "Base fee of the EXP opcode" }, "expByte": { "v": 10, "d": "Times ceil(log256(exponent)) for the EXP instruction" }, - "sha3": { "v": 30, - "d": "Once per SHA3 operation" + "d": "Base fee of the SHA3 opcode" }, "sha3Word": { "v": 6, @@ -44,7 +51,7 @@ }, "sload": { "v": 50, - "d": "Once per SLOAD operation" + "d": "Base fee of the SLOAD opcode" }, "sstoreSet": { "v": 20000, @@ -60,12 +67,11 @@ }, "jumpdest": { "v": 1, - "d": "Refunded gas, once per SSTORE operation if the zeroness changes to zero" + "d": "Base fee of the JUMPDEST opcode" }, - "log": { "v": 375, - "d": "Per LOG* operation" + "d": "Base fee of the LOG opcode" }, "logData": { "v": 8, @@ -75,15 +81,13 @@ "v": 375, "d": "Multiplied by the * of the LOG*, per LOG transaction. e.g. LOG0 incurs 0 * c_txLogTopicGas, LOG4 incurs 4 * c_txLogTopicGas" }, - "create": { "v": 32000, - "d": "Once per CREATE operation & contract-creation transaction" + "d": "Base fee of the CREATE opcode" }, - "call": { "v": 40, - "d": "Once per CALL operation & message call transaction" + "d": "Base fee of the CALL opcode" }, "callStipend": { "v": 2300, @@ -97,12 +101,10 @@ "v": 25000, "d": "Paid for CALL when the destination address didn't exist prior" }, - "selfdestructRefund": { "v": 24000, "d": "Refunded following a selfdestruct operation" }, - "memory": { "v": 3, "d": "Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL" @@ -111,7 +113,6 @@ "v": 512, "d": "Divisor for the quadratic particle of the memory cost equation" }, - "createData": { "v": 200, "d": "" @@ -132,7 +133,6 @@ "v": 68, "d": "Per byte of data attached to a transaction that is not equal to zero. NOTE: Not payable on data of calls between transactions" }, - "copy": { "v": 3, "d": "Multiplied by the number of 32-byte words that are copied (round up) for any *COPY operation and added" @@ -164,6 +164,238 @@ "identityWord": { "v": 3, "d": "" + }, + "stop": { + "v": 0, + "d": "Base fee of the STOP opcode" + }, + "add": { + "v": 3, + "d": "Base fee of the ADD opcode" + }, + "mul": { + "v": 5, + "d": "Base fee of the MUL opcode" + }, + "sub": { + "v": 3, + "d": "Base fee of the SUB opcode" + }, + "div": { + "v": 5, + "d": "Base fee of the DIV opcode" + }, + "sdiv": { + "v": 5, + "d": "Base fee of the SDIV opcode" + }, + "mod": { + "v": 5, + "d": "Base fee of the MOD opcode" + }, + "smod": { + "v": 5, + "d": "Base fee of the SMOD opcode" + }, + "addmod": { + "v": 8, + "d": "Base fee of the ADDMOD opcode" + }, + "mulmod": { + "v": 8, + "d": "Base fee of the MULMOD opcode" + }, + "signextend": { + "v": 5, + "d": "Base fee of the SIGNEXTEND opcode" + }, + "lt": { + "v": 3, + "d": "Base fee of the LT opcode" + }, + "gt": { + "v": 3, + "d": "Base fee of the GT opcode" + }, + "slt": { + "v": 3, + "d": "Base fee of the SLT opcode" + }, + "sgt": { + "v": 3, + "d": "Base fee of the SGT opcode" + }, + "eq": { + "v": 3, + "d": "Base fee of the EQ opcode" + }, + "iszero": { + "v": 3, + "d": "Base fee of the ISZERO opcode" + }, + "and": { + "v": 3, + "d": "Base fee of the AND opcode" + }, + "or": { + "v": 3, + "d": "Base fee of the OR opcode" + }, + "xor": { + "v": 3, + "d": "Base fee of the XOR opcode" + }, + "not": { + "v": 3, + "d": "Base fee of the NOT opcode" + }, + "byte": { + "v": 3, + "d": "Base fee of the BYTE opcode" + }, + "address": { + "v": 2, + "d": "Base fee of the ADDRESS opcode" + }, + "balance": { + "v": 20, + "d": "Base fee of the BALANCE opcode" + }, + "origin": { + "v": 2, + "d": "Base fee of the ORIGIN opcode" + }, + "caller": { + "v": 2, + "d": "Base fee of the CALLER opcode" + }, + "callvalue": { + "v": 2, + "d": "Base fee of the CALLVALUE opcode" + }, + "calldataload": { + "v": 3, + "d": "Base fee of the CALLDATALOAD opcode" + }, + "calldatasize": { + "v": 2, + "d": "Base fee of the CALLDATASIZE opcode" + }, + "calldatacopy": { + "v": 3, + "d": "Base fee of the CALLDATACOPY opcode" + }, + "codesize": { + "v": 2, + "d": "Base fee of the CODESIZE opcode" + }, + "codecopy": { + "v": 3, + "d": "Base fee of the CODECOPY opcode" + }, + "gasprice": { + "v": 2, + "d": "Base fee of the GASPRICE opcode" + }, + "extcodesize": { + "v": 20, + "d": "Base fee of the EXTCODESIZE opcode" + }, + "extcodecopy": { + "v": 20, + "d": "Base fee of the EXTCODECOPY opcode" + }, + "blockhash": { + "v": 20, + "d": "Base fee of the BLOCKHASH opcode" + }, + "coinbase": { + "v": 2, + "d": "Base fee of the COINBASE opcode" + }, + "timestamp": { + "v": 2, + "d": "Base fee of the TIMESTAMP opcode" + }, + "number": { + "v": 2, + "d": "Base fee of the NUMBER opcode" + }, + "difficulty": { + "v": 2, + "d": "Base fee of the DIFFICULTY opcode" + }, + "gaslimit": { + "v": 2, + "d": "Base fee of the GASLIMIT opcode" + }, + "pop": { + "v": 2, + "d": "Base fee of the POP opcode" + }, + "mload": { + "v": 3, + "d": "Base fee of the MLOAD opcode" + }, + "mstore": { + "v": 3, + "d": "Base fee of the MSTORE opcode" + }, + "mstore8": { + "v": 3, + "d": "Base fee of the MSTORE8 opcode" + }, + "sstore": { + "v": 0, + "d": "Base fee of the SSTORE opcode" + }, + "jump": { + "v": 8, + "d": "Base fee of the JUMP opcode" + }, + "jumpi": { + "v": 10, + "d": "Base fee of the JUMPI opcode" + }, + "pc": { + "v": 2, + "d": "Base fee of the PC opcode" + }, + "msize": { + "v": 2, + "d": "Base fee of the MSIZE opcode" + }, + "gas": { + "v": 2, + "d": "Base fee of the GAS opcode" + }, + "push": { + "v": 3, + "d": "Base fee of the PUSH opcode" + }, + "dup": { + "v": 3, + "d": "Base fee of the DUP opcode" + }, + "swap": { + "v": 3, + "d": "Base fee of the SWAP opcode" + }, + "callcode": { + "v": 40, + "d": "Base fee of the CALLCODE opcode" + }, + "return": { + "v": 0, + "d": "Base fee of the RETURN opcode" + }, + "invalid": { + "v": 0, + "d": "Base fee of the INVALID opcode" + }, + "selfdestruct": { + "v": 0, + "d": "Base fee of the SELFDESTRUCT opcode" } }, "vm": { @@ -206,4 +438,4 @@ "d": "the amount a miner get rewarded for mining a block" } } -} +} \ No newline at end of file diff --git a/packages/common/src/hardforks/constantinople.json b/packages/common/src/hardforks/constantinople.json index 7c3048ba5c..237ac722a8 100644 --- a/packages/common/src/hardforks/constantinople.json +++ b/packages/common/src/hardforks/constantinople.json @@ -34,6 +34,26 @@ "netSstoreResetClearRefund": { "v": 19800, "d": "Once per SSTORE operation for resetting to the original zero value" + }, + "shl": { + "v": 3, + "d": "Base fee of the SHL opcode" + }, + "shr": { + "v": 3, + "d": "Base fee of the SHR opcode" + }, + "sar": { + "v": 3, + "d": "Base fee of the SAR opcode" + }, + "extcodehash": { + "v": 400, + "d": "Base fee of the EXTCODEHASH opcode" + }, + "create2": { + "v": 32000, + "d": "Base fee of the CREATE2 opcode" } }, "vm": {}, diff --git a/packages/common/src/hardforks/homestead.json b/packages/common/src/hardforks/homestead.json index e314f8447e..09a26145a2 100644 --- a/packages/common/src/hardforks/homestead.json +++ b/packages/common/src/hardforks/homestead.json @@ -6,7 +6,12 @@ "status": "Final" }, "gasConfig": {}, - "gasPrices": {}, + "gasPrices": { + "delegatecall": { + "v": 40, + "d": "Base fee of the DELEGATECALL opcode" + } + }, "vm": {}, "pow": {} } diff --git a/packages/common/src/hardforks/istanbul.json b/packages/common/src/hardforks/istanbul.json index 8dc6facdca..2ffc86f928 100644 --- a/packages/common/src/hardforks/istanbul.json +++ b/packages/common/src/hardforks/istanbul.json @@ -62,6 +62,26 @@ "sstoreClearRefundEIP2200": { "v": 15000, "d": "Once per SSTORE operation for clearing an originally existing storage slot" + }, + "balance": { + "v": 700, + "d": "Base fee of the BALANCE opcode" + }, + "extcodehash": { + "v": 700, + "d": "Base fee of the EXTCODEHASH opcode" + }, + "chainid": { + "v": 2, + "d": "Base fee of the CHAINID opcode" + }, + "selfbalance": { + "v": 5, + "d": "Base fee of the SELFBALANCE opcode" + }, + "sload": { + "v": 800, + "d": "Base fee of the SLOAD opcode" } }, "vm": {}, diff --git a/packages/common/src/hardforks/tangerineWhistle.json b/packages/common/src/hardforks/tangerineWhistle.json index 6a08c80453..be6a3093fd 100644 --- a/packages/common/src/hardforks/tangerineWhistle.json +++ b/packages/common/src/hardforks/tangerineWhistle.json @@ -14,6 +14,30 @@ "call": { "v": 700, "d": "Once per CALL operation & message call transaction" + }, + "extcodesize": { + "v": 700, + "d": "Base fee of the EXTCODESIZE opcode" + }, + "extcodecopy": { + "v": 700, + "d": "Base fee of the EXTCODECOPY opcode" + }, + "balance": { + "v": 400, + "d": "Base fee of the BALANCE opcode" + }, + "delegatecall": { + "v": 700, + "d": "Base fee of the DELEGATECALL opcode" + }, + "callcode": { + "v": 700, + "d": "Base fee of the CALLCODE opcode" + }, + "selfdestruct": { + "v": 5000, + "d": "Base fee of the SELFDESTRUCT opcode" } }, "vm": {}, diff --git a/packages/vm/lib/evm/opFns.ts b/packages/vm/lib/evm/opFns.ts index 33af20f40e..53e4f3a962 100644 --- a/packages/vm/lib/evm/opFns.ts +++ b/packages/vm/lib/evm/opFns.ts @@ -221,9 +221,6 @@ export const handlers: { [k: string]: OpHandler } = { }, SHL: function (runState: RunState) { const [a, b] = runState.stack.popN(2) - if (!runState._common.gteHardfork('constantinople')) { - trap(ERROR.INVALID_OPCODE) - } if (a.gten(256)) { runState.stack.push(new BN(0)) return @@ -234,9 +231,6 @@ export const handlers: { [k: string]: OpHandler } = { }, SHR: function (runState: RunState) { const [a, b] = runState.stack.popN(2) - if (!runState._common.gteHardfork('constantinople')) { - trap(ERROR.INVALID_OPCODE) - } if (a.gten(256)) { runState.stack.push(new BN(0)) return @@ -247,9 +241,6 @@ export const handlers: { [k: string]: OpHandler } = { }, SAR: function (runState: RunState) { const [a, b] = runState.stack.popN(2) - if (!runState._common.gteHardfork('constantinople')) { - trap(ERROR.INVALID_OPCODE) - } let r const isSigned = b.testn(255) @@ -381,9 +372,6 @@ export const handlers: { [k: string]: OpHandler } = { }, EXTCODEHASH: async function (runState: RunState) { let address = runState.stack.pop() - if (!runState._common.gteHardfork('constantinople')) { - trap(ERROR.INVALID_OPCODE) - } const addressBuf = addressToBuffer(address) const empty = await runState.eei.isAccountEmpty(addressBuf) @@ -401,15 +389,9 @@ export const handlers: { [k: string]: OpHandler } = { runState.stack.push(new BN(keccak256(code))) }, RETURNDATASIZE: function (runState: RunState) { - if (!runState._common.gteHardfork('byzantium')) { - trap(ERROR.INVALID_OPCODE) - } runState.stack.push(runState.eei.getReturnDataSize()) }, RETURNDATACOPY: function (runState: RunState) { - if (!runState._common.gteHardfork('byzantium')) { - trap(ERROR.INVALID_OPCODE) - } let [memOffset, returnDataOffset, length] = runState.stack.popN(3) if (returnDataOffset.add(length).gt(runState.eei.getReturnDataSize())) { @@ -460,17 +442,9 @@ export const handlers: { [k: string]: OpHandler } = { runState.stack.push(runState.eei.getBlockGasLimit()) }, CHAINID: function (runState: RunState) { - if (!runState._common.gteHardfork('istanbul')) { - trap(ERROR.INVALID_OPCODE) - } - runState.stack.push(runState.eei.getChainId()) }, SELFBALANCE: function (runState: RunState) { - if (!runState._common.gteHardfork('istanbul')) { - trap(ERROR.INVALID_OPCODE) - } - runState.stack.push(runState.eei.getSelfBalance()) }, // 0x50 range - 'storage' and execution @@ -644,10 +618,6 @@ export const handlers: { [k: string]: OpHandler } = { runState.stack.push(ret) }, CREATE2: async function (runState: RunState) { - if (!runState._common.gteHardfork('constantinople')) { - trap(ERROR.INVALID_OPCODE) - } - if (runState.eei.isStatic()) { trap(ERROR.STATIC_STATE_CHANGE) } @@ -775,9 +745,6 @@ export const handlers: { [k: string]: OpHandler } = { runState.stack.push(ret) }, STATICCALL: async function (runState: RunState) { - if (!runState._common.gteHardfork('byzantium')) { - trap(ERROR.INVALID_OPCODE) - } const value = new BN(0) let [gasLimit, toAddress, inOffset, inLength, outOffset, outLength] = runState.stack.popN(6) const toAddressBuf = addressToBuffer(toAddress) @@ -806,9 +773,6 @@ export const handlers: { [k: string]: OpHandler } = { runState.eei.finish(returnData) }, REVERT: function (runState: RunState) { - if (!runState._common.gteHardfork('byzantium')) { - trap(ERROR.INVALID_OPCODE) - } const [offset, length] = runState.stack.popN(2) subMemUsage(runState, offset, length) let returnData = Buffer.alloc(0) diff --git a/packages/vm/lib/evm/opcodes.ts b/packages/vm/lib/evm/opcodes.ts index 6da3ed8dd2..0c20f1dd00 100644 --- a/packages/vm/lib/evm/opcodes.ts +++ b/packages/vm/lib/evm/opcodes.ts @@ -36,198 +36,194 @@ export interface OpcodeList { } // Base opcode list. The opcode list is extended in future hardforks -const opcodes: OpcodeList = createOpcodes({ +const opcodes = { // 0x0 range - arithmetic ops - // name, baseCost, async - 0x00: { name: 'STOP', fee: 0, isAsync: false }, - 0x01: { name: 'ADD', fee: 3, isAsync: false }, - 0x02: { name: 'MUL', fee: 5, isAsync: false }, - 0x03: { name: 'SUB', fee: 3, isAsync: false }, - 0x04: { name: 'DIV', fee: 5, isAsync: false }, - 0x05: { name: 'SDIV', fee: 5, isAsync: false }, - 0x06: { name: 'MOD', fee: 5, isAsync: false }, - 0x07: { name: 'SMOD', fee: 5, isAsync: false }, - 0x08: { name: 'ADDMOD', fee: 8, isAsync: false }, - 0x09: { name: 'MULMOD', fee: 8, isAsync: false }, - 0x0a: { name: 'EXP', fee: 10, isAsync: false }, - 0x0b: { name: 'SIGNEXTEND', fee: 5, isAsync: false }, + // name, async + 0x00: { name: 'STOP', isAsync: false }, + 0x01: { name: 'ADD', isAsync: false }, + 0x02: { name: 'MUL', isAsync: false }, + 0x03: { name: 'SUB', isAsync: false }, + 0x04: { name: 'DIV', isAsync: false }, + 0x05: { name: 'SDIV', isAsync: false }, + 0x06: { name: 'MOD', isAsync: false }, + 0x07: { name: 'SMOD', isAsync: false }, + 0x08: { name: 'ADDMOD', isAsync: false }, + 0x09: { name: 'MULMOD', isAsync: false }, + 0x0a: { name: 'EXP', isAsync: false }, + 0x0b: { name: 'SIGNEXTEND', isAsync: false }, // 0x10 range - bit ops - 0x10: { name: 'LT', fee: 3, isAsync: false }, - 0x11: { name: 'GT', fee: 3, isAsync: false }, - 0x12: { name: 'SLT', fee: 3, isAsync: false }, - 0x13: { name: 'SGT', fee: 3, isAsync: false }, - 0x14: { name: 'EQ', fee: 3, isAsync: false }, - 0x15: { name: 'ISZERO', fee: 3, isAsync: false }, - 0x16: { name: 'AND', fee: 3, isAsync: false }, - 0x17: { name: 'OR', fee: 3, isAsync: false }, - 0x18: { name: 'XOR', fee: 3, isAsync: false }, - 0x19: { name: 'NOT', fee: 3, isAsync: false }, - 0x1a: { name: 'BYTE', fee: 3, isAsync: false }, + 0x10: { name: 'LT', isAsync: false }, + 0x11: { name: 'GT', isAsync: false }, + 0x12: { name: 'SLT', isAsync: false }, + 0x13: { name: 'SGT', isAsync: false }, + 0x14: { name: 'EQ', isAsync: false }, + 0x15: { name: 'ISZERO', isAsync: false }, + 0x16: { name: 'AND', isAsync: false }, + 0x17: { name: 'OR', isAsync: false }, + 0x18: { name: 'XOR', isAsync: false }, + 0x19: { name: 'NOT', isAsync: false }, + 0x1a: { name: 'BYTE', isAsync: false }, // 0x20 range - crypto - 0x20: { name: 'SHA3', fee: 30, isAsync: false }, + 0x20: { name: 'SHA3', isAsync: false }, // 0x30 range - closure state - 0x30: { name: 'ADDRESS', fee: 2, isAsync: true }, - 0x31: { name: 'BALANCE', fee: 400, isAsync: true }, - 0x32: { name: 'ORIGIN', fee: 2, isAsync: true }, - 0x33: { name: 'CALLER', fee: 2, isAsync: true }, - 0x34: { name: 'CALLVALUE', fee: 2, isAsync: true }, - 0x35: { name: 'CALLDATALOAD', fee: 3, isAsync: true }, - 0x36: { name: 'CALLDATASIZE', fee: 2, isAsync: true }, - 0x37: { name: 'CALLDATACOPY', fee: 3, isAsync: true }, - 0x38: { name: 'CODESIZE', fee: 2, isAsync: false }, - 0x39: { name: 'CODECOPY', fee: 3, isAsync: false }, - 0x3a: { name: 'GASPRICE', fee: 2, isAsync: false }, - 0x3b: { name: 'EXTCODESIZE', fee: 700, isAsync: true }, - 0x3c: { name: 'EXTCODECOPY', fee: 700, isAsync: true }, + 0x30: { name: 'ADDRESS', isAsync: true }, + 0x31: { name: 'BALANCE', isAsync: true }, + 0x32: { name: 'ORIGIN', isAsync: true }, + 0x33: { name: 'CALLER', isAsync: true }, + 0x34: { name: 'CALLVALUE', isAsync: true }, + 0x35: { name: 'CALLDATALOAD', isAsync: true }, + 0x36: { name: 'CALLDATASIZE', isAsync: true }, + 0x37: { name: 'CALLDATACOPY', isAsync: true }, + 0x38: { name: 'CODESIZE', isAsync: false }, + 0x39: { name: 'CODECOPY', isAsync: false }, + 0x3a: { name: 'GASPRICE', isAsync: false }, + 0x3b: { name: 'EXTCODESIZE', isAsync: true }, + 0x3c: { name: 'EXTCODECOPY', isAsync: true }, // '0x40' range - block operations - 0x40: { name: 'BLOCKHASH', fee: 20, isAsync: true }, - 0x41: { name: 'COINBASE', fee: 2, isAsync: true }, - 0x42: { name: 'TIMESTAMP', fee: 2, isAsync: true }, - 0x43: { name: 'NUMBER', fee: 2, isAsync: true }, - 0x44: { name: 'DIFFICULTY', fee: 2, isAsync: true }, - 0x45: { name: 'GASLIMIT', fee: 2, isAsync: true }, + 0x40: { name: 'BLOCKHASH', isAsync: true }, + 0x41: { name: 'COINBASE', isAsync: true }, + 0x42: { name: 'TIMESTAMP', isAsync: true }, + 0x43: { name: 'NUMBER', isAsync: true }, + 0x44: { name: 'DIFFICULTY', isAsync: true }, + 0x45: { name: 'GASLIMIT', isAsync: true }, // 0x50 range - 'storage' and execution - 0x50: { name: 'POP', fee: 2, isAsync: false }, - 0x51: { name: 'MLOAD', fee: 3, isAsync: false }, - 0x52: { name: 'MSTORE', fee: 3, isAsync: false }, - 0x53: { name: 'MSTORE8', fee: 3, isAsync: false }, - 0x54: { name: 'SLOAD', fee: 200, isAsync: true }, - 0x55: { name: 'SSTORE', fee: 0, isAsync: true }, - 0x56: { name: 'JUMP', fee: 8, isAsync: false }, - 0x57: { name: 'JUMPI', fee: 10, isAsync: false }, - 0x58: { name: 'PC', fee: 2, isAsync: false }, - 0x59: { name: 'MSIZE', fee: 2, isAsync: false }, - 0x5a: { name: 'GAS', fee: 2, isAsync: false }, - 0x5b: { name: 'JUMPDEST', fee: 1, isAsync: false }, + 0x50: { name: 'POP', isAsync: false }, + 0x51: { name: 'MLOAD', isAsync: false }, + 0x52: { name: 'MSTORE', isAsync: false }, + 0x53: { name: 'MSTORE8', isAsync: false }, + 0x54: { name: 'SLOAD', isAsync: true }, + 0x55: { name: 'SSTORE', isAsync: true }, + 0x56: { name: 'JUMP', isAsync: false }, + 0x57: { name: 'JUMPI', isAsync: false }, + 0x58: { name: 'PC', isAsync: false }, + 0x59: { name: 'MSIZE', isAsync: false }, + 0x5a: { name: 'GAS', isAsync: false }, + 0x5b: { name: 'JUMPDEST', isAsync: false }, // 0x60, range - 0x60: { name: 'PUSH', fee: 3, isAsync: false }, - 0x61: { name: 'PUSH', fee: 3, isAsync: false }, - 0x62: { name: 'PUSH', fee: 3, isAsync: false }, - 0x63: { name: 'PUSH', fee: 3, isAsync: false }, - 0x64: { name: 'PUSH', fee: 3, isAsync: false }, - 0x65: { name: 'PUSH', fee: 3, isAsync: false }, - 0x66: { name: 'PUSH', fee: 3, isAsync: false }, - 0x67: { name: 'PUSH', fee: 3, isAsync: false }, - 0x68: { name: 'PUSH', fee: 3, isAsync: false }, - 0x69: { name: 'PUSH', fee: 3, isAsync: false }, - 0x6a: { name: 'PUSH', fee: 3, isAsync: false }, - 0x6b: { name: 'PUSH', fee: 3, isAsync: false }, - 0x6c: { name: 'PUSH', fee: 3, isAsync: false }, - 0x6d: { name: 'PUSH', fee: 3, isAsync: false }, - 0x6e: { name: 'PUSH', fee: 3, isAsync: false }, - 0x6f: { name: 'PUSH', fee: 3, isAsync: false }, - 0x70: { name: 'PUSH', fee: 3, isAsync: false }, - 0x71: { name: 'PUSH', fee: 3, isAsync: false }, - 0x72: { name: 'PUSH', fee: 3, isAsync: false }, - 0x73: { name: 'PUSH', fee: 3, isAsync: false }, - 0x74: { name: 'PUSH', fee: 3, isAsync: false }, - 0x75: { name: 'PUSH', fee: 3, isAsync: false }, - 0x76: { name: 'PUSH', fee: 3, isAsync: false }, - 0x77: { name: 'PUSH', fee: 3, isAsync: false }, - 0x78: { name: 'PUSH', fee: 3, isAsync: false }, - 0x79: { name: 'PUSH', fee: 3, isAsync: false }, - 0x7a: { name: 'PUSH', fee: 3, isAsync: false }, - 0x7b: { name: 'PUSH', fee: 3, isAsync: false }, - 0x7c: { name: 'PUSH', fee: 3, isAsync: false }, - 0x7d: { name: 'PUSH', fee: 3, isAsync: false }, - 0x7e: { name: 'PUSH', fee: 3, isAsync: false }, - 0x7f: { name: 'PUSH', fee: 3, isAsync: false }, + 0x60: { name: 'PUSH', isAsync: false }, + 0x61: { name: 'PUSH', isAsync: false }, + 0x62: { name: 'PUSH', isAsync: false }, + 0x63: { name: 'PUSH', isAsync: false }, + 0x64: { name: 'PUSH', isAsync: false }, + 0x65: { name: 'PUSH', isAsync: false }, + 0x66: { name: 'PUSH', isAsync: false }, + 0x67: { name: 'PUSH', isAsync: false }, + 0x68: { name: 'PUSH', isAsync: false }, + 0x69: { name: 'PUSH', isAsync: false }, + 0x6a: { name: 'PUSH', isAsync: false }, + 0x6b: { name: 'PUSH', isAsync: false }, + 0x6c: { name: 'PUSH', isAsync: false }, + 0x6d: { name: 'PUSH', isAsync: false }, + 0x6e: { name: 'PUSH', isAsync: false }, + 0x6f: { name: 'PUSH', isAsync: false }, + 0x70: { name: 'PUSH', isAsync: false }, + 0x71: { name: 'PUSH', isAsync: false }, + 0x72: { name: 'PUSH', isAsync: false }, + 0x73: { name: 'PUSH', isAsync: false }, + 0x74: { name: 'PUSH', isAsync: false }, + 0x75: { name: 'PUSH', isAsync: false }, + 0x76: { name: 'PUSH', isAsync: false }, + 0x77: { name: 'PUSH', isAsync: false }, + 0x78: { name: 'PUSH', isAsync: false }, + 0x79: { name: 'PUSH', isAsync: false }, + 0x7a: { name: 'PUSH', isAsync: false }, + 0x7b: { name: 'PUSH', isAsync: false }, + 0x7c: { name: 'PUSH', isAsync: false }, + 0x7d: { name: 'PUSH', isAsync: false }, + 0x7e: { name: 'PUSH', isAsync: false }, + 0x7f: { name: 'PUSH', isAsync: false }, - 0x80: { name: 'DUP', fee: 3, isAsync: false }, - 0x81: { name: 'DUP', fee: 3, isAsync: false }, - 0x82: { name: 'DUP', fee: 3, isAsync: false }, - 0x83: { name: 'DUP', fee: 3, isAsync: false }, - 0x84: { name: 'DUP', fee: 3, isAsync: false }, - 0x85: { name: 'DUP', fee: 3, isAsync: false }, - 0x86: { name: 'DUP', fee: 3, isAsync: false }, - 0x87: { name: 'DUP', fee: 3, isAsync: false }, - 0x88: { name: 'DUP', fee: 3, isAsync: false }, - 0x89: { name: 'DUP', fee: 3, isAsync: false }, - 0x8a: { name: 'DUP', fee: 3, isAsync: false }, - 0x8b: { name: 'DUP', fee: 3, isAsync: false }, - 0x8c: { name: 'DUP', fee: 3, isAsync: false }, - 0x8d: { name: 'DUP', fee: 3, isAsync: false }, - 0x8e: { name: 'DUP', fee: 3, isAsync: false }, - 0x8f: { name: 'DUP', fee: 3, isAsync: false }, + 0x80: { name: 'DUP', isAsync: false }, + 0x81: { name: 'DUP', isAsync: false }, + 0x82: { name: 'DUP', isAsync: false }, + 0x83: { name: 'DUP', isAsync: false }, + 0x84: { name: 'DUP', isAsync: false }, + 0x85: { name: 'DUP', isAsync: false }, + 0x86: { name: 'DUP', isAsync: false }, + 0x87: { name: 'DUP', isAsync: false }, + 0x88: { name: 'DUP', isAsync: false }, + 0x89: { name: 'DUP', isAsync: false }, + 0x8a: { name: 'DUP', isAsync: false }, + 0x8b: { name: 'DUP', isAsync: false }, + 0x8c: { name: 'DUP', isAsync: false }, + 0x8d: { name: 'DUP', isAsync: false }, + 0x8e: { name: 'DUP', isAsync: false }, + 0x8f: { name: 'DUP', isAsync: false }, - 0x90: { name: 'SWAP', fee: 3, isAsync: false }, - 0x91: { name: 'SWAP', fee: 3, isAsync: false }, - 0x92: { name: 'SWAP', fee: 3, isAsync: false }, - 0x93: { name: 'SWAP', fee: 3, isAsync: false }, - 0x94: { name: 'SWAP', fee: 3, isAsync: false }, - 0x95: { name: 'SWAP', fee: 3, isAsync: false }, - 0x96: { name: 'SWAP', fee: 3, isAsync: false }, - 0x97: { name: 'SWAP', fee: 3, isAsync: false }, - 0x98: { name: 'SWAP', fee: 3, isAsync: false }, - 0x99: { name: 'SWAP', fee: 3, isAsync: false }, - 0x9a: { name: 'SWAP', fee: 3, isAsync: false }, - 0x9b: { name: 'SWAP', fee: 3, isAsync: false }, - 0x9c: { name: 'SWAP', fee: 3, isAsync: false }, - 0x9d: { name: 'SWAP', fee: 3, isAsync: false }, - 0x9e: { name: 'SWAP', fee: 3, isAsync: false }, - 0x9f: { name: 'SWAP', fee: 3, isAsync: false }, + 0x90: { name: 'SWAP', isAsync: false }, + 0x91: { name: 'SWAP', isAsync: false }, + 0x92: { name: 'SWAP', isAsync: false }, + 0x93: { name: 'SWAP', isAsync: false }, + 0x94: { name: 'SWAP', isAsync: false }, + 0x95: { name: 'SWAP', isAsync: false }, + 0x96: { name: 'SWAP', isAsync: false }, + 0x97: { name: 'SWAP', isAsync: false }, + 0x98: { name: 'SWAP', isAsync: false }, + 0x99: { name: 'SWAP', isAsync: false }, + 0x9a: { name: 'SWAP', isAsync: false }, + 0x9b: { name: 'SWAP', isAsync: false }, + 0x9c: { name: 'SWAP', isAsync: false }, + 0x9d: { name: 'SWAP', isAsync: false }, + 0x9e: { name: 'SWAP', isAsync: false }, + 0x9f: { name: 'SWAP', isAsync: false }, - 0xa0: { name: 'LOG', fee: 375, isAsync: false }, - 0xa1: { name: 'LOG', fee: 375, isAsync: false }, - 0xa2: { name: 'LOG', fee: 375, isAsync: false }, - 0xa3: { name: 'LOG', fee: 375, isAsync: false }, - 0xa4: { name: 'LOG', fee: 375, isAsync: false }, + 0xa0: { name: 'LOG', isAsync: false }, + 0xa1: { name: 'LOG', isAsync: false }, + 0xa2: { name: 'LOG', isAsync: false }, + 0xa3: { name: 'LOG', isAsync: false }, + 0xa4: { name: 'LOG', isAsync: false }, // '0xf0' range - closures - 0xf0: { name: 'CREATE', fee: 32000, isAsync: true }, - 0xf1: { name: 'CALL', fee: 700, isAsync: true }, - 0xf2: { name: 'CALLCODE', fee: 700, isAsync: true }, - 0xf3: { name: 'RETURN', fee: 0, isAsync: false }, - 0xfa: { name: 'STATICCALL', fee: 700, isAsync: true }, + 0xf0: { name: 'CREATE', isAsync: true }, + 0xf1: { name: 'CALL', isAsync: true }, + 0xf2: { name: 'CALLCODE', isAsync: true }, + 0xf3: { name: 'RETURN', isAsync: false }, // '0x70', range - other - 0xfe: { name: 'INVALID', fee: 0, isAsync: false }, - 0xff: { name: 'SELFDESTRUCT', fee: 5000, isAsync: true }, -}) + 0xfe: { name: 'INVALID', isAsync: false }, + 0xff: { name: 'SELFDESTRUCT', isAsync: true }, +} // Array of hard forks in order. These changes are repeatedly applied to `opcodes` until the hard fork is in the future based upon the common // TODO: All gas price changes should be moved to common const hardforkOpcodes = [ { hardforkName: 'homestead', - opcodes: createOpcodes({ - 0xf4: { name: 'DELEGATECALL', fee: 700, isAsync: true }, // EIP 7 - }), + opcodes: { + 0xf4: { name: 'DELEGATECALL', isAsync: true }, // EIP 7 + }, }, { hardforkName: 'byzantium', - opcodes: createOpcodes({ - 0xfd: { name: 'REVERT', fee: 0, isAsync: false }, // EIP 140 - 0xfa: { name: 'STATICCALL', fee: 700, isAsync: true }, // EIP 214 - 0x3d: { name: 'RETURNDATASIZE', fee: 2, isAsync: true }, // EIP 211 - 0x3e: { name: 'RETURNDATACOPY', fee: 3, isAsync: true }, // EIP 211 - }), + opcodes: { + 0xfd: { name: 'REVERT', isAsync: false }, // EIP 140 + 0xfa: { name: 'STATICCALL', isAsync: true }, // EIP 214 + 0x3d: { name: 'RETURNDATASIZE', isAsync: true }, // EIP 211 + 0x3e: { name: 'RETURNDATACOPY', isAsync: true }, // EIP 211 + }, }, { hardforkName: 'constantinople', - opcodes: createOpcodes({ - 0x1b: { name: 'SHL', fee: 3, isAsync: false }, // EIP 145 - 0x1c: { name: 'SHR', fee: 3, isAsync: false }, // EIP 145 - 0x1d: { name: 'SAR', fee: 3, isAsync: false }, // EIP 145 - 0x3f: { name: 'EXTCODEHASH', fee: 400, isAsync: true }, // EIP 1052 - 0xf5: { name: 'CREATE2', fee: 32000, isAsync: true }, // EIP 1014 - }), + opcodes: { + 0x1b: { name: 'SHL', isAsync: false }, // EIP 145 + 0x1c: { name: 'SHR', isAsync: false }, // EIP 145 + 0x1d: { name: 'SAR', isAsync: false }, // EIP 145 + 0x3f: { name: 'EXTCODEHASH', isAsync: true }, // EIP 1052 + 0xf5: { name: 'CREATE2', isAsync: true }, // EIP 1014 + }, }, { hardforkName: 'istanbul', - opcodes: createOpcodes({ - 0x31: { name: 'BALANCE', fee: 700, isAsync: true }, // gas price change, EIP 1884 - 0x3f: { name: 'EXTCODEHASH', fee: 700, isAsync: true }, // gas price change, EIP 1884 - 0x46: { name: 'CHAINID', fee: 2, isAsync: false }, // EIP 1344 - 0x47: { name: 'SELFBALANCE', fee: 5, isAsync: false }, // EIP 1884 - 0x54: { name: 'SLOAD', fee: 800, isAsync: true }, // gas price change, EIP 1884 - }), + opcodes: { + 0x46: { name: 'CHAINID', isAsync: false }, // EIP 1344 + 0x47: { name: 'SELFBALANCE', isAsync: false }, // EIP 1884 + }, }, ] @@ -284,7 +280,7 @@ function getFullname(code: number, name: string): string { * @returns {OpcodeList} Opcodes dictionary object. */ export function getOpcodesForHF(common: Common): OpcodeList { - let opcodeBuilder = { ...opcodes } + let opcodeBuilder: any = { ...opcodes } for (let fork = 0; fork < hardforkOpcodes.length; fork++) { if (common.gteHardfork(hardforkOpcodes[fork].hardforkName)) { @@ -292,5 +288,14 @@ export function getOpcodesForHF(common: Common): OpcodeList { } } - return opcodeBuilder + for (let key in opcodeBuilder) { + let baseFee = 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()) + } + + return createOpcodes(opcodeBuilder) }