417 lines
13 KiB
Nim
Raw Normal View History

2021-04-13 18:12:47 +01:00
# Nimbus
# Copyright (c) 2018-2024 Status Research & Development GmbH
2021-04-13 18:12:47 +01: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: Environmental Information
## ==============================================
##
{.push raises: [].}
2021-04-13 18:12:47 +01:00
import
../../evm_errors,
../../code_stream,
../../computation,
../../memory,
../../stack,
../gas_costs,
../op_codes,
../utils/utils_numeric,
2021-04-13 18:12:47 +01:00
./oph_defs,
2021-04-15 17:42:19 +01:00
./oph_helpers,
eth/common,
stint
2021-04-13 18:12:47 +01:00
when not defined(evmc_enabled):
import ../../state
2021-04-13 18:12:47 +01:00
# ------------------------------------------------------------------------------
# Private, op handlers implementation
# ------------------------------------------------------------------------------
proc addressOp (k: var VmCtx): EvmResultVoid =
## 0x30, Get address of currently executing account.
k.cpt.stack.push k.cpt.msg.contractAddress
2021-04-13 18:12:47 +01:00
# ------------------
2021-04-15 17:42:19 +01:00
proc balanceOp (k: var VmCtx): EvmResultVoid =
## 0x31, Get balance of the given account.
let
cpt = k.cpt
address = ? cpt.stack.popAddress
cpt.stack.push cpt.getBalance(address)
2021-04-13 18:12:47 +01:00
proc balanceEIP2929Op (k: var VmCtx): EvmResultVoid =
## 0x31, EIP292: Get balance of the given account for Berlin and later
let
cpt = k.cpt
address = ? cpt.stack.popAddress()
gasCost = cpt.gasEip2929AccountCheck(address)
2021-04-15 17:42:19 +01:00
? cpt.opcodeGastCost(Balance, gasCost, reason = "Balance EIP2929")
cpt.stack.push cpt.getBalance(address)
2021-04-15 17:42:19 +01:00
# ------------------
2021-04-15 17:42:19 +01:00
proc originOp (k: var VmCtx): EvmResultVoid =
## 0x32, Get execution origination address.
k.cpt.stack.push k.cpt.getOrigin()
2021-04-13 18:12:47 +01:00
proc callerOp (k: var VmCtx): EvmResultVoid =
## 0x33, Get caller address.
k.cpt.stack.push k.cpt.msg.sender
2021-04-13 18:12:47 +01:00
proc callValueOp (k: var VmCtx): EvmResultVoid =
## 0x34, Get deposited value by the instruction/transaction
## responsible for this execution
k.cpt.stack.push k.cpt.msg.value
2021-04-13 18:12:47 +01:00
proc callDataLoadOp (k: var VmCtx): EvmResultVoid =
## 0x35, Get input data of current environment
let
startPos = ? k.cpt.stack.popInt()
start = startPos.cleanMemRef
if start >= k.cpt.msg.data.len:
return k.cpt.stack.push 0
2021-04-13 18:12:47 +01:00
# If the data does not take 32 bytes, pad with zeros
let
endRange = min(k.cpt.msg.data.len - 1, start + 31)
presentBytes = endRange - start
2021-04-13 18:12:47 +01:00
# We rely on value being initialized with 0 by default
var value: array[32, byte]
value[0 .. presentBytes] = k.cpt.msg.data.toOpenArray(start, endRange)
k.cpt.stack.push value
2021-04-13 18:12:47 +01:00
proc callDataSizeOp (k: var VmCtx): EvmResultVoid =
## 0x36, Get size of input data in current environment.
k.cpt.stack.push k.cpt.msg.data.len.u256
2021-04-13 18:12:47 +01:00
proc callDataCopyOp (k: var VmCtx): EvmResultVoid =
## 0x37, Copy input data in current environment to memory.
let (memStartPos, copyStartPos, size) = ? k.cpt.stack.popInt(3)
2021-04-13 18:12:47 +01:00
# TODO tests: https://github.com/status-im/nimbus/issues/67
let (memPos, copyPos, len) =
(memStartPos.cleanMemRef, copyStartPos.cleanMemRef, size.cleanMemRef)
2021-04-13 18:12:47 +01:00
? k.cpt.opcodeGastCost(CallDataCopy,
k.cpt.gasCosts[CallDataCopy].m_handler(k.cpt.memory.len, memPos, len),
reason = "CallDataCopy fee")
2021-04-13 18:12:47 +01:00
k.cpt.memory.writePadded(k.cpt.msg.data, memPos, copyPos, len)
ok()
2021-04-13 18:12:47 +01:00
proc codeSizeOp (k: var VmCtx): EvmResultVoid =
## 0x38, Get size of code running in current environment.
let cpt = k.cpt
cpt.stack.push cpt.code.len
2021-04-13 18:12:47 +01:00
proc codeCopyOp (k: var VmCtx): EvmResultVoid =
## 0x39, Copy code running in current environment to memory.
let
cpt = k.cpt
(memStartPos, copyStartPos, size) = ? cpt.stack.popInt(3)
2021-04-13 18:12:47 +01:00
# TODO tests: https://github.com/status-im/nimbus/issues/67
let (memPos, copyPos, len) =
(memStartPos.cleanMemRef, copyStartPos.cleanMemRef, size.cleanMemRef)
? cpt.opcodeGastCost(CodeCopy,
cpt.gasCosts[CodeCopy].m_handler(cpt.memory.len, memPos, len),
reason = "CodeCopy fee")
2021-04-13 18:12:47 +01:00
cpt.memory.writePadded(cpt.code.bytes, memPos, copyPos, len)
ok()
2021-04-13 18:12:47 +01:00
proc gasPriceOp (k: var VmCtx): EvmResultVoid =
## 0x3A, Get price of gas in current environment.
k.cpt.stack.push k.cpt.getGasPrice()
2021-04-13 18:12:47 +01:00
# -----------
proc extCodeSizeOp (k: var VmCtx): EvmResultVoid =
## 0x3b, Get size of an account's code
let
cpt = k.cpt
address = ? k.cpt.stack.popAddress()
2021-04-13 18:12:47 +01:00
cpt.stack.push cpt.getCodeSize(address)
2021-04-15 17:42:19 +01:00
proc extCodeSizeEIP2929Op (k: var VmCtx): EvmResultVoid =
## 0x3b, Get size of an account's code
let
cpt = k.cpt
address = ? cpt.stack.popAddress()
gasCost = cpt.gasEip2929AccountCheck(address)
2021-04-15 17:42:19 +01:00
? cpt.opcodeGastCost(ExtCodeSize, gasCost, reason = "ExtCodeSize EIP2929")
cpt.stack.push cpt.getCodeSize(address)
2021-04-13 18:12:47 +01:00
# -----------
2021-04-13 18:12:47 +01:00
proc extCodeCopyOp (k: var VmCtx): EvmResultVoid =
## 0x3c, Copy an account's code to memory.
let
cpt = k.cpt
address = ? cpt.stack.popAddress()
(memStartPos, codeStartPos, size) = ? cpt.stack.popInt(3)
(memPos, codePos, len) =
(memStartPos.cleanMemRef, codeStartPos.cleanMemRef, size.cleanMemRef)
2021-04-13 18:12:47 +01:00
? cpt.opcodeGastCost(ExtCodeCopy,
cpt.gasCosts[ExtCodeCopy].m_handler(cpt.memory.len, memPos, len),
reason = "ExtCodeCopy fee")
2021-04-13 18:12:47 +01:00
let code = cpt.getCode(address)
cpt.memory.writePadded(code.bytes, memPos, codePos, len)
ok()
2021-04-13 18:12:47 +01:00
2021-04-15 17:42:19 +01:00
proc extCodeCopyEIP2929Op (k: var VmCtx): EvmResultVoid =
## 0x3c, Copy an account's code to memory.
let
cpt = k.cpt
address = ? cpt.stack.popAddress()
(memStartPos, codeStartPos, size) = ? cpt.stack.popInt(3)
(memPos, codePos, len) = (memStartPos.cleanMemRef,
codeStartPos.cleanMemRef, size.cleanMemRef)
2021-04-15 17:42:19 +01:00
gasCost = cpt.gasCosts[ExtCodeCopy].m_handler(cpt.memory.len, memPos, len) +
cpt.gasEip2929AccountCheck(address)
? cpt.opcodeGastCost(ExtCodeCopy, gasCost, reason = "ExtCodeCopy EIP2929")
2021-04-15 17:42:19 +01:00
let code = cpt.getCode(address)
cpt.memory.writePadded(code.bytes(), memPos, codePos, len)
ok()
2021-04-15 17:42:19 +01:00
# -----------
2021-04-13 18:12:47 +01:00
proc returnDataSizeOp (k: var VmCtx): EvmResultVoid =
## 0x3d, Get size of output data from the previous call from the
## current environment.
k.cpt.stack.push k.cpt.returnData.len
proc returnDataCopyOp (k: var VmCtx): EvmResultVoid =
## 0x3e, Copy output data from the previous call to memory.
let
(memStartPos, copyStartPos, size) = ? k.cpt.stack.popInt(3)
(memPos, copyPos, len) =
(memStartPos.cleanMemRef, copyStartPos.cleanMemRef, size.cleanMemRef)
gasCost = k.cpt.gasCosts[ReturnDataCopy].m_handler(
k.cpt.memory.len, memPos, len)
2021-04-13 18:12:47 +01:00
? k.cpt.opcodeGastCost(ReturnDataCopy, gasCost, reason = "returnDataCopy fee")
2021-04-13 18:12:47 +01:00
if copyPos + len > k.cpt.returnData.len:
return err(opErr(OutOfBounds))
k.cpt.memory.writePadded(k.cpt.returnData, memPos, copyPos, len)
ok()
2021-04-13 18:12:47 +01:00
# ---------------
2021-04-13 18:12:47 +01:00
proc extCodeHashOp (k: var VmCtx): EvmResultVoid =
## 0x3f, Returns the keccak256 hash of a contracts code
let
cpt = k.cpt
address = ? k.cpt.stack.popAddress()
2021-04-15 17:42:19 +01:00
cpt.stack.push cpt.getCodeHash(address)
2021-04-15 17:42:19 +01:00
proc extCodeHashEIP2929Op (k: var VmCtx): EvmResultVoid =
## 0x3f, EIP2929: Returns the keccak256 hash of a contracts code
let
cpt = k.cpt
address = ? k.cpt.stack.popAddress()
gasCost = cpt.gasEip2929AccountCheck(address)
2021-04-15 17:42:19 +01:00
? cpt.opcodeGastCost(ExtCodeHash, gasCost, reason = "ExtCodeHash EIP2929")
cpt.stack.push cpt.getCodeHash(address)
2021-04-15 17:42:19 +01:00
2021-04-13 18:12:47 +01:00
# ------------------------------------------------------------------------------
# Public, op exec table entries
# ------------------------------------------------------------------------------
const
VmOpExecEnvInfo*: seq[VmOpExec] = @[
2021-04-13 18:12:47 +01:00
(opCode: Address, ## 0x20, Address
forks: VmOpAllForks,
name: "address",
2021-04-13 18:12:47 +01:00
info: "Get address of currently executing account",
exec: (prep: VmOpIgnore,
run: VmOpFn addressOp,
post: VmOpIgnore)),
2021-04-13 18:12:47 +01:00
(opCode: Balance, ## 0x31, Balance
forks: VmOpAllForks - VmOpBerlinAndLater,
name: "balance",
2021-04-13 18:12:47 +01:00
info: "Get balance of the given account",
exec: (prep: VmOpIgnore,
2021-04-13 18:12:47 +01:00
run: balanceOp,
post: VmOpIgnore)),
2021-04-13 18:12:47 +01:00
2021-04-15 17:42:19 +01:00
(opCode: Balance, ## 0x31, Balance for Berlin and later
forks: VmOpBerlinAndLater,
name: "balanceEIP2929",
2021-04-15 17:42:19 +01:00
info: "EIP2929: Get balance of the given account",
exec: (prep: VmOpIgnore,
2021-04-15 17:42:19 +01:00
run: balanceEIP2929Op,
post: VmOpIgnore)),
2021-04-15 17:42:19 +01:00
2021-04-13 18:12:47 +01:00
(opCode: Origin, ## 0x32, Origination address
forks: VmOpAllForks,
name: "origin",
2021-04-13 18:12:47 +01:00
info: "Get execution origination address",
exec: (prep: VmOpIgnore,
2021-04-13 18:12:47 +01:00
run: originOp,
post: VmOpIgnore)),
2021-04-13 18:12:47 +01:00
(opCode: Caller, ## 0x33, Caller address
forks: VmOpAllForks,
name: "caller",
2021-04-13 18:12:47 +01:00
info: "Get caller address",
exec: (prep: VmOpIgnore,
2021-04-13 18:12:47 +01:00
run: callerOp,
post: VmOpIgnore)),
2021-04-13 18:12:47 +01:00
(opCode: CallValue, ## 0x34, Execution deposited value
forks: VmOpAllForks,
name: "callValue",
2021-04-13 18:12:47 +01:00
info: "Get deposited value by the instruction/transaction " &
"responsible for this execution",
exec: (prep: VmOpIgnore,
2021-04-13 18:12:47 +01:00
run: callValueOp,
post: VmOpIgnore)),
2021-04-13 18:12:47 +01:00
(opCode: CallDataLoad, ## 0x35, Input data
forks: VmOpAllForks,
name: "callDataLoad",
2021-04-13 18:12:47 +01:00
info: "Get input data of current environment",
exec: (prep: VmOpIgnore,
2021-04-13 18:12:47 +01:00
run: callDataLoadOp,
post: VmOpIgnore)),
2021-04-13 18:12:47 +01:00
(opCode: CallDataSize, ## 0x36, Size of input data
forks: VmOpAllForks,
name: "callDataSize",
2021-04-13 18:12:47 +01:00
info: "Get size of input data in current environment",
exec: (prep: VmOpIgnore,
2021-04-13 18:12:47 +01:00
run: callDataSizeOp,
post: VmOpIgnore)),
2021-04-13 18:12:47 +01:00
(opCode: CallDataCopy, ## 0x37, Copy input data to memory.
forks: VmOpAllForks,
name: "callDataCopy",
2021-04-13 18:12:47 +01:00
info: "Copy input data in current environment to memory",
exec: (prep: VmOpIgnore,
2021-04-13 18:12:47 +01:00
run: callDataCopyOp,
post: VmOpIgnore)),
2021-04-13 18:12:47 +01:00
(opCode: CodeSize, ## 0x38, Size of code
forks: VmOpAllForks,
name: "codeSize",
2021-04-13 18:12:47 +01:00
info: "Get size of code running in current environment",
exec: (prep: VmOpIgnore,
2021-04-13 18:12:47 +01:00
run: codeSizeOp,
post: VmOpIgnore)),
2021-04-13 18:12:47 +01:00
(opCode: CodeCopy, ## 0x39, Copy code to memory.
forks: VmOpAllForks,
name: "codeCopy",
2021-04-13 18:12:47 +01:00
info: "Copy code running in current environment to memory",
exec: (prep: VmOpIgnore,
2021-04-13 18:12:47 +01:00
run: codeCopyOp,
post: VmOpIgnore)),
2021-04-13 18:12:47 +01:00
(opCode: GasPrice, ## 0x3a, Gas price
forks: VmOpAllForks,
name: "gasPrice",
2021-04-13 18:12:47 +01:00
info: "Get price of gas in current environment",
exec: (prep: VmOpIgnore,
2021-04-13 18:12:47 +01:00
run: gasPriceOp,
post: VmOpIgnore)),
2021-04-13 18:12:47 +01:00
(opCode: ExtCodeSize, ## 0x3b, Account code size
forks: VmOpAllForks - VmOpBerlinAndLater,
name: "extCodeSize",
2021-04-13 18:12:47 +01:00
info: "Get size of an account's code",
exec: (prep: VmOpIgnore,
2021-04-13 18:12:47 +01:00
run: extCodeSizeOp,
post: VmOpIgnore)),
2021-04-13 18:12:47 +01:00
2021-04-15 17:42:19 +01:00
(opCode: ExtCodeSize, ## 0x3b, Account code size for Berlin and later
forks: VmOpBerlinAndLater,
name: "extCodeSizeEIP2929",
2021-04-15 17:42:19 +01:00
info: "EIP2929: Get size of an account's code",
exec: (prep: VmOpIgnore,
2021-04-15 17:42:19 +01:00
run: extCodeSizeEIP2929Op,
post: VmOpIgnore)),
2021-04-15 17:42:19 +01:00
2021-04-13 18:12:47 +01:00
(opCode: ExtCodeCopy, ## 0x3c, Account code copy to memory.
forks: VmOpAllForks - VmOpBerlinAndLater,
name: "extCodeCopy",
2021-04-13 18:12:47 +01:00
info: "Copy an account's code to memory",
exec: (prep: VmOpIgnore,
2021-04-13 18:12:47 +01:00
run: extCodeCopyOp,
post: VmOpIgnore)),
2021-04-13 18:12:47 +01:00
2021-04-15 17:42:19 +01:00
(opCode: ExtCodeCopy, ## 0x3c, Account Code-copy for Berlin and later
forks: VmOpBerlinAndLater,
name: "extCodeCopyEIP2929",
2021-04-15 17:42:19 +01:00
info: "EIP2929: Copy an account's code to memory",
exec: (prep: VmOpIgnore,
2021-04-15 17:42:19 +01:00
run: extCodeCopyEIP2929Op,
post: VmOpIgnore)),
2021-04-15 17:42:19 +01:00
2021-04-13 18:12:47 +01:00
(opCode: ReturnDataSize, ## 0x3d, Previous call output data size
forks: VmOpByzantiumAndLater,
name: "returnDataSize",
2021-04-13 18:12:47 +01:00
info: "Get size of output data from the previous call " &
"from the current environment",
exec: (prep: VmOpIgnore,
2021-04-13 18:12:47 +01:00
run: returnDataSizeOp,
post: VmOpIgnore)),
2021-04-13 18:12:47 +01:00
(opCode: ReturnDataCopy, ## 0x3e, Previous call output data copy to memory
forks: VmOpByzantiumAndLater,
name: "returnDataCopy",
2021-04-13 18:12:47 +01:00
info: "Copy output data from the previous call to memory",
exec: (prep: VmOpIgnore,
2021-04-13 18:12:47 +01:00
run: returnDataCopyOp,
post: VmOpIgnore)),
2021-04-15 17:42:19 +01:00
(opCode: ExtCodeHash, ## 0x3f, Contract hash
forks: VmOpConstantinopleAndLater - VmOpBerlinAndLater,
name: "extCodeHash",
2021-04-15 17:42:19 +01:00
info: "Returns the keccak256 hash of a contracts code",
exec: (prep: VmOpIgnore,
2021-04-15 17:42:19 +01:00
run: extCodeHashOp,
post: VmOpIgnore)),
2021-04-15 17:42:19 +01:00
(opCode: ExtCodeHash, ## 0x3f, Contract hash for berlin and later
forks: VmOpBerlinAndLater,
name: "extCodeHashEIP2929",
2021-04-15 17:42:19 +01:00
info: "EIP2929: Returns the keccak256 hash of a contracts code",
exec: (prep: VmOpIgnore,
2021-04-15 17:42:19 +01:00
run: extCodeHashEIP2929Op,
post: VmOpIgnore))]
2021-04-13 18:12:47 +01:00
# ------------------------------------------------------------------------------
# End
# ------------------------------------------------------------------------------