Files
grenadeandClaude Opus 5.5 739a2f5345
ci / gate (push) Successful in 5m41s
deploy / validate (push) Skipped
deploy / build (push) Successful in 10m12s
deploy / deploy-web (push) Successful in 5s
deploy / deploy-api (push) Successful in 22s
fix: a reorged height takes the winner's block and events, not the loser's
`chain_subscribeNewHeads` reports the best head, so a fork that wins at h
arrives as its h+1 and the replacement at h is never delivered. Ingest
checked heights for gaps but never parents for continuity, so h kept the
losing block's row, and `chain_event`, upserted by index, kept its
reward. Mainnet 61041 credited baba-gorchitsa 0.31 QTC the chain paid
QUANPOOL: its "mined" read 14.97 against a balance of 14.68 that can
only ever rise.

- `record` reads the header at the hash it resolved, then compares its
  parent with the row beneath it and walks a fork back (`repair_fork`),
  re-recording each replaced block and re-reading its events.
- Event and extrinsic rows carry `block_hash` (0024); a height is cleared
  of rows from any other block before it is written.
- The backfill stays `SETTLE_DEPTH` behind the tip and re-records any
  block row that is not canonical. 0024 collapses its cursor so all
  history is re-checked.
- `RollingWindow::push` replaces a block at a height it already holds
  instead of counting both forks.

Closes #52

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CKabPYLTYP2G5s7ph7oCpo
2026-10-14 08:29:07 +03:00

25 lines
1.4 KiB
SQL

-- Which block each indexed row was decoded from (blackbeard/observer#52).
--
-- `chain_event` and `chain_extrinsic` are keyed on `(chain, height, index)`
-- and said nothing about *which* block at that height they came from. A reorg
-- replaces the block at a height, and an upsert by index cannot remove rows the
-- replacement does not have: mainnet 61041 kept the losing fork's
-- `MinerRewarded`, `Minted` and `NativeTransferred` to baba-gorchitsa beside
-- the winner's exit, so that account was credited 0.31 QTC the chain never paid
-- it and QUANPOOL's reward at that height was never indexed at all.
--
-- With the hash on every row, indexing a height first removes whatever was read
-- from a different block, then writes. Rows from before this migration carry
-- null, which is "provenance unknown" and is treated as different from
-- everything.
alter table chain_event add column block_hash text;
alter table chain_extrinsic add column block_hash text;
-- Re-read every block, so that every row gains a hash and every height that a
-- reorg left mixed is replaced by its canonical block's events. The backfill
-- also compares the `block` row at each height it walks against the canonical
-- hash, so the same pass corrects block rows a reorg left behind. Collapsing to
-- the top as 0008 did: the backfill walks down to genesis again, and
-- `indexed_from` reports the real, shrinking range while it does.
update event_scan set low = high, updated_at = now();