nimbus-eth1/nimbus/p2p/executor/process_transaction.nim

108 lines
3.9 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.
import
std/[sets],
../../db/accounts_cache,
../../forks,
../../transaction/call_evm,
../../vm_state,
../../vm_types,
../validate,
./executor_helpers,
chronicles,
eth/common
{.push raises: [Defect].}
# ------------------------------------------------------------------------------
# Private functions
# ------------------------------------------------------------------------------
proc eip1559TxNormalization(tx: Transaction): Transaction =
result = tx
if tx.txType < TxEip1559:
result.maxPriorityFee = tx.gasPrice
result.maxFee = tx.gasPrice
proc processTransactionImpl(tx: Transaction, sender: EthAddress,
vmState: BaseVMState, fork: Fork): GasInt
# wildcard exception, wrapped below
{.gcsafe, raises: [Exception].} =
trace "Sender", sender
trace "txHash", rlpHash = tx.rlpHash
var tx = eip1559TxNormalization(tx)
var priorityFee: GasInt
if fork >= FkLondon:
# priority fee is capped because the base fee is filled first
let baseFee = vmState.blockHeader.baseFee.truncate(GasInt)
priorityFee = min(tx.maxPriorityFee, tx.maxFee - baseFee)
# signer pays both the priority fee and the base fee
# tx.gasPrice now is the effective gasPrice
tx.gasPrice = priorityFee + baseFee
let miner = vmState.coinbase()
if validateTransaction(vmState, tx, sender, fork):
result = txCallEvm(tx, sender, vmState, fork)
# miner fee
if fork >= FkLondon:
# miner only receives the priority fee;
# note that the base fee is not given to anyone (it is burned)
let txFee = result.u256 * priorityFee.u256
vmState.accountDb.addBalance(miner, txFee)
else:
let txFee = result.u256 * tx.gasPrice.u256
vmState.accountDb.addBalance(miner, txFee)
vmState.cumulativeGasUsed += result
vmState.mutateStateDB:
for deletedAccount in vmState.selfDestructs:
db.deleteAccount deletedAccount
if fork >= FkSpurious:
vmState.touchedAccounts.incl(miner)
# EIP158/161 state clearing
for account in vmState.touchedAccounts:
if db.accountExists(account) and db.isEmptyAccount(account):
debug "state clearing", account
db.deleteAccount(account)
if vmState.generateWitness:
vmState.accountDb.collectWitnessData()
vmState.accountDb.persist(clearCache = false)
# ------------------------------------------------------------------------------
# Public functions
# ------------------------------------------------------------------------------
proc processTransaction*(tx: Transaction, sender: EthAddress,
vmState: BaseVMState, fork: Fork): GasInt
{.gcsafe, raises: [Defect,CatchableError].} =
## Process the transaction, write the results to db.
## Returns amount of ETH to be rewarded to miner
safeExecutor("processTransaction"):
result = tx.processTransactionImpl(sender, vmState, fork)
proc processTransaction*(tx: Transaction, sender: EthAddress,
vmState: BaseVMState): GasInt
{.gcsafe, raises: [Defect,CatchableError].} =
## Same as the other prototype variant with the `fork` argument derived
## from `vmState` in a canonical way
safeExecutor("processTransaction"):
result = tx.processTransaction(sender, vmState, vmState.getForkUnsafe)
# ------------------------------------------------------------------------------
# End
# ------------------------------------------------------------------------------