public static ChainIndexer Load(this ChainIndexer chainIndexer, BitcoinStream stream)
        {
            stream.ConsensusFactory = chainIndexer.Network.Consensus.ConsensusFactory;

            try
            {
                int height = 0;
                while (true)
                {
                    uint256.MutableUint256 id = null;
                    stream.ReadWrite <uint256.MutableUint256>(ref id);
                    BlockHeader header = null;
                    stream.ReadWrite(ref header);
                    if (height == 0)
                    {
                        Assert.True(header.GetHash() == chainIndexer.Tip.HashBlock);
                    }
                    else if (chainIndexer.Tip.HashBlock == header.HashPrevBlock && !(header.IsNull && header.Nonce == 0))
                    {
                        chainIndexer.Add(new ChainedHeader(header, id.Value, chainIndexer.Tip));
                    }
                    else
                    {
                        break;
                    }

                    height++;
                }
            }
            catch (EndOfStreamException)
            {
            }

            return(chainIndexer);
        }
        public void Query_Range_During_Reorg_Success(int chainLength, int start, int?end)
        {
            // Simulate a reorg occuring mid-enumeration and check that the query still returns the full old chain.

            var chainIndexer = new ChainIndexer(this.network);

            ChainedHeader[] chainBeforeReorg = this.CreateChain(chainIndexer.Genesis, chainLength);

            // Create a new reorg that removes 3 blocks and adds another 5.
            ChainedHeader[] chainAfterReorg = this.CreateChain(chainBeforeReorg[chainLength - 3], 5);

            chainIndexer.Initialize(chainBeforeReorg.Last());

            var query = new ChainIndexerRangeQuery(chainIndexer);

            IEnumerator <ChainedHeader> enumerator = query.EnumerateRange(start, end).GetEnumerator();

            int position = start;

            while (position < (end ?? chainBeforeReorg.Length))
            {
                enumerator.MoveNext();

                ChainedHeader item = enumerator.Current;

                // Trigger a reorg at position chainLength - 3
                if (position == chainLength - 3)
                {
                    // Remove two headers.
                    chainIndexer.Remove(chainIndexer.Tip);
                    chainIndexer.Remove(chainIndexer.Tip);

                    // Add the reorged chain's headers.
                    // Note: Most likely is that headers are removed only before the enumeration is completed.
                    chainIndexer.Add(chainAfterReorg[1]);
                    chainIndexer.Add(chainAfterReorg[2]);
                    chainIndexer.Add(chainAfterReorg[3]);
                    chainIndexer.Add(chainAfterReorg[4]);
                }

                Assert.Equal(chainBeforeReorg[position], item);

                position++;
            }

            enumerator.Dispose();
        }
        public static ChainedHeaderBlock[] GetBlocks(int count, ChainIndexer chainIndexer, Func <int, ChainedHeaderBlock> block, ChainedHeader previousHeader = null)
        {
            ChainedHeader previous = null;

            if (previousHeader != null)
            {
                previous = previousHeader;
            }

            return(Enumerable.Range(0, count).Select(i =>
            {
                ChainedHeaderBlock chainedHeaderBlock = block(i);
                chainedHeaderBlock.ChainedHeader.SetPrivatePropertyValue("Previous", previous);
                previous = chainedHeaderBlock.ChainedHeader;
                chainIndexer.Add(chainedHeaderBlock.ChainedHeader);
                return chainedHeaderBlock;
            }).ToArray());
        }