예제 #1
0
        private void EnqueueRange(ChainBase chain, ChainedBlock startCumul, int blockCount)
        {
            ListenerTrace.Info("Enqueing from " + startCumul.Height + " " + blockCount + " blocks");
            if (blockCount == 0)
            {
                return;
            }
            var tasks = _IndexTasks
                        .Where(t => chain.FindFork(t.Value.Item1.BlockLocator).Height <= startCumul.Height + blockCount)
                        .Select(t => new BlockRange()
            {
                From   = startCumul.Height,
                Count  = blockCount,
                Target = t.Key
            })
                        .Select(t => _Conf.Topics.InitialIndexing.AddAsync(t))
                        .ToArray();

            try
            {
                Task.WaitAll(tasks);
            }
            catch (AggregateException aex)
            {
                ExceptionDispatchInfo.Capture(aex.InnerException).Throw();
                throw;
            }
        }
예제 #2
0
        /// <summary>
        /// Returns the first common chained block header between two chains.
        /// </summary>
        /// <param name="chainSrc">The source chain.</param>
        /// <param name="otherChain">The other chain.</param>
        /// <returns>First common chained block header or <c>null</c>.</returns>
        private ChainedBlock FindFork(ChainBase chainSrc, ChainBase otherChain)
        {
            if (otherChain == null)
            {
                throw new ArgumentNullException("otherChain");
            }

            return(chainSrc.FindFork(otherChain.Tip.EnumerateToGenesis().Select(o => o.HashBlock)));
        }
예제 #3
0
        public IEnumerator <BlockInfo> GetEnumerator()
        {
            Queue <DateTime> lastLogs    = new Queue <DateTime>();
            Queue <int>      lastHeights = new Queue <int>();

            var fork    = _BlockHeaders.FindFork(_Checkpoint.BlockLocator);
            var headers = _BlockHeaders.EnumerateAfter(fork);

            headers = headers.Where(h => h.Height <= ToHeight);
            var first = headers.FirstOrDefault();

            if (first == null)
            {
                yield break;
            }
            var height = first.Height;

            if (first.Height == 1)
            {
                headers = new[] { fork }.Concat(headers);
                height  = 0;
            }

            foreach (var block in _BlocksRepository.GetBlocks(headers.Select(b => b.HashBlock), CancellationToken))
            {
                var header = _BlockHeaders.GetBlock(height);

                if (block == null)
                {
                    var storeTip = _BlocksRepository.GetStoreTip();
                    if (storeTip != null)
                    {
                        // Store is caught up with Chain but the block is missing from the store.
                        if (header.Header.BlockTime <= storeTip.Header.BlockTime)
                        {
                            throw new InvalidOperationException($"Chained block not found in store (height = { height }). Re-create the block store.");
                        }
                    }
                    // Allow Store to catch up with Chain.
                    break;
                }

                _LastProcessed = header;
                yield return(new BlockInfo()
                {
                    Block = block,
                    BlockId = header.HashBlock,
                    Height = header.Height
                });

                IndexerTrace.Processed(height, Math.Min(ToHeight, _BlockHeaders.Tip.Height), lastLogs, lastHeights);
                height++;
            }
        }
예제 #4
0
        public IEnumerator <BlockInfo> GetEnumerator()
        {
            Queue <DateTime> lastLogs    = new Queue <DateTime>();
            Queue <int>      lastHeights = new Queue <int>();

            var locator = DisableSaving ? new BlockLocator(new List <uint256>()
            {
                _Checkpoint.Genesis
            }) : _Checkpoint.BlockLocator;

            var fork    = _BlockHeaders.FindFork(locator);
            var headers = _BlockHeaders.EnumerateAfter(fork);

            headers = headers.Where(h => h.Height >= FromHeight && h.Height <= ToHeight);
            var first = headers.FirstOrDefault();

            if (first == null)
            {
                yield break;
            }
            var height = first.Height;

            if (first.Height == 1)
            {
                headers = new[] { fork }.Concat(headers);
                height  = 0;
            }

            foreach (var block in _Node.GetBlocks(headers.Select(b => b.HashBlock)))
            {
                var header = _BlockHeaders.GetBlock(height);
                _LastProcessed = header;
                yield return(new BlockInfo()
                {
                    Block = block,
                    BlockId = header.HashBlock,
                    Height = header.Height
                });

                IndexerTrace.Processed(height, Math.Min(ToHeight, _BlockHeaders.Tip.Height), lastLogs, lastHeights);
                height++;
            }
        }
