Merge pull request #5159 from mempool/mononaut/handle-services-failures
Handle services backend failures in block component
This commit is contained in:
commit
bf81cc5ba9
@ -8,7 +8,7 @@ import { StateService } from '../../services/state.service';
|
|||||||
import { SeoService } from '../../services/seo.service';
|
import { SeoService } from '../../services/seo.service';
|
||||||
import { WebsocketService } from '../../services/websocket.service';
|
import { WebsocketService } from '../../services/websocket.service';
|
||||||
import { RelativeUrlPipe } from '../../shared/pipes/relative-url/relative-url.pipe';
|
import { RelativeUrlPipe } from '../../shared/pipes/relative-url/relative-url.pipe';
|
||||||
import { BlockAudit, BlockExtended, TransactionStripped } from '../../interfaces/node-api.interface';
|
import { Acceleration, BlockAudit, BlockExtended, TransactionStripped } from '../../interfaces/node-api.interface';
|
||||||
import { ApiService } from '../../services/api.service';
|
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';
|
||||||
@ -44,6 +44,7 @@ export class BlockComponent implements OnInit, OnDestroy {
|
|||||||
latestBlocks: BlockExtended[] = [];
|
latestBlocks: BlockExtended[] = [];
|
||||||
oobFees: number = 0;
|
oobFees: number = 0;
|
||||||
strippedTransactions: TransactionStripped[];
|
strippedTransactions: TransactionStripped[];
|
||||||
|
accelerations: Acceleration[];
|
||||||
overviewTransitionDirection: string;
|
overviewTransitionDirection: string;
|
||||||
isLoadingOverview = true;
|
isLoadingOverview = true;
|
||||||
error: any;
|
error: any;
|
||||||
@ -68,6 +69,7 @@ export class BlockComponent implements OnInit, OnDestroy {
|
|||||||
mode: 'projected' | 'actual' = 'projected';
|
mode: 'projected' | 'actual' = 'projected';
|
||||||
|
|
||||||
overviewSubscription: Subscription;
|
overviewSubscription: Subscription;
|
||||||
|
accelerationsSubscription: Subscription;
|
||||||
keyNavigationSubscription: Subscription;
|
keyNavigationSubscription: Subscription;
|
||||||
blocksSubscription: Subscription;
|
blocksSubscription: Subscription;
|
||||||
cacheBlocksSubscription: Subscription;
|
cacheBlocksSubscription: Subscription;
|
||||||
@ -183,6 +185,9 @@ export class BlockComponent implements OnInit, OnDestroy {
|
|||||||
} else {
|
} else {
|
||||||
this.isLoadingBlock = true;
|
this.isLoadingBlock = true;
|
||||||
this.isLoadingOverview = true;
|
this.isLoadingOverview = true;
|
||||||
|
this.strippedTransactions = undefined;
|
||||||
|
this.blockAudit = undefined;
|
||||||
|
this.accelerations = undefined;
|
||||||
|
|
||||||
let blockInCache: BlockExtended;
|
let blockInCache: BlockExtended;
|
||||||
if (isBlockHeight) {
|
if (isBlockHeight) {
|
||||||
@ -294,158 +299,36 @@ export class BlockComponent implements OnInit, OnDestroy {
|
|||||||
this.overviewError = err;
|
this.overviewError = err;
|
||||||
return of(null);
|
return of(null);
|
||||||
})
|
})
|
||||||
),
|
)
|
||||||
this.stateService.env.ACCELERATOR === true && block.height > 819500
|
|
||||||
? this.servicesApiService.getAccelerationHistory$({ blockHeight: block.height })
|
|
||||||
.pipe(catchError(() => {
|
|
||||||
return of([]);
|
|
||||||
}))
|
|
||||||
: of([])
|
|
||||||
]);
|
]);
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.subscribe(([transactions, blockAudit, accelerations]) => {
|
.subscribe(([transactions, blockAudit]) => {
|
||||||
if (transactions) {
|
if (transactions) {
|
||||||
this.strippedTransactions = transactions;
|
this.strippedTransactions = transactions;
|
||||||
} else {
|
} else {
|
||||||
this.strippedTransactions = [];
|
this.strippedTransactions = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const acceleratedInBlock = {};
|
|
||||||
for (const acc of accelerations) {
|
|
||||||
if (acc.pools?.some(pool => pool === this.block?.extras?.pool.id)) {
|
|
||||||
acceleratedInBlock[acc.txid] = acc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const tx of transactions) {
|
|
||||||
if (acceleratedInBlock[tx.txid]) {
|
|
||||||
tx.acc = true;
|
|
||||||
const acceleration = acceleratedInBlock[tx.txid];
|
|
||||||
const boostCost = acceleration.boostCost || acceleration.bidBoost;
|
|
||||||
const acceleratedFeeRate = Math.max(acceleration.effectiveFee, acceleration.effectiveFee + boostCost) / acceleration.effectiveVsize;
|
|
||||||
if (acceleratedFeeRate > tx.rate) {
|
|
||||||
tx.rate = acceleratedFeeRate;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
tx.acc = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.blockAudit = null;
|
|
||||||
if (transactions && blockAudit) {
|
|
||||||
const inTemplate = {};
|
|
||||||
const inBlock = {};
|
|
||||||
const isAdded = {};
|
|
||||||
const isPrioritized = {};
|
|
||||||
const isCensored = {};
|
|
||||||
const isMissing = {};
|
|
||||||
const isSelected = {};
|
|
||||||
const isFresh = {};
|
|
||||||
const isSigop = {};
|
|
||||||
const isRbf = {};
|
|
||||||
const isAccelerated = {};
|
|
||||||
this.numMissing = 0;
|
|
||||||
this.numUnexpected = 0;
|
|
||||||
|
|
||||||
if (blockAudit?.template) {
|
|
||||||
for (const tx of blockAudit.template) {
|
|
||||||
inTemplate[tx.txid] = true;
|
|
||||||
if (tx.acc) {
|
|
||||||
isAccelerated[tx.txid] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const tx of transactions) {
|
|
||||||
inBlock[tx.txid] = true;
|
|
||||||
}
|
|
||||||
for (const txid of blockAudit.addedTxs) {
|
|
||||||
isAdded[txid] = true;
|
|
||||||
}
|
|
||||||
for (const txid of blockAudit.prioritizedTxs || []) {
|
|
||||||
isPrioritized[txid] = true;
|
|
||||||
}
|
|
||||||
for (const txid of blockAudit.missingTxs) {
|
|
||||||
isCensored[txid] = true;
|
|
||||||
}
|
|
||||||
for (const txid of blockAudit.freshTxs || []) {
|
|
||||||
isFresh[txid] = true;
|
|
||||||
}
|
|
||||||
for (const txid of blockAudit.sigopTxs || []) {
|
|
||||||
isSigop[txid] = true;
|
|
||||||
}
|
|
||||||
for (const txid of blockAudit.fullrbfTxs || []) {
|
|
||||||
isRbf[txid] = true;
|
|
||||||
}
|
|
||||||
for (const txid of blockAudit.acceleratedTxs || []) {
|
|
||||||
isAccelerated[txid] = true;
|
|
||||||
}
|
|
||||||
// set transaction statuses
|
|
||||||
for (const tx of blockAudit.template) {
|
|
||||||
tx.context = 'projected';
|
|
||||||
if (isCensored[tx.txid]) {
|
|
||||||
tx.status = 'censored';
|
|
||||||
} else if (inBlock[tx.txid]) {
|
|
||||||
tx.status = 'found';
|
|
||||||
} else {
|
|
||||||
if (isFresh[tx.txid]) {
|
|
||||||
if (tx.rate - (tx.fee / tx.vsize) >= 0.1) {
|
|
||||||
tx.status = 'freshcpfp';
|
|
||||||
} else {
|
|
||||||
tx.status = 'fresh';
|
|
||||||
}
|
|
||||||
} else if (isSigop[tx.txid]) {
|
|
||||||
tx.status = 'sigop';
|
|
||||||
} else if (isRbf[tx.txid]) {
|
|
||||||
tx.status = 'rbf';
|
|
||||||
} else {
|
|
||||||
tx.status = 'missing';
|
|
||||||
}
|
|
||||||
isMissing[tx.txid] = true;
|
|
||||||
this.numMissing++;
|
|
||||||
}
|
|
||||||
if (isAccelerated[tx.txid]) {
|
|
||||||
tx.status = 'accelerated';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const [index, tx] of transactions.entries()) {
|
|
||||||
tx.context = 'actual';
|
|
||||||
if (index === 0) {
|
|
||||||
tx.status = null;
|
|
||||||
} else if (isAdded[tx.txid]) {
|
|
||||||
tx.status = 'added';
|
|
||||||
} else if (isPrioritized[tx.txid]) {
|
|
||||||
tx.status = 'prioritized';
|
|
||||||
} else if (inTemplate[tx.txid]) {
|
|
||||||
tx.status = 'found';
|
|
||||||
} else if (isRbf[tx.txid]) {
|
|
||||||
tx.status = 'rbf';
|
|
||||||
} else {
|
|
||||||
tx.status = 'selected';
|
|
||||||
isSelected[tx.txid] = true;
|
|
||||||
this.numUnexpected++;
|
|
||||||
}
|
|
||||||
if (isAccelerated[tx.txid]) {
|
|
||||||
tx.status = 'accelerated';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const tx of transactions) {
|
|
||||||
inBlock[tx.txid] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
blockAudit.feeDelta = blockAudit.expectedFees > 0 ? (blockAudit.expectedFees - (this.block?.extras.totalFees + this.oobFees)) / blockAudit.expectedFees : 0;
|
|
||||||
blockAudit.weightDelta = blockAudit.expectedWeight > 0 ? (blockAudit.expectedWeight - this.block?.weight) / blockAudit.expectedWeight : 0;
|
|
||||||
blockAudit.txDelta = blockAudit.template.length > 0 ? (blockAudit.template.length - this.block?.tx_count) / blockAudit.template.length : 0;
|
|
||||||
this.blockAudit = blockAudit;
|
this.blockAudit = blockAudit;
|
||||||
this.setAuditAvailable(true);
|
|
||||||
} else {
|
|
||||||
this.setAuditAvailable(false);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.setAuditAvailable(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
this.setupBlockAudit();
|
||||||
this.isLoadingOverview = false;
|
this.isLoadingOverview = false;
|
||||||
this.setupBlockGraphs();
|
});
|
||||||
this.cd.markForCheck();
|
|
||||||
|
this.accelerationsSubscription = this.block$.pipe(
|
||||||
|
switchMap((block) => {
|
||||||
|
return this.stateService.env.ACCELERATOR === true && block.height > 819500
|
||||||
|
? this.servicesApiService.getAccelerationHistory$({ blockHeight: block.height })
|
||||||
|
.pipe(catchError(() => {
|
||||||
|
return of([]);
|
||||||
|
}))
|
||||||
|
: of([]);
|
||||||
|
})
|
||||||
|
).subscribe((accelerations) => {
|
||||||
|
this.accelerations = accelerations;
|
||||||
|
if (accelerations.length) {
|
||||||
|
this.setupBlockAudit();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.oobSubscription = this.block$.pipe(
|
this.oobSubscription = this.block$.pipe(
|
||||||
@ -609,6 +492,147 @@ export class BlockComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setupBlockAudit(): void {
|
||||||
|
const transactions = this.strippedTransactions || [];
|
||||||
|
const blockAudit = this.blockAudit;
|
||||||
|
const accelerations = this.accelerations || [];
|
||||||
|
|
||||||
|
const acceleratedInBlock = {};
|
||||||
|
for (const acc of accelerations) {
|
||||||
|
if (acc.pools?.some(pool => pool === this.block?.extras?.pool.id)) {
|
||||||
|
acceleratedInBlock[acc.txid] = acc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const tx of transactions) {
|
||||||
|
if (acceleratedInBlock[tx.txid]) {
|
||||||
|
tx.acc = true;
|
||||||
|
const acceleration = acceleratedInBlock[tx.txid];
|
||||||
|
const boostCost = acceleration.boostCost || acceleration.bidBoost;
|
||||||
|
const acceleratedFeeRate = Math.max(acceleration.effectiveFee, acceleration.effectiveFee + boostCost) / acceleration.effectiveVsize;
|
||||||
|
if (acceleratedFeeRate > tx.rate) {
|
||||||
|
tx.rate = acceleratedFeeRate;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tx.acc = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transactions && blockAudit) {
|
||||||
|
const inTemplate = {};
|
||||||
|
const inBlock = {};
|
||||||
|
const isAdded = {};
|
||||||
|
const isPrioritized = {};
|
||||||
|
const isCensored = {};
|
||||||
|
const isMissing = {};
|
||||||
|
const isSelected = {};
|
||||||
|
const isFresh = {};
|
||||||
|
const isSigop = {};
|
||||||
|
const isRbf = {};
|
||||||
|
const isAccelerated = {};
|
||||||
|
this.numMissing = 0;
|
||||||
|
this.numUnexpected = 0;
|
||||||
|
|
||||||
|
if (blockAudit?.template) {
|
||||||
|
for (const tx of blockAudit.template) {
|
||||||
|
inTemplate[tx.txid] = true;
|
||||||
|
if (tx.acc) {
|
||||||
|
isAccelerated[tx.txid] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const tx of transactions) {
|
||||||
|
inBlock[tx.txid] = true;
|
||||||
|
}
|
||||||
|
for (const txid of blockAudit.addedTxs) {
|
||||||
|
isAdded[txid] = true;
|
||||||
|
}
|
||||||
|
for (const txid of blockAudit.prioritizedTxs || []) {
|
||||||
|
isPrioritized[txid] = true;
|
||||||
|
}
|
||||||
|
for (const txid of blockAudit.missingTxs) {
|
||||||
|
isCensored[txid] = true;
|
||||||
|
}
|
||||||
|
for (const txid of blockAudit.freshTxs || []) {
|
||||||
|
isFresh[txid] = true;
|
||||||
|
}
|
||||||
|
for (const txid of blockAudit.sigopTxs || []) {
|
||||||
|
isSigop[txid] = true;
|
||||||
|
}
|
||||||
|
for (const txid of blockAudit.fullrbfTxs || []) {
|
||||||
|
isRbf[txid] = true;
|
||||||
|
}
|
||||||
|
for (const txid of blockAudit.acceleratedTxs || []) {
|
||||||
|
isAccelerated[txid] = true;
|
||||||
|
}
|
||||||
|
// set transaction statuses
|
||||||
|
for (const tx of blockAudit.template) {
|
||||||
|
tx.context = 'projected';
|
||||||
|
if (isCensored[tx.txid]) {
|
||||||
|
tx.status = 'censored';
|
||||||
|
} else if (inBlock[tx.txid]) {
|
||||||
|
tx.status = 'found';
|
||||||
|
} else {
|
||||||
|
if (isFresh[tx.txid]) {
|
||||||
|
if (tx.rate - (tx.fee / tx.vsize) >= 0.1) {
|
||||||
|
tx.status = 'freshcpfp';
|
||||||
|
} else {
|
||||||
|
tx.status = 'fresh';
|
||||||
|
}
|
||||||
|
} else if (isSigop[tx.txid]) {
|
||||||
|
tx.status = 'sigop';
|
||||||
|
} else if (isRbf[tx.txid]) {
|
||||||
|
tx.status = 'rbf';
|
||||||
|
} else {
|
||||||
|
tx.status = 'missing';
|
||||||
|
}
|
||||||
|
isMissing[tx.txid] = true;
|
||||||
|
this.numMissing++;
|
||||||
|
}
|
||||||
|
if (isAccelerated[tx.txid]) {
|
||||||
|
tx.status = 'accelerated';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const [index, tx] of transactions.entries()) {
|
||||||
|
tx.context = 'actual';
|
||||||
|
if (index === 0) {
|
||||||
|
tx.status = null;
|
||||||
|
} else if (isAdded[tx.txid]) {
|
||||||
|
tx.status = 'added';
|
||||||
|
} else if (isPrioritized[tx.txid]) {
|
||||||
|
tx.status = 'prioritized';
|
||||||
|
} else if (inTemplate[tx.txid]) {
|
||||||
|
tx.status = 'found';
|
||||||
|
} else if (isRbf[tx.txid]) {
|
||||||
|
tx.status = 'rbf';
|
||||||
|
} else {
|
||||||
|
tx.status = 'selected';
|
||||||
|
isSelected[tx.txid] = true;
|
||||||
|
this.numUnexpected++;
|
||||||
|
}
|
||||||
|
if (isAccelerated[tx.txid]) {
|
||||||
|
tx.status = 'accelerated';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const tx of transactions) {
|
||||||
|
inBlock[tx.txid] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockAudit.feeDelta = blockAudit.expectedFees > 0 ? (blockAudit.expectedFees - (this.block?.extras.totalFees + this.oobFees)) / blockAudit.expectedFees : 0;
|
||||||
|
blockAudit.weightDelta = blockAudit.expectedWeight > 0 ? (blockAudit.expectedWeight - this.block?.weight) / blockAudit.expectedWeight : 0;
|
||||||
|
blockAudit.txDelta = blockAudit.template.length > 0 ? (blockAudit.template.length - this.block?.tx_count) / blockAudit.template.length : 0;
|
||||||
|
this.blockAudit = blockAudit;
|
||||||
|
this.setAuditAvailable(true);
|
||||||
|
} else {
|
||||||
|
this.setAuditAvailable(false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.setAuditAvailable(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setupBlockGraphs();
|
||||||
|
this.cd.markForCheck();
|
||||||
|
}
|
||||||
|
|
||||||
setupBlockGraphs(): void {
|
setupBlockGraphs(): void {
|
||||||
if (this.blockAudit || this.strippedTransactions) {
|
if (this.blockAudit || this.strippedTransactions) {
|
||||||
this.blockGraphProjected.forEach(graph => {
|
this.blockGraphProjected.forEach(graph => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user