public void Query_Range_Negative_Count_Empty()
        {
            var chainIndexer = new ChainIndexer(this.network);

            var query = new ChainIndexerRangeQuery(chainIndexer);

            // Must call ToList here or nothing gets enumerated
            Assert.Empty(query.EnumerateRange(100, 10));
        }
        public void Query_Range_To_Header_Null()
        {
            var chainIndexer = new ChainIndexer(this.network);

            var chain = this.CreateChain(chainIndexer.Genesis, 5);

            chainIndexer.Initialize(chain.Last());

            var query = new ChainIndexerRangeQuery(chainIndexer);

            // Chain length is only 5, so this should return all elements.
            var result = query.EnumerateRange(0, 10);

            Assert.Equal(5, result.Count());
        }
        public void Query_Range_From_Header_Null_Empty()
        {
            var chainIndexer = new ChainIndexer(this.network);

            var chain = this.CreateChain(chainIndexer.Genesis, 1);

            chainIndexer.Initialize(chain.Last());

            var query = new ChainIndexerRangeQuery(chainIndexer);

            // Chain length is only the genesis block, so this should fail.
            var result = query.EnumerateRange(1, 10);

            Assert.Empty(result);
        }
        public List <Receipt> SearchReceipts(string contractAddress, int fromBlock = 0, int?toBlock = null, IEnumerable <byte[]> topics = null)
        {
            topics = topics?.Where(topic => topic != null) ?? Enumerable.Empty <byte[]>();

            // Build the bytes we can use to check for this event.
            // TODO use address.ToUint160 extension when it is in .Core.
            var addressUint160 = new uint160(new BitcoinPubKeyAddress(contractAddress, this.network).Hash.ToBytes());

            var chainIndexerRangeQuery = new ChainIndexerRangeQuery(this.chainIndexer);

            // WORKAROUND
            // This is a workaround due to the BlockStore.GetBlocks returning null for genesis.
            // We don't ever expect any receipts in the genesis block, so it's safe to ignore it.
            if (fromBlock == 0)
            {
                fromBlock = 1;
            }

            // Loop through all headers and check bloom.
            IEnumerable <ChainedHeader> blockHeaders = chainIndexerRangeQuery.EnumerateRange(fromBlock, toBlock);

            // Match the blocks where the combination of all receipts passes the filter.
            var matches = new List <ChainedHeader>();

            foreach (ChainedHeader chainedHeader in blockHeaders)
            {
                var scHeader = (ISmartContractBlockHeader)chainedHeader.Header;

                if (scHeader.LogsBloom.Test(addressUint160, topics))
                {
                    matches.Add(chainedHeader);
                }
            }

            // For all matching headers, get the block from local db.
            List <uint256>        matchedBlockHashes = matches.Select(m => m.HashBlock).ToList();
            List <NBitcoin.Block> blocks             = this.blockStore.GetBlocks(matchedBlockHashes);

            List <uint256> transactionHashes = blocks
                                               .SelectMany(block => block.Transactions)
                                               .Select(t => t.GetHash())
                                               .ToList();

            IList <Receipt> receipts = this.receiptRepository.RetrieveMany(transactionHashes);

            // For each block, get all receipts, and if they match, add to list to return.
            return(this.matcher.MatchReceipts(receipts, addressUint160, topics));
        }
        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 void Query_Range_Success(int chainLength, int start, int?end)
        {
            var chainIndexer = new ChainIndexer(this.network);

            var chain = this.CreateChain(chainIndexer.Genesis, chainLength);

            chainIndexer.Initialize(chain.Last());

            var query = new ChainIndexerRangeQuery(chainIndexer);

            var result = query.EnumerateRange(start, end).ToList();

            for (var i = 0; i < result.Count; i++)
            {
                Assert.Equal(chain[start + i], result[i]);
            }

            Assert.Equal((end ?? (chainLength - 1)) - start + 1, result.Count);
        }