2021-07-06 13:14:45 +00:00
|
|
|
# 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
|
|
|
|
../../constants,
|
|
|
|
../../db/[db_chain, accounts_cache],
|
|
|
|
../../transaction,
|
|
|
|
../../utils,
|
|
|
|
../../vm_state,
|
|
|
|
../../vm_types,
|
|
|
|
../clique,
|
|
|
|
../dao,
|
|
|
|
./calculate_reward,
|
|
|
|
./executor_helpers,
|
|
|
|
./process_transaction,
|
|
|
|
chronicles,
|
|
|
|
eth/[common, trie/db],
|
2022-01-10 09:04:06 +00:00
|
|
|
stew/results
|
2021-07-06 13:14:45 +00:00
|
|
|
|
2021-07-14 15:13:27 +00:00
|
|
|
{.push raises: [Defect].}
|
|
|
|
|
2021-07-06 13:14:45 +00:00
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# Private functions
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
|
2022-01-10 09:04:06 +00:00
|
|
|
proc procBlkPreamble(vmState: BaseVMState;
|
|
|
|
header: BlockHeader; body: BlockBody): bool
|
|
|
|
{.gcsafe, raises: [Defect,CatchableError].} =
|
|
|
|
|
2021-07-06 13:14:45 +00:00
|
|
|
if vmState.chainDB.config.daoForkSupport and
|
|
|
|
vmState.chainDB.config.daoForkBlock == header.blockNumber:
|
|
|
|
vmState.mutateStateDB:
|
|
|
|
db.applyDAOHardFork()
|
|
|
|
|
|
|
|
if body.transactions.calcTxRoot != header.txRoot:
|
|
|
|
debug "Mismatched txRoot",
|
|
|
|
blockNumber = header.blockNumber
|
|
|
|
return false
|
|
|
|
|
2022-09-03 18:15:35 +00:00
|
|
|
if header.txRoot != EMPTY_ROOT_HASH:
|
2021-07-06 13:14:45 +00:00
|
|
|
if body.transactions.len == 0:
|
|
|
|
debug "No transactions in body",
|
|
|
|
blockNumber = header.blockNumber
|
|
|
|
return false
|
|
|
|
else:
|
Tracing: Remove some trace messages that occur a lot during sync
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>
2021-07-22 13:35:41 +00:00
|
|
|
#trace "Has transactions",
|
|
|
|
# blockNumber = header.blockNumber,
|
|
|
|
# blockHash = header.blockHash
|
2021-07-06 13:14:45 +00:00
|
|
|
vmState.receipts = newSeq[Receipt](body.transactions.len)
|
|
|
|
vmState.cumulativeGasUsed = 0
|
|
|
|
for txIndex, tx in body.transactions:
|
|
|
|
var sender: EthAddress
|
2022-01-10 09:04:06 +00:00
|
|
|
if not tx.getSender(sender):
|
2021-07-06 13:14:45 +00:00
|
|
|
debug "Could not get sender",
|
|
|
|
txIndex, tx
|
|
|
|
return false
|
2022-01-10 09:04:06 +00:00
|
|
|
let rc = vmState.processTransaction(tx, sender, header)
|
|
|
|
if rc.isErr:
|
|
|
|
return false
|
2021-07-06 13:14:45 +00:00
|
|
|
vmState.receipts[txIndex] = vmState.makeReceipt(tx.txType)
|
|
|
|
|
|
|
|
if vmState.cumulativeGasUsed != header.gasUsed:
|
|
|
|
debug "gasUsed neq cumulativeGasUsed",
|
|
|
|
gasUsed = header.gasUsed,
|
|
|
|
cumulativeGasUsed = vmState.cumulativeGasUsed
|
|
|
|
return false
|
|
|
|
|
|
|
|
if header.ommersHash != EMPTY_UNCLE_HASH:
|
|
|
|
let h = vmState.chainDB.persistUncles(body.uncles)
|
|
|
|
if h != header.ommersHash:
|
|
|
|
debug "Uncle hash mismatch"
|
|
|
|
return false
|
|
|
|
|
2022-01-18 13:05:00 +00:00
|
|
|
true
|
2021-07-06 13:14:45 +00:00
|
|
|
|
|
|
|
|
2022-01-10 09:04:06 +00:00
|
|
|
proc procBlkEpilogue(vmState: BaseVMState;
|
|
|
|
header: BlockHeader; body: BlockBody): bool
|
|
|
|
{.gcsafe, raises: [Defect,RlpError].} =
|
2021-07-06 13:14:45 +00:00
|
|
|
# Reward beneficiary
|
|
|
|
vmState.mutateStateDB:
|
|
|
|
if vmState.generateWitness:
|
|
|
|
db.collectWitnessData()
|
|
|
|
db.persist(ClearCache in vmState.flags)
|
|
|
|
|
2021-10-28 09:42:39 +00:00
|
|
|
let stateDb = vmState.stateDB
|
2021-07-06 13:14:45 +00:00
|
|
|
if header.stateRoot != stateDb.rootHash:
|
|
|
|
debug "wrong state root in block",
|
|
|
|
blockNumber = header.blockNumber,
|
|
|
|
expected = header.stateRoot,
|
|
|
|
actual = stateDb.rootHash,
|
|
|
|
arrivedFrom = vmState.chainDB.getCanonicalHead().stateRoot
|
|
|
|
return false
|
|
|
|
|
|
|
|
let bloom = createBloom(vmState.receipts)
|
|
|
|
if header.bloom != bloom:
|
|
|
|
debug "wrong bloom in block",
|
|
|
|
blockNumber = header.blockNumber
|
|
|
|
return false
|
|
|
|
|
|
|
|
let receiptRoot = calcReceiptRoot(vmState.receipts)
|
|
|
|
if header.receiptRoot != receiptRoot:
|
|
|
|
debug "wrong receiptRoot in block",
|
|
|
|
blockNumber = header.blockNumber,
|
|
|
|
actual = receiptRoot,
|
|
|
|
expected = header.receiptRoot
|
|
|
|
return false
|
|
|
|
|
2022-01-18 13:05:00 +00:00
|
|
|
true
|
2021-07-06 13:14:45 +00:00
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# Public functions
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
|
2022-01-10 09:04:06 +00:00
|
|
|
proc processBlockNotPoA*(
|
|
|
|
vmState: BaseVMState; ## Parent environment of header/body block
|
|
|
|
header: BlockHeader; ## Header/body block to add to the blockchain
|
|
|
|
body: BlockBody): ValidationResult
|
|
|
|
{.gcsafe, raises: [Defect,CatchableError].} =
|
2021-07-30 14:06:51 +00:00
|
|
|
## Processes `(header,body)` pair for a non-PoA network, only. This function
|
|
|
|
## will fail when applied to a PoA network like `Goerli`.
|
2021-07-06 13:14:45 +00:00
|
|
|
if vmState.chainDB.config.poaEngine:
|
|
|
|
# PoA consensus engine unsupported, see the other version of
|
|
|
|
# processBlock() below
|
|
|
|
debug "Unsupported PoA request"
|
|
|
|
return ValidationResult.Error
|
|
|
|
|
|
|
|
var dbTx = vmState.chainDB.db.beginTransaction()
|
|
|
|
defer: dbTx.dispose()
|
|
|
|
|
2022-01-10 09:04:06 +00:00
|
|
|
if not vmState.procBlkPreamble(header, body):
|
2021-07-06 13:14:45 +00:00
|
|
|
return ValidationResult.Error
|
|
|
|
|
2022-02-08 09:27:04 +00:00
|
|
|
if not vmState.ttdReached: # EIP-3675: no reward for miner
|
|
|
|
vmState.calculateReward(header, body)
|
2021-07-06 13:14:45 +00:00
|
|
|
|
2022-01-10 09:04:06 +00:00
|
|
|
if not vmState.procBlkEpilogue(header, body):
|
2021-07-06 13:14:45 +00:00
|
|
|
return ValidationResult.Error
|
|
|
|
|
|
|
|
# `applyDeletes = false`
|
|
|
|
# If the trie pruning activated, each of the block will have its own state
|
|
|
|
# trie keep intact, rather than destroyed by trie pruning. But the current
|
|
|
|
# block will still get a pruned trie. If trie pruning deactivated,
|
|
|
|
# `applyDeletes` have no effects.
|
|
|
|
dbTx.commit(applyDeletes = false)
|
|
|
|
|
2022-01-10 09:04:06 +00:00
|
|
|
ValidationResult.OK
|
|
|
|
|
2021-07-06 13:14:45 +00:00
|
|
|
|
2022-01-10 09:04:06 +00:00
|
|
|
proc processBlock*(
|
|
|
|
vmState: BaseVMState; ## Parent environment of header/body block
|
|
|
|
poa: Clique; ## PoA descriptor (if needed, at all)
|
|
|
|
header: BlockHeader; ## Header/body block to add to the blockchain
|
|
|
|
body: BlockBody): ValidationResult
|
|
|
|
{.gcsafe, raises: [Defect,CatchableError].} =
|
2021-07-14 15:13:27 +00:00
|
|
|
## Generalised function to processes `(header,body)` pair for any network,
|
2021-07-30 14:06:51 +00:00
|
|
|
## regardless of PoA or not. Currently there is no mining support so this
|
|
|
|
## function is mostly the same as `processBlockNotPoA()`.
|
|
|
|
##
|
|
|
|
## Rather than calculating the PoA state change here, it is done with the
|
|
|
|
## verification in the `chain/persist_blocks.persistBlocks()` method. So
|
|
|
|
## the `poa` descriptor is currently unused and only provided for later
|
|
|
|
## implementations (but can be savely removed, as well.)
|
2022-01-10 09:04:06 +00:00
|
|
|
## variant of `processBlock()` where the `header` argument is explicitely set.
|
|
|
|
##
|
2021-07-30 14:06:51 +00:00
|
|
|
# # Process PoA state transition first so there is no need to re-wind on
|
|
|
|
# # an error.
|
|
|
|
# if vmState.chainDB.config.poaEngine and
|
|
|
|
# not poa.updatePoaState(header, body):
|
|
|
|
# debug "PoA update failed"
|
|
|
|
# return ValidationResult.Error
|
2021-07-14 15:13:27 +00:00
|
|
|
|
2021-07-06 13:14:45 +00:00
|
|
|
var dbTx = vmState.chainDB.db.beginTransaction()
|
|
|
|
defer: dbTx.dispose()
|
|
|
|
|
2022-01-10 09:04:06 +00:00
|
|
|
if not vmState.procBlkPreamble(header, body):
|
2021-07-06 13:14:45 +00:00
|
|
|
return ValidationResult.Error
|
|
|
|
|
2022-02-08 09:27:04 +00:00
|
|
|
let disableReward = vmState.chainDB.config.poaEngine or
|
|
|
|
vmState.ttdReached # EIP-3675: no reward for miner
|
|
|
|
|
|
|
|
if not disableReward:
|
2021-07-06 13:14:45 +00:00
|
|
|
vmState.calculateReward(header, body)
|
|
|
|
|
2022-01-10 09:04:06 +00:00
|
|
|
if not vmState.procBlkEpilogue(header, body):
|
2021-07-06 13:14:45 +00:00
|
|
|
return ValidationResult.Error
|
|
|
|
|
|
|
|
dbTx.commit(applyDeletes = false)
|
|
|
|
|
2022-01-10 09:04:06 +00:00
|
|
|
ValidationResult.OK
|
|
|
|
|
2021-07-06 13:14:45 +00:00
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# End
|
|
|
|
# ------------------------------------------------------------------------------
|