@gzeoneth/gov-tracker 0.2.1-beta.ec7d8a7 → 0.2.1-beta.f5af747
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +126 -80
- package/dist/abis.d.ts +3 -0
- package/dist/abis.d.ts.map +1 -1
- package/dist/abis.js +30 -2
- package/dist/abis.js.map +1 -1
- package/dist/calldata/index.d.ts +1 -1
- package/dist/calldata/index.d.ts.map +1 -1
- package/dist/calldata/index.js.map +1 -1
- package/dist/calldata/parameter-decoder.d.ts.map +1 -1
- package/dist/calldata/parameter-decoder.js +8 -1
- package/dist/calldata/parameter-decoder.js.map +1 -1
- package/dist/calldata/signature-lookup.d.ts +17 -2
- package/dist/calldata/signature-lookup.d.ts.map +1 -1
- package/dist/calldata/signature-lookup.js +20 -2
- package/dist/calldata/signature-lookup.js.map +1 -1
- package/dist/cli/cli.js +266 -27
- package/dist/cli/cli.js.map +1 -1
- package/dist/cli/lib/cli.d.ts +50 -2
- package/dist/cli/lib/cli.d.ts.map +1 -1
- package/dist/cli/lib/cli.js +378 -66
- package/dist/cli/lib/cli.js.map +1 -1
- package/dist/cli/lib/json-state.d.ts +23 -0
- package/dist/cli/lib/json-state.d.ts.map +1 -1
- package/dist/cli/lib/json-state.js +51 -4
- package/dist/cli/lib/json-state.js.map +1 -1
- package/dist/constants.d.ts +9 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +16 -1
- package/dist/constants.js.map +1 -1
- package/dist/data/bundled-cache.json +3720 -1240
- package/dist/deduplication.d.ts +132 -0
- package/dist/deduplication.d.ts.map +1 -0
- package/dist/deduplication.js +270 -0
- package/dist/deduplication.js.map +1 -0
- package/dist/discovery/governor-discovery.d.ts.map +1 -1
- package/dist/discovery/governor-discovery.js +50 -35
- package/dist/discovery/governor-discovery.js.map +1 -1
- package/dist/discovery/timelock-discovery.d.ts +15 -6
- package/dist/discovery/timelock-discovery.d.ts.map +1 -1
- package/dist/discovery/timelock-discovery.js +27 -11
- package/dist/discovery/timelock-discovery.js.map +1 -1
- package/dist/election/contracts.d.ts +8 -0
- package/dist/election/contracts.d.ts.map +1 -0
- package/dist/election/contracts.js +28 -0
- package/dist/election/contracts.js.map +1 -0
- package/dist/election/details.d.ts +5 -0
- package/dist/election/details.d.ts.map +1 -0
- package/dist/election/details.js +95 -0
- package/dist/election/details.js.map +1 -0
- package/dist/election/index.d.ts +11 -0
- package/dist/election/index.d.ts.map +1 -0
- package/dist/election/index.js +45 -0
- package/dist/election/index.js.map +1 -0
- package/dist/election/params.d.ts +13 -0
- package/dist/election/params.d.ts.map +1 -0
- package/dist/election/params.js +93 -0
- package/dist/election/params.js.map +1 -0
- package/dist/election/participants.d.ts +6 -0
- package/dist/election/participants.d.ts.map +1 -0
- package/dist/election/participants.js +102 -0
- package/dist/election/participants.js.map +1 -0
- package/dist/election/prepare.d.ts +10 -0
- package/dist/election/prepare.d.ts.map +1 -0
- package/dist/election/prepare.js +52 -0
- package/dist/election/prepare.js.map +1 -0
- package/dist/election/proposal-ids.d.ts +18 -0
- package/dist/election/proposal-ids.d.ts.map +1 -0
- package/dist/election/proposal-ids.js +77 -0
- package/dist/election/proposal-ids.js.map +1 -0
- package/dist/election/status.d.ts +6 -0
- package/dist/election/status.d.ts.map +1 -0
- package/dist/election/status.js +86 -0
- package/dist/election/status.js.map +1 -0
- package/dist/election/tracking.d.ts +28 -0
- package/dist/election/tracking.d.ts.map +1 -0
- package/dist/election/tracking.js +412 -0
- package/dist/election/tracking.js.map +1 -0
- package/dist/index.d.ts +29 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +81 -8
- package/dist/index.js.map +1 -1
- package/dist/stages/builder.d.ts +4 -0
- package/dist/stages/builder.d.ts.map +1 -1
- package/dist/stages/builder.js +7 -0
- package/dist/stages/builder.js.map +1 -1
- package/dist/stages/l2-to-l1-message.d.ts +3 -1
- package/dist/stages/l2-to-l1-message.d.ts.map +1 -1
- package/dist/stages/l2-to-l1-message.js +6 -6
- package/dist/stages/l2-to-l1-message.js.map +1 -1
- package/dist/stages/proposal-created.d.ts +1 -0
- package/dist/stages/proposal-created.d.ts.map +1 -1
- package/dist/stages/proposal-created.js +1 -0
- package/dist/stages/proposal-created.js.map +1 -1
- package/dist/stages/proposal-queued.d.ts +1 -0
- package/dist/stages/proposal-queued.d.ts.map +1 -1
- package/dist/stages/proposal-queued.js +3 -1
- package/dist/stages/proposal-queued.js.map +1 -1
- package/dist/stages/retryables.js +2 -2
- package/dist/stages/retryables.js.map +1 -1
- package/dist/stages/timelock.d.ts +3 -1
- package/dist/stages/timelock.d.ts.map +1 -1
- package/dist/stages/timelock.js +11 -7
- package/dist/stages/timelock.js.map +1 -1
- package/dist/stages/utils.d.ts +4 -7
- package/dist/stages/utils.d.ts.map +1 -1
- package/dist/stages/utils.js +31 -22
- package/dist/stages/utils.js.map +1 -1
- package/dist/stages/voting.d.ts.map +1 -1
- package/dist/stages/voting.js +5 -4
- package/dist/stages/voting.js.map +1 -1
- package/dist/tracker/cache.d.ts +10 -6
- package/dist/tracker/cache.d.ts.map +1 -1
- package/dist/tracker/cache.js +36 -13
- package/dist/tracker/cache.js.map +1 -1
- package/dist/tracker/checkpoint-helpers.d.ts +63 -0
- package/dist/tracker/checkpoint-helpers.d.ts.map +1 -0
- package/dist/tracker/checkpoint-helpers.js +176 -0
- package/dist/tracker/checkpoint-helpers.js.map +1 -0
- package/dist/tracker/discovery.d.ts +40 -9
- package/dist/tracker/discovery.d.ts.map +1 -1
- package/dist/tracker/discovery.js +152 -15
- package/dist/tracker/discovery.js.map +1 -1
- package/dist/tracker/execute.d.ts.map +1 -1
- package/dist/tracker/execute.js +1 -25
- package/dist/tracker/execute.js.map +1 -1
- package/dist/tracker/pipeline.d.ts.map +1 -1
- package/dist/tracker/pipeline.js +26 -11
- package/dist/tracker/pipeline.js.map +1 -1
- package/dist/tracker/query.d.ts +1 -0
- package/dist/tracker/query.d.ts.map +1 -1
- package/dist/tracker/query.js +14 -61
- package/dist/tracker/query.js.map +1 -1
- package/dist/tracker/state.d.ts +0 -10
- package/dist/tracker/state.d.ts.map +1 -1
- package/dist/tracker/state.js +1 -28
- package/dist/tracker/state.js.map +1 -1
- package/dist/tracker.d.ts +69 -4
- package/dist/tracker.d.ts.map +1 -1
- package/dist/tracker.js +274 -13
- package/dist/tracker.js.map +1 -1
- package/dist/types/config.d.ts +49 -0
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/core.d.ts +4 -2
- package/dist/types/core.d.ts.map +1 -1
- package/dist/types/election.d.ts +91 -0
- package/dist/types/election.d.ts.map +1 -1
- package/dist/types/index.d.ts +5 -7
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +2 -3
- package/dist/types/index.js.map +1 -1
- package/dist/types/stages.d.ts +70 -1
- package/dist/types/stages.d.ts.map +1 -1
- package/dist/types/stages.js.map +1 -1
- package/dist/types/tracking.d.ts +30 -4
- package/dist/types/tracking.d.ts.map +1 -1
- package/dist/utils/block-cache.d.ts +50 -0
- package/dist/utils/block-cache.d.ts.map +1 -0
- package/dist/utils/block-cache.js +80 -0
- package/dist/utils/block-cache.js.map +1 -0
- package/dist/utils/formatters.d.ts +91 -0
- package/dist/utils/formatters.d.ts.map +1 -0
- package/dist/utils/formatters.js +327 -0
- package/dist/utils/formatters.js.map +1 -0
- package/dist/utils/multicall.d.ts +52 -0
- package/dist/utils/multicall.d.ts.map +1 -0
- package/dist/utils/multicall.js +75 -0
- package/dist/utils/multicall.js.map +1 -0
- package/dist/utils/salt-computation.d.ts.map +1 -1
- package/dist/utils/salt-computation.js +33 -7
- package/dist/utils/salt-computation.js.map +1 -1
- package/dist/utils/stage-metadata.d.ts +0 -20
- package/dist/utils/stage-metadata.d.ts.map +1 -1
- package/dist/utils/stage-metadata.js +29 -44
- package/dist/utils/stage-metadata.js.map +1 -1
- package/dist/utils/timing.d.ts +13 -0
- package/dist/utils/timing.d.ts.map +1 -1
- package/dist/utils/timing.js +37 -1
- package/dist/utils/timing.js.map +1 -1
- package/package.json +10 -2
- package/dist/election.d.ts +0 -172
- package/dist/election.d.ts.map +0 -1
- package/dist/election.js +0 -467
- package/dist/election.js.map +0 -1
- package/dist/types/cross-chain.d.ts +0 -24
- package/dist/types/cross-chain.d.ts.map +0 -1
- package/dist/types/cross-chain.js +0 -6
- package/dist/types/cross-chain.js.map +0 -1
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checkpoint Helper Utilities
|
|
3
|
+
*
|
|
4
|
+
* Shared functions for working with TrackingCheckpoint objects
|
|
5
|
+
* across proposals, timelocks, and elections.
|
|
6
|
+
*/
|
|
7
|
+
import type { TrackingCheckpoint, TrackerStats } from "../types";
|
|
8
|
+
export declare const DEFAULT_ERROR_THRESHOLD = 5;
|
|
9
|
+
/**
|
|
10
|
+
* Checkpoint metadata type (matches TrackingCheckpoint.metadata)
|
|
11
|
+
*/
|
|
12
|
+
export interface CheckpointMetadata {
|
|
13
|
+
errorCount: number;
|
|
14
|
+
lastTrackedAt: number;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Create standard checkpoint metadata
|
|
18
|
+
*/
|
|
19
|
+
export declare function createCheckpointMetadata(errorCount?: number): CheckpointMetadata;
|
|
20
|
+
/**
|
|
21
|
+
* Increment error count for retry logic
|
|
22
|
+
* Gas errors don't increment the count (transient)
|
|
23
|
+
*/
|
|
24
|
+
export declare function incrementErrorCount(currentCount: number, error: Error | string): number;
|
|
25
|
+
/**
|
|
26
|
+
* Check if checkpoint has too many errors to continue tracking
|
|
27
|
+
*/
|
|
28
|
+
export declare function isCheckpointErrored(checkpoint: TrackingCheckpoint, threshold?: number): boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Check if checkpoint represents a completed tracking
|
|
31
|
+
* Works for both proposal/timelock (completedStages) and election (phase) checkpoints
|
|
32
|
+
*/
|
|
33
|
+
export declare function isCheckpointComplete(checkpoint: TrackingCheckpoint): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Get the error count from a checkpoint
|
|
36
|
+
*/
|
|
37
|
+
export declare function getCheckpointErrorCount(checkpoint: TrackingCheckpoint): number;
|
|
38
|
+
/**
|
|
39
|
+
* Cache key format utilities
|
|
40
|
+
*/
|
|
41
|
+
export declare const ELECTION_KEY_PREFIX = "election:";
|
|
42
|
+
export declare const TX_KEY_PREFIX = "tx:";
|
|
43
|
+
export declare const DISCOVERY_KEY_PREFIX = "discovery:";
|
|
44
|
+
export declare const WATERMARKS_KEY = "discovery:watermarks";
|
|
45
|
+
export declare function electionCacheKey(electionIndex: number): string;
|
|
46
|
+
export declare function txHashCacheKey(txHash: string): string;
|
|
47
|
+
export declare function isElectionKey(key: string): boolean;
|
|
48
|
+
export declare function isTxKey(key: string): boolean;
|
|
49
|
+
export declare function isDiscoveryKey(key: string): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Extract election index from cache key
|
|
52
|
+
*/
|
|
53
|
+
export declare function parseElectionKey(key: string): number | null;
|
|
54
|
+
/**
|
|
55
|
+
* Compute aggregated stats from loaded checkpoints.
|
|
56
|
+
*
|
|
57
|
+
* This is the single source of truth for stats computation. Used by:
|
|
58
|
+
* - tracker/query.ts::getStats() (loads from cache adapter)
|
|
59
|
+
* - cli/lib/cli.ts (loads from file)
|
|
60
|
+
* - useCache.ts (already has loaded data)
|
|
61
|
+
*/
|
|
62
|
+
export declare function computeCacheStats(checkpoints: Map<string, TrackingCheckpoint>, elections: Map<number, TrackingCheckpoint>, maxErrorCount?: number): TrackerStats;
|
|
63
|
+
//# sourceMappingURL=checkpoint-helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkpoint-helpers.d.ts","sourceRoot":"","sources":["../../src/tracker/checkpoint-helpers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAIjE,eAAO,MAAM,uBAAuB,IAAI,CAAC;AAEzC;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,UAAU,SAAI,GAAG,kBAAkB,CAK3E;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,CASvF;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,kBAAkB,EAC9B,SAAS,SAA0B,GAClC,OAAO,CAGT;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,kBAAkB,GAAG,OAAO,CAc5E;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,kBAAkB,GAAG,MAAM,CAE9E;AAED;;GAEG;AACH,eAAO,MAAM,mBAAmB,cAAc,CAAC;AAC/C,eAAO,MAAM,aAAa,QAAQ,CAAC;AACnC,eAAO,MAAM,oBAAoB,eAAe,CAAC;AACjD,eAAO,MAAM,cAAc,yBAAyB,CAAC;AAErD,wBAAgB,gBAAgB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAErD;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAElD;AAED,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAE5C;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEnD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAI3D;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,EAC5C,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,EAC1C,aAAa,GAAE,MAAgC,GAC9C,YAAY,CAiEd"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Checkpoint Helper Utilities
|
|
4
|
+
*
|
|
5
|
+
* Shared functions for working with TrackingCheckpoint objects
|
|
6
|
+
* across proposals, timelocks, and elections.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.WATERMARKS_KEY = exports.DISCOVERY_KEY_PREFIX = exports.TX_KEY_PREFIX = exports.ELECTION_KEY_PREFIX = exports.DEFAULT_ERROR_THRESHOLD = void 0;
|
|
10
|
+
exports.createCheckpointMetadata = createCheckpointMetadata;
|
|
11
|
+
exports.incrementErrorCount = incrementErrorCount;
|
|
12
|
+
exports.isCheckpointErrored = isCheckpointErrored;
|
|
13
|
+
exports.isCheckpointComplete = isCheckpointComplete;
|
|
14
|
+
exports.getCheckpointErrorCount = getCheckpointErrorCount;
|
|
15
|
+
exports.electionCacheKey = electionCacheKey;
|
|
16
|
+
exports.txHashCacheKey = txHashCacheKey;
|
|
17
|
+
exports.isElectionKey = isElectionKey;
|
|
18
|
+
exports.isTxKey = isTxKey;
|
|
19
|
+
exports.isDiscoveryKey = isDiscoveryKey;
|
|
20
|
+
exports.parseElectionKey = parseElectionKey;
|
|
21
|
+
exports.computeCacheStats = computeCacheStats;
|
|
22
|
+
const utils_1 = require("../stages/utils");
|
|
23
|
+
const constants_1 = require("../constants");
|
|
24
|
+
exports.DEFAULT_ERROR_THRESHOLD = 5;
|
|
25
|
+
/**
|
|
26
|
+
* Create standard checkpoint metadata
|
|
27
|
+
*/
|
|
28
|
+
function createCheckpointMetadata(errorCount = 0) {
|
|
29
|
+
return {
|
|
30
|
+
errorCount,
|
|
31
|
+
lastTrackedAt: Date.now(),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Increment error count for retry logic
|
|
36
|
+
* Gas errors don't increment the count (transient)
|
|
37
|
+
*/
|
|
38
|
+
function incrementErrorCount(currentCount, error) {
|
|
39
|
+
const isGasError = error instanceof Error
|
|
40
|
+
? error.message.includes("insufficient funds") ||
|
|
41
|
+
error.message.includes("gas required exceeds allowance")
|
|
42
|
+
: typeof error === "string" &&
|
|
43
|
+
(error.includes("insufficient funds") || error.includes("gas required exceeds allowance"));
|
|
44
|
+
return isGasError ? currentCount : currentCount + 1;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Check if checkpoint has too many errors to continue tracking
|
|
48
|
+
*/
|
|
49
|
+
function isCheckpointErrored(checkpoint, threshold = exports.DEFAULT_ERROR_THRESHOLD) {
|
|
50
|
+
const errorCount = checkpoint.metadata?.errorCount ?? 0;
|
|
51
|
+
return errorCount >= threshold;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Check if checkpoint represents a completed tracking
|
|
55
|
+
* Works for both proposal/timelock (completedStages) and election (phase) checkpoints
|
|
56
|
+
*/
|
|
57
|
+
function isCheckpointComplete(checkpoint) {
|
|
58
|
+
const inputType = checkpoint.input.type;
|
|
59
|
+
if (inputType === "election") {
|
|
60
|
+
const electionStatus = checkpoint.cachedData?.electionStatus;
|
|
61
|
+
return electionStatus?.phase === "COMPLETED";
|
|
62
|
+
}
|
|
63
|
+
if (inputType === "discovery") {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
const stages = checkpoint.cachedData?.completedStages ?? [];
|
|
67
|
+
return stages.length > 0 && (0, utils_1.areAllStagesComplete)(stages);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Get the error count from a checkpoint
|
|
71
|
+
*/
|
|
72
|
+
function getCheckpointErrorCount(checkpoint) {
|
|
73
|
+
return checkpoint.metadata?.errorCount ?? 0;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Cache key format utilities
|
|
77
|
+
*/
|
|
78
|
+
exports.ELECTION_KEY_PREFIX = "election:";
|
|
79
|
+
exports.TX_KEY_PREFIX = "tx:";
|
|
80
|
+
exports.DISCOVERY_KEY_PREFIX = "discovery:";
|
|
81
|
+
exports.WATERMARKS_KEY = "discovery:watermarks";
|
|
82
|
+
function electionCacheKey(electionIndex) {
|
|
83
|
+
return `${exports.ELECTION_KEY_PREFIX}${electionIndex}`;
|
|
84
|
+
}
|
|
85
|
+
function txHashCacheKey(txHash) {
|
|
86
|
+
return `${exports.TX_KEY_PREFIX}${txHash.toLowerCase()}`;
|
|
87
|
+
}
|
|
88
|
+
function isElectionKey(key) {
|
|
89
|
+
return key.startsWith(exports.ELECTION_KEY_PREFIX);
|
|
90
|
+
}
|
|
91
|
+
function isTxKey(key) {
|
|
92
|
+
return key.startsWith(exports.TX_KEY_PREFIX);
|
|
93
|
+
}
|
|
94
|
+
function isDiscoveryKey(key) {
|
|
95
|
+
return key.startsWith(exports.DISCOVERY_KEY_PREFIX);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Extract election index from cache key
|
|
99
|
+
*/
|
|
100
|
+
function parseElectionKey(key) {
|
|
101
|
+
if (!isElectionKey(key))
|
|
102
|
+
return null;
|
|
103
|
+
const index = parseInt(key.slice(exports.ELECTION_KEY_PREFIX.length), 10);
|
|
104
|
+
return isNaN(index) ? null : index;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Compute aggregated stats from loaded checkpoints.
|
|
108
|
+
*
|
|
109
|
+
* This is the single source of truth for stats computation. Used by:
|
|
110
|
+
* - tracker/query.ts::getStats() (loads from cache adapter)
|
|
111
|
+
* - cli/lib/cli.ts (loads from file)
|
|
112
|
+
* - useCache.ts (already has loaded data)
|
|
113
|
+
*/
|
|
114
|
+
function computeCacheStats(checkpoints, elections, maxErrorCount = exports.DEFAULT_ERROR_THRESHOLD) {
|
|
115
|
+
let proposalTotal = 0, proposalComplete = 0, proposalActive = 0, proposalErrored = 0;
|
|
116
|
+
let timelockTotal = 0, timelockComplete = 0, timelockActive = 0, timelockErrored = 0;
|
|
117
|
+
let electionTotal = 0, electionComplete = 0;
|
|
118
|
+
for (const checkpoint of checkpoints.values()) {
|
|
119
|
+
const complete = isCheckpointComplete(checkpoint);
|
|
120
|
+
const errored = isCheckpointErrored(checkpoint, maxErrorCount);
|
|
121
|
+
const inputType = checkpoint.input.type;
|
|
122
|
+
if (inputType === "governor") {
|
|
123
|
+
if (checkpoint.input.governorAddress &&
|
|
124
|
+
(0, constants_1.isElectionGovernor)(checkpoint.input.governorAddress)) {
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
proposalTotal++;
|
|
128
|
+
if (complete)
|
|
129
|
+
proposalComplete++;
|
|
130
|
+
else if (errored)
|
|
131
|
+
proposalErrored++;
|
|
132
|
+
else
|
|
133
|
+
proposalActive++;
|
|
134
|
+
}
|
|
135
|
+
else if (inputType === "election") {
|
|
136
|
+
electionTotal++;
|
|
137
|
+
if (complete)
|
|
138
|
+
electionComplete++;
|
|
139
|
+
}
|
|
140
|
+
else if (inputType === "timelock") {
|
|
141
|
+
timelockTotal++;
|
|
142
|
+
if (complete)
|
|
143
|
+
timelockComplete++;
|
|
144
|
+
else if (errored)
|
|
145
|
+
timelockErrored++;
|
|
146
|
+
else
|
|
147
|
+
timelockActive++;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
for (const checkpoint of elections.values()) {
|
|
151
|
+
electionTotal++;
|
|
152
|
+
if (isCheckpointComplete(checkpoint)) {
|
|
153
|
+
electionComplete++;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return {
|
|
157
|
+
total: checkpoints.size + elections.size,
|
|
158
|
+
proposals: {
|
|
159
|
+
total: proposalTotal,
|
|
160
|
+
complete: proposalComplete,
|
|
161
|
+
active: proposalActive,
|
|
162
|
+
errored: proposalErrored,
|
|
163
|
+
},
|
|
164
|
+
timelocks: {
|
|
165
|
+
total: timelockTotal,
|
|
166
|
+
complete: timelockComplete,
|
|
167
|
+
active: timelockActive,
|
|
168
|
+
errored: timelockErrored,
|
|
169
|
+
},
|
|
170
|
+
elections: {
|
|
171
|
+
total: electionTotal,
|
|
172
|
+
complete: electionComplete,
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=checkpoint-helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkpoint-helpers.js","sourceRoot":"","sources":["../../src/tracker/checkpoint-helpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Provides unified discovery API with watermark management.
|
|
6
6
|
*/
|
|
7
7
|
import { ethers } from "ethers";
|
|
8
|
-
import { DiscoveryWatermarks, DiscoveryTargets, CacheAdapter } from "../types";
|
|
8
|
+
import { DiscoveryWatermarks, WatermarkHashes, DiscoveryTargets, DiscoveryKey, CacheAdapter } from "../types";
|
|
9
9
|
import { DiscoveredProposal } from "../discovery/governor-discovery";
|
|
10
10
|
import { DiscoveredTimelockOp } from "../discovery/timelock-discovery";
|
|
11
11
|
export { DiscoveredProposal, DiscoveredTimelockOp };
|
|
@@ -14,18 +14,44 @@ export { DiscoveredProposal, DiscoveredTimelockOp };
|
|
|
14
14
|
* Uses "discovery:" prefix to follow checkpoint pattern.
|
|
15
15
|
*/
|
|
16
16
|
export declare const WATERMARKS_KEY = "discovery:watermarks";
|
|
17
|
+
/**
|
|
18
|
+
* Loaded watermark data including block hashes for reorg detection.
|
|
19
|
+
*/
|
|
20
|
+
export interface LoadedWatermarks {
|
|
21
|
+
watermarks: DiscoveryWatermarks;
|
|
22
|
+
hashes: WatermarkHashes;
|
|
23
|
+
}
|
|
17
24
|
/**
|
|
18
25
|
* Load discovery watermarks from cache.
|
|
19
26
|
* Watermarks are stored as a TrackingCheckpoint for unified cache format.
|
|
20
|
-
* Returns empty
|
|
27
|
+
* Returns empty objects if no watermarks are cached.
|
|
28
|
+
*/
|
|
29
|
+
export declare function loadWatermarks(cache: CacheAdapter | undefined): Promise<LoadedWatermarks>;
|
|
30
|
+
/**
|
|
31
|
+
* Verify a watermark's block hash against the chain.
|
|
32
|
+
* If the hash doesn't match (reorg detected), returns a rolled-back block number.
|
|
33
|
+
*
|
|
34
|
+
* @param key - Watermark key for logging
|
|
35
|
+
* @param blockNumber - The watermark block number to verify
|
|
36
|
+
* @param expectedHash - The stored block hash (undefined if not stored)
|
|
37
|
+
* @param provider - Provider to fetch current block hash
|
|
38
|
+
* @returns The verified block number (original if valid, rolled back if reorg detected)
|
|
21
39
|
*/
|
|
22
|
-
export declare function
|
|
40
|
+
export declare function verifyWatermark(key: DiscoveryKey, blockNumber: number, expectedHash: string | undefined, provider: ethers.providers.Provider): Promise<{
|
|
41
|
+
blockNumber: number;
|
|
42
|
+
isValid: boolean;
|
|
43
|
+
newHash?: string;
|
|
44
|
+
}>;
|
|
23
45
|
/**
|
|
24
46
|
* Save discovery watermarks to cache.
|
|
25
47
|
* Watermarks are stored as TrackingCheckpoint with proper metadata,
|
|
26
48
|
* following the same pattern as proposal/timelock checkpoints.
|
|
49
|
+
*
|
|
50
|
+
* @param watermarks - Block numbers per discovery key
|
|
51
|
+
* @param hashes - Block hashes per discovery key (for reorg detection)
|
|
52
|
+
* @param cache - Cache adapter
|
|
27
53
|
*/
|
|
28
|
-
export declare function saveWatermarks(watermarks: DiscoveryWatermarks, cache: CacheAdapter | undefined): Promise<void>;
|
|
54
|
+
export declare function saveWatermarks(watermarks: DiscoveryWatermarks, hashes: WatermarkHashes, cache: CacheAdapter | undefined): Promise<void>;
|
|
29
55
|
/**
|
|
30
56
|
* Discover proposals from a governor in a block range.
|
|
31
57
|
*
|
|
@@ -61,29 +87,34 @@ export declare function discoverTimelockOps(timelockAddress: string, fromBlock:
|
|
|
61
87
|
* 2. The monitor-loop skips timelock ops that were tracked via governor
|
|
62
88
|
* 3. Creating pending checkpoints for all timelock ops causes double-counting
|
|
63
89
|
*/
|
|
64
|
-
export declare function createPendingCheckpoints(proposals: DiscoveredProposal[],
|
|
90
|
+
export declare function createPendingCheckpoints(proposals: DiscoveredProposal[], timelockOps: DiscoveredTimelockOp[], cache: CacheAdapter | undefined): Promise<void>;
|
|
65
91
|
/**
|
|
66
92
|
* Discover all proposals and timelock operations with auto-watermark management.
|
|
67
93
|
*
|
|
68
94
|
* This is the unified discovery API that handles everything internally:
|
|
95
|
+
* - Verifies watermark hashes to detect chain reorgs (rolls back if mismatch)
|
|
69
96
|
* - Loads watermarks from provided watermarks or starts from governance deployment
|
|
70
97
|
* - Discovers from all enabled targets in parallel (with scoped logging)
|
|
71
98
|
* - Creates pending checkpoints for discovered items
|
|
72
|
-
* - Returns updated watermarks for saving
|
|
99
|
+
* - Returns updated watermarks and hashes for saving
|
|
73
100
|
*
|
|
74
101
|
* @param targets - Which governors/timelocks to scan
|
|
75
102
|
* @param toBlock - End block for discovery
|
|
76
103
|
* @param l2Provider - L2 provider
|
|
77
104
|
* @param cache - Cache adapter for pending checkpoint creation
|
|
78
|
-
* @param fromWatermarks - Starting watermarks
|
|
105
|
+
* @param fromWatermarks - Starting watermarks (block numbers)
|
|
106
|
+
* @param fromHashes - Starting hashes for reorg detection
|
|
79
107
|
* @param options.chunkSize - Optional chunk size for log searches
|
|
80
|
-
* @
|
|
108
|
+
* @param options.skipReorgCheck - Skip reorg verification (for testing)
|
|
109
|
+
* @returns Discovered proposals, timelock ops, updated watermarks and hashes
|
|
81
110
|
*/
|
|
82
|
-
export declare function discoverAll(targets: DiscoveryTargets, toBlock: number, l2Provider: ethers.providers.Provider, cache: CacheAdapter | undefined, fromWatermarks: DiscoveryWatermarks, options?: {
|
|
111
|
+
export declare function discoverAll(targets: DiscoveryTargets, toBlock: number, l2Provider: ethers.providers.Provider, cache: CacheAdapter | undefined, fromWatermarks: DiscoveryWatermarks, fromHashes?: WatermarkHashes, options?: {
|
|
83
112
|
chunkSize?: number;
|
|
113
|
+
skipReorgCheck?: boolean;
|
|
84
114
|
}): Promise<{
|
|
85
115
|
proposals: DiscoveredProposal[];
|
|
86
116
|
timelockOps: DiscoveredTimelockOp[];
|
|
87
117
|
watermarks: DiscoveryWatermarks;
|
|
118
|
+
hashes: WatermarkHashes;
|
|
88
119
|
}>;
|
|
89
120
|
//# sourceMappingURL=discovery.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../src/tracker/discovery.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,
|
|
1
|
+
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../src/tracker/discovery.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAEL,mBAAmB,EACnB,eAAe,EACf,gBAAgB,EAChB,YAAY,EACZ,YAAY,EACb,MAAM,UAAU,CAAC;AAElB,OAAO,EAEL,kBAAkB,EAGnB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAEL,oBAAoB,EACrB,MAAM,iCAAiC,CAAC;AAMzC,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,CAAC;AAEpD;;;GAGG;AACH,eAAO,MAAM,cAAc,yBAAyB,CAAC;AAErD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,mBAAmB,CAAC;IAChC,MAAM,EAAE,eAAe,CAAC;CACzB;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,KAAK,EAAE,YAAY,GAAG,SAAS,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAO/F;AAQD;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,YAAY,EACjB,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,QAAQ,EAAE,MAAM,CAAC,SAAS,CAAC,QAAQ,GAClC,OAAO,CAAC;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAsDtE;AAED;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAClC,UAAU,EAAE,mBAAmB,EAC/B,MAAM,EAAE,eAAe,EACvB,KAAK,EAAE,YAAY,GAAG,SAAS,GAC9B,OAAO,CAAC,IAAI,CAAC,CAiCf;AAED;;;;;;;;;GASG;AACH,wBAAsB,iBAAiB,CACrC,eAAe,EAAE,MAAM,EACvB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,CAAC,SAAS,CAAC,QAAQ,EACrC,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GACnC,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAG/B;AAED;;;;;;;;;GASG;AACH,wBAAsB,mBAAmB,CACvC,eAAe,EAAE,MAAM,EACvB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,CAAC,SAAS,CAAC,QAAQ,EACrC,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GACnC,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAGjC;AAED;;;;;;;;GAQG;AACH,wBAAsB,wBAAwB,CAC5C,SAAS,EAAE,kBAAkB,EAAE,EAC/B,WAAW,EAAE,oBAAoB,EAAE,EACnC,KAAK,EAAE,YAAY,GAAG,SAAS,GAC9B,OAAO,CAAC,IAAI,CAAC,CA8Cf;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,gBAAgB,EACzB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,CAAC,SAAS,CAAC,QAAQ,EACrC,KAAK,EAAE,YAAY,GAAG,SAAS,EAC/B,cAAc,EAAE,mBAAmB,EACnC,UAAU,GAAE,eAAoB,EAChC,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,OAAO,CAAA;CAAO,GAC7D,OAAO,CAAC;IACT,SAAS,EAAE,kBAAkB,EAAE,CAAC;IAChC,WAAW,EAAE,oBAAoB,EAAE,CAAC;IACpC,UAAU,EAAE,mBAAmB,CAAC;IAChC,MAAM,EAAE,eAAe,CAAC;CACzB,CAAC,CAgMD"}
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
9
|
exports.WATERMARKS_KEY = void 0;
|
|
10
10
|
exports.loadWatermarks = loadWatermarks;
|
|
11
|
+
exports.verifyWatermark = verifyWatermark;
|
|
11
12
|
exports.saveWatermarks = saveWatermarks;
|
|
12
13
|
exports.discoverProposals = discoverProposals;
|
|
13
14
|
exports.discoverTimelockOps = discoverTimelockOps;
|
|
@@ -17,6 +18,7 @@ const constants_1 = require("../constants");
|
|
|
17
18
|
const governor_discovery_1 = require("../discovery/governor-discovery");
|
|
18
19
|
const timelock_discovery_1 = require("../discovery/timelock-discovery");
|
|
19
20
|
const logger_1 = require("../utils/logger");
|
|
21
|
+
const rpc_utils_1 = require("../utils/rpc-utils");
|
|
20
22
|
const { tracker: logTracker, discovery: logDiscovery } = logger_1.loggers;
|
|
21
23
|
/**
|
|
22
24
|
* Cache key for discovery watermarks checkpoint.
|
|
@@ -26,20 +28,83 @@ exports.WATERMARKS_KEY = "discovery:watermarks";
|
|
|
26
28
|
/**
|
|
27
29
|
* Load discovery watermarks from cache.
|
|
28
30
|
* Watermarks are stored as a TrackingCheckpoint for unified cache format.
|
|
29
|
-
* Returns empty
|
|
31
|
+
* Returns empty objects if no watermarks are cached.
|
|
30
32
|
*/
|
|
31
33
|
async function loadWatermarks(cache) {
|
|
32
34
|
if (!cache)
|
|
33
|
-
return {};
|
|
35
|
+
return { watermarks: {}, hashes: {} };
|
|
34
36
|
const checkpoint = await cache.get(exports.WATERMARKS_KEY);
|
|
35
|
-
return
|
|
37
|
+
return {
|
|
38
|
+
watermarks: checkpoint?.cachedData.discoveryWatermarks ?? {},
|
|
39
|
+
hashes: checkpoint?.cachedData.watermarkHashes ?? {},
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Number of blocks to roll back when a reorg is detected.
|
|
44
|
+
* 1000 blocks on L2 Arbitrum ≈ ~4 minutes, provides safety margin.
|
|
45
|
+
*/
|
|
46
|
+
const REORG_ROLLBACK_BLOCKS = 1000;
|
|
47
|
+
/**
|
|
48
|
+
* Verify a watermark's block hash against the chain.
|
|
49
|
+
* If the hash doesn't match (reorg detected), returns a rolled-back block number.
|
|
50
|
+
*
|
|
51
|
+
* @param key - Watermark key for logging
|
|
52
|
+
* @param blockNumber - The watermark block number to verify
|
|
53
|
+
* @param expectedHash - The stored block hash (undefined if not stored)
|
|
54
|
+
* @param provider - Provider to fetch current block hash
|
|
55
|
+
* @returns The verified block number (original if valid, rolled back if reorg detected)
|
|
56
|
+
*/
|
|
57
|
+
async function verifyWatermark(key, blockNumber, expectedHash, provider) {
|
|
58
|
+
const rollback = () => ({
|
|
59
|
+
blockNumber: Math.max(0, blockNumber - REORG_ROLLBACK_BLOCKS),
|
|
60
|
+
isValid: false,
|
|
61
|
+
});
|
|
62
|
+
// No stored hash - can't verify, but fetch current hash for future verification
|
|
63
|
+
if (!expectedHash) {
|
|
64
|
+
try {
|
|
65
|
+
const block = await (0, rpc_utils_1.queryWithRetry)(() => provider.getBlock(blockNumber));
|
|
66
|
+
if (block) {
|
|
67
|
+
logDiscovery("%s: no stored hash, establishing hash at block %d", key, blockNumber);
|
|
68
|
+
return { blockNumber, isValid: true, newHash: block.hash };
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
// Block might not exist yet or provider error - continue without hash
|
|
73
|
+
}
|
|
74
|
+
return { blockNumber, isValid: true };
|
|
75
|
+
}
|
|
76
|
+
// Verify stored hash against chain
|
|
77
|
+
try {
|
|
78
|
+
const block = await (0, rpc_utils_1.queryWithRetry)(() => provider.getBlock(blockNumber));
|
|
79
|
+
if (!block) {
|
|
80
|
+
const result = rollback();
|
|
81
|
+
logDiscovery("%s: block %d not found, rolling back to %d", key, blockNumber, result.blockNumber);
|
|
82
|
+
return result;
|
|
83
|
+
}
|
|
84
|
+
if (block.hash.toLowerCase() === expectedHash.toLowerCase()) {
|
|
85
|
+
return { blockNumber, isValid: true, newHash: block.hash };
|
|
86
|
+
}
|
|
87
|
+
// Hash mismatch - reorg detected
|
|
88
|
+
const result = rollback();
|
|
89
|
+
logDiscovery("%s: REORG DETECTED at block %d (expected %s, got %s), rolling back to %d", key, blockNumber, expectedHash.slice(0, 10), block.hash.slice(0, 10), result.blockNumber);
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
// Provider error - be conservative and continue with stored watermark
|
|
94
|
+
logDiscovery("%s: failed to verify block %d, continuing with stored value", key, blockNumber);
|
|
95
|
+
return { blockNumber, isValid: true };
|
|
96
|
+
}
|
|
36
97
|
}
|
|
37
98
|
/**
|
|
38
99
|
* Save discovery watermarks to cache.
|
|
39
100
|
* Watermarks are stored as TrackingCheckpoint with proper metadata,
|
|
40
101
|
* following the same pattern as proposal/timelock checkpoints.
|
|
102
|
+
*
|
|
103
|
+
* @param watermarks - Block numbers per discovery key
|
|
104
|
+
* @param hashes - Block hashes per discovery key (for reorg detection)
|
|
105
|
+
* @param cache - Cache adapter
|
|
41
106
|
*/
|
|
42
|
-
async function saveWatermarks(watermarks, cache) {
|
|
107
|
+
async function saveWatermarks(watermarks, hashes, cache) {
|
|
43
108
|
if (!cache)
|
|
44
109
|
return;
|
|
45
110
|
// Calculate the max L2 block from watermarks for lastProcessedBlock
|
|
@@ -61,6 +126,7 @@ async function saveWatermarks(watermarks, cache) {
|
|
|
61
126
|
lastProcessedBlock: { l1: 0, l2: maxL2Block },
|
|
62
127
|
cachedData: {
|
|
63
128
|
discoveryWatermarks: watermarks,
|
|
129
|
+
watermarkHashes: hashes,
|
|
64
130
|
},
|
|
65
131
|
metadata: {
|
|
66
132
|
errorCount: 0,
|
|
@@ -107,13 +173,21 @@ async function discoverTimelockOps(timelockAddress, fromBlock, toBlock, l2Provid
|
|
|
107
173
|
* 2. The monitor-loop skips timelock ops that were tracked via governor
|
|
108
174
|
* 3. Creating pending checkpoints for all timelock ops causes double-counting
|
|
109
175
|
*/
|
|
110
|
-
async function createPendingCheckpoints(proposals,
|
|
176
|
+
async function createPendingCheckpoints(proposals, timelockOps, cache) {
|
|
177
|
+
void timelockOps;
|
|
111
178
|
if (!cache)
|
|
112
179
|
return;
|
|
113
180
|
let created = 0;
|
|
181
|
+
let skippedElections = 0;
|
|
114
182
|
// Create pending checkpoints for proposals (if not already tracked)
|
|
115
183
|
// Use tx: key format to match trackByTxHash cache keys
|
|
184
|
+
// Skip election proposals - they use election:* checkpoints
|
|
116
185
|
for (const p of proposals) {
|
|
186
|
+
const proposalType = (0, governor_discovery_1.detectProposalType)(p.governorAddress);
|
|
187
|
+
if ((0, governor_discovery_1.isElectionProposal)(proposalType)) {
|
|
188
|
+
skippedElections++;
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
117
191
|
const key = `tx:${p.creationTxHash.toLowerCase()}`;
|
|
118
192
|
const existing = await cache.get(key);
|
|
119
193
|
if (existing)
|
|
@@ -135,33 +209,73 @@ async function createPendingCheckpoints(proposals, _timelockOps, cache) {
|
|
|
135
209
|
await cache.set(key, checkpoint);
|
|
136
210
|
created++;
|
|
137
211
|
}
|
|
138
|
-
if (created > 0) {
|
|
139
|
-
logDiscovery("created pending checkpoints: %d proposals", created);
|
|
212
|
+
if (created > 0 || skippedElections > 0) {
|
|
213
|
+
logDiscovery("created pending checkpoints: %d proposals (skipped %d elections)", created, skippedElections);
|
|
140
214
|
}
|
|
141
215
|
}
|
|
142
216
|
/**
|
|
143
217
|
* Discover all proposals and timelock operations with auto-watermark management.
|
|
144
218
|
*
|
|
145
219
|
* This is the unified discovery API that handles everything internally:
|
|
220
|
+
* - Verifies watermark hashes to detect chain reorgs (rolls back if mismatch)
|
|
146
221
|
* - Loads watermarks from provided watermarks or starts from governance deployment
|
|
147
222
|
* - Discovers from all enabled targets in parallel (with scoped logging)
|
|
148
223
|
* - Creates pending checkpoints for discovered items
|
|
149
|
-
* - Returns updated watermarks for saving
|
|
224
|
+
* - Returns updated watermarks and hashes for saving
|
|
150
225
|
*
|
|
151
226
|
* @param targets - Which governors/timelocks to scan
|
|
152
227
|
* @param toBlock - End block for discovery
|
|
153
228
|
* @param l2Provider - L2 provider
|
|
154
229
|
* @param cache - Cache adapter for pending checkpoint creation
|
|
155
|
-
* @param fromWatermarks - Starting watermarks
|
|
230
|
+
* @param fromWatermarks - Starting watermarks (block numbers)
|
|
231
|
+
* @param fromHashes - Starting hashes for reorg detection
|
|
156
232
|
* @param options.chunkSize - Optional chunk size for log searches
|
|
157
|
-
* @
|
|
233
|
+
* @param options.skipReorgCheck - Skip reorg verification (for testing)
|
|
234
|
+
* @returns Discovered proposals, timelock ops, updated watermarks and hashes
|
|
158
235
|
*/
|
|
159
|
-
async function discoverAll(targets, toBlock, l2Provider, cache, fromWatermarks, options = {}) {
|
|
160
|
-
const watermarks = fromWatermarks;
|
|
236
|
+
async function discoverAll(targets, toBlock, l2Provider, cache, fromWatermarks, fromHashes = {}, options = {}) {
|
|
161
237
|
const defaultStartBlock = constants_1.GOVERNANCE_START_BLOCKS.L2;
|
|
238
|
+
// Determine which keys we'll be discovering
|
|
239
|
+
const allKeys = [
|
|
240
|
+
"constitutionalGovernor",
|
|
241
|
+
"nonConstitutionalGovernor",
|
|
242
|
+
"electionNomineeGovernor",
|
|
243
|
+
"electionMemberGovernor",
|
|
244
|
+
"l2ConstitutionalTimelock",
|
|
245
|
+
"l2NonConstitutionalTimelock",
|
|
246
|
+
];
|
|
247
|
+
const activeKeys = allKeys.filter((key) => targets[key]);
|
|
248
|
+
// Verify watermarks and get effective start blocks (with reorg detection)
|
|
249
|
+
const verifiedWatermarks = {};
|
|
250
|
+
const updatedHashes = { ...fromHashes };
|
|
251
|
+
if (!options.skipReorgCheck) {
|
|
252
|
+
// Verify all active watermarks in parallel
|
|
253
|
+
const verificationPromises = activeKeys.map(async (key) => {
|
|
254
|
+
const storedBlock = fromWatermarks[key];
|
|
255
|
+
if (storedBlock === undefined) {
|
|
256
|
+
return { key, blockNumber: defaultStartBlock };
|
|
257
|
+
}
|
|
258
|
+
const result = await verifyWatermark(key, storedBlock, fromHashes[key], l2Provider);
|
|
259
|
+
// Update hash if we got a new one
|
|
260
|
+
if (result.newHash) {
|
|
261
|
+
updatedHashes[key] = result.newHash;
|
|
262
|
+
}
|
|
263
|
+
return { key, blockNumber: result.blockNumber };
|
|
264
|
+
});
|
|
265
|
+
const verificationResults = await Promise.all(verificationPromises);
|
|
266
|
+
for (const { key, blockNumber } of verificationResults) {
|
|
267
|
+
verifiedWatermarks[key] = blockNumber;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
// Skip verification - use provided watermarks directly
|
|
272
|
+
for (const key of activeKeys) {
|
|
273
|
+
verifiedWatermarks[key] = fromWatermarks[key] ?? defaultStartBlock;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
162
276
|
// Helper to create scoped discovery task
|
|
163
277
|
const scopedProposalTask = (key, scopeName, governorAddress) => {
|
|
164
|
-
const fromBlock =
|
|
278
|
+
const fromBlock = verifiedWatermarks[key] ?? defaultStartBlock;
|
|
165
279
|
return (0, logger_1.withScope)(scopeName, async () => {
|
|
166
280
|
const proposals = await discoverProposals(governorAddress, fromBlock, toBlock, l2Provider, {
|
|
167
281
|
chunkSize: options.chunkSize,
|
|
@@ -170,7 +284,7 @@ async function discoverAll(targets, toBlock, l2Provider, cache, fromWatermarks,
|
|
|
170
284
|
});
|
|
171
285
|
};
|
|
172
286
|
const scopedTimelockTask = (key, scopeName, timelockAddress) => {
|
|
173
|
-
const fromBlock =
|
|
287
|
+
const fromBlock = verifiedWatermarks[key] ?? defaultStartBlock;
|
|
174
288
|
return (0, logger_1.withScope)(scopeName, async () => {
|
|
175
289
|
const ops = await discoverTimelockOps(timelockAddress, fromBlock, toBlock, l2Provider, {
|
|
176
290
|
chunkSize: options.chunkSize,
|
|
@@ -207,7 +321,7 @@ async function discoverAll(targets, toBlock, l2Provider, cache, fromWatermarks,
|
|
|
207
321
|
// Collect results and update watermarks
|
|
208
322
|
const allProposals = [];
|
|
209
323
|
const allTimelockOps = [];
|
|
210
|
-
const newWatermarks = { ...
|
|
324
|
+
const newWatermarks = { ...verifiedWatermarks };
|
|
211
325
|
for (const { key, proposals } of proposalResults) {
|
|
212
326
|
allProposals.push(...proposals);
|
|
213
327
|
newWatermarks[key] = toBlock;
|
|
@@ -216,6 +330,28 @@ async function discoverAll(targets, toBlock, l2Provider, cache, fromWatermarks,
|
|
|
216
330
|
allTimelockOps.push(...ops);
|
|
217
331
|
newWatermarks[key] = toBlock;
|
|
218
332
|
}
|
|
333
|
+
// Fetch toBlock hash for reorg detection on next run
|
|
334
|
+
// Only need to fetch once since all keys use the same toBlock
|
|
335
|
+
let toBlockHash;
|
|
336
|
+
if (activeKeys.length > 0) {
|
|
337
|
+
try {
|
|
338
|
+
const block = await (0, rpc_utils_1.queryWithRetry)(() => l2Provider.getBlock(toBlock));
|
|
339
|
+
if (block) {
|
|
340
|
+
toBlockHash = block.hash;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
catch {
|
|
344
|
+
// Failed to get block hash - continue without it
|
|
345
|
+
logDiscovery("failed to fetch toBlock hash for reorg detection");
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
// Update hashes for all active keys with toBlock hash
|
|
349
|
+
const newHashes = { ...updatedHashes };
|
|
350
|
+
if (toBlockHash) {
|
|
351
|
+
for (const key of activeKeys) {
|
|
352
|
+
newHashes[key] = toBlockHash;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
219
355
|
// Create pending checkpoints for discovered items
|
|
220
356
|
await createPendingCheckpoints(allProposals, allTimelockOps, cache);
|
|
221
357
|
logDiscovery("complete: %d proposals, %d timelockOps", allProposals.length, allTimelockOps.length);
|
|
@@ -223,6 +359,7 @@ async function discoverAll(targets, toBlock, l2Provider, cache, fromWatermarks,
|
|
|
223
359
|
proposals: allProposals,
|
|
224
360
|
timelockOps: allTimelockOps,
|
|
225
361
|
watermarks: newWatermarks,
|
|
362
|
+
hashes: newHashes,
|
|
226
363
|
};
|
|
227
364
|
}
|
|
228
365
|
//# sourceMappingURL=discovery.js.map
|