From 886a099a2fd026d9c2051ba51ba6b2f2f168c8cb Mon Sep 17 00:00:00 2001 From: Mononaut Date: Wed, 12 Jul 2023 16:25:00 +0900 Subject: [PATCH] Detect stale blocks from client blockchain cache --- .../app/components/block/block.component.ts | 22 +++++++++++++++++++ .../src/app/services/websocket.service.ts | 5 +++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/components/block/block.component.ts b/frontend/src/app/components/block/block.component.ts index 5a24ebab8..84028820c 100644 --- a/frontend/src/app/components/block/block.component.ts +++ b/frontend/src/app/components/block/block.component.ts @@ -14,6 +14,7 @@ import { ApiService } from '../../services/api.service'; import { BlockOverviewGraphComponent } from '../../components/block-overview-graph/block-overview-graph.component'; import { detectWebGL } from '../../shared/graphs.utils'; import { PriceService, Price } from '../../services/price.service'; +import { CacheService } from '../../services/cache.service'; @Component({ selector: 'app-block', @@ -72,6 +73,7 @@ export class BlockComponent implements OnInit, OnDestroy { auditSubscription: Subscription; keyNavigationSubscription: Subscription; blocksSubscription: Subscription; + cacheBlocksSubscription: Subscription; networkChangedSubscription: Subscription; queryParamsSubscription: Subscription; nextBlockSubscription: Subscription = undefined; @@ -99,6 +101,7 @@ export class BlockComponent implements OnInit, OnDestroy { private relativeUrlPipe: RelativeUrlPipe, private apiService: ApiService, private priceService: PriceService, + private cacheService: CacheService, ) { 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) ); + this.cacheBlocksSubscription = this.cacheService.loadedBlocks$.subscribe((block) => { + this.loadedCacheBlock(block); + }); + this.blocksSubscription = this.stateService.blocks$ .subscribe((blocks) => { this.latestBlock = blocks[0]; @@ -258,6 +265,13 @@ export class BlockComponent implements OnInit, OnDestroy { this.transactionsError = null; this.isLoadingOverview = true; 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 }), shareReplay(1) @@ -463,6 +477,7 @@ export class BlockComponent implements OnInit, OnDestroy { this.auditSubscription?.unsubscribe(); this.keyNavigationSubscription?.unsubscribe(); this.blocksSubscription?.unsubscribe(); + this.cacheBlocksSubscription?.unsubscribe(); this.networkChangedSubscription?.unsubscribe(); this.queryParamsSubscription?.unsubscribe(); this.timeLtrSubscription?.unsubscribe(); @@ -683,4 +698,11 @@ export class BlockComponent implements OnInit, OnDestroy { } 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; + } + } } \ No newline at end of file diff --git a/frontend/src/app/services/websocket.service.ts b/frontend/src/app/services/websocket.service.ts index 472501384..7eed09e77 100644 --- a/frontend/src/app/services/websocket.service.ts +++ b/frontend/src/app/services/websocket.service.ts @@ -1,13 +1,13 @@ import { Injectable } from '@angular/core'; 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 { Transaction } from '../interfaces/electrs.interface'; import { Subscription } from 'rxjs'; import { ApiService } from './api.service'; import { take } from 'rxjs/operators'; 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_PING_CHECK_AFTER_MS = 30000; @@ -40,6 +40,7 @@ export class WebsocketService { private stateService: StateService, private apiService: ApiService, private transferState: TransferState, + private cacheService: CacheService, ) { if (!this.stateService.isBrowser) { // @ts-ignore