mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-01-12 05:14:14 +00:00
fix txpool: using consensus rule to prepare header
This commit is contained in:
parent
b81511fcfc
commit
a26a9f9ece
@ -17,7 +17,7 @@ import
|
||||
./genesis,
|
||||
../utils/[utils, ec_recover],
|
||||
../db/[db_chain, storage_types],
|
||||
../core/[pow, clique]
|
||||
../core/[pow, clique, casper]
|
||||
|
||||
export
|
||||
chain_config,
|
||||
@ -72,6 +72,9 @@ type
|
||||
poa: Clique ##\
|
||||
## For non-PoA networks this descriptor is ignored.
|
||||
|
||||
pos: CasperRef
|
||||
## Proof Of Stake descriptor
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Forward declarations
|
||||
# ------------------------------------------------------------------------------
|
||||
@ -145,6 +148,7 @@ proc init(com : CommonRef,
|
||||
|
||||
# Always initialise the PoW epoch cache even though it migh no be used
|
||||
com.pow = PowRef.new
|
||||
com.pos = CasperRef.new
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Public constructors
|
||||
@ -197,7 +201,10 @@ proc clone*(com: CommonRef, db: TrieDatabaseRef): CommonRef =
|
||||
syncProgress : com.syncProgress,
|
||||
networkId : com.networkId,
|
||||
currentFork : com.currentFork,
|
||||
consensusType: com.consensusType
|
||||
consensusType: com.consensusType,
|
||||
pow : com.pow,
|
||||
poa : com.poa,
|
||||
pos : com.pos
|
||||
)
|
||||
|
||||
proc clone*(com: CommonRef): CommonRef =
|
||||
@ -357,6 +364,10 @@ proc pow*(com: CommonRef): PowRef =
|
||||
## Getter
|
||||
com.pow
|
||||
|
||||
proc pos*(com: CommonRef): CasperRef =
|
||||
## Getter
|
||||
com.pos
|
||||
|
||||
func db*(com: CommonRef): ChainDBRef =
|
||||
com.db
|
||||
|
||||
|
54
nimbus/core/casper.nim
Normal file
54
nimbus/core/casper.nim
Normal file
@ -0,0 +1,54 @@
|
||||
# Nimbus
|
||||
# Copyright (c) 2022 Status Research & Development GmbH
|
||||
# Licensed under either of
|
||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||
# at your option.
|
||||
# This file may not be copied, modified, or distributed except according to
|
||||
# those terms.
|
||||
import
|
||||
eth/common
|
||||
|
||||
type
|
||||
CasperRef* = ref object
|
||||
feeRecipient : EthAddress
|
||||
timestamp : EthTime
|
||||
prevRandao : Hash256
|
||||
|
||||
proc prepare*(ctx: CasperRef, header: var BlockHeader) =
|
||||
header.coinbase = ctx.feeRecipient
|
||||
header.timestamp = ctx.timestamp
|
||||
header.prevRandao = ctx.prevRandao
|
||||
header.difficulty = DifficultyInt.zero
|
||||
|
||||
proc prepareForSeal*(ctx: CasperRef, header: var BlockHeader) =
|
||||
header.nonce = default(BlockNonce)
|
||||
header.extraData = @[] # TODO: probably this should be configurable by user?
|
||||
# this repetition, assigning prevRandao is because how txpool works
|
||||
header.prevRandao = ctx.prevRandao
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Getters
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
func feeRecipient*(ctx: CasperRef): EthAddress =
|
||||
ctx.feeRecipient
|
||||
|
||||
func timestamp*(ctx: CasperRef): EthTime =
|
||||
ctx.timestamp
|
||||
|
||||
func prevRandao*(ctx: CasperRef): Hash256 =
|
||||
ctx.prevRandao
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Setters
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
proc `feeRecipient=`*(ctx: CasperRef, val: EthAddress) =
|
||||
ctx.feeRecipient = val
|
||||
|
||||
proc `timestamp=`*(ctx: CasperRef, val: EthTime) =
|
||||
ctx.timestamp = val
|
||||
|
||||
proc `prevRandao=`*(ctx: CasperRef, val: Hash256) =
|
||||
ctx.prevRandao = val
|
@ -173,7 +173,7 @@ proc prepare*(c: Clique; parent: BlockHeader, header: var BlockHeader): CliqueOk
|
||||
## running the transactions on top.
|
||||
|
||||
# Assemble the voting snapshot to check which votes make sense
|
||||
let rc = c.cliqueSnapshot(header.parentHash, @[])
|
||||
let rc = c.cliqueSnapshot(parent.blockHash, @[])
|
||||
if rc.isErr:
|
||||
return err(rc.error)
|
||||
|
||||
@ -184,7 +184,8 @@ proc prepare*(c: Clique; parent: BlockHeader, header: var BlockHeader): CliqueOk
|
||||
# signer list
|
||||
header.coinbase.reset
|
||||
|
||||
if (header.blockNumber mod c.cfg.epoch) != 0:
|
||||
let modEpoch = (parent.blockNumber+1) mod c.cfg.epoch
|
||||
if modEpoch != 0:
|
||||
c.doExclusively:
|
||||
# Gather all the proposals that make sense voting on
|
||||
var addresses: seq[EthAddress]
|
||||
@ -203,7 +204,7 @@ proc prepare*(c: Clique; parent: BlockHeader, header: var BlockHeader): CliqueOk
|
||||
|
||||
# Ensure the extra data has all its components
|
||||
header.extraData.setLen(EXTRA_VANITY)
|
||||
if (header.blockNumber mod c.cfg.epoch) == 0:
|
||||
if modEpoch == 0:
|
||||
header.extraData.add c.snapshot.ballot.authSigners.mapIt(toSeq(it)).concat
|
||||
header.extraData.add 0.byte.repeat(EXTRA_SEAL)
|
||||
|
||||
@ -217,6 +218,12 @@ proc prepare*(c: Clique; parent: BlockHeader, header: var BlockHeader): CliqueOk
|
||||
|
||||
ok()
|
||||
|
||||
proc prepareForSeal*(c: Clique; prepHeader: BlockHeader; header: var BlockHeader) =
|
||||
# TODO: use system.move?
|
||||
header.nonce = prepHeader.nonce
|
||||
header.extraData = prepHeader.extraData
|
||||
header.mixDigest = prepHeader.mixDigest
|
||||
|
||||
# clique/clique.go(589): func (c *Clique) Authorize(signer [..]
|
||||
proc authorize*(c: Clique; signer: EthAddress; signFn: CliqueSignerFn) =
|
||||
## Injects private key into the consensus engine to mint new blocks with.
|
||||
@ -313,7 +320,8 @@ proc seal*(c: Clique; ethBlock: var EthBlock):
|
||||
header.extraData.setLen(extraLen - EXTRA_SEAL)
|
||||
header.extraData.add signature.value
|
||||
except Exception as exc:
|
||||
return err((errCliqueSealSigFn, "Error when signing block header"))
|
||||
return err((errCliqueSealSigFn,
|
||||
"Error when signing block header: " & exc.msg))
|
||||
|
||||
ethBlock = ethBlock.withHeader(header)
|
||||
ok()
|
||||
|
@ -20,6 +20,7 @@ import
|
||||
"."/[
|
||||
chain,
|
||||
tx_pool,
|
||||
casper,
|
||||
validate],
|
||||
"."/clique/[clique_defs,
|
||||
clique_desc,
|
||||
@ -70,47 +71,14 @@ proc validateSealer*(conf: NimbusConf, ctx: EthContext, chain: ChainRef): Result
|
||||
|
||||
ok()
|
||||
|
||||
proc prepareBlock(engine: SealingEngineRef,
|
||||
parent: BlockHeader,
|
||||
time: Time,
|
||||
prevRandao: Hash256): Result[EthBlock, string] =
|
||||
let timestamp = if parent.timestamp >= time:
|
||||
parent.timestamp + 1.seconds
|
||||
else:
|
||||
time
|
||||
proc generateBlock(engine: SealingEngineRef,
|
||||
outBlock: var EthBlock): Result[void, string] =
|
||||
|
||||
engine.txPool.prevRandao = prevRandao
|
||||
|
||||
var blk = engine.txPool.ethBlock()
|
||||
|
||||
if engine.chain.com.isBlockAfterTtd(blk.header):
|
||||
blk.header.difficulty = DifficultyInt.zero
|
||||
blk.header.mixDigest = prevRandao
|
||||
blk.header.nonce = default(BlockNonce)
|
||||
blk.header.extraData = @[] # TODO: probably this should be configurable by user?
|
||||
outBlock = engine.txPool.ethBlock()
|
||||
if engine.chain.com.consensus == ConsensusType.POS:
|
||||
# Stop the block generator if we reach TTD
|
||||
engine.state = EnginePostMerge
|
||||
else:
|
||||
let res = engine.chain.clique.prepare(parent, blk.header)
|
||||
if res.isErr:
|
||||
return err($res.error)
|
||||
|
||||
ok(blk)
|
||||
|
||||
proc generateBlock(engine: SealingEngineRef,
|
||||
parentHeader: BlockHeader,
|
||||
outBlock: var EthBlock,
|
||||
timestamp = getTime(),
|
||||
prevRandao = Hash256()): Result[void, string] =
|
||||
# deviation from standard block generator
|
||||
# - no DAO hard fork
|
||||
# - no local and remote uncles inclusion
|
||||
|
||||
let res = prepareBlock(engine, parentHeader, timestamp, prevRandao)
|
||||
if res.isErr:
|
||||
return err("error prepare header")
|
||||
|
||||
outBlock = res.get()
|
||||
if engine.state != EnginePostMerge:
|
||||
# Post merge, Clique should not be executing
|
||||
let sealRes = engine.chain.clique.seal(outBlock)
|
||||
@ -123,13 +91,6 @@ proc generateBlock(engine: SealingEngineRef,
|
||||
|
||||
ok()
|
||||
|
||||
proc generateBlock(engine: SealingEngineRef,
|
||||
outBlock: var EthBlock,
|
||||
timestamp = getTime(),
|
||||
prevRandao = Hash256()): Result[void, string] =
|
||||
generateBlock(engine, engine.chain.currentBlock(),
|
||||
outBlock, timestamp, prevRandao)
|
||||
|
||||
proc sealingLoop(engine: SealingEngineRef): Future[void] {.async.} =
|
||||
let clique = engine.chain.clique
|
||||
|
||||
@ -145,20 +106,6 @@ proc sealingLoop(engine: SealingEngineRef): Future[void] {.async.} =
|
||||
|
||||
clique.authorize(engine.signer, signerFunc)
|
||||
|
||||
proc diffCalculator(timeStamp: EthTime, parent: BlockHeader): DifficultyInt {.gcsafe, raises:[].} =
|
||||
# pesky Nim effect system
|
||||
try:
|
||||
discard timestamp
|
||||
let rc = clique.calcDifficulty(parent)
|
||||
if rc.isErr:
|
||||
return 0.u256
|
||||
rc.get()
|
||||
except:
|
||||
0.u256
|
||||
|
||||
# switch to PoA difficulty calculator
|
||||
engine.txPool.calcDifficulty = diffCalculator
|
||||
|
||||
# convert times.Duration to chronos.Duration
|
||||
let period = chronos.seconds(clique.cfg.period.inSeconds)
|
||||
|
||||
@ -198,32 +145,24 @@ proc generateExecutionPayload*(engine: SealingEngineRef,
|
||||
let
|
||||
headBlock = try: engine.chain.db.getCanonicalHead()
|
||||
except CatchableError: return err "No head block in database"
|
||||
prevRandao = Hash256(data: distinctBase payloadAttrs.prevRandao)
|
||||
timestamp = fromUnix(payloadAttrs.timestamp.unsafeQuantityToInt64)
|
||||
coinbase = EthAddress payloadAttrs.suggestedFeeRecipient
|
||||
pos = engine.chain.com.pos
|
||||
|
||||
pos.prevRandao = Hash256(data: distinctBase payloadAttrs.prevRandao)
|
||||
pos.timestamp = fromUnix(payloadAttrs.timestamp.unsafeQuantityToInt64)
|
||||
pos.feeRecipient = EthAddress payloadAttrs.suggestedFeeRecipient
|
||||
|
||||
if headBlock.blockHash != engine.txPool.head.blockHash:
|
||||
# reorg
|
||||
discard engine.txPool.smartHead(headBlock)
|
||||
|
||||
var blk: EthBlock
|
||||
engine.txPool.feeRecipient = coinbase
|
||||
|
||||
let blkRes = engine.generateBlock(
|
||||
headBlock,
|
||||
blk,
|
||||
timestamp,
|
||||
prevRandao)
|
||||
|
||||
if blkRes.isErr:
|
||||
error "sealing engine generateBlock error", msg = blkRes.error
|
||||
return blkRes
|
||||
let res = engine.generateBlock(blk)
|
||||
if res.isErr:
|
||||
error "sealing engine generateBlock error", msg = res.error
|
||||
return res
|
||||
|
||||
# make sure both generated block header and payloadRes(ExecutionPayloadV1)
|
||||
# produce the same blockHash
|
||||
doAssert blk.header.coinbase == coinbase
|
||||
blk.header.timestamp = timestamp
|
||||
blk.header.prevRandao = prevRandao
|
||||
blk.header.fee = some(blk.header.fee.get(UInt256.zero)) # force it with some(UInt256)
|
||||
|
||||
let blockHash = rlpHash(blk.header)
|
||||
|
@ -771,22 +771,6 @@ proc `minTipPrice=`*(xp: TxPoolRef; val: GasPrice) =
|
||||
xp.pMinTipPrice = val
|
||||
xp.pDirtyBuckets = true
|
||||
|
||||
proc `prevRandao=`*(xp: TxPoolRef; val: Hash256) =
|
||||
## Setter, PoS block randomness
|
||||
## Used by `prevRandao` op code in EVM after transition to PoS
|
||||
## do nothing before transition
|
||||
xp.chain.prevRandao = val
|
||||
|
||||
proc `feeRecipient=`*(xp: TxPoolRef; beneficiary: EthAddress) =
|
||||
## Setter, PoS tx fee recipient
|
||||
## a.k.a miner in PoW chain or coinbase
|
||||
xp.chain.miner = beneficiary
|
||||
|
||||
proc `calcDifficulty=`*(xp: TxPoolRef; val: DifficultyCalculator) =
|
||||
## Setter, either PoW or PoA difficulty calculator
|
||||
## PoS difficulty always zero
|
||||
xp.chain.calcDifficulty = val
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Public functions, per-tx-item operations
|
||||
# ------------------------------------------------------------------------------
|
||||
|
@ -17,11 +17,13 @@ import
|
||||
../../common/common,
|
||||
../../constants,
|
||||
../../db/accounts_cache,
|
||||
../../core/executor,
|
||||
../../utils/utils,
|
||||
../../core/pow/difficulty,
|
||||
../../vm_state,
|
||||
../../vm_types,
|
||||
../clique/clique_sealer,
|
||||
../pow/difficulty,
|
||||
../executor,
|
||||
../casper,
|
||||
./tx_chain/[tx_basefee, tx_gaslimits],
|
||||
./tx_item
|
||||
|
||||
@ -51,8 +53,6 @@ type
|
||||
txRoot: Hash256 ## `rootHash` after packing
|
||||
stateRoot: Hash256 ## `stateRoot` after packing
|
||||
|
||||
DifficultyCalculator* = proc(timeStamp: EthTime, parent: BlockHeader): DifficultyInt {.gcsafe, raises:[].}
|
||||
|
||||
TxChainRef* = ref object ##\
|
||||
## State cache of the transaction environment for creating a new\
|
||||
## block. This state is typically synchrionised with the canonical\
|
||||
@ -65,16 +65,40 @@ type
|
||||
roAcc: ReadOnlyStateDB ## Accounts cache fixed on current sync header
|
||||
limits: TxChainGasLimits ## Gas limits for packer and next header
|
||||
txEnv: TxChainPackerEnv ## Assorted parameters, tx packer environment
|
||||
|
||||
# EIP-4399 and EIP-3675
|
||||
prevRandao: Hash256 ## PoS block randomness
|
||||
|
||||
# overrideable difficulty calculator
|
||||
calcDifficulty: DifficultyCalculator
|
||||
prepHeader: BlockHeader ## Prepared Header from Consensus Engine
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Private functions
|
||||
# ------------------------------------------------------------------------------
|
||||
proc prepareHeader(dh: TxChainRef; parent: BlockHeader)
|
||||
{.gcsafe, raises: [Defect, CatchableError].} =
|
||||
|
||||
case dh.com.consensus
|
||||
of ConsensusType.POW:
|
||||
dh.prepHeader.timestamp = getTime().utc.toTime
|
||||
dh.prepHeader.difficulty = dh.com.calcDifficulty(
|
||||
dh.prepHeader.timestamp, parent)
|
||||
dh.prepHeader.coinbase = dh.miner
|
||||
dh.prepHeader.mixDigest.reset
|
||||
of ConsensusType.POA:
|
||||
discard dh.com.poa.prepare(parent, dh.prepHeader)
|
||||
# beware POA header.coinbase != signerAddress
|
||||
# but BaseVMState.minerAddress == signerAddress
|
||||
# - minerAddress is extracted from header.extraData
|
||||
# - header.coinbase is from clique engine
|
||||
dh.prepHeader.coinbase = dh.miner
|
||||
of ConsensusType.POS:
|
||||
dh.com.pos.prepare(dh.prepHeader)
|
||||
|
||||
proc prepareForSeal(dh: TxChainRef; header: var BlockHeader) =
|
||||
case dh.com.consensus
|
||||
of ConsensusType.POW:
|
||||
# do nothing, tx pool was designed with POW in mind
|
||||
discard
|
||||
of ConsensusType.POA:
|
||||
dh.com.poa.prepareForSeal(dh.prepHeader, header)
|
||||
of ConsensusType.POS:
|
||||
dh.com.pos.prepareForSeal(header)
|
||||
|
||||
proc resetTxEnv(dh: TxChainRef; parent: BlockHeader; fee: Option[UInt256])
|
||||
{.gcsafe,raises: [Defect,CatchableError].} =
|
||||
@ -83,18 +107,18 @@ proc resetTxEnv(dh: TxChainRef; parent: BlockHeader; fee: Option[UInt256])
|
||||
# do hardfork transition before
|
||||
# BaseVMState querying any hardfork/consensus from CommonRef
|
||||
dh.com.hardForkTransition(parent.blockHash, parent.blockNumber+1)
|
||||
dh.prepareHeader(parent)
|
||||
|
||||
let timestamp = getTime().utc.toTime
|
||||
# we don't consider PoS difficulty here
|
||||
# because that is handled in vmState
|
||||
dh.txEnv.vmState = BaseVMState.new(
|
||||
parent = parent,
|
||||
timestamp = timestamp,
|
||||
timestamp = dh.prepHeader.timestamp,
|
||||
gasLimit = (if dh.maxMode: dh.limits.maxLimit else: dh.limits.trgLimit),
|
||||
fee = fee,
|
||||
prevRandao= dh.prevRandao,
|
||||
difficulty= dh.calcDifficulty(timestamp, parent),
|
||||
miner = dh.miner,
|
||||
prevRandao= dh.prepHeader.prevRandao,
|
||||
difficulty= dh.prepHeader.difficulty,
|
||||
miner = dh.prepHeader.coinbase,
|
||||
com = dh.com)
|
||||
|
||||
dh.txEnv.txRoot = EMPTY_ROOT_HASH
|
||||
@ -132,12 +156,6 @@ proc new*(T: type TxChainRef; com: CommonRef; miner: EthAddress): T
|
||||
result.lhwm.hwmMax = MAX_THRESHOLD_PER_CENT
|
||||
result.lhwm.gasFloor = DEFAULT_GAS_LIMIT
|
||||
result.lhwm.gasCeil = DEFAULT_GAS_LIMIT
|
||||
result.calcDifficulty = proc(timeStamp: EthTime, parent: BlockHeader):
|
||||
DifficultyInt {.gcsafe, raises:[].} =
|
||||
try:
|
||||
com.calcDifficulty(timestamp, parent)
|
||||
except:
|
||||
0.u256
|
||||
result.update(com.db.getCanonicalHead)
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
@ -168,24 +186,25 @@ proc getHeader*(dh: TxChainRef): BlockHeader
|
||||
let gasUsed = if dh.txEnv.receipts.len == 0: 0.GasInt
|
||||
else: dh.txEnv.receipts[^1].cumulativeGasUsed
|
||||
|
||||
BlockHeader(
|
||||
result = BlockHeader(
|
||||
parentHash: dh.txEnv.vmState.parent.blockHash,
|
||||
ommersHash: EMPTY_UNCLE_HASH,
|
||||
coinbase: dh.miner,
|
||||
coinbase: dh.prepHeader.coinbase,
|
||||
stateRoot: dh.txEnv.stateRoot,
|
||||
txRoot: dh.txEnv.txRoot,
|
||||
receiptRoot: dh.txEnv.receipts.calcReceiptRoot,
|
||||
bloom: dh.txEnv.receipts.createBloom,
|
||||
difficulty: dh.txEnv.vmState.difficulty,
|
||||
difficulty: dh.prepHeader.difficulty,
|
||||
blockNumber: dh.txEnv.vmState.blockNumber,
|
||||
gasLimit: dh.txEnv.vmState.gasLimit,
|
||||
gasUsed: gasUsed,
|
||||
timestamp: dh.txEnv.vmState.timestamp,
|
||||
timestamp: dh.prepHeader.timestamp,
|
||||
# extraData: Blob # signing data
|
||||
# mixDigest: Hash256 # mining hash for given difficulty
|
||||
# nonce: BlockNonce # mining free vaiable
|
||||
fee: dh.txEnv.vmState.fee)
|
||||
|
||||
dh.prepareForSeal(result)
|
||||
|
||||
proc clearAccounts*(dh: TxChainRef)
|
||||
{.gcsafe,raises: [Defect,CatchableError].} =
|
||||
@ -216,9 +235,12 @@ proc maxMode*(dh: TxChainRef): bool =
|
||||
## Getter
|
||||
dh.maxMode
|
||||
|
||||
proc miner*(dh: TxChainRef): EthAddress =
|
||||
## Getter, shortcut for `dh.vmState.minerAddress`
|
||||
dh.miner
|
||||
proc feeRecipient*(dh: TxChainRef): EthAddress =
|
||||
## Getter
|
||||
if dh.com.consensus == ConsensusType.POS:
|
||||
dh.com.pos.feeRecipient
|
||||
else:
|
||||
dh.miner
|
||||
|
||||
proc baseFee*(dh: TxChainRef): GasPrice =
|
||||
## Getter, baseFee for the next bock header. This value is auto-generated
|
||||
@ -323,14 +345,6 @@ proc `txRoot=`*(dh: TxChainRef; val: Hash256) =
|
||||
## Setter
|
||||
dh.txEnv.txRoot = val
|
||||
|
||||
proc `prevRandao=`*(dh: TxChainRef; val: Hash256) =
|
||||
## Setter
|
||||
dh.prevRandao = val
|
||||
|
||||
proc `calcDifficulty=`*(dh: TxChainRef; val: DifficultyCalculator) =
|
||||
## Setter
|
||||
dh.calcDifficulty = val
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# End
|
||||
# ------------------------------------------------------------------------------
|
||||
|
@ -109,7 +109,7 @@ proc runTxCommit(pst: TxPackerStateRef; item: TxItemRef; gasBurned: GasInt)
|
||||
# are vetted for profitability before entering that bucket.
|
||||
assert 0 <= gasTip
|
||||
let reward = gasBurned.u256 * gasTip.uint64.u256
|
||||
vmState.stateDB.addBalance(xp.chain.miner, reward)
|
||||
vmState.stateDB.addBalance(xp.chain.feeRecipient, reward)
|
||||
|
||||
# Update account database
|
||||
vmState.mutateStateDB:
|
||||
@ -117,7 +117,7 @@ proc runTxCommit(pst: TxPackerStateRef; item: TxItemRef; gasBurned: GasInt)
|
||||
db.deleteAccount deletedAccount
|
||||
|
||||
if FkSpurious <= xp.chain.nextFork:
|
||||
vmState.touchedAccounts.incl(xp.chain.miner)
|
||||
vmState.touchedAccounts.incl(xp.chain.feeRecipient)
|
||||
# EIP158/161 state clearing
|
||||
for account in vmState.touchedAccounts:
|
||||
if db.accountExists(account) and db.isEmptyAccount(account):
|
||||
@ -169,7 +169,7 @@ proc vmExecInit(xp: TxPoolRef): TxPackerStateRef
|
||||
TxPackerStateRef( # return value
|
||||
xp: xp,
|
||||
tr: newMemoryDB().initHexaryTrie,
|
||||
balance: xp.chain.vmState.readOnlyStateDB.getBalance(xp.chain.miner))
|
||||
balance: xp.chain.vmState.readOnlyStateDB.getBalance(xp.chain.feeRecipient))
|
||||
|
||||
|
||||
proc vmExecGrabItem(pst: TxPackerStateRef; item: TxItemRef): Result[bool,void]
|
||||
@ -218,7 +218,7 @@ proc vmExecCommit(pst: TxPackerStateRef)
|
||||
let
|
||||
number = xp.chain.head.blockNumber + 1
|
||||
uncles: seq[BlockHeader] = @[] # no uncles yet
|
||||
vmState.calculateReward(xp.chain.miner, number + 1, uncles)
|
||||
vmState.calculateReward(xp.chain.feeRecipient, number + 1, uncles)
|
||||
|
||||
# Reward beneficiary
|
||||
vmState.mutateStateDB:
|
||||
@ -236,7 +236,7 @@ proc vmExecCommit(pst: TxPackerStateRef)
|
||||
xp.chain.stateRoot = vmState.stateDB.rootHash
|
||||
|
||||
proc balanceDelta: UInt256 =
|
||||
let postBalance = vmState.readOnlyStateDB.getBalance(xp.chain.miner)
|
||||
let postBalance = vmState.readOnlyStateDB.getBalance(xp.chain.feeRecipient)
|
||||
if pst.balance < postBalance:
|
||||
return postBalance - pst.balance
|
||||
|
||||
|
@ -9,8 +9,8 @@
|
||||
# according to those terms.
|
||||
|
||||
import
|
||||
std/[options, times, json, strutils],
|
||||
eth/common,
|
||||
std/[options, times, json, strutils, sets],
|
||||
../common/common,
|
||||
stew/byteutils,
|
||||
../vm_state,
|
||||
../vm_types,
|
||||
@ -84,3 +84,23 @@ proc debugAccounts*(vmState: BaseVMState): string =
|
||||
}
|
||||
|
||||
res.pretty
|
||||
|
||||
proc debug*(vms: BaseVMState): string =
|
||||
result.add "com.consensus :" & $vms.com.consensus & "\n"
|
||||
result.add "parent :" & $vms.parent.blockHash & "\n"
|
||||
result.add "timestamp :" & $vms.timestamp.toUnix & "\n"
|
||||
result.add "gasLimit :" & $vms.gasLimit & "\n"
|
||||
result.add "fee :" & $vms.fee & "\n"
|
||||
result.add "prevRandao :" & $vms.prevRandao & "\n"
|
||||
result.add "blockDifficulty :" & $vms.blockDifficulty & "\n"
|
||||
result.add "flags :" & $vms.flags & "\n"
|
||||
result.add "logEntries.len :" & $vms.logEntries.len & "\n"
|
||||
result.add "receipts.len :" & $vms.receipts.len & "\n"
|
||||
result.add "stateDB.root :" & $vms.stateDB.rootHash & "\n"
|
||||
result.add "cumulativeGasUsed:" & $vms.cumulativeGasUsed & "\n"
|
||||
result.add "touchedAccs.len :" & $vms.touchedAccounts.len & "\n"
|
||||
result.add "selfDestructs.len:" & $vms.selfDestructs.len & "\n"
|
||||
result.add "txOrigin :" & $vms.txOrigin & "\n"
|
||||
result.add "txGasPrice :" & $vms.txGasPrice & "\n"
|
||||
result.add "fork :" & $vms.fork & "\n"
|
||||
result.add "minerAddress :" & $vms.minerAddress & "\n"
|
||||
|
@ -14,6 +14,7 @@ import
|
||||
../nimbus/core/[chain, clique, executor],
|
||||
../nimbus/core/[tx_pool, tx_pool/tx_item],
|
||||
../nimbus/common/common,
|
||||
../nimbus/core/clique/clique_sealer,
|
||||
./test_txpool/[helpers, setup, sign_helper],
|
||||
./test_txpool2,
|
||||
chronos,
|
||||
@ -217,7 +218,6 @@ proc runTxLoader(noisy = true; capture = loadSpecs) =
|
||||
check 0.GasPrice <= minGasPrice
|
||||
check minGasPrice <= maxGasPrice
|
||||
|
||||
|
||||
proc runTxPoolTests(noisy = true) =
|
||||
let elapNoisy = false
|
||||
|
||||
@ -781,6 +781,10 @@ proc runTxPackerTests(noisy = true) =
|
||||
# if true: return
|
||||
test "Store generated block in block chain database":
|
||||
|
||||
# authorized signer is needed to produce correct
|
||||
# POA difficulty and blockheader fields
|
||||
bcCom.poa.authorize(testAddress, signerFunc)
|
||||
|
||||
noisy.say "***", "locality",
|
||||
" locals=", xq.accountRanks.local.len,
|
||||
" remotes=", xq.accountRanks.remote.len
|
||||
@ -830,17 +834,22 @@ proc runTxPackerTests(noisy = true) =
|
||||
# much less than permitted so this block will be accepted.
|
||||
check 0 < overlap
|
||||
|
||||
#setTraceLevel()
|
||||
setTraceLevel()
|
||||
|
||||
# Test low-level function for adding the new block to the database
|
||||
xq.chain.maxMode = (packItemsMaxGasLimit in xq.flags)
|
||||
xq.chain.clearAccounts
|
||||
check xq.chain.vmState.processBlock(poa, hdr, bdy).isOK
|
||||
|
||||
#debugEcho "VMSTATE 1: ", debugAccounts(xq.chain.vmState)
|
||||
|
||||
setErrorLevel()
|
||||
|
||||
# Re-allocate using VM environment from `persistBlocks()`
|
||||
check BaseVMState.new(hdr, bcCom).processBlock(poa, hdr, bdy).isOK
|
||||
let vmstate2 = BaseVMState.new(hdr, bcCom)
|
||||
check vmstate2.processBlock(poa, hdr, bdy).isOK
|
||||
|
||||
#debugEcho "VMSTATE 2: ", debugAccounts(vmstate2)
|
||||
|
||||
# This should not have changed
|
||||
check canonicalHead == xq.chain.com.db.getCanonicalHead
|
||||
@ -871,9 +880,9 @@ proc txPoolMain*(noisy = defined(debug)) =
|
||||
noisy.runTxLoader
|
||||
noisy.runTxPoolTests
|
||||
noisy.runTxPackerTests
|
||||
#runTxPoolCliqueTest()
|
||||
#runTxPoolPosTest()
|
||||
#noisy.runTxHeadDelta
|
||||
runTxPoolCliqueTest()
|
||||
runTxPoolPosTest()
|
||||
noisy.runTxHeadDelta
|
||||
|
||||
when isMainModule:
|
||||
const
|
||||
@ -889,9 +898,9 @@ when isMainModule:
|
||||
noisy.runTxPoolTests
|
||||
noisy.runTxPackerTests
|
||||
|
||||
runTxPoolCliqueTest()
|
||||
runTxPoolPosTest()
|
||||
noisy.runTxHeadDelta
|
||||
#runTxPoolCliqueTest()
|
||||
#runTxPoolPosTest()
|
||||
#noisy.runTxHeadDelta
|
||||
|
||||
#noisy.runTxLoader(dir = ".")
|
||||
#noisy.runTxPoolTests
|
||||
|
@ -12,6 +12,7 @@ import
|
||||
../../nimbus/constants,
|
||||
../../nimbus/utils/ec_recover,
|
||||
../../nimbus/core/tx_pool/tx_item,
|
||||
../../nimbus/core/clique/clique_desc,
|
||||
eth/[common, common/transaction, keys],
|
||||
stew/results,
|
||||
stint
|
||||
@ -89,4 +90,13 @@ proc testKeySign*(header: BlockHeader): BlockHeader =
|
||||
## Sign the header and embed the signature in extra data
|
||||
header.sign(prvTestKey)
|
||||
|
||||
proc signerFunc*(signer: EthAddress, msg: openArray[byte]):
|
||||
Result[RawSignature, cstring] {.gcsafe.} =
|
||||
doAssert(signer == testAddress)
|
||||
let
|
||||
data = keccakHash(msg)
|
||||
rawSign = sign(prvTestKey, SkMessage(data.data)).toRaw
|
||||
|
||||
ok(rawSign)
|
||||
|
||||
# End
|
||||
|
@ -7,10 +7,15 @@ import
|
||||
../nimbus/core/clique/[clique_sealer, clique_desc],
|
||||
../nimbus/[config, transaction, constants],
|
||||
../nimbus/core/tx_pool,
|
||||
../nimbus/core/casper,
|
||||
../nimbus/core/executor,
|
||||
../nimbus/common/common,
|
||||
../nimbus/[vm_state, vm_types],
|
||||
./test_txpool/helpers,
|
||||
./macro_assembler
|
||||
|
||||
import ../nimbus/utils/debug
|
||||
|
||||
const
|
||||
baseDir = [".", "tests"]
|
||||
repoDir = [".", "customgenesis"]
|
||||
@ -115,11 +120,11 @@ proc runTxPoolCliqueTest*() =
|
||||
tx = env.makeTx(recipient, amount)
|
||||
xp = env.xp
|
||||
conf = env.conf
|
||||
com = env.com
|
||||
chain = env.chain
|
||||
clique = env.chain.clique
|
||||
body: BlockBody
|
||||
blk: EthBlock
|
||||
com = env.chain.com
|
||||
|
||||
let signerKey = privKey(signerKeyHex)
|
||||
proc signerFunc(signer: EthAddress, msg: openArray[byte]):
|
||||
@ -130,6 +135,7 @@ proc runTxPoolCliqueTest*() =
|
||||
rawSign = sign(signerKey, SkMessage(data.data)).toRaw
|
||||
|
||||
ok(rawSign)
|
||||
clique.authorize(conf.engineSigner, signerFunc)
|
||||
|
||||
suite "Test TxPool with Clique sealer":
|
||||
test "TxPool addLocal":
|
||||
@ -143,31 +149,27 @@ proc runTxPoolCliqueTest*() =
|
||||
check xp.nItems.total == 1
|
||||
|
||||
test "TxPool ethBlock":
|
||||
xp.prevRandao = EMPTY_UNCLE_HASH
|
||||
blk = xp.ethBlock()
|
||||
|
||||
blk.header.prevRandao = EMPTY_UNCLE_HASH
|
||||
body = BlockBody(
|
||||
transactions: blk.txs,
|
||||
uncles: blk.uncles
|
||||
)
|
||||
check blk.txs.len == 1
|
||||
|
||||
test "Clique prepare and seal":
|
||||
clique.authorize(conf.engineSigner, signerFunc)
|
||||
let parent = com.db.getBlockHeader(blk.header.parentHash)
|
||||
let ry = chain.clique.prepare(parent, blk.header)
|
||||
check ry.isOk
|
||||
if ry.isErr:
|
||||
debugEcho ry.error
|
||||
return
|
||||
|
||||
test "Clique seal":
|
||||
let rx = clique.seal(blk)
|
||||
check rx.isOk
|
||||
if rx.isErr:
|
||||
debugEcho rx.error
|
||||
return
|
||||
|
||||
test "Store generated block in block chain database":
|
||||
xp.chain.clearAccounts
|
||||
check xp.chain.vmState.processBlock(com.poa, blk.header, body).isOK
|
||||
|
||||
let vmstate2 = BaseVMState.new(blk.header, com)
|
||||
check vmstate2.processBlock(com.poa, blk.header, body).isOK
|
||||
|
||||
test "Clique persistBlocks":
|
||||
let rr = chain.persistBlocks([blk.header], [body])
|
||||
check rr == ValidationResult.OK
|
||||
@ -196,22 +198,20 @@ proc runTxPoolPosTest*() =
|
||||
check xp.nItems.total == 1
|
||||
|
||||
test "TxPool ethBlock":
|
||||
xp.prevRandao = prevRandao
|
||||
xp.feeRecipient = feeRecipient
|
||||
com.pos.prevRandao = prevRandao
|
||||
com.pos.feeRecipient = feeRecipient
|
||||
com.pos.timestamp = getTime()
|
||||
|
||||
blk = xp.ethBlock()
|
||||
|
||||
check com.isBlockAfterTtd(blk.header)
|
||||
|
||||
blk.header.difficulty = DifficultyInt.zero
|
||||
blk.header.prevRandao = prevRandao
|
||||
blk.header.nonce = default(BlockNonce)
|
||||
blk.header.extraData = @[]
|
||||
|
||||
body = BlockBody(
|
||||
transactions: blk.txs,
|
||||
uncles: blk.uncles
|
||||
)
|
||||
check blk.txs.len == 1
|
||||
|
||||
test "PoS persistBlocks":
|
||||
let rr = chain.persistBlocks([blk.header], [body])
|
||||
check rr == ValidationResult.OK
|
||||
@ -262,17 +262,14 @@ proc runTxHeadDelta*(noisy = true) =
|
||||
# pending/staged/packed : total/disposed
|
||||
&" stats={xp.nItems.pp}"
|
||||
|
||||
xp.prevRandao = prevRandao
|
||||
timestamp = timestamp + 1.seconds
|
||||
com.pos.prevRandao = prevRandao
|
||||
com.pos.timestamp = timestamp
|
||||
com.pos.feeRecipient = feeRecipient
|
||||
|
||||
var blk = xp.ethBlock()
|
||||
check com.isBlockAfterTtd(blk.header)
|
||||
|
||||
timestamp = timestamp + 1.seconds
|
||||
blk.header.difficulty = DifficultyInt.zero
|
||||
blk.header.prevRandao = prevRandao
|
||||
blk.header.nonce = default(BlockNonce)
|
||||
blk.header.extraData = @[]
|
||||
blk.header.timestamp = timestamp
|
||||
|
||||
let body = BlockBody(
|
||||
transactions: blk.txs,
|
||||
uncles: blk.uncles)
|
||||
|
Loading…
x
Reference in New Issue
Block a user