/// <summary> /// Pre-fetch UTXOs for a block and some blocks with higher height. /// <para> /// This task runs in the background. /// </para> /// </summary> /// <param name="header">Header of a block that is about to be partially validated and that requires pre-fetching.</param> private Task OnHeaderEnqueued(ChainedHeader header, CancellationToken cancellation) { ChainedHeader currentHeader = header; // Go Lookahead blocks ahead of current header and get block for pre-fetching. // There might be several blocks at height of header.Height + Lookahead but // only first one will be pre-fetched since pre-fetching is in place mostly to // speed up IBD. for (int i = 0; i < Lookahead; i++) { if (currentHeader.Next.Count == 0) { this.logger.LogTrace("(-)[NO_HEADERS]"); return(Task.CompletedTask); } currentHeader = currentHeader.Next.FirstOrDefault(); if (currentHeader == null) { this.logger.LogTrace("(-)[NO_NEXT_HEADER]"); return(Task.CompletedTask); } } Block block = currentHeader.Block; if (block == null) { this.logger.LogTrace("(-)[NO_BLOCK_DATA]"); return(Task.CompletedTask); } bool farFromTip = currentHeader.Height > this.chainIndexer.Tip.Height + (Lookahead / 2); if (!farFromTip) { this.logger.LogDebug("Skipping pre-fetch, the block selected is too close to the tip."); this.logger.LogTrace("(-)[TOO_CLOSE_TO_PREFETCH_HEIGHT]"); return(Task.CompletedTask); } bool enforceBIP30 = false; if (currentHeader.Height > this.checkpoints.GetLastCheckpointHeight()) { enforceBIP30 = DeploymentFlags.EnforceBIP30ForBlock(currentHeader); } OutPoint[] idsToCache = this.coinviewHelper.GetIdsToFetch(block, enforceBIP30); if (idsToCache.Length != 0) { this.coinview.CacheCoins(idsToCache); this.logger.LogDebug("Block '{0}' had {1} ids pre-fetched.", currentHeader.Height, idsToCache.Length); } return(Task.CompletedTask); }
/// <summary> /// Pre-fetches UTXOs for a block and some blocks with higher height. /// pre-fetching is done on the background. /// </summary> /// <param name="header">Header of a block that is about to be partially validated and requires pre-fetching.</param> private async Task OnHeaderEnqueuedAsync(ChainedHeader header, CancellationToken cancellation) { ChainedHeader currentHeader = header; // Go Lookahead blocks ahead of current header and get block for pre-fetching. // There might be several blocks at height of header.Height + Lookahead but // only first one will be pre-fetched since pre-fetching is in place mostly to // speed up IBD. for (int i = 0; i < Lookahead; i++) { if (currentHeader.Next.Count == 0) { this.logger.LogTrace("(-)[NO_HEADERS]"); return; } currentHeader = currentHeader.Next.FirstOrDefault(); if (currentHeader == null) { this.logger.LogTrace("(-)[NO_NEXT_HEADER]"); return; } } Block block = currentHeader.Block; if (block == null) { this.logger.LogTrace("(-)[NO_BLOCK_DATA]"); return; } bool farFromTip = currentHeader.Height > this.chainIndexer.Tip.Height + (Lookahead / 2); if (!farFromTip) { this.logger.LogDebug("Block selected for pre-fetching is too close to the tip! Skipping pre-fetching."); this.logger.LogTrace("(-)[TOO_CLOSE_TO_PREFETCH]"); return; } bool enforceBIP30 = DeploymentFlags.EnforceBIP30ForBlock(currentHeader); uint256[] idsToFetch = this.coinviewHelper.GetIdsToFetch(block, enforceBIP30); if (idsToFetch.Length != 0) { this.coinview.FetchCoins(idsToFetch, cancellation); this.logger.LogTrace("{0} ids were pre-fetched.", idsToFetch.Length); } }