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
## current values for sender and value.
Create2 = 0xf5, ## Behaves identically to CREATE, except using
## keccak256( 0xff ++ address ++ salt ++
## keccak256(init_code))[12:]
## keccak256
Nop0xF6, Nop0xF7, Nop0xF8, Nop0xF9, ## ..

View File

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

View File

@ -41,8 +41,6 @@ when not breakCircularDependency:
else:
import macros
var blindGasCosts: array[Op,int]
# copied from stack.nim
macro genTupleType(len: static[int], elemType: untyped): untyped =
result = nnkTupleConstr.newNimNode()
@ -50,13 +48,13 @@ else:
# function stubs from stack.nim (to satisfy compiler logic)
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 =
var rc: genTupleType(n, UInt256)
return rc
# 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
proc extractSign(v: var UInt256, sign: var bool) = discard
@ -67,7 +65,7 @@ else:
proc consumeGas(gasMeter: var GasMeter; amount: int; reason: string) = discard
# 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

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

View File

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

View File

@ -43,14 +43,9 @@ else:
import macros
type
GasInt = int
GasResult = tuple[gasCost, gasRefund: GasInt]
const
ColdAccountAccessCost = 42
var
blindGasCosts: array[Op,int]
blindAddress: EthAddress
blindGasResult: GasResult
# copied from stack.nim
macro genTupleType(len: static[int], elemType: untyped): untyped =
@ -58,23 +53,23 @@ else:
for i in 0 ..< len: result.add(elemType)
# 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 =
var rc: genTupleType(n, UInt256)
return rc
# 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 selfDestruct(c: Computation, address: EthAddress) = discard
proc accountExists(c: Computation, address: EthAddress): bool = false
proc getBalance[T](c: Computation, address: T): Uint256 = 0.u256
proc accountExists(c: Computation, address: EthAddress): bool = result
proc getBalance[T](c: Computation, address: T): Uint256 = result
# function stubs from v2utils_numeric.nim
func cleanMemRef(x: UInt256): int = 0
func cleanMemRef(x: UInt256): int = result
# 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 read(mem: var Memory, startPos: Natural, size: Natural): seq[byte] = @[]
@ -94,11 +89,11 @@ else:
sd_condition: bool
else:
discard
proc c_handler(x: int; y: Uint256, z: GasParams): GasResult = blindGasResult
proc m_handler(x: int; curMemSize, memOffset, memLen: int64): int = 0
proc c_handler(x: int; y: Uint256, z: GasParams): GasResult = result
proc m_handler(x: int; curMemSize, memOffset, memLen: int64): int = result
# 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
# ------------------------------------------------------------------------------

View File

@ -202,6 +202,8 @@ opHandler log1, Op.Log1
opHandler log2, Op.Log2
opHandler log3, Op.Log3
opHandler log4, Op.Log4
opHandler create, Op.Create
opHandler create2, Op.Create2
opHandler returnOp, Op.Return
opHandler revert, Op.Revert
opHandler invalidOp, Op.Invalid
@ -213,76 +215,6 @@ opHandler selfDestructEIP2929, Op.SelfDestruct
# ##########################################
# 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) =
let gas = c.stack.popInt()