Ejemplo n.º 1
0
        public void MinerCreateBlockCoinbaseMempoolTemplateCreationFails()
        {
            using (NodeBuilder builder = NodeBuilder.Create(this))
            {
                CoreNode miner = builder.CreateStratisPowNode(this.network).WithDummyWallet().Start();

                TestHelper.MineBlocks(miner, 1);

                // Create an invalid coinbase transaction to be added to the mempool.
                var duplicateCoinbase = this.network.CreateTransaction();
                duplicateCoinbase.AddInput(new TxIn());
                duplicateCoinbase.AddOutput(new TxOut());
                duplicateCoinbase.Inputs[0].PrevOut   = new OutPoint();
                duplicateCoinbase.Inputs[0].ScriptSig = new Script(OpcodeType.OP_0, OpcodeType.OP_1);
                duplicateCoinbase.Outputs[0].Value    = 0;

                var txMempoolHelper = new TestMemPoolEntryHelper();
                var txMempoolEntry  = txMempoolHelper.Fee(Money.CENT).Time(DateTimeProvider.Default.GetTime()).SpendsCoinbase(false).FromTx(duplicateCoinbase);
                miner.FullNode.NodeService <ITxMempool>().AddUnchecked(duplicateCoinbase.GetHash(), txMempoolEntry);

                var error = Assert.Throws <ConsensusException>(() => TestHelper.MineBlocks(miner, 1));
                Assert.True(error.Message == ConsensusErrors.BadMultipleCoinbase.ToString());

                TestBase.WaitLoop(() => TestHelper.IsNodeSynced(miner));

                Assert.True(miner.FullNode.ConsensusManager().Tip.Height == 1);
            }
        }
Ejemplo n.º 2
0
        public void MinerCreateBlockSigopsLimit1000()
        {
            using (NodeBuilder builder = NodeBuilder.Create(this))
            {
                CoreNode miner = builder.CreateStratisPowNode(this.network);

                builder.StartAll();
                miner.NotInIBD();
                miner.SetDummyMinerSecret(new BitcoinSecret(new Key(), miner.FullNode.Network));
                miner.GenerateStratisWithMiner(1);

                var txMempoolHelper = new TestMemPoolEntryHelper();

                // Block sigops > limit: 1000 CHECKMULTISIG + 1
                var genesis         = this.network.GetGenesis();
                var genesisCoinbase = genesis.Transactions[0];
                var tx = this.network.CreateTransaction();
                tx.AddInput(new TxIn(new OutPoint(genesisCoinbase.GetHash(), 0), new Script(new byte[] { (byte)OpcodeType.OP_0, (byte)OpcodeType.OP_0, (byte)OpcodeType.OP_0, (byte)OpcodeType.OP_NOP, (byte)OpcodeType.OP_CHECKMULTISIG, (byte)OpcodeType.OP_1 })));

                // NOTE: OP_NOP is used to force 20 SigOps for the CHECKMULTISIG
                tx.AddOutput(Money.Coins(50), new Script());
                for (int i = 0; i < 1001; ++i)
                {
                    tx.Outputs[0].Value -= Money.CENT;
                    bool spendsCoinbase = (i == 0); // only first tx spends coinbase
                                                    // If we don't set the # of sig ops in the CTxMemPoolEntry, template creation fails
                    var txMempoolEntry = txMempoolHelper.Fee(Money.CENT).Time(DateTimeProvider.Default.GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx);
                    miner.FullNode.NodeService <ITxMempool>().AddUnchecked(tx.GetHash(), txMempoolEntry);

                    tx = this.network.CreateTransaction(tx.ToBytes());
                    tx.Inputs[0].PrevOut.Hash = tx.GetHash();
                }

                var error = Assert.Throws <ConsensusException>(() => miner.GenerateStratisWithMiner(1));
                Assert.True(error.Message == ConsensusErrors.BadBlockSigOps.Message);

                TestHelper.WaitLoop(() => TestHelper.IsNodeSynced(miner));

                Assert.True(miner.FullNode.ConsensusManager().Tip.Height == 1);
            }
        }
