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-07-17 13:48:50 +00:00
|
|
|
stew/assign2,
|
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
|
2024-07-07 06:52:11 +00:00
|
|
|
else:
|
|
|
|
import
|
|
|
|
stew/saturation_arith
|
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-07-07 06:52:11 +00:00
|
|
|
c.gasMeter.returnGas(GasInt c.res.gas_left)
|
2024-06-19 12:15:23 +00:00
|
|
|
c.gasMeter.refundGas(c.res.gas_refund)
|
2022-09-26 04:56:54 +00:00
|
|
|
if c.res.status_code == EVMC_SUCCESS:
|
2024-07-18 11:59:53 +00:00
|
|
|
c.stack.lsTop(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-07-17 13:48:50 +00:00
|
|
|
assign(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:
|
2024-06-19 12:15:23 +00:00
|
|
|
c.gasMeter.refundGas(child.gasMeter.gasRefunded)
|
2024-07-18 11:59:53 +00:00
|
|
|
c.stack.lsTop 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-07-19 01:44:01 +00:00
|
|
|
proc createOp(cpt: VmCpt): EvmResultVoid =
|
2024-06-17 16:13:38 +00:00
|
|
|
## 0xf0, Create a new account with associated code
|
2024-07-19 01:44:01 +00:00
|
|
|
? cpt.checkInStaticContext()
|
|
|
|
? cpt.stack.lsCheck(3)
|
2024-06-17 16:13:38 +00:00
|
|
|
|
|
|
|
let
|
2024-07-18 11:59:53 +00:00
|
|
|
endowment = cpt.stack.lsPeekInt(^1)
|
|
|
|
memPos = cpt.stack.lsPeekSafeInt(^2)
|
|
|
|
memLen = cpt.stack.lsPeekSafeInt(^3)
|
2024-06-17 16:13:38 +00:00
|
|
|
|
2024-07-18 11:59:53 +00:00
|
|
|
cpt.stack.lsShrink(2)
|
|
|
|
cpt.stack.lsTop(0)
|
2024-06-17 16:13:38 +00:00
|
|
|
|
|
|
|
# EIP-3860
|
|
|
|
if cpt.fork >= FkShanghai and memLen > EIP3860_MAX_INITCODE_SIZE:
|
|
|
|
trace "Initcode size exceeds maximum", initcodeSize = memLen
|
|
|
|
return err(opErr(InvalidInitCode))
|
|
|
|
|
|
|
|
let
|
2024-07-05 04:55:13 +00:00
|
|
|
gasParams = GasParamsCr(
|
|
|
|
currentMemSize: cpt.memory.len,
|
|
|
|
memOffset: memPos,
|
|
|
|
memLength: memLen)
|
|
|
|
gasCost = cpt.gasCosts[Create].cr_handler(1.u256, gasParams)
|
2024-06-17 16:13:38 +00:00
|
|
|
|
2024-07-13 18:42:49 +00:00
|
|
|
? cpt.opcodeGasCost(Create,
|
2024-07-05 04:55:13 +00:00
|
|
|
gasCost, reason = "CREATE: GasCreate + memLen * memory expansion")
|
2024-06-17 16:13:38 +00:00
|
|
|
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,
|
2024-07-07 06:52:11 +00:00
|
|
|
gas: int64.saturate(createMsgGas),
|
2024-06-17 16:13:38 +00:00
|
|
|
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:
|
2024-07-17 13:48:50 +00:00
|
|
|
var childMsg = Message(
|
|
|
|
kind: EVMC_CREATE,
|
|
|
|
depth: cpt.msg.depth + 1,
|
|
|
|
gas: createMsgGas,
|
|
|
|
sender: cpt.msg.contractAddress,
|
|
|
|
value: endowment)
|
|
|
|
assign(childMsg.data, cpt.memory.read(memPos, memLen))
|
|
|
|
cpt.execSubCreate(childMsg)
|
2024-06-17 16:13:38 +00:00
|
|
|
ok()
|
|
|
|
|
|
|
|
# ---------------------
|
|
|
|
|
2024-07-19 01:44:01 +00:00
|
|
|
proc create2Op(cpt: VmCpt): EvmResultVoid =
|
2024-06-17 16:13:38 +00:00
|
|
|
## 0xf5, Behaves identically to CREATE, except using keccak256
|
2024-07-19 01:44:01 +00:00
|
|
|
? cpt.checkInStaticContext()
|
|
|
|
? cpt.stack.lsCheck(4)
|
2024-06-17 16:13:38 +00:00
|
|
|
|
|
|
|
let
|
2024-07-18 11:59:53 +00:00
|
|
|
endowment = cpt.stack.lsPeekInt(^1)
|
|
|
|
memPos = cpt.stack.lsPeekSafeInt(^2)
|
|
|
|
memLen = cpt.stack.lsPeekSafeInt(^3)
|
|
|
|
salt256 = cpt.stack.lsPeekInt(^4)
|
2024-06-17 16:13:38 +00:00
|
|
|
salt = ContractSalt(bytes: salt256.toBytesBE)
|
|
|
|
|
2024-07-18 11:59:53 +00:00
|
|
|
cpt.stack.lsShrink(3)
|
|
|
|
cpt.stack.lsTop(0)
|
2024-06-17 16:13:38 +00:00
|
|
|
|
|
|
|
# EIP-3860
|
|
|
|
if cpt.fork >= FkShanghai and memLen > EIP3860_MAX_INITCODE_SIZE:
|
|
|
|
trace "Initcode size exceeds maximum", initcodeSize = memLen
|
|
|
|
return err(opErr(InvalidInitCode))
|
|
|
|
|
|
|
|
let
|
2024-07-05 04:55:13 +00:00
|
|
|
gasParams = GasParamsCr(
|
|
|
|
currentMemSize: cpt.memory.len,
|
|
|
|
memOffset: memPos,
|
|
|
|
memLength: memLen)
|
|
|
|
|
|
|
|
var gasCost = cpt.gasCosts[Create].cr_handler(1.u256, gasParams)
|
|
|
|
gasCost = gasCost + cpt.gasCosts[Create2].m_handler(0, 0, memLen)
|
2024-06-17 16:13:38 +00:00
|
|
|
|
2024-07-13 18:42:49 +00:00
|
|
|
? cpt.opcodeGasCost(Create2,
|
2024-06-17 16:13:38 +00:00
|
|
|
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,
|
2024-07-07 06:52:11 +00:00
|
|
|
gas: int64.saturate(createMsgGas),
|
2024-06-17 16:13:38 +00:00
|
|
|
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:
|
2024-07-17 13:48:50 +00:00
|
|
|
var childMsg = Message(
|
|
|
|
kind: EVMC_CREATE2,
|
|
|
|
depth: cpt.msg.depth + 1,
|
|
|
|
gas: createMsgGas,
|
|
|
|
sender: cpt.msg.contractAddress,
|
|
|
|
value: endowment)
|
|
|
|
assign(childMsg.data, cpt.memory.read(memPos, memLen))
|
|
|
|
cpt.execSubCreate(salt = salt, childMsg = childMsg)
|
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-24 05:58:15 +00:00
|
|
|
exec: createOp),
|
|
|
|
|
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-24 05:58:15 +00:00
|
|
|
exec: create2Op)]
|
2021-04-16 10:53:05 +00:00
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# End
|
|
|
|
# ------------------------------------------------------------------------------
|