re-integrated/added Create and Create2 handlers
This commit is contained in:
parent
1bb6ef43a1
commit
1bdbfda37f
|
@ -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, ## ..
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
# ------------------------------------------------------------------------------
|
|
@ -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
|
||||
|
|
|
@ -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) =
|
||||
|
|
|
@ -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
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in New Issue