diff --git a/tests/test_txpool2.nim b/tests/test_txpool2.nim index 525a2a9615..379b071f0b 100644 --- a/tests/test_txpool2.nim +++ b/tests/test_txpool2.nim @@ -122,12 +122,15 @@ proc initEnv(envFork: HardFork): TestEnv = if envFork >= Cancun: conf.networkParams.config.cancunTime = Opt.some(0.EthTime) + if envFork >= Prague: + conf.networkParams.config.pragueTime = Opt.some(0.EthTime) + let com = CommonRef.new(newCoreDbRef DefaultDbMemory, nil, conf.networkId, conf.networkParams) chain = newForkedChain(com, com.genesisHeader) - result = TestEnv( + TestEnv( conf: conf, com: com, chain: chain, @@ -142,267 +145,226 @@ const slot = 0x11.u256 prevRandao = Bytes32 EMPTY_UNCLE_HASH # it can be any valid hash -proc runTxPoolPosTest() = - var env = initEnv(MergeFork) - - var - tx = env.makeTx(recipient, amount) - xp = env.xp - com = env.com - chain = env.chain - body: BlockBody - blk: EthBlock - - suite "Test TxPool with PoS block": - test "TxPool add": - xp.add(PooledTransaction(tx: tx)) - - test "TxPool jobCommit": - check xp.nItems.total == 1 - - test "TxPool ethBlock": +template runTxPoolPosTest() = + test "Test TxPool with PoS block": + var + env = initEnv(MergeFork) + tx = env.makeTx(recipient, amount) + xp = env.xp + com = env.com + chain = env.chain + + xp.add(PooledTransaction(tx: tx)) + check xp.nItems.total == 1 + + # generate block + com.pos.prevRandao = prevRandao + com.pos.feeRecipient = feeRecipient + com.pos.timestamp = EthTime.now() + + let bundle = xp.assembleBlock().valueOr: + debugEcho error + check false + return + + let blk = bundle.blk + check blk.transactions.len == 1 + + # import block + chain.importBlock(blk).isOkOr: + debugEcho error + check false + return + + let + sdb = LedgerRef.init(com.db) + val = sdb.getStorage(recipient, slot) + randao = Bytes32(val.toBytesBE) + bal = sdb.getBalance(feeRecipient) + + check randao == prevRandao + check blk.header.coinbase == feeRecipient + check not bal.isZero + +template runTxPoolBlobhashTest() = + test "Test TxPool with blobhash block": + var + env = initEnv(Cancun) + tx1 = env.createPooledTransactionWithBlob(recipient, amount) + tx2 = env.createPooledTransactionWithBlob(recipient, amount) + xp = env.xp + com = env.com + chain = env.chain + + xp.add(tx1) + xp.add(tx2) + check xp.nItems.total == 2 + + # generate block + com.pos.prevRandao = prevRandao + com.pos.feeRecipient = feeRecipient + com.pos.timestamp = EthTime.now() + + let bundle = xp.assembleBlock().valueOr: + debugEcho error + check false + return + + let + blk = bundle.blk + check blk.txs.len == 2 + + let + gasUsed1 = xp.vmState.receipts[0].cumulativeGasUsed + gasUsed2 = xp.vmState.receipts[1].cumulativeGasUsed - gasUsed1 + totalBlobGasUsed = tx1.tx.getTotalBlobGas + tx2.tx.getTotalBlobGas + blockValue = + gasUsed1.u256 * tx1.tx.effectiveGasTip(blk.header.baseFeePerGas).u256 + + gasUsed2.u256 * tx2.tx.effectiveGasTip(blk.header.baseFeePerGas).u256 + + check blockValue == bundle.blockValue + check totalBlobGasUsed == blk.header.blobGasUsed.get() + + chain.importBlock(blk).isOkOr: + debugEcho error + check false + return + + let + sdb = LedgerRef.init(com.db) + val = sdb.getStorage(recipient, slot) + randao = Bytes32(val.toBytesBE) + bal = sdb.getBalance(feeRecipient) + + check randao == prevRandao + check blk.header.coinbase == feeRecipient + check not bal.isZero + + let + tx3 = env.makeTx(recipient, amount) + tx4 = env.signTxWithNonce(tx3, AccountNonce(env.nonce - 2)) + + check xp.smartHead(blk.header) + xp.add(PooledTransaction(tx: tx4)) + check inPoolAndOk(xp, rlpHash(tx4)) == false + +template runTxHeadDelta() = + ## see github.com/status-im/nimbus-eth1/issues/1031 + test "TxPool: Synthesising blocks (covers issue #1031)": + var + env = initEnv(MergeFork) + xp = env.xp + com = env.com + chain = env.chain + head = chain.latestHeader + timestamp = head.timestamp + + const + txPerblock = 20 + numBlocks = 10 + + for n in 0 ..< numBlocks: + for tn in 0 ..< txPerblock: + let tx = env.makeTx(recipient, amount) + xp.add(PooledTransaction(tx: tx)) + + timestamp = timestamp + 1 com.pos.prevRandao = prevRandao + com.pos.timestamp = timestamp com.pos.feeRecipient = feeRecipient - com.pos.timestamp = EthTime.now() - let r = xp.assembleBlock() - if r.isErr: - debugEcho r.error + let bundle = xp.assembleBlock().valueOr: + debugEcho error check false return - blk = r.get.blk - body = BlockBody(transactions: blk.txs, uncles: blk.uncles) - check blk.txs.len == 1 - - test "PoS persistBlocks": - let rr = chain.importBlock(EthBlock.init(blk.header, body)) - check rr.isOk() - - test "validate TxPool prevRandao setter": - var sdb = LedgerRef.init(com.db) - let val = sdb.getStorage(recipient, slot) - let randao = Bytes32(val.toBytesBE) - check randao == prevRandao - - test "feeRecipient rewarded": - check blk.header.coinbase == feeRecipient - var sdb = LedgerRef.init(com.db) - let bal = sdb.getBalance(feeRecipient) - check not bal.isZero - -proc runTxPoolBlobhashTest() = - var env = initEnv(Cancun) - - var - tx1 = env.createPooledTransactionWithBlob(recipient, amount) - tx2 = env.createPooledTransactionWithBlob(recipient, amount) - xp = env.xp - com = env.com - chain = env.chain - body: BlockBody - blk: EthBlock - - suite "Test TxPool with blobhash block": - test "TxPool jobCommit": - xp.add(tx1) - xp.add(tx2) - check xp.nItems.total == 2 - - test "TxPool ethBlock": - com.pos.prevRandao = prevRandao - com.pos.feeRecipient = feeRecipient - com.pos.timestamp = EthTime.now() - - let r = xp.assembleBlock() - if r.isErr: - debugEcho r.error + let blk = bundle.blk + # Commit to block chain + chain.importBlock(blk).isOkOr: + debugEcho error check false return - let bundle = r.get - blk = bundle.blk - body = BlockBody( - transactions: blk.txs, - uncles: blk.uncles, - withdrawals: Opt.some(newSeq[Withdrawal]()), - ) - check blk.txs.len == 2 - - let - gasUsed1 = xp.vmState.receipts[0].cumulativeGasUsed - gasUsed2 = xp.vmState.receipts[1].cumulativeGasUsed - gasUsed1 - totalBlobGasUsed = tx1.tx.getTotalBlobGas + tx2.tx.getTotalBlobGas - blockValue = - gasUsed1.u256 * tx1.tx.effectiveGasTip(blk.header.baseFeePerGas).u256 + - gasUsed2.u256 * tx2.tx.effectiveGasTip(blk.header.baseFeePerGas).u256 - - check blockValue == bundle.blockValue - check totalBlobGasUsed == blk.header.blobGasUsed.get() - - test "Blobhash persistBlocks": - let rr = chain.importBlock(EthBlock.init(blk.header, body)) - check rr.isOk() - - test "validate TxPool prevRandao setter": - var sdb = LedgerRef.init(com.db) - let val = sdb.getStorage(recipient, slot) - let randao = Bytes32(val.toBytesBE) - check randao == prevRandao - - test "feeRecipient rewarded": - check blk.header.coinbase == feeRecipient - var sdb = LedgerRef.init(com.db) - let bal = sdb.getBalance(feeRecipient) - check not bal.isZero - - test "add tx with nonce too low": - let - tx3 = env.makeTx(recipient, amount) - tx4 = env.signTxWithNonce(tx3, AccountNonce(env.nonce - 2)) - xp = env.xp - + # Synchronise TxPool against new chain head, register txs differences. + # In this particular case, these differences will simply flush the + # packer bucket. check xp.smartHead(blk.header) - xp.add(PooledTransaction(tx: tx4)) - - check inPoolAndOk(xp, rlpHash(tx4)) == false - -proc runTxHeadDelta(noisy = true) = - ## see github.com/status-im/nimbus-eth1/issues/1031 - - suite "TxPool: Synthesising blocks (covers issue #1031)": - test "Packing and adding multiple blocks to chain": - var - env = initEnv(MergeFork) - xp = env.xp - com = env.com - chain = env.chain - head = chain.latestHeader - timestamp = head.timestamp - - const - txPerblock = 20 - numBlocks = 10 - - # setTraceLevel() - - block: - for n in 0 ..< numBlocks: - for tn in 0 ..< txPerblock: - let tx = env.makeTx(recipient, amount) - xp.add(PooledTransaction(tx: tx)) - - noisy.say "***", - "txDB", - &" n={n}", - # pending/staged/packed : total/disposed - &" stats={xp.nItems.pp}" - - timestamp = timestamp + 1 - com.pos.prevRandao = prevRandao - com.pos.timestamp = timestamp - com.pos.feeRecipient = feeRecipient - - let r = xp.assembleBlock() - if r.isErr: - debugEcho r.error - check false - return - - let blk = r.get.blk - let body = BlockBody(transactions: blk.txs, uncles: blk.uncles) - - # Commit to block chain - check chain.importBlock(EthBlock.init(blk.header, body)).isOk - - # Synchronise TxPool against new chain head, register txs differences. - # In this particular case, these differences will simply flush the - # packer bucket. - check xp.smartHead(blk.header) - - # Move TxPool chain head to new chain head and apply delta jobs - check xp.nItems.staged == 0 - check xp.nItems.packed == 0 - - setErrorLevel() # in case we set trace level - - check com.syncCurrent == 10.BlockNumber - head = chain.headerByNumber(com.syncCurrent).expect("block header exists") - let - sdb = LedgerRef.init(com.db) - expected = u256(txPerblock * numBlocks) * amount - balance = sdb.getBalance(recipient) - check balance == expected - -proc runGetBlockBodyTest() = - var - env = initEnv(Cancun) - blockTime = EthTime.now() - parentHeader: Header - currentHeader: Header - - suite "Test get parent transactions after persistBlock": - test "TxPool create first block": - let - tx1 = env.makeTx(recipient, 1.u256) - tx2 = env.makeTx(recipient, 2.u256) - - env.xp.add(PooledTransaction(tx: tx1)) - env.xp.add(PooledTransaction(tx: tx2)) - - env.com.pos.prevRandao = prevRandao - env.com.pos.feeRecipient = feeRecipient - env.com.pos.timestamp = blockTime - - let r = env.xp.assembleBlock() - if r.isErr: - check false - return - - let blk = r.get.blk - check env.chain.importBlock(blk).isOk - parentHeader = blk.header - check env.xp.smartHead(parentHeader) - check blk.transactions.len == 2 - - test "TxPool create second block": - let - tx1 = env.makeTx(recipient, 3.u256) - tx2 = env.makeTx(recipient, 4.u256) - tx3 = env.makeTx(recipient, 5.u256) - - env.xp.add(PooledTransaction(tx: tx1)) - env.xp.add(PooledTransaction(tx: tx2)) - env.xp.add(PooledTransaction(tx: tx3)) - env.com.pos.prevRandao = prevRandao - env.com.pos.feeRecipient = feeRecipient - env.com.pos.timestamp = blockTime + 1 - - let r = env.xp.assembleBlock() - if r.isErr: - check false - return - - let blk = r.get.blk - check env.chain.importBlock(blk).isOk - currentHeader = blk.header - check env.xp.smartHead(currentHeader) - check blk.transactions.len == 3 - let currHash = currentHeader.blockHash - check env.chain.forkChoice(currHash, currHash).isOk + # Move TxPool chain head to new chain head and apply delta jobs + check xp.nItems.staged == 0 + check xp.nItems.packed == 0 + + check com.syncCurrent == 10.BlockNumber + head = chain.headerByNumber(com.syncCurrent).expect("block header exists") + let + sdb = LedgerRef.init(com.db) + expected = u256(txPerblock * numBlocks) * amount + balance = sdb.getBalance(recipient) + check balance == expected + +template runGetBlockBodyTest() = + test "Test get parent transactions after persistBlock": + var + env = initEnv(Cancun) + blockTime = EthTime.now() + parentHeader: Header + currentHeader: Header + + let + tx1 = env.makeTx(recipient, 1.u256) + tx2 = env.makeTx(recipient, 2.u256) + + env.xp.add(PooledTransaction(tx: tx1)) + env.xp.add(PooledTransaction(tx: tx2)) + + env.com.pos.prevRandao = prevRandao + env.com.pos.feeRecipient = feeRecipient + env.com.pos.timestamp = blockTime + + let bundle = env.xp.assembleBlock().valueOr: + debugEcho error + check false + return + + let blk = bundle.blk + check env.chain.importBlock(blk).isOk + parentHeader = blk.header + check env.xp.smartHead(parentHeader) + check blk.transactions.len == 2 + + let + tx3 = env.makeTx(recipient, 3.u256) + tx4 = env.makeTx(recipient, 4.u256) + tx5 = env.makeTx(recipient, 5.u256) + + env.xp.add(PooledTransaction(tx: tx3)) + env.xp.add(PooledTransaction(tx: tx4)) + env.xp.add(PooledTransaction(tx: tx5)) + + env.com.pos.prevRandao = prevRandao + env.com.pos.feeRecipient = feeRecipient + env.com.pos.timestamp = blockTime + 1 + + let bundle2 = env.xp.assembleBlock().valueOr: + debugEcho error + check false + return + + let blk2 = bundle2.blk + check env.chain.importBlock(blk2).isOk + currentHeader = blk2.header + check env.xp.smartHead(currentHeader) + check blk2.transactions.len == 3 + let currHash = currentHeader.blockHash + check env.chain.forkChoice(currHash, currHash).isOk proc txPool2Main*() = - const noisy = defined(debug) - - loadKzgTrustedSetup().expect("Failed to load KZG trusted setup") - - setErrorLevel() # mute logger - - runTxPoolPosTest() - runTxPoolBlobhashTest() - noisy.runTxHeadDelta - runGetBlockBodyTest() + suite "TxPool test suite": + loadKzgTrustedSetup().expect("KZG trusted setup loaded") + runTxPoolPosTest() + runTxPoolBlobhashTest() + runTxHeadDelta() + runGetBlockBodyTest() when isMainModule: txPool2Main()