diff --git a/nimbus/common/common.nim b/nimbus/common/common.nim index 54034ebb3..fd473daa6 100644 --- a/nimbus/common/common.nim +++ b/nimbus/common/common.nim @@ -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 diff --git a/nimbus/core/casper.nim b/nimbus/core/casper.nim new file mode 100644 index 000000000..e9e12128f --- /dev/null +++ b/nimbus/core/casper.nim @@ -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 diff --git a/nimbus/core/clique/clique_sealer.nim b/nimbus/core/clique/clique_sealer.nim index bb6c44d4d..0c14cfadf 100644 --- a/nimbus/core/clique/clique_sealer.nim +++ b/nimbus/core/clique/clique_sealer.nim @@ -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() diff --git a/nimbus/core/sealer.nim b/nimbus/core/sealer.nim index 436064bea..8bf73f014 100644 --- a/nimbus/core/sealer.nim +++ b/nimbus/core/sealer.nim @@ -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) diff --git a/nimbus/core/tx_pool.nim b/nimbus/core/tx_pool.nim index 634df7cc1..edac2ef71 100644 --- a/nimbus/core/tx_pool.nim +++ b/nimbus/core/tx_pool.nim @@ -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 # ------------------------------------------------------------------------------ diff --git a/nimbus/core/tx_pool/tx_chain.nim b/nimbus/core/tx_pool/tx_chain.nim index 5a71edb3b..547ad4405 100644 --- a/nimbus/core/tx_pool/tx_chain.nim +++ b/nimbus/core/tx_pool/tx_chain.nim @@ -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 # ------------------------------------------------------------------------------ diff --git a/nimbus/core/tx_pool/tx_tasks/tx_packer.nim b/nimbus/core/tx_pool/tx_tasks/tx_packer.nim index 70afe0131..97690fb58 100644 --- a/nimbus/core/tx_pool/tx_tasks/tx_packer.nim +++ b/nimbus/core/tx_pool/tx_tasks/tx_packer.nim @@ -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 diff --git a/nimbus/utils/debug.nim b/nimbus/utils/debug.nim index 4f55ef10b..1678a0407 100644 --- a/nimbus/utils/debug.nim +++ b/nimbus/utils/debug.nim @@ -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" diff --git a/tests/test_txpool.nim b/tests/test_txpool.nim index c3c54b27b..0c58bbdf1 100644 --- a/tests/test_txpool.nim +++ b/tests/test_txpool.nim @@ -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 diff --git a/tests/test_txpool/sign_helper.nim b/tests/test_txpool/sign_helper.nim index adf2f0caa..203659b19 100644 --- a/tests/test_txpool/sign_helper.nim +++ b/tests/test_txpool/sign_helper.nim @@ -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 diff --git a/tests/test_txpool2.nim b/tests/test_txpool2.nim index b7d442acf..5295483a2 100644 --- a/tests/test_txpool2.nim +++ b/tests/test_txpool2.nim @@ -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)