2021-04-16 10:53:05 +00:00
|
|
|
# Nimbus
|
2024-02-20 07:16:12 +00:00
|
|
|
# Copyright (c) 2021-2024 Status Research & Development GmbH
|
2021-04-16 10:53:05 +00:00
|
|
|
# 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
|
|
|
|
## ======================================
|
|
|
|
##
|
|
|
|
|
2023-02-14 20:27:17 +00:00
|
|
|
{.push raises: [CatchableError].} # basically the annotation type of a `Vm2OpFn`
|
|
|
|
|
2021-04-16 10:53:05 +00:00
|
|
|
import
|
2021-04-23 17:43:44 +00:00
|
|
|
../../../constants,
|
2021-04-16 10:53:05 +00:00
|
|
|
../../../errors,
|
2022-12-02 04:35:41 +00:00
|
|
|
../../../common/evmforks,
|
|
|
|
../../../utils/utils,
|
2021-04-26 16:00:46 +00:00
|
|
|
../../computation,
|
2021-04-22 16:05:58 +00:00
|
|
|
../../memory,
|
2021-04-23 17:43:44 +00:00
|
|
|
../../stack,
|
|
|
|
../../types,
|
|
|
|
../gas_costs,
|
|
|
|
../gas_meter,
|
2021-04-21 17:04:54 +00:00
|
|
|
../op_codes,
|
2021-04-22 16:05:58 +00:00
|
|
|
../utils/utils_numeric,
|
2021-04-23 17:43:44 +00:00
|
|
|
./oph_defs,
|
|
|
|
./oph_helpers,
|
2021-04-16 10:53:05 +00:00
|
|
|
chronicles,
|
2021-04-23 17:43:44 +00:00
|
|
|
eth/common,
|
2021-04-21 17:04:54 +00:00
|
|
|
eth/common/eth_types,
|
|
|
|
stint,
|
|
|
|
strformat
|
2021-04-16 10:53:05 +00:00
|
|
|
|
2022-09-28 06:09:33 +00:00
|
|
|
when not defined(evmc_enabled):
|
|
|
|
import
|
|
|
|
../../state,
|
2023-12-12 19:12:56 +00:00
|
|
|
../../../db/ledger
|
2022-09-28 06:09:33 +00:00
|
|
|
|
2021-04-16 10:53:05 +00:00
|
|
|
# ------------------------------------------------------------------------------
|
2021-04-23 17:43:44 +00:00
|
|
|
# Private helpers
|
2021-04-16 10:53:05 +00:00
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
|
2022-09-26 04:56:54 +00:00
|
|
|
when evmc_enabled:
|
|
|
|
template execSubCreate(c: Computation; msg: ref nimbus_message) =
|
2024-02-20 07:16:12 +00:00
|
|
|
c.chainTo(msg, shouldRaise = true):
|
2022-09-26 04:56:54 +00:00
|
|
|
c.gasMeter.returnGas(c.res.gas_left)
|
|
|
|
if c.res.status_code == EVMC_SUCCESS:
|
2023-04-24 20:59:38 +00:00
|
|
|
c.stack.top(c.res.create_address)
|
2022-09-26 04:56:54 +00:00
|
|
|
elif c.res.status_code == EVMC_REVERT:
|
|
|
|
# From create, only use `outputData` if child returned with `REVERT`.
|
2024-02-20 07:16:12 +00:00
|
|
|
c.returnData = @(makeOpenArray(c.res.output_data, c.res.output_size.int))
|
2022-09-26 04:56:54 +00:00
|
|
|
if not c.res.release.isNil:
|
|
|
|
c.res.release(c.res)
|
|
|
|
|
|
|
|
else:
|
|
|
|
proc execSubCreate(c: Computation; childMsg: Message;
|
2024-02-20 07:16:12 +00:00
|
|
|
salt: ContractSalt = ZERO_CONTRACTSALT) {.raises: [].} =
|
2022-09-26 04:56:54 +00:00
|
|
|
## Create new VM -- helper for `Create`-like operations
|
|
|
|
|
|
|
|
# need to provide explicit <c> and <child> for capturing in chainTo proc()
|
|
|
|
var
|
2023-09-20 13:10:16 +00:00
|
|
|
child = newComputation(c.vmState, false, childMsg, salt)
|
2022-09-26 04:56:54 +00:00
|
|
|
|
2024-02-20 07:16:12 +00:00
|
|
|
c.chainTo(child, shouldRaise = false):
|
2022-09-26 04:56:54 +00:00
|
|
|
if not child.shouldBurnGas:
|
|
|
|
c.gasMeter.returnGas(child.gasMeter.gasRemaining)
|
|
|
|
|
|
|
|
if child.isSuccess:
|
|
|
|
c.merge(child)
|
2023-04-24 20:59:38 +00:00
|
|
|
c.stack.top child.msg.contractAddress
|
2022-09-26 04:56:54 +00:00
|
|
|
elif not child.error.burnsGas: # Means return was `REVERT`.
|
|
|
|
# From create, only use `outputData` if child returned with `REVERT`.
|
|
|
|
c.returnData = child.output
|
|
|
|
|
2021-04-16 10:53:05 +00:00
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# Private, op handlers implementation
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
const
|
2021-04-20 12:07:01 +00:00
|
|
|
createOp: Vm2OpFn = proc(k: var Vm2Ctx) =
|
2021-04-16 10:53:05 +00:00
|
|
|
## 0xf0, Create a new account with associated code
|
|
|
|
checkInStaticContext(k.cpt)
|
|
|
|
|
2023-04-24 20:59:38 +00:00
|
|
|
let
|
2023-08-27 06:13:37 +00:00
|
|
|
cpt = k.cpt
|
|
|
|
endowment = cpt.stack.popInt()
|
|
|
|
memPos = cpt.stack.popInt().safeInt
|
|
|
|
memLen = cpt.stack.peekInt().safeInt
|
2023-04-24 20:59:38 +00:00
|
|
|
|
2023-08-27 06:13:37 +00:00
|
|
|
cpt.stack.top(0)
|
2023-04-24 20:59:38 +00:00
|
|
|
|
|
|
|
# EIP-3860
|
2023-08-27 06:13:37 +00:00
|
|
|
if cpt.fork >= FkShanghai and memLen > EIP3860_MAX_INITCODE_SIZE:
|
2023-04-24 20:59:38 +00:00
|
|
|
trace "Initcode size exceeds maximum", initcodeSize = memLen
|
|
|
|
raise newException(InitcodeError,
|
|
|
|
&"CREATE: have {memLen}, max {EIP3860_MAX_INITCODE_SIZE}")
|
|
|
|
|
2023-08-23 09:29:33 +00:00
|
|
|
let
|
|
|
|
gasParams = GasParams(
|
|
|
|
kind: Create,
|
2023-08-27 06:13:37 +00:00
|
|
|
cr_currentMemSize: cpt.memory.len,
|
2023-08-23 09:29:33 +00:00
|
|
|
cr_memOffset: memPos,
|
|
|
|
cr_memLength: memLen)
|
2023-04-24 20:59:38 +00:00
|
|
|
|
2023-08-27 06:13:37 +00:00
|
|
|
let gasCost = cpt.gasCosts[Create].c_handler(1.u256, gasParams).gasCost
|
|
|
|
|
|
|
|
cpt.opcodeGastCost(Create,
|
2023-04-24 20:59:38 +00:00
|
|
|
gasCost, reason = &"CREATE: GasCreate + {memLen} * memory expansion")
|
2023-08-27 06:13:37 +00:00
|
|
|
cpt.memory.extend(memPos, memLen)
|
|
|
|
cpt.returnData.setLen(0)
|
2023-04-24 20:59:38 +00:00
|
|
|
|
2023-08-27 06:13:37 +00:00
|
|
|
if cpt.msg.depth >= MaxCallDepth:
|
2023-04-24 20:59:38 +00:00
|
|
|
debug "Computation Failure",
|
|
|
|
reason = "Stack too deep",
|
|
|
|
maxDepth = MaxCallDepth,
|
2023-08-27 06:13:37 +00:00
|
|
|
depth = cpt.msg.depth
|
2023-04-24 20:59:38 +00:00
|
|
|
return
|
|
|
|
|
|
|
|
if endowment != 0:
|
2023-08-27 06:13:37 +00:00
|
|
|
let senderBalance = cpt.getBalance(cpt.msg.contractAddress)
|
2023-04-24 20:59:38 +00:00
|
|
|
if senderBalance < endowment:
|
2021-04-16 10:53:05 +00:00
|
|
|
debug "Computation Failure",
|
2023-04-24 20:59:38 +00:00
|
|
|
reason = "Insufficient funds available to transfer",
|
|
|
|
required = endowment,
|
|
|
|
balance = senderBalance
|
2021-04-16 10:53:05 +00:00
|
|
|
return
|
|
|
|
|
2023-08-27 06:13:37 +00:00
|
|
|
var createMsgGas = cpt.gasMeter.gasRemaining
|
|
|
|
if cpt.fork >= FkTangerine:
|
2023-04-24 20:59:38 +00:00
|
|
|
createMsgGas -= createMsgGas div 64
|
2023-08-27 06:13:37 +00:00
|
|
|
cpt.gasMeter.consumeGas(createMsgGas, reason = "CREATE msg gas")
|
2023-08-23 09:29:33 +00:00
|
|
|
|
2023-04-24 20:59:38 +00:00
|
|
|
when evmc_enabled:
|
|
|
|
let
|
|
|
|
msg = new(nimbus_message)
|
2023-08-27 06:13:37 +00:00
|
|
|
c = cpt
|
2023-04-24 20:59:38 +00:00
|
|
|
msg[] = nimbus_message(
|
2023-08-28 12:10:31 +00:00
|
|
|
kind: EVMC_CREATE,
|
2023-08-27 06:13:37 +00:00
|
|
|
depth: (cpt.msg.depth + 1).int32,
|
2023-04-24 20:59:38 +00:00
|
|
|
gas: createMsgGas,
|
2023-08-27 06:13:37 +00:00
|
|
|
sender: cpt.msg.contractAddress,
|
|
|
|
input_data: cpt.memory.readPtr(memPos),
|
2023-04-24 20:59:38 +00:00
|
|
|
input_size: memLen.uint,
|
|
|
|
value: toEvmc(endowment),
|
|
|
|
create2_salt: toEvmc(ZERO_CONTRACTSALT),
|
|
|
|
)
|
|
|
|
c.execSubCreate(msg)
|
|
|
|
else:
|
2023-08-27 06:13:37 +00:00
|
|
|
cpt.execSubCreate(
|
2023-04-24 20:59:38 +00:00
|
|
|
childMsg = Message(
|
2023-08-28 12:10:31 +00:00
|
|
|
kind: EVMC_CREATE,
|
2023-08-27 06:13:37 +00:00
|
|
|
depth: cpt.msg.depth + 1,
|
2023-04-24 20:59:38 +00:00
|
|
|
gas: createMsgGas,
|
2023-08-27 06:13:37 +00:00
|
|
|
sender: cpt.msg.contractAddress,
|
2023-04-24 20:59:38 +00:00
|
|
|
value: endowment,
|
2023-08-27 06:13:37 +00:00
|
|
|
data: cpt.memory.read(memPos, memLen)))
|
2021-04-16 10:53:05 +00:00
|
|
|
|
|
|
|
# ---------------------
|
|
|
|
|
2021-04-20 12:07:01 +00:00
|
|
|
create2Op: Vm2OpFn = proc(k: var Vm2Ctx) =
|
2021-04-16 10:53:05 +00:00
|
|
|
## 0xf5, Behaves identically to CREATE, except using keccak256
|
2023-04-24 20:59:38 +00:00
|
|
|
checkInStaticContext(k.cpt)
|
2021-04-16 10:53:05 +00:00
|
|
|
|
2023-04-24 20:59:38 +00:00
|
|
|
let
|
2023-08-27 06:13:37 +00:00
|
|
|
cpt = k.cpt
|
|
|
|
endowment = cpt.stack.popInt()
|
|
|
|
memPos = cpt.stack.popInt().safeInt
|
|
|
|
memLen = cpt.stack.popInt().safeInt
|
|
|
|
salt = ContractSalt(bytes: cpt.stack.peekInt().toBytesBE)
|
2023-04-24 20:59:38 +00:00
|
|
|
|
2023-08-27 06:13:37 +00:00
|
|
|
cpt.stack.top(0)
|
2023-04-24 20:59:38 +00:00
|
|
|
|
|
|
|
# EIP-3860
|
2023-08-27 06:13:37 +00:00
|
|
|
if cpt.fork >= FkShanghai and memLen > EIP3860_MAX_INITCODE_SIZE:
|
2023-04-24 20:59:38 +00:00
|
|
|
trace "Initcode size exceeds maximum", initcodeSize = memLen
|
|
|
|
raise newException(InitcodeError,
|
|
|
|
&"CREATE2: have {memLen}, max {EIP3860_MAX_INITCODE_SIZE}")
|
|
|
|
|
2023-08-23 09:29:33 +00:00
|
|
|
let
|
|
|
|
gasParams = GasParams(
|
|
|
|
kind: Create,
|
2023-08-27 06:13:37 +00:00
|
|
|
cr_currentMemSize: cpt.memory.len,
|
2023-08-23 09:29:33 +00:00
|
|
|
cr_memOffset: memPos,
|
|
|
|
cr_memLength: memLen)
|
2023-04-24 20:59:38 +00:00
|
|
|
|
2023-08-27 06:13:37 +00:00
|
|
|
var gasCost = cpt.gasCosts[Create].c_handler(1.u256, gasParams).gasCost
|
|
|
|
gasCost = gasCost + cpt.gasCosts[Create2].m_handler(0, 0, memLen)
|
2023-04-24 20:59:38 +00:00
|
|
|
|
2023-08-27 06:13:37 +00:00
|
|
|
cpt.opcodeGastCost(Create2,
|
2023-04-24 20:59:38 +00:00
|
|
|
gasCost, reason = &"CREATE2: GasCreate + {memLen} * memory expansion")
|
2023-08-27 06:13:37 +00:00
|
|
|
cpt.memory.extend(memPos, memLen)
|
|
|
|
cpt.returnData.setLen(0)
|
2023-04-24 20:59:38 +00:00
|
|
|
|
2023-08-27 06:13:37 +00:00
|
|
|
if cpt.msg.depth >= MaxCallDepth:
|
2023-04-24 20:59:38 +00:00
|
|
|
debug "Computation Failure",
|
|
|
|
reason = "Stack too deep",
|
|
|
|
maxDepth = MaxCallDepth,
|
2023-08-27 06:13:37 +00:00
|
|
|
depth = cpt.msg.depth
|
2023-04-24 20:59:38 +00:00
|
|
|
return
|
|
|
|
|
|
|
|
if endowment != 0:
|
2023-08-27 06:13:37 +00:00
|
|
|
let senderBalance = cpt.getBalance(cpt.msg.contractAddress)
|
2023-04-24 20:59:38 +00:00
|
|
|
if senderBalance < endowment:
|
2021-04-16 10:53:05 +00:00
|
|
|
debug "Computation Failure",
|
2023-04-24 20:59:38 +00:00
|
|
|
reason = "Insufficient funds available to transfer",
|
|
|
|
required = endowment,
|
|
|
|
balance = senderBalance
|
2021-04-16 10:53:05 +00:00
|
|
|
return
|
|
|
|
|
2023-08-27 06:13:37 +00:00
|
|
|
var createMsgGas = cpt.gasMeter.gasRemaining
|
|
|
|
if cpt.fork >= FkTangerine:
|
2023-04-24 20:59:38 +00:00
|
|
|
createMsgGas -= createMsgGas div 64
|
2023-08-27 06:13:37 +00:00
|
|
|
cpt.gasMeter.consumeGas(createMsgGas, reason = "CREATE2 msg gas")
|
2023-08-23 09:29:33 +00:00
|
|
|
|
2023-04-24 20:59:38 +00:00
|
|
|
when evmc_enabled:
|
|
|
|
let
|
|
|
|
msg = new(nimbus_message)
|
2023-08-27 06:13:37 +00:00
|
|
|
c = cpt
|
2023-04-24 20:59:38 +00:00
|
|
|
msg[] = nimbus_message(
|
2023-08-28 12:10:31 +00:00
|
|
|
kind: EVMC_CREATE2,
|
2023-08-27 06:13:37 +00:00
|
|
|
depth: (cpt.msg.depth + 1).int32,
|
2023-04-24 20:59:38 +00:00
|
|
|
gas: createMsgGas,
|
2023-08-27 06:13:37 +00:00
|
|
|
sender: cpt.msg.contractAddress,
|
|
|
|
input_data: cpt.memory.readPtr(memPos),
|
2023-04-24 20:59:38 +00:00
|
|
|
input_size: memLen.uint,
|
|
|
|
value: toEvmc(endowment),
|
|
|
|
create2_salt: toEvmc(salt),
|
|
|
|
)
|
|
|
|
c.execSubCreate(msg)
|
|
|
|
else:
|
2023-08-27 06:13:37 +00:00
|
|
|
cpt.execSubCreate(
|
2023-04-24 20:59:38 +00:00
|
|
|
salt = salt,
|
|
|
|
childMsg = Message(
|
2023-08-28 12:10:31 +00:00
|
|
|
kind: EVMC_CREATE2,
|
2023-08-27 06:13:37 +00:00
|
|
|
depth: cpt.msg.depth + 1,
|
2023-04-24 20:59:38 +00:00
|
|
|
gas: createMsgGas,
|
2023-08-27 06:13:37 +00:00
|
|
|
sender: cpt.msg.contractAddress,
|
2023-04-24 20:59:38 +00:00
|
|
|
value: endowment,
|
2023-08-27 06:13:37 +00:00
|
|
|
data: cpt.memory.read(memPos, memLen)))
|
2021-04-16 10:53:05 +00:00
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# Public, op exec table entries
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
const
|
|
|
|
vm2OpExecCreate*: seq[Vm2OpExec] = @[
|
|
|
|
|
|
|
|
(opCode: Create, ## 0xf0, Create a new account with associated code
|
|
|
|
forks: Vm2OpAllForks,
|
2021-04-19 09:15:35 +00:00
|
|
|
name: "create",
|
2021-04-16 10:53:05 +00:00
|
|
|
info: "Create a new account with associated code",
|
|
|
|
exec: (prep: vm2OpIgnore,
|
|
|
|
run: createOp,
|
|
|
|
post: vm2OpIgnore)),
|
|
|
|
|
|
|
|
(opCode: Create2, ## 0xf5, Create using keccak256
|
2021-04-19 09:15:35 +00:00
|
|
|
forks: Vm2OpConstantinopleAndLater,
|
|
|
|
name: "create2",
|
2021-04-16 10:53:05 +00:00
|
|
|
info: "Behaves identically to CREATE, except using keccak256",
|
|
|
|
exec: (prep: vm2OpIgnore,
|
|
|
|
run: create2Op,
|
|
|
|
post: vm2OpIgnore))]
|
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# End
|
|
|
|
# ------------------------------------------------------------------------------
|