Ejemplo n.º 3
0
        public async Task MinerTestPackageSelectionAsync()
        {
            var context = new TestContext();
            await context.InitializeAsync();

            // Test the ancestor feerate transaction selection.
            TestMemPoolEntryHelper entry = new TestMemPoolEntryHelper();

            // Test that a medium fee transaction will be selected after a higher fee
            // rate package with a low fee rate parent.
            Transaction tx = new Transaction();

            tx.AddInput(new TxIn(new OutPoint(context.txFirst[0].GetHash(), 0), new Script(OpcodeType.OP_1)));
            tx.AddOutput(new TxOut(new Money(5000000000L - 1000), new Script()));

            // This tx has a low fee: 1000 satoshis
            uint256 hashParentTx = tx.GetHash(); // save this txid for later use

            context.mempool.AddUnchecked(hashParentTx, entry.Fee(1000).Time(context.DateTimeProvider.GetTime()).SpendsCoinbase(true).FromTx(tx));

            // This tx has a medium fee: 10000 satoshis
            tx = tx.Clone();
            tx.Inputs[0].PrevOut.Hash = context.txFirst[1].GetHash();
            tx.Outputs[0].Value       = 5000000000L - 10000;
            uint256 hashMediumFeeTx = tx.GetHash();

            context.mempool.AddUnchecked(hashMediumFeeTx, entry.Fee(10000).Time(context.DateTimeProvider.GetTime()).SpendsCoinbase(true).FromTx(tx));

            // This tx has a high fee, but depends on the first transaction
            tx = tx.Clone();
            tx.Inputs[0].PrevOut.Hash = hashParentTx;
            tx.Outputs[0].Value       = 5000000000L - 1000 - 50000; // 50k satoshi fee
            uint256 hashHighFeeTx = tx.GetHash();

            context.mempool.AddUnchecked(hashHighFeeTx, entry.Fee(50000).Time(context.DateTimeProvider.GetTime()).SpendsCoinbase(false).FromTx(tx));

            var pblocktemplate = AssemblerForTest(context).Build(context.chain.Tip, context.scriptPubKey);

            Assert.True(pblocktemplate.Block.Transactions[1].GetHash() == hashParentTx);
            Assert.True(pblocktemplate.Block.Transactions[2].GetHash() == hashHighFeeTx);
            Assert.True(pblocktemplate.Block.Transactions[3].GetHash() == hashMediumFeeTx);

            // Test that a package below the block min tx fee doesn't get included
            tx = tx.Clone();
            tx.Inputs[0].PrevOut.Hash = hashHighFeeTx;
            tx.Outputs[0].Value       = 5000000000L - 1000 - 50000; // 0 fee
            uint256 hashFreeTx = tx.GetHash();

            context.mempool.AddUnchecked(hashFreeTx, entry.Fee(0).FromTx(tx));
            var freeTxSize = tx.GetSerializedSize();

            // Calculate a fee on child transaction that will put the package just
            // below the block min tx fee (assuming 1 child tx of the same size).
            var feeToUse = blockMinFeeRate.GetFee(2 * freeTxSize) - 1;

            tx = tx.Clone();
            tx.Inputs[0].PrevOut.Hash = hashFreeTx;
            tx.Outputs[0].Value       = 5000000000L - 1000 - 50000 - feeToUse;
            uint256 hashLowFeeTx = tx.GetHash();

            context.mempool.AddUnchecked(hashLowFeeTx, entry.Fee(feeToUse).FromTx(tx));
            pblocktemplate = AssemblerForTest(context).Build(context.chain.Tip, context.scriptPubKey);
            // Verify that the free tx and the low fee tx didn't get selected
            for (var i = 0; i < pblocktemplate.Block.Transactions.Count; ++i)
            {
                Assert.True(pblocktemplate.Block.Transactions[i].GetHash() != hashFreeTx);
                Assert.True(pblocktemplate.Block.Transactions[i].GetHash() != hashLowFeeTx);
            }

            // Test that packages above the min relay fee do get included, even if one
            // of the transactions is below the min relay fee
            // Remove the low fee transaction and replace with a higher fee transaction
            context.mempool.RemoveRecursive(tx);
            tx = tx.Clone();
            tx.Outputs[0].Value -= 2; // Now we should be just over the min relay fee
            hashLowFeeTx         = tx.GetHash();
            context.mempool.AddUnchecked(hashLowFeeTx, entry.Fee(feeToUse + 2).FromTx(tx));
            pblocktemplate = AssemblerForTest(context).Build(context.chain.Tip, context.scriptPubKey);
            Assert.True(pblocktemplate.Block.Transactions[4].GetHash() == hashFreeTx);
            Assert.True(pblocktemplate.Block.Transactions[5].GetHash() == hashLowFeeTx);

            // Test that transaction selection properly updates ancestor fee
            // calculations as ancestor transactions get included in a block.
            // Add a 0-fee transaction that has 2 outputs.
            tx = tx.Clone();
            tx.Inputs[0].PrevOut.Hash = context.txFirst[2].GetHash();
            tx.AddOutput(Money.Zero, new Script());
            tx.Outputs[0].Value = 5000000000L - 100000000;
            tx.Outputs[1].Value = 100000000; // 1BTC output
            uint256 hashFreeTx2 = tx.GetHash();

            context.mempool.AddUnchecked(hashFreeTx2, entry.Fee(0).SpendsCoinbase(true).FromTx(tx));

            // This tx can't be mined by itself
            tx = tx.Clone();
            tx.Inputs[0].PrevOut.Hash = hashFreeTx2;
            tx.Outputs.RemoveAt(1);
            feeToUse            = blockMinFeeRate.GetFee(freeTxSize);
            tx.Outputs[0].Value = 5000000000L - 100000000 - feeToUse;
            uint256 hashLowFeeTx2 = tx.GetHash();

            context.mempool.AddUnchecked(hashLowFeeTx2, entry.Fee(feeToUse).SpendsCoinbase(false).FromTx(tx));
            pblocktemplate = AssemblerForTest(context).Build(context.chain.Tip, context.scriptPubKey);

            // Verify that this tx isn't selected.
            for (var i = 0; i < pblocktemplate.Block.Transactions.Count; ++i)
            {
                Assert.True(pblocktemplate.Block.Transactions[i].GetHash() != hashFreeTx2);
                Assert.True(pblocktemplate.Block.Transactions[i].GetHash() != hashLowFeeTx2);
            }

            // This tx will be mineable, and should cause hashLowFeeTx2 to be selected
            // as well.
            tx = tx.Clone();
            tx.Inputs[0].PrevOut.N = 1;
            tx.Outputs[0].Value    = 100000000 - 10000; // 10k satoshi fee
            context.mempool.AddUnchecked(tx.GetHash(), entry.Fee(10000).FromTx(tx));
            pblocktemplate = AssemblerForTest(context).Build(context.chain.Tip, context.scriptPubKey);
            Assert.True(pblocktemplate.Block.Transactions[8].GetHash() == hashLowFeeTx2);
        }
