/// <summary>
        /// Tries to get and remove the next block from pending storage. If it exists
        /// then add it to <see cref="ProcessPendingStorageContext.PendingBlockPairsToStore"/>.
        /// This will also check if the next block can be processed.
        /// </summary>
        /// <param name="context"><see cref="ProcessPendingStorageContext"/></param>
        private StepResult PrepareNextBlockFromPendingStorage(ProcessPendingStorageContext context)
        {
            var blockIsInPendingStorage = this.BlockStoreLoop.PendingStorage.TryRemove(context.NextChainedBlock.HashBlock, out context.PendingBlockPairToStore);

            if (blockIsInPendingStorage)
            {
                context.PendingBlockPairsToStore.Push(context.PendingBlockPairToStore);
                context.PendingStorageBatchSize += context.PendingBlockPairToStore.Block.GetSerializedSize();
            }

            return(context.CanProcessNextBlock() ? StepResult.Next : StepResult.Stop);
        }
        /// <summary>
        /// Store missing blocks and remove them from pending blocks and set the Store's tip to <see cref="ProcessPendingStorageContext.NextChainedBlock"/>
        /// </summary>
        /// <param name="context"><see cref="ProcessPendingStorageContext"/></param>
        private async Task PushBlocksToRepositoryAsync(ProcessPendingStorageContext context)
        {
            this.logger.LogDebug(context.ToString());

            await this.BlockStoreLoop.BlockRepository.PutAsync(context.PendingBlockPairsToStore.First().ChainedBlock.HashBlock, context.PendingBlockPairsToStore.Select(b => b.Block).ToList());

            this.BlockStoreLoop.SetStoreTip(context.PendingBlockPairsToStore.First().ChainedBlock);

            context.PendingBlockPairToStore = null;
            context.PendingBlockPairsToStore.Clear();
            context.PendingStorageBatchSize = 0;
        }
        /// <inheritdoc/>
        internal override async Task <StepResult> ExecuteAsync(ChainedBlock nextChainedBlock, CancellationToken cancellationToken, bool disposeMode)
        {
            this.logger.LogTrace("({0}:'{1}',{2}:{3})", nameof(nextChainedBlock), nextChainedBlock, nameof(disposeMode), disposeMode);

            var context = new ProcessPendingStorageContext(this.logger, this.BlockStoreLoop, nextChainedBlock, cancellationToken);

            // Next block does not exist in pending storage, continue onto the download blocks step.
            if (!this.BlockStoreLoop.PendingStorage.ContainsKey(context.NextChainedBlock.HashBlock))
            {
                this.logger.LogTrace("(-)[NOT_FOUND]:{0}", StepResult.Next);
                return(StepResult.Next);
            }

            // In case of IBD do not save every single block- persist them in batches.
            if (this.BlockStoreLoop.PendingStorage.Count < BlockStoreLoop.PendingStorageBatchThreshold &&
                !disposeMode && this.BlockStoreLoop.InitialBlockDownloadState.IsInitialBlockDownload())
            {
                return(StepResult.Stop);
            }

            while (!context.CancellationToken.IsCancellationRequested)
            {
                StepResult result = this.PrepareNextBlockFromPendingStorage(context);
                if (result == StepResult.Stop)
                {
                    break;
                }

                if (context.PendingStorageBatchSize > BlockStoreLoop.MaxPendingInsertBlockSize)
                {
                    await this.PushBlocksToRepositoryAsync(context).ConfigureAwait(false);
                }
            }

            if (context.PendingBlockPairsToStore.Any())
            {
                await this.PushBlocksToRepositoryAsync(context).ConfigureAwait(false);
            }

            return(StepResult.Continue);
        }