Merge site-ui-4: the live API's per-block proof read (joined by hash, windows to 1800 s) and the observer's 30-minute record window
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
commit
f1cc7ff0ad
2 changed files with 17 additions and 10 deletions
|
|
@ -1,5 +1,5 @@
|
|||
// Igneum live devnet feed. GET /api/live returns what tools/observer wrote to Neon:
|
||||
// {now, state (incl. height = chain block number), blocks (last 90 s, or ?window=N up to 300), miners (last 10 min), events (last 30), finality (checkpoints, newest lock),
|
||||
// {now, state (incl. height = chain block number), blocks (last 90 s, or ?window=N up to 1800, at most 1,800 blocks), miners (last 10 min), events (last 30), finality (checkpoints, newest lock),
|
||||
// proving (activation and 10-minute counts; every chain block carries shards: [{i, state, prover, lag, payout}])}.
|
||||
// Five queries, all on indexed columns. Cached one second at the edge.
|
||||
// LIVE_TABLE_PREFIX (default empty) reads a test observer's tables (fintest_live_*, provtest_live_*) instead of the devnet's.
|
||||
|
|
@ -37,9 +37,10 @@ export default async function handler(req, res) {
|
|||
}
|
||||
try {
|
||||
const sql = neon();
|
||||
// ?window=N seconds of blocks (30 to 300, default 90): the page's diagnostic long view; the row cap keeps a busy DAG bounded
|
||||
// ?window=N seconds of blocks (30 to 1800, default 90): the page's long views; the row cap of 1,800 blocks keeps a busy DAG bounded
|
||||
// (7 October 2026: the cap was 300 s while proofs land two to five minutes after the block, so no window could show a proven block)
|
||||
const q = new URL(req.url || '/', 'http://x').searchParams;
|
||||
const windowS = Math.max(30, Math.min(300, Number(q.get('window')) || 90));
|
||||
const windowS = Math.max(30, Math.min(1800, Number(q.get('window')) || 90));
|
||||
const [head, blockRows, minerRows, checkpointRows, proofRows] = await Promise.all([
|
||||
sql(`SELECT now() AS now,
|
||||
(SELECT row_to_json(s) FROM ${T}live_state s WHERE s.id = 1) AS state,
|
||||
|
|
@ -49,7 +50,7 @@ export default async function handler(req, res) {
|
|||
FROM ${T}live_blocks
|
||||
WHERE received_at > now() - ($1 || ' seconds')::interval
|
||||
ORDER BY received_at DESC
|
||||
LIMIT 2000`, [String(windowS)]),
|
||||
LIMIT 1800`, [String(windowS)]),
|
||||
sql(`SELECT vote_key_hash, count(*)::int AS blocks, max(received_at) AS last_seen, max(engine) AS engine, max(miner_address) AS address
|
||||
FROM ${T}live_blocks
|
||||
WHERE received_at > now() - interval '10 minutes' AND vote_key_hash IS NOT NULL
|
||||
|
|
@ -60,11 +61,13 @@ export default async function handler(req, res) {
|
|||
FROM ${T}live_checkpoints
|
||||
ORDER BY index DESC
|
||||
LIMIT 40`).catch(() => []),
|
||||
// Proving v0: the planned shards of the chain blocks in the window and what became of them (an older observer has no table)
|
||||
sql(`SELECT block_hash, shard, shards, state, prover, lag_daa, payout_wei, pgas
|
||||
FROM ${T}live_proofs
|
||||
WHERE received_at > now() - ($1 || ' seconds')::interval
|
||||
ORDER BY block_hash, shard`, [String(windowS + 30)]).catch(() => []),
|
||||
// Proving v0: the planned shards of the blocks in the window and what became of them (an older observer has no table).
|
||||
// The rows are joined by block hash, never by when the plan or the proof landed: a block in view carries its shard
|
||||
// states (planned, proving, verified, paid) whatever its age, and the proof's own landing is what moves them.
|
||||
sql(`SELECT p.block_hash, p.shard, p.shards, p.state, p.prover, p.lag_daa, p.payout_wei, p.pgas
|
||||
FROM ${T}live_proofs p
|
||||
WHERE p.block_hash IN (SELECT hash FROM ${T}live_blocks WHERE received_at > now() - ($1 || ' seconds')::interval ORDER BY received_at DESC LIMIT 1800)
|
||||
ORDER BY p.block_hash, p.shard`, [String(windowS)]).catch(() => []),
|
||||
]);
|
||||
|
||||
const now = new Date(head[0].now).getTime();
|
||||
|
|
|
|||
|
|
@ -848,7 +848,11 @@ async function backfillCertificate(rpc, report) {
|
|||
// {blockHash}. The EVM node may trail the observer's node by a segment or two: a plan that is "not found" is retried
|
||||
// with a growing delay, up to 30 attempts. A node without the RPCs answers -32601 once and the feed is marked
|
||||
// unsupported (rechecked every 5 minutes, so an upgraded node is picked up without a restart).
|
||||
const PLAN_BATCH = 24, RECORD_BATCH_ACTIVE = 80, RECORD_BATCH_INACTIVE = 10, PROOF_WINDOW_MS = 10 * 60_000;
|
||||
// PROOF_WINDOW_MS: how long a planned block keeps being read for its records. 30 minutes (7 October 2026, was 10): the fleet's
|
||||
// proofs land a median 258 s after the block and the tail runs past 10 minutes, and a block dropped from the open set never
|
||||
// moves past 'proving' on the page. The open set at 0.45 blocks a second is about 800 blocks; the batch of 80 reads each one
|
||||
// every 10 ticks.
|
||||
const PLAN_BATCH = 24, RECORD_BATCH_ACTIVE = 80, RECORD_BATCH_INACTIVE = 10, PROOF_WINDOW_MS = 30 * 60_000;
|
||||
const pendingPlans = new Map(); // chain block hash -> { tries, nextAt }
|
||||
const openBlocks = new Map(); // chain block hash -> { number, daa, ts, shards: [state...], provers, polledAt, done }
|
||||
const daaOfNumber = new Map(); // chain block number -> daa score, from the plans fetched (carriers are later chain blocks)
|
||||
|
|
|
|||
Loading…
Reference in a new issue