Exemplo n.º 1
0
        private async Task ProcessFilterModelAsync(FilterModel filterModel, CancellationToken cancel)
        {
            if (ProcessedBlocks.Contains(filterModel.BlockHash))
            {
                return;
            }

            var matchFound = filterModel.Filter.MatchAny(KeyManager.GetKeys().Select(x => x.GetP2wpkhScript().ToCompressedBytes()), filterModel.FilterKey);

            if (!matchFound)
            {
                return;
            }

            Block currentBlock = await GetOrDownloadBlockAsync(filterModel.BlockHash, cancel);             // Wait until not downloaded.

            WalletBlocks.AddOrReplace(filterModel.BlockHeight, filterModel.BlockHash);

            if (currentBlock.GetHash() == WalletBlocks.Last().Value)             // If this is the latest block then no need for deep gothrough.
            {
                ProcessBlock(filterModel.BlockHeight, currentBlock);
            }
            else             // must go through all the blocks in order
            {
                foreach (var blockRef in WalletBlocks)
                {
                    var block = await GetOrDownloadBlockAsync(blockRef.Value, CancellationToken.None);

                    ProcessedBlocks.Clear();
                    Coins.Clear();
                    ProcessBlock(blockRef.Key, block);
                }
            }
        }
Exemplo n.º 2
0
        private void ProcessBlock(Height height, Block block)
        {
            var keys = KeyManager.GetKeys().ToList();

            foreach (var tx in block.Transactions)
            {
                ProcessTransaction(new SmartTransaction(tx, height), keys);
            }

            ProcessedBlocks.Add(block.GetHash());
        }
Exemplo n.º 3
0
        private async Task HandleMissedBlocksAsync(Block arrivedBlock)
        {
            List <Block> missedBlocks = new List <Block>
            {
                arrivedBlock
            };
            var currentHeader = arrivedBlock.Header;

            while (true)
            {
                Block missedBlock = await RpcClient.GetBlockAsync(currentHeader.HashPrevBlock).ConfigureAwait(false);

                if (missedBlocks.Count > 144)
                {
                    missedBlocks.RemoveFirst();
                }

                currentHeader = missedBlock.Header;
                currentHeader.PrecomputeHash(false, true);
                missedBlocks.Add(missedBlock);

                if (currentHeader.GetHash() == Network.GenesisHash)
                {
                    var processedBlocksClone    = ProcessedBlocks.ToArray();
                    var processedReversedBlocks = processedBlocksClone.Reverse();
                    ProcessedBlocks.Clear();
                    foreach (var processedBlock in processedReversedBlocks)
                    {
                        OnReorg?.Invoke(this, processedBlock);
                    }
                    break;
                }

                // If we found the proper chain.
                var foundPrevBlock = ProcessedBlocks.FirstOrDefault(x => x.GetHash() == currentHeader.HashPrevBlock);
                if (foundPrevBlock != null)
                {
                    // If the last block hash is not what we found, then we missed a reorg also.
                    if (foundPrevBlock.GetHash() != ProcessedBlocks.Last().GetHash())
                    {
                        ReorgToBlock(foundPrevBlock);
                    }

                    break;
                }
            }

            missedBlocks.Reverse();
            foreach (var b in missedBlocks)
            {
                AddBlock(b);
            }
        }
Exemplo n.º 4
0
        private void ReorgToBlock(BlockHeader correctBlock)
        {
            var index         = ProcessedBlocks.IndexOf(correctBlock);
            int countToRemove = ProcessedBlocks.Count - (index + 1);
            var toRemoves     = ProcessedBlocks.TakeLast(countToRemove).ToList();

            ProcessedBlocks.RemoveRange(index + 1, countToRemove);
            toRemoves.Reverse();
            foreach (var toRemove in toRemoves)
            {
                OnReorg?.Invoke(this, toRemove);
            }
        }
Exemplo n.º 5
0
        private async void IndexDownloader_ReorgedAsync(object sender, uint256 invalidBlockHash)
        {
            using (HandleFiltersLock.Lock())
                using (WalletBlocksLock.Lock())
                {
                    var elem = WalletBlocks.SingleOrDefault(x => x.Value == invalidBlockHash);
                    await DeleteBlockAsync(invalidBlockHash);

                    WalletBlocks.RemoveByValue(invalidBlockHash);
                    ProcessedBlocks.Remove(invalidBlockHash);
                    if (elem.Key != null)
                    {
                        foreach (var toRemove in Coins.Where(x => x.Height == elem.Key).ToHashSet())
                        {
                            RemoveCoinRecursively(toRemove);
                        }
                    }
                }
        }
Exemplo n.º 6
0
        protected override async Task <uint256> ActionAsync(CancellationToken cancel)
        {
            var bestBlockHash = await RpcClient.GetBestBlockHashAsync().ConfigureAwait(false);

            // If there's no new block.
            if (bestBlockHash == Status)
            {
                return(bestBlockHash);
            }

            var arrivedBlock = await RpcClient.GetBlockAsync(bestBlockHash).ConfigureAwait(false);

            var arrivedHeader = arrivedBlock.Header;

            arrivedHeader.PrecomputeHash(false, true);

            // If we haven't processed any block yet then we're processing the first seven to avoid accidental reogs.
            // 7 blocks, because
            //   - That was the largest recorded reorg so far.
            //   - Reorg in this point of time would be very unlikely anyway.
            //   - 100 blocks would be the sure, but that'd be a huge performance overkill.
            if (!ProcessedBlocks.Any())
            {
                var reorgProtection7Headers = new List <BlockHeader>()
                {
                    arrivedHeader
                };

                var currentHeader = arrivedHeader;
                while (reorgProtection7Headers.Count < 7 && currentHeader.GetHash() != Network.GenesisHash)
                {
                    currentHeader = await RpcClient.GetBlockHeaderAsync(currentHeader.HashPrevBlock).ConfigureAwait(false);

                    reorgProtection7Headers.Add(currentHeader);
                }

                reorgProtection7Headers.Reverse();
                foreach (var header in reorgProtection7Headers)
                {
                    // It's initialization. Don't notify about it.
                    AddHeader(header);
                }

                return(bestBlockHash);
            }

            // If block was already processed return.
            if (ProcessedBlocks.Any(x => x.GetHash() == arrivedHeader.GetHash()))
            {
                return(bestBlockHash);
            }

            // If this block follows the proper order then add.
            if (ProcessedBlocks.Last().GetHash() == arrivedHeader.HashPrevBlock)
            {
                AddBlock(arrivedBlock);
                return(bestBlockHash);
            }

            // Else let's sort out things.
            var foundPrevBlock = ProcessedBlocks.FirstOrDefault(x => x.GetHash() == arrivedHeader.HashPrevBlock);

            // Missed notifications on some previous blocks.
            if (foundPrevBlock != null)
            {
                // Reorg happened.
                ReorgToBlock(foundPrevBlock);
                AddBlock(arrivedBlock);
                return(bestBlockHash);
            }

            await HandleMissedBlocksAsync(arrivedBlock);

            return(bestBlockHash);
        }
Exemplo n.º 7
0
 private void AddHeader(BlockHeader block)
 {
     ProcessedBlocks.Add(block);
 }