diff --git a/src/indexer/block.ts b/src/indexer/block.ts index d799ffe..38e9e44 100644 --- a/src/indexer/block.ts +++ b/src/indexer/block.ts @@ -4,6 +4,11 @@ import { RpcClient } from './rpc.js'; import type { RpcBlock, RpcReceipt, RpcTransaction } from './types.js'; import { hexToBigIntString, hexToBuffer } from './utils.js'; +function isHistoricalStateError(error: unknown): boolean { + return error instanceof Error + && /Storage error|state|archive|histor/i.test(error.message); +} + export function parseHeight(hexValue: string): bigint { const parsed = hexToBigIntString(hexValue); if (!parsed) { @@ -110,8 +115,24 @@ async function upsertAccounts(client: PoolClient, addresses: string[], blockHeig export async function refreshAccountState( client: PoolClient, rpc: RpcClient, address: string, blockHex: string, blockHeight: bigint ): Promise { - const balanceHex = await rpc.callWithRetry('eth_getBalance', [address, blockHex]); - const nonceHex = await rpc.callWithRetry('eth_getTransactionCount', [address, blockHex]); + let balanceHex: string; + let nonceHex: string; + + try { + balanceHex = await rpc.callWithRetry('eth_getBalance', [address, blockHex]); + nonceHex = await rpc.callWithRetry('eth_getTransactionCount', [address, blockHex]); + } catch (error) { + if (!isHistoricalStateError(error)) { + throw error; + } + + console.warn( + `Historical state unavailable for ${address} at block ${blockHeight}; falling back to latest state` + ); + balanceHex = await rpc.callWithRetry('eth_getBalance', [address, 'latest']); + nonceHex = await rpc.callWithRetry('eth_getTransactionCount', [address, 'latest']); + } + const balance = hexToBigIntString(balanceHex) ?? '0'; const nonce = parseHeight(nonceHex).toString(10); diff --git a/src/routes/inference.ts b/src/routes/inference.ts index 7d68f38..e7857e6 100644 --- a/src/routes/inference.ts +++ b/src/routes/inference.ts @@ -42,22 +42,15 @@ export default async function inferenceRoutes(app: FastifyInstance) { const submitter = q.submitter?.toLowerCase() || null; const data = await cached(`inference:tasks:${page}:${limit}:${statusFilter}:${submitter}`, 10, async () => { - // Fetch all tasks from RPC - const allTasks = await rpcCallSafe('qfc_getInferenceTasks', []) ?? []; - - // Filter - let filtered = allTasks; - if (statusFilter) { - filtered = filtered.filter((t) => String(t.status).toLowerCase() === statusFilter.toLowerCase()); - } - if (submitter) { - filtered = filtered.filter((t) => String(t.submitter).toLowerCase() === submitter); - } - - // Sort by createdAt descending - filtered.sort((a, b) => Number(b.createdAt ?? 0) - Number(a.createdAt ?? 0)); - - // Stats + // Build RPC filter — qfc_listPublicTasks supports server-side filtering & pagination + const filter: Record = {}; + if (statusFilter) filter.status = statusFilter; + if (submitter) filter.submitter = submitter; + + // Fetch all matching tasks (with generous limit for stats calculation) + const allTasks = await rpcCallSafe('qfc_listPublicTasks', [{ ...filter, limit: 1000 }]) ?? []; + + // Stats from full result set const completed = allTasks.filter((t) => String(t.status).toLowerCase() === 'completed').length; const pending = allTasks.filter((t) => String(t.status).toLowerCase() === 'pending').length; const failed = allTasks.filter((t) => String(t.status).toLowerCase() === 'failed').length; @@ -66,10 +59,10 @@ export default async function inferenceRoutes(app: FastifyInstance) { ? Math.round(completedTasks.reduce((sum, t) => sum + Number(t.executionTimeMs), 0) / completedTasks.length) : 0; - // Paginate - const total = filtered.length; + // Paginate (RPC already returns newest-first) + const total = allTasks.length; const start = (page - 1) * limit; - const items = filtered.slice(start, start + limit); + const items = allTasks.slice(start, start + limit); return { page, @@ -90,7 +83,7 @@ export default async function inferenceRoutes(app: FastifyInstance) { const [models, stats, allTasks, miners] = await Promise.all([ rpcCallSafe('qfc_getSupportedModels', []) ?? [], rpcCallSafe>('qfc_getInferenceStats', []), - rpcCallSafe('qfc_getInferenceTasks', []) ?? [], + rpcCallSafe('qfc_listPublicTasks', [{ limit: 1000 }]) ?? [], rpcCallSafe>>('qfc_getRegisteredMiners', []) ?? [], ]);