private void SaveAll()
        {
            this.logger.LogDebug("Saving address indexer.");

            lock (this.lockObject)
            {
                this.addressIndexRepository.SaveAllItems();
                this.outpointsRepository.SaveAllItems();

                AddressIndexerTipData tipData = this.tipDataStore.FindAll().FirstOrDefault();

                if (tipData == null)
                {
                    tipData = new AddressIndexerTipData();
                }

                tipData.Height       = this.IndexerTip.Height;
                tipData.TipHashBytes = this.IndexerTip.HashBlock.ToBytes();

                this.tipDataStore.Upsert(tipData);
                this.lastSavedHeight = this.IndexerTip.Height;
            }

            this.logger.LogDebug("Address indexer saved.");
        }
        public void Initialize()
        {
            // The transaction index is needed in the event of a reorg.
            if (!this.storeSettings.AddressIndex)
            {
                this.logger.LogTrace("(-)[DISABLED]");
                return;
            }

            string dbPath = Path.Combine(this.dataFolder.RootPath, AddressIndexerDatabaseFilename);

            FileMode fileMode = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? FileMode.Exclusive : FileMode.Shared;

            this.db = new LiteDatabase(new ConnectionString()
            {
                Filename = dbPath, Mode = fileMode
            });

            this.addressIndexRepository = new AddressIndexRepository(this.db, this.loggerFactory);

            this.logger.LogDebug("Address indexing is enabled.");

            this.tipDataStore = this.db.GetCollection <AddressIndexerTipData>(DbTipDataKey);

            lock (this.lockObject)
            {
                AddressIndexerTipData tipData = this.tipDataStore.FindAll().FirstOrDefault();

                this.logger.LogDebug("Tip data: '{0}'.", tipData == null ? "null" : tipData.ToString());

                this.IndexerTip = tipData == null ? this.chainIndexer.Genesis : this.consensusManager.Tip.FindAncestorOrSelf(new uint256(tipData.TipHashBytes));

                if (this.IndexerTip == null)
                {
                    // This can happen if block hash from tip data is no longer a part of the consensus chain and node was killed in the middle of a reorg.
                    int rewindAmount = this.compactionTriggerDistance / 2;

                    if (rewindAmount > this.consensusManager.Tip.Height)
                    {
                        this.IndexerTip = this.chainIndexer.Genesis;
                    }
                    else
                    {
                        this.IndexerTip = this.consensusManager.Tip.GetAncestor(this.consensusManager.Tip.Height - rewindAmount);
                    }
                }
            }

            this.outpointsRepository = new AddressIndexerOutpointsRepository(this.db, this.loggerFactory);

            this.RewindAndSave(this.IndexerTip);

            this.logger.LogDebug("Indexer initialized at '{0}'.", this.IndexerTip);

            this.indexingTask = Task.Run(async() => await this.IndexAddressesContinuouslyAsync().ConfigureAwait(false));

            this.asyncProvider.RegisterTask($"{nameof(AddressIndexer)}.{nameof(this.indexingTask)}", this.indexingTask);

            this.nodeStats.RegisterStats(this.AddInlineStats, StatsType.Inline, this.GetType().Name, 400);
        }
        public void Initialize()
        {
            // The transaction index is needed in the event of a reorg.
            if (!this.storeSettings.AddressIndex)
            {
                this.logger.LogTrace("(-)[DISABLED]");
                return;
            }

            string dbPath = Path.Combine(this.dataFolder.RootPath, AddressIndexerDatabaseFilename);

            FileMode fileMode = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? FileMode.Exclusive : FileMode.Shared;

            this.db = new LiteDatabase(new ConnectionString()
            {
                Filename = dbPath, Mode = fileMode
            });

            this.addressIndexRepository = new AddressIndexRepository(this.db, this.loggerFactory);

            this.logger.LogDebug("Address indexing is enabled.");

            this.tipDataStore = this.db.GetCollection <AddressIndexerTipData>(DbTipDataKey);

            lock (this.lockObject)
            {
                this.tipData = this.tipDataStore.FindAll().FirstOrDefault();

                if (this.tipData == null)
                {
                    this.logger.LogDebug("Tip was not found, initializing with genesis.");

                    this.tipData = new AddressIndexerTipData()
                    {
                        TipHashBytes = this.network.GenesisHash.ToBytes(), Height = 0
                    };
                    this.tipDataStore.Insert(this.tipData);
                }

                this.IndexerTip = this.consensusManager.Tip.FindAncestorOrSelf(new uint256(this.tipData.TipHashBytes));
            }

            this.outpointsRepository = new AddressIndexerOutpointsRepository(this.db, this.loggerFactory);

            if (this.IndexerTip == null)
            {
                this.IndexerTip = this.consensusManager.Tip.GetAncestor(0);
            }

            this.indexingTask = Task.Run(async() => await this.IndexAddressesContinuouslyAsync().ConfigureAwait(false));

            this.asyncProvider.RegisterTask($"{nameof(AddressIndexer)}.{nameof(this.indexingTask)}", this.indexingTask);

            this.nodeStats.RegisterStats(this.AddInlineStats, StatsType.Inline, 400);
        }