Ejemplo n.º 1
0
 static void ProcessPoWReward(Network.Models.Transaction tx, Model.BCExplorerContext context)
 {
     foreach (var vout in tx.TransactionsOut)
     {
         //var vout = tx.TransactionsOut;
         var           address  = vout.Address;
         var           amount   = vout.Value;
         Model.Address existing = context.Addresses.Find(address);
         if (existing == null)
         {
             var newAddress = new Model.Address
             {
                 Id      = address,
                 Balance = amount,
                 LastModifiedBlockHeight = (int)tx.Block.Height,
             };
             InsertAddressIfShouldBeIndexed(newAddress, context);
             UpdateTxIdBlob(newAddress, tx.TransactionId, tx.Time, newAddress.Balance, amount, context);
             return;
         }
         existing.Balance += amount;
         existing.LastModifiedBlockHeight = (int)tx.Block.Height;
         UpdateTxIdBlob(existing, tx.TransactionId, tx.Time, existing.Balance, amount, context);
     }
 }
Ejemplo n.º 2
0
        static async Task Index(CancellationToken token)
        {
            bool wait = false;

            while (!token.IsCancellationRequested)
            {
                if (wait)
                {
                    _logger.Log(LogLevel.Information, $"Waiting for {_interval} seconds.");
                    Thread.Sleep(TimeSpan.FromSeconds(_interval));
                    wait = false;
                }

                try
                {
                    using (var context = new Model.BCExplorerContext())
                    {
                        using (IDbContextTransaction dbtx = context.Database.BeginTransaction(System.Data.IsolationLevel.Serializable))
                        {
                            if (await context.Blocks.AnyAsync())
                            {
                                _currentBlockNumber = await context.Blocks.MaxAsync(p => p.Id);

                                _currentBlockHeight = _currentBlockNumber - 1;
                                _currentBlockHeight++;
                                _currentBlockNumber++;
                            }
                        }

                        var tipHash = await _client.GetBestBlockHashAsync();

                        var tip = await _client.GetBlockAsync(tipHash);

                        if (_currentBlockHeight > tip.Height - 3)
                        {
                            Console.WriteLine($"Block at height {_currentBlockHeight} is not yet mature enough....");
                            wait = true;
                            continue;
                        }

                        string blockHash = await _client.GetBlockHashAsync(_currentBlockHeight);

                        var result = await IndexBlock(context, blockHash);

                        if (!result)
                        {
                            return;
                        }
                    }
                }

                catch (Exception e)
                {
                    _logger.Log(LogLevel.Error, $"Error creating transaction: {e.Message}");
                    _logger.Log(LogLevel.Error, $"Suspending for {_suspendInterval} seconds.");
                    Thread.Sleep(TimeSpan.FromSeconds(_suspendInterval));
                    _logger.Log(LogLevel.Error, $"Retrying...");
                }
            }
        }
Ejemplo n.º 3
0
        public async Task <Address> GetAddress(string id, int page, int itemsOnPage)
        {
            using (var context = new Model.BCExplorerContext())
            {
                var addressFromDb = await context.Addresses.FindAsync(id);

                if (addressFromDb == null)
                {
                    return(null);
                }

                List <Transaction> transactions = new List <Transaction>();
                var addressTransactions         = _transactionService.GetTransactionsForAddress(id, page, itemsOnPage);
                var transactionCount            = _transactionService.GetTransactionCountForAddress(id);
                var totalSent     = _transactionService.GetTotalSent(id);
                var totalReceived = _transactionService.GetTotalReceived(id);

                var address = new Address()
                {
                    Id      = id,
                    Balance = addressFromDb.Balance,
                    LastModifiedBlockHeight = addressFromDb.LastModifiedBlockHeight,
                    Transactions            = addressTransactions,
                    TotalTransactions       = transactionCount,
                    TotalSent     = totalSent,
                    TotalReceived = totalReceived
                };
                return(address);
            }
        }
