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
|
|
|
|
## ======================================
|
|
|
|
##
|
|
|
|
|
2024-06-15 16:18:53 +00:00
|
|
|
{.push raises: [].} # basically the annotation type of a `VmOpFn`
|
2023-02-14 20:27:17 +00:00
|
|
|
|
2021-04-16 10:53:05 +00:00
|
|
|
import
|
2021-04-23 17:43:44 +00:00
|
|
|
../../../constants,
|
2024-06-07 08:24:32 +00:00
|
|
|
../../evm_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-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,
|
2024-06-07 08:24:32 +00:00
|
|
|
stint
|
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-06-07 08:24:32 +00:00
|
|
|
c.chainTo(msg):
|
2024-06-14 07:31:08 +00:00
|
|
|
c.gasMeter.returnGas(GasInt c.res.gas_left)
|
2022-09-26 04:56:54 +00:00
|
|
|
if c.res.status_code == EVMC_SUCCESS:
|
2024-06-07 08:24:32 +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)
|
2024-06-07 08:24:32 +00:00
|
|
|
ok()
|
2022-09-26 04:56:54 +00:00
|
|
|
|
|
|
|
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-06-07 08:24:32 +00:00
|
|
|
c.chainTo(child):
|
2022-09-26 04:56:54 +00:00
|
|
|
if not child.shouldBurnGas:
|
|
|
|
c.gasMeter.returnGas(child.gasMeter.gasRemaining)
|
|
|
|
|
|
|
|
if child.isSuccess:
|
|
|
|
c.merge(child)
|
2024-06-07 08:24:32 +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
|
2024-06-07 08:24:32 +00:00
|
|
|
ok()
|
2022-09-26 04:56:54 +00:00
|
|
|
|
2021-04-16 10:53:05 +00:00
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# Private, op handlers implementation
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
|
2023-04-24 20:59:38 +00:00
|
|
|
|
2024-06-17 16:13:38 +00:00
|
|
|
proc createOp(k: var VmCtx): EvmResultVoid =
|
|
|
|
## 0xf0, Create a new account with associated code
|
|
|
|
? checkInStaticContext(k.cpt)
|
|
|
|
|
|
|
|
let
|
|
|
|
cpt = k.cpt
|
|
|
|
endowment = ? cpt.stack.popInt()
|
|
|
|
memPos = ? cpt.stack.popSafeInt()
|
|
|
|
memLen = ? cpt.stack.peekSafeInt()
|
|
|
|
|
|
|
|
? cpt.stack.top(0)
|
|
|
|
|
|
|
|
# EIP-3860
|
|
|
|
if cpt.fork >= FkShanghai and memLen > EIP3860_MAX_INITCODE_SIZE:
|
|
|
|
trace "Initcode size exceeds maximum", initcodeSize = memLen
|
|
|
|
return err(opErr(InvalidInitCode))
|
|
|
|
|
|
|
|
let
|
|
|
|
gasParams = GasParams(
|
|
|
|
kind: Create,
|
|
|
|
cr_currentMemSize: cpt.memory.len,
|
|
|
|
cr_memOffset: memPos,
|
|
|
|
cr_memLength: memLen)
|
|
|
|
res = cpt.gasCosts[Create].cr_handler(1.u256, gasParams)
|
|
|
|
|
|
|
|
? cpt.opcodeGastCost(Create,
|
|
|
|
res.gasCost, reason = "CREATE: GasCreate + memLen * memory expansion")
|
|
|
|
cpt.memory.extend(memPos, memLen)
|
|
|
|
cpt.returnData.setLen(0)
|
|
|
|
|
|
|
|
if cpt.msg.depth >= MaxCallDepth:
|
|
|
|
debug "Computation Failure",
|
|
|
|
reason = "Stack too deep",
|
|
|
|
maxDepth = MaxCallDepth,
|
|
|
|
depth = cpt.msg.depth
|
|
|
|
return ok()
|
|
|
|
|
|
|
|
if endowment != 0:
|
|
|
|
let senderBalance = cpt.getBalance(cpt.msg.contractAddress)
|
|
|
|
if senderBalance < endowment:
|
2023-04-24 20:59:38 +00:00
|
|
|
debug "Computation Failure",
|
2024-06-17 16:13:38 +00:00
|
|
|
reason = "Insufficient funds available to transfer",
|
|
|
|
required = endowment,
|
|
|
|
balance = senderBalance
|
2024-06-07 08:24:32 +00:00
|
|
|
return ok()
|
2023-04-24 20:59:38 +00:00
|
|
|
|
2024-06-17 16:13:38 +00:00
|
|
|
var createMsgGas = cpt.gasMeter.gasRemaining
|
|
|
|
if cpt.fork >= FkTangerine:
|
|
|
|
createMsgGas -= createMsgGas div 64
|
|
|
|
? cpt.gasMeter.consumeGas(createMsgGas, reason = "CREATE msg gas")
|
2021-04-16 10:53:05 +00:00
|
|
|
|
2024-06-17 16:13:38 +00:00
|
|
|
when evmc_enabled:
|
2023-04-24 20:59:38 +00:00
|
|
|
let
|
2024-06-17 16:13:38 +00:00
|
|
|
msg = new(nimbus_message)
|
|
|
|
c = cpt
|
|
|
|
msg[] = nimbus_message(
|
|
|
|
kind: EVMC_CREATE,
|
|
|
|
depth: (cpt.msg.depth + 1).int32,
|
|
|
|
gas: createMsgGas,
|
|
|
|
sender: cpt.msg.contractAddress,
|
|
|
|
input_data: cpt.memory.readPtr(memPos),
|
|
|
|
input_size: memLen.uint,
|
|
|
|
value: toEvmc(endowment),
|
|
|
|
create2_salt: toEvmc(ZERO_CONTRACTSALT),
|
|
|
|
)
|
|
|
|
c.execSubCreate(msg)
|
|
|
|
else:
|
|
|
|
cpt.execSubCreate(
|
|
|
|
childMsg = Message(
|
|
|
|
kind: EVMC_CREATE,
|
|
|
|
depth: cpt.msg.depth + 1,
|
|
|
|
gas: createMsgGas,
|
|
|
|
sender: cpt.msg.contractAddress,
|
|
|
|
value: endowment,
|
2024-06-18 00:55:35 +00:00
|
|
|
data: @(cpt.memory.read(memPos, memLen))))
|
2024-06-17 16:13:38 +00:00
|
|
|
ok()
|
|
|
|
|
|
|
|
# ---------------------
|
|
|
|
|
|
|
|
proc create2Op(k: var VmCtx): EvmResultVoid =
|
|
|
|
## 0xf5, Behaves identically to CREATE, except using keccak256
|
|
|
|
? checkInStaticContext(k.cpt)
|
|
|
|
|
|
|
|
let
|
|
|
|
cpt = k.cpt
|
|
|
|
endowment = ? cpt.stack.popInt()
|
|
|
|
memPos = ? cpt.stack.popSafeInt()
|
|
|
|
memLen = ? cpt.stack.popSafeInt()
|
|
|
|
salt256 = ? cpt.stack.peekInt()
|
|
|
|
salt = ContractSalt(bytes: salt256.toBytesBE)
|
|
|
|
|
|
|
|
? cpt.stack.top(0)
|
|
|
|
|
|
|
|
# EIP-3860
|
|
|
|
if cpt.fork >= FkShanghai and memLen > EIP3860_MAX_INITCODE_SIZE:
|
|
|
|
trace "Initcode size exceeds maximum", initcodeSize = memLen
|
|
|
|
return err(opErr(InvalidInitCode))
|
|
|
|
|
|
|
|
let
|
|
|
|
gasParams = GasParams(
|
|
|
|
kind: Create,
|
|
|
|
cr_currentMemSize: cpt.memory.len,
|
|
|
|
cr_memOffset: memPos,
|
|
|
|
cr_memLength: memLen)
|
|
|
|
res = cpt.gasCosts[Create].cr_handler(1.u256, gasParams)
|
|
|
|
|
|
|
|
let gasCost = res.gasCost + cpt.gasCosts[Create2].m_handler(0, 0, memLen)
|
|
|
|
|
|
|
|
? cpt.opcodeGastCost(Create2,
|
|
|
|
gasCost, reason = "CREATE2: GasCreate + memLen * memory expansion")
|
|
|
|
cpt.memory.extend(memPos, memLen)
|
|
|
|
cpt.returnData.setLen(0)
|
|
|
|
|
|
|
|
if cpt.msg.depth >= MaxCallDepth:
|
|
|
|
debug "Computation Failure",
|
|
|
|
reason = "Stack too deep",
|
|
|
|
maxDepth = MaxCallDepth,
|
|
|
|
depth = cpt.msg.depth
|
|
|
|
return ok()
|
|
|
|
|
|
|
|
if endowment != 0:
|
|
|
|
let senderBalance = cpt.getBalance(cpt.msg.contractAddress)
|
|
|
|
if senderBalance < endowment:
|
2023-04-24 20:59:38 +00:00
|
|
|
debug "Computation Failure",
|
2024-06-17 16:13:38 +00:00
|
|
|
reason = "Insufficient funds available to transfer",
|
|
|
|
required = endowment,
|
|
|
|
balance = senderBalance
|
2024-06-07 08:24:32 +00:00
|
|
|
return ok()
|
2023-04-24 20:59:38 +00:00
|
|
|
|
2024-06-17 16:13:38 +00:00
|
|
|
var createMsgGas = cpt.gasMeter.gasRemaining
|
|
|
|
if cpt.fork >= FkTangerine:
|
|
|
|
createMsgGas -= createMsgGas div 64
|
|
|
|
? cpt.gasMeter.consumeGas(createMsgGas, reason = "CREATE2 msg gas")
|
|
|
|
|
|
|
|
when evmc_enabled:
|
|
|
|
let
|
|
|
|
msg = new(nimbus_message)
|
|
|
|
c = cpt
|
|
|
|
msg[] = nimbus_message(
|
|
|
|
kind: EVMC_CREATE2,
|
|
|
|
depth: (cpt.msg.depth + 1).int32,
|
|
|
|
gas: createMsgGas,
|
|
|
|
sender: cpt.msg.contractAddress,
|
|
|
|
input_data: cpt.memory.readPtr(memPos),
|
|
|
|
input_size: memLen.uint,
|
|
|
|
value: toEvmc(endowment),
|
|
|
|
create2_salt: toEvmc(salt),
|
|
|
|
)
|
|
|
|
c.execSubCreate(msg)
|
|
|
|
else:
|
|
|
|
cpt.execSubCreate(
|
|
|
|
salt = salt,
|
|
|
|
childMsg = Message(
|
|
|
|
kind: EVMC_CREATE2,
|
|
|
|
depth: cpt.msg.depth + 1,
|
|
|
|
gas: createMsgGas,
|
2023-08-27 06:13:37 +00:00
|
|
|
sender: cpt.msg.contractAddress,
|
2024-06-17 16:13:38 +00:00
|
|
|
value: endowment,
|
2024-06-18 00:55:35 +00:00
|
|
|
data: @(cpt.memory.read(memPos, memLen))))
|
2024-06-17 16:13:38 +00:00
|
|
|
ok()
|
2021-04-16 10:53:05 +00:00
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# Public, op exec table entries
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
const
|
2024-06-15 16:18:53 +00:00
|
|
|
VmOpExecCreate*: seq[VmOpExec] = @[
|
2021-04-16 10:53:05 +00:00
|
|
|
|
|
|
|
(opCode: Create, ## 0xf0, Create a new account with associated code
|
2024-06-15 16:18:53 +00:00
|
|
|
forks: VmOpAllForks,
|
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",
|
2024-06-15 16:18:53 +00:00
|
|
|
exec: (prep: VmOpIgnore,
|
2021-04-16 10:53:05 +00:00
|
|
|
run: createOp,
|
2024-06-15 16:18:53 +00:00
|
|
|
post: VmOpIgnore)),
|
2021-04-16 10:53:05 +00:00
|
|
|
|
|
|
|
(opCode: Create2, ## 0xf5, Create using keccak256
|
2024-06-15 16:18:53 +00:00
|
|
|
forks: VmOpConstantinopleAndLater,
|
2021-04-19 09:15:35 +00:00
|
|
|
name: "create2",
|
2021-04-16 10:53:05 +00:00
|
|
|
info: "Behaves identically to CREATE, except using keccak256",
|
2024-06-15 16:18:53 +00:00
|
|
|
exec: (prep: VmOpIgnore,
|
2021-04-16 10:53:05 +00:00
|
|
|
run: create2Op,
|
2024-06-15 16:18:53 +00:00
|
|
|
post: VmOpIgnore))]
|
2021-04-16 10:53:05 +00:00
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# End
|
|
|
|
# ------------------------------------------------------------------------------
|