GenerateForkedChainAndBlocksWithHeight(int blockAmount, Network network, int forkBlock)
        {
            var     rightchain      = new ChainIndexer(network);
            var     leftchain       = new ChainIndexer(network);
            uint256 prevBlockHash   = rightchain.Genesis.HashBlock;
            var     leftForkBlocks  = new List <Block>();
            var     rightForkBlocks = new List <Block>();

            // build up left fork fully and right fork until forkblock
            uint256 forkBlockPrevHash = null;

            for (int i = 0; i < blockAmount; i++)
            {
                Block block = network.Consensus.ConsensusFactory.CreateBlock();
                block.AddTransaction(network.CreateTransaction());
                block.UpdateMerkleRoot();
                block.Header.HashPrevBlock = prevBlockHash;
                block.Header.Nonce         = RandomUtils.GetUInt32();
                leftchain.SetTip(block.Header);

                if (leftchain.Height == forkBlock)
                {
                    forkBlockPrevHash = block.GetHash();
                }
                prevBlockHash = block.GetHash();
                leftForkBlocks.Add(block);

                if (rightchain.Height < forkBlock)
                {
                    rightForkBlocks.Add(block);
                    rightchain.SetTip(block.Header);
                }
            }

            // build up the right fork further.
            for (int i = forkBlock; i < blockAmount; i++)
            {
                Block block = network.Consensus.ConsensusFactory.CreateBlock();
                block.AddTransaction(network.CreateTransaction());
                block.UpdateMerkleRoot();
                block.Header.HashPrevBlock = forkBlockPrevHash;
                block.Header.Nonce         = RandomUtils.GetUInt32();
                rightchain.SetTip(block.Header);
                forkBlockPrevHash = block.GetHash();
                rightForkBlocks.Add(block);
            }

            // if all blocks are on both sides the fork fails.
            if (leftForkBlocks.All(l => rightForkBlocks.Select(r => r.GetHash()).Contains(l.GetHash())))
            {
                throw new InvalidOperationException("No fork created.");
            }

            return(leftchain, rightchain, leftForkBlocks, rightForkBlocks);
        }
Example #2
0
        /// <summary>
        /// Synchronize a given Chain to the tip of the given node if its height is higher. (Thread safe).
        /// </summary>
        /// <param name="peer">Node to synchronize the chain for.</param>
        /// <param name="chain">The chain to synchronize.</param>
        /// <param name="hashStop">The location until which it synchronize.</param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        private IEnumerable <ChainedHeader> SynchronizeChain(INetworkPeer peer, ChainIndexer chain, uint256 hashStop = null, CancellationToken cancellationToken = default(CancellationToken))
        {
            ChainedHeader        oldTip  = chain.Tip;
            List <ChainedHeader> headers = this.GetHeadersFromFork(peer, oldTip, hashStop, cancellationToken).ToList();

            if (headers.Count == 0)
            {
                return(new ChainedHeader[0]);
            }

            ChainedHeader newTip = headers[headers.Count - 1];

            if (newTip.Height <= oldTip.Height)
            {
                throw new ProtocolException("No tip should have been recieved older than the local one");
            }

            foreach (ChainedHeader header in headers)
            {
                if (!header.Validate(peer.Network))
                {
                    throw new ProtocolException("A header which does not pass proof of work verification has been received");
                }
            }

            chain.SetTip(newTip);

            return(headers);
        }
