예제 #1
0
        public static async Task <ITestChainContext> CreatePosAsync(Network network, Script scriptPubKey, string dataDir, bool requireStandard = true)
        {
            var nodeSettings = new NodeSettings(network, args: new string[] { $"-datadir={dataDir}" });

            ILoggerFactory    loggerFactory    = nodeSettings.LoggerFactory;
            IDateTimeProvider dateTimeProvider = DateTimeProvider.Default;

            network.Consensus.Options = new ConsensusOptions();

            var consensusRulesContainer = new ConsensusRulesContainer();

            foreach (var ruleType in network.Consensus.ConsensusRules.HeaderValidationRules)
            {
                // Don't check PoW of a header in this test.
                if (ruleType == typeof(CheckDifficultyPowRule))
                {
                    continue;
                }

                consensusRulesContainer.HeaderValidationRules.Add(Activator.CreateInstance(ruleType) as HeaderValidationConsensusRule);
            }
            foreach (Type ruleType in network.Consensus.ConsensusRules.FullValidationRules)
            {
                consensusRulesContainer.FullValidationRules.Add(Activator.CreateInstance(ruleType) as FullValidationConsensusRule);
            }
            foreach (Type ruleType in network.Consensus.ConsensusRules.PartialValidationRules)
            {
                consensusRulesContainer.PartialValidationRules.Add(Activator.CreateInstance(ruleType) as PartialValidationConsensusRule);
            }

            var consensusSettings = new ConsensusSettings(nodeSettings);
            var chain             = new ChainIndexer(network);
            var inMemoryCoinView  = new InMemoryCoinView(new HashHeightPair(chain.Tip));

            var chainState  = new ChainState();
            var deployments = new NodeDeployments(network, chain);

            var asyncProvider = new AsyncProvider(loggerFactory, new Mock <ISignals>().Object, new NodeLifetime());

            var stakeChain = new StakeChainStore(network, chain, null, loggerFactory);
            ConsensusRuleEngine consensusRules = new PosConsensusRuleEngine(network, loggerFactory, dateTimeProvider, chain, deployments, consensusSettings, new Checkpoints(),
                                                                            inMemoryCoinView, stakeChain, new StakeValidator(network, stakeChain, chain, inMemoryCoinView, loggerFactory), chainState, new InvalidBlockHashStore(dateTimeProvider),
                                                                            new NodeStats(dateTimeProvider, loggerFactory), new RewindDataIndexCache(dateTimeProvider, network, new FinalizedBlockInfoRepository(new HashHeightPair()), new Checkpoints()), asyncProvider, consensusRulesContainer).SetupRulesEngineParent();

            ConsensusManager consensus = ConsensusManagerHelper.CreateConsensusManager(network, dataDir, chainState, chainIndexer: chain, consensusRules: consensusRules, inMemoryCoinView: inMemoryCoinView);

            var genesis = new ChainedHeader(network.GetGenesis().Header, network.GenesisHash, 0);

            chainState.BlockStoreTip = genesis;
            await consensus.InitializeAsync(genesis).ConfigureAwait(false);

            var mempoolSettings = new MempoolSettings(nodeSettings)
            {
                RequireStandard = requireStandard
            };
            var blockPolicyEstimator = new BlockPolicyEstimator(mempoolSettings, loggerFactory, nodeSettings);
            var mempool     = new TxMempool(dateTimeProvider, blockPolicyEstimator, loggerFactory, nodeSettings);
            var mempoolLock = new MempoolSchedulerLock();

            // The mempool rule constructors aren't parameterless, so we have to manually inject the dependencies for every rule
            var mempoolRules = new List <MempoolRule>
            {
                new CheckConflictsMempoolRule(network, mempool, mempoolSettings, chain, loggerFactory),
                new CheckCoinViewMempoolRule(network, mempool, mempoolSettings, chain, loggerFactory),
                new CreateMempoolEntryMempoolRule(network, mempool, mempoolSettings, chain, consensusRules, loggerFactory),
                new CheckSigOpsMempoolRule(network, mempool, mempoolSettings, chain, loggerFactory),
                new CheckFeeMempoolRule(network, mempool, mempoolSettings, chain, loggerFactory),
                new CheckRateLimitMempoolRule(network, mempool, mempoolSettings, chain, loggerFactory),
                new CheckAncestorsMempoolRule(network, mempool, mempoolSettings, chain, loggerFactory),
                new CheckReplacementMempoolRule(network, mempool, mempoolSettings, chain, loggerFactory),
                new CheckAllInputsMempoolRule(network, mempool, mempoolSettings, chain, consensusRules, deployments, loggerFactory),
                new CheckTxOutDustRule(network, mempool, mempoolSettings, chain, loggerFactory),
            };

            // We also have to check that the manually instantiated rules match the ones in the network, or the test isn't valid
            for (int i = 0; i < network.Consensus.MempoolRules.Count; i++)
            {
                if (network.Consensus.MempoolRules[i] != mempoolRules[i].GetType())
                {
                    throw new Exception("Mempool rule type mismatch");
                }
            }

            var mempoolValidator = new MempoolValidator(mempool, mempoolLock, dateTimeProvider, mempoolSettings, chain, inMemoryCoinView, loggerFactory, nodeSettings, consensusRules, mempoolRules, deployments);

            var            blocks = new List <Block>();
            var            srcTxs = new List <Transaction>();
            DateTimeOffset now    = DateTimeOffset.UtcNow;

            for (int i = 0; i < 50; i++)
            {
                uint  nonce = 0;
                Block block = network.CreateBlock();
                block.Header.HashPrevBlock = chain.Tip.HashBlock;
                block.Header.Bits          = block.Header.GetWorkRequired(network, chain.Tip);
                block.Header.UpdateTime(now, network, chain.Tip);

                Transaction coinbase = network.CreateTransaction();
                coinbase.AddInput(TxIn.CreateCoinbase(chain.Height + 1));
                coinbase.AddOutput(new TxOut(network.Consensus.ProofOfWorkReward, scriptPubKey));
                block.AddTransaction(coinbase);
                block.UpdateMerkleRoot();
                while (!block.CheckProofOfWork())
                {
                    block.Header.Nonce = ++nonce;
                }
                block.Header.PrecomputeHash();
                blocks.Add(block);
                chain.SetTip(block.Header);
                srcTxs.Add(block.Transactions[0]);

                inMemoryCoinView.SaveChanges(new List <UnspentOutput>()
                {
                    new UnspentOutput(new OutPoint(block.Transactions[0], 0), new Coins((uint)(i + 1), block.Transactions[0].Outputs.First(), block.Transactions[0].IsCoinBase))
                }, new HashHeightPair(chain.Tip.Previous), new HashHeightPair(chain.Tip));
            }

            return(new TestChainContext {
                MempoolValidator = mempoolValidator, MempoolSettings = mempoolSettings, ChainIndexer = chain, SrcTxs = srcTxs
            });
        }
