re-integrated/added Create and Create2 handlers

This commit is contained in:
Jordan Hrycaj 2021-04-16 11:53:05 +01:00 committed by zah
parent 1bb6ef43a1
commit 1bdbfda37f
8 changed files with 280 additions and 96 deletions

View File

@ -194,8 +194,7 @@ type
## alternative account's code, but persisting the ## alternative account's code, but persisting the
## current values for sender and value. ## current values for sender and value.
Create2 = 0xf5, ## Behaves identically to CREATE, except using Create2 = 0xf5, ## Behaves identically to CREATE, except using
## keccak256( 0xff ++ address ++ salt ++ ## keccak256
## keccak256(init_code))[12:]
Nop0xF6, Nop0xF7, Nop0xF8, Nop0xF9, ## .. Nop0xF6, Nop0xF7, Nop0xF8, Nop0xF9, ## ..

View File

@ -22,7 +22,7 @@ import
./op_handlers/[oph_defs, ./op_handlers/[oph_defs,
oph_arithmetic, oph_hash, oph_envinfo, oph_blockdata, oph_arithmetic, oph_hash, oph_envinfo, oph_blockdata,
oph_memory, oph_push, oph_dup, oph_swap, oph_log, oph_memory, oph_push, oph_dup, oph_swap, oph_log,
oph_sysops] oph_create, oph_sysops]
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Helper # Helper
@ -51,7 +51,7 @@ proc mkOpTable(select: Fork): array[Op,Vm2OpExec] {.compileTime.} =
result.importList(select, vm2OpExecDup, "Dup") result.importList(select, vm2OpExecDup, "Dup")
result.importList(select, vm2OpExecSwap, "Swap") result.importList(select, vm2OpExecSwap, "Swap")
result.importList(select, vm2OpExecLog, "Log") result.importList(select, vm2OpExecLog, "Log")
#result.importList(select, vm2OpExecCreate, "Create") result.importList(select, vm2OpExecCreate, "Create")
#result.importList(select, vm2OpExecCall, "Call") #result.importList(select, vm2OpExecCall, "Call")
result.importList(select, vm2OpExecSysOp, "SysOp") result.importList(select, vm2OpExecSysOp, "SysOp")

View File

@ -41,8 +41,6 @@ when not breakCircularDependency:
else: else:
import macros import macros
var blindGasCosts: array[Op,int]
# copied from stack.nim # copied from stack.nim
macro genTupleType(len: static[int], elemType: untyped): untyped = macro genTupleType(len: static[int], elemType: untyped): untyped =
result = nnkTupleConstr.newNimNode() result = nnkTupleConstr.newNimNode()
@ -50,13 +48,13 @@ else:
# function stubs from stack.nim (to satisfy compiler logic) # function stubs from stack.nim (to satisfy compiler logic)
proc push[T](x: Stack; n: T) = discard proc push[T](x: Stack; n: T) = discard
proc popInt(x: var Stack): UInt256 = discard proc popInt(x: var Stack): UInt256 = result
proc popInt(x: var Stack, n: static[int]): auto = proc popInt(x: var Stack, n: static[int]): auto =
var rc: genTupleType(n, UInt256) var rc: genTupleType(n, UInt256)
return rc return rc
# function stubs from v2computation.nim (to satisfy compiler logic) # function stubs from v2computation.nim (to satisfy compiler logic)
proc gasCosts(c: Computation): array[Op,int] = blindGasCosts proc gasCosts(c: Computation): array[Op,int] = result
# function stubs from v2utils_numeric.nim # function stubs from v2utils_numeric.nim
proc extractSign(v: var UInt256, sign: var bool) = discard proc extractSign(v: var UInt256, sign: var bool) = discard
@ -67,7 +65,7 @@ else:
proc consumeGas(gasMeter: var GasMeter; amount: int; reason: string) = discard proc consumeGas(gasMeter: var GasMeter; amount: int; reason: string) = discard
# stubs from v2gas_costs.nim # stubs from v2gas_costs.nim
proc d_handler(x: int; value: Uint256): int = 0 proc d_handler(x: int; value: Uint256): int = result
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Kludge END # Kludge END

