From 0f8affb7c9bb3851ca3b3c3134a7ec67649db2b7 Mon Sep 17 00:00:00 2001 From: andri lim Date: Mon, 1 Apr 2019 08:54:02 +0700 Subject: [PATCH 01/12] remove explicit return value from VM --- nimbus/vm/computation.nim | 54 ++++++++++++++++---------------- nimbus/vm_state_transactions.nim | 5 +-- 2 files changed, 30 insertions(+), 29 deletions(-) diff --git a/nimbus/vm/computation.nim b/nimbus/vm/computation.nim index e8ce9fc5c..9905ed7c9 100644 --- a/nimbus/vm/computation.nim +++ b/nimbus/vm/computation.nim @@ -111,6 +111,14 @@ proc commit*(comp: BaseComputation) = proc dispose*(comp: BaseComputation) {.inline.} = comp.dbsnapshot.transaction.dispose() +proc rollback*(comp: BaseComputation) = + comp.dbsnapshot.transaction.rollback() + comp.vmState.accountDb.rootHash = comp.dbsnapshot.intermediateRoot + comp.vmState.blockHeader.stateRoot = comp.dbsnapshot.intermediateRoot + +proc setError*(comp: BaseComputation, msg: string, burnsGas = false) {.inline.} = + comp.error = Error(info: msg, burnsGas: burnsGas) + proc getFork*(computation: BaseComputation): Fork = result = if computation.forkOverride.isSome: @@ -142,34 +150,33 @@ proc writeContract*(computation: var BaseComputation, fork: Fork): bool = if fork < FkHomestead: computation.output = @[] result = false -proc transferBalance(computation: var BaseComputation, opCode: static[Op]): bool = +proc transferBalance(computation: var BaseComputation, opCode: static[Op]) = if computation.msg.depth > MaxCallDepth: - debug "Stack depth limit reached", depth=computation.msg.depth - return false + computation.setError(&"Stack depth limit reached depth={computation.msg.depth}") + return let senderBalance = computation.vmState.readOnlyStateDb(). getBalance(computation.msg.sender) if senderBalance < computation.msg.value: - debug "insufficient funds", available=senderBalance, needed=computation.msg.value - return false + computation.setError(&"insufficient funds available={senderBalance}, needed={computation.msg.value}") + return when opCode in {Call, Create}: computation.vmState.mutateStateDb: db.subBalance(computation.msg.sender, computation.msg.value) db.addBalance(computation.msg.storageAddress, computation.msg.value) - result = true - proc executeOpcodes*(computation: var BaseComputation) {.gcsafe.} -proc applyMessage*(computation: var BaseComputation, opCode: static[Op]): bool = +proc applyMessage*(computation: var BaseComputation, opCode: static[Op]) = computation.snapshot() defer: computation.dispose() when opCode in {CallCode, Call, Create}: - if not computation.transferBalance(opCode): - computation.revert() + computation.transferBalance(opCode) + if computation.isError(): + computation.rollback() return if computation.gasMeter.gasRemaining < 0: @@ -178,27 +185,20 @@ proc applyMessage*(computation: var BaseComputation, opCode: static[Op]): bool = try: executeOpcodes(computation) - result = not computation.isError - except VMError: - result = false - debug "applyMessage VM Error", - msg = getCurrentExceptionMsg(), - depth = computation.msg.depth - except ValueError: - result = false - debug "applyMessage Value Error", - msg = getCurrentExceptionMsg(), - depth = computation.msg.depth + except: + let msg = getCurrentExceptionMsg() + computation.setError(&"applyMessage Error msg={msg}, depth={computation.msg.depth}", true) - if result and computation.msg.isCreate: - var fork = computation.getFork + if computation.isSuccess and computation.msg.isCreate: + let fork = computation.getFork let contractFailed = not computation.writeContract(fork) - result = not(contractFailed and fork == FkHomestead) + if contractFailed and fork == FkHomestead: + computation.setError(&"writeContract failed, depth={computation.msg.depth}", true) - if result: + if computation.isSuccess: computation.commit() else: - computation.revert(true) + computation.rollback() proc addChildComputation(computation: var BaseComputation, child: BaseComputation) = if child.isError: @@ -220,7 +220,7 @@ proc addChildComputation(computation: var BaseComputation, child: BaseComputatio proc applyChildComputation*(parentComp, childComp: var BaseComputation, opCode: static[Op]) = ## Apply the vm message childMsg as a child computation. - discard childComp.applyMessage(opCode) + childComp.applyMessage(opCode) parentComp.addChildComputation(childComp) proc registerAccountForDeletion*(c: var BaseComputation, beneficiary: EthAddress) = diff --git a/nimbus/vm_state_transactions.nim b/nimbus/vm_state_transactions.nim index ba8bfff1f..790449a29 100644 --- a/nimbus/vm_state_transactions.nim +++ b/nimbus/vm_state_transactions.nim @@ -65,9 +65,9 @@ proc setupComputation*(vmState: BaseVMState, tx: Transaction, sender, recipient: proc execComputation*(computation: var BaseComputation): bool = if computation.msg.isCreate: - result = computation.applyMessage(Create) + computation.applyMessage(Create) else: - result = computation.applyMessage(Call) + computation.applyMessage(Call) computation.vmState.mutateStateDB: var suicidedCount = 0 @@ -79,6 +79,7 @@ proc execComputation*(computation: var BaseComputation): bool = const RefundSelfDestruct = 24_000 computation.gasMeter.refundGas(RefundSelfDestruct * suicidedCount) + result = computation.isSuccess if result: computation.vmState.addLogs(computation.logEntries) else: From 112d2219df4fa5936c1b2839b32cfbb956304924 Mon Sep 17 00:00:00 2001 From: andri lim Date: Tue, 2 Apr 2019 12:13:18 +0700 Subject: [PATCH 02/12] reduce indirect call in EVM --- nimbus/vm/computation.nim | 10 ++++------ nimbus/vm/interpreter/opcodes_impl.nim | 14 ++++---------- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/nimbus/vm/computation.nim b/nimbus/vm/computation.nim index 9905ed7c9..a4ebc1717 100644 --- a/nimbus/vm/computation.nim +++ b/nimbus/vm/computation.nim @@ -200,7 +200,7 @@ proc applyMessage*(computation: var BaseComputation, opCode: static[Op]) = else: computation.rollback() -proc addChildComputation(computation: var BaseComputation, child: BaseComputation) = +proc addChildComputation*(computation: var BaseComputation, child: BaseComputation) = if child.isError: if child.msg.isCreate: computation.returnData = child.output @@ -216,12 +216,10 @@ proc addChildComputation(computation: var BaseComputation, child: BaseComputatio for k, v in child.accountsToDelete: computation.accountsToDelete[k] = v computation.logEntries.add child.logEntries - computation.children.add(child) -proc applyChildComputation*(parentComp, childComp: var BaseComputation, opCode: static[Op]) = - ## Apply the vm message childMsg as a child computation. - childComp.applyMessage(opCode) - parentComp.addChildComputation(childComp) + if not child.shouldBurnGas: + computation.gasMeter.returnGas(child.gasMeter.gasRemaining) + computation.children.add(child) proc registerAccountForDeletion*(c: var BaseComputation, beneficiary: EthAddress) = if c.msg.storageAddress in c.accountsToDelete: diff --git a/nimbus/vm/interpreter/opcodes_impl.nim b/nimbus/vm/interpreter/opcodes_impl.nim index 9ccbebb51..576a8489d 100644 --- a/nimbus/vm/interpreter/opcodes_impl.nim +++ b/nimbus/vm/interpreter/opcodes_impl.nim @@ -593,16 +593,14 @@ op create, inline = false, value, startPosition, size: var childComp = setupCreate(computation, memPos, len, value) if childComp.isNil: return - computation.applyChildComputation(childComp, Create) + childComp.applyMessage(Create) + computation.addChildComputation(childComp) if childComp.isError: push: 0 else: push: childComp.msg.storageAddress - if not childComp.shouldBurnGas: - computation.gasMeter.returnGas(childComp.gasMeter.gasRemaining) - proc callParams(computation: var BaseComputation): (UInt256, UInt256, EthAddress, EthAddress, EthAddress, UInt256, UInt256, UInt256, UInt256, MsgFlags) = let gas = computation.stack.popInt() let codeAddress = computation.stack.popAddress() @@ -761,7 +759,8 @@ template genCall(callName: untyped, opCode: Op): untyped = ## STATICCALL, 0xfa, Static message-call into an account. var (childComp, memOutPos, memOutLen) = `callName Setup`(computation, callName.astToStr) - applyChildComputation(computation, childComp, opCode) + childComp.applyMessage(opCode) + addChildComputation(computation, childComp) if childComp.isError: push: 0 @@ -773,11 +772,6 @@ template genCall(callName: untyped, opCode: Op): untyped = computation.memory.write( memOutPos, childComp.output.toOpenArray(0, actualOutputSize - 1)) - if not childComp.shouldBurnGas: - computation.gasMeter.returnGas(childComp.gasMeter.gasRemaining) - - if computation.gasMeter.gasRemaining <= 0: - raise newException(OutOfGas, "computation out of gas after contract call (" & callName.astToStr & ")") genCall(call, Call) genCall(callCode, CallCode) From 26b40f41e3c76f70c72f61a01d1911ab9288fed8 Mon Sep 17 00:00:00 2001 From: andri lim Date: Tue, 2 Apr 2019 13:05:42 +0700 Subject: [PATCH 03/12] fix precompiles selection, GST +5 --- GeneralStateTests.md | 14 +++++++------- nimbus/vm/computation.nim | 10 ++++++---- nimbus/vm/interpreter_dispatch.nim | 6 ++---- nimbus/vm/precompiles.nim | 10 ++++++---- tests/test_generalstate_failing.nim | 10 ++-------- 5 files changed, 23 insertions(+), 27 deletions(-) diff --git a/GeneralStateTests.md b/GeneralStateTests.md index f35754bd4..f9b4e6a26 100644 --- a/GeneralStateTests.md +++ b/GeneralStateTests.md @@ -2377,13 +2377,13 @@ OK: 24/24 Fail: 0/24 Skip: 0/24 ecpairing_two_point_match_5.json Skip ecpairing_two_point_oog.json Skip ecpairing_two_points_with_one_g2_zero.json Skip - pairingTest.json Skip - pointAdd.json Skip - pointAddTrunc.json Skip - pointMulAdd.json Skip - pointMulAdd2.json Skip ++ pairingTest.json OK ++ pointAdd.json OK ++ pointAddTrunc.json OK ++ pointMulAdd.json OK ++ pointMulAdd2.json OK ``` -OK: 0/133 Fail: 0/133 Skip: 133/133 +OK: 5/133 Fail: 0/133 Skip: 128/133 ## stZeroKnowledge2 ```diff ecadd_0-0_0-0_21000_0.json Skip @@ -2520,4 +2520,4 @@ OK: 0/133 Fail: 0/133 Skip: 133/133 OK: 0/130 Fail: 0/130 Skip: 130/130 ---TOTAL--- -OK: 1433/2334 Fail: 0/2334 Skip: 901/2334 +OK: 1438/2334 Fail: 0/2334 Skip: 896/2334 diff --git a/nimbus/vm/computation.nim b/nimbus/vm/computation.nim index a4ebc1717..56c9cf67f 100644 --- a/nimbus/vm/computation.nim +++ b/nimbus/vm/computation.nim @@ -182,15 +182,17 @@ proc applyMessage*(computation: var BaseComputation, opCode: static[Op]) = if computation.gasMeter.gasRemaining < 0: computation.commit() return - + + let fork = computation.getFork + try: - executeOpcodes(computation) + if not computation.execPrecompiles(fork): + executeOpcodes(computation) except: let msg = getCurrentExceptionMsg() computation.setError(&"applyMessage Error msg={msg}, depth={computation.msg.depth}", true) - if computation.isSuccess and computation.msg.isCreate: - let fork = computation.getFork + if computation.isSuccess and computation.msg.isCreate: let contractFailed = not computation.writeContract(fork) if contractFailed and fork == FkHomestead: computation.setError(&"writeContract failed, depth={computation.msg.depth}", true) diff --git a/nimbus/vm/interpreter_dispatch.nim b/nimbus/vm/interpreter_dispatch.nim index a4445cc7e..3aff39318 100644 --- a/nimbus/vm/interpreter_dispatch.nim +++ b/nimbus/vm/interpreter_dispatch.nim @@ -247,12 +247,10 @@ macro genHomesteadDispatch(computation: BaseComputation): untyped = result = opTableToCaseStmt(HomesteadOpDispatch, computation) proc frontierVM(computation: var BaseComputation) = - if not computation.execPrecompiles: - genFrontierDispatch(computation) + genFrontierDispatch(computation) proc homesteadVM(computation: var BaseComputation) = - if not computation.execPrecompiles: - genHomesteadDispatch(computation) + genHomesteadDispatch(computation) proc executeOpcodes(computation: var BaseComputation) = # TODO: Optimise getting fork and updating opCodeExec only when necessary diff --git a/nimbus/vm/precompiles.nim b/nimbus/vm/precompiles.nim index 60428e04b..873d00ced 100644 --- a/nimbus/vm/precompiles.nim +++ b/nimbus/vm/precompiles.nim @@ -1,15 +1,16 @@ import - ../vm_types, interpreter/[gas_meter, gas_costs, utils/utils_numeric], + ../vm_types, interpreter/[gas_meter, gas_costs, utils/utils_numeric, vm_forks], ../errors, stint, eth/[keys, common], chronicles, tables, macros, message, math, nimcrypto, bncurve/[fields, groups] type PrecompileAddresses* = enum + # Frontier to Spurious Dragron paEcRecover = 1, paSha256, paRipeMd160, paIdentity, - # + # Byzantium onward paModExp, paEcAdd, paEcMul, @@ -274,12 +275,13 @@ proc bn256ecPairing*(computation: var BaseComputation) = # computation.gasMeter.consumeGas(gasFee, reason="ecPairing Precompile") computation.rawOutput = @output -proc execPrecompiles*(computation: var BaseComputation): bool {.inline.} = +proc execPrecompiles*(computation: var BaseComputation, fork: Fork): bool {.inline.} = for i in 0..18: if computation.msg.codeAddress[i] != 0: return let lb = computation.msg.codeAddress[19] - if lb in PrecompileAddresses.low.byte .. PrecompileAddresses.high.byte: + let maxPrecompileAddr = if fork < FkByzantium: paIdentity else: PrecompileAddresses.high + if lb in PrecompileAddresses.low.byte .. maxPrecompileAddr.byte: result = true let precompile = PrecompileAddresses(lb) trace "Call precompile", precompile = precompile, codeAddr = computation.msg.codeAddress diff --git a/tests/test_generalstate_failing.nim b/tests/test_generalstate_failing.nim index 0b9bc3dc6..fcd00bc1e 100644 --- a/tests/test_generalstate_failing.nim +++ b/tests/test_generalstate_failing.nim @@ -13,14 +13,8 @@ # being mostly used for short-term regression prevention. func allowedFailingGeneralStateTest*(folder, name: string): bool = let allowedFailingGeneralStateTests = @[ - "randomStatetest14.json", - "randomStatetest85.json", - # 2019-02-17: - "pairingTest.json", - "pointAdd.json", - "pointAddTrunc.json", - "pointMulAdd.json", - "pointMulAdd2.json", + "randomStatetest14.json", # SHA3 offset + "randomStatetest85.json", # CALL* memoffset # Homestead recursives "ContractCreationSpam.json", "Call1024OOG.json", From e8f6eeca43f777cd66e43c0930022e75a6253f11 Mon Sep 17 00:00:00 2001 From: andri lim Date: Tue, 2 Apr 2019 13:23:16 +0700 Subject: [PATCH 04/12] update test data --- tests/fixtures/TracerTests/block46402.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/fixtures/TracerTests/block46402.json b/tests/fixtures/TracerTests/block46402.json index 27b50bddc..2158d4add 100644 --- a/tests/fixtures/TracerTests/block46402.json +++ b/tests/fixtures/TracerTests/block46402.json @@ -283,7 +283,7 @@ "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000060" ], - "error": "" + "error": "applyMessage Error msg=Out of gas: Needed 20000 - Remaining 412 - Reason: SSTORE: 9a049f5d18c239efaa258af9f3e7002949a977a0[0] -> 924236965777326770894530693462975209021625492404 (0), depth=0" } ], "stateDiff": { @@ -704,7 +704,7 @@ "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000060" ], - "error": "" + "error": "applyMessage Error msg=Out of gas: Needed 20000 - Remaining 412 - Reason: SSTORE: 9a049f5d18c239efaa258af9f3e7002949a977a0[0] -> 924236965777326770894530693462975209021625492404 (0), depth=0" } ] }, From 07ac4620d91c8d28b06174030128ae255e0d5972 Mon Sep 17 00:00:00 2001 From: andri lim Date: Thu, 4 Apr 2019 10:20:00 +0700 Subject: [PATCH 05/12] remove 'var' modifier from 'computation: var BaseComputation' --- nimbus/vm/computation.nim | 20 ++++++++--------- nimbus/vm/interpreter/opcodes_impl.nim | 14 ++++++------ .../utils/macros_procs_opcodes.nim | 22 +++++++++---------- nimbus/vm/interpreter_dispatch.nim | 8 +++---- nimbus/vm/precompiles.nim | 20 ++++++++--------- 5 files changed, 42 insertions(+), 42 deletions(-) diff --git a/nimbus/vm/computation.nim b/nimbus/vm/computation.nim index 56c9cf67f..1705de668 100644 --- a/nimbus/vm/computation.nim +++ b/nimbus/vm/computation.nim @@ -61,7 +61,7 @@ func output*(c: BaseComputation): seq[byte] = else: c.rawOutput -func `output=`*(c: var BaseComputation, value: openarray[byte]) = +func `output=`*(c: BaseComputation, value: openarray[byte]) = c.rawOutput = @value proc outputHex*(c: BaseComputation): string = @@ -69,11 +69,11 @@ proc outputHex*(c: BaseComputation): string = return "0x" c.rawOutput.bytesToHex -proc isSuicided*(c: var BaseComputation, address: EthAddress): bool = +proc isSuicided*(c: BaseComputation, address: EthAddress): bool = result = address in c.accountsToDelete proc prepareChildMessage*( - c: var BaseComputation, + c: BaseComputation, gas: GasInt, to: EthAddress, value: UInt256, @@ -126,7 +126,7 @@ proc getFork*(computation: BaseComputation): Fork = else: computation.vmState.blockNumber.toFork -proc writeContract*(computation: var BaseComputation, fork: Fork): bool = +proc writeContract*(computation: BaseComputation, fork: Fork): bool = result = true let contractCode = computation.output @@ -150,7 +150,7 @@ proc writeContract*(computation: var BaseComputation, fork: Fork): bool = if fork < FkHomestead: computation.output = @[] result = false -proc transferBalance(computation: var BaseComputation, opCode: static[Op]) = +proc transferBalance(computation: BaseComputation, opCode: static[Op]) = if computation.msg.depth > MaxCallDepth: computation.setError(&"Stack depth limit reached depth={computation.msg.depth}") return @@ -167,9 +167,9 @@ proc transferBalance(computation: var BaseComputation, opCode: static[Op]) = db.subBalance(computation.msg.sender, computation.msg.value) db.addBalance(computation.msg.storageAddress, computation.msg.value) -proc executeOpcodes*(computation: var BaseComputation) {.gcsafe.} +proc executeOpcodes*(computation: BaseComputation) {.gcsafe.} -proc applyMessage*(computation: var BaseComputation, opCode: static[Op]) = +proc applyMessage*(computation: BaseComputation, opCode: static[Op]) = computation.snapshot() defer: computation.dispose() @@ -202,7 +202,7 @@ proc applyMessage*(computation: var BaseComputation, opCode: static[Op]) = else: computation.rollback() -proc addChildComputation*(computation: var BaseComputation, child: BaseComputation) = +proc addChildComputation*(computation: BaseComputation, child: BaseComputation) = if child.isError: if child.msg.isCreate: computation.returnData = child.output @@ -223,14 +223,14 @@ proc addChildComputation*(computation: var BaseComputation, child: BaseComputati computation.gasMeter.returnGas(child.gasMeter.gasRemaining) computation.children.add(child) -proc registerAccountForDeletion*(c: var BaseComputation, beneficiary: EthAddress) = +proc registerAccountForDeletion*(c: BaseComputation, beneficiary: EthAddress) = if c.msg.storageAddress in c.accountsToDelete: raise newException(ValueError, "invariant: should be impossible for an account to be " & "registered for deletion multiple times") c.accountsToDelete[c.msg.storageAddress] = beneficiary -proc addLogEntry*(c: var BaseComputation, log: Log) {.inline.} = +proc addLogEntry*(c: BaseComputation, log: Log) {.inline.} = c.logEntries.add(log) # many methods are basically TODO, but they still return valid values diff --git a/nimbus/vm/interpreter/opcodes_impl.nim b/nimbus/vm/interpreter/opcodes_impl.nim index 576a8489d..c7e3b8952 100644 --- a/nimbus/vm/interpreter/opcodes_impl.nim +++ b/nimbus/vm/interpreter/opcodes_impl.nim @@ -452,7 +452,7 @@ op sstore, inline = false, slot, value: computation.vmState.mutateStateDB: db.setStorage(computation.msg.storageAddress, slot, value) -proc jumpImpl(computation: var BaseComputation, jumpTarget: UInt256) = +proc jumpImpl(computation: BaseComputation, jumpTarget: UInt256) = if jumpTarget >= computation.code.len.u256: raise newException(InvalidJumpDestination, "Invalid Jump Destination") @@ -537,7 +537,7 @@ proc canTransfer(computation: BaseComputation, memPos, memLen: int, value: Uint2 result = true -proc setupCreate(computation: var BaseComputation, memPos, len: int, value: Uint256): BaseComputation = +proc setupCreate(computation: BaseComputation, memPos, len: int, value: Uint256): BaseComputation = let callData = computation.memory.read(memPos, len) createMsgGas = computation.getGasRemaining() @@ -601,7 +601,7 @@ op create, inline = false, value, startPosition, size: else: push: childComp.msg.storageAddress -proc callParams(computation: var BaseComputation): (UInt256, UInt256, EthAddress, EthAddress, EthAddress, UInt256, UInt256, UInt256, UInt256, MsgFlags) = +proc callParams(computation: BaseComputation): (UInt256, UInt256, EthAddress, EthAddress, EthAddress, UInt256, UInt256, UInt256, UInt256, MsgFlags) = let gas = computation.stack.popInt() let codeAddress = computation.stack.popAddress() @@ -623,7 +623,7 @@ proc callParams(computation: var BaseComputation): (UInt256, UInt256, EthAddress memoryOutputSize, computation.msg.flags) -proc callCodeParams(computation: var BaseComputation): (UInt256, UInt256, EthAddress, EthAddress, EthAddress, UInt256, UInt256, UInt256, UInt256, MsgFlags) = +proc callCodeParams(computation: BaseComputation): (UInt256, UInt256, EthAddress, EthAddress, EthAddress, UInt256, UInt256, UInt256, UInt256, MsgFlags) = let gas = computation.stack.popInt() let to = computation.stack.popAddress() @@ -642,7 +642,7 @@ proc callCodeParams(computation: var BaseComputation): (UInt256, UInt256, EthAdd memoryOutputSize, computation.msg.flags) -proc delegateCallParams(computation: var BaseComputation): (UInt256, UInt256, EthAddress, EthAddress, EthAddress, UInt256, UInt256, UInt256, UInt256, MsgFlags) = +proc delegateCallParams(computation: BaseComputation): (UInt256, UInt256, EthAddress, EthAddress, EthAddress, UInt256, UInt256, UInt256, UInt256, MsgFlags) = let gas = computation.stack.popInt() let codeAddress = computation.stack.popAddress() @@ -664,7 +664,7 @@ proc delegateCallParams(computation: var BaseComputation): (UInt256, UInt256, Et memoryOutputSize, computation.msg.flags) -proc staticCallParams(computation: var BaseComputation): (UInt256, UInt256, EthAddress, EthAddress, EthAddress, UInt256, UInt256, UInt256, UInt256, MsgFlags) = +proc staticCallParams(computation: BaseComputation): (UInt256, UInt256, EthAddress, EthAddress, EthAddress, UInt256, UInt256, UInt256, UInt256, MsgFlags) = let gas = computation.stack.popInt() let to = computation.stack.popAddress() @@ -683,7 +683,7 @@ proc staticCallParams(computation: var BaseComputation): (UInt256, UInt256, EthA emvcStatic) # is_static template genCall(callName: untyped, opCode: Op): untyped = - proc `callName Setup`(computation: var BaseComputation, callNameStr: string): (BaseComputation, int, int) = + proc `callName Setup`(computation: BaseComputation, callNameStr: string): (BaseComputation, int, int) = let (gas, value, to, sender, codeAddress, memoryInputStartPosition, memoryInputSize, diff --git a/nimbus/vm/interpreter/utils/macros_procs_opcodes.nim b/nimbus/vm/interpreter/utils/macros_procs_opcodes.nim index df25831a0..612c5becd 100644 --- a/nimbus/vm/interpreter/utils/macros_procs_opcodes.nim +++ b/nimbus/vm/interpreter/utils/macros_procs_opcodes.nim @@ -59,12 +59,12 @@ macro op*(procname: untyped, inline: static[bool], stackParams_body: varargs[unt # TODO: replace by func to ensure no side effects if inline: result = quote do: - proc `procname`*(`computation`: var BaseComputation) {.inline.} = + proc `procname`*(`computation`: BaseComputation) {.inline.} = `popStackStmt` `body` else: result = quote do: - proc `procname`*(`computation`: var BaseComputation) = + proc `procname`*(`computation`: BaseComputation) = `popStackStmt` `body` @@ -76,7 +76,7 @@ macro genPush*(): untyped = for size in 1 .. 32: let name = genName(size) result.add quote do: - func `name`*(computation: var BaseComputation) {.inline.}= + func `name`*(computation: BaseComputation) {.inline.}= ## Push `size`-byte(s) on the stack computation.stack.push computation.code.readVmWord(`size`) @@ -87,7 +87,7 @@ macro genDup*(): untyped = for pos in 1 .. 16: let name = genName(pos) result.add quote do: - func `name`*(computation: var BaseComputation) {.inline.}= + func `name`*(computation: BaseComputation) {.inline.}= computation.stack.dup(`pos`) macro genSwap*(): untyped = @@ -97,10 +97,10 @@ macro genSwap*(): untyped = for pos in 1 .. 16: let name = genName(pos) result.add quote do: - func `name`*(computation: var BaseComputation) {.inline.}= + func `name`*(computation: BaseComputation) {.inline.}= computation.stack.swap(`pos`) -proc logImpl(c: var BaseComputation, opcode: Op, topicCount: int) = +proc logImpl(c: BaseComputation, opcode: Op, topicCount: int) = doAssert(topicCount in 0 .. 4) let (memStartPosition, size) = c.stack.popInt(2) let (memPos, len) = (memStartPosition.cleanMemRef, size.cleanMemRef) @@ -122,8 +122,8 @@ proc logImpl(c: var BaseComputation, opcode: Op, topicCount: int) = c.addLogEntry(log) template genLog*() = - proc log0*(c: var BaseComputation) {.inline.} = logImpl(c, Log0, 0) - proc log1*(c: var BaseComputation) {.inline.} = logImpl(c, Log1, 1) - proc log2*(c: var BaseComputation) {.inline.} = logImpl(c, Log2, 2) - proc log3*(c: var BaseComputation) {.inline.} = logImpl(c, Log3, 3) - proc log4*(c: var BaseComputation) {.inline.} = logImpl(c, Log4, 4) + proc log0*(c: BaseComputation) {.inline.} = logImpl(c, Log0, 0) + proc log1*(c: BaseComputation) {.inline.} = logImpl(c, Log1, 1) + proc log2*(c: BaseComputation) {.inline.} = logImpl(c, Log2, 2) + proc log3*(c: BaseComputation) {.inline.} = logImpl(c, Log3, 3) + proc log4*(c: BaseComputation) {.inline.} = logImpl(c, Log4, 4) diff --git a/nimbus/vm/interpreter_dispatch.nim b/nimbus/vm/interpreter_dispatch.nim index 3aff39318..2512a9ad8 100644 --- a/nimbus/vm/interpreter_dispatch.nim +++ b/nimbus/vm/interpreter_dispatch.nim @@ -16,7 +16,7 @@ import logScope: topics = "vm opcode" -func invalidInstruction*(computation: var BaseComputation) {.inline.} = +func invalidInstruction*(computation: BaseComputation) {.inline.} = raise newException(InvalidInstruction, "Invalid instruction, received an opcode not implemented in the current fork.") let FrontierOpDispatch {.compileTime.}: array[Op, NimNode] = block: @@ -246,13 +246,13 @@ macro genFrontierDispatch(computation: BaseComputation): untyped = macro genHomesteadDispatch(computation: BaseComputation): untyped = result = opTableToCaseStmt(HomesteadOpDispatch, computation) -proc frontierVM(computation: var BaseComputation) = +proc frontierVM(computation: BaseComputation) = genFrontierDispatch(computation) -proc homesteadVM(computation: var BaseComputation) = +proc homesteadVM(computation: BaseComputation) = genHomesteadDispatch(computation) -proc executeOpcodes(computation: var BaseComputation) = +proc executeOpcodes(computation: BaseComputation) = # TODO: Optimise getting fork and updating opCodeExec only when necessary let fork = computation.getFork diff --git a/nimbus/vm/precompiles.nim b/nimbus/vm/precompiles.nim index 873d00ced..110c21b05 100644 --- a/nimbus/vm/precompiles.nim +++ b/nimbus/vm/precompiles.nim @@ -63,7 +63,7 @@ proc getFR(data: openarray[byte]): FR = if not result.fromBytes2(data): raise newException(ValidationError, "Could not get FR value") -proc ecRecover*(computation: var BaseComputation) = +proc ecRecover*(computation: BaseComputation) = computation.gasMeter.consumeGas( GasECRecover, reason="ECRecover Precompile") @@ -79,7 +79,7 @@ proc ecRecover*(computation: var BaseComputation) = computation.rawOutput[12..31] = pubKey.toCanonicalAddress() trace "ECRecover precompile", derivedKey = pubKey.toCanonicalAddress() -proc sha256*(computation: var BaseComputation) = +proc sha256*(computation: BaseComputation) = let wordCount = wordCount(computation.msg.data.len) gasFee = GasSHA256 + wordCount * GasSHA256Word @@ -88,7 +88,7 @@ proc sha256*(computation: var BaseComputation) = computation.rawOutput = @(nimcrypto.sha_256.digest(computation.msg.data).data) trace "SHA256 precompile", output = computation.rawOutput.toHex -proc ripemd160*(computation: var BaseComputation) = +proc ripemd160*(computation: BaseComputation) = let wordCount = wordCount(computation.msg.data.len) gasFee = GasRIPEMD160 + wordCount * GasRIPEMD160Word @@ -98,7 +98,7 @@ proc ripemd160*(computation: var BaseComputation) = computation.rawOutput[12..31] = @(nimcrypto.ripemd160.digest(computation.msg.data).data) trace "RIPEMD160 precompile", output = computation.rawOutput.toHex -proc identity*(computation: var BaseComputation) = +proc identity*(computation: BaseComputation) = let wordCount = wordCount(computation.msg.data.len) gasFee = GasIdentity + wordCount * GasIdentityWord @@ -107,7 +107,7 @@ proc identity*(computation: var BaseComputation) = computation.rawOutput = computation.msg.data trace "Identity precompile", output = computation.rawOutput.toHex -proc modExpInternal(computation: var BaseComputation, base_len, exp_len, mod_len: int, T: type StUint) = +proc modExpInternal(computation: BaseComputation, base_len, exp_len, mod_len: int, T: type StUint) = template rawMsg: untyped {.dirty.} = computation.msg.data @@ -171,7 +171,7 @@ proc modExpInternal(computation: var BaseComputation, base_len, exp_len, mod_len else: computation.rawOutput = @(powmod(base, exp, modulo).toByteArrayBE) -proc modExp*(computation: var BaseComputation) = +proc modExp*(computation: BaseComputation) = ## Modular exponentiation precompiled contract ## Yellow Paper Appendix E ## EIP-198 - https://github.com/ethereum/EIPs/blob/master/EIPS/eip-198.md @@ -200,7 +200,7 @@ proc modExp*(computation: var BaseComputation) = else: raise newException(ValueError, "The Nimbus VM doesn't support modular exponentiation with numbers larger than uint8192") -proc bn256ecAdd*(computation: var BaseComputation) = +proc bn256ecAdd*(computation: BaseComputation) = var input: array[128, byte] output: array[64, byte] @@ -220,7 +220,7 @@ proc bn256ecAdd*(computation: var BaseComputation) = # computation.gasMeter.consumeGas(gasFee, reason = "ecAdd Precompile") computation.rawOutput = @output -proc bn256ecMul*(computation: var BaseComputation) = +proc bn256ecMul*(computation: BaseComputation) = var input: array[96, byte] output: array[64, byte] @@ -242,7 +242,7 @@ proc bn256ecMul*(computation: var BaseComputation) = # computation.gasMeter.consumeGas(gasFee, reason="ecMul Precompile") computation.rawOutput = @output -proc bn256ecPairing*(computation: var BaseComputation) = +proc bn256ecPairing*(computation: BaseComputation) = var output: array[32, byte] let msglen = len(computation.msg.data) @@ -275,7 +275,7 @@ proc bn256ecPairing*(computation: var BaseComputation) = # computation.gasMeter.consumeGas(gasFee, reason="ecPairing Precompile") computation.rawOutput = @output -proc execPrecompiles*(computation: var BaseComputation, fork: Fork): bool {.inline.} = +proc execPrecompiles*(computation: BaseComputation, fork: Fork): bool {.inline.} = for i in 0..18: if computation.msg.codeAddress[i] != 0: return From 4c0ba876ef7c3569f95f4f4bff4138ee347ee278 Mon Sep 17 00:00:00 2001 From: andri lim Date: Thu, 4 Apr 2019 10:50:25 +0700 Subject: [PATCH 06/12] move exception handler deeper in the EVM --- nimbus/vm/computation.nim | 38 ++++++++++++++++-------------- nimbus/vm/interpreter_dispatch.nim | 25 +++++++++++++------- nimbus/vm_types.nim | 1 + tests/test_vm_json.nim | 7 ++---- 4 files changed, 40 insertions(+), 31 deletions(-) diff --git a/nimbus/vm/computation.nim b/nimbus/vm/computation.nim index 1705de668..f6375cf76 100644 --- a/nimbus/vm/computation.nim +++ b/nimbus/vm/computation.nim @@ -167,6 +167,24 @@ proc transferBalance(computation: BaseComputation, opCode: static[Op]) = db.subBalance(computation.msg.sender, computation.msg.value) db.addBalance(computation.msg.storageAddress, computation.msg.value) +template continuation*(comp: BaseComputation, body: untyped) = + var tmpNext = comp.nextProc + comp.nextProc = proc() = + body + tmpNext() + +proc postExecuteVM(computation: BaseComputation) = + if computation.isSuccess and computation.msg.isCreate: + let fork = computation.getFork + let contractFailed = not computation.writeContract(fork) + if contractFailed and fork == FkHomestead: + computation.setError(&"writeContract failed, depth={computation.msg.depth}", true) + + if computation.isSuccess: + computation.commit() + else: + computation.rollback() + proc executeOpcodes*(computation: BaseComputation) {.gcsafe.} proc applyMessage*(computation: BaseComputation, opCode: static[Op]) = @@ -182,25 +200,9 @@ proc applyMessage*(computation: BaseComputation, opCode: static[Op]) = if computation.gasMeter.gasRemaining < 0: computation.commit() return - - let fork = computation.getFork - - try: - if not computation.execPrecompiles(fork): - executeOpcodes(computation) - except: - let msg = getCurrentExceptionMsg() - computation.setError(&"applyMessage Error msg={msg}, depth={computation.msg.depth}", true) - if computation.isSuccess and computation.msg.isCreate: - let contractFailed = not computation.writeContract(fork) - if contractFailed and fork == FkHomestead: - computation.setError(&"writeContract failed, depth={computation.msg.depth}", true) - - if computation.isSuccess: - computation.commit() - else: - computation.rollback() + executeOpcodes(computation) + postExecuteVM(computation) proc addChildComputation*(computation: BaseComputation, child: BaseComputation) = if child.isError: diff --git a/nimbus/vm/interpreter_dispatch.nim b/nimbus/vm/interpreter_dispatch.nim index 2512a9ad8..8e2fac6e4 100644 --- a/nimbus/vm/interpreter_dispatch.nim +++ b/nimbus/vm/interpreter_dispatch.nim @@ -231,14 +231,23 @@ proc opTableToCaseStmt(opTable: array[Op, NimNode], computation: NimNode): NimNo # Wrap the case statement in while true + computed goto result = quote do: - if `computation`.tracingEnabled: - `computation`.prepareTracer() - `computation`.instr = `computation`.code.next() - while true: - {.computedGoto.} - # TODO lots of macro magic here to unravel, with chronicles... - # `computation`.logger.log($`computation`.stack & "\n\n", fgGreen) - `result` + try: + let fork = `computation`.getFork + if `computation`.execPrecompiles(fork): + return + + if `computation`.tracingEnabled: + `computation`.prepareTracer() + `computation`.instr = `computation`.code.next() + while true: + {.computedGoto.} + # TODO lots of macro magic here to unravel, with chronicles... + # `computation`.logger.log($`computation`.stack & "\n\n", fgGreen) + `result` + except: + let msg = getCurrentExceptionMsg() + let errorMsg = "Opcode Dispatch Error msg=" & msg & ", depth=" & $computation.msg.depth + `computation`.setError(errorMsg, true) macro genFrontierDispatch(computation: BaseComputation): untyped = result = opTableToCaseStmt(FrontierOpDispatch, computation) diff --git a/nimbus/vm_types.nim b/nimbus/vm_types.nim index 54767397c..051577d56 100644 --- a/nimbus/vm_types.nim +++ b/nimbus/vm_types.nim @@ -67,6 +67,7 @@ type dbsnapshot*: Snapshot instr*: Op opIndex*: int + nextProc*: proc() Error* = ref object info*: string diff --git a/tests/test_vm_json.nim b/tests/test_vm_json.nim index f8a13f5be..c34d74659 100644 --- a/tests/test_vm_json.nim +++ b/tests/test_vm_json.nim @@ -56,11 +56,8 @@ proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus) = createAddress = toAddress)) var computation = newBaseComputation(vmState, header.blockNumber, message) - try: - computation.executeOpcodes() - except VMError: - computation.error = Error(info: getCurrentExceptionMsg()) - + computation.executeOpcodes() + if not fixture{"post"}.isNil: # Success checks check(not computation.isError) From e5cca19e7fc505494c5cf9e8bef7bd619a24b2f1 Mon Sep 17 00:00:00 2001 From: andri lim Date: Thu, 4 Apr 2019 11:44:35 +0700 Subject: [PATCH 07/12] tail call recursion with continuation passing --- nimbus/vm/computation.nim | 17 +++++++-- nimbus/vm/interpreter/opcodes_impl.nim | 48 +++++++++++++++----------- nimbus/vm_types.nim | 3 ++ 3 files changed, 44 insertions(+), 24 deletions(-) diff --git a/nimbus/vm/computation.nim b/nimbus/vm/computation.nim index f6375cf76..fad89fe08 100644 --- a/nimbus/vm/computation.nim +++ b/nimbus/vm/computation.nim @@ -34,6 +34,9 @@ proc newBaseComputation*(vmState: BaseVMState, blockNumber: UInt256, message: Me else: blockNumber.toFork.forkToSchedule result.forkOverride = forkOverride + # a dummy/terminus continuation proc + result.nextProc = proc() = + discard proc isOriginComputation*(c: BaseComputation): bool = # Is this computation the computation initiated by a transaction @@ -168,6 +171,8 @@ proc transferBalance(computation: BaseComputation, opCode: static[Op]) = db.addBalance(computation.msg.storageAddress, computation.msg.value) template continuation*(comp: BaseComputation, body: untyped) = + # this is a helper template to implement continuation + # passing and convert all recursion into tail call var tmpNext = comp.nextProc comp.nextProc = proc() = body @@ -189,21 +194,27 @@ proc executeOpcodes*(computation: BaseComputation) {.gcsafe.} proc applyMessage*(computation: BaseComputation, opCode: static[Op]) = computation.snapshot() - defer: computation.dispose() + defer: + computation.dispose() when opCode in {CallCode, Call, Create}: computation.transferBalance(opCode) if computation.isError(): computation.rollback() + computation.nextProc() return if computation.gasMeter.gasRemaining < 0: computation.commit() + computation.nextProc() return - executeOpcodes(computation) - postExecuteVM(computation) + continuation(computation): + postExecuteVM(computation) + executeOpcodes(computation) + computation.nextProc() + proc addChildComputation*(computation: BaseComputation, child: BaseComputation) = if child.isError: if child.msg.isCreate: diff --git a/nimbus/vm/interpreter/opcodes_impl.nim b/nimbus/vm/interpreter/opcodes_impl.nim index c7e3b8952..192ed26cc 100644 --- a/nimbus/vm/interpreter/opcodes_impl.nim +++ b/nimbus/vm/interpreter/opcodes_impl.nim @@ -593,13 +593,15 @@ op create, inline = false, value, startPosition, size: var childComp = setupCreate(computation, memPos, len, value) if childComp.isNil: return - childComp.applyMessage(Create) - computation.addChildComputation(childComp) + continuation(childComp): + computation.addChildComputation(childComp) - if childComp.isError: - push: 0 - else: - push: childComp.msg.storageAddress + if childComp.isError: + push: 0 + else: + push: childComp.msg.storageAddress + + childComp.applyMessage(Create) proc callParams(computation: BaseComputation): (UInt256, UInt256, EthAddress, EthAddress, EthAddress, UInt256, UInt256, UInt256, UInt256, MsgFlags) = let gas = computation.stack.popInt() @@ -683,7 +685,7 @@ proc staticCallParams(computation: BaseComputation): (UInt256, UInt256, EthAddre emvcStatic) # is_static template genCall(callName: untyped, opCode: Op): untyped = - proc `callName Setup`(computation: BaseComputation, callNameStr: string): (BaseComputation, int, int) = + proc `callName Setup`(computation: BaseComputation, callNameStr: string): BaseComputation = let (gas, value, to, sender, codeAddress, memoryInputStartPosition, memoryInputSize, @@ -750,28 +752,32 @@ template genCall(callName: untyped, opCode: Op): untyped = childMsg, some(computation.getFork)) - result = (childComp, memOutPos, memOutLen) + computation.memOutPos = memOutPos + computation.memOutLen = memOutLen + result = childComp op callName, inline = false: ## CALL, 0xf1, Message-Call into an account ## CALLCODE, 0xf2, Message-call into this account with an alternative account's code. ## DELEGATECALL, 0xf4, Message-call into this account with an alternative account's code, but persisting the current values for sender and value. ## STATICCALL, 0xfa, Static message-call into an account. - var (childComp, memOutPos, memOutLen) = `callName Setup`(computation, callName.astToStr) + var childComp = `callName Setup`(computation, callName.astToStr) + + continuation(childComp): + addChildComputation(computation, childComp) + + if childComp.isError: + push: 0 + else: + push: 1 + + if not childComp.shouldEraseReturnData: + let actualOutputSize = min(computation.memOutLen, childComp.output.len) + computation.memory.write( + computation.memOutPos, + childComp.output.toOpenArray(0, actualOutputSize - 1)) childComp.applyMessage(opCode) - addChildComputation(computation, childComp) - - if childComp.isError: - push: 0 - else: - push: 1 - - if not childComp.shouldEraseReturnData: - let actualOutputSize = min(memOutLen, childComp.output.len) - computation.memory.write( - memOutPos, - childComp.output.toOpenArray(0, actualOutputSize - 1)) genCall(call, Call) genCall(callCode, CallCode) diff --git a/nimbus/vm_types.nim b/nimbus/vm_types.nim index 051577d56..b71ee91e9 100644 --- a/nimbus/vm_types.nim +++ b/nimbus/vm_types.nim @@ -67,7 +67,10 @@ type dbsnapshot*: Snapshot instr*: Op opIndex*: int + # continuation helpers nextProc*: proc() + memOutLen*: int + memOutPos*: int Error* = ref object info*: string From 60df7ea5e22491d1441bf98dd3cc048171ed82f2 Mon Sep 17 00:00:00 2001 From: andri lim Date: Thu, 4 Apr 2019 12:13:33 +0700 Subject: [PATCH 08/12] update test data --- nimbus/vm/computation.nim | 2 +- tests/fixtures/TracerTests/block46402.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/nimbus/vm/computation.nim b/nimbus/vm/computation.nim index fad89fe08..c5bb91768 100644 --- a/nimbus/vm/computation.nim +++ b/nimbus/vm/computation.nim @@ -214,7 +214,7 @@ proc applyMessage*(computation: BaseComputation, opCode: static[Op]) = executeOpcodes(computation) computation.nextProc() - + proc addChildComputation*(computation: BaseComputation, child: BaseComputation) = if child.isError: if child.msg.isCreate: diff --git a/tests/fixtures/TracerTests/block46402.json b/tests/fixtures/TracerTests/block46402.json index 2158d4add..46b0d28d6 100644 --- a/tests/fixtures/TracerTests/block46402.json +++ b/tests/fixtures/TracerTests/block46402.json @@ -283,7 +283,7 @@ "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000060" ], - "error": "applyMessage Error msg=Out of gas: Needed 20000 - Remaining 412 - Reason: SSTORE: 9a049f5d18c239efaa258af9f3e7002949a977a0[0] -> 924236965777326770894530693462975209021625492404 (0), depth=0" + "error": "Opcode Dispatch Error msg=Out of gas: Needed 20000 - Remaining 412 - Reason: SSTORE: 9a049f5d18c239efaa258af9f3e7002949a977a0[0] -> 924236965777326770894530693462975209021625492404 (0), depth=0" } ], "stateDiff": { @@ -704,7 +704,7 @@ "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000060" ], - "error": "applyMessage Error msg=Out of gas: Needed 20000 - Remaining 412 - Reason: SSTORE: 9a049f5d18c239efaa258af9f3e7002949a977a0[0] -> 924236965777326770894530693462975209021625492404 (0), depth=0" + "error": "Opcode Dispatch Error msg=Out of gas: Needed 20000 - Remaining 412 - Reason: SSTORE: 9a049f5d18c239efaa258af9f3e7002949a977a0[0] -> 924236965777326770894530693462975209021625492404 (0), depth=0" } ] }, From 039256de6a0b8df0826526a056a32543b6f676b5 Mon Sep 17 00:00:00 2001 From: andri lim Date: Thu, 4 Apr 2019 15:21:24 +0700 Subject: [PATCH 09/12] more on continuation passsing --- nimbus/vm/computation.nim | 1 - nimbus/vm/interpreter/opcodes_impl.nim | 2 ++ nimbus/vm/interpreter_dispatch.nim | 2 ++ nimbus/vm_types.nim | 1 + 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/nimbus/vm/computation.nim b/nimbus/vm/computation.nim index c5bb91768..a8c1411c2 100644 --- a/nimbus/vm/computation.nim +++ b/nimbus/vm/computation.nim @@ -213,7 +213,6 @@ proc applyMessage*(computation: BaseComputation, opCode: static[Op]) = postExecuteVM(computation) executeOpcodes(computation) - computation.nextProc() proc addChildComputation*(computation: BaseComputation, child: BaseComputation) = if child.isError: diff --git a/nimbus/vm/interpreter/opcodes_impl.nim b/nimbus/vm/interpreter/opcodes_impl.nim index 192ed26cc..1a4e5ef07 100644 --- a/nimbus/vm/interpreter/opcodes_impl.nim +++ b/nimbus/vm/interpreter/opcodes_impl.nim @@ -593,6 +593,7 @@ op create, inline = false, value, startPosition, size: var childComp = setupCreate(computation, memPos, len, value) if childComp.isNil: return + computation.child = childComp continuation(childComp): computation.addChildComputation(childComp) @@ -763,6 +764,7 @@ template genCall(callName: untyped, opCode: Op): untyped = ## STATICCALL, 0xfa, Static message-call into an account. var childComp = `callName Setup`(computation, callName.astToStr) + computation.child = childComp continuation(childComp): addChildComputation(computation, childComp) diff --git a/nimbus/vm/interpreter_dispatch.nim b/nimbus/vm/interpreter_dispatch.nim index 8e2fac6e4..1038344e0 100644 --- a/nimbus/vm/interpreter_dispatch.nim +++ b/nimbus/vm/interpreter_dispatch.nim @@ -234,6 +234,7 @@ proc opTableToCaseStmt(opTable: array[Op, NimNode], computation: NimNode): NimNo try: let fork = `computation`.getFork if `computation`.execPrecompiles(fork): + computation.nextProc() return if `computation`.tracingEnabled: @@ -248,6 +249,7 @@ proc opTableToCaseStmt(opTable: array[Op, NimNode], computation: NimNode): NimNo let msg = getCurrentExceptionMsg() let errorMsg = "Opcode Dispatch Error msg=" & msg & ", depth=" & $computation.msg.depth `computation`.setError(errorMsg, true) + computation.nextProc() macro genFrontierDispatch(computation: BaseComputation): untyped = result = opTableToCaseStmt(FrontierOpDispatch, computation) diff --git a/nimbus/vm_types.nim b/nimbus/vm_types.nim index b71ee91e9..c75bdfa4f 100644 --- a/nimbus/vm_types.nim +++ b/nimbus/vm_types.nim @@ -71,6 +71,7 @@ type nextProc*: proc() memOutLen*: int memOutPos*: int + child*: BaseComputation Error* = ref object info*: string From fb97d8d0ce94465055a064b4eecc0f625d2af223 Mon Sep 17 00:00:00 2001 From: andri lim Date: Thu, 4 Apr 2019 15:26:12 +0700 Subject: [PATCH 10/12] move exception handler to executeOpcodes --- nimbus/vm/interpreter_dispatch.nim | 43 +++++++++++++++--------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/nimbus/vm/interpreter_dispatch.nim b/nimbus/vm/interpreter_dispatch.nim index 1038344e0..baadcfd96 100644 --- a/nimbus/vm/interpreter_dispatch.nim +++ b/nimbus/vm/interpreter_dispatch.nim @@ -231,25 +231,14 @@ proc opTableToCaseStmt(opTable: array[Op, NimNode], computation: NimNode): NimNo # Wrap the case statement in while true + computed goto result = quote do: - try: - let fork = `computation`.getFork - if `computation`.execPrecompiles(fork): - computation.nextProc() - return - - if `computation`.tracingEnabled: - `computation`.prepareTracer() - `computation`.instr = `computation`.code.next() - while true: - {.computedGoto.} - # TODO lots of macro magic here to unravel, with chronicles... - # `computation`.logger.log($`computation`.stack & "\n\n", fgGreen) - `result` - except: - let msg = getCurrentExceptionMsg() - let errorMsg = "Opcode Dispatch Error msg=" & msg & ", depth=" & $computation.msg.depth - `computation`.setError(errorMsg, true) - computation.nextProc() + if `computation`.tracingEnabled: + `computation`.prepareTracer() + `computation`.instr = `computation`.code.next() + while true: + {.computedGoto.} + # TODO lots of macro magic here to unravel, with chronicles... + # `computation`.logger.log($`computation`.stack & "\n\n", fgGreen) + `result` macro genFrontierDispatch(computation: BaseComputation): untyped = result = opTableToCaseStmt(FrontierOpDispatch, computation) @@ -263,10 +252,8 @@ proc frontierVM(computation: BaseComputation) = proc homesteadVM(computation: BaseComputation) = genHomesteadDispatch(computation) -proc executeOpcodes(computation: BaseComputation) = +proc selectVM(computation: BaseComputation, fork: Fork) = # TODO: Optimise getting fork and updating opCodeExec only when necessary - let fork = computation.getFork - case fork of FkFrontier..FkThawing: computation.frontierVM() @@ -274,3 +261,15 @@ proc executeOpcodes(computation: BaseComputation) = computation.homesteadVM() else: raise newException(VMError, "Unknown or not implemented fork: " & $fork) + +proc executeOpcodes(computation: BaseComputation) = + try: + let fork = computation.getFork + if `computation`.execPrecompiles(fork): + computation.nextProc() + return + computation.selectVM(fork) + except: + let msg = getCurrentExceptionMsg() + computation.setError(&"Opcode Dispatch Error msg={msg}, depth={computation.msg.depth}", true) + computation.nextProc() From d37d7fa6a5ad3f918458bc2d2a0379b5e9b73e4a Mon Sep 17 00:00:00 2001 From: andri lim Date: Thu, 4 Apr 2019 17:23:28 +0700 Subject: [PATCH 11/12] remove computedGoto pragma --- nimbus/vm/interpreter_dispatch.nim | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/nimbus/vm/interpreter_dispatch.nim b/nimbus/vm/interpreter_dispatch.nim index baadcfd96..ee5ce8469 100644 --- a/nimbus/vm/interpreter_dispatch.nim +++ b/nimbus/vm/interpreter_dispatch.nim @@ -211,7 +211,6 @@ proc opTableToCaseStmt(opTable: array[Op, NimNode], computation: NimNode): NimNo `opImpl`(`computation`) if `computation`.tracingEnabled: `computation`.traceOpCodeEnded(`asOp`, `computation`.opIndex) - `instr` = `computation`.code.next() else: quote do: if `computation`.tracingEnabled: @@ -221,8 +220,6 @@ proc opTableToCaseStmt(opTable: array[Op, NimNode], computation: NimNode): NimNo `computation`.traceOpCodeEnded(`asOp`, `computation`.opIndex) when `asOp` in {Return, Revert, SelfDestruct}: break - else: - `instr` = `computation`.code.next() result.add nnkOfBranch.newTree( newIdentNode($op), @@ -233,9 +230,11 @@ proc opTableToCaseStmt(opTable: array[Op, NimNode], computation: NimNode): NimNo result = quote do: if `computation`.tracingEnabled: `computation`.prepareTracer() - `computation`.instr = `computation`.code.next() while true: - {.computedGoto.} + `instr` = `computation`.code.next() + #{.computedGoto.} + # computed goto causing stack overflow, it consumes a lot of space + # we could use manual jump table instead # TODO lots of macro magic here to unravel, with chronicles... # `computation`.logger.log($`computation`.stack & "\n\n", fgGreen) `result` From f97bd57aa20ea8332ed80488f7b4aa7a234266d0 Mon Sep 17 00:00:00 2001 From: andri lim Date: Thu, 4 Apr 2019 17:25:10 +0700 Subject: [PATCH 12/12] GST +52 --- GeneralStateTests.md | 116 ++++++++++++++-------------- tests/test_generalstate_failing.nim | 4 +- 2 files changed, 60 insertions(+), 60 deletions(-) diff --git a/GeneralStateTests.md b/GeneralStateTests.md index f9b4e6a26..17bfd822d 100644 --- a/GeneralStateTests.md +++ b/GeneralStateTests.md @@ -52,10 +52,10 @@ GeneralStateTests OK: 0/46 Fail: 0/46 Skip: 46/46 ## stAttackTest ```diff - ContractCreationSpam.json Skip ++ ContractCreationSpam.json OK + CrashingTransaction.json OK ``` -OK: 1/2 Fail: 0/2 Skip: 1/2 +OK: 2/2 Fail: 0/2 Skip: 0/2 ## stBadOpcode ```diff + badOpcodes.json OK @@ -89,7 +89,7 @@ OK: 2/3 Fail: 0/3 Skip: 1/3 + callcallcallcode_001_OOGMBefore.json OK + callcallcallcode_001_SuicideEnd.json OK + callcallcallcode_001_SuicideMiddle.json OK - callcallcallcode_ABCB_RECURSIVE.json Skip ++ callcallcallcode_ABCB_RECURSIVE.json OK + callcallcode_01.json OK + callcallcode_01_OOGE.json OK + callcallcode_01_SuicideEnd.json OK @@ -99,14 +99,14 @@ OK: 2/3 Fail: 0/3 Skip: 1/3 + callcallcodecall_010_OOGMBefore.json OK + callcallcodecall_010_SuicideEnd.json OK + callcallcodecall_010_SuicideMiddle.json OK - callcallcodecall_ABCB_RECURSIVE.json Skip ++ callcallcodecall_ABCB_RECURSIVE.json OK + callcallcodecallcode_011.json OK + callcallcodecallcode_011_OOGE.json OK + callcallcodecallcode_011_OOGMAfter.json OK + callcallcodecallcode_011_OOGMBefore.json OK + callcallcodecallcode_011_SuicideEnd.json OK + callcallcodecallcode_011_SuicideMiddle.json OK - callcallcodecallcode_ABCB_RECURSIVE.json Skip ++ callcallcodecallcode_ABCB_RECURSIVE.json OK + callcodeDynamicCode.json OK + callcodeDynamicCode2SelfCall.json OK + callcodeEmptycontract.json OK @@ -124,14 +124,14 @@ OK: 2/3 Fail: 0/3 Skip: 1/3 + callcodecallcall_100_OOGMBefore.json OK + callcodecallcall_100_SuicideEnd.json OK + callcodecallcall_100_SuicideMiddle.json OK - callcodecallcall_ABCB_RECURSIVE.json Skip ++ callcodecallcall_ABCB_RECURSIVE.json OK + callcodecallcallcode_101.json OK + callcodecallcallcode_101_OOGE.json OK + callcodecallcallcode_101_OOGMAfter.json OK + callcodecallcallcode_101_OOGMBefore.json OK + callcodecallcallcode_101_SuicideEnd.json OK + callcodecallcallcode_101_SuicideMiddle.json OK - callcodecallcallcode_ABCB_RECURSIVE.json Skip ++ callcodecallcallcode_ABCB_RECURSIVE.json OK + callcodecallcode_11.json OK + callcodecallcode_11_OOGE.json OK + callcodecallcode_11_SuicideEnd.json OK @@ -141,25 +141,25 @@ OK: 2/3 Fail: 0/3 Skip: 1/3 + callcodecallcodecall_110_OOGMBefore.json OK + callcodecallcodecall_110_SuicideEnd.json OK + callcodecallcodecall_110_SuicideMiddle.json OK - callcodecallcodecall_ABCB_RECURSIVE.json Skip ++ callcodecallcodecall_ABCB_RECURSIVE.json OK + callcodecallcodecallcode_111.json OK + callcodecallcodecallcode_111_OOGE.json OK + callcodecallcodecallcode_111_OOGMAfter.json OK + callcodecallcodecallcode_111_OOGMBefore.json OK + callcodecallcodecallcode_111_SuicideEnd.json OK + callcodecallcodecallcode_111_SuicideMiddle.json OK - callcodecallcodecallcode_ABCB_RECURSIVE.json Skip ++ callcodecallcodecallcode_ABCB_RECURSIVE.json OK ``` -OK: 72/79 Fail: 0/79 Skip: 7/79 +OK: 79/79 Fail: 0/79 Skip: 0/79 ## stCallCreateCallCodeTest ```diff - Call1024BalanceTooLow.json Skip - Call1024OOG.json Skip - Call1024PreCalls.json Skip ++ Call1024BalanceTooLow.json OK ++ Call1024OOG.json OK ++ Call1024PreCalls.json OK + CallLoseGasOOG.json OK - CallRecursiveBombPreCall.json Skip ++ CallRecursiveBombPreCall.json OK + Callcode1024BalanceTooLow.json OK - Callcode1024OOG.json Skip ++ Callcode1024OOG.json OK + CallcodeLoseGasOOG.json OK + callOutput1.json OK + callOutput2.json OK @@ -193,7 +193,7 @@ OK: 72/79 Fail: 0/79 Skip: 7/79 + createNameRegistratorPreStore1NotEnoughGas.json OK + createNameRegistratorendowmentTooHigh.json OK ``` -OK: 34/39 Fail: 0/39 Skip: 5/39 +OK: 39/39 Fail: 0/39 Skip: 0/39 ## stCallDelegateCodesCallCodeHomestead ```diff + callcallcallcode_001.json OK @@ -202,7 +202,7 @@ OK: 34/39 Fail: 0/39 Skip: 5/39 + callcallcallcode_001_OOGMBefore.json OK + callcallcallcode_001_SuicideEnd.json OK + callcallcallcode_001_SuicideMiddle.json OK - callcallcallcode_ABCB_RECURSIVE.json Skip ++ callcallcallcode_ABCB_RECURSIVE.json OK + callcallcode_01.json OK + callcallcode_01_OOGE.json OK + callcallcode_01_SuicideEnd.json OK @@ -212,14 +212,14 @@ OK: 34/39 Fail: 0/39 Skip: 5/39 + callcallcodecall_010_OOGMBefore.json OK + callcallcodecall_010_SuicideEnd.json OK + callcallcodecall_010_SuicideMiddle.json OK - callcallcodecall_ABCB_RECURSIVE.json Skip ++ callcallcodecall_ABCB_RECURSIVE.json OK + callcallcodecallcode_011.json OK + callcallcodecallcode_011_OOGE.json OK + callcallcodecallcode_011_OOGMAfter.json OK + callcallcodecallcode_011_OOGMBefore.json OK + callcallcodecallcode_011_SuicideEnd.json OK + callcallcodecallcode_011_SuicideMiddle.json OK - callcallcodecallcode_ABCB_RECURSIVE.json Skip ++ callcallcodecallcode_ABCB_RECURSIVE.json OK + callcodecall_10.json OK + callcodecall_10_OOGE.json OK + callcodecall_10_SuicideEnd.json OK @@ -229,14 +229,14 @@ OK: 34/39 Fail: 0/39 Skip: 5/39 + callcodecallcall_100_OOGMBefore.json OK + callcodecallcall_100_SuicideEnd.json OK + callcodecallcall_100_SuicideMiddle.json OK - callcodecallcall_ABCB_RECURSIVE.json Skip ++ callcodecallcall_ABCB_RECURSIVE.json OK + callcodecallcallcode_101.json OK + callcodecallcallcode_101_OOGE.json OK + callcodecallcallcode_101_OOGMAfter.json OK + callcodecallcallcode_101_OOGMBefore.json OK + callcodecallcallcode_101_SuicideEnd.json OK + callcodecallcallcode_101_SuicideMiddle.json OK - callcodecallcallcode_ABCB_RECURSIVE.json Skip ++ callcodecallcallcode_ABCB_RECURSIVE.json OK + callcodecallcode_11.json OK + callcodecallcode_11_OOGE.json OK + callcodecallcode_11_SuicideEnd.json OK @@ -246,16 +246,16 @@ OK: 34/39 Fail: 0/39 Skip: 5/39 + callcodecallcodecall_110_OOGMBefore.json OK + callcodecallcodecall_110_SuicideEnd.json OK + callcodecallcodecall_110_SuicideMiddle.json OK - callcodecallcodecall_ABCB_RECURSIVE.json Skip ++ callcodecallcodecall_ABCB_RECURSIVE.json OK + callcodecallcodecallcode_111.json OK + callcodecallcodecallcode_111_OOGE.json OK + callcodecallcodecallcode_111_OOGMAfter.json OK + callcodecallcodecallcode_111_OOGMBefore.json OK + callcodecallcodecallcode_111_SuicideEnd.json OK + callcodecallcodecallcode_111_SuicideMiddle.json OK - callcodecallcodecallcode_ABCB_RECURSIVE.json Skip ++ callcodecallcodecallcode_ABCB_RECURSIVE.json OK ``` -OK: 51/58 Fail: 0/58 Skip: 7/58 +OK: 58/58 Fail: 0/58 Skip: 0/58 ## stCallDelegateCodesHomestead ```diff + callcallcallcode_001.json OK @@ -264,7 +264,7 @@ OK: 51/58 Fail: 0/58 Skip: 7/58 + callcallcallcode_001_OOGMBefore.json OK + callcallcallcode_001_SuicideEnd.json OK + callcallcallcode_001_SuicideMiddle.json OK - callcallcallcode_ABCB_RECURSIVE.json Skip ++ callcallcallcode_ABCB_RECURSIVE.json OK + callcallcode_01.json OK + callcallcode_01_OOGE.json OK + callcallcode_01_SuicideEnd.json OK @@ -274,14 +274,14 @@ OK: 51/58 Fail: 0/58 Skip: 7/58 + callcallcodecall_010_OOGMBefore.json OK + callcallcodecall_010_SuicideEnd.json OK + callcallcodecall_010_SuicideMiddle.json OK - callcallcodecall_ABCB_RECURSIVE.json Skip ++ callcallcodecall_ABCB_RECURSIVE.json OK + callcallcodecallcode_011.json OK + callcallcodecallcode_011_OOGE.json OK + callcallcodecallcode_011_OOGMAfter.json OK + callcallcodecallcode_011_OOGMBefore.json OK + callcallcodecallcode_011_SuicideEnd.json OK + callcallcodecallcode_011_SuicideMiddle.json OK - callcallcodecallcode_ABCB_RECURSIVE.json Skip ++ callcallcodecallcode_ABCB_RECURSIVE.json OK + callcodecall_10.json OK + callcodecall_10_OOGE.json OK + callcodecall_10_SuicideEnd.json OK @@ -291,14 +291,14 @@ OK: 51/58 Fail: 0/58 Skip: 7/58 + callcodecallcall_100_OOGMBefore.json OK + callcodecallcall_100_SuicideEnd.json OK + callcodecallcall_100_SuicideMiddle.json OK - callcodecallcall_ABCB_RECURSIVE.json Skip ++ callcodecallcall_ABCB_RECURSIVE.json OK + callcodecallcallcode_101.json OK + callcodecallcallcode_101_OOGE.json OK + callcodecallcallcode_101_OOGMAfter.json OK + callcodecallcallcode_101_OOGMBefore.json OK + callcodecallcallcode_101_SuicideEnd.json OK + callcodecallcallcode_101_SuicideMiddle.json OK - callcodecallcallcode_ABCB_RECURSIVE.json Skip ++ callcodecallcallcode_ABCB_RECURSIVE.json OK + callcodecallcode_11.json OK + callcodecallcode_11_OOGE.json OK + callcodecallcode_11_SuicideEnd.json OK @@ -308,20 +308,20 @@ OK: 51/58 Fail: 0/58 Skip: 7/58 + callcodecallcodecall_110_OOGMBefore.json OK + callcodecallcodecall_110_SuicideEnd.json OK + callcodecallcodecall_110_SuicideMiddle.json OK - callcodecallcodecall_ABCB_RECURSIVE.json Skip ++ callcodecallcodecall_ABCB_RECURSIVE.json OK + callcodecallcodecallcode_111.json OK + callcodecallcodecallcode_111_OOGE.json OK + callcodecallcodecallcode_111_OOGMAfter.json OK + callcodecallcodecallcode_111_OOGMBefore.json OK + callcodecallcodecallcode_111_SuicideEnd.json OK + callcodecallcodecallcode_111_SuicideMiddle.json OK - callcodecallcodecallcode_ABCB_RECURSIVE.json Skip ++ callcodecallcodecallcode_ABCB_RECURSIVE.json OK ``` -OK: 51/58 Fail: 0/58 Skip: 7/58 +OK: 58/58 Fail: 0/58 Skip: 0/58 ## stChangedEIP150 ```diff - Call1024BalanceTooLow.json Skip - Call1024PreCalls.json Skip ++ Call1024BalanceTooLow.json OK ++ Call1024PreCalls.json OK + Callcode1024BalanceTooLow.json OK + callcall_00_OOGE_1.json OK + callcall_00_OOGE_2.json OK @@ -351,7 +351,7 @@ OK: 51/58 Fail: 0/58 Skip: 7/58 + contractCreationMakeCallThatAskMoreGasThenTransactionProvided.jsonOK + createInitFail_OOGduringInit.json OK ``` -OK: 28/30 Fail: 0/30 Skip: 2/30 +OK: 30/30 Fail: 0/30 Skip: 0/30 ## stCodeCopyTest ```diff + ExtCodeCopyTests.json OK @@ -400,14 +400,14 @@ OK: 3/3 Fail: 0/3 Skip: 0/3 OK: 23/30 Fail: 0/30 Skip: 7/30 ## stDelegatecallTestHomestead ```diff - Call1024BalanceTooLow.json Skip - Call1024OOG.json Skip - Call1024PreCalls.json Skip ++ Call1024BalanceTooLow.json OK ++ Call1024OOG.json OK ++ Call1024PreCalls.json OK + CallLoseGasOOG.json OK - CallRecursiveBombPreCall.json Skip ++ CallRecursiveBombPreCall.json OK + CallcodeLoseGasOOG.json OK - Delegatecall1024.json Skip - Delegatecall1024OOG.json Skip ++ Delegatecall1024.json OK ++ Delegatecall1024OOG.json OK + callOutput1.json OK + callOutput2.json OK + callOutput3.json OK @@ -435,7 +435,7 @@ OK: 23/30 Fail: 0/30 Skip: 7/30 + delegatecodeDynamicCode.json OK + delegatecodeDynamicCode2SelfCall.json OK ``` -OK: 28/34 Fail: 0/34 Skip: 6/34 +OK: 34/34 Fail: 0/34 Skip: 0/34 ## stEIP150Specific ```diff CallAndCallcodeConsumeMoreGasThenTransactionHas.json Skip @@ -1518,10 +1518,10 @@ OK: 321/327 Fail: 0/327 Skip: 6/327 OK: 223/227 Fail: 0/227 Skip: 4/227 ## stRecursiveCreate ```diff - recursiveCreate.json Skip - recursiveCreateReturnValue.json Skip ++ recursiveCreate.json OK ++ recursiveCreateReturnValue.json OK ``` -OK: 0/2 Fail: 0/2 Skip: 2/2 +OK: 2/2 Fail: 0/2 Skip: 0/2 ## stRefundTest ```diff + refund50_1.json OK @@ -1700,8 +1700,8 @@ OK: 16/16 Fail: 0/16 Skip: 0/16 ## stSpecialTest ```diff + FailedCreateRevertsDeletion.json OK - JUMPDEST_Attack.json Skip - JUMPDEST_AttackwithJump.json Skip ++ JUMPDEST_Attack.json OK ++ JUMPDEST_AttackwithJump.json OK OverflowGasMakeMoney.json Skip + StackDepthLimitSEC.json OK block504980.json Skip @@ -1713,7 +1713,7 @@ OK: 16/16 Fail: 0/16 Skip: 0/16 txCost-sec73.json Skip + tx_e1c174e2.json OK ``` -OK: 5/13 Fail: 0/13 Skip: 8/13 +OK: 7/13 Fail: 0/13 Skip: 6/13 ## stStackTests ```diff shallowStack.json Skip @@ -2016,19 +2016,19 @@ OK: 0/284 Fail: 0/284 Skip: 284/284 ## stSystemOperationsTest ```diff + ABAcalls0.json OK - ABAcalls1.json Skip - ABAcalls2.json Skip ++ ABAcalls1.json OK ++ ABAcalls2.json OK + ABAcalls3.json OK + ABAcallsSuicide0.json OK + ABAcallsSuicide1.json OK + Call10.json OK - CallRecursiveBomb0.json Skip - CallRecursiveBomb0_OOG_atMaxCallDepth.json Skip - CallRecursiveBomb1.json Skip - CallRecursiveBomb2.json Skip ++ CallRecursiveBomb0.json OK ++ CallRecursiveBomb0_OOG_atMaxCallDepth.json OK ++ CallRecursiveBomb1.json OK ++ CallRecursiveBomb2.json OK + CallRecursiveBomb3.json OK - CallRecursiveBombLog.json Skip - CallRecursiveBombLog2.json Skip ++ CallRecursiveBombLog.json OK ++ CallRecursiveBombLog2.json OK + CallToNameRegistrator0.json OK + CallToNameRegistratorAddressTooBigLeft.json OK + CallToNameRegistratorAddressTooBigRight.json OK @@ -2083,7 +2083,7 @@ OK: 0/284 Fail: 0/284 Skip: 284/284 + suicideSendEtherToMe.json OK + testRandomTest.json OK ``` -OK: 57/67 Fail: 0/67 Skip: 10/67 +OK: 65/67 Fail: 0/67 Skip: 2/67 ## stTransactionTest ```diff + ContractStoreClearsOOG.json OK @@ -2520,4 +2520,4 @@ OK: 5/133 Fail: 0/133 Skip: 128/133 OK: 0/130 Fail: 0/130 Skip: 130/130 ---TOTAL--- -OK: 1438/2334 Fail: 0/2334 Skip: 896/2334 +OK: 1485/2334 Fail: 0/2334 Skip: 849/2334 diff --git a/tests/test_generalstate_failing.nim b/tests/test_generalstate_failing.nim index fcd00bc1e..1ceaecc77 100644 --- a/tests/test_generalstate_failing.nim +++ b/tests/test_generalstate_failing.nim @@ -16,7 +16,7 @@ func allowedFailingGeneralStateTest*(folder, name: string): bool = "randomStatetest14.json", # SHA3 offset "randomStatetest85.json", # CALL* memoffset # Homestead recursives - "ContractCreationSpam.json", + #["ContractCreationSpam.json", "Call1024OOG.json", "Call1024PreCalls.json", "CallRecursiveBombPreCall.json", @@ -43,6 +43,6 @@ func allowedFailingGeneralStateTest*(folder, name: string): bool = "callcodecallcallcode_ABCB_RECURSIVE.json", "callcodecallcodecall_ABCB_RECURSIVE.json", "callcodecallcodecallcode_ABCB_RECURSIVE.json", - "callcallcallcode_ABCB_RECURSIVE.json", + "callcallcallcode_ABCB_RECURSIVE.json",]# ] result = name in allowedFailingGeneralStateTests