fix txpool: using consensus rule to prepare header

This commit is contained in:
jangko 2022-12-06 12:55:40 +07:00
parent b81511fcfc
commit a26a9f9ece
No known key found for this signature in database
GPG Key ID: 31702AE10541E6B9
11 changed files with 223 additions and 177 deletions

View File

@ -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
View 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

View File

@ -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()

View File

@ -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)

View File

@ -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
# ------------------------------------------------------------------------------

View File

@ -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
# ------------------------------------------------------------------------------

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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)