From 80aec9ccd96709b5170ed2936e9316287e76729d Mon Sep 17 00:00:00 2001 From: jangko Date: Sun, 27 Aug 2023 13:13:37 +0700 Subject: [PATCH] Fix EVM tracer: capture exception properly Also fix EVM to support new tracer --- nimbus/evm/computation.nim | 12 +- nimbus/evm/interpreter/gas_costs.nim | 22 ++-- nimbus/evm/interpreter/op_dispatcher.nim | 2 +- .../op_handlers/oph_arithmetic.nim | 5 +- .../evm/interpreter/op_handlers/oph_call.nim | 70 +++-------- .../interpreter/op_handlers/oph_create.nim | 113 ++++++++--------- .../interpreter/op_handlers/oph_envinfo.nim | 25 ++-- .../evm/interpreter/op_handlers/oph_hash.nim | 3 +- .../interpreter/op_handlers/oph_helpers.nim | 40 +++--- .../evm/interpreter/op_handlers/oph_log.nim | 3 +- .../interpreter/op_handlers/oph_memory.nim | 78 +++++------- .../interpreter/op_handlers/oph_sysops.nim | 11 +- nimbus/evm/precompiles.nim | 5 +- nimbus/evm/state.nim | 18 +-- nimbus/evm/tracer/json_tracer.nim | 118 ++++++++++-------- nimbus/evm/tracer/legacy_tracer.nim | 12 +- nimbus/evm/types.nim | 20 +-- nimbus/vm_state.nim | 2 +- tools/t8n/t8n_test.nim | 9 ++ tools/t8n/testdata/00-521/alloc.json | 68 ++++++++++ tools/t8n/testdata/00-521/env.json | 10 ++ tools/t8n/testdata/00-521/exp.txt | 17 +++ tools/t8n/testdata/00-521/txs.json | 14 +++ 23 files changed, 382 insertions(+), 295 deletions(-) create mode 100644 tools/t8n/testdata/00-521/alloc.json create mode 100644 tools/t8n/testdata/00-521/env.json create mode 100644 tools/t8n/testdata/00-521/exp.txt create mode 100644 tools/t8n/testdata/00-521/txs.json diff --git a/nimbus/evm/computation.nim b/nimbus/evm/computation.nim index fe924ac58..8500f1ba4 100644 --- a/nimbus/evm/computation.nim +++ b/nimbus/evm/computation.nim @@ -396,9 +396,6 @@ proc traceOpCodeStarted*(c: Computation, op: Op): int {.gcsafe, raises: [].} = c.gasMeter.gasRemaining, c.msg.depth + 1) -proc traceCallFamilyGas*(c: Computation, op: Op, gas: GasInt) {.gcsafe, raises: [].} = - c.vmState.callFamilyGas(c, op, gas, c.msg.depth + 1) - proc traceOpCodeEnded*(c: Computation, op: Op, opIndex: int) {.gcsafe, raises: [].} = c.vmState.captureOpEnd( c, @@ -424,6 +421,15 @@ proc traceError*(c: Computation) {.gcsafe, raises: [].} = proc prepareTracer*(c: Computation) = c.vmState.capturePrepare(c, c.msg.depth) +proc opcodeGastCost*(c: Computation, op: Op, gasCost: GasInt, reason: string) {.gcsafe, raises: [OutOfGas, ValueError].} = + c.vmState.captureGasCost( + c, + op, + gasCost, + c.gasMeter.gasRemaining, + c.msg.depth + 1) + c.gasMeter.consumeGas(gasCost, reason) + # ------------------------------------------------------------------------------ # End # ------------------------------------------------------------------------------ diff --git a/nimbus/evm/interpreter/gas_costs.nim b/nimbus/evm/interpreter/gas_costs.nim index d6a174968..981d5a63a 100644 --- a/nimbus/evm/interpreter/gas_costs.nim +++ b/nimbus/evm/interpreter/gas_costs.nim @@ -94,7 +94,8 @@ type GckFixed, GckDynamic, GckMemExpansion, - GckComplex + GckComplex, + GckLater GasResult = tuple[gasCost, gasRefund: GasInt] @@ -102,7 +103,7 @@ type case kind*: GasCostKind of GckInvalidOp: discard - of GckFixed: + of GckFixed, GckLater: cost*: GasInt of GckDynamic: d_handler*: proc(value: UInt256): GasInt @@ -535,6 +536,13 @@ template gasCosts(fork: EVMFork, prefix, ResultGasCostsName: untyped) = func fixed(gasFeeKind: static[GasFeeKind]): GasCost = GasCost(kind: GckFixed, cost: static(FeeSchedule[gasFeeKind])) + func fixedOrLater(gasFeeKind: static[GasFeeKind]): GasCost = + when fork < FkBerlin: + GasCost(kind: GckFixed, cost: static(FeeSchedule[gasFeeKind])) + else: + # GckLater is processed by the opcode + GasCost(kind: GckLater, cost: static(FeeSchedule[gasFeeKind])) + func dynamic(handler: proc(value: UInt256): GasInt {.nimcall, gcsafe, raises: [CatchableError].}): GasCost = GasCost(kind: GckDynamic, d_handler: handler) @@ -585,7 +593,7 @@ template gasCosts(fork: EVMFork, prefix, ResultGasCostsName: untyped) = # 30s: Environmental Information Address: fixed GasBase, - Balance: fixed GasBalance, + Balance: fixedOrLater GasBalance, Origin: fixed GasBase, Caller: fixed GasBase, CallValue: fixed GasBase, @@ -595,11 +603,11 @@ template gasCosts(fork: EVMFork, prefix, ResultGasCostsName: untyped) = CodeSize: fixed GasBase, CodeCopy: memExpansion `prefix gasCopy`, GasPrice: fixed GasBase, - ExtCodeSize: fixed GasExtCode, + ExtCodeSize: fixedOrLater GasExtCode, ExtCodeCopy: memExpansion `prefix gasExtCodeCopy`, ReturnDataSize: fixed GasBase, ReturnDataCopy: memExpansion `prefix gasCopy`, - ExtCodeHash: fixed GasExtCodeHash, + ExtCodeHash: fixedOrLater GasExtCodeHash, # 40s: Block Information Blockhash: fixed GasBlockhash, @@ -618,7 +626,7 @@ template gasCosts(fork: EVMFork, prefix, ResultGasCostsName: untyped) = Mload: memExpansion `prefix gasLoadStore`, Mstore: memExpansion `prefix gasLoadStore`, Mstore8: memExpansion `prefix gasLoadStore`, - Sload: fixed GasSload, + Sload: fixedOrLater GasSload, Sstore: complex `prefix gasSstore`, Jump: fixed GasMid, JumpI: fixed GasHigh, @@ -630,7 +638,7 @@ template gasCosts(fork: EVMFork, prefix, ResultGasCostsName: untyped) = # 5c & 5d: Transient storage operations Tload: fixed GasWarmStorageRead, Tstore: fixed GasWarmStorageRead, - + # 5e: Memory copy Mcopy: memExpansion `prefix gasCopy`, diff --git a/nimbus/evm/interpreter/op_dispatcher.nim b/nimbus/evm/interpreter/op_dispatcher.nim index 5322ea102..67678a293 100644 --- a/nimbus/evm/interpreter/op_dispatcher.nim +++ b/nimbus/evm/interpreter/op_dispatcher.nim @@ -47,7 +47,7 @@ template handleFixedGasCostsDirective(fork: EVMFork; op: Op; k: var Vm2Ctx) = if k.cpt.tracingEnabled: k.cpt.opIndex = k.cpt.traceOpCodeStarted(op) - k.cpt.gasMeter.consumeGas(k.cpt.gasCosts[op].cost, reason = $op) + k.cpt.opcodeGastCost(op, k.cpt.gasCosts[op].cost, reason = $op) vmOpHandlers[fork][op].run(k) # If continuation is not nil, traceOpCodeEnded will be called in executeOpcodes. diff --git a/nimbus/evm/interpreter/op_handlers/oph_arithmetic.nim b/nimbus/evm/interpreter/op_handlers/oph_arithmetic.nim index b0b723493..a2dabe5bb 100644 --- a/nimbus/evm/interpreter/op_handlers/oph_arithmetic.nim +++ b/nimbus/evm/interpreter/op_handlers/oph_arithmetic.nim @@ -20,7 +20,6 @@ import ../../types, ../op_codes, ../gas_costs, - ../gas_meter, ../utils/utils_numeric, ./oph_defs, eth/common @@ -131,7 +130,7 @@ const ## 0x0A, Exponentiation let (base, exponent) = k.cpt.stack.popInt(2) - k.cpt.gasMeter.consumeGas( + k.cpt.opcodeGastCost(Exp, k.cpt.gasCosts[Exp].d_handler(exponent), reason = "EXP: exponent bytes") @@ -231,7 +230,7 @@ const byteOp: Vm2OpFn = proc(k: var Vm2Ctx) = ## 0x20, Retrieve single byte from word. - let (position, value) = k.cpt.stack.popInt(2) + let (position, value) = k.cpt.stack.popInt(2) k.cpt.stack.push: if position >= 32.u256: zero(UInt256) diff --git a/nimbus/evm/interpreter/op_handlers/oph_call.nim b/nimbus/evm/interpreter/op_handlers/oph_call.nim index b3b8d7197..0d93a8086 100644 --- a/nimbus/evm/interpreter/op_handlers/oph_call.nim +++ b/nimbus/evm/interpreter/op_handlers/oph_call.nim @@ -56,6 +56,7 @@ type memOffset: int memLength: int contractAddress: EthAddress + gasCallEIP2929: GasInt proc updateStackAndParams(q: var LocalParams; c: Computation) = @@ -79,9 +80,7 @@ proc updateStackAndParams(q: var LocalParams; c: Computation) = if FkBerlin <= c.fork: when evmc_enabled: if c.host.accessAccount(q.codeAddress) == EVMC_ACCESS_COLD: - c.gasMeter.consumeGas( - ColdAccountAccessCost - WarmStorageReadCost, - reason = "EIP2929 gasCall") + q.gasCallEIP2929 = ColdAccountAccessCost - WarmStorageReadCost else: c.vmState.mutateStateDB: if not db.inAccessList(q.codeAddress): @@ -89,9 +88,7 @@ proc updateStackAndParams(q: var LocalParams; c: Computation) = # The WarmStorageReadCostEIP2929 (100) is already deducted in # the form of a constant `gasCall` - c.gasMeter.consumeGas( - ColdAccountAccessCost - WarmStorageReadCost, - reason = "EIP2929 gasCall") + q.gasCallEIP2929 = ColdAccountAccessCost - WarmStorageReadCost proc callParams(c: Computation): LocalParams = @@ -205,7 +202,6 @@ const "Cannot modify state while inside of a STATICCALL context") let - gasAtStart = cpt.gasMeter.gasRemaining p = cpt.callParams cpt.asyncChainTo(ifNecessaryGetAccounts(cpt.vmState, @[p.sender])): @@ -215,17 +211,15 @@ const GasParams( kind: Call, c_isNewAccount: not cpt.accountExists(p.contractAddress), - c_gasBalance: cpt.gasMeter.gasRemaining, + c_gasBalance: cpt.gasMeter.gasRemaining - p.gasCallEIP2929, c_contractGas: p.gas, c_currentMemSize: cpt.memory.len, c_memOffset: p.memOffset, c_memLength: p.memLength)) - # EIP 2046: temporary disabled - # reduce gas fee for precompiles - # from 700 to 40 + gasCost += p.gasCallEIP2929 if gasCost >= 0: - cpt.gasMeter.consumeGas(gasCost, reason = $Call) + cpt.opcodeGastCost(Call, gasCost, reason = $Call) cpt.returnData.setLen(0) @@ -241,17 +235,11 @@ const raise newException( OutOfGas, "Gas not enough to perform calculation (call)") - gasCost = gasAtStart - cpt.gasMeter.gasRemaining - cpt.traceCallFamilyGas(Call, gasCost) - cpt.memory.extend(p.memInPos, p.memInLen) cpt.memory.extend(p.memOutPos, p.memOutLen) let senderBalance = cpt.getBalance(p.sender) if senderBalance < p.value: - #debug "Insufficient funds", - # available = senderBalance, - # needed = cpt.msg.value cpt.gasMeter.returnGas(childGasLimit) return @@ -293,7 +281,6 @@ const ## 0xf2, Message-call into this account with an alternative account's code. let cpt = k.cpt - gasAtStart = cpt.gasMeter.gasRemaining p = cpt.callCodeParams cpt.asyncChainTo(ifNecessaryGetAccounts(cpt.vmState, @[p.sender])): @@ -303,17 +290,15 @@ const GasParams( kind: CallCode, c_isNewAccount: not cpt.accountExists(p.contractAddress), - c_gasBalance: cpt.gasMeter.gasRemaining, + c_gasBalance: cpt.gasMeter.gasRemaining - p.gasCallEIP2929, c_contractGas: p.gas, c_currentMemSize: cpt.memory.len, c_memOffset: p.memOffset, c_memLength: p.memLength)) - # EIP 2046: temporary disabled - # reduce gas fee for precompiles - # from 700 to 40 + gasCost += p.gasCallEIP2929 if gasCost >= 0: - cpt.gasMeter.consumeGas(gasCost, reason = $CallCode) + cpt.opcodeGastCost(CallCode, gasCost, reason = $CallCode) cpt.returnData.setLen(0) @@ -325,24 +310,15 @@ const cpt.gasMeter.returnGas(childGasLimit) return - # EIP 2046: temporary disabled - # reduce gas fee for precompiles - # from 700 to 40 if gasCost < 0 and childGasLimit <= 0: raise newException( OutOfGas, "Gas not enough to perform calculation (callCode)") - gasCost = gasAtStart - cpt.gasMeter.gasRemaining - cpt.traceCallFamilyGas(CallCode, gasCost) - cpt.memory.extend(p.memInPos, p.memInLen) cpt.memory.extend(p.memOutPos, p.memOutLen) let senderBalance = cpt.getBalance(p.sender) if senderBalance < p.value: - #debug "Insufficient funds", - # available = senderBalance, - # needed = cpt.msg.value cpt.gasMeter.returnGas(childGasLimit) return @@ -385,7 +361,6 @@ const ## code, but persisting the current values for sender and value. let cpt = k.cpt - gasAtStart = cpt.gasMeter.gasRemaining p = cpt.delegateCallParams cpt.asyncChainTo(ifNecessaryGetAccounts(cpt.vmState, @[p.sender])): @@ -395,17 +370,15 @@ const GasParams( kind: DelegateCall, c_isNewAccount: not cpt.accountExists(p.contractAddress), - c_gasBalance: cpt.gasMeter.gasRemaining, + c_gasBalance: cpt.gasMeter.gasRemaining - p.gasCallEIP2929, c_contractGas: p.gas, c_currentMemSize: cpt.memory.len, c_memOffset: p.memOffset, c_memLength: p.memLength)) - # EIP 2046: temporary disabled - # reduce gas fee for precompiles - # from 700 to 40 + gasCost += p.gasCallEIP2929 if gasCost >= 0: - cpt.gasMeter.consumeGas(gasCost, reason = $DelegateCall) + cpt.opcodeGastCost(DelegateCall, gasCost, reason = $DelegateCall) cpt.returnData.setLen(0) if cpt.msg.depth >= MaxCallDepth: @@ -420,9 +393,6 @@ const raise newException( OutOfGas, "Gas not enough to perform calculation (delegateCall)") - gasCost = gasAtStart - cpt.gasMeter.gasRemaining - cpt.traceCallFamilyGas(DelegateCall, gasCost) - cpt.memory.extend(p.memInPos, p.memInLen) cpt.memory.extend(p.memOutPos, p.memOutLen) @@ -465,7 +435,6 @@ const let cpt = k.cpt - gasAtStart = cpt.gasMeter.gasRemaining p = cpt.staticCallParams cpt.asyncChainTo(ifNecessaryGetAccounts(cpt.vmState, @[p.sender])): @@ -475,21 +444,15 @@ const GasParams( kind: StaticCall, c_isNewAccount: not cpt.accountExists(p.contractAddress), - c_gasBalance: cpt.gasMeter.gasRemaining, + c_gasBalance: cpt.gasMeter.gasRemaining - p.gasCallEIP2929, c_contractGas: p.gas, c_currentMemSize: cpt.memory.len, c_memOffset: p.memOffset, c_memLength: p.memLength)) - # EIP 2046: temporary disabled - # reduce gas fee for precompiles - # from 700 to 40 - # - # when opCode == StaticCall: - # if cpt.fork >= FkBerlin and codeAddress.toInt <= MaxPrecompilesAddr: - # gasCost = gasCost - 660.GasInt + gasCost += p.gasCallEIP2929 if gasCost >= 0: - cpt.gasMeter.consumeGas(gasCost, reason = $StaticCall) + cpt.opcodeGastCost(StaticCall, gasCost, reason = $StaticCall) cpt.returnData.setLen(0) @@ -505,9 +468,6 @@ const raise newException( OutOfGas, "Gas not enough to perform calculation (staticCall)") - gasCost = gasAtStart - cpt.gasMeter.gasRemaining - cpt.traceCallFamilyGas(StaticCall, gasCost) - cpt.memory.extend(p.memInPos, p.memInLen) cpt.memory.extend(p.memOutPos, p.memOutLen) diff --git a/nimbus/evm/interpreter/op_handlers/oph_create.nim b/nimbus/evm/interpreter/op_handlers/oph_create.nim index 394016a8a..b300cc7ba 100644 --- a/nimbus/evm/interpreter/op_handlers/oph_create.nim +++ b/nimbus/evm/interpreter/op_handlers/oph_create.nim @@ -87,41 +87,42 @@ const checkInStaticContext(k.cpt) let - endowment = k.cpt.stack.popInt() - memPos = k.cpt.stack.popInt().safeInt - memLen = k.cpt.stack.peekInt().safeInt + cpt = k.cpt + endowment = cpt.stack.popInt() + memPos = cpt.stack.popInt().safeInt + memLen = cpt.stack.peekInt().safeInt - k.cpt.stack.top(0) + cpt.stack.top(0) # EIP-3860 - if k.cpt.fork >= FkShanghai and memLen > EIP3860_MAX_INITCODE_SIZE: + if cpt.fork >= FkShanghai and memLen > EIP3860_MAX_INITCODE_SIZE: trace "Initcode size exceeds maximum", initcodeSize = memLen raise newException(InitcodeError, &"CREATE: have {memLen}, max {EIP3860_MAX_INITCODE_SIZE}") let - gasAtStart = k.cpt.gasMeter.gasRemaining gasParams = GasParams( kind: Create, - cr_currentMemSize: k.cpt.memory.len, + cr_currentMemSize: cpt.memory.len, cr_memOffset: memPos, cr_memLength: memLen) - var gasCost = k.cpt.gasCosts[Create].c_handler(1.u256, gasParams).gasCost - k.cpt.gasMeter.consumeGas( - gasCost, reason = &"CREATE: GasCreate + {memLen} * memory expansion") - k.cpt.memory.extend(memPos, memLen) - k.cpt.returnData.setLen(0) + let gasCost = cpt.gasCosts[Create].c_handler(1.u256, gasParams).gasCost - if k.cpt.msg.depth >= MaxCallDepth: + cpt.opcodeGastCost(Create, + gasCost, reason = &"CREATE: GasCreate + {memLen} * memory expansion") + cpt.memory.extend(memPos, memLen) + cpt.returnData.setLen(0) + + if cpt.msg.depth >= MaxCallDepth: debug "Computation Failure", reason = "Stack too deep", maxDepth = MaxCallDepth, - depth = k.cpt.msg.depth + depth = cpt.msg.depth return if endowment != 0: - let senderBalance = k.cpt.getBalance(k.cpt.msg.contractAddress) + let senderBalance = cpt.getBalance(cpt.msg.contractAddress) if senderBalance < endowment: debug "Computation Failure", reason = "Insufficient funds available to transfer", @@ -129,38 +130,35 @@ const balance = senderBalance return - var createMsgGas = k.cpt.gasMeter.gasRemaining - if k.cpt.fork >= FkTangerine: + var createMsgGas = cpt.gasMeter.gasRemaining + if cpt.fork >= FkTangerine: createMsgGas -= createMsgGas div 64 - k.cpt.gasMeter.consumeGas(createMsgGas, reason = "CREATE") - - gasCost = gasAtStart - k.cpt.gasMeter.gasRemaining - k.cpt.traceCallFamilyGas(Create, gasCost) + cpt.gasMeter.consumeGas(createMsgGas, reason = "CREATE msg gas") when evmc_enabled: let msg = new(nimbus_message) - c = k.cpt + c = cpt msg[] = nimbus_message( kind: evmcCreate.ord.evmc_call_kind, - depth: (k.cpt.msg.depth + 1).int32, + depth: (cpt.msg.depth + 1).int32, gas: createMsgGas, - sender: k.cpt.msg.contractAddress, - input_data: k.cpt.memory.readPtr(memPos), + sender: cpt.msg.contractAddress, + input_data: cpt.memory.readPtr(memPos), input_size: memLen.uint, value: toEvmc(endowment), create2_salt: toEvmc(ZERO_CONTRACTSALT), ) c.execSubCreate(msg) else: - k.cpt.execSubCreate( + cpt.execSubCreate( childMsg = Message( kind: evmcCreate, - depth: k.cpt.msg.depth + 1, + depth: cpt.msg.depth + 1, gas: createMsgGas, - sender: k.cpt.msg.contractAddress, + sender: cpt.msg.contractAddress, value: endowment, - data: k.cpt.memory.read(memPos, memLen))) + data: cpt.memory.read(memPos, memLen))) # --------------------- @@ -169,44 +167,44 @@ const checkInStaticContext(k.cpt) let - endowment = k.cpt.stack.popInt() - memPos = k.cpt.stack.popInt().safeInt - memLen = k.cpt.stack.popInt().safeInt - salt = ContractSalt(bytes: k.cpt.stack.peekInt().toBytesBE) + cpt = k.cpt + endowment = cpt.stack.popInt() + memPos = cpt.stack.popInt().safeInt + memLen = cpt.stack.popInt().safeInt + salt = ContractSalt(bytes: cpt.stack.peekInt().toBytesBE) - k.cpt.stack.top(0) + cpt.stack.top(0) # EIP-3860 - if k.cpt.fork >= FkShanghai and memLen > EIP3860_MAX_INITCODE_SIZE: + if cpt.fork >= FkShanghai and memLen > EIP3860_MAX_INITCODE_SIZE: trace "Initcode size exceeds maximum", initcodeSize = memLen raise newException(InitcodeError, &"CREATE2: have {memLen}, max {EIP3860_MAX_INITCODE_SIZE}") let - gasAtStart = k.cpt.gasMeter.gasRemaining gasParams = GasParams( kind: Create, - cr_currentMemSize: k.cpt.memory.len, + cr_currentMemSize: cpt.memory.len, cr_memOffset: memPos, cr_memLength: memLen) - var gasCost = k.cpt.gasCosts[Create].c_handler(1.u256, gasParams).gasCost - gasCost = gasCost + k.cpt.gasCosts[Create2].m_handler(0, 0, memLen) + var gasCost = cpt.gasCosts[Create].c_handler(1.u256, gasParams).gasCost + gasCost = gasCost + cpt.gasCosts[Create2].m_handler(0, 0, memLen) - k.cpt.gasMeter.consumeGas( + cpt.opcodeGastCost(Create2, gasCost, reason = &"CREATE2: GasCreate + {memLen} * memory expansion") - k.cpt.memory.extend(memPos, memLen) - k.cpt.returnData.setLen(0) + cpt.memory.extend(memPos, memLen) + cpt.returnData.setLen(0) - if k.cpt.msg.depth >= MaxCallDepth: + if cpt.msg.depth >= MaxCallDepth: debug "Computation Failure", reason = "Stack too deep", maxDepth = MaxCallDepth, - depth = k.cpt.msg.depth + depth = cpt.msg.depth return if endowment != 0: - let senderBalance = k.cpt.getBalance(k.cpt.msg.contractAddress) + let senderBalance = cpt.getBalance(cpt.msg.contractAddress) if senderBalance < endowment: debug "Computation Failure", reason = "Insufficient funds available to transfer", @@ -214,39 +212,36 @@ const balance = senderBalance return - var createMsgGas = k.cpt.gasMeter.gasRemaining - if k.cpt.fork >= FkTangerine: + var createMsgGas = cpt.gasMeter.gasRemaining + if cpt.fork >= FkTangerine: createMsgGas -= createMsgGas div 64 - k.cpt.gasMeter.consumeGas(createMsgGas, reason = "CREATE2") - - gasCost = gasAtStart - k.cpt.gasMeter.gasRemaining - k.cpt.traceCallFamilyGas(Create2, gasCost) + cpt.gasMeter.consumeGas(createMsgGas, reason = "CREATE2 msg gas") when evmc_enabled: let msg = new(nimbus_message) - c = k.cpt + c = cpt msg[] = nimbus_message( kind: evmcCreate2.ord.evmc_call_kind, - depth: (k.cpt.msg.depth + 1).int32, + depth: (cpt.msg.depth + 1).int32, gas: createMsgGas, - sender: k.cpt.msg.contractAddress, - input_data: k.cpt.memory.readPtr(memPos), + sender: cpt.msg.contractAddress, + input_data: cpt.memory.readPtr(memPos), input_size: memLen.uint, value: toEvmc(endowment), create2_salt: toEvmc(salt), ) c.execSubCreate(msg) else: - k.cpt.execSubCreate( + cpt.execSubCreate( salt = salt, childMsg = Message( kind: evmcCreate2, - depth: k.cpt.msg.depth + 1, + depth: cpt.msg.depth + 1, gas: createMsgGas, - sender: k.cpt.msg.contractAddress, + sender: cpt.msg.contractAddress, value: endowment, - data: k.cpt.memory.read(memPos, memLen))) + data: cpt.memory.read(memPos, memLen))) # ------------------------------------------------------------------------------ # Public, op exec table entries diff --git a/nimbus/evm/interpreter/op_handlers/oph_envinfo.nim b/nimbus/evm/interpreter/op_handlers/oph_envinfo.nim index 08cb728cb..0e26b0422 100644 --- a/nimbus/evm/interpreter/op_handlers/oph_envinfo.nim +++ b/nimbus/evm/interpreter/op_handlers/oph_envinfo.nim @@ -20,7 +20,6 @@ import ../../stack, ../../async/operations, ../gas_costs, - ../gas_meter, ../op_codes, ../utils/utils_numeric, ./oph_defs, @@ -84,7 +83,8 @@ const let address = cpt.stack.popAddress() cpt.asyncChainTo(ifNecessaryGetAccount(cpt.vmState, address)): - cpt.gasEip2929AccountCheck(address) + let gasCost = cpt.gasCosts[Balance].cost + cpt.gasEip2929AccountCheck(address) + cpt.opcodeGastCost(Balance, gasCost, reason = "Balance EIP2929") cpt.stack.push: cpt.getBalance(address) @@ -140,7 +140,7 @@ const let (memPos, copyPos, len) = (memStartPos.cleanMemRef, copyStartPos.cleanMemRef, size.cleanMemRef) - k.cpt.gasMeter.consumeGas( + k.cpt.opcodeGastCost(CallDataCopy, k.cpt.gasCosts[CallDataCopy].m_handler(k.cpt.memory.len, memPos, len), reason = "CallDataCopy fee") @@ -165,7 +165,7 @@ const let (memPos, copyPos, len) = (memStartPos.cleanMemRef, copyStartPos.cleanMemRef, size.cleanMemRef) - cpt.gasMeter.consumeGas( + cpt.opcodeGastCost(CodeCopy, cpt.gasCosts[CodeCopy].m_handler(cpt.memory.len, memPos, len), reason = "CodeCopy fee") @@ -193,7 +193,8 @@ const let address = cpt.stack.popAddress() cpt.asyncChainTo(ifNecessaryGetCode(cpt.vmState, address)): - cpt.gasEip2929AccountCheck(address) + let gasCost = cpt.gasCosts[ExtCodeSize].cost + cpt.gasEip2929AccountCheck(address) + cpt.opcodeGastCost(ExtCodeSize, gasCost, reason = "ExtCodeSize EIP2929") cpt.stack.push: cpt.getCodeSize(address) @@ -209,7 +210,7 @@ const let (memPos, codePos, len) = (memStartPos.cleanMemRef, codeStartPos.cleanMemRef, size.cleanMemRef) - cpt.gasMeter.consumeGas( + cpt.opcodeGastCost(ExtCodeCopy, cpt.gasCosts[ExtCodeCopy].m_handler(cpt.memory.len, memPos, len), reason = "ExtCodeCopy fee") @@ -226,11 +227,10 @@ const let (memStartPos, codeStartPos, size) = cpt.stack.popInt(3) let (memPos, codePos, len) = (memStartPos.cleanMemRef, codeStartPos.cleanMemRef, size.cleanMemRef) - cpt.gasMeter.consumeGas( - cpt.gasCosts[ExtCodeCopy].m_handler(cpt.memory.len, memPos, len), - reason = "ExtCodeCopy fee") - cpt.gasEip2929AccountCheck(address) + let gasCost = cpt.gasCosts[ExtCodeCopy].m_handler(cpt.memory.len, memPos, len) + + cpt.gasEip2929AccountCheck(address) + cpt.opcodeGastCost(ExtCodeCopy, gasCost, reason = "ExtCodeCopy EIP2929") let codeBytes = cpt.getCode(address) cpt.memory.writePaddedResult(codeBytes, memPos, codePos, len) @@ -253,7 +253,7 @@ const let gasCost = k.cpt.gasCosts[ReturnDataCopy].m_handler( k.cpt.memory.len, memPos, len) - k.cpt.gasMeter.consumeGas(gasCost, reason = "returnDataCopy fee") + k.cpt.opcodeGastCost(ReturnDataCopy, gasCost, reason = "returnDataCopy fee") if copyPos + len > k.cpt.returnData.len: raise newException( @@ -280,7 +280,8 @@ const let address = k.cpt.stack.popAddress() cpt.asyncChainTo(ifNecessaryGetCode(cpt.vmState, address)): - cpt.gasEip2929AccountCheck(address) + let gasCost = cpt.gasCosts[ExtCodeHash].cost + cpt.gasEip2929AccountCheck(address) + cpt.opcodeGastCost(ExtCodeHash, gasCost, reason = "ExtCodeHash EIP2929") cpt.stack.push: cpt.getCodeHash(address) diff --git a/nimbus/evm/interpreter/op_handlers/oph_hash.nim b/nimbus/evm/interpreter/op_handlers/oph_hash.nim index 16014bfeb..ad7c0b221 100644 --- a/nimbus/evm/interpreter/op_handlers/oph_hash.nim +++ b/nimbus/evm/interpreter/op_handlers/oph_hash.nim @@ -19,7 +19,6 @@ import ../../memory, ../../stack, ../gas_costs, - ../gas_meter, ../op_codes, ../utils/utils_numeric, ./oph_defs, @@ -40,7 +39,7 @@ const if pos < 0 or len < 0 or pos > 2147483648'i64: raise newException(OutOfBoundsRead, "Out of bounds memory access") - k.cpt.gasMeter.consumeGas( + k.cpt.opcodeGastCost(Op.Sha3, k.cpt.gasCosts[Op.Sha3].m_handler(k.cpt.memory.len, pos, len), reason = "SHA3: word gas cost") diff --git a/nimbus/evm/interpreter/op_handlers/oph_helpers.nim b/nimbus/evm/interpreter/op_handlers/oph_helpers.nim index e2279205b..e2e56df0f 100644 --- a/nimbus/evm/interpreter/op_handlers/oph_helpers.nim +++ b/nimbus/evm/interpreter/op_handlers/oph_helpers.nim @@ -18,7 +18,6 @@ import ../../../errors, ../../types, ../gas_costs, - ../gas_meter, eth/common, eth/common/eth_types, macros, @@ -35,26 +34,33 @@ else: # Public # ------------------------------------------------------------------------------ -proc gasEip2929AccountCheck*(c: Computation; address: EthAddress) = +proc gasEip2929AccountCheck*(c: Computation; address: EthAddress): GasInt = when defined(evmc_enabled): - let gasCost = if c.host.accessAccount(address) == EVMC_ACCESS_COLD: - ColdAccountAccessCost - else: - WarmStorageReadCost - c.gasMeter.consumeGas( - gasCost, - reason = "gasEIP2929AccountCheck") + result = if c.host.accessAccount(address) == EVMC_ACCESS_COLD: + ColdAccountAccessCost + else: + WarmStorageReadCost else: c.vmState.mutateStateDB: - let gasCost = if not db.inAccessList(address): - db.accessList(address) - ColdAccountAccessCost - else: - WarmStorageReadCost + result = if not db.inAccessList(address): + db.accessList(address) + ColdAccountAccessCost + else: + WarmStorageReadCost - c.gasMeter.consumeGas( - gasCost, - reason = "gasEIP2929AccountCheck") +proc gasEip2929AccountCheck*(c: Computation; address: EthAddress, slot: UInt256): GasInt = + when defined(evmc_enabled): + result = if c.host.accessStorage(address, slot) == EVMC_ACCESS_COLD: + ColdSloadCost + else: + WarmStorageReadCost + else: + c.vmState.mutateStateDB: + result = if not db.inAccessList(address, slot): + db.accessList(address, slot) + ColdSloadCost + else: + WarmStorageReadCost template checkInStaticContext*(c: Computation) = ## Verify static context in handler function, raise an error otherwise diff --git a/nimbus/evm/interpreter/op_handlers/oph_log.nim b/nimbus/evm/interpreter/op_handlers/oph_log.nim index 6331af88b..1fa83e41f 100644 --- a/nimbus/evm/interpreter/op_handlers/oph_log.nim +++ b/nimbus/evm/interpreter/op_handlers/oph_log.nim @@ -20,7 +20,6 @@ import ../../stack, ../../types, ../gas_costs, - ../gas_meter, ../op_codes, ../utils/utils_numeric, ./oph_defs, @@ -59,7 +58,7 @@ proc logImpl(c: Computation, opcode: Op, topicCount: int) = if memPos < 0 or len < 0: raise newException(OutOfBoundsRead, "Out of bounds memory access") - c.gasMeter.consumeGas( + c.opcodeGastCost(opcode, c.gasCosts[opcode].m_handler(c.memory.len, memPos, len), reason = "Memory expansion, Log topic and data gas cost") c.memory.extend(memPos, len) diff --git a/nimbus/evm/interpreter/op_handlers/oph_memory.nim b/nimbus/evm/interpreter/op_handlers/oph_memory.nim index f355e892c..b992d9a3c 100644 --- a/nimbus/evm/interpreter/op_handlers/oph_memory.nim +++ b/nimbus/evm/interpreter/op_handlers/oph_memory.nim @@ -41,15 +41,14 @@ when not defined(evmc_enabled): # ------------------------------------------------------------------------------ when evmc_enabled: - proc sstoreEvmc(c: Computation, slot, newValue: UInt256) = + proc sstoreEvmc(c: Computation, slot, newValue: UInt256, coldAccess = 0.GasInt) = let currentValue = c.getStorage(slot) status = c.host.setStorage(c.msg.contractAddress, slot, newValue) gasParam = GasParams(kind: Op.Sstore, s_status: status) - gasCost = c.gasCosts[Sstore].c_handler(newValue, gasParam)[0] + gasCost = c.gasCosts[Sstore].c_handler(newValue, gasParam)[0] + coldAccess - c.gasMeter.consumeGas( - gasCost, "SSTORE") + c.opcodeGastCost(Sstore, gasCost, "SSTORE") else: proc sstoreImpl(c: Computation, slot, newValue: UInt256) = @@ -62,8 +61,7 @@ else: (gasCost, gasRefund) = c.gasCosts[Sstore].c_handler(newValue, gasParam) - c.gasMeter.consumeGas( - gasCost, "SSTORE") + c.opcodeGastCost(Sstore, gasCost, "SSTORE") if gasRefund > 0: c.gasMeter.refundGas(gasRefund) @@ -71,7 +69,7 @@ else: db.setStorage(c.msg.contractAddress, slot, newValue) - proc sstoreNetGasMeteringImpl(c: Computation; slot, newValue: UInt256) = + proc sstoreNetGasMeteringImpl(c: Computation; slot, newValue: UInt256, coldAccess = 0.GasInt) = let stateDB = c.vmState.readOnlyStateDB currentValue = c.getStorage(slot) @@ -81,17 +79,21 @@ else: s_currentValue: currentValue, s_originalValue: stateDB.getCommittedStorage(c.msg.contractAddress, slot)) - (gasCost, gasRefund) = c.gasCosts[Sstore].c_handler(newValue, gasParam) + res = c.gasCosts[Sstore].c_handler(newValue, gasParam) - c.gasMeter.consumeGas( - gasCost, "SSTORE EIP2200") + c.opcodeGastCost(Sstore, res.gasCost + coldAccess, "SSTORE") - if gasRefund != 0: - c.gasMeter.refundGas(gasRefund) + if res.gasRefund != 0: + c.gasMeter.refundGas(res.gasRefund) c.vmState.mutateStateDB: db.setStorage(c.msg.contractAddress, slot, newValue) +template sstoreEvmcOrNetGasMetering(cpt, slot, newValue: untyped, coldAccess = 0.GasInt) = + when evmc_enabled: + sstoreEvmc(cpt, slot, newValue, coldAccess) + else: + sstoreNetGasMeteringImpl(cpt, slot, newValue, coldAccess) proc jumpImpl(c: Computation; jumpTarget: UInt256) = if jumpTarget >= c.code.len.u256: @@ -124,7 +126,7 @@ const let (memStartPos) = k.cpt.stack.popInt(1) let memPos = memStartPos.cleanMemRef - k.cpt.gasMeter.consumeGas( + k.cpt.opcodeGastCost(Mload, k.cpt.gasCosts[Mload].m_handler(k.cpt.memory.len, memPos, 32), reason = "MLOAD: GasVeryLow + memory expansion") @@ -138,7 +140,7 @@ const let (memStartPos, value) = k.cpt.stack.popInt(2) let memPos = memStartPos.cleanMemRef - k.cpt.gasMeter.consumeGas( + k.cpt.opcodeGastCost(Mstore, k.cpt.gasCosts[Mstore].m_handler(k.cpt.memory.len, memPos, 32), reason = "MSTORE: GasVeryLow + memory expansion") @@ -151,8 +153,8 @@ const let (memStartPos, value) = k.cpt.stack.popInt(2) let memPos = memStartPos.cleanMemRef - k.cpt.gasMeter.consumeGas( - k.cpt.gasCosts[Mstore].m_handler(k.cpt.memory.len, memPos, 1), + k.cpt.opcodeGastCost(Mstore8, + k.cpt.gasCosts[Mstore8].m_handler(k.cpt.memory.len, memPos, 1), reason = "MSTORE8: GasVeryLow + memory expansion") k.cpt.memory.extend(memPos, 1) @@ -174,20 +176,9 @@ const let (slot) = cpt.stack.popInt(1) cpt.asyncChainTo(ifNecessaryGetSlot(cpt.vmState, cpt.msg.contractAddress, slot)): - when evmc_enabled: - let gasCost = if cpt.host.accessStorage(cpt.msg.contractAddress, slot) == EVMC_ACCESS_COLD: - ColdSloadCost - else: - WarmStorageReadCost - cpt.gasMeter.consumeGas(gasCost, reason = "sloadEIP2929") - else: - cpt.vmState.mutateStateDB: - let gasCost = if not db.inAccessList(cpt.msg.contractAddress, slot): - db.accessList(cpt.msg.contractAddress, slot) - ColdSloadCost - else: - WarmStorageReadCost - cpt.gasMeter.consumeGas(gasCost, reason = "sloadEIP2929") + let gasCost = cpt.gasEip2929AccountCheck(cpt.msg.contractAddress, slot) + + cpt.gasCosts[Sload].cost + cpt.opcodeGastCost(Sload, gasCost, reason = "sloadEIP2929") cpt.stack.push: cpt.getStorage(slot) @@ -200,10 +191,7 @@ const checkInStaticContext(cpt) cpt.asyncChainTo(ifNecessaryGetSlot(cpt.vmState, cpt.msg.contractAddress, slot)): - when evmc_enabled: - sstoreEvmc(cpt, slot, newValue) - else: - sstoreImpl(cpt, slot, newValue) + sstoreEvmcOrNetGasMetering(cpt, slot, newValue) sstoreEIP1283Op: Vm2OpFn = proc (k: var Vm2Ctx) = @@ -213,10 +201,7 @@ const checkInStaticContext(cpt) cpt.asyncChainTo(ifNecessaryGetSlot(cpt.vmState, cpt.msg.contractAddress, slot)): - when evmc_enabled: - sstoreEvmc(cpt, slot, newValue) - else: - sstoreNetGasMeteringImpl(cpt, slot, newValue) + sstoreEvmcOrNetGasMetering(cpt, slot, newValue) sstoreEIP2200Op: Vm2OpFn = proc (k: var Vm2Ctx) = @@ -233,10 +218,7 @@ const "Gas not enough to perform EIP2200 SSTORE") cpt.asyncChainTo(ifNecessaryGetSlot(cpt.vmState, cpt.msg.contractAddress, slot)): - when evmc_enabled: - sstoreEvmc(cpt, slot, newValue) - else: - sstoreNetGasMeteringImpl(cpt, slot, newValue) + sstoreEvmcOrNetGasMetering(cpt, slot, newValue) sstoreEIP2929Op: Vm2OpFn = proc (k: var Vm2Ctx) = @@ -252,19 +234,17 @@ const raise newException(OutOfGas, "Gas not enough to perform EIP2200 SSTORE") cpt.asyncChainTo(ifNecessaryGetSlot(cpt.vmState, cpt.msg.contractAddress, slot)): + var coldAccessGas = 0.GasInt when evmc_enabled: if cpt.host.accessStorage(cpt.msg.contractAddress, slot) == EVMC_ACCESS_COLD: - cpt.gasMeter.consumeGas(ColdSloadCost, reason = "sstoreEIP2929") + coldAccessGas = ColdSloadCost else: cpt.vmState.mutateStateDB: if not db.inAccessList(cpt.msg.contractAddress, slot): db.accessList(cpt.msg.contractAddress, slot) - cpt.gasMeter.consumeGas(ColdSloadCost, reason = "sstoreEIP2929") + coldAccessGas = ColdSloadCost - when evmc_enabled: - sstoreEvmc(cpt, slot, newValue) - else: - sstoreNetGasMeteringImpl(cpt, slot, newValue) + sstoreEvmcOrNetGasMetering(cpt, slot, newValue, coldAccessGas) # ------- @@ -324,7 +304,7 @@ const let (dstPos, srcPos, len) = (dst.cleanMemRef, src.cleanMemRef, size.cleanMemRef) - k.cpt.gasMeter.consumeGas( + k.cpt.opcodeGastCost(Mcopy, k.cpt.gasCosts[Mcopy].m_handler(k.cpt.memory.len, max(dstPos, srcPos), len), reason = "Mcopy fee") diff --git a/nimbus/evm/interpreter/op_handlers/oph_sysops.nim b/nimbus/evm/interpreter/op_handlers/oph_sysops.nim index 4cddc5cce..68125dbe7 100644 --- a/nimbus/evm/interpreter/op_handlers/oph_sysops.nim +++ b/nimbus/evm/interpreter/op_handlers/oph_sysops.nim @@ -20,7 +20,6 @@ import ../../types, ../../async/operations, ../gas_costs, - ../gas_meter, ../op_codes, ../utils/utils_numeric, ./oph_defs, @@ -45,7 +44,7 @@ const let (startPos, size) = k.cpt.stack.popInt(2) let (pos, len) = (startPos.cleanMemRef, size.cleanMemRef) - k.cpt.gasMeter.consumeGas( + k.cpt.opcodeGastCost(Return, k.cpt.gasCosts[Return].m_handler(k.cpt.memory.len, pos, len), reason = "RETURN") k.cpt.memory.extend(pos, len) @@ -58,7 +57,7 @@ const let (startPos, size) = k.cpt.stack.popInt(2) let (pos, len) = (startPos.cleanMemRef, size.cleanMemRef) - k.cpt.gasMeter.consumeGas( + k.cpt.opcodeGastCost(Revert, k.cpt.gasCosts[Revert].m_handler(k.cpt.memory.len, pos, len), reason = "REVERT") @@ -95,7 +94,7 @@ const let gasCost = cpt.gasCosts[SelfDestruct].c_handler(0.u256, gasParams).gasCost - cpt.gasMeter.consumeGas( + cpt.opcodeGastCost(SelfDestruct, gasCost, reason = "SELFDESTRUCT EIP150") cpt.selfDestruct(beneficiary) @@ -117,7 +116,7 @@ const let gasCost = cpt.gasCosts[SelfDestruct].c_handler(0.u256, gasParams).gasCost - cpt.gasMeter.consumeGas( + cpt.opcodeGastCost(SelfDestruct, gasCost, reason = "SELFDESTRUCT EIP161") cpt.selfDestruct(beneficiary) @@ -149,7 +148,7 @@ const db.accessList(beneficiary) gasCost = gasCost + ColdAccountAccessCost - cpt.gasMeter.consumeGas( + cpt.opcodeGastCost(SelfDestruct, gasCost, reason = "SELFDESTRUCT EIP2929") cpt.selfDestruct(beneficiary) diff --git a/nimbus/evm/precompiles.nim b/nimbus/evm/precompiles.nim index 4dfe3761e..817baabad 100644 --- a/nimbus/evm/precompiles.nim +++ b/nimbus/evm/precompiles.nim @@ -34,6 +34,7 @@ type paPairing = 0x08, # Istanbul paBlake2bf = 0x09, + paPointEvaluation = 0x0A # Berlin # EIP-2537: disabled # reason: not included in berlin @@ -47,7 +48,7 @@ type # paBlsMapG1 # paBlsMapG2 # Cancun - paPointEvaluation = 0x0A + proc getMaxPrecompileAddr(fork: EVMFork): PrecompileAddresses = if fork < FkByzantium: paIdentity @@ -705,7 +706,7 @@ proc execPrecompiles*(computation: Computation, fork: EVMFork): bool {.inline.} of paPairing: bn256ecPairing(computation, fork) of paBlake2bf: blake2bf(computation) of paPointEvaluation: pointEvaluation(computation) - else: discard + #else: discard # EIP 2537: disabled # reason: not included in berlin # of paBlsG1Add: blsG1Add(computation) diff --git a/nimbus/evm/state.nim b/nimbus/evm/state.nim index 4bd1a117a..f45620eb6 100644 --- a/nimbus/evm/state.nim +++ b/nimbus/evm/state.nim @@ -17,7 +17,7 @@ import ../db/accounts_cache, ../common/[common, evmforks], ./async/data_sources, - ./interpreter/op_codes, + ./interpreter/[op_codes, gas_costs], ./types proc init( @@ -391,28 +391,32 @@ proc captureOpStart*(vmState: BaseVMState, comp: Computation, pc: int, op: Op, gas: GasInt, depth: int): int = if vmState.tracingEnabled: - result = vmState.tracer.captureOpStart(comp, pc, op, gas, depth) + let fixed = vmState.gasCosts[op].kind == GckFixed + result = vmState.tracer.captureOpStart(comp, fixed, pc, op, gas, depth) -proc callFamilyGas*(vmState: BaseVMState, +proc captureGasCost*(vmState: BaseVMState, comp: Computation, - op: Op, gas: GasInt, + op: Op, gasCost: GasInt, gasRemaining: GasInt, depth: int) = if vmState.tracingEnabled: - vmState.tracer.callFamilyGas(comp, op, gas, depth) + let fixed = vmState.gasCosts[op].kind == GckFixed + vmState.tracer.captureGasCost(comp, fixed, op, gasCost, gasRemaining, depth) proc captureOpEnd*(vmState: BaseVMState, comp: Computation, pc: int, op: Op, gas: GasInt, refund: GasInt, rData: openArray[byte], depth: int, opIndex: int) = if vmState.tracingEnabled: - vmState.tracer.captureOpEnd(comp, pc, op, gas, refund, rData, depth, opIndex) + let fixed = vmState.gasCosts[op].kind == GckFixed + vmState.tracer.captureOpEnd(comp, fixed, pc, op, gas, refund, rData, depth, opIndex) proc captureFault*(vmState: BaseVMState, comp: Computation, pc: int, op: Op, gas: GasInt, refund: GasInt, rData: openArray[byte], depth: int, error: Option[string]) = if vmState.tracingEnabled: - vmState.tracer.captureFault(comp, pc, op, gas, refund, rData, depth, error) + let fixed = vmState.gasCosts[op].kind == GckFixed + vmState.tracer.captureFault(comp, fixed, pc, op, gas, refund, rData, depth, error) proc capturePrepare*(vmState: BaseVMState, comp: Computation, depth: int) = if vmState.tracingEnabled: diff --git a/nimbus/evm/tracer/json_tracer.nim b/nimbus/evm/tracer/json_tracer.nim index 7a9469f06..bd5157865 100644 --- a/nimbus/evm/tracer/json_tracer.nim +++ b/nimbus/evm/tracer/json_tracer.nim @@ -28,17 +28,7 @@ type stack: JsonNode storageKeys: seq[HashSet[UInt256]] index: int - callFamilyNode: JsonNode - -const - callFamily = [ - Create, - Create2, - Call, - CallCode, - DelegateCall, - StaticCall, - ] + node: JsonNode template stripLeadingZeros(value: string): string = var cidx = 0 @@ -47,9 +37,12 @@ template stripLeadingZeros(value: string): string = cidx.inc value[cidx .. ^1] -proc encodeHexInt(x: SomeInteger): JsonNode = +proc encodeHex(x: SomeInteger): JsonNode = %("0x" & x.toHex.stripLeadingZeros.toLowerAscii) +proc encodeHex(x: UInt256): string = + "0x" & x.dumpHex.stripLeadingZeros + proc `%`(x: openArray[byte]): JsonNode = if x.len == 0: %("") @@ -77,16 +70,15 @@ iterator storage(ctx: JsonTracer, compDepth: int): UInt256 = proc captureOpImpl(ctx: JsonTracer, c: Computation, pc: int, op: Op, gas: GasInt, refund: GasInt, - rData: openArray[byte], - depth: int, error: Option[string]) {.gcsafe.} = + rData: openArray[byte], depth: int, error: Option[string]) {.gcsafe.} = let gasCost = ctx.gas - gas var res = %{ "pc": %(ctx.pc), "op": %(op.int), - "gas": encodeHexInt(ctx.gas), - "gasCost": encodeHexInt(gasCost), + "gas": encodeHex(ctx.gas), + "gasCost": encodeHex(gasCost), "memSize": %(c.memory.len) } @@ -114,8 +106,7 @@ proc captureOpImpl(ctx: JsonTracer, c: Computation, pc: int, var stateDB = c.vmState.stateDB for key in ctx.storage(c.msg.depth): let value = stateDB.getStorage(c.msg.contractAddress, key) - storage["0x" & key.dumpHex.stripLeadingZeros] = - %("0x" & value.dumpHex.stripLeadingZeros) + storage[key.encodeHex] = %(value.encodeHex) res["storage"] = storage res["depth"] = %(depth) @@ -125,10 +116,7 @@ proc captureOpImpl(ctx: JsonTracer, c: Computation, pc: int, if error.isSome: res["error"] = %(error.get) - if op in callFamily: - ctx.callFamilyNode = res - else: - ctx.writeJson(res) + ctx.node = res proc newJsonTracer*(stream: Stream, flags: set[TracerFlags], pretty: bool): JsonTracer = JsonTracer( @@ -157,15 +145,15 @@ method captureEnd*(ctx: JsonTracer, comp: Computation, output: openArray[byte], gasUsed: GasInt, error: Option[string]) {.gcsafe.} = var res = %{ "output": %(output), - "gasUsed": encodeHexInt(gasUsed) + "gasUsed": encodeHex(gasUsed) } if error.isSome: res["error"] = %(error.get()) ctx.writeJson(res) # Opcode level -method captureOpStart*(ctx: JsonTracer, c: Computation, pc: int, - op: Op, gas: GasInt, +method captureOpStart*(ctx: JsonTracer, c: Computation, + fixed: bool, pc: int, op: Op, gas: GasInt, depth: int): int {.gcsafe.} = ctx.gas = gas ctx.pc = pc @@ -173,7 +161,7 @@ method captureOpStart*(ctx: JsonTracer, c: Computation, pc: int, if TracerFlags.DisableStack notin ctx.flags: ctx.stack = newJArray() for v in c.stack.values: - ctx.stack.add(%("0x" & v.dumpHex.stripLeadingZeros)) + ctx.stack.add(%(v.encodeHex)) if TracerFlags.DisableStorage notin ctx.flags and op == SSTORE: try: @@ -184,47 +172,71 @@ method captureOpStart*(ctx: JsonTracer, c: Computation, pc: int, except ValueError as ex: error "JsonTracer captureOpStart", msg=ex.msg - if op in callFamily: - try: - ctx.captureOpImpl(c, pc, op, 0, 0, [], depth, none(string)) - except RlpError as ex: - error "JsonTracer captureOpEnd", msg=ex.msg + try: + ctx.captureOpImpl(c, pc, op, 0, 0, [], depth, none(string)) + except RlpError as ex: + error "JsonTracer captureOpStart", msg=ex.msg # make sure captureOpEnd get the right opIndex result = ctx.index inc ctx.index -method callFamilyGas*(ctx: JsonTracer, comp: Computation, - op: Op, gas: GasInt, - depth: int) {.gcsafe.} = - doAssert(op in callFamily) - doAssert(ctx.callFamilyNode.isNil.not) - let res = ctx.callFamilyNode - res["gasCost"] = encodeHexInt(gas) - ctx.writeJson(res) +method captureGasCost*(ctx: JsonTracer, comp: Computation, + fixed: bool, op: Op, gasCost: GasInt, gasRemaining: GasInt, + depth: int) {.gcsafe.} = + doAssert(ctx.node.isNil.not) + let res = ctx.node + res["gasCost"] = encodeHex(gasCost) -method captureOpEnd*(ctx: JsonTracer, comp: Computation, pc: int, - op: Op, gas: GasInt, refund: GasInt, + if gasCost <= gasRemaining and not fixed: + ctx.writeJson(res) + ctx.node = nil + # else: + # OOG will be handled by captureFault + # opcode with fixed gasCost will be handled by captureOpEnd + +method captureOpEnd*(ctx: JsonTracer, comp: Computation, + fixed: bool, pc: int, op: Op, gas: GasInt, refund: GasInt, rData: openArray[byte], depth: int, opIndex: int) {.gcsafe.} = + if fixed: + doAssert(ctx.node.isNil.not) + let res = ctx.node + res["refund"] = %(refund) - if op in callFamily: - # call family opcode is processed in captureOpStart + if TracerFlags.DisableReturnData notin ctx.flags: + res["returnData"] = %(rData) + + ctx.writeJson(res) + ctx.node = nil + return + +method captureFault*(ctx: JsonTracer, comp: Computation, + fixed: bool, pc: int, op: Op, gas: GasInt, refund: GasInt, + rData: openArray[byte], + depth: int, error: Option[string]) {.gcsafe.} = + + if ctx.node.isNil.not: + let res = ctx.node + res["refund"] = %(refund) + + if TracerFlags.DisableReturnData notin ctx.flags: + res["returnData"] = %(rData) + + if error.isSome: + res["error"] = %(error.get) + + ctx.writeJson(res) + ctx.node = nil return - try: - ctx.captureOpImpl(comp, pc, op, gas, refund, rData, depth, none(string)) - except RlpError as ex: - error "JsonTracer captureOpEnd", msg=ex.msg - -method captureFault*(ctx: JsonTracer, comp: Computation, pc: int, - op: Op, gas: GasInt, refund: GasInt, - rData: openArray[byte], - depth: int, error: Option[string]) {.gcsafe.} = try: ctx.captureOpImpl(comp, pc, op, gas, refund, rData, depth, error) + doAssert(ctx.node.isNil.not) + ctx.writeJson(ctx.node) + ctx.node = nil except RlpError as ex: - error "JsonTracer captureOpEnd", msg=ex.msg + error "JsonTracer captureOpFault", msg=ex.msg proc close*(ctx: JsonTracer) = ctx.stream.close() diff --git a/nimbus/evm/tracer/legacy_tracer.nim b/nimbus/evm/tracer/legacy_tracer.nim index 479a20590..b203aa179 100644 --- a/nimbus/evm/tracer/legacy_tracer.nim +++ b/nimbus/evm/tracer/legacy_tracer.nim @@ -71,8 +71,8 @@ method capturePrepare*(ctx: LegacyTracer, comp: Computation, depth: int) {.gcsaf ctx.storageKeys[depth] = initHashSet[UInt256]() # Opcode level -method captureOpStart*(ctx: LegacyTracer, c: Computation, pc: int, - op: Op, gas: GasInt, +method captureOpStart*(ctx: LegacyTracer, c: Computation, + fixed: bool, pc: int, op: Op, gas: GasInt, depth: int): int {.gcsafe.} = try: let @@ -126,8 +126,8 @@ method captureOpStart*(ctx: LegacyTracer, c: Computation, pc: int, except InsufficientStack as ex: error "LegacyTracer captureOpEnd", msg=ex.msg -method captureOpEnd*(ctx: LegacyTracer, c: Computation, pc: int, - op: Op, gas: GasInt, refund: GasInt, +method captureOpEnd*(ctx: LegacyTracer, c: Computation, + fixed: bool, pc: int, op: Op, gas: GasInt, refund: GasInt, rData: openArray[byte], depth: int, opIndex: int) {.gcsafe.} = try: @@ -156,8 +156,8 @@ method captureOpEnd*(ctx: LegacyTracer, c: Computation, pc: int, except RlpError as ex: error "LegacyTracer captureOpEnd", msg=ex.msg -method captureFault*(ctx: LegacyTracer, comp: Computation, pc: int, - op: Op, gas: GasInt, refund: GasInt, +method captureFault*(ctx: LegacyTracer, comp: Computation, + fixed: bool, pc: int, op: Op, gas: GasInt, refund: GasInt, rData: openArray[byte], depth: int, error: Option[string]) {.gcsafe.} = try: diff --git a/nimbus/evm/types.nim b/nimbus/evm/types.nim index 6e00febae..24890caca 100644 --- a/nimbus/evm/types.nim +++ b/nimbus/evm/types.nim @@ -169,28 +169,28 @@ method captureExit*(ctx: TracerRef, comp: Computation, output: openArray[byte], discard # Opcode level -method captureOpStart*(ctx: TracerRef, comp: Computation, pc: int, - op: Op, gas: GasInt, +method captureOpStart*(ctx: TracerRef, comp: Computation, + fixed: bool, pc: int, op: Op, gas: GasInt, depth: int): int {.base, gcsafe.} = discard -method callFamilyGas*(ctx: TracerRef, comp: Computation, - op: Op, gas: GasInt, - depth: int) {.base, gcsafe.} = +method captureGasCost*(ctx: TracerRef, comp: Computation, + fixed: bool, op: Op, gasCost: GasInt, + gasRemaining: GasInt, depth: int) {.base, gcsafe.} = discard -method captureOpEnd*(ctx: TracerRef, comp: Computation, pc: int, - op: Op, gas: GasInt, refund: GasInt, +method captureOpEnd*(ctx: TracerRef, comp: Computation, + fixed: bool, pc: int, op: Op, gas: GasInt, refund: GasInt, rData: openArray[byte], depth: int, opIndex: int) {.base, gcsafe.} = discard -method captureFault*(ctx: TracerRef, comp: Computation, pc: int, - op: Op, gas: GasInt, refund: GasInt, +method captureFault*(ctx: TracerRef, comp: Computation, + fixed: bool, pc: int, op: Op, gas: GasInt, refund: GasInt, rData: openArray[byte], depth: int, error: Option[string]) {.base, gcsafe.} = discard - +# Called at the start of EVM interpreter loop method capturePrepare*(ctx: TracerRef, comp: Computation, depth: int) {.base, gcsafe.} = discard diff --git a/nimbus/vm_state.nim b/nimbus/vm_state.nim index 3d12211dc..040c35b9c 100644 --- a/nimbus/vm_state.nim +++ b/nimbus/vm_state.nim @@ -43,7 +43,7 @@ export vms.captureEnter, vms.captureExit, vms.captureOpStart, - vms.callFamilyGas, + vms.captureGasCost, vms.captureOpEnd, vms.captureFault, vms.capturePrepare diff --git a/tools/t8n/t8n_test.nim b/tools/t8n/t8n_test.nim index 1d9f0dd0b..feff82447 100644 --- a/tools/t8n/t8n_test.nim +++ b/tools/t8n/t8n_test.nim @@ -515,6 +515,15 @@ const output: T8nOutput(trace: true, result: true), expOut: "exp.txt", ), + TestSpec( + name : "EVM tracer CALL family exception", + base : "testdata/00-521", + input : t8nInput( + "alloc.json", "txs.json", "env.json", "Shanghai", "0", + ), + output: T8nOutput(trace: true, result: true), + expOut: "exp.txt", + ), ] proc main() = diff --git a/tools/t8n/testdata/00-521/alloc.json b/tools/t8n/testdata/00-521/alloc.json new file mode 100644 index 000000000..4f806b2e4 --- /dev/null +++ b/tools/t8n/testdata/00-521/alloc.json @@ -0,0 +1,68 @@ +{ + "0x00000000000000000000000000000000000000f1": { + "balance": "0x0", + "code": "0x600060006000600060fa5af4507f60095450600354506000600055600654507f60faff61507a6c957f60075450606000527fa06000536083600153600060025360f360036000527f536032600453600560606020527e527f055360606006536002600753606060085360006020527f6009536055606040527f0a536060600b536020527f6001600c536054600d536050600e536040527f60606060527f600f5360206010536060601153600060405260606060536012606153605360606080527f527f606253606060635360f3606453606060655360136066536053606753606060a0527f60686080527f5360146069536060606a536000606b5360f3606c536000606d6060c0527e6000f5600060a0527f6000600060006000855af15050823d76b158605c326060e0527e60006000600060006060c0527f095af250337583987e9360f4ff6000600060610100527e6000600060055af2509843046560e0527f468456603e5f3084576004545060610120527e600060006000600060f75af25091636563610100527f936a83180260006000610140527f60006000600060f85af2507e6001545060035450600060610120526000610140610160527f5360606101415360006101425360606101435360006101445360606101455360610180527f0561014653605a6101475360f461014853605061014953606061014a536000616101a0527f014b53606061014c53600461014d53605561014e53608d61014f53607d6101506101c0527f53605961015153607d61015253600961015353608f61015453606061015553606101e0527f0261015653606061015753600161015853605561015953606061015a5360206161020052600161022053605b61022153605361022253606061022353606061022453606161022553600161022653605c61022753605361022853606061022953600061022a53606161022b53600161022c53605d61022d53605361022e53606061022f5360fd61023053606161023153600161023253605e61023353605361023453606161023553600161023653605f6102375360606102385360006102395360f361023a53600061023b60006000f560006000600060006000855af25050", + "nonce": "0x0", + "storage": {} + }, + "0x00000000000000000000000000000000000000f2": { + "balance": "0x0", + "code": "0x60045450600060006000600060f55af450600060025560f9ff068c6a914360016003551cfe5a8a5e68fe50201d4265600bff60206000fd", + "nonce": "0x0", + "storage": {} + }, + "0x00000000000000000000000000000000000000f3": { + "balance": "0x0", + "code": "0x6001600255cf7f60005450600954506007545060065450600354507f6000600060006000600a5a6000527ff450600eff7f6000600355600354506002545060086000527f54507f7f6006546020527f507ff988b145087f887a6000527f34393a977050649aa3f47f6020527f6002606040527f015560066000527f546000527f50600554506020527f6000527f6004546040526060527f7f5060016003556001600255600060046020527f556000527f606040527f20526080527f7f6060527f6001600155600754506020527f600160045560026002556040527f60a0527f60016060526080527f7f600055600060006040527f556007546020527f50600360c0527f54506040527f60606060a0527f606080527f527f60005360026001536054600260e0527f536060527f605060035360506060c0527f045360616060a0527f40526080527f610100527f7f606060527f05536041600653605b600760e0527f6080527f53609f600860c0610120527f527f5360d760095360a0527f6060600a536000600b610100527f606080527f60610140527f527f536060606060e0527fa0527f0c536004600d5360c0527f60610120527f55610160527f600e536060600f536020601053606060610100527f60a0527f11536060c05261610180527f0140527f7f60805260e0527f600060a053606060a153601260a2610120527f536101a0527f605360a3610160527f53606060a4536060c05260e052610100527f7f7ffd60a56101c0527f53606060610140527f610180527fa653601360a753605360a853606060a953606101e0527f1460aa5360610120527f606101006101a0527f610160527f527f6060e0527fab610200527f53600060ac5360f360ad53600060ae600060006101c0527ff561014052610180610220527f527f7f600060006000610120527f6000600085610100527f6101e0527f5af150610240527f50507f918b6b6a6101a0527fa1610160527fa1760652600aff50103f45610200610260527f527f610140527ff1845e601917087f45796101c0527f61012052600b61018052610280527f7f61610220527f014053603761014153601461014253610160527f6101e0527f6102a0527f60136101435360610240527f5a6101446101a0527f53606061014553602061016102c0527f4653606061610200527f0147610260527f5360006101805260616101a05360616102e0527f01c0527f016101a15360486101a2536102610280527f20527f60536101a35360610300527f606101a45360f36101a5536061616101e0527f01a6536102a0527f6001616102610320527f40527f01a75360496101a85360536101a95360616101aa536001616102c0527f610340527f01ab610200527f53610260527f604a6101ac5360606101ad5360006101ae5360610360527f6102e0527ff36101af5360006101b0600061610280527f022052606061024053610380527f6000610241610300527f5360f56102425360606102435360006102446102a0526103a0527f7f536060610245536000610320527f61024653606061024753600061024853606103c0527f6061024953606102c0527e61024a53610340527f606061024b53600061024c536103e0527f608561024d53605a61024e5360f2616102e05260610360527f0261030053604f610400527f61030153605361030253606061030353605061030453606161610380527f0305610420527f53600261030653605061030753605361030853606061030953605061030a6103610440527fa0527f53606161030b53600261030c53605161030d53605361030e5360616103610460527f0f53606103c0527f026103105360526103115360606103125360006103135360610480527ff3610314536103156103e05260606104005360006104015360606104025360006104a0527f6104035360f061040453606061040553600061040653606061040753600061046104c0527f0853606061040953600061040a53606061040b53600061040c53606061040d536104e0527f600061040e53608561040f53605a6104105360f26104115360506104125360506105005260616105205360046105215360136105225360536105235360616105245360046105255360146105265360606105275360006105285360f36105295361052a60006000f06000600060006000845af45050", + "nonce": "0x0", + "storage": {} + }, + "0x00000000000000000000000000000000000000f4": { + "balance": "0x0", + "code": "0x7f600260045560005450600054506052600053605960015360b0600253604860036000527f53606060045360006005536060600653600060075360606008536000600953606020527f60600a536000600b536060600c536000600d536060600e5360f7600f53605a606040527f105360f260115360506012536060601353602060145360606015536000601653606052606060805360f3608153606060825360176083536053608453606060855360186086536060608753600060885360f3608953608a60006000f060006000600060006000855af15050600060006000600060085af4509e6c9d1d971b000660f7ff600454506000600060006000600060025af2509c475968419b3aa08593a2600160015573723c5c93313020435e90136c69a060006000600060006000600b5af25082a34587374694600254502818e1600354506002ff60f6ff60025450600060006000600060085af45060006002555938175a79c36006ff60206000f3", + "nonce": "0x0", + "storage": {} + }, + "0x00000000000000000000000000000000000000f5": { + "balance": "0x0", + "code": "0xf570b11897ff9b1da093177f645c31168c93a46000600455cd600060045560206000f3", + "nonce": "0x0", + "storage": {} + }, + "0x00000000000000000000000000000000000000f6": { + "balance": "0x0", + "code": "0x60206000fd", + "nonce": "0x0", + "storage": {} + }, + "0x00000000000000000000000000000000000000f7": { + "balance": "0x0", + "code": "0x7f6002545060006000556002600355600654506000600155600854507f60faff9b6000527f023f5bfa904270645484563c3af0748b956c546afdfa825b888a60066000527f6020527fff236000600060006000600060f25af2506000600060006000600060f95af2506040527f6020527f60025450676003545060006000600060006000600a5af1509c0238456060527fa1375d086040527f6a0173ff687402743080530196697c6000600060006000606080527ff75af450507965fe6060527f0360006000600060006000600d5af2507f60006060a0527e55600060025560035450606080527e6004556060600053602060015360606060c0527f60005260026020536053602153606060a0527f6022536000602353606060245360e0527f60036025536053602653606060275360f3602860c0527f536060602953600460610100527f2a536053602b536060602c536005602d536060602e536060e0527e602f5360f3610120527f6030536000603160006000f56000600060006000845af450501561010052609f610140527f6101205360876101215360646101225360536101235360606101245360006101610160527f2553606061012653600061012753606061012853600061012953606061012a53610180527f600061012b53606061012c53600061012d53606061012e5360f761012f53605a6101a0527f6101305360f161013153605061013253606061013353602061013453606061016101c05260356101e05360536101e15360606101e25360006101e35360616101e45360016101e55360366101e65360536101e75360606101e85360f36101e95360616101ea5360016101eb5360376101ec5360536101ed5360616101ee5360016101ef5360386101f05360606101f15360006101f25360f36101f3536101f460006000f06000600060006000845af45050", + "nonce": "0x0", + "storage": {} + }, + "0x00000000000000000000000000000000000000f8": { + "balance": "0x0", + "code": "0x600060006000600060065af4506000600060006000600060f65af1507f600054507f663a148bfd0ba3396000600060006000600060f25af250600060006000527f60006000606000527e600c5af250600454507f7f9c757985621d9779001466466020527f78183760006002556020527faf60006003550047149a046000527ff06000527f6040527f080864543efe3f3f445803356040527f600354505a8e45a4b071383862fa19606060527f20527f9c5b7c52076020527f600160036060527f55b27f6007545060006004556080527f600260025560016040527f6002556007545060026080527f6040527f5450600160a0527f6002556000527f60065450600160016060527f556000545060a0527f6008545060c0527f600654506060527f60016004556007545060046020527f6080527f5460c0527f60e0527f506060600053600060015360606002536080527f600060035360606004536060610100527f60e0527fa0527e6005536040527f6060600653600060075360606060a0527f08610120527f53600060610100527f095360c0527f6060600a536006600b53605a6060527f60610140527f0c5360f2600d536060610120527fc0527f50600e60e0527f536060600f536020610160527f6010536060601153600060126080610140527f52605360a0536060e052610100610180527f527f7f6060a15360f360a253606060a3536013610160527f60a453605360a5536101a0527f606060a6536014610120527f60610100527fa753606060a8610180527f5360006101c0527f60a95360f360aa53600060ab60006000f5610140527f600060006000616101a06101e0527f527f0120527f6000845af450509e20915e89f0684660026000559a610160527f610200527f60006101c0527f600060006000600060610140527f0d5af15060016002556009610220527fff3f8c329761016101e0527f80527f7f60006002556000545060095450600161610240527f0160527f6003556000600055610200527f6000606101a0527f02556000545060610260527e527f600260035560026003557f610180610220527f527f6000600060006101610280527fc0527f6000600060035af25060005450600d60205260610240527fff604053606102a0527f60606101a0527f416101e0527f5360016042536060604353600260610260527f6102c0527f445360556045536060604653602060475361610200527f01c0527f60606048536102e0527f610280527f600060495360f3604a536060604b536000604c5360526061022052610300527f7f4d5360606102a0527f6101e0527f604e536020604f53606060505360006051610320527f5360f3605253610240526102c0527f7f605360006000f0600061020052606061610340527f0220536000610221536060610222536102e0527f60610260527e610223536060610360527f6102245360006102255360606102265360006102610300527f27536085616102610380527f80527f022853605a6102295360f161022a53605061022b5360610320527f50616103a0527f022c5361022d60006102a05260f36102c0536102c160006000f06000600061036103c0527f40526060610360536000610361536060610362536000610363536084610364536103e052606061040053605a6104015360616104025360036104035360656104045360536104055360606104065360f461040753606161040853600361040953606661040a53605361040b53606061040c53605061040d53606161040e53600361040f53606761041053605361041153606061041253605061041353606161041453600361041553606861041653605361041753606161041853600361041953606961041a53606061041b53600061041c5360f361041d5361041e60006000f060006000600060006000855af15050", + "nonce": "0x0", + "storage": {} + }, + "0x00000000000000000000000000000000000000f9": { + "balance": "0x0", + "code": "0x9f9d404467600060006000600060f65af450533a9e7060006000600060006000600e5af150f5032095fd177d99306000600060006000600060005af1506000600060006000600d5af450916858b03c60006000600060006000600e5af25060206000f3", + "nonce": "0x0", + "storage": {} + }, + "0x00000000000000000000000000000000000000fa": { + "balance": "0x0", + "code": "0x6000600060006000600060fa5af15060206000fd", + "nonce": "0x0", + "storage": {} + }, + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "balance": "0xffffffffff", + "code": "0x", + "nonce": "0x0", + "storage": {} + } +} \ No newline at end of file diff --git a/tools/t8n/testdata/00-521/env.json b/tools/t8n/testdata/00-521/env.json new file mode 100644 index 000000000..2af32f581 --- /dev/null +++ b/tools/t8n/testdata/00-521/env.json @@ -0,0 +1,10 @@ +{ + "currentBaseFee": "0x10", + "currentCoinbase": "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "currentDifficulty": "0x0", + "currentGasLimit": "0x26e1f476fe1e22", + "currentNumber": "0x1", + "currentRandom": "0x0000000000000000000000000000000000000000000000000000000000020000", + "currentTimestamp": "0x3e8", + "withdrawals": [], +} diff --git a/tools/t8n/testdata/00-521/exp.txt b/tools/t8n/testdata/00-521/exp.txt new file mode 100644 index 000000000..24528badf --- /dev/null +++ b/tools/t8n/testdata/00-521/exp.txt @@ -0,0 +1,17 @@ +{"pc":0,"op":96,"gas":"0xa54","gasCost":"0x3","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":2,"op":96,"gas":"0xa51","gasCost":"0x3","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":4,"op":96,"gas":"0xa4e","gasCost":"0x3","memSize":0,"stack":["0x0","0x0"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":6,"op":96,"gas":"0xa4b","gasCost":"0x3","memSize":0,"stack":["0x0","0x0","0x0"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":8,"op":96,"gas":"0xa48","gasCost":"0x3","memSize":0,"stack":["0x0","0x0","0x0","0x0"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":10,"op":90,"gas":"0xa45","gasCost":"0x2","memSize":0,"stack":["0x0","0x0","0x0","0x0","0xfa"],"depth":1,"refund":0,"opName":"GAS"} +{"pc":11,"op":244,"gas":"0xa43","gasCost":"0xa43","memSize":0,"stack":["0x0","0x0","0x0","0x0","0xfa","0xa43"],"depth":1,"refund":0,"opName":"DELEGATECALL"} +{"pc":0,"op":96,"gas":"0x1b","gasCost":"0x3","memSize":0,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":2,"op":96,"gas":"0x18","gasCost":"0x3","memSize":0,"stack":["0x0"],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":4,"op":96,"gas":"0x15","gasCost":"0x3","memSize":0,"stack":["0x0","0x0"],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":6,"op":96,"gas":"0x12","gasCost":"0x3","memSize":0,"stack":["0x0","0x0","0x0"],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":8,"op":96,"gas":"0xf","gasCost":"0x3","memSize":0,"stack":["0x0","0x0","0x0","0x0"],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":10,"op":96,"gas":"0xc","gasCost":"0x3","memSize":0,"stack":["0x0","0x0","0x0","0x0","0x0"],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":12,"op":90,"gas":"0x9","gasCost":"0x2","memSize":0,"stack":["0x0","0x0","0x0","0x0","0x0","0xfa"],"depth":2,"refund":0,"opName":"GAS"} +{"pc":13,"op":241,"gas":"0x7","gasCost":"0x9","memSize":0,"stack":["0x0","0x0","0x0","0x0","0x0","0xfa","0x7"],"depth":2,"refund":0,"opName":"CALL","error":"Opcode Dispatch Error: Out of gas: Needed 9 - Remaining 7 - Reason: Call, depth=2"} +{"pc":12,"op":80,"gas":"0x0","gasCost":"0x2","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"POP","error":"Opcode Dispatch Error: Out of gas: Needed 2 - Remaining 0 - Reason: Pop, depth=1"} +{"output":"","gasUsed":"0xa54","error":"Opcode Dispatch Error: Out of gas: Needed 2 - Remaining 0 - Reason: Pop, depth=1"} diff --git a/tools/t8n/testdata/00-521/txs.json b/tools/t8n/testdata/00-521/txs.json new file mode 100644 index 000000000..995f2d6bc --- /dev/null +++ b/tools/t8n/testdata/00-521/txs.json @@ -0,0 +1,14 @@ +[ + { + "type": "0x0", + "chainId": "0x1", + "input": "0x4235beb96136f67f5076ae8700b86ef876b2b95037c04c311ea03790a15b97389485f03361", + "gas": "0x5ea0", + "gasPrice": "0x10", + "nonce": "0x0", + "secretKey": "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "sender": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "to": "0x00000000000000000000000000000000000000f1", + "value": "0x1a5474" + } +]