View File

@ -0,0 +1,255 @@
# Nimbus
# Copyright (c) 2018 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http://www.apache.org/licenses/LICENSE-2.0)
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or
# http://opensource.org/licenses/MIT)
# at your option. This file may not be copied, modified, or distributed except
# according to those terms.
## EVM Opcode Handlers: Create Operations
## ======================================
##
const
kludge {.intdefine.}: int = 0
breakCircularDependency {.used.} = kludge > 0
import
../../../errors,
./oph_defs,
./oph_helpers,
chronicles,
strformat,
stint
# ------------------------------------------------------------------------------
# Kludge BEGIN
# ------------------------------------------------------------------------------
when not breakCircularDependency:
import
../../../constants,
../../stack,
../../v2computation,
../../v2memory,
../../v2state,
../../v2types,
../gas_meter,
../utils/v2utils_numeric,
../v2gas_costs,
eth/common
else:
import macros
type
GasResult = tuple[gasCost, gasRefund: GasInt]
const
evmcCreate = 42
evmcCreate2 = 43
MaxCallDepth = 45
# function stubs from stack.nim (to satisfy compiler logic)
proc top[T](x: Stack, value: T) = discard
proc peekInt(x: Stack): UInt256 = result
proc popInt(x: var Stack): UInt256 = result
# function stubs from v2computation.nim (to satisfy compiler logic)
proc gasCosts(c: Computation): array[Op,int] = result
proc getBalance[T](c: Computation, address: T): Uint256 = result
proc newComputation[A,B](v:A, m:B, salt = 0.u256): Computation = new result
func shouldBurnGas(c: Computation): bool = result
proc isSuccess(c: Computation): bool = result
proc merge(c, child: Computation) = discard
template chainTo(c, d: Computation, e: untyped) =
c.child = d; c.continuation = proc() = e
# function stubs from v2utils_numeric.nim
func safeInt(x: Uint256): int = 0
# function stubs from v2memory.nim
proc len(mem: Memory): int = 0
proc extend(mem: var Memory; startPos: Natural; size: Natural) = discard
proc read(mem: var Memory, startPos: Natural, size: Natural): seq[byte] = @[]
# function stubs from gas_meter.nim
proc consumeGas(gasMeter: var GasMeter; amount: int; reason: string) = discard
proc returnGas(gasMeter: var GasMeter; amount: GasInt) = discard
# stubs from v2gas_costs.nim
type GasParams = object
case kind*: Op
of Create:
cr_currentMemSize, cr_memOffset, cr_memLength: int64
else:
discard
proc c_handler(x: int; y: Uint256, z: GasParams): GasResult = result
proc m_handler(x: int; curMemSize, memOffset, memLen: int64): int = result
# ------------------------------------------------------------------------------
# Kludge END
# ------------------------------------------------------------------------------
# ------------------------------------------------------------------------------
# Private, op handlers implementation
# ------------------------------------------------------------------------------
const
createOp: Vm2OpFn = proc(k: Vm2Ctx) =
## 0xf0, Create a new account with associated code
checkInStaticContext(k.cpt)
let
endowment = k.cpt.stack.popInt()
memPos = k.cpt.stack.popInt().safeInt
memLen = k.cpt.stack.peekInt().safeInt
salt = 0.u256
k.cpt.stack.top(0)
let gasParams = GasParams(
kind: Create,
cr_currentMemSize: k.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)
if k.cpt.msg.depth >= MaxCallDepth:
debug "Computation Failure",
reason = "Stack too deep",
maxDepth = MaxCallDepth,
depth = k.cpt.msg.depth
return
if endowment != 0:
let senderBalance = k.cpt.getBalance(k.cpt.msg.contractAddress)
if senderBalance < endowment:
debug "Computation Failure",
reason = "Insufficient funds available to transfer",
required = endowment,
balance = senderBalance
return
var createMsgGas = k.cpt.gasMeter.gasRemaining
if k.cpt.fork >= FkTangerine:
createMsgGas -= createMsgGas div 64
k.cpt.gasMeter.consumeGas(createMsgGas, reason = "CREATE")
let childMsg = Message(
kind: evmcCreate,
depth: k.cpt.msg.depth + 1,
gas: createMsgGas,
sender: k.cpt.msg.contractAddress,
value: endowment,
data: k.cpt.memory.read(memPos, memLen))
var child = newComputation(k.cpt.vmState, childMsg, salt)
k.cpt.chainTo(child):
if not child.shouldBurnGas:
k.cpt.gasMeter.returnGas(child.gasMeter.gasRemaining)
if child.isSuccess:
k.cpt.merge(child)
k.cpt.stack.top child.msg.contractAddress
else:
k.cpt.returnData = child.output
# ---------------------
create2Op: Vm2OpFn = proc(k: Vm2Ctx) =
## 0xf5, Behaves identically to CREATE, except using keccak256
checkInStaticContext(k.cpt)
let
endowment = k.cpt.stack.popInt()
memPos = k.cpt.stack.popInt().safeInt
memLen = k.cpt.stack.popInt().safeInt
salt = k.cpt.stack.peekInt()
k.cpt.stack.top(0)
let gasParams = GasParams(
kind: Create,
cr_currentMemSize: k.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)
k.cpt.gasMeter.consumeGas(
gasCost, reason = &"CREATE: GasCreate + {memLen} * memory expansion")
k.cpt.memory.extend(memPos, memLen)
k.cpt.returnData.setLen(0)
if k.cpt.msg.depth >= MaxCallDepth:
debug "Computation Failure",
reason = "Stack too deep",
maxDepth = MaxCallDepth,
depth = k.cpt.msg.depth
return
if endowment != 0:
let senderBalance = k.cpt.getBalance(k.cpt.msg.contractAddress)
if senderBalance < endowment:
debug "Computation Failure",
reason = "Insufficient funds available to transfer",
required = endowment,
balance = senderBalance
return
var createMsgGas = k.cpt.gasMeter.gasRemaining
if k.cpt.fork >= FkTangerine:
createMsgGas -= createMsgGas div 64
k.cpt.gasMeter.consumeGas(createMsgGas, reason = "CREATE")
let childMsg = Message(
kind: evmcCreate2,
depth: k.cpt.msg.depth + 1,
gas: createMsgGas,
sender: k.cpt.msg.contractAddress,
value: endowment,
data: k.cpt.memory.read(memPos, memLen))
var child = newComputation(k.cpt.vmState, childMsg, salt)
k.cpt.chainTo(child):
if not child.shouldBurnGas:
k.cpt.gasMeter.returnGas(child.gasMeter.gasRemaining)
if child.isSuccess:
k.cpt.merge(child)
k.cpt.stack.top child.msg.contractAddress
else:
k.cpt.returnData = child.output
# ------------------------------------------------------------------------------
# Public, op exec table entries
# ------------------------------------------------------------------------------
const
vm2OpExecCreate*: seq[Vm2OpExec] = @[
(opCode: Create, ## 0xf0, Create a new account with associated code
forks: Vm2OpAllForks,
info: "Create a new account with associated code",
exec: (prep: vm2OpIgnore,
run: createOp,
post: vm2OpIgnore)),
(opCode: Create2, ## 0xf5, Create using keccak256
forks: Vm2OpAllForks,
info: "Behaves identically to CREATE, except using keccak256",
exec: (prep: vm2OpIgnore,
run: create2Op,
post: vm2OpIgnore))]
# ------------------------------------------------------------------------------
# End
# ------------------------------------------------------------------------------