Ejemplo n.º 4
0
        public void BlockPolicyEstimates()
        {
            var       dateTimeSet        = new MemoryPoolTests.DateTimeProviderSet();
            TxMempool mpool              = new TxMempool(new FeeRate(1000), DateTimeProvider.Default, new BlockPolicyEstimator(new FeeRate(1000), NodeSettings.Default()));
            TestMemPoolEntryHelper entry = new TestMemPoolEntryHelper();
            Money        basefee         = new Money(2000);
            Money        deltaFee        = new Money(100);
            List <Money> feeV            = new List <Money>();

            // Populate vectors of increasing fees
            for (int j = 0; j < 10; j++)
            {
                feeV.Add(basefee * (j + 1));
            }

            // Store the hashes of transactions that have been
            // added to the mempool by their associate fee
            // txHashes[j] is populated with transactions either of
            // fee = basefee * (j+1)
            List <uint256>[] txHashes = new List <uint256> [10];
            for (int i = 0; i < txHashes.Length; i++)
            {
                txHashes[i] = new List <uint256>();
            }

            // Create a transaction template
            Script garbage = new Script(Enumerable.Range(0, 128).Select(i => (byte)1).ToArray());

            Transaction txf = new Transaction();

            txf.AddInput(new TxIn(garbage));
            txf.AddOutput(new TxOut(0L, Script.Empty));
            FeeRate baseRate = new FeeRate(basefee, txf.GetVirtualSize());

            // Create a fake block
            List <Transaction> block = new List <Transaction>();
            int blocknum             = 0;
            int answerFound;

            // Loop through 200 blocks
            // At a decay .998 and 4 fee transactions per block
            // This makes the tx count about 1.33 per bucket, above the 1 threshold
            while (blocknum < 200)
            {
                for (int j = 0; j < 10; j++)
                {                                                                        // For each fee
                    for (int k = 0; k < 4; k++)
                    {                                                                    // add 4 fee txs
                        var tx = txf.Clone(false);
                        tx.Inputs[0].PrevOut.N = (uint)(10000 * blocknum + 100 * j + k); // make transaction unique
                        uint256 hash = tx.GetHash();
                        mpool.AddUnchecked(hash, entry.Fee(feeV[j]).Time(dateTimeSet.GetTime()).Priority(0).Height(blocknum).FromTx(tx, mpool));
                        txHashes[j].Add(hash);
                    }
                }
                //Create blocks where higher fee txs are included more often
                for (int h = 0; h <= blocknum % 10; h++)
                {
                    // 10/10 blocks add highest fee transactions
                    // 9/10 blocks add 2nd highest and so on until ...
                    // 1/10 blocks add lowest fee transactions
                    while (txHashes[9 - h].Count > 0)
                    {
                        var ptx = mpool.Get(txHashes[9 - h].Last());
                        if (ptx != null)
                        {
                            block.Add(ptx);
                        }
                        txHashes[9 - h].Remove(txHashes[9 - h].Last());
                    }
                }
                mpool.RemoveForBlock(block, ++blocknum);
                block.Clear();
                if (blocknum == 30)
                {
                    // At this point we should need to combine 5 buckets to get enough data points
                    // So estimateFee(1,2,3) should fail and estimateFee(4) should return somewhere around
                    // 8*baserate.  estimateFee(4) %'s are 100,100,100,100,90 = average 98%
                    Assert.True(mpool.EstimateFee(1) == new FeeRate(0));
                    Assert.True(mpool.EstimateFee(2) == new FeeRate(0));
                    Assert.True(mpool.EstimateFee(3) == new FeeRate(0));
                    Assert.True(mpool.EstimateFee(4).FeePerK < 8 * baseRate.FeePerK + deltaFee);
                    Assert.True(mpool.EstimateFee(4).FeePerK > 8 * baseRate.FeePerK - deltaFee);

                    Assert.True(mpool.EstimateSmartFee(1, out answerFound) == mpool.EstimateFee(4) && answerFound == 4);
                    Assert.True(mpool.EstimateSmartFee(3, out answerFound) == mpool.EstimateFee(4) && answerFound == 4);
                    Assert.True(mpool.EstimateSmartFee(4, out answerFound) == mpool.EstimateFee(4) && answerFound == 4);
                    Assert.True(mpool.EstimateSmartFee(8, out answerFound) == mpool.EstimateFee(8) && answerFound == 8);
                }
            }

            List <Money> origFeeEst = new List <Money>();

            // Highest feerate is 10*baseRate and gets in all blocks,
            // second highest feerate is 9*baseRate and gets in 9/10 blocks = 90%,
            // third highest feerate is 8*base rate, and gets in 8/10 blocks = 80%,
            // so estimateFee(1) would return 10*baseRate but is hardcoded to return failure
            // Second highest feerate has 100% chance of being included by 2 blocks,
            // so estimateFee(2) should return 9*baseRate etc...
            for (int i = 1; i < 10; i++)
            {
                origFeeEst.Add(mpool.EstimateFee(i).FeePerK);
                if (i > 2)
                {                 // Fee estimates should be monotonically decreasing
                    Assert.True(origFeeEst[i - 1] <= origFeeEst[i - 2]);
                }
                int mult = 11 - i;
                if (i > 1)
                {
                    Assert.True(origFeeEst[i - 1] < mult * baseRate.FeePerK + deltaFee);
                    Assert.True(origFeeEst[i - 1] > mult * baseRate.FeePerK - deltaFee);
                }
                else
                {
                    Assert.True(origFeeEst[i - 1] == new FeeRate(0).FeePerK);
                }
            }

            // Mine 50 more blocks with no transactions happening, estimates shouldn't change
            // We haven't decayed the moving average enough so we still have enough data points in every bucket
            while (blocknum < 250)
            {
                mpool.RemoveForBlock(block, ++blocknum);
            }

            Assert.True(mpool.EstimateFee(1) == new FeeRate(0));
            for (int i = 2; i < 10; i++)
            {
                Assert.True(mpool.EstimateFee(i).FeePerK < origFeeEst[i - 1] + deltaFee);
                Assert.True(mpool.EstimateFee(i).FeePerK > origFeeEst[i - 1] - deltaFee);
            }


            // Mine 15 more blocks with lots of transactions happening and not getting mined
            // Estimates should go up
            while (blocknum < 265)
            {
                for (int j = 0; j < 10; j++)
                {                 // For each fee multiple
                    for (int k = 0; k < 4; k++)
                    {             // add 4 fee txs
                        var tx = txf.Clone(false);
                        tx.Inputs[0].PrevOut.N = (uint)(10000 * blocknum + 100 * j + k);
                        uint256 hash = tx.GetHash();
                        mpool.AddUnchecked(hash, entry.Fee(feeV[j]).Time(dateTimeSet.GetTime()).Priority(0).Height(blocknum).FromTx(tx, mpool));
                        txHashes[j].Add(hash);
                    }
                }
                mpool.RemoveForBlock(block, ++blocknum);
            }

            for (int i = 1; i < 10; i++)
            {
                Assert.True(mpool.EstimateFee(i) == new FeeRate(0) || mpool.EstimateFee(i).FeePerK > origFeeEst[i - 1] - deltaFee);
                Assert.True(mpool.EstimateSmartFee(i, out answerFound).FeePerK > origFeeEst[answerFound - 1] - deltaFee);
            }

            // Mine all those transactions
            // Estimates should still not be below original
            for (int j = 0; j < 10; j++)
            {
                while (txHashes[j].Count > 0)
                {
                    var ptx = mpool.Get(txHashes[j].Last());
                    if (ptx != null)
                    {
                        block.Add(ptx);
                    }
                    txHashes[j].Remove(txHashes[j].Last());
                }
            }
            mpool.RemoveForBlock(block, 265);
            block.Clear();
            Assert.True(mpool.EstimateFee(1) == new FeeRate(0));
            for (int i = 2; i < 10; i++)
            {
                Assert.True(mpool.EstimateFee(i).FeePerK > origFeeEst[i - 1] - deltaFee);
            }

            // Mine 200 more blocks where everything is mined every block
            // Estimates should be below original estimates
            while (blocknum < 465)
            {
                for (int j = 0; j < 10; j++)
                {                 // For each fee multiple
                    for (int k = 0; k < 4; k++)
                    {             // add 4 fee txs
                        var tx = txf.Clone(false);
                        tx.Inputs[0].PrevOut.N = (uint)(10000 * blocknum + 100 * j + k);
                        uint256 hash = tx.GetHash();
                        mpool.AddUnchecked(hash, entry.Fee(feeV[j]).Time(dateTimeSet.GetTime()).Priority(0).Height(blocknum).FromTx(tx, mpool));
                        var ptx = mpool.Get(hash);
                        if (ptx != null)
                        {
                            block.Add(ptx);
                        }
                    }
                }
                mpool.RemoveForBlock(block, ++blocknum);
                block.Clear();
            }
            Assert.True(mpool.EstimateFee(1) == new FeeRate(0));
            for (int i = 2; i < 10; i++)
            {
                Assert.True(mpool.EstimateFee(i).FeePerK < origFeeEst[i - 1] - deltaFee);
            }

            // Test that if the mempool is limited, estimateSmartFee won't return a value below the mempool min fee
            // and that estimateSmartPriority returns essentially an infinite value
            mpool.AddUnchecked(txf.GetHash(), entry.Fee(feeV[5]).Time(dateTimeSet.GetTime()).Priority(0).Height(blocknum).FromTx(txf, mpool));
            // evict that transaction which should set a mempool min fee of minRelayTxFee + feeV[5]
            mpool.TrimToSize(1);
            Assert.True(mpool.GetMinFee(1).FeePerK > feeV[5]);
            for (int i = 1; i < 10; i++)
            {
                Assert.True(mpool.EstimateSmartFee(i, out answerFound).FeePerK >= mpool.EstimateFee(i).FeePerK);
                Assert.True(mpool.EstimateSmartFee(i, out answerFound).FeePerK >= mpool.GetMinFee(1).FeePerK);
                Assert.True(mpool.EstimateSmartPriority(i, out answerFound) == BlockPolicyEstimator.INF_PRIORITY);
            }
        }
