feat(freshness): enhance diagnostics and update snapshot structure

- Introduced a new Diagnostics struct to capture transaction visibility state and activity state.
- Updated BuildSnapshot function to return diagnostics alongside snapshot, completeness, and sampling.
- Enhanced test cases to validate the new diagnostics data.
- Updated frontend components to utilize the new diagnostics information for improved user feedback on freshness context.

This change improves the observability of transaction activity and enhances the user experience by providing clearer insights into the freshness of data.
This commit is contained in:
defiQUG
2026-04-12 18:22:08 -07:00
parent 50c5435c0c
commit b5a2e0c0a4
34 changed files with 1328 additions and 165 deletions

View File

@@ -1,4 +1,5 @@
import { getExplorerApiBase } from './blockscout'
import type { ExplorerFreshnessDiagnostics } from './stats'
export interface MissionControlRelaySummary {
text: string
@@ -99,6 +100,7 @@ export interface MissionControlBridgeStatusResponse {
status?: string
checked_at?: string
freshness?: unknown
diagnostics?: ExplorerFreshnessDiagnostics | null
sampling?: {
stats_generated_at?: string | null
rpc_probe_at?: string | null
@@ -150,6 +152,11 @@ function describeRelayStatus(snapshot: MissionControlRelaySnapshot, status: stri
? 'underfunded queued release'
: 'underfunded release'
}
if (snapshot.last_error?.scope === 'bridge_inventory_probe') {
return snapshot.queue?.size && snapshot.queue.size > 0
? 'inventory check deferred'
: 'inventory check pending'
}
if (status === 'paused' && snapshot.monitoring?.delivery_enabled === false) {
return snapshot.queue?.size && snapshot.queue.size > 0 ? 'delivery paused (queueing)' : 'delivery paused'
}

View File

@@ -26,6 +26,7 @@ describe('normalizeExplorerStats', () => {
freshness: null,
completeness: null,
sampling: null,
diagnostics: null,
})
})
@@ -48,6 +49,7 @@ describe('normalizeExplorerStats', () => {
freshness: null,
completeness: null,
sampling: null,
diagnostics: null,
})
})

View File

@@ -12,6 +12,7 @@ export interface ExplorerStats {
freshness: ExplorerFreshnessSnapshot | null
completeness: ExplorerStatsCompleteness | null
sampling: ExplorerStatsSampling | null
diagnostics: ExplorerFreshnessDiagnostics | null
}
export interface ExplorerFreshnessReference {
@@ -33,6 +34,22 @@ export interface ExplorerFreshnessSnapshot {
latest_non_empty_block: ExplorerFreshnessReference
}
export interface ExplorerFreshnessDiagnostics {
tx_visibility_state?: string | null
activity_state?: string | null
explanation?: string | null
tx_lag_blocks?: number | null
tx_lag_seconds?: number | null
recent_block_sample_size?: number | null
recent_non_empty_blocks?: number | null
recent_transactions?: number | null
latest_non_empty_block_from_block_feed?: ExplorerFreshnessReference | null
source?: string | null
confidence?: string | null
provenance?: string | null
completeness?: string | null
}
export interface ExplorerStatsCompleteness {
transactions_feed?: string | null
blocks_feed?: string | null
@@ -87,6 +104,21 @@ interface RawExplorerStats {
} | null
completeness?: ExplorerStatsCompleteness | null
sampling?: ExplorerStatsSampling | null
diagnostics?: {
tx_visibility_state?: string | null
activity_state?: string | null
explanation?: string | null
tx_lag_blocks?: number | string | null
tx_lag_seconds?: number | string | null
recent_block_sample_size?: number | string | null
recent_non_empty_blocks?: number | string | null
recent_transactions?: number | string | null
latest_non_empty_block_from_block_feed?: RawExplorerFreshnessReference | null
source?: string | null
confidence?: string | null
provenance?: string | null
completeness?: string | null
} | null
}
interface RawExplorerFreshnessReference {
@@ -135,6 +167,34 @@ function normalizeFreshnessSnapshot(raw?: RawExplorerStats['freshness'] | null):
}
}
function normalizeFreshnessDiagnostics(raw?: RawExplorerStats['diagnostics'] | null): ExplorerFreshnessDiagnostics | null {
if (!raw) return null
return {
tx_visibility_state: raw.tx_visibility_state || null,
activity_state: raw.activity_state || null,
explanation: raw.explanation || null,
tx_lag_blocks: raw.tx_lag_blocks == null || raw.tx_lag_blocks === '' ? null : toNumber(raw.tx_lag_blocks),
tx_lag_seconds: raw.tx_lag_seconds == null || raw.tx_lag_seconds === '' ? null : toNumber(raw.tx_lag_seconds),
recent_block_sample_size:
raw.recent_block_sample_size == null || raw.recent_block_sample_size === ''
? null
: toNumber(raw.recent_block_sample_size),
recent_non_empty_blocks:
raw.recent_non_empty_blocks == null || raw.recent_non_empty_blocks === ''
? null
: toNumber(raw.recent_non_empty_blocks),
recent_transactions:
raw.recent_transactions == null || raw.recent_transactions === ''
? null
: toNumber(raw.recent_transactions),
latest_non_empty_block_from_block_feed: normalizeFreshnessReference(raw.latest_non_empty_block_from_block_feed),
source: raw.source || null,
confidence: raw.confidence || null,
provenance: raw.provenance || null,
completeness: raw.completeness || null,
}
}
export function normalizeExplorerStats(raw: RawExplorerStats): ExplorerStats {
const latestBlockValue = raw.latest_block
const averageBlockTimeValue = raw.average_block_time
@@ -169,6 +229,7 @@ export function normalizeExplorerStats(raw: RawExplorerStats): ExplorerStats {
freshness: normalizeFreshnessSnapshot(raw.freshness),
completeness: raw.completeness || null,
sampling: raw.sampling || null,
diagnostics: normalizeFreshnessDiagnostics(raw.diagnostics),
}
}