Skip to content

Commit 6f4d27f

Browse files
authored
feat(indexer): genesis import framework with account and balance seed (#3587)
* feat(indexer): add genesis import framework with account and balance seed Balance tracking is only trustworthy from a network's genesis, so this seeds genesis state before the first block: accounts, per-denom balances (recorded as genesis-reason ledger entries), validators, and staking delegations, all in one transaction. It is gated behind GENESIS_IMPORT (default off). When enabled, the sync role runs a per-module seeder framework exactly once, using a genesis checkpoint in indexer_state so a restart is a no-op, and it rejects a fresh start that is not at the network's genesis height. Genesis is fetched over RPC /genesis_chunked and its chain_id is asserted against the node being indexed. This adds the accounts, account_balances, balance_changes, validators, and delegations tables (L-3); the ongoing per-block ledger lands in L-4. Refs CON-805 * refactor(indexer): share genesis validator and chunked-insert helpers Extract mapDescription/mapCommissionRates so the staking and gentx validator mappers stop duplicating the description and commission field mapping, and add an insertChunked helper the bank and staking seeders call instead of hand-rolling the chunked insert loop. * fix(indexer): warn when genesis import is enabled too late to seed The seed only runs on a fresh start, so turning GENESIS_IMPORT on after the indexer already has a sync checkpoint silently skips it and leaves the account and balance tables empty with no signal. Add a hasSeeded check on resume and log a warning so the operator knows genesis was never backfilled.
1 parent f13778e commit 6f4d27f

36 files changed

Lines changed: 2410 additions & 17 deletions

apps/chain-indexer/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ curl localhost:3092/v1/status
4040

4141
The checkpoint height should advance as blocks land in `cosmos.blocks`, `cosmos.transactions`, and `cosmos.messages`.
4242

43+
## Genesis import
44+
45+
Set `GENESIS_IMPORT=true` to seed genesis state before the first block: accounts, per-denom balances (as `genesis`-reason ledger entries), validators, and staking delegations, all in one transaction. Because balance history is only trustworthy from the network's genesis, a fresh `sync` with the flag on must begin at the genesis height, and a fresh start anywhere else is rejected with a clear error. On sandbox that height is 1 (`SYNC_START_HEIGHT=1`); the height is read from the genesis file itself, so a chain continued from an export uses its continuation height.
46+
47+
The import runs once. A `genesis` checkpoint in `indexer_state` makes a restart skip it, and the seed commits in a single transaction, so an interrupted run rolls back and retries cleanly. Genesis is fetched over RPC `/genesis_chunked` from the same nodes sync uses, and its `chain_id` must match the chain being indexed. Leave the flag unset (the default) and sync tails blocks, transactions, and messages from any height exactly as before.
48+
4349
## Backfill
4450

4551
The backfill role fills the database over an explicit, inclusive height range and exits when done, so it fits a one-off K8s Job:
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
CREATE TYPE "cosmos"."balance_change_reason" AS ENUM('genesis', 'transfer', 'fee', 'reward', 'commission', 'slash', 'gov', 'ibc', 'escrow', 'bme', 'mint', 'burn');--> statement-breakpoint
2+
CREATE TABLE "cosmos"."account_balances" (
3+
"account_id" integer NOT NULL,
4+
"denom" text NOT NULL,
5+
"amount" numeric(38, 0) NOT NULL,
6+
CONSTRAINT "account_balances_account_id_denom_pk" PRIMARY KEY("account_id","denom")
7+
);
8+
--> statement-breakpoint
9+
CREATE TABLE "cosmos"."accounts" (
10+
"id" serial PRIMARY KEY NOT NULL,
11+
"address" text NOT NULL,
12+
"account_number" bigint,
13+
"account_type" text,
14+
"is_module_account" boolean DEFAULT false NOT NULL
15+
);
16+
--> statement-breakpoint
17+
CREATE TABLE "cosmos"."balance_changes" (
18+
"id" bigserial PRIMARY KEY NOT NULL,
19+
"account_id" integer NOT NULL,
20+
"denom" text NOT NULL,
21+
"delta" numeric(38, 0) NOT NULL,
22+
"balance_after" numeric(38, 0) NOT NULL,
23+
"reason" "cosmos"."balance_change_reason" NOT NULL,
24+
"height" bigint NOT NULL,
25+
"counterparty_account_id" integer
26+
);
27+
--> statement-breakpoint
28+
CREATE TABLE "cosmos"."delegations" (
29+
"delegator_account_id" integer NOT NULL,
30+
"validator_operator_address" text NOT NULL,
31+
"shares" numeric(38, 18) NOT NULL,
32+
CONSTRAINT "delegations_delegator_account_id_validator_operator_address_pk" PRIMARY KEY("delegator_account_id","validator_operator_address")
33+
);
34+
--> statement-breakpoint
35+
CREATE TABLE "cosmos"."validators" (
36+
"operator_address" text PRIMARY KEY NOT NULL,
37+
"account_address" text,
38+
"hex_address" text,
39+
"moniker" text,
40+
"identity" text,
41+
"website" text,
42+
"details" text,
43+
"security_contact" text,
44+
"commission_rate" numeric(20, 18),
45+
"commission_max_rate" numeric(20, 18),
46+
"commission_max_change_rate" numeric(20, 18),
47+
"min_self_delegation" numeric(38, 0)
48+
);
49+
--> statement-breakpoint
50+
ALTER TABLE "cosmos"."account_balances" ADD CONSTRAINT "account_balances_account_id_accounts_id_fk" FOREIGN KEY ("account_id") REFERENCES "cosmos"."accounts"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
51+
ALTER TABLE "cosmos"."balance_changes" ADD CONSTRAINT "balance_changes_account_id_accounts_id_fk" FOREIGN KEY ("account_id") REFERENCES "cosmos"."accounts"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
52+
ALTER TABLE "cosmos"."balance_changes" ADD CONSTRAINT "balance_changes_counterparty_account_id_accounts_id_fk" FOREIGN KEY ("counterparty_account_id") REFERENCES "cosmos"."accounts"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
53+
ALTER TABLE "cosmos"."delegations" ADD CONSTRAINT "delegations_delegator_account_id_accounts_id_fk" FOREIGN KEY ("delegator_account_id") REFERENCES "cosmos"."accounts"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
54+
CREATE UNIQUE INDEX "accounts_address_idx" ON "cosmos"."accounts" USING btree ("address");--> statement-breakpoint
55+
CREATE INDEX "balance_changes_account_denom_height_idx" ON "cosmos"."balance_changes" USING btree ("account_id","denom","height");

0 commit comments

Comments
 (0)