View File

@ -37,6 +37,8 @@ else:
{.fatal: "Flag \"vm2_enabled\" must be unset "& {.fatal: "Flag \"vm2_enabled\" must be unset "&
"while circular dependency breaker kludge is activated".} "while circular dependency breaker kludge is activated".}
type type
GasInt* = int
ReadOnlyStateDB* = ReadOnlyStateDB* =
seq[byte] seq[byte]
@ -51,8 +53,11 @@ else:
accountDb*: ReadOnlyStateDB accountDb*: ReadOnlyStateDB
Message* = ref object Message* = ref object
kind*: int
depth*: int
gas*: GasInt
contractAddress*: EthAddress contractAddress*: EthAddress
sender*: UInt256 sender*: EthAddress
value*: UInt256 value*: UInt256
data*: seq[byte] data*: seq[byte]
flags*: int flags*: int
@ -68,6 +73,8 @@ else:
code*: CodeStream code*: CodeStream
returnData*: seq[byte] returnData*: seq[byte]
fork*: Fork fork*: Fork
parent*, child*: Computation
continuation*: proc() {.gcsafe.}
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Kludge END # Kludge END

View File

@ -47,8 +47,6 @@ else:
emvcStatic = 1 emvcStatic = 1
ColdAccountAccessCost = 2 ColdAccountAccessCost = 2
WarmStorageReadCost = 3 WarmStorageReadCost = 3
type
GasInt = int
# function stubs from v2state.nim # function stubs from v2state.nim
template mutateStateDB(vmState: BaseVMState, body: untyped) = template mutateStateDB(vmState: BaseVMState, body: untyped) =

