Merge pull request #5305 from mempool/natsoni/avoid-fetching-full-audit

Avoid fetching full audit on tx page
This commit is contained in:
softsimon
2024-07-12 17:10:36 +09:00
committed by GitHub
7 changed files with 128 additions and 30 deletions

View File

@@ -42,7 +42,7 @@ interface Pool {
slug: string;
}
interface AuditStatus {
export interface TxAuditStatus {
seen?: boolean;
expected?: boolean;
added?: boolean;
@@ -100,7 +100,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
sigops: number | null;
adjustedVsize: number | null;
pool: Pool | null;
auditStatus: AuditStatus | null;
auditStatus: TxAuditStatus | null;
isAcceleration: boolean = false;
filters: Filter[] = [];
showCpfpDetails = false;
@@ -374,33 +374,41 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
const auditAvailable = this.isAuditAvailable(height);
const isCoinbase = this.tx.vin.some(v => v.is_coinbase);
const fetchAudit = auditAvailable && !isCoinbase;
return fetchAudit ? this.apiService.getBlockAudit$(hash).pipe(
map(audit => {
const isAdded = audit.addedTxs.includes(txid);
const isPrioritized = audit.prioritizedTxs.includes(txid);
const isAccelerated = audit.acceleratedTxs.includes(txid);
const isConflict = audit.fullrbfTxs.includes(txid);
const isExpected = audit.template.some(tx => tx.txid === txid);
const firstSeen = audit.template.find(tx => tx.txid === txid)?.time;
return {
seen: isExpected || isPrioritized || isAccelerated,
expected: isExpected,
added: isAdded,
prioritized: isPrioritized,
conflict: isConflict,
accelerated: isAccelerated,
firstSeen,
};
}),
retry({ count: 3, delay: 2000 }),
catchError(() => {
return of(null);
})
) : of(isCoinbase ? { coinbase: true } : null);
if (fetchAudit) {
// If block audit is already cached, use it to get transaction audit
const blockAuditLoaded = this.apiService.getBlockAuditLoaded(hash);
if (blockAuditLoaded) {
return this.apiService.getBlockAudit$(hash).pipe(
map(audit => {
const isAdded = audit.addedTxs.includes(txid);
const isPrioritized = audit.prioritizedTxs.includes(txid);
const isAccelerated = audit.acceleratedTxs.includes(txid);
const isConflict = audit.fullrbfTxs.includes(txid);
const isExpected = audit.template.some(tx => tx.txid === txid);
const firstSeen = audit.template.find(tx => tx.txid === txid)?.time;
return {
seen: isExpected || isPrioritized || isAccelerated,
expected: isExpected,
added: isAdded,
prioritized: isPrioritized,
conflict: isConflict,
accelerated: isAccelerated,
firstSeen,
};
})
)
} else {
return this.apiService.getBlockTxAudit$(hash, txid).pipe(
retry({ count: 3, delay: 2000 }),
catchError(() => {
return of(null);
})
)
}
} else {
return of(isCoinbase ? { coinbase: true } : null);
}
}),
catchError((e) => {
return of(null);
})
).subscribe(auditStatus => {
this.auditStatus = auditStatus;
if (this.auditStatus?.firstSeen) {

View File

@@ -8,6 +8,7 @@ import { Transaction } from '../interfaces/electrs.interface';
import { Conversion } from './price.service';
import { StorageService } from './storage.service';
import { WebsocketResponse } from '../interfaces/websocket.interface';
import { TxAuditStatus } from '../components/transaction/transaction.component';
@Injectable({
providedIn: 'root'
@@ -17,6 +18,7 @@ export class ApiService {
private apiBasePath: string; // network path is /testnet, etc. or '' for mainnet
private requestCache = new Map<string, { subject: BehaviorSubject<any>, expiry: number }>;
public blockAuditLoaded: { [hash: string]: boolean } = {};
constructor(
private httpClient: HttpClient,
@@ -369,11 +371,18 @@ export class ApiService {
}
getBlockAudit$(hash: string) : Observable<BlockAudit> {
this.setBlockAuditLoaded(hash);
return this.httpClient.get<BlockAudit>(
this.apiBaseUrl + this.apiBasePath + `/api/v1/block/${hash}/audit-summary`
);
}
getBlockTxAudit$(hash: string, txid: string) : Observable<TxAuditStatus> {
return this.httpClient.get<TxAuditStatus>(
this.apiBaseUrl + this.apiBasePath + `/api/v1/block/${hash}/tx/${txid}/audit`
);
}
getBlockAuditScores$(from: number): Observable<AuditScore[]> {
return this.httpClient.get<AuditScore[]>(
this.apiBaseUrl + this.apiBasePath + `/api/v1/mining/blocks/audit/scores` +
@@ -526,4 +535,13 @@ export class ApiService {
this.apiBaseUrl + this.apiBasePath + '/api/v1/accelerations/total' + (queryString?.length ? '?' + queryString : '')
);
}
// Cache methods
async setBlockAuditLoaded(hash: string) {
this.blockAuditLoaded[hash] = true;
}
getBlockAuditLoaded(hash) {
return this.blockAuditLoaded[hash];
}
}

View File

@@ -124,6 +124,7 @@ export class CacheService {
resetBlockCache() {
this.blockHashCache = {};
this.blockCache = {};
this.apiService.blockAuditLoaded = {};
this.blockLoading = {};
this.copiesInBlockQueue = {};
this.blockPriorities = [];