Skip to content

Commit ccdc870

Browse files
authored
fix: better connnect and rotate key support (#30)
* fix: better connect/disconnect handling * feat: add consensus key rotation support * chore: bump versions * fix: cache population fixes * chore: bump version and changelog * chore: bump version
1 parent 5ee8468 commit ccdc870

8 files changed

Lines changed: 263 additions & 69 deletions

File tree

‎packages/core-modules/CHANGELOG.md‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
# @eclesia/core-modules-pg
22

3+
## 2.15.1
4+
5+
### Patch Changes
6+
7+
- 7e721b5: `getConsensusAddress` now falls back to the `validators` table on a cache miss (instead of immediately throwing "No consensus address"), so an evicted `validatorAddressCache` (LRU, capped at 1000) entry or a not-yet-warmed cache after a restart no longer crashes block processing. It only throws when the validator is genuinely absent from the database.
8+
9+
## 2.15.0
10+
11+
### Minor Changes
12+
13+
- 10c0226: Handle `MsgRotateConsPubKey` in the staking module: append the new consensus key to `validators` (now carrying `operator_address`, `is_active`, and `height`), deactivate the previous key, and carry live delegations over to the new consensus address. `validator_infos.consensus_address` is dropped in favour of the operator↔consensus mapping now held on `validators`.
14+
315
## 2.14.3
416

517
### Patch Changes

‎packages/core-modules/package.json‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@eclesia/core-modules-pg",
3-
"version": "2.14.4",
3+
"version": "2.15.2",
44
"description": "Eclesia postgres indexer core modules",
55
"type": "module",
66
"scripts": {
@@ -42,6 +42,7 @@
4242
"access": "public"
4343
},
4444
"dependencies": {
45+
"@atomone/atomone-types": "^4.0.2",
4546
"@cosmjs/encoding": "^0.36.0",
4647
"@cosmjs/proto-signing": "^0.36.0",
4748
"@cosmjs/tendermint-rpc": "^0.36.0",

‎packages/core-modules/src/cosmos.staking.v1beta1/index.ts‎

Lines changed: 168 additions & 38 deletions
Large diffs are not rendered by default.

‎packages/core-modules/src/cosmos.staking.v1beta1/sql/module.sql‎

Lines changed: 37 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,49 @@
1-
/* ---- PARAMS ---- */
1+
/* ---- VALIDATORS INFO ---- */
2+
3+
/* Operator-level static info. One row per validator, keyed by operator_address
4+
(which never changes across a consensus-key rotation). Referenced by the
5+
description/commission/voting-power/status tables. */
6+
CREATE TABLE validator_infos
7+
(
8+
operator_address TEXT NOT NULL UNIQUE,
9+
self_delegate_address TEXT REFERENCES accounts (address),
10+
max_change_rate TEXT NOT NULL,
11+
max_rate TEXT NOT NULL,
12+
height BIGINT REFERENCES blocks (height)
13+
);
14+
CREATE INDEX validator_info_operator_address_index ON validator_infos (operator_address);
15+
CREATE INDEX validator_info_self_delegate_address_index ON validator_infos (self_delegate_address);
16+
17+
/* ---- VALIDATORS (consensus keys) ---- */
18+
19+
/* One row per consensus key a validator has ever used. On a MsgRotateConsPubKey
20+
the previous row is flipped to is_active=false and a new row is appended, so
21+
this table doubles as the historical operator<->consensus mapping (an old
22+
block's proposer_address still resolves here to its operator). */
223
CREATE TABLE validators
324
(
4-
consensus_address TEXT NOT NULL PRIMARY KEY, /* Validator consensus address */
5-
consensus_pubkey TEXT NOT NULL UNIQUE /* Validator consensus public key */
25+
consensus_address TEXT NOT NULL PRIMARY KEY, /* Validator consensus address */
26+
consensus_pubkey TEXT NOT NULL UNIQUE, /* Validator consensus public key */
27+
operator_address TEXT NOT NULL REFERENCES validator_infos (operator_address),
28+
is_active BOOLEAN NOT NULL DEFAULT TRUE, /* Whether this is the validator's current consensus key */
29+
height BIGINT REFERENCES blocks (height) /* Height at which this key became active */
630
);
31+
/* At most one active consensus key per operator */
32+
CREATE UNIQUE INDEX validators_active_operator_idx ON validators (operator_address) WHERE is_active;
33+
CREATE INDEX validators_operator_address_index ON validators (operator_address);
734
ALTER TABLE blocks ADD CONSTRAINT block_validator_fkey FOREIGN KEY(proposer_address) REFERENCES validators(consensus_address);
835

36+
/* ---- PARAMS ---- */
937
CREATE TABLE staking_params
1038
(
11-
39+
1240
params JSONB NOT NULL,
1341
height BIGINT
14-
42+
1543
);
1644
CREATE INDEX staking_params_height_index ON staking_params (height DESC NULLS LAST);
1745

18-
CREATE TABLE staked_balances
46+
CREATE TABLE staked_balances
1947
(
2048
delegator TEXT REFERENCES accounts (address),
2149
shares numeric NOT NULL,
@@ -30,29 +58,14 @@ CREATE INDEX staked_balances_lookup_index ON staked_balances (delegator, validat
3058
/* ---- POOL ---- */
3159
CREATE TABLE staking_pool
3260
(
33-
61+
3462
bonded_tokens TEXT NOT NULL,
3563
not_bonded_tokens TEXT NOT NULL,
3664
height BIGINT,
3765
CONSTRAINT unique_pool UNIQUE (bonded_tokens, not_bonded_tokens)
38-
39-
);
40-
CREATE INDEX staking_pool_height_index ON staking_pool (height DESC NULLS LAST);
4166

42-
/* ---- VALIDATORS INFO ---- */
43-
44-
CREATE TABLE validator_infos
45-
(
46-
consensus_address TEXT NOT NULL UNIQUE REFERENCES validators (consensus_address),
47-
operator_address TEXT NOT NULL UNIQUE,
48-
self_delegate_address TEXT REFERENCES accounts (address),
49-
max_change_rate TEXT NOT NULL,
50-
max_rate TEXT NOT NULL,
51-
height BIGINT REFERENCES blocks (height)
5267
);
53-
CREATE INDEX validator_info_operator_address_index ON validator_infos (operator_address);
54-
CREATE INDEX validator_info_consensus_address_index ON validator_infos (consensus_address);
55-
CREATE INDEX validator_info_self_delegate_address_index ON validator_infos (self_delegate_address);
68+
CREATE INDEX staking_pool_height_index ON staking_pool (height DESC NULLS LAST);
5669

5770
CREATE TABLE validator_descriptions
5871
(
@@ -98,4 +111,4 @@ CREATE TABLE validator_status
98111
);
99112
CREATE INDEX validator_status_height_index ON validator_status (height DESC NULLS LAST);
100113
CREATE INDEX validator_status_height_desc_null_lasts_index ON validator_status (height DESC NULLS LAST);
101-
CREATE INDEX validator_status_address_index ON validator_status (validator_address);
114+
CREATE INDEX validator_status_address_index ON validator_status (validator_address);

‎packages/indexer-engine/CHANGELOG.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# @eclesia/indexer-engine
22

3+
## 2.14.5
4+
5+
### Patch Changes
6+
7+
- 10c0226: Better RPC connect/disconnect handling and logging
8+
39
## 2.14.2
410

511
### Patch Changes

‎packages/indexer-engine/package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@eclesia/indexer-engine",
3-
"version": "2.14.2",
3+
"version": "2.14.5",
44
"description": "Core eclesia indexer engine",
55
"scripts": {
66
"build": "tsc --noEmit && tsdown",

‎packages/indexer-engine/src/indexer/index.ts‎

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -332,18 +332,27 @@ export class EcleciaIndexer extends EclesiaEmitter {
332332

333333
public async connect() {
334334
try {
335-
if (this.client && this.tryToRecover) {
335+
if (this.client) {
336336
this.log.verbose("Recover from error. Attempting to disconnect from RPC");
337-
this.client.disconnect();
338-
this.blockClient.disconnect();
337+
try {
338+
this.client.disconnect();
339+
}
340+
catch (_e) { /* empty */ }
341+
try {
342+
this.blockClient?.disconnect();
343+
}
344+
catch (_e) { /* empty */ }
339345
this.log.verbose("Disconnected from RPC");
340346
}
341347
const connectTimeoutPromise = new Promise<ReturnType<typeof connectComet>>((resolve, reject) => {
342-
setTimeout(reject, CONNECT_TIMEOUT_MS, []);
348+
setTimeout(reject, CONNECT_TIMEOUT_MS, new RPCError("RPC connection timed out"));
343349
});
350+
this.log.info("Attempting to connected to RPC: " + this.config.rpcUrl);
344351
this.client = await Promise.race([connectComet(this.config.rpcUrl), connectTimeoutPromise]);
352+
await Promise.race([this.client.status(), connectTimeoutPromise]);
345353
this.log.info("Connected to RPC for ad hoc queries");
346354
this.blockClient = await Promise.race([connectComet(this.config.rpcUrl), connectTimeoutPromise]);
355+
await Promise.race([this.blockClient.status(), connectTimeoutPromise]);
347356
this.log.info("Connected to RPC for block & validator info");
348357

349358
return true;
@@ -420,7 +429,7 @@ export class EcleciaIndexer extends EclesiaEmitter {
420429
const statusPromise: Promise<StatusResponse> = new Promise((resolve, reject) => {
421430
setTimeout(reject,
422431
RPC_TIMEOUT_MS,
423-
false);
432+
new RPCError("RPC status call timed out"));
424433
});
425434
const status = await Promise.race([this.client.status(), statusPromise]);
426435
this.latestHeight = status.syncInfo.latestBlockHeight;

‎pnpm-lock.yaml‎

Lines changed: 23 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)