Ejemplo n.º 4
0
        public async Task <Address> GetAddress(string id)
        {
            using (var context = new Model.BCExplorerContext())
            {
                var addressFromDb = await context.Addresses.FindAsync(id);

                if (addressFromDb == null)
                {
                    return(null);
                }

                List <Transaction> transactions = new List <Transaction>();
                var addressTransactions         = _transactionService.GetTransactionsForAddress(id);

                var address = new Address()
                {
                    Id      = id,
                    Balance = addressFromDb.Balance,
                    LastModifiedBlockHeight = addressFromDb.LastModifiedBlockHeight,
                    Transactions            = addressTransactions,
                    TotalTransactions       = addressTransactions.Count,
                };
                return(address);
            }
        }
Ejemplo n.º 5
0
        public async Task <List <Block> > GetLatestBlocks(int count)
        {
            List <Block> latestBlocks = new List <Block>();

            using (Model.BCExplorerContext context = new Model.BCExplorerContext())
            {
                var blocks = await context.Blocks.OrderByDescending(p => p.Id).Take(count).ToListAsync();

                foreach (var block in blocks)
                {
                    var blockData = JsonConvert.DeserializeObject <RpcResult <BlockResult> >(block.BlockData);
                    var b         = new Block
                    {
                        Bits              = blockData.Result.Bits,
                        Chainwork         = blockData.Result.Chainwork,
                        Confirmations     = blockData.Result.Confirmations,
                        Difficulty        = blockData.Result.Difficulty,
                        Hash              = blockData.Result.Hash,
                        Height            = blockData.Result.Height,
                        MerkleRoot        = blockData.Result.Merkleroot,
                        NextBlock         = blockData.Result.Nextblockhash,
                        Nonce             = blockData.Result.Nonce,
                        PreviousBlock     = blockData.Result.Previousblockhash,
                        Size              = blockData.Result.Size,
                        Time              = blockData.Result.GetTime(),
                        Age               = blockData.Result.GetAge(),
                        TotalTransactions = blockData.Result.Transactions.Count,
                        Version           = (uint)blockData.Result.Version
                    };

                    latestBlocks.Add(b);
                }
            }
            return(latestBlocks);
        }
Ejemplo n.º 6
0
        private static async Task <bool> IndexBlock(Model.BCExplorerContext context, string blockHash)
        {
            _logger.LogInformation($"Processing block at height {_currentBlockHeight}: {blockHash}");

            BlockResult blockResult = await _client.GetBlockAsync(blockHash);

            if (blockResult == null)
            {
                _logger.LogWarning($"Warning - could not retrieve block at height {_currentBlockHeight}: {blockHash}");
                return(false);
            }

            var block = new Model.Block
            {
                Id        = _currentBlockNumber,
                Height    = _currentBlockHeight,
                BlockHash = blockHash,
                BlockData = blockResult.OriginalJson
            };

            context.Blocks.Add(block);

            if (_currentBlockHeight == 0)
            {
                // for the transaction in the genesis block, we can't pull transaction data, so this is all we know
                var genesisBlockTransaction = new Model.Transaction {
                    Block = block, Id = blockResult.Transactions[0]
                };
                context.Transactions.Add(genesisBlockTransaction);
                _currentBlockHeight++;
                _currentBlockNumber++;
                context.SaveChanges();
                return(true);
            }

            List <BCExplorer.Network.Models.Transaction> blockTransactions = new List <BCExplorer.Network.Models.Transaction>();

            foreach (var txid in blockResult.Transactions)
            {
                var transaction = await _transactionProvider.GetTransaction(txid);

                transaction.Block = new BCExplorer.Network.Models.Block {
                    Height = _currentBlockHeight
                };
                blockTransactions.Add(transaction);
            }

            foreach (var blockTx in blockTransactions)
            {
                ProcessTransaction(blockTx, context);
            }

            context.SaveChanges();
            _currentBlockHeight++;
            _currentBlockNumber++;
            return(true);
        }
Ejemplo n.º 7
0
 static void InsertAddressIfShouldBeIndexed(Model.Address address, Model.BCExplorerContext context)
 {
     if (address.Id.StartsWith("OP_RETURN", StringComparison.OrdinalIgnoreCase))
     {
         address.Id = "OP_RETURN";
     }
     if (address.Id != TransactionProvider.NON_STANDARD)
     {
         context.Addresses.Add(address);
     }
 }