View File

@ -43,14 +43,9 @@ else:
import macros import macros
type type
GasInt = int
GasResult = tuple[gasCost, gasRefund: GasInt] GasResult = tuple[gasCost, gasRefund: GasInt]
const const
ColdAccountAccessCost = 42 ColdAccountAccessCost = 42
var
blindGasCosts: array[Op,int]
blindAddress: EthAddress
blindGasResult: GasResult
# copied from stack.nim # copied from stack.nim
macro genTupleType(len: static[int], elemType: untyped): untyped = macro genTupleType(len: static[int], elemType: untyped): untyped =
@ -58,23 +53,23 @@ else:
for i in 0 ..< len: result.add(elemType) for i in 0 ..< len: result.add(elemType)
# function stubs from stack.nim (to satisfy compiler logic) # function stubs from stack.nim (to satisfy compiler logic)
proc popAddress(x: var Stack): EthAddress = blindAddress proc popAddress(x: var Stack): EthAddress = result
proc popInt(x: var Stack, n: static[int]): auto = proc popInt(x: var Stack, n: static[int]): auto =
var rc: genTupleType(n, UInt256) var rc: genTupleType(n, UInt256)
return rc return rc
# function stubs from v2computation.nim (to satisfy compiler logic) # function stubs from v2computation.nim (to satisfy compiler logic)
proc gasCosts(c: Computation): array[Op,int] = blindGasCosts proc gasCosts(c: Computation): array[Op,int] = result
proc setError(c: Computation, msg: string, burnsGas = false) = discard proc setError(c: Computation, msg: string, burnsGas = false) = discard
proc selfDestruct(c: Computation, address: EthAddress) = discard proc selfDestruct(c: Computation, address: EthAddress) = discard
proc accountExists(c: Computation, address: EthAddress): bool = false proc accountExists(c: Computation, address: EthAddress): bool = result
proc getBalance[T](c: Computation, address: T): Uint256 = 0.u256 proc getBalance[T](c: Computation, address: T): Uint256 = result
# function stubs from v2utils_numeric.nim # function stubs from v2utils_numeric.nim
func cleanMemRef(x: UInt256): int = 0 func cleanMemRef(x: UInt256): int = result
# function stubs from v2memory.nim # function stubs from v2memory.nim
proc len(mem: Memory): int = 0 proc len(mem: Memory): int = result
proc extend(mem: var Memory; startPos: Natural; size: Natural) = discard proc extend(mem: var Memory; startPos: Natural; size: Natural) = discard
proc read(mem: var Memory, startPos: Natural, size: Natural): seq[byte] = @[] proc read(mem: var Memory, startPos: Natural, size: Natural): seq[byte] = @[]
@ -94,11 +89,11 @@ else:
sd_condition: bool sd_condition: bool
else: else:
discard discard
proc c_handler(x: int; y: Uint256, z: GasParams): GasResult = blindGasResult proc c_handler(x: int; y: Uint256, z: GasParams): GasResult = result
proc m_handler(x: int; curMemSize, memOffset, memLen: int64): int = 0 proc m_handler(x: int; curMemSize, memOffset, memLen: int64): int = result
# function stubs from accounts_cache.nim: # function stubs from accounts_cache.nim:
func inAccessList[A,B](ac: A; address: B): bool = false func inAccessList[A,B](ac: A; address: B): bool = result
proc accessList[A,B](ac: var A; address: B) = discard proc accessList[A,B](ac: var A; address: B) = discard
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------