예제 #5
0
 /// <summary>
 /// Get a block fetcher of the specified chain from the specified checkpoint
 /// </summary>
 /// <param name="checkpoint">The checkpoint to load from</param>
 /// <param name="chain">The chain to fetcher (default: the Node's main chain)</param>
 /// <returns>A BlockFetcher for enumerating blocks and saving progression</returns>
 public BlockFetcher GetBlockFetcher(Checkpoint checkpoint, Node node, ChainBase chain = null)
 {
     if (checkpoint == null)
     {
         throw new ArgumentNullException("checkpoint");
     }
     if (node == null)
     {
         throw new ArgumentNullException("node");
     }
     chain = chain ?? this.GetNodeChain(node);
     IndexerTrace.CheckpointLoaded(chain.FindFork(checkpoint.BlockLocator), checkpoint.CheckpointName);
     return(new BlockFetcher(checkpoint, new NodeBlocksRepository(node), chain)
     {
         NeedSaveInterval = this.CheckpointInterval,
         FromHeight = this.FromHeight,
         ToHeight = this.ToHeight
     });
 }
예제 #6
0
        public IEnumerator <BlockInfo> GetEnumerator()
        {
            Queue <DateTime> lastLogs    = new Queue <DateTime>();
            Queue <int>      lastHeights = new Queue <int>();

            var fork = _BlockHeaders.FindFork(_Checkpoint.BlockLocator);

            _LastProcessed = fork;
            var headers = _BlockHeaders.EnumerateAfter(fork);

            headers = headers.Where(h => h.Height >= FromHeight && h.Height <= ToHeight);
            var first = headers.FirstOrDefault();

            if (first == null)
            {
                yield break;
            }
            var height = first.Height;

            if (first.Height == 1)
            {
                headers = new[] { fork }.Concat(headers);
                height  = 0;
            }

            foreach (var block in _BlocksRepository.GetBlocks(headers.Select(b => b.HashBlock), CancellationToken).TakeWhile(b => b != null))
            {
                var header = _BlockHeaders.GetBlock(height);
                _LastProcessed = header;
                yield return(new BlockInfo()
                {
                    Block = block,
                    BlockId = header.HashBlock,
                    Height = header.Height
                });

                IndexerTrace.Processed(height, Math.Min(ToHeight, _BlockHeaders.Tip.Height), lastLogs, lastHeights);
                height++;
            }
        }
