diff --git a/nimbus/vm/interpreter/gas_costs.nim b/nimbus/vm/interpreter/gas_costs.nim index 35366fdff..0b5497caa 100644 --- a/nimbus/vm/interpreter/gas_costs.nim +++ b/nimbus/vm/interpreter/gas_costs.nim @@ -48,7 +48,9 @@ type GasSha3, # Paid for each SHA3 operation. GasSha3Word, # Paid for each word (rounded up) for input data to a SHA3 operation. GasCopy, # Partial payment for COPY operations, multiplied by words copied, rounded up. - GasBlockhash # Payment for BLOCKHASH operation. + GasBlockhash, # Payment for BLOCKHASH operation. + GasArithmetic, # Payment for bitwise Shl and Shr operators + GasExtCodeHash # Payment for contract's code hashing GasFeeSchedule = array[GasFeeKind, GasInt] @@ -400,6 +402,9 @@ template gasCosts(fork: Fork, prefix, ResultGasCostsName: untyped) = Xor: fixed GasVeryLow, Not: fixed GasVeryLow, Byte: fixed GasVeryLow, + Shl: fixed GasArithmetic, + Shr: fixed GasArithmetic, + Sar: fixed GasVeryLow, # 20s: SHA3 Sha3: memExpansion `prefix gasSha3`, @@ -420,6 +425,7 @@ template gasCosts(fork: Fork, prefix, ResultGasCostsName: untyped) = ExtCodeCopy: memExpansion `prefix gasExtCodeCopy`, ReturnDataSize: fixed GasBase, ReturnDataCopy: memExpansion `prefix gasCopy`, + ExtCodeHash: fixed GasExtCodeHash, # 40s: Block Information Blockhash: fixed GasBlockhash, @@ -526,6 +532,7 @@ template gasCosts(fork: Fork, prefix, ResultGasCostsName: untyped) = CallCode: complex `prefix gasCall`, Return: memExpansion `prefix gasHalt`, DelegateCall: complex `prefix gasCall`, + Create2: complex `prefix gasCall`, StaticCall: complex `prefix gasCall`, Revert: memExpansion `prefix gasHalt`, Invalid: fixed GasZero, @@ -570,7 +577,9 @@ const GasSha3: 30, GasSha3Word: 6, GasCopy: 3, - GasBlockhash: 20 + GasBlockhash: 20, + GasArithmetic: 35, + GasExtCodeHash: 400 ] # Create the schedule for each forks @@ -605,7 +614,8 @@ const FkDao: HomesteadGasFees, FkTangerine: TangerineGasFees, FkSpurious: SpuriousGasFees, - FkByzantium: SpuriousGasFees, # not supported yet + FkByzantium: SpuriousGasFees, + FkConstantinople: SpuriousGasFees ] diff --git a/nimbus/vm/interpreter/opcode_values.nim b/nimbus/vm/interpreter/opcode_values.nim index d214fafa2..916b155e1 100644 --- a/nimbus/vm/interpreter/opcode_values.nim +++ b/nimbus/vm/interpreter/opcode_values.nim @@ -46,6 +46,9 @@ fill_enum_holes: Xor = 0x18, # Bitwise XOR operation. Not = 0x19, # Bitwise NOT operation. Byte = 0x1A, # Retrieve single byte from word. + Shl = 0x1B, # Shift left + Shr = 0x1C, # Logical shift right + Sar = 0x1D, # Arithmetic shift right # 20s: SHA3 Sha3 = 0x20, # Compute Keccak-256 hash. @@ -66,6 +69,7 @@ fill_enum_holes: ExtCodeCopy = 0x3c, # Copy an account's code to memory. ReturnDataSize = 0x3d, # Get size of output data from the previous call from the current environment. ReturnDataCopy = 0x3e, # Copy output data from the previous call to memory. + ExtCodeHash = 0x3f, # Returns the keccak256 hash of a contract’s code # 40s: Block Information Blockhash = 0x40, # Get the hash of one of the 256 most recent complete blocks. @@ -172,6 +176,7 @@ fill_enum_holes: CallCode = 0xf2, # Message-call into this account with an alternative account's code. Return = 0xf3, # Halt execution returning output data. DelegateCall = 0xf4, # Message-call into this account with an alternative account's code, but persisting the current values for sender and value. + Create2 = 0xf5, # Behaves identically to CREATE, except using keccak256( 0xff ++ address ++ salt ++ keccak256(init_code))[12:] StaticCall = 0xfa, # Static message-call into an account. Revert = 0xfd, # Halt execution reverting state changes but returning data and remaining gas. Invalid = 0xfe, # Designated invalid instruction. diff --git a/nimbus/vm/interpreter/opcodes_impl.nim b/nimbus/vm/interpreter/opcodes_impl.nim index 0861b0bc9..e88707c12 100644 --- a/nimbus/vm/interpreter/opcodes_impl.nim +++ b/nimbus/vm/interpreter/opcodes_impl.nim @@ -881,3 +881,24 @@ op selfDestructEip161, inline = false: let gasCost = computation.gasCosts[SelfDestruct].c_handler(0.u256, gasParams).gasCost computation.gasMeter.consumeGas(gasCost, reason = "SELFDESTRUCT EIP161") selfDestructImpl(computation, beneficiary) + +# Constantinople's new opcodes +op shlOp, inline = true, num, shift: + # TODO: implementation + discard + +op shrOp, inline = true, num, shift: + # TODO: implementation + discard + +op sarOp, inline = true, num, shift: + # TODO: implementation + discard + +op extCodeHash, inline = true, address: + # TODO: implementation + discard + +op create2, inline = false: + # TODO: implementation + discard diff --git a/nimbus/vm/interpreter/vm_forks.nim b/nimbus/vm/interpreter/vm_forks.nim index d644f46c4..f352529b8 100644 --- a/nimbus/vm/interpreter/vm_forks.nim +++ b/nimbus/vm/interpreter/vm_forks.nim @@ -15,17 +15,19 @@ type FkDao, FkTangerine, FkSpurious, - FkByzantium + FkByzantium, + FkConstantinople const forkBlocks*: array[Fork, Uint256] = [ - FkFrontier: 1.u256, # 30/07/2015 19:26:28 - FkThawing: 200_000.u256, # 08/09/2015 01:33:09 - FkHomestead: 1_150_000.u256, # 14/03/2016 20:49:53 - FkDao: 1_920_000.u256, # 20/07/2016 17:20:40 - FkTangerine: 2_463_000.u256, # 18/10/2016 17:19:31 - FkSpurious: 2_675_000.u256, # 22/11/2016 18:15:44 - FkByzantium: 4_370_000.u256 # 16/10/2017 09:22:11 + FkFrontier: 1.u256, # 30/07/2015 19:26:28 + FkThawing: 200_000.u256, # 08/09/2015 01:33:09 + FkHomestead: 1_150_000.u256, # 14/03/2016 20:49:53 + FkDao: 1_920_000.u256, # 20/07/2016 17:20:40 + FkTangerine: 2_463_000.u256, # 18/10/2016 17:19:31 + FkSpurious: 2_675_000.u256, # 22/11/2016 18:15:44 + FkByzantium: 4_370_000.u256, # 16/10/2017 09:22:11 + FkConstantinople: 7_280_000.u256 # 28/02/2019 07:52:04 ] proc toFork*(blockNumber: UInt256): Fork = @@ -44,8 +46,8 @@ proc toFork*(blockNumber: UInt256): Fork = elif blockNumber < forkBlocks[FkTangerine]: FkDao elif blockNumber < forkBlocks[FkSpurious]: FkTangerine elif blockNumber < forkBlocks[FkByzantium]: FkSpurious - else: - FkByzantium # Update for constantinople when announced + elif blockNumber < forkBlocks[FkConstantinople]: FkByzantium + else: FkConstantinople proc `$`*(fork: Fork): string = case fork @@ -56,4 +58,5 @@ proc `$`*(fork: Fork): string = of FkTangerine: result = "Tangerine Whistle" of FkSpurious: result = "Spurious Dragon" of FkByzantium: result = "Byzantium" + of FkConstantinople: result = "Constantinople" diff --git a/nimbus/vm/interpreter_dispatch.nim b/nimbus/vm/interpreter_dispatch.nim index 9054292ea..a38e29817 100644 --- a/nimbus/vm/interpreter_dispatch.nim +++ b/nimbus/vm/interpreter_dispatch.nim @@ -205,6 +205,16 @@ proc genByzantiumJumpTable(ops: array[Op, NimNode]): array[Op, NimNode] {.compil let ByzantiumOpDispatch {.compileTime.}: array[Op, NimNode] = genByzantiumJumpTable(SpuriousOpDispatch) +proc genConstantinopleJumpTable(ops: array[Op, NimNode]): array[Op, NimNode] {.compileTime.} = + result = ops + result[Shl] = newIdentNode "shlOp" + result[Shr] = newIdentNode "shrOp" + result[Sar] = newIdentNode "sarOp" + result[ExtCodeHash] = newIdentNode "extCodeHash" + result[Create2] = newIdentNode "create2" + +let ConstantinopleOpDispatch {.compileTime.}: array[Op, NimNode] = genConstantinopleJumpTable(ByzantiumOpDispatch) + proc opTableToCaseStmt(opTable: array[Op, NimNode], computation: NimNode): NimNode = let instr = quote do: `computation`.instr @@ -275,6 +285,9 @@ macro genSpuriousDispatch(computation: BaseComputation): untyped = macro genByzantiumDispatch(computation: BaseComputation): untyped = result = opTableToCaseStmt(ByzantiumOpDispatch, computation) +macro genConstantinopleDispatch(computation: BaseComputation): untyped = + result = opTableToCaseStmt(ConstantinopleOpDispatch, computation) + proc frontierVM(computation: BaseComputation) = genFrontierDispatch(computation) @@ -290,6 +303,9 @@ proc spuriousVM(computation: BaseComputation) {.gcsafe.} = proc byzantiumVM(computation: BaseComputation) {.gcsafe.} = genByzantiumDispatch(computation) +proc constantinopleVM(computation: BaseComputation) {.gcsafe.} = + genConstantinopleDispatch(computation) + proc selectVM(computation: BaseComputation, fork: Fork) {.gcsafe.} = # TODO: Optimise getting fork and updating opCodeExec only when necessary case fork @@ -303,6 +319,8 @@ proc selectVM(computation: BaseComputation, fork: Fork) {.gcsafe.} = computation.spuriousVM() of FKByzantium: computation.byzantiumVM() + else: + computation.constantinopleVM() proc executeOpcodes(computation: BaseComputation) = try: diff --git a/tests/test_helpers.nim b/tests/test_helpers.nim index 61a046b30..ab5941ba6 100644 --- a/tests/test_helpers.nim +++ b/tests/test_helpers.nim @@ -21,6 +21,7 @@ const FkTangerine: "EIP150", FkSpurious: "EIP158", FkByzantium: "Byzantium", + FkConstantinople: "ConstantinopleFix" }.toTable supportedForks* = {FkFrontier, FkHomestead, FkTangerine, FkSpurious, FkByzantium}