예제 #2
0
        /// <summary>
        /// Creates the test chain with some default blocks and txs.
        /// </summary>
        /// <param name="network">Network to create the chain on.</param>
        /// <param name="scriptPubKey">Public key to create blocks/txs with.</param>
        /// <returns>Context object representing the test chain.</returns>
        public static async Task <ITestChainContext> CreateAsync(Network network, Script scriptPubKey, string dataDir)
        {
            var nodeSettings = new NodeSettings(network, args: new string[] { $"-datadir={dataDir}" });

            ILoggerFactory    loggerFactory    = nodeSettings.LoggerFactory;
            IDateTimeProvider dateTimeProvider = DateTimeProvider.Default;

            network.Consensus.Options = new ConsensusOptions();
            new FullNodeBuilderConsensusExtension.PowConsensusRulesRegistration().RegisterRules(network.Consensus);

            // Dont check PoW of a header in this test.
            network.Consensus.HeaderValidationRules.RemoveAll(x => x.GetType() == typeof(CheckDifficultyPowRule));

            var consensusSettings = new ConsensusSettings(nodeSettings);
            var chain             = new ConcurrentChain(network);
            var inMemoryCoinView  = new InMemoryCoinView(chain.Tip.HashBlock);

            var chainState  = new ChainState();
            var deployments = new NodeDeployments(network, chain);
            ConsensusRuleEngine consensusRules = new PowConsensusRuleEngine(network, loggerFactory, dateTimeProvider, chain, deployments, consensusSettings, new Checkpoints(),
                                                                            inMemoryCoinView, chainState, new InvalidBlockHashStore(dateTimeProvider), new NodeStats(dateTimeProvider)).Register();

            ConsensusManager consensus = ConsensusManagerHelper.CreateConsensusManager(network, dataDir, chainState);

            var genesis = new ChainedHeader(network.GetGenesis().Header, network.GenesisHash, 0);

            chainState.BlockStoreTip = genesis;
            await consensus.InitializeAsync(genesis).ConfigureAwait(false);

            var blockPolicyEstimator = new BlockPolicyEstimator(new MempoolSettings(nodeSettings), loggerFactory, nodeSettings);
            var mempool     = new TxMempool(dateTimeProvider, blockPolicyEstimator, loggerFactory, nodeSettings);
            var mempoolLock = new MempoolSchedulerLock();

            var minerSettings = new MinerSettings(nodeSettings);

            // Simple block creation, nothing special yet:
            var           blockDefinition = new PowBlockDefinition(consensus, dateTimeProvider, loggerFactory, mempool, mempoolLock, minerSettings, network, consensusRules);
            BlockTemplate newBlock        = blockDefinition.Build(chain.Tip, scriptPubKey);

            await consensus.BlockMinedAsync(newBlock.Block);

            List <BlockInfo> blockinfo = CreateBlockInfoList();

            // We can't make transactions until we have inputs therefore, load 100 blocks.
            var blocks = new List <Block>();
            var srcTxs = new List <Transaction>();

            for (int i = 0; i < blockinfo.Count; ++i)
            {
                Block currentBlock = Block.Load(newBlock.Block.ToBytes(network.Consensus.ConsensusFactory), network);
                currentBlock.Header.HashPrevBlock = chain.Tip.HashBlock;
                currentBlock.Header.Version       = 1;
                currentBlock.Header.Time          = Utils.DateTimeToUnixTime(chain.Tip.GetMedianTimePast()) + 1;

                Transaction txCoinbase = network.CreateTransaction(currentBlock.Transactions[0].ToBytes());
                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()));
                currentBlock.Transactions[0] = txCoinbase;

                if (srcTxs.Count < 4)
                {
                    srcTxs.Add(currentBlock.Transactions[0]);
                }

                currentBlock.UpdateMerkleRoot();

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

                chain.SetTip(currentBlock.Header);
            }

            // Just to make sure we can still make simple blocks
            blockDefinition = new PowBlockDefinition(consensus, dateTimeProvider, loggerFactory, mempool, mempoolLock, minerSettings, network, consensusRules);
            blockDefinition.Build(chain.Tip, scriptPubKey);

            var mempoolValidator = new MempoolValidator(mempool, mempoolLock, dateTimeProvider, new MempoolSettings(nodeSettings), chain, inMemoryCoinView, loggerFactory, nodeSettings, consensusRules);

            var outputs = new List <UnspentOutputs>();

            foreach (Transaction tx in srcTxs)
            {
                var output = new UnspentOutputs(0, tx);

                outputs.Add(output);
            }

            inMemoryCoinView.SaveChanges(outputs, new List <TxOut[]>(), chain.GetBlock(0).HashBlock, chain.GetBlock(1).HashBlock, chain.GetBlock(0).Height);

            return(new TestChainContext {
                MempoolValidator = mempoolValidator, SrcTxs = srcTxs
            });
        }