Example #3
0
        private static ChainIndexer GenerateChainWithHeightAndActivatedBip9(int blockAmount, Network network, Key key, BIP9DeploymentsParameters parameter, Target bits = null)
        {
            var     chain         = new ChainIndexer(network);
            uint    nonce         = RandomUtils.GetUInt32();
            uint256 prevBlockHash = chain.Genesis.HashBlock;

            for (int i = 0; i < blockAmount; i++)
            {
                Block       block    = network.Consensus.ConsensusFactory.CreateBlock();
                Transaction coinbase = CreateCoinbaseTransaction(network, key, chain.Height + 1);

                block.AddTransaction(coinbase);
                block.UpdateMerkleRoot();
                block.Header.BlockTime     = new DateTimeOffset(new DateTime(2017, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddDays(i));
                block.Header.HashPrevBlock = prevBlockHash;
                block.Header.Nonce         = nonce;

                if (bits != null)
                {
                    block.Header.Bits = bits;
                }

                if (parameter != null)
                {
                    uint version = ThresholdConditionCache.VersionbitsTopBits;
                    version |= ((uint)1) << parameter.Bit;
                    block.Header.Version = (int)version;
                }

                chain.SetTip(block.Header);
                prevBlockHash = block.GetHash();
            }

            return(chain);
        }
Example #4
0
        public void GetChainReturnsConcurrentChainFromDisk()
        {
            string        dir   = CreateTestDir(this);
            var           chain = new ChainIndexer(KnownNetworks.StratisRegTest);
            ChainedHeader tip   = this.AppendBlock(chain);

            using (var engine = new DBreezeEngine(dir))
            {
                using (DBreeze.Transactions.Transaction transaction = engine.GetTransaction())
                {
                    ChainedHeader toSave = tip;
                    var           blocks = new List <ChainedHeader>();
                    while (toSave != null)
                    {
                        blocks.Insert(0, toSave);
                        toSave = toSave.Previous;
                    }

                    foreach (ChainedHeader block in blocks)
                    {
                        transaction.Insert("Chain", block.Height, this.dBreezeSerializer.Serialize(block.Header));
                    }

                    transaction.Commit();
                }
            }
            using (var repo = new ChainRepository(dir, new LoggerFactory(), this.dBreezeSerializer))
            {
                var testChain = new ChainIndexer(KnownNetworks.StratisRegTest);
                testChain.SetTip(repo.LoadAsync(testChain.Genesis).GetAwaiter().GetResult());
                Assert.Equal(tip, testChain.Tip);
            }
        }
Example #5
0
        public void CanSaveChainIncrementally()
        {
            var chain = new ChainIndexer(this.regTest);
            var data  = new DataFolder(TestBase.CreateTestDir(this));

            var chainStore = new LevelDbChainStore(this.network, data, chain);

            chain[0].SetChainStore(chainStore);

            using (var repo = new ChainRepository(chainStore))
            {
                chain.SetTip(repo.LoadAsync(chain.Genesis).GetAwaiter().GetResult());
                Assert.True(chain.Tip == chain.Genesis);
                chain = new ChainIndexer(this.regTest);
                chain[0].SetChainStore(chainStore);
                ChainedHeader tip = this.AppendBlock(chain);
                repo.SaveAsync(chain).GetAwaiter().GetResult();
                var newChain = new ChainIndexer(this.regTest);
                newChain.SetTip(repo.LoadAsync(chain.Genesis).GetAwaiter().GetResult());
                Assert.Equal(tip, newChain.Tip);
                tip = this.AppendBlock(chain);
                repo.SaveAsync(chain).GetAwaiter().GetResult();
                newChain = new ChainIndexer(this.regTest);
                newChain.SetTip(repo.LoadAsync(chain.Genesis).GetAwaiter().GetResult());
                Assert.Equal(tip, newChain.Tip);
            }
        }
        public void GetChainReturnsConcurrentChainFromDisk()
        {
            string        dir   = CreateTestDir(this);
            var           chain = new ChainIndexer(KnownNetworks.StratisRegTest);
            ChainedHeader tip   = this.AppendBlock(chain);

            using (var engine = new DB(new Options {
                CreateIfMissing = true
            }, dir))
            {
                using (var batch = new WriteBatch())
                {
                    ChainedHeader toSave = tip;
                    var           blocks = new List <ChainedHeader>();
                    while (toSave != null)
                    {
                        blocks.Insert(0, toSave);
                        toSave = toSave.Previous;
                    }

                    foreach (ChainedHeader block in blocks)
                    {
                        batch.Put(BitConverter.GetBytes(block.Height), this.dataStoreSerializer.Serialize(block.Header));
                    }

                    engine.Write(batch);
                }
            }
            using (var repo = new ChainRepository(dir, new LoggerFactory(), this.dataStoreSerializer, new MemoryHeaderStore()))
            {
                var testChain = new ChainIndexer(KnownNetworks.StratisRegTest);
                testChain.SetTip(repo.LoadAsync(testChain.Genesis).GetAwaiter().GetResult());
                Assert.Equal(tip, testChain.Tip);
            }
        }
Example #7
0
        private ChainedHeader AddBlock(ChainIndexer chainIndexer)
        {
            BlockHeader header = this.network.Consensus.ConsensusFactory.CreateBlockHeader();

            header.Nonce         = RandomUtils.GetUInt32();
            header.HashPrevBlock = chainIndexer.Tip.HashBlock;
            chainIndexer.SetTip(header);
            return(chainIndexer.GetHeader(header.GetHash()));
        }
Example #8
0
        public void CanBuildConcurrentChain()
        {
            var cchain = new ChainIndexer(this.network);
            var chain  = new ChainIndexer(this.network);

            ChainedHeader b0 = cchain.Tip;

            Assert.Equal(cchain.Tip, chain.Tip);

            ChainedHeader b1 = this.AddBlock(chain);
            ChainedHeader b2 = this.AddBlock(chain);

            this.AddBlock(chain);
            this.AddBlock(chain);
            ChainedHeader b5 = this.AddBlock(chain);

            Assert.Equal(cchain.SetTip(chain.Tip), b0);
            Assert.Equal(cchain.Tip, chain.Tip);

            Assert.Equal(cchain.GetHeader(5), chain.Tip);
            Assert.Equal(cchain.GetHeader(b5.HashBlock), chain.Tip);

            Assert.Equal(cchain.SetTip(b1), b1);
            Assert.Null(cchain.GetHeader(b5.HashBlock));
            Assert.Null(cchain.GetHeader(b2.HashBlock));

            Assert.Equal(cchain.SetTip(b5), b1);
            Assert.Equal(cchain.GetHeader(b5.HashBlock), chain.Tip);

            chain.SetTip(b2);
            this.AddBlock(chain);
            this.AddBlock(chain);
            ChainedHeader b5b = this.AddBlock(chain);
            ChainedHeader b6b = this.AddBlock(chain);

            Assert.Equal(cchain.SetTip(b6b), b2);

            Assert.Null(cchain.GetHeader(b5.HashBlock));
            Assert.Equal(cchain.GetHeader(b2.HashBlock), b2);
            Assert.Equal(cchain.GetHeader(6), b6b);
            Assert.Equal(cchain.GetHeader(5), b5b);
        }
Example #9
0
 public void AppendBlocksToChain(ChainIndexer chainIndexer, IEnumerable <Block> blocks)
 {
     foreach (Block block in blocks)
     {
         if (chainIndexer.Tip != null)
         {
             block.Header.HashPrevBlock = chainIndexer.Tip.HashBlock;
         }
         chainIndexer.SetTip(block.Header);
     }
 }
        public static ChainIndexer PrepareChainWithBlock()
        {
            var   chain = new ChainIndexer(KnownNetworks.StratisMain);
            uint  nonce = RandomUtils.GetUInt32();
            Block block = KnownNetworks.StratisMain.CreateBlock();

            block.AddTransaction(KnownNetworks.StratisMain.CreateTransaction());
            block.UpdateMerkleRoot();
            block.Header.HashPrevBlock = chain.Genesis.HashBlock;
            block.Header.Nonce         = nonce;
            block.Header.BlockTime     = DateTimeOffset.Now;
            chain.SetTip(block.Header);
            return(chain);
        }
Example #11
0
        public void LoadChainFromDisk()
        {
            string        dir   = CreateTestDir(this);
            var           chain = new ChainIndexer(KnownNetworks.StraxRegTest);
            ChainedHeader tip   = this.AppendBlock(chain);

            using (var engine = new DB(new Options {
                CreateIfMissing = true
            }, new DataFolder(dir).ChainPath))
            {
                using (var batch = new WriteBatch())
                {
                    ChainedHeader toSave = tip;
                    var           blocks = new List <ChainedHeader>();
                    while (toSave != null)
                    {
                        blocks.Insert(0, toSave);
                        toSave = toSave.Previous;
                    }

                    foreach (ChainedHeader block in blocks)
                    {
                        batch.Put(1, BitConverter.GetBytes(block.Height),
                                  new ChainRepository.ChainRepositoryData()
                        {
                            Hash = block.HashBlock, Work = block.ChainWorkBytes
                        }
                                  .ToBytes(this.Network.Consensus.ConsensusFactory));

                        ConsensusFactory consensusFactory = KnownNetworks.StraxRegTest.Consensus.ConsensusFactory;
                        batch.Put(2, block.Header.GetHash().ToBytes(), block.Header.ToBytes(consensusFactory));
                    }

                    engine.Write(batch);
                }
            }

            var chainStore = new LevelDbChainStore(chain.Network, new DataFolder(dir), chain);

            using (var repo = new ChainRepository(chainStore))
            {
                var testChain = new ChainIndexer(KnownNetworks.StraxRegTest);
                testChain[0].SetChainStore(chainStore);
                testChain.SetTip(repo.LoadAsync(testChain.Genesis).GetAwaiter().GetResult());
                Assert.Equal(tip, testChain.Tip);
            }
        }
Example #12
0
        /// <summary>Creates specified number of consecutive headers.</summary>
        /// <param name="count">Number of blocks to generate.</param>
        /// <param name="prevBlock">If not <c>null</c> the headers will be generated on top of it.</param>
        /// <param name="includePrevBlock">If <c>true</c> <paramref name="prevBlock"/> will be added as a first item in the list or genesis header if <paramref name="prevBlock"/> is <c>null</c>.</param>
        public static List <ChainedHeader> CreateConsecutiveHeaders(int count, ChainedHeader prevBlock = null, bool includePrevBlock = false, Target bits = null, Network network = null, ChainIndexer chainIndexer = null)
        {
            var chainedHeaders = new List <ChainedHeader>();

            network = network ?? KnownNetworks.StraxMain;

            ChainedHeader tip = prevBlock;

            if (tip == null)
            {
                ChainedHeader genesis = CreateGenesisChainedHeader(network);
                tip = genesis;
            }

            if (includePrevBlock)
            {
                chainedHeaders.Add(tip);
            }

            uint256 hashPrevBlock = tip.HashBlock;

            uint time = 0;

            for (int i = 0; i < count; i++)
            {
                BlockHeader header = network.Consensus.ConsensusFactory.CreateBlockHeader();
                header.Time          = time += (uint)network.Consensus.TargetSpacing.TotalSeconds;
                header.Nonce         = (uint)Interlocked.Increment(ref currentNonce);
                header.HashPrevBlock = hashPrevBlock;
                header.Bits          = bits ?? Target.Difficulty1;

                var chainedHeader = new ChainedHeader(header, header.GetHash(), tip);

                hashPrevBlock = chainedHeader.HashBlock;
                tip           = chainedHeader;

                if (chainIndexer != null)
                {
                    chainIndexer.SetTip(tip);
                }

                chainedHeaders.Add(chainedHeader);
            }

            return(chainedHeaders);
        }
        private ChainIndexer CreateChain(int blocksCount)
        {
            var chain = new ChainIndexer(this.network);

            for (int i = 0; i < blocksCount; i++)
            {
                BlockHeader header = this.network.Consensus.ConsensusFactory.CreateBlockHeader();
                header.Nonce         = RandomUtils.GetUInt32();
                header.HashPrevBlock = chain.Tip.HashBlock;
                header.Bits          = Target.Difficulty1;

                var chainedHeader = new ChainedHeader(header, header.GetHash(), chain.Tip);
                chain.SetTip(chainedHeader);
            }

            return(chain);
        }
Example #14
0
        private ChainIndexer CreateChain(BlockHeader genesis, int height)
        {
            var chain = new ChainIndexer(this.network);

            var chainedHeaderPrev = chain.Tip;

            for (int i = 0; i < height; i++)
            {
                Block b = TestUtils.CreateFakeBlock(this.network);
                b.Header.HashPrevBlock = chainedHeaderPrev.HashBlock;

                chainedHeaderPrev = new ChainedHeader(b.Header, b.Header.GetHash(), chainedHeaderPrev);
            }

            chain.SetTip(chainedHeaderPrev);

            return(chain);
        }
        public static bool TrySetTip(this ChainIndexer chainIndexer, BlockHeader header, out ChainedHeader chainedHeader)
        {
            if (header == null)
            {
                throw new ArgumentNullException("header");
            }

            chainedHeader = null;
            ChainedHeader prev = chainIndexer.GetHeader(header.HashPrevBlock);

            if (prev == null)
            {
                return(false);
            }

            chainedHeader = new ChainedHeader(header, header.GetHash(), chainIndexer.GetHeader(header.HashPrevBlock));
            chainIndexer.SetTip(chainedHeader);
            return(true);
        }
        public static ChainIndexer GenerateChainWithHeight(int blockAmount, Network network)
        {
            var     chain         = new ChainIndexer(network);
            uint    nonce         = RandomUtils.GetUInt32();
            uint256 prevBlockHash = chain.Genesis.HashBlock;

            for (int i = 0; i < blockAmount; i++)
            {
                Block block = network.Consensus.ConsensusFactory.CreateBlock();
                block.AddTransaction(network.CreateTransaction());
                block.UpdateMerkleRoot();
                block.Header.BlockTime     = new DateTimeOffset(new DateTime(2017, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddDays(i));
                block.Header.HashPrevBlock = prevBlockHash;
                block.Header.Nonce         = nonce;
                chain.SetTip(block.Header);
                prevBlockHash = block.GetHash();
            }

            return(chain);
        }
        private static void AddBlockToChainWithBlockTimeAndDifficulty(ChainIndexer chainIndexer, int blockAmount, int incrementSeconds, uint nbits, Network network)
        {
            uint256  prevBlockHash = chainIndexer.Tip.HashBlock;
            uint     nonce         = RandomUtils.GetUInt32();
            DateTime blockTime     = Utils.UnixTimeToDateTime(chainIndexer.Tip.Header.Time).UtcDateTime;

            for (int i = 0; i < blockAmount; i++)
            {
                Block block = network.Consensus.ConsensusFactory.CreateBlock();
                block.AddTransaction(new Transaction());
                block.UpdateMerkleRoot();
                block.Header.BlockTime = new DateTimeOffset(blockTime);
                blockTime = blockTime.AddSeconds(incrementSeconds);
                block.Header.HashPrevBlock = prevBlockHash;
                block.Header.Nonce         = nonce;
                block.Header.Bits          = new Target(nbits);
                chainIndexer.SetTip(block.Header);
                prevBlockHash = block.GetHash();
            }
        }
        public static (ChainIndexer Chain, List <Block> Blocks) GenerateChainAndBlocksWithHeight(int blockAmount, Network network)
        {
            var     chain         = new ChainIndexer(network);
            uint    nonce         = RandomUtils.GetUInt32();
            uint256 prevBlockHash = chain.Genesis.HashBlock;
            var     blocks        = new List <Block>();

            for (int i = 0; i < blockAmount; i++)
            {
                Block block = network.Consensus.ConsensusFactory.CreateBlock();
                block.AddTransaction(network.CreateTransaction());
                block.UpdateMerkleRoot();
                block.Header.HashPrevBlock = prevBlockHash;
                block.Header.Nonce         = nonce;
                chain.SetTip(block.Header);
                prevBlockHash = block.GetHash();
                blocks.Add(block);
            }

            return(chain, blocks);
        }
        public void CanSaveChainIncrementally()
        {
            using (var repo = new ChainRepository(TestBase.CreateTestDir(this), this.loggerFactory, this.dBreezeSerializer))
            {
                var chain = new ChainIndexer(this.regTest);

                chain.SetTip(repo.LoadAsync(chain.Genesis).GetAwaiter().GetResult());
                Assert.True(chain.Tip == chain.Genesis);
                chain = new ChainIndexer(this.regTest);
                ChainedHeader tip = this.AppendBlock(chain);
                repo.SaveAsync(chain).GetAwaiter().GetResult();
                var newChain = new ChainIndexer(this.regTest);
                newChain.SetTip(repo.LoadAsync(chain.Genesis).GetAwaiter().GetResult());
                Assert.Equal(tip, newChain.Tip);
                tip = this.AppendBlock(chain);
                repo.SaveAsync(chain).GetAwaiter().GetResult();
                newChain = new ChainIndexer(this.regTest);
                newChain.SetTip(repo.LoadAsync(chain.Genesis).GetAwaiter().GetResult());
                Assert.Equal(tip, newChain.Tip);
            }
        }
Example #20
0
        public void CanLoadAndSaveConcurrentChain()
        {
            var cchain = new ChainIndexer(this.network);
            var chain  = new ChainIndexer(this.network);

            this.AddBlock(chain);
            this.AddBlock(chain);
            this.AddBlock(chain);

            cchain.SetTip(chain.Tip);

            byte[] bytes = cchain.ToBytes();
            cchain = new ChainIndexer(this.network);
            cchain.Load(bytes);

            Assert.Equal(cchain.Tip, chain.Tip);
            Assert.NotNull(cchain.GetHeader(0));

            cchain = new ChainIndexer(this.networkTest);
            cchain.Load(cchain.ToBytes());
            Assert.NotNull(cchain.GetHeader(0));
        }
        public static ChainIndexer GenerateChainWithBlockTimeAndHeight(int blockAmount, Network network, int incrementSeconds, uint nbits)
        {
            var      chain         = new ChainIndexer(network);
            uint     nonce         = RandomUtils.GetUInt32();
            uint256  prevBlockHash = chain.Genesis.HashBlock;
            DateTime blockTime     = Utils.UnixTimeToDateTime(chain.Genesis.Header.Time).UtcDateTime;

            for (int i = 0; i < blockAmount; i++)
            {
                Block block = network.Consensus.ConsensusFactory.CreateBlock();
                block.AddTransaction(new Transaction());
                block.UpdateMerkleRoot();
                block.Header.BlockTime = new DateTimeOffset(blockTime);
                blockTime = blockTime.AddSeconds(incrementSeconds);
                block.Header.HashPrevBlock = prevBlockHash;
                block.Header.Nonce         = nonce;
                block.Header.Bits          = new Target(nbits);
                chain.SetTip(block.Header);
                prevBlockHash = block.GetHash();
            }

            return(chain);
        }
        protected void AddBlocksToChain(ChainIndexer chainIndexer, int blockAmount)
        {
            uint    nonce         = RandomUtils.GetUInt32();
            uint256 prevBlockHash = chainIndexer.Tip.HashBlock;

            (this.ruleContext as UtxoRuleContext).UnspentOutputSet = new UnspentOutputSet();
            (this.ruleContext as UtxoRuleContext).UnspentOutputSet.SetCoins(new UnspentOutput[0]);

            for (int i = 0; i < blockAmount; i++)
            {
                Block       block       = chainIndexer.Network.Consensus.ConsensusFactory.CreateBlock();
                Transaction transaction = chainIndexer.Network.CreateTransaction();
                block.AddTransaction(transaction);
                block.UpdateMerkleRoot();
                block.Header.BlockTime     = new DateTimeOffset(new DateTime(2017, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddDays(i));
                block.Header.HashPrevBlock = prevBlockHash;
                block.Header.Nonce         = nonce;
                chainIndexer.SetTip(block.Header);
                prevBlockHash = block.GetHash();
                (this.ruleContext as UtxoRuleContext).UnspentOutputSet.Update(this.network, transaction, i);
                this.lastAddedTransaction = transaction;
            }
        }
Example #23
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
            });
        }