View File

@ -202,6 +202,8 @@ opHandler log1, Op.Log1
opHandler log2, Op.Log2 opHandler log2, Op.Log2
opHandler log3, Op.Log3 opHandler log3, Op.Log3
opHandler log4, Op.Log4 opHandler log4, Op.Log4
opHandler create, Op.Create
opHandler create2, Op.Create2
opHandler returnOp, Op.Return opHandler returnOp, Op.Return
opHandler revert, Op.Revert opHandler revert, Op.Revert
opHandler invalidOp, Op.Invalid opHandler invalidOp, Op.Invalid
@ -213,76 +215,6 @@ opHandler selfDestructEIP2929, Op.SelfDestruct
# ########################################## # ##########################################
# f0s: System operations. # f0s: System operations.
template genCreate(callName: untyped, opCode: Op): untyped =
op callName, inline = false:
checkInStaticContext(c)
let
endowment = c.stack.popInt()
memPos = c.stack.popInt().safeInt
when opCode == Create:
const callKind = evmcCreate
let memLen {.inject.} = c.stack.peekInt().safeInt
let salt = 0.u256
else:
const callKind = evmcCreate2
let memLen {.inject.} = c.stack.popInt().safeInt
let salt = c.stack.peekInt()
c.stack.top(0)
let gasParams = GasParams(kind: Create,
cr_currentMemSize: c.memory.len,
cr_memOffset: memPos,
cr_memLength: memLen
)
var gasCost = c.gasCosts[Create].c_handler(1.u256, gasParams).gasCost
when opCode == Create2:
gasCost = gasCost + c.gasCosts[Create2].m_handler(0, 0, memLen)
let reason = &"CREATE: GasCreate + {memLen} * memory expansion"
c.gasMeter.consumeGas(gasCost, reason = reason)
c.memory.extend(memPos, memLen)
c.returnData.setLen(0)
if c.msg.depth >= MaxCallDepth:
debug "Computation Failure", reason = "Stack too deep", maxDepth = MaxCallDepth, depth = c.msg.depth
return
if endowment != 0:
let senderBalance = c.getBalance(c.msg.contractAddress)
if senderBalance < endowment:
debug "Computation Failure", reason = "Insufficient funds available to transfer", required = endowment, balance = senderBalance
return
var createMsgGas = c.gasMeter.gasRemaining
if c.fork >= FkTangerine:
createMsgGas -= createMsgGas div 64
c.gasMeter.consumeGas(createMsgGas, reason="CREATE")
block:
let childMsg = Message(
kind: callKind,
depth: c.msg.depth + 1,
gas: createMsgGas,
sender: c.msg.contractAddress,
value: endowment,
data: c.memory.read(memPos, memLen)
)
var child = newComputation(c.vmState, childMsg, salt)
c.chainTo(child):
if not child.shouldBurnGas:
c.gasMeter.returnGas(child.gasMeter.gasRemaining)
if child.isSuccess:
c.merge(child)
c.stack.top child.msg.contractAddress
else:
c.returnData = child.output
genCreate(create, Create)
genCreate(create2, Create2)
proc callParams(c: Computation): (UInt256, UInt256, EthAddress, EthAddress, CallKind, int, int, int, int, MsgFlags) = proc callParams(c: Computation): (UInt256, UInt256, EthAddress, EthAddress, CallKind, int, int, int, int, MsgFlags) =
let gas = c.stack.popInt() let gas = c.stack.popInt()