예제 #3
0
        /// <summary>
        /// Creates the test chain with some default blocks and txs.
        /// </summary>
        /// <param name="network">Network to create the chain on.</param>
        /// <param name="scriptPubKey">Public key to create blocks/txs with.</param>
        /// <param name="requireStandard">By default testnet and regtest networks do not require transactions to be standard. This changes that default.</param>
        /// <returns>Context object representing the test chain.</returns>
        public static async Task <ITestChainContext> CreateAsync(Network network, Script scriptPubKey, string dataDir, bool requireStandard = true)
        {
            var nodeSettings = new NodeSettings(network, args: new string[] { $"-datadir={dataDir}" });

            ILoggerFactory    loggerFactory    = nodeSettings.LoggerFactory;
            IDateTimeProvider dateTimeProvider = DateTimeProvider.Default;

            network.Consensus.Options = new ConsensusOptions();

            var consensusRulesContainer = new ConsensusRulesContainer();

            foreach (Type ruleType in network.Consensus.ConsensusRules.HeaderValidationRules)
            {
                // Don't check PoW of a header in this test.
                if (ruleType == typeof(CheckDifficultyPowRule))
                {
                    continue;
                }

                consensusRulesContainer.HeaderValidationRules.Add(Activator.CreateInstance(ruleType) as HeaderValidationConsensusRule);
            }
            foreach (Type ruleType in network.Consensus.ConsensusRules.PartialValidationRules)
            {
                consensusRulesContainer.PartialValidationRules.Add(Activator.CreateInstance(ruleType) as PartialValidationConsensusRule);
            }
            foreach (var ruleType in network.Consensus.ConsensusRules.FullValidationRules)
            {
                FullValidationConsensusRule rule = null;
                if (ruleType == typeof(FlushCoinviewRule))
                {
                    rule = new FlushCoinviewRule(new Mock <IInitialBlockDownloadState>().Object);
                }
                else
                {
                    rule = Activator.CreateInstance(ruleType) as FullValidationConsensusRule;
                }

                consensusRulesContainer.FullValidationRules.Add(rule);
            }

            var consensusSettings = new ConsensusSettings(nodeSettings);
            var chain             = new ChainIndexer(network);
            var inMemoryCoinView  = new InMemoryCoinView(new HashHeightPair(chain.Tip));

            var asyncProvider = new AsyncProvider(loggerFactory, new Mock <ISignals>().Object, new NodeLifetime());

            var chainState  = new ChainState();
            var deployments = new NodeDeployments(network, chain);

            ConsensusRuleEngine consensusRules = new PowConsensusRuleEngine(network, loggerFactory, dateTimeProvider, chain, deployments, consensusSettings, new Checkpoints(),
                                                                            inMemoryCoinView, chainState, new InvalidBlockHashStore(dateTimeProvider), new NodeStats(dateTimeProvider, loggerFactory), asyncProvider, consensusRulesContainer).SetupRulesEngineParent();

            ConsensusManager consensus = ConsensusManagerHelper.CreateConsensusManager(network, dataDir, chainState, chainIndexer: chain, consensusRules: consensusRules, inMemoryCoinView: inMemoryCoinView);

            var genesis = new ChainedHeader(network.GetGenesis().Header, network.GenesisHash, 0);

            chainState.BlockStoreTip = genesis;
            await consensus.InitializeAsync(genesis).ConfigureAwait(false);

            var blockPolicyEstimator = new BlockPolicyEstimator(new MempoolSettings(nodeSettings), loggerFactory, nodeSettings);
            var mempool     = new TxMempool(dateTimeProvider, blockPolicyEstimator, loggerFactory, nodeSettings);
            var mempoolLock = new MempoolSchedulerLock();

            var minerSettings = new MinerSettings(nodeSettings);

            // Simple block creation, nothing special yet:
            var           blockDefinition = new PowBlockDefinition(consensus, dateTimeProvider, loggerFactory, mempool, mempoolLock, minerSettings, network, consensusRules, deployments);
            BlockTemplate newBlock        = blockDefinition.Build(chain.Tip, scriptPubKey);

            await consensus.BlockMinedAsync(newBlock.Block);

            List <BlockInfo> blockinfo = CreateBlockInfoList();

            // We can't make transactions until we have inputs therefore, load 100 blocks.

            var srcTxs = new List <Transaction>();

            for (int i = 0; i < blockinfo.Count; ++i)
            {
                Block currentBlock = Block.Load(newBlock.Block.ToBytes(network.Consensus.ConsensusFactory), network.Consensus.ConsensusFactory);
                currentBlock.Header.HashPrevBlock = chain.Tip.HashBlock;
                currentBlock.Header.Version       = 1;
                currentBlock.Header.Time          = Utils.DateTimeToUnixTime(chain.Tip.GetMedianTimePast()) + 1;

                Transaction txCoinbase = network.CreateTransaction(currentBlock.Transactions[0].ToBytes());
                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()));
                currentBlock.Transactions[0] = txCoinbase;

                currentBlock.UpdateMerkleRoot();
                currentBlock.Header.Nonce = blockinfo[i].nonce;

                chain.SetTip(currentBlock.Header);
                srcTxs.Add(currentBlock.Transactions[0]);

                inMemoryCoinView.SaveChanges(new List <UnspentOutput>()
                {
                    new UnspentOutput(new OutPoint(currentBlock.Transactions[0], 0), new Coins((uint)(i + 1), currentBlock.Transactions[0].Outputs.First(), currentBlock.Transactions[0].IsCoinBase))
                }, new HashHeightPair(chain.Tip.Previous), new HashHeightPair(chain.Tip));
            }

            // Just to make sure we can still make simple blocks
            blockDefinition = new PowBlockDefinition(consensus, dateTimeProvider, loggerFactory, mempool, mempoolLock, minerSettings, network, consensusRules, deployments);
            blockDefinition.Build(chain.Tip, scriptPubKey);

            var mempoolSettings = new MempoolSettings(nodeSettings)
            {
                RequireStandard = requireStandard
            };

            // The mempool rule constructors aren't parameterless, so we have to manually inject the dependencies for every rule
            var mempoolRules = new List <MempoolRule>
            {
                new CheckConflictsMempoolRule(network, mempool, mempoolSettings, chain, loggerFactory),
                new CheckCoinViewMempoolRule(network, mempool, mempoolSettings, chain, loggerFactory),
                new CreateMempoolEntryMempoolRule(network, mempool, mempoolSettings, chain, consensusRules, loggerFactory),
                new CheckSigOpsMempoolRule(network, mempool, mempoolSettings, chain, loggerFactory),
                new CheckFeeMempoolRule(network, mempool, mempoolSettings, chain, loggerFactory),
                new CheckRateLimitMempoolRule(network, mempool, mempoolSettings, chain, loggerFactory),
                new CheckAncestorsMempoolRule(network, mempool, mempoolSettings, chain, loggerFactory),
                new CheckReplacementMempoolRule(network, mempool, mempoolSettings, chain, loggerFactory),
                new CheckAllInputsMempoolRule(network, mempool, mempoolSettings, chain, consensusRules, deployments, loggerFactory),
                new CheckTxOutDustRule(network, mempool, mempoolSettings, chain, loggerFactory),
            };

            // We also have to check that the manually instantiated rules match the ones in the network, or the test isn't valid
            for (int i = 0; i < network.Consensus.MempoolRules.Count; i++)
            {
                if (network.Consensus.MempoolRules[i] != mempoolRules[i].GetType())
                {
                    throw new Exception("Mempool rule type mismatch");
                }
            }

            Assert.Equal(network.Consensus.MempoolRules.Count, mempoolRules.Count);

            var mempoolValidator = new MempoolValidator(mempool, mempoolLock, dateTimeProvider, mempoolSettings, chain, inMemoryCoinView, loggerFactory, nodeSettings, consensusRules, mempoolRules, deployments);

            return(new TestChainContext {
                MempoolValidator = mempoolValidator, MempoolSettings = mempoolSettings, ChainIndexer = chain, SrcTxs = srcTxs
            });
        }