Detect stale blocks from client blockchain cache

This commit is contained in:
Mononaut 2023-07-12 16:25:00 +09:00
parent 7230b65dc3
commit 886a099a2f
No known key found for this signature in database
GPG Key ID: A3F058E41374C04E
2 changed files with 25 additions and 2 deletions

View File

@ -14,6 +14,7 @@ import { ApiService } from '../../services/api.service';
import { BlockOverviewGraphComponent } from '../../components/block-overview-graph/block-overview-graph.component'; import { BlockOverviewGraphComponent } from '../../components/block-overview-graph/block-overview-graph.component';
import { detectWebGL } from '../../shared/graphs.utils'; import { detectWebGL } from '../../shared/graphs.utils';
import { PriceService, Price } from '../../services/price.service'; import { PriceService, Price } from '../../services/price.service';
import { CacheService } from '../../services/cache.service';
@Component({ @Component({
selector: 'app-block', selector: 'app-block',
@ -72,6 +73,7 @@ export class BlockComponent implements OnInit, OnDestroy {
auditSubscription: Subscription; auditSubscription: Subscription;
keyNavigationSubscription: Subscription; keyNavigationSubscription: Subscription;
blocksSubscription: Subscription; blocksSubscription: Subscription;
cacheBlocksSubscription: Subscription;
networkChangedSubscription: Subscription; networkChangedSubscription: Subscription;
queryParamsSubscription: Subscription; queryParamsSubscription: Subscription;
nextBlockSubscription: Subscription = undefined; nextBlockSubscription: Subscription = undefined;
@ -99,6 +101,7 @@ export class BlockComponent implements OnInit, OnDestroy {
private relativeUrlPipe: RelativeUrlPipe, private relativeUrlPipe: RelativeUrlPipe,
private apiService: ApiService, private apiService: ApiService,
private priceService: PriceService, private priceService: PriceService,
private cacheService: CacheService,
) { ) {
this.webGlEnabled = detectWebGL(); this.webGlEnabled = detectWebGL();
} }
@ -128,6 +131,10 @@ export class BlockComponent implements OnInit, OnDestroy {
map((indicators) => indicators['blocktxs-' + this.blockHash] !== undefined ? indicators['blocktxs-' + this.blockHash] : 0) map((indicators) => indicators['blocktxs-' + this.blockHash] !== undefined ? indicators['blocktxs-' + this.blockHash] : 0)
); );
this.cacheBlocksSubscription = this.cacheService.loadedBlocks$.subscribe((block) => {
this.loadedCacheBlock(block);
});
this.blocksSubscription = this.stateService.blocks$ this.blocksSubscription = this.stateService.blocks$
.subscribe((blocks) => { .subscribe((blocks) => {
this.latestBlock = blocks[0]; this.latestBlock = blocks[0];
@ -258,6 +265,13 @@ export class BlockComponent implements OnInit, OnDestroy {
this.transactionsError = null; this.transactionsError = null;
this.isLoadingOverview = true; this.isLoadingOverview = true;
this.overviewError = null; this.overviewError = null;
const cachedBlock = this.cacheService.getCachedBlock(block.height);
if (!cachedBlock) {
this.cacheService.loadBlock(block.height);
} else {
this.loadedCacheBlock(cachedBlock);
}
}), }),
throttleTime(300, asyncScheduler, { leading: true, trailing: true }), throttleTime(300, asyncScheduler, { leading: true, trailing: true }),
shareReplay(1) shareReplay(1)
@ -463,6 +477,7 @@ export class BlockComponent implements OnInit, OnDestroy {
this.auditSubscription?.unsubscribe(); this.auditSubscription?.unsubscribe();
this.keyNavigationSubscription?.unsubscribe(); this.keyNavigationSubscription?.unsubscribe();
this.blocksSubscription?.unsubscribe(); this.blocksSubscription?.unsubscribe();
this.cacheBlocksSubscription?.unsubscribe();
this.networkChangedSubscription?.unsubscribe(); this.networkChangedSubscription?.unsubscribe();
this.queryParamsSubscription?.unsubscribe(); this.queryParamsSubscription?.unsubscribe();
this.timeLtrSubscription?.unsubscribe(); this.timeLtrSubscription?.unsubscribe();
@ -683,4 +698,11 @@ export class BlockComponent implements OnInit, OnDestroy {
} }
return 0; return 0;
} }
loadedCacheBlock(block: BlockExtended): void {
if (block.height === this.block.height && block.id !== this.block.id) {
this.block.stale = true;
this.block.canonical = block.id;
}
}
} }

View File

@ -1,13 +1,13 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { webSocket, WebSocketSubject } from 'rxjs/webSocket'; import { webSocket, WebSocketSubject } from 'rxjs/webSocket';
import { WebsocketResponse, IBackendInfo } from '../interfaces/websocket.interface'; import { WebsocketResponse } from '../interfaces/websocket.interface';
import { StateService } from './state.service'; import { StateService } from './state.service';
import { Transaction } from '../interfaces/electrs.interface'; import { Transaction } from '../interfaces/electrs.interface';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { ApiService } from './api.service'; import { ApiService } from './api.service';
import { take } from 'rxjs/operators'; import { take } from 'rxjs/operators';
import { TransferState, makeStateKey } from '@angular/platform-browser'; import { TransferState, makeStateKey } from '@angular/platform-browser';
import { BlockExtended } from '../interfaces/node-api.interface'; import { CacheService } from './cache.service';
const OFFLINE_RETRY_AFTER_MS = 2000; const OFFLINE_RETRY_AFTER_MS = 2000;
const OFFLINE_PING_CHECK_AFTER_MS = 30000; const OFFLINE_PING_CHECK_AFTER_MS = 30000;
@ -40,6 +40,7 @@ export class WebsocketService {
private stateService: StateService, private stateService: StateService,
private apiService: ApiService, private apiService: ApiService,
private transferState: TransferState, private transferState: TransferState,
private cacheService: CacheService,
) { ) {
if (!this.stateService.isBrowser) { if (!this.stateService.isBrowser) {
// @ts-ignore // @ts-ignore