Ejemplo n.º 5
0
            public TestContext()
            {
                Logs.Configure(new LoggerFactory());

                this.blockinfo = new List <Blockinfo>();
                var lst = blockinfoarr.Cast <long>().ToList();

                for (int i = 0; i < lst.Count; i += 2)
                {
                    blockinfo.Add(new Blockinfo()
                    {
                        extranonce = (int)lst[i], nonce = (uint)lst[i + 1]
                    });
                }

                // Note that by default, these tests run with size accounting enabled.
                network = Network.Main;
                var hex = Encoders.Hex.DecodeData("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f");

                scriptPubKey = new Script(new[] { Op.GetPushOp(hex), OpcodeType.OP_CHECKSIG });
                newBlock     = new BlockTemplate();

                entry = new TestMemPoolEntryHelper();
                chain = new ConcurrentChain(network);
                network.Consensus.Options = new PowConsensusOptions();
                cachedCoinView            = new CachedCoinView(new InMemoryCoinView(chain.Tip.HashBlock));
                consensus = new ConsensusLoop(new PowConsensusValidator(network), chain, cachedCoinView, new LookaheadBlockPuller(chain, new ConnectionManager(network, new NodeConnectionParameters(), new NodeSettings())));
                consensus.Initialize();

                entry.Fee(11);
                entry.Height(11);
                var date1 = new MemoryPoolTests.DateTimeProviderSet();

                date1.time    = DateTimeProvider.Default.GetTime();
                date1.timeutc = DateTimeProvider.Default.GetUtcNow();
                date          = date1;
                mempool       = new TxMempool(new FeeRate(0), new NodeSettings());
                scheduler     = new MempoolScheduler();

                // Simple block creation, nothing special yet:
                newBlock = AssemblerForTest(this).CreateNewBlock(scriptPubKey);
                chain.SetTip(newBlock.Block.Header);
                consensus.AcceptBlock(new ContextInformation(new BlockResult {
                    Block = newBlock.Block
                }, network.Consensus)
                {
                    CheckPow = false, CheckMerkleRoot = false
                });

                // We can't make transactions until we have inputs
                // Therefore, load 100 blocks :)
                this.baseheight = 0;
                List <Block> blocks = new List <Block>();

                txFirst = new List <Transaction>();
                for (int i = 0; i < blockinfo.Count; ++i)
                {
                    var pblock = newBlock.Block.Clone();                     // pointer for convenience
                    pblock.Header.HashPrevBlock = chain.Tip.HashBlock;
                    pblock.Header.Version       = 1;
                    pblock.Header.Time          = Utils.DateTimeToUnixTime(chain.Tip.GetMedianTimePast()) + 1;
                    Transaction txCoinbase = pblock.Transactions[0].Clone();
                    txCoinbase.Inputs.Clear();
                    txCoinbase.Version = 1;
                    txCoinbase.AddInput(new TxIn(new Script(new[] { Op.GetPushOp(blockinfo[i].extranonce), Op.GetPushOp(chain.Height) })));
                    // Ignore the (optional) segwit commitment added by CreateNewBlock (as the hardcoded nonces don't account for this)
                    txCoinbase.AddOutput(new TxOut(Money.Zero, new Script()));
                    pblock.Transactions[0] = txCoinbase;

                    if (txFirst.Count == 0)
                    {
                        this.baseheight = chain.Height;
                    }
                    if (txFirst.Count < 4)
                    {
                        txFirst.Add(pblock.Transactions[0]);
                    }
                    pblock.UpdateMerkleRoot();

                    pblock.Header.Nonce = blockinfo[i].nonce;

                    chain.SetTip(pblock.Header);
                    consensus.AcceptBlock(new ContextInformation(new BlockResult {
                        Block = pblock
                    }, network.Consensus)
                    {
                        CheckPow = false, CheckMerkleRoot = false
                    });
                    blocks.Add(pblock);
                }

                // Just to make sure we can still make simple blocks
                newBlock = AssemblerForTest(this).CreateNewBlock(scriptPubKey);
                Assert.NotNull(newBlock);
            }