Beispiel #1
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.date.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.date.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.date.GetTime()).SpendsCoinbase(false).FromTx(tx));

            var pblocktemplate = AssemblerForTest(context).CreateNewBlock(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).CreateNewBlock(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).CreateNewBlock(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).CreateNewBlock(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).CreateNewBlock(context.scriptPubKey);
            Assert.True(pblocktemplate.Block.Transactions[8].GetHash() == hashLowFeeTx2);
        }
Beispiel #2
0
            public async Task InitializeAsync()
            {
                this.blockinfo = new List <Blockinfo>();
                var lst = blockinfoarr.Cast <long>().ToList();

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

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

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

                this.entry = new TestMemPoolEntryHelper();
                this.chain = new ConcurrentChain(this.network);
                this.network.Consensus.Options = new PowConsensusOptions();
                IDateTimeProvider dateTimeProvider = DateTimeProvider.Default;

                this.cachedCoinView = new CachedCoinView(new InMemoryCoinView(this.chain.Tip.HashBlock), dateTimeProvider, new LoggerFactory());

                var loggerFactory = new ExtendedLoggerFactory();

                loggerFactory.AddConsoleWithFilters();

                NodeSettings nodeSettings      = new NodeSettings(args: new string[] { "-checkpoints" });
                var          consensusSettings = new ConsensusSettings().Load(nodeSettings);

                PowConsensusValidator consensusValidator = new PowConsensusValidator(this.network, new Checkpoints(), dateTimeProvider, loggerFactory);
                NetworkPeerFactory    networkPeerFactory = new NetworkPeerFactory(this.network, dateTimeProvider, loggerFactory, new PayloadProvider().DiscoverPayloads(), new SelfEndpointTracker());

                var peerAddressManager = new PeerAddressManager(DateTimeProvider.Default, nodeSettings.DataFolder, loggerFactory, new SelfEndpointTracker());
                var peerDiscovery      = new PeerDiscovery(new AsyncLoopFactory(loggerFactory), loggerFactory, Network.Main, networkPeerFactory, new NodeLifetime(), nodeSettings, peerAddressManager);
                var connectionSettings = new ConnectionManagerSettings();

                connectionSettings.Load(nodeSettings);
                var connectionManager = new ConnectionManager(dateTimeProvider, loggerFactory, this.network, networkPeerFactory, nodeSettings, new NodeLifetime(), new NetworkPeerConnectionParameters(), peerAddressManager, new IPeerConnector[] { }, peerDiscovery, connectionSettings);

                LookaheadBlockPuller blockPuller    = new LookaheadBlockPuller(this.chain, connectionManager, new LoggerFactory());
                PeerBanning          peerBanning    = new PeerBanning(connectionManager, loggerFactory, dateTimeProvider, peerAddressManager);
                NodeDeployments      deployments    = new NodeDeployments(this.network, this.chain);
                ConsensusRules       consensusRules = new PowConsensusRules(this.network, loggerFactory, dateTimeProvider, this.chain, deployments, consensusSettings, new Checkpoints()).Register(new FullNodeBuilderConsensusExtension.PowConsensusRulesRegistration());

                this.consensus = new ConsensusLoop(new AsyncLoopFactory(loggerFactory), consensusValidator, new NodeLifetime(), this.chain, this.cachedCoinView, blockPuller, new NodeDeployments(this.network, this.chain), loggerFactory, new ChainState(new InvalidBlockHashStore(dateTimeProvider)), connectionManager, dateTimeProvider, new Signals.Signals(), consensusSettings, nodeSettings, peerBanning, consensusRules);
                await this.consensus.StartAsync();

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

                date1.time       = dateTimeProvider.GetTime();
                date1.timeutc    = dateTimeProvider.GetUtcNow();
                this.date        = date1;
                this.mempool     = new TxMempool(dateTimeProvider, new BlockPolicyEstimator(new MempoolSettings(nodeSettings), new LoggerFactory(), nodeSettings), new LoggerFactory(), nodeSettings);
                this.mempoolLock = new MempoolSchedulerLock();

                // Simple block creation, nothing special yet:
                this.newBlock = AssemblerForTest(this).CreateNewBlock(this.scriptPubKey);
                this.chain.SetTip(this.newBlock.Block.Header);
                await this.consensus.ValidateAndExecuteBlockAsync(new RuleContext(new BlockValidationContext {
                    Block = this.newBlock.Block
                }, this.network.Consensus, this.consensus.Tip) { 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>();

                this.txFirst = new List <Transaction>();
                for (int i = 0; i < this.blockinfo.Count; ++i)
                {
                    var pblock = this.newBlock.Block.Clone(); // pointer for convenience
                    pblock.Header.HashPrevBlock = this.chain.Tip.HashBlock;
                    pblock.Header.Version       = 1;
                    pblock.Header.Time          = Utils.DateTimeToUnixTime(this.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(this.blockinfo[i].extranonce), Op.GetPushOp(this.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 (this.txFirst.Count == 0)
                    {
                        this.baseheight = this.chain.Height;
                    }
                    if (this.txFirst.Count < 4)
                    {
                        this.txFirst.Add(pblock.Transactions[0]);
                    }
                    pblock.UpdateMerkleRoot();

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

                    this.chain.SetTip(pblock.Header);
                    await this.consensus.ValidateAndExecuteBlockAsync(new RuleContext(new BlockValidationContext {
                        Block = pblock
                    }, this.network.Consensus, this.consensus.Tip) { CheckPow = false, CheckMerkleRoot = false });

                    blocks.Add(pblock);
                }

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