예제 #7
0
        public bool Process(ChainBase mainChain, IBlockProvider blockProvider)
        {
            var chainCopy       = Chain.Clone();
            var chainPosition   = chainCopy.Changes.Position;
            var accountCopy     = Account.Clone();
            var accountPosition = accountCopy.Entries.Position;

            bool newChain = false;

            if (!chainCopy.Initialized)
            {
                newChain = true;

                var firstBlock = mainChain.GetBlock(StartHeight);
                chainCopy.Initialize(firstBlock.Header, StartHeight);
            }
            var forkBlock = mainChain.FindFork(chainCopy);

            if (forkBlock.HashBlock != chainCopy.Tip.HashBlock)
            {
                var subChain = chainCopy.CreateSubChain(forkBlock, false, chainCopy.Tip, true);
                chainCopy.SetTip(chainCopy.GetBlock(forkBlock.Height));
                foreach (var e in accountCopy.GetInChain(subChain, true)
                         .Where(c => c.Reason != AccountEntryReason.Lock && c.Reason != AccountEntryReason.Unlock)
                         .Reverse())
                {
                    var neutralized = e.Neutralize();
                    accountCopy.PushAccountEntry(neutralized);
                }
            }

            var unprocessedBlocks = mainChain.ToEnumerable(true)
                                    .TakeWhile(block => block != forkBlock)
                                    .Concat(newChain ? new ChainedBlock[] { forkBlock } : new ChainedBlock[0])
                                    .Reverse().ToArray();

            foreach (var block in unprocessedBlocks)
            {
                List <byte[]> searchedData = new List <byte[]>();
                Scanner.GetScannedPushData(searchedData);
                foreach (var unspent in accountCopy.Unspent)
                {
                    searchedData.Add(unspent.OutPoint.ToBytes());
                }

                var fullBlock = blockProvider.GetBlock(block.HashBlock, searchedData);
                if (fullBlock == null)
                {
                    continue;
                }

                List <Tuple <OutPoint, AccountEntry> > spents = new List <Tuple <OutPoint, AccountEntry> >();
                foreach (var spent in FindSpent(fullBlock, accountCopy.Unspent))
                {
                    var entry = new AccountEntry(AccountEntryReason.Outcome,
                                                 block.HashBlock,
                                                 spent.Spendable, -spent.Spendable.TxOut.Value, spent.TxId);
                    spents.Add(Tuple.Create(entry.Spendable.OutPoint, entry));
                }

                if (CheckDoubleSpend)
                {
                    var spentsDico = spents.ToDictionary(t => t.Item1, t => t.Item2);
                    foreach (var spent in Scanner.FindSpent(fullBlock))
                    {
                        if (!spentsDico.ContainsKey(spent.PrevOut))
                        {
                            return(false);
                        }
                    }
                }

                foreach (var spent in spents)
                {
                    if (accountCopy.PushAccountEntry(spent.Item2) == null)
                    {
                        return(false);
                    }
                }

                foreach (var coins in Scanner.ScanCoins(fullBlock, (int)block.Height))
                {
                    int i = 0;
                    foreach (var output in coins.Coins.Outputs)
                    {
                        if (!output.IsNull)
                        {
                            var entry = new AccountEntry(AccountEntryReason.Income, block.HashBlock,
                                                         new Spendable(new OutPoint(coins.TxId, i), output), output.Value, null);
                            if (accountCopy.PushAccountEntry(entry) == null)
                            {
                                return(false);
                            }
                        }
                        i++;
                    }
                }

                chainCopy.SetTip(block);
            }

            accountCopy.Entries.GoTo(accountPosition);
            Account.PushAccountEntries(accountCopy.Entries);

            chainCopy.Changes.GoTo(chainPosition);
            Chain.PushChanges(chainCopy.Changes);
            return(true);
        }
 /// <summary>
 /// Get a block fetcher of the specified chain from the specified checkpoint
 /// </summary>
 /// <param name="checkpoint">The checkpoint to load from</param>
 /// <param name="chain">The chain to fetcher (default: the Node's main chain)</param>
 /// <returns>A BlockFetcher for enumerating blocks and saving progression</returns>
 public BlockFetcher GetBlockFetcher(Checkpoint checkpoint, Node node, ChainBase chain = null)
 {
     if(checkpoint == null)
         throw new ArgumentNullException("checkpoint");
     if(node == null)
         throw new ArgumentNullException("node");
     chain = chain ?? GetNodeChain(node);
     IndexerTrace.CheckpointLoaded(chain.FindFork(checkpoint.BlockLocator), checkpoint.CheckpointName);
     return new BlockFetcher(checkpoint, new NodeBlocksRepository(node), chain)
     {
         NeedSaveInterval = CheckpointInterval,
         FromHeight = FromHeight,
         ToHeight = ToHeight
     };
 }
