public void Add(int height, Block block)
        {
            foreach (var spk in TrackedScriptPubKeys)
            {
                TrackIfFindRelatedTransactions(spk, height, block);
            }

            FullBlockBuffer.AddOrReplace(height, block);
            HashSet <uint256> notFoundTransactions = GetNotYetFoundTrackedTransactions();
            HashSet <uint256> foundTransactions    = new HashSet <uint256>();

            foreach (var txid in notFoundTransactions)
            {
                if (block.Transactions.Any(x => x.GetHash().Equals(txid)))
                {
                    foundTransactions.Add(txid);
                }
            }
            MerkleBlock merkleProof  = foundTransactions.Count == 0 ? block.Filter() : block.Filter(foundTransactions.ToArray());
            var         partialBlock = new PartialBlock(height, merkleProof);

            foreach (var txid in foundTransactions)
            {
                foreach (var tx in block.Transactions)
                {
                    if (tx.GetHash().Equals(txid))
                    {
                        partialBlock.Transactions.Add(tx);
                    }
                }
            }

            Chain.AddOrReplace(partialBlock.Height, partialBlock);
        }
        /// <summary> Track a transaction </summary>
        /// <returns>False if not found. When confirms, it starts tracking. If too old you need to resync the chain.</returns>
        public bool Track(uint256 transactionId)
        {
            if (TrackedTransactions.Keys.Contains(transactionId))
            {
                var tracked = TrackedTransactions.First(x => x.Key.Equals(transactionId));
                if (tracked.Value == -1)
                {
                    return(false);
                }
                else
                {
                    return(true);
                }
            }

            TrackedTransactions.AddOrReplace(transactionId, -1);

            Transaction transaction = null;
            Block       block       = null;

            foreach (var b in FullBlockBuffer.Values)
            {
                Transaction tx = b.Transactions.FirstOrDefault(x => transactionId.Equals(x.GetHash()));
                if (tx != default(Transaction))
                {
                    transaction = tx;
                    block       = b;
                    break;
                }
            }

            // This warning doesn't make sense:
            // ReSharper disable once ConditionIsAlwaysTrueOrFalse
            if (block == null || transaction == null)
            {
                return(false);
            }
            else
            {
                PartialBlock partialBlock =
                    Chain.First(x => block.Header.GetHash().Equals(x.Value.MerkleProof.Header.GetHash())).Value;

                partialBlock.Transactions.Add(transaction);
                var transactionHashes = partialBlock.MerkleProof.PartialMerkleTree.GetMatchedTransactions() as HashSet <uint256>;
                transactionHashes.Add(transaction.GetHash());
                partialBlock.MerkleProof = block.Filter(transactionHashes.ToArray());

                return(true);
            }
        }
        public async Task LoadAsync(string partialChainFolderPath)
        {
            await Saving.WaitAsync().ConfigureAwait(false);

            try
            {
                if (!Directory.Exists(partialChainFolderPath))
                {
                    throw new DirectoryNotFoundException($"No Blockchain found at {partialChainFolderPath}");
                }

                var tspb = Path.Combine(partialChainFolderPath, FilesNames.TrackedScriptPubKeys.ToString());
                if (File.Exists(tspb) && new FileInfo(tspb).Length != 0)
                {
                    foreach (var line in File.ReadAllLines(tspb))
                    {
                        TrackedScriptPubKeys.Add(new Script(line));
                    }
                }

                var tt = Path.Combine(partialChainFolderPath, FilesNames.TrackedTransactions.ToString());
                if (File.Exists(tt) && new FileInfo(tt).Length != 0)
                {
                    foreach (var line in File.ReadAllLines(tt))
                    {
                        var pieces = line.Split(':');
                        TrackedTransactions.TryAdd(new uint256(pieces[0]), int.Parse(pieces[1]));
                    }
                }

                var pbc = Path.Combine(partialChainFolderPath, FilesNames.PartialBlockChain.ToString());
                if (File.Exists(pbc) && new FileInfo(pbc).Length != 0)
                {
                    foreach (var block in Help.Separate(File.ReadAllBytes(pbc), blockSep))
                    {
                        PartialBlock pb = new PartialBlock().FromBytes(block);

                        Chain.TryAdd(pb.Height, pb);
                    }
                }
            }
            finally
            {
                Saving.Release();
            }
        }