mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-02-07 01:35:38 +00:00
Disable some trace messages which appeared a lot in the output and probably aren't so useful any more, when block processing is functioning well at high speed. Turning on the trace level globally is useful to get a feel for what's happening, but only if each category is kept to a reasonable amount. As well as overwhelming the output so that it's hard to see general activity, some of these messages happen so much they severely slow down processing. Ones called every time an EVM opcode uses some gas are particularly extreme. These messages have all been chosen as things which are probably not useful any more (the relevant functionality has been debugged and is tested plenty). These have been commented out rather than removed. It may be that turning trace topics on/off, or other selection, is a better longer term solution, but that will require better command line options and good defaults for sure. (I think higher levels `tracev` and `tracevv` levels (extra verbose) would be more useful for this sort of deep tracing on request.) For now, enabling `--log-level:TRACE` on the command line is quite useful as long as we keep each category reasonable, and this patch tries to keep that balance. - Don't show "has transactions" on virtually every block imported. - Don't show "Sender" and "txHash" lines on every transaction processed. - Don't show "GAS CONSUMPTION" on every opcode executed", this is way too much. - Don't show "GAS RETURNED" and "GAS REFUND" on each contract call. - Don't show "op: Stop" on every Stop opcode, which means every transaction. - Don't show "Insufficient funds" whenever a contract can't call another. - Don't show "ECRecover", "SHA256 precompile", "RIPEMD160", "Identity" or even "Call precompile" every time a precompile is called. These are very well tested now. - Don't show "executeOpcodes error" whenever a contract returns an error. (This is changed to `trace` too, it's a normal event that is well tested.) Signed-off-by: Jamie Lokier <jamie@shareable.org>
459 lines
14 KiB
Nim
459 lines
14 KiB
Nim
# Nimbus
|
|
# Copyright (c) 2018 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: Call Operations
|
|
## ====================================
|
|
##
|
|
|
|
import
|
|
../../../constants,
|
|
../../../db/accounts_cache,
|
|
../../../errors,
|
|
../../../forks,
|
|
../../computation,
|
|
../../memory,
|
|
../../stack,
|
|
../../state,
|
|
../../types,
|
|
../gas_costs,
|
|
../gas_meter,
|
|
../op_codes,
|
|
../utils/utils_numeric,
|
|
./oph_defs,
|
|
chronicles,
|
|
eth/common,
|
|
eth/common/eth_types,
|
|
stint
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Private
|
|
# ------------------------------------------------------------------------------
|
|
|
|
type
|
|
LocalParams = tuple
|
|
gas: UInt256
|
|
value: UInt256
|
|
destination: EthAddress
|
|
sender: EthAddress
|
|
memInPos: int
|
|
memInLen: int
|
|
memOutPos: int
|
|
memOutLen: int
|
|
flags: MsgFlags
|
|
memOffset: int
|
|
memLength: int
|
|
contractAddress: EthAddress
|
|
|
|
|
|
proc updateStackAndParams(q: var LocalParams; c: Computation) =
|
|
c.stack.push(0)
|
|
|
|
let
|
|
outLen = calcMemSize(q.memOutPos, q.memOutLen)
|
|
inLen = calcMemSize(q.memInPos, q.memInLen)
|
|
|
|
# get the bigger one
|
|
if outLen < inLen:
|
|
q.memOffset = q.memInPos
|
|
q.memLength = q.memInLen
|
|
else:
|
|
q.memOffset = q.memOutPos
|
|
q.memLength = q.memOutLen
|
|
|
|
# EIP2929: This came before old gas calculator
|
|
# because it will affect `c.gasMeter.gasRemaining`
|
|
# and further `childGasLimit`
|
|
if FkBerlin <= c.fork:
|
|
c.vmState.mutateStateDB:
|
|
if not db.inAccessList(q.destination):
|
|
db.accessList(q.destination)
|
|
|
|
# The WarmStorageReadCostEIP2929 (100) is already deducted in
|
|
# the form of a constant `gasCall`
|
|
c.gasMeter.consumeGas(
|
|
ColdAccountAccessCost - WarmStorageReadCost,
|
|
reason = "EIP2929 gasCall")
|
|
|
|
|
|
proc callParams(c: Computation): LocalParams =
|
|
## Helper for callOp()
|
|
result.gas = c.stack.popInt()
|
|
result.destination = c.stack.popAddress()
|
|
result.value = c.stack.popInt()
|
|
result.memInPos = c.stack.popInt().cleanMemRef
|
|
result.memInLen = c.stack.popInt().cleanMemRef
|
|
result.memOutPos = c.stack.popInt().cleanMemRef
|
|
result.memOutLen = c.stack.popInt().cleanMemRef
|
|
|
|
result.sender = c.msg.contractAddress
|
|
result.flags = c.msg.flags
|
|
result.contractAddress = result.destination
|
|
|
|
result.updateStackAndParams(c)
|
|
|
|
|
|
proc callCodeParams(c: Computation): LocalParams =
|
|
## Helper for callCodeOp()
|
|
result = c.callParams
|
|
result.contractAddress = c.msg.contractAddress
|
|
|
|
|
|
proc delegateCallParams(c: Computation): LocalParams =
|
|
## Helper for delegateCall()
|
|
result.gas = c.stack.popInt()
|
|
result.destination = c.stack.popAddress()
|
|
result.memInPos = c.stack.popInt().cleanMemRef
|
|
result.memInLen = c.stack.popInt().cleanMemRef
|
|
result.memOutPos = c.stack.popInt().cleanMemRef
|
|
result.memOutLen = c.stack.popInt().cleanMemRef
|
|
|
|
result.value = c.msg.value
|
|
result.sender = c.msg.sender
|
|
result.flags = c.msg.flags
|
|
result.contractAddress = c.msg.contractAddress
|
|
|
|
result.updateStackAndParams(c)
|
|
|
|
|
|
proc staticCallParams(c: Computation): LocalParams =
|
|
## Helper for staticCall()
|
|
result.gas = c.stack.popInt()
|
|
result.destination = c.stack.popAddress()
|
|
result.memInPos = c.stack.popInt().cleanMemRef
|
|
result.memInLen = c.stack.popInt().cleanMemRef
|
|
result.memOutPos = c.stack.popInt().cleanMemRef
|
|
result.memOutLen = c.stack.popInt().cleanMemRef
|
|
|
|
result.value = 0.u256
|
|
result.sender = c.msg.contractAddress
|
|
result.flags = emvcStatic
|
|
result.contractAddress = result.destination
|
|
|
|
result.updateStackAndParams(c)
|
|
|
|
|
|
proc execSubCall(k: var Vm2Ctx; childMsg: Message; memPos, memLen: int) =
|
|
## Call new VM -- helper for `Call`-like operations
|
|
|
|
# need to provide explicit <c> and <child> for capturing in chainTo proc()
|
|
# <memPos> and <memLen> are provided by value and need not be captured
|
|
var
|
|
c = k.cpt
|
|
child = newComputation(k.cpt.vmState, childMsg)
|
|
|
|
k.cpt.chainTo(child):
|
|
if not child.shouldBurnGas:
|
|
c.gasMeter.returnGas(child.gasMeter.gasRemaining)
|
|
|
|
if child.isSuccess:
|
|
c.merge(child)
|
|
c.stack.top(1)
|
|
|
|
c.returnData = child.output
|
|
let actualOutputSize = min(memLen, child.output.len)
|
|
if actualOutputSize > 0:
|
|
c.memory.write(memPos, child.output.toOpenArray(0, actualOutputSize - 1))
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Private, op handlers implementation
|
|
# ------------------------------------------------------------------------------
|
|
|
|
const
|
|
callOp: Vm2OpFn = proc(k: var Vm2Ctx) =
|
|
## 0xf1, Message-Call into an account
|
|
|
|
if emvcStatic == k.cpt.msg.flags and k.cpt.stack[^3, UInt256] > 0.u256:
|
|
raise newException(
|
|
StaticContextError,
|
|
"Cannot modify state while inside of a STATICCALL context")
|
|
let
|
|
p = k.cpt.callParams
|
|
|
|
var (gasCost, childGasLimit) = k.cpt.gasCosts[Call].c_handler(
|
|
p.value,
|
|
GasParams(
|
|
kind: Call,
|
|
c_isNewAccount: not k.cpt.accountExists(p.contractAddress),
|
|
c_gasBalance: k.cpt.gasMeter.gasRemaining,
|
|
c_contractGas: p.gas,
|
|
c_currentMemSize: k.cpt.memory.len,
|
|
c_memOffset: p.memOffset,
|
|
c_memLength: p.memLength))
|
|
|
|
# EIP 2046: temporary disabled
|
|
# reduce gas fee for precompiles
|
|
# from 700 to 40
|
|
if gasCost >= 0:
|
|
k.cpt.gasMeter.consumeGas(gasCost, reason = $Call)
|
|
|
|
k.cpt.returnData.setLen(0)
|
|
|
|
if k.cpt.msg.depth >= MaxCallDepth:
|
|
debug "Computation Failure",
|
|
reason = "Stack too deep",
|
|
maximumDepth = MaxCallDepth,
|
|
depth = k.cpt.msg.depth
|
|
k.cpt.gasMeter.returnGas(childGasLimit)
|
|
return
|
|
|
|
if gasCost < 0 and childGasLimit <= 0:
|
|
raise newException(
|
|
OutOfGas, "Gas not enough to perform calculation (call)")
|
|
|
|
k.cpt.memory.extend(p.memInPos, p.memInLen)
|
|
k.cpt.memory.extend(p.memOutPos, p.memOutLen)
|
|
|
|
let senderBalance = k.cpt.getBalance(p.sender)
|
|
if senderBalance < p.value:
|
|
#debug "Insufficient funds",
|
|
# available = senderBalance,
|
|
# needed = k.cpt.msg.value
|
|
k.cpt.gasMeter.returnGas(childGasLimit)
|
|
return
|
|
|
|
k.execSubCall(
|
|
memPos = p.memOutPos,
|
|
memLen = p.memOutLen,
|
|
childMsg = Message(
|
|
kind: evmcCall,
|
|
depth: k.cpt.msg.depth + 1,
|
|
gas: childGasLimit,
|
|
sender: p.sender,
|
|
contractAddress: p.contractAddress,
|
|
codeAddress: p.destination,
|
|
value: p.value,
|
|
data: k.cpt.memory.read(p.memInPos, p.memInLen),
|
|
flags: p.flags))
|
|
|
|
# ---------------------
|
|
|
|
callCodeOp: Vm2OpFn = proc(k: var Vm2Ctx) =
|
|
## 0xf2, Message-call into this account with an alternative account's code.
|
|
let
|
|
p = k.cpt.callCodeParams
|
|
|
|
var (gasCost, childGasLimit) = k.cpt.gasCosts[CallCode].c_handler(
|
|
p.value,
|
|
GasParams(
|
|
kind: CallCode,
|
|
c_isNewAccount: not k.cpt.accountExists(p.contractAddress),
|
|
c_gasBalance: k.cpt.gasMeter.gasRemaining,
|
|
c_contractGas: p.gas,
|
|
c_currentMemSize: k.cpt.memory.len,
|
|
c_memOffset: p.memOffset,
|
|
c_memLength: p.memLength))
|
|
|
|
# EIP 2046: temporary disabled
|
|
# reduce gas fee for precompiles
|
|
# from 700 to 40
|
|
if gasCost >= 0:
|
|
k.cpt.gasMeter.consumeGas(gasCost, reason = $CallCode)
|
|
|
|
k.cpt.returnData.setLen(0)
|
|
|
|
if k.cpt.msg.depth >= MaxCallDepth:
|
|
debug "Computation Failure",
|
|
reason = "Stack too deep",
|
|
maximumDepth = MaxCallDepth,
|
|
depth = k.cpt.msg.depth
|
|
k.cpt.gasMeter.returnGas(childGasLimit)
|
|
return
|
|
|
|
# EIP 2046: temporary disabled
|
|
# reduce gas fee for precompiles
|
|
# from 700 to 40
|
|
if gasCost < 0 and childGasLimit <= 0:
|
|
raise newException(
|
|
OutOfGas, "Gas not enough to perform calculation (callCode)")
|
|
|
|
k.cpt.memory.extend(p.memInPos, p.memInLen)
|
|
k.cpt.memory.extend(p.memOutPos, p.memOutLen)
|
|
|
|
let senderBalance = k.cpt.getBalance(p.sender)
|
|
if senderBalance < p.value:
|
|
#debug "Insufficient funds",
|
|
# available = senderBalance,
|
|
# needed = k.cpt.msg.value
|
|
k.cpt.gasMeter.returnGas(childGasLimit)
|
|
return
|
|
|
|
k.execSubCall(
|
|
memPos = p.memOutPos,
|
|
memLen = p.memOutLen,
|
|
childMsg = Message(
|
|
kind: evmcCallCode,
|
|
depth: k.cpt.msg.depth + 1,
|
|
gas: childGasLimit,
|
|
sender: p.sender,
|
|
contractAddress: p.contractAddress,
|
|
codeAddress: p.destination,
|
|
value: p.value,
|
|
data: k.cpt.memory.read(p.memInPos, p.memInLen),
|
|
flags: p.flags))
|
|
|
|
# ---------------------
|
|
|
|
delegateCallOp: Vm2OpFn = proc(k: var Vm2Ctx) =
|
|
## 0xf4, Message-call into this account with an alternative account's
|
|
## code, but persisting the current values for sender and value.
|
|
let
|
|
p = k.cpt.delegateCallParams
|
|
|
|
var (gasCost, childGasLimit) = k.cpt.gasCosts[DelegateCall].c_handler(
|
|
p.value,
|
|
GasParams(
|
|
kind: DelegateCall,
|
|
c_isNewAccount: not k.cpt.accountExists(p.contractAddress),
|
|
c_gasBalance: k.cpt.gasMeter.gasRemaining,
|
|
c_contractGas: p.gas,
|
|
c_currentMemSize: k.cpt.memory.len,
|
|
c_memOffset: p.memOffset,
|
|
c_memLength: p.memLength))
|
|
|
|
# EIP 2046: temporary disabled
|
|
# reduce gas fee for precompiles
|
|
# from 700 to 40
|
|
if gasCost >= 0:
|
|
k.cpt.gasMeter.consumeGas(gasCost, reason = $DelegateCall)
|
|
|
|
k.cpt.returnData.setLen(0)
|
|
if k.cpt.msg.depth >= MaxCallDepth:
|
|
debug "Computation Failure",
|
|
reason = "Stack too deep",
|
|
maximumDepth = MaxCallDepth,
|
|
depth = k.cpt.msg.depth
|
|
k.cpt.gasMeter.returnGas(childGasLimit)
|
|
return
|
|
|
|
if gasCost < 0 and childGasLimit <= 0:
|
|
raise newException(
|
|
OutOfGas, "Gas not enough to perform calculation (delegateCall)")
|
|
|
|
k.cpt.memory.extend(p.memInPos, p.memInLen)
|
|
k.cpt.memory.extend(p.memOutPos, p.memOutLen)
|
|
|
|
k.execSubCall(
|
|
memPos = p.memOutPos,
|
|
memLen = p.memOutLen,
|
|
childMsg = Message(
|
|
kind: evmcDelegateCall,
|
|
depth: k.cpt.msg.depth + 1,
|
|
gas: childGasLimit,
|
|
sender: p.sender,
|
|
contractAddress: p.contractAddress,
|
|
codeAddress: p.destination,
|
|
value: p.value,
|
|
data: k.cpt.memory.read(p.memInPos, p.memInLen),
|
|
flags: p.flags))
|
|
|
|
# ---------------------
|
|
|
|
staticCallOp: Vm2OpFn = proc(k: var Vm2Ctx) =
|
|
## 0xfa, Static message-call into an account.
|
|
|
|
let
|
|
p = k.cpt.staticCallParams
|
|
|
|
var (gasCost, childGasLimit) = k.cpt.gasCosts[StaticCall].c_handler(
|
|
p.value,
|
|
GasParams(
|
|
kind: StaticCall,
|
|
c_isNewAccount: not k.cpt.accountExists(p.contractAddress),
|
|
c_gasBalance: k.cpt.gasMeter.gasRemaining,
|
|
c_contractGas: p.gas,
|
|
c_currentMemSize: k.cpt.memory.len,
|
|
c_memOffset: p.memOffset,
|
|
c_memLength: p.memLength))
|
|
|
|
# EIP 2046: temporary disabled
|
|
# reduce gas fee for precompiles
|
|
# from 700 to 40
|
|
#
|
|
# when opCode == StaticCall:
|
|
# if k.cpt.fork >= FkBerlin and destination.toInt <= MaxPrecompilesAddr:
|
|
# gasCost = gasCost - 660.GasInt
|
|
if gasCost >= 0:
|
|
k.cpt.gasMeter.consumeGas(gasCost, reason = $StaticCall)
|
|
|
|
k.cpt.returnData.setLen(0)
|
|
|
|
if k.cpt.msg.depth >= MaxCallDepth:
|
|
debug "Computation Failure",
|
|
reason = "Stack too deep",
|
|
maximumDepth = MaxCallDepth,
|
|
depth = k.cpt.msg.depth
|
|
k.cpt.gasMeter.returnGas(childGasLimit)
|
|
return
|
|
|
|
if gasCost < 0 and childGasLimit <= 0:
|
|
raise newException(
|
|
OutOfGas, "Gas not enough to perform calculation (staticCall)")
|
|
|
|
k.cpt.memory.extend(p.memInPos, p.memInLen)
|
|
k.cpt.memory.extend(p.memOutPos, p.memOutLen)
|
|
|
|
k.execSubCall(
|
|
memPos = p.memOutPos,
|
|
memLen = p.memOutLen,
|
|
childMsg = Message(
|
|
kind: evmcCall,
|
|
depth: k.cpt.msg.depth + 1,
|
|
gas: childGasLimit,
|
|
sender: p.sender,
|
|
contractAddress: p.contractAddress,
|
|
codeAddress: p.destination,
|
|
value: p.value,
|
|
data: k.cpt.memory.read(p.memInPos, p.memInLen),
|
|
flags: p.flags))
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Public, op exec table entries
|
|
# ------------------------------------------------------------------------------
|
|
|
|
const
|
|
vm2OpExecCall*: seq[Vm2OpExec] = @[
|
|
|
|
(opCode: Call, ## 0xf1, Message-Call into an account
|
|
forks: Vm2OpAllForks,
|
|
name: "call",
|
|
info: "Message-Call into an account",
|
|
exec: (prep: vm2OpIgnore,
|
|
run: callOp,
|
|
post: vm2OpIgnore)),
|
|
|
|
(opCode: CallCode, ## 0xf2, Message-Call with alternative code
|
|
forks: Vm2OpAllForks,
|
|
name: "callCode",
|
|
info: "Message-call into this account with alternative account's code",
|
|
exec: (prep: vm2OpIgnore,
|
|
run: callCodeOp,
|
|
post: vm2OpIgnore)),
|
|
|
|
(opCode: DelegateCall, ## 0xf4, CallCode with persisting sender and value
|
|
forks: Vm2OpHomesteadAndLater,
|
|
name: "delegateCall",
|
|
info: "Message-call into this account with an alternative account's " &
|
|
"code but persisting the current values for sender and value.",
|
|
exec: (prep: vm2OpIgnore,
|
|
run: delegateCallOp,
|
|
post: vm2OpIgnore)),
|
|
|
|
(opCode: StaticCall, ## 0xfa, Static message-call into an account
|
|
forks: Vm2OpByzantiumAndLater,
|
|
name: "staticCall",
|
|
info: "Static message-call into an account",
|
|
exec: (prep: vm2OpIgnore,
|
|
run: staticCallOp,
|
|
post: vm2OpIgnore))]
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# End
|
|
# ------------------------------------------------------------------------------
|