예제 #9
0
        static void Main(string[] args)
        {
            try
            {
                var options = new IndexerOptions();
                if (args.Length == 0)
                {
                    System.Console.WriteLine(options.GetUsage());
                }
                if (Parser.Default.ParseArguments(args, options))
                {
                    System.Console.WriteLine("NBitcoin.Indexer " + typeof(AzureIndexer).Assembly.GetName().Version);

                    if (options.All)
                    {
                        options.IndexAddresses    = true;
                        options.IndexBlocks       = true;
                        options.IndexWallets      = true;
                        options.IndexChain        = true;
                        options.IndexTransactions = true;
                    }

                    var indexer = AzureIndexer.CreateIndexer();
                    indexer.Configuration.EnsureSetup();
                    indexer.TaskScheduler      = new CustomThreadPoolTaskScheduler(30, 100);
                    indexer.CheckpointInterval = TimeSpan.Parse(options.CheckpointInterval);
                    indexer.IgnoreCheckpoints  = options.IgnoreCheckpoints;
                    indexer.FromHeight         = options.From;
                    indexer.ToHeight           = options.To;

                    ChainBase chain = null;
                    var       checkpointRepository = indexer.GetCheckpointRepository();
                    checkpointRepository.CheckpointSet = null;
                    if (options.ListCheckpoints)
                    {
                        foreach (var checkpoint in checkpointRepository.GetCheckpointsAsync().Result)
                        {
                            chain = chain ?? indexer.GetNodeChain();
                            var fork = chain.FindFork(checkpoint.BlockLocator);
                            System.Console.WriteLine("Name : " + checkpoint.CheckpointName);
                            if (fork != null)
                            {
                                System.Console.WriteLine("Height : " + fork.Height);
                                System.Console.WriteLine("Hash : " + fork.HashBlock);
                            }
                            System.Console.WriteLine();
                        }
                    }
                    if (options.DeleteCheckpoint != null)
                    {
                        checkpointRepository.GetCheckpoint(options.DeleteCheckpoint).DeleteAsync().Wait();
                        System.Console.WriteLine("Checkpoint " + options.DeleteCheckpoint + " deleted");
                    }
                    if (options.AddCheckpoint != null)
                    {
                        chain = chain ?? indexer.GetNodeChain();
                        var split  = options.AddCheckpoint.Split(':');
                        var name   = split[0];
                        var height = int.Parse(split[1]);
                        var b      = chain.GetBlock(height);

                        var checkpoint = checkpointRepository.GetCheckpoint(name);
                        checkpoint.SaveProgress(b.GetLocator());
                        System.Console.WriteLine("Checkpoint " + options.AddCheckpoint + " saved to height " + b.Height);
                    }
                    if (ConfigurationManager.AppSettings["MainDirectory"] != null)
                    {
                        System.Console.WriteLine("Warning : obsolete appsetting detected, MainDirectory");
                        string[] oldCheckpoints = new string[] { "transactions", "blocks", "wallets", "balances" };
                        foreach (var chk in oldCheckpoints)
                        {
                            var path = GetFilePath(indexer.Configuration, chk);
                            if (File.Exists(path))
                            {
                                var onlineCheckpoint = checkpointRepository.GetCheckpointsAsync().Result.FirstOrDefault(r => r.CheckpointName.ToLowerInvariant() == chk);
                                if (onlineCheckpoint == null)
                                {
                                    onlineCheckpoint = checkpointRepository.GetCheckpoint(indexer.Configuration.CheckpointSetName + "/" + chk);
                                    BlockLocator offlineLocator = new BlockLocator();
                                    offlineLocator.FromBytes(File.ReadAllBytes(path));
                                    onlineCheckpoint.SaveProgress(offlineLocator);
                                    System.Console.WriteLine("Local checkpoint " + chk + " saved in azure");
                                }
                                File.Delete(path);
                                System.Console.WriteLine("Checkpoint File deleted " + path);
                            }
                        }
                    }


                    if (options.IndexBlocks)
                    {
                        chain = chain ?? indexer.GetNodeChain();
                        indexer.IndexBlocks(chain);
                    }
                    if (options.IndexTransactions)
                    {
                        chain = chain ?? indexer.GetNodeChain();
                        indexer.IndexTransactions(chain);
                    }
                    if (options.IndexAddresses)
                    {
                        chain = chain ?? indexer.GetNodeChain();
                        indexer.IndexOrderedBalances(chain);
                    }
                    if (options.IndexWallets)
                    {
                        chain = chain ?? indexer.GetNodeChain();
                        indexer.IndexWalletBalances(chain);
                    }
                    if (options.IndexChain)
                    {
                        chain = chain ?? indexer.GetNodeChain();
                        indexer.IndexChain(chain);
                    }
                }
            }
            catch (ConfigurationErrorsException ex)
            {
                System.Console.WriteLine("LocalSettings.config missing settings : " + ex.Message);
            }
        }