Example #24
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 ChainIndexer(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.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;

                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.GetHeader(0).HashBlock, chain.GetHeader(1).HashBlock, chain.GetHeader(0).Height);

            return(new TestChainContext {
                MempoolValidator = mempoolValidator, SrcTxs = srcTxs
            });
        }
        /// <summary>Creates the and attaches a new <see cref="ConsensusManagerBehavior"/>.</summary>
        /// <param name="consensusTip">Consensus tip.</param>
        /// <param name="cache">List of cached headers with which behavior is initialized.</param>
        /// <param name="bestReceivedTip">Behavior's expected tip's initial value.</param>
        /// <param name="peerState">Peer connection state returned by the <see cref="INetworkPeer.State"/>.</param>
        /// <param name="connectNewHeadersMethod">Method which is invoked when behavior calls <see cref="IConsensusManager.HeadersPresented"/>.</param>
        /// <returns></returns>
        public ConsensusManagerBehavior CreateAndAttachBehavior(ChainedHeader consensusTip, List <BlockHeader> cache = null,
                                                                ChainedHeader bestReceivedTip = null, NetworkPeerState peerState = NetworkPeerState.HandShaked,
                                                                Func <List <BlockHeader>, bool, ConnectNewHeadersResult> connectNewHeadersMethod = null)
        {
            // Chain
            var chain = new ChainIndexer(KnownNetworks.StraxMain);

            chain.SetTip(consensusTip);

            // Ibd
            var ibdState = new Mock <IInitialBlockDownloadState>();

            ibdState.Setup(x => x.IsInitialBlockDownload()).Returns(() => this.IsIBD);

            // Consensus manager
            var cmMock = new Mock <IConsensusManager>();

            cmMock.Setup(x => x.HeadersPresented(It.IsAny <INetworkPeer>(), It.IsAny <List <BlockHeader> >(), It.IsAny <bool>()))
            .Returns((INetworkPeer p, List <BlockHeader> presentedHeaders, bool triggerDownload) =>
            {
                this.HeadersPresentedCalledTimes++;

                return(connectNewHeadersMethod?.Invoke(presentedHeaders, triggerDownload));
            });

            cmMock.Setup(x => x.Tip).Returns(consensusTip);

            this.testPeerBanning = new TestPeerBanning();

            var connectionManagerMock = new Mock <IConnectionManager>();

            connectionManagerMock.SetupGet(x => x.ConnectionSettings).Returns(new ConnectionManagerSettings(new NodeSettings(KnownNetworks.StraxMain)));

            var cmBehavior = new ConsensusManagerBehavior(chain, ibdState.Object, cmMock.Object, this.testPeerBanning, this.loggerFactory);

            // Peer and behavior
            this.PeerMock = this.CreatePeerMock();

            cmBehavior.Attach(this.PeerMock.Object);

            this.PeerMock.Setup(x => x.Behavior <ConsensusManagerBehavior>()).Returns(() => cmBehavior);
            this.PeerMock.Setup(x => x.State).Returns(peerState);

            if (bestReceivedTip != null)
            {
                cmBehavior.SetPrivatePropertyValue(nameof(cmBehavior.BestReceivedTip), bestReceivedTip);
                cmBehavior.SetPrivatePropertyValue(nameof(cmBehavior.BestSentHeader), bestReceivedTip);
            }

            if (cache != null)
            {
                cmBehavior.SetPrivateVariableValue("cachedHeaders", cache);
            }

            this.GetHeadersPayloadSentTimes = 0;
            this.HeadersPayloadsSent        = new List <HeadersPayload>();
            this.GetHeadersPayloadsSent     = new List <GetHeadersPayload>();

            this.PeerMock.Setup(x => x.SendMessageAsync(It.IsAny <Payload>(), It.IsAny <CancellationToken>())).Returns((Payload payload, CancellationToken token) =>
            {
                if (payload is GetHeadersPayload getHeadersPayload)
                {
                    this.GetHeadersPayloadSentTimes++;
                    this.GetHeadersPayloadsSent.Add(getHeadersPayload);
                }

                if (payload is HeadersPayload headersPayload)
                {
                    this.HeadersPayloadsSent.Add(headersPayload);
                }

                return(Task.CompletedTask);
            });

            this.PeerMock.Setup(x => x.SendMessage(It.IsAny <Payload>())).Callback((Payload payload) =>
            {
                if (payload is GetHeadersPayload getHeadersPayload)
                {
                    this.GetHeadersPayloadSentTimes++;
                    this.GetHeadersPayloadsSent.Add(getHeadersPayload);
                }

                if (payload is HeadersPayload headersPayload)
                {
                    this.HeadersPayloadsSent.Add(headersPayload);
                }
            });

            return(cmBehavior);
        }
Example #26
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
            });
        }