public IActionResult GetBalancesOverAmount(int blockHeight, decimal amount)
        {
            Money thresholdBalance = Money.Coins(amount);

            CoinviewContext            coinView = GetCoinviewAtHeight(blockHeight);
            Dictionary <Script, Money> balances = GetBalances(coinView);

            List <Script> addressesWithThreshold = balances
                                                   .Where(x => x.Value >= thresholdBalance)
                                                   .Select(x => x.Key)
                                                   .ToList();

            List <string> base58Addresses = new List <string>();

            foreach (Script script in addressesWithThreshold)
            {
                GetSenderResult senderResult = this.GetAddressFromScript(script);

                if (senderResult.Success)
                {
                    base58Addresses.Add(senderResult.Sender.ToBase58Address(this.network));
                }
                else
                {
                    this.logger.LogWarning($"{script} has a balance of {balances[script]} but is not a P2PK or P2PKH.");
                }
            }

            return(Json(base58Addresses));
        }
        private void AdjustCoinviewForBlock(Block block, CoinviewContext coinView)
        {
            foreach (Transaction tx in block.Transactions)
            {
                // Add outputs
                for (int i = 0; i < tx.Outputs.Count; i++)
                {
                    TxOut output = tx.Outputs[i];

                    if (output.Value > 0)
                    {
                        coinView.UnspentOutputs.Add(new OutPoint(tx, i));
                        coinView.Transactions[tx.GetHash()] = tx;
                    }
                }

                // Spend inputs
                if (!tx.IsCoinBase)
                {
                    foreach (TxIn txIn in tx.Inputs)
                    {
                        if (!coinView.UnspentOutputs.Remove(txIn.PrevOut))
                        {
                            throw new Exception("Spending PrevOut that isn't in Coinview at this time.");
                        }
                    }
                }
            }
        }
        private CoinviewContext GetCoinviewAtHeight(int blockHeight)
        {
            var coinView = new CoinviewContext();

            const int batchSize = 1000;
            IEnumerable <ChainedHeader> allBlockHeaders = this.chainIndexer.EnumerateToTip(this.chainIndexer.Genesis);

            int totalBlocksCounted = 0;

            int i = 0;

            while (true)
            {
                List <ChainedHeader> headers = allBlockHeaders.Skip(i * batchSize).Take(batchSize).ToList();

                List <Block> blocks = this.blockStore.GetBlocks(headers.Select(x => x.HashBlock).ToList());

                foreach (Block block in blocks)
                {
                    this.AdjustCoinviewForBlock(block, coinView);
                    totalBlocksCounted += 1;

                    // We have reached the blockheight asked for
                    if (totalBlocksCounted >= blockHeight)
                    {
                        break;
                    }
                }

                // We have seen every block up to the tip or our blockheight
                if (headers.Count < batchSize || totalBlocksCounted >= blockHeight)
                {
                    break;
                }

                // Give the user some feedback every 10k blocks
                if (i % 10 == 9)
                {
                    this.logger.LogInformation($"Counted {totalBlocksCounted} blocks for balance calculation.");
                }

                i++;
            }

            return(coinView);
        }
 private Dictionary <Script, Money> GetBalances(CoinviewContext coinView)
 {
     return(coinView.UnspentOutputs.Select(x => coinView.Transactions[x.Hash].Outputs[x.N]) // Get the full output data for each known unspent output.
            .GroupBy(x => x.ScriptPubKey)                                                   // Group them by Script aka address.
            .ToDictionary(x => x.Key, x => (Money)x.Sum(y => y.Value)));                    // Find the total value owned by this address.
 }