Ejemplo n.º 8
0
        private static void ProcessMoneyTransfer(Network.Models.Transaction tx,
                                                 Model.BCExplorerContext context)
        {
            List <Network.Models.Transaction.TransactionIn> vins = tx.TransactionsIn;
            List <string> inAdresses = new List <string>();

            foreach (var vin in vins)
            {
                Model.Address existing = context.Addresses.Find(vin.PrevVOutFetchedAddress);

                if (existing == null)
                {
                    _logger.LogWarning($"{vin.PrevVOutFetchedAddress} could not be found.");
                    continue;
                }

                inAdresses.Add(existing.Id);
                existing.Balance -= vin.PrevVOutFetchedValue;
                existing.LastModifiedBlockHeight = (int)tx.Block.Height;
                UpdateTxIdBlob(existing, tx.TransactionId, tx.Time, existing.Balance, -vin.PrevVOutFetchedValue, context);
            }
            IList <Network.Models.Transaction.TransactionOut> vouts = tx.TransactionsOut;

            foreach (var vout in vouts)
            {
                string outAdress = vout.Address;
                if (outAdress.StartsWith("OP_RETURN", StringComparison.OrdinalIgnoreCase))
                {
                    outAdress = "OP_RETURN";
                }

                Model.Address existing = context.Addresses.Find(outAdress);
                if (existing != null)
                {
                    existing.Balance += vout.Value;
                    if (!inAdresses.Contains(existing.Id))
                    {
                        UpdateTxIdBlob(existing, tx.TransactionId, tx.Time, existing.Balance, vout.Value, context);
                        existing.LastModifiedBlockHeight = (int)tx.Block.Height;
                    }
                }
                else
                {
                    var newAddress = new Model.Address
                    {
                        Id      = vout.Address,
                        Balance = vout.Value,
                        LastModifiedBlockHeight = (int)tx.Block.Height
                    };
                    InsertAddressIfShouldBeIndexed(newAddress, context);
                    UpdateTxIdBlob(newAddress, tx.TransactionId, tx.Time, newAddress.Balance, vout.Value, context);
                }
            }
        }
Ejemplo n.º 9
0
        private static void UpdateTxIdBlob(Model.Address existing, string transactionId,
                                           DateTime time,
                                           decimal balance,
                                           decimal amount,
                                           Model.BCExplorerContext context)
        {
            var at = new Model.AddressTransaction()
            {
                Address       = existing,
                TimeStamp     = time,
                Balance       = balance,
                Amount        = amount,
                TransactionId = transactionId
            };

            context.AddressTransactions.Add(at);
        }
Ejemplo n.º 10
0
        static void ProcessTransaction(Network.Models.Transaction blockTx, Model.BCExplorerContext context)
        {
            switch (blockTx.TransactionType)
            {
            case TransactionType.PoW_Reward_Coinbase:
                ProcessPoWReward(blockTx, context);
                break;

            case TransactionType.PoS_Reward:
                ProcessStakingReward(blockTx, context);
                break;

            case TransactionType.Money:
                ProcessMoneyTransfer(blockTx, context);
                break;

            default:
                throw new IndexOutOfRangeException("Unsupported TransactionType.");
            }
        }
Ejemplo n.º 11
0
        static void ProcessStakingReward(Network.Models.Transaction tx, Model.BCExplorerContext context)
        {
            foreach (var vin in tx.TransactionsIn)
            {
                //var vin = tx.TransactionsIn[0];
                var inAddress  = vin.PrevVOutFetchedAddress;
                var oldBalance = vin.PrevVOutFetchedValue;

                var outValue1 = tx.TransactionsOut[1].Value;
                var outValue2 = tx.TransactionsOut[2].Value;
                var change    = outValue1 + outValue2 - oldBalance;

                // we can assume that only pre-existing addresses get a staking reward
                Model.Address existing = context.Addresses.Find(inAddress);
                if (existing == null)
                {
                    _logger.LogError($"{vin.PrevVOutFetchedAddress} could not be found.");
                }

                existing.Balance += change;
                existing.LastModifiedBlockHeight = (int)tx.Block.Height;
                UpdateTxIdBlob(existing, tx.TransactionId, tx.Time, existing.Balance, change, context);
            }
        }