nimbus-eth1/nimbus/evm/interpreter/op_handlers/oph_log.nim

115 lines
3.2 KiB
Nim

# Nimbus
# Copyright (c) 2018-2024 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: Logging Operations
## =======================================
##
{.push raises: [].}
import
stew/assign2,
../../../constants,
../../evm_errors,
../../computation,
../../memory,
../../stack,
../../types,
../gas_costs,
../op_codes,
./oph_defs,
./oph_gen_handlers,
./oph_helpers,
eth/common,
sequtils,
stint
# ------------------------------------------------------------------------------
# Private, names & settings
# ------------------------------------------------------------------------------
proc fnName(n: int): string {.compileTime.} =
"log" & $n & "Op"
proc opName(n: int): string {.compileTime.} =
"Log" & $n
proc fnInfo(n: int): string {.compileTime.} =
var blurb = case n
of 1: "topic"
else: "topics"
"Append log record with " & $n & " " & blurb
proc logImpl(c: Computation, opcode: Op, topicCount: static int): EvmResultVoid =
static: doAssert(topicCount in 0 .. 4)
? checkInStaticContext(c)
const stackSize = 2 + topicCount
? c.stack.lsCheck(stackSize)
let
memPos = c.stack.lsPeekMemRef(^1)
len = c.stack.lsPeekMemRef(^2)
if memPos < 0 or len < 0:
return err(opErr(OutOfBounds))
? c.opcodeGasCost(opcode,
c.gasCosts[opcode].m_handler(c.memory.len, memPos, len),
reason = "Memory expansion, Log topic and data gas cost")
c.memory.extend(memPos, len)
when evmc_enabled:
var topics: array[4, evmc_bytes32]
for i in 0 ..< topicCount:
topics[i].bytes = c.stack.lsPeekTopic(^(i+3))
c.host.emitLog(c.msg.contractAddress,
c.memory.read(memPos, len),
topics[0].addr, topicCount)
else:
var log: Log
log.topics = newSeqOfCap[Topic](topicCount)
for i in 0 ..< topicCount:
log.topics.add Bytes32 c.stack.lsPeekTopic(^(i+3))
assign(log.data, c.memory.read(memPos, len))
log.address = c.msg.contractAddress
c.addLogEntry(log)
c.stack.lsShrink(stackSize)
ok()
const
inxRange = toSeq(0 .. 4)
logOpArg = block:
var rc: array[inxRange.len + 1, Op]
for n in inxRange:
rc[n] = Op(Log0.int + n)
rc
# ------------------------------------------------------------------------------
# Private, op handlers implementation
# ------------------------------------------------------------------------------
proc wrapperFn(cpt: VmCpt; n: static int): EvmResultVoid =
cpt.logImpl(logOpArg[n], n)
genOphHandlers fnName, fnInfo, inxRange, wrapperFn
# ------------------------------------------------------------------------------
# Public, op exec table entries
# ------------------------------------------------------------------------------
genOphList fnName, fnInfo, inxRange, "VmOpExecLog", opName
# ------------------------------------------------------------------------------
# End
# ------------------------------------------------------------------------------