@gzeoneth/gov-tracker 0.3.0 → 0.4.0-alpha.addr-feedback.36ae67e
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 +6 -11
- package/dist/calldata/decoder.d.ts.map +1 -1
- package/dist/calldata/decoder.js +35 -76
- package/dist/calldata/decoder.js.map +1 -1
- package/dist/calldata/parameter-decoder.d.ts +21 -1
- package/dist/calldata/parameter-decoder.d.ts.map +1 -1
- package/dist/calldata/parameter-decoder.js +30 -0
- package/dist/calldata/parameter-decoder.js.map +1 -1
- package/dist/calldata/retryable-ticket.d.ts +2 -2
- package/dist/calldata/retryable-ticket.d.ts.map +1 -1
- package/dist/calldata/retryable-ticket.js +17 -12
- package/dist/calldata/retryable-ticket.js.map +1 -1
- package/dist/calldata/signature-lookup.js +5 -4
- package/dist/calldata/signature-lookup.js.map +1 -1
- package/dist/cli/cli.js +39 -19
- package/dist/cli/cli.js.map +1 -1
- package/dist/cli/lib/cli.d.ts +4 -2
- package/dist/cli/lib/cli.d.ts.map +1 -1
- package/dist/cli/lib/cli.js +61 -58
- package/dist/cli/lib/cli.js.map +1 -1
- package/dist/cli/lib/json-state.js +1 -1
- package/dist/cli/lib/json-state.js.map +1 -1
- package/dist/cli/tui/components/StageProgress.js +1 -1
- package/dist/cli/tui/components/StageProgress.js.map +1 -1
- package/dist/cli/tui/components/StageRow.d.ts.map +1 -1
- package/dist/cli/tui/components/StageRow.js +15 -20
- package/dist/cli/tui/components/StageRow.js.map +1 -1
- package/dist/cli/tui/hooks/useCache.d.ts.map +1 -1
- package/dist/cli/tui/hooks/useCache.js +2 -1
- package/dist/cli/tui/hooks/useCache.js.map +1 -1
- package/dist/cli/tui/hooks/useElectionData.d.ts.map +1 -1
- package/dist/cli/tui/hooks/useElectionData.js +3 -2
- package/dist/cli/tui/hooks/useElectionData.js.map +1 -1
- package/dist/cli/tui/hooks/useProposals.d.ts.map +1 -1
- package/dist/cli/tui/hooks/useProposals.js +24 -34
- package/dist/cli/tui/hooks/useProposals.js.map +1 -1
- package/dist/cli/tui/hooks/useStageCalldata.d.ts.map +1 -1
- package/dist/cli/tui/hooks/useStageCalldata.js +2 -1
- package/dist/cli/tui/hooks/useStageCalldata.js.map +1 -1
- package/dist/cli/tui/utils/index.d.ts +6 -6
- package/dist/cli/tui/utils/index.d.ts.map +1 -1
- package/dist/cli/tui/utils/index.js +14 -14
- package/dist/cli/tui/utils/index.js.map +1 -1
- package/dist/cli/tui/utils/markdown-parser.d.ts +5 -0
- package/dist/cli/tui/utils/markdown-parser.d.ts.map +1 -1
- package/dist/cli/tui/utils/markdown-parser.js +16 -0
- package/dist/cli/tui/utils/markdown-parser.js.map +1 -1
- package/dist/cli/tui/utils/navigation.d.ts.map +1 -1
- package/dist/cli/tui/utils/navigation.js +5 -1
- package/dist/cli/tui/utils/navigation.js.map +1 -1
- package/dist/cli/tui/utils/proposal-detail-helpers.js +6 -6
- package/dist/cli/tui/utils/proposal-detail-helpers.js.map +1 -1
- package/dist/cli/tui/utils/time.d.ts +4 -4
- package/dist/cli/tui/utils/time.d.ts.map +1 -1
- package/dist/cli/tui/utils/time.js +13 -11
- package/dist/cli/tui/utils/time.js.map +1 -1
- package/dist/cli/tui/views/DescriptionView.d.ts.map +1 -1
- package/dist/cli/tui/views/DescriptionView.js +4 -2
- package/dist/cli/tui/views/DescriptionView.js.map +1 -1
- package/dist/cli/tui/views/ElectionView.d.ts.map +1 -1
- package/dist/cli/tui/views/ElectionView.js +3 -3
- package/dist/cli/tui/views/ElectionView.js.map +1 -1
- package/dist/cli/tui/views/StageView.d.ts.map +1 -1
- package/dist/cli/tui/views/StageView.js +1 -1
- package/dist/cli/tui/views/StageView.js.map +1 -1
- package/dist/constants.d.ts +11 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +16 -4
- package/dist/constants.js.map +1 -1
- package/dist/data/bundled-cache.json +21513 -22619
- package/dist/deduplication.d.ts.map +1 -1
- package/dist/deduplication.js +36 -33
- package/dist/deduplication.js.map +1 -1
- package/dist/discovery/governor-discovery.d.ts.map +1 -1
- package/dist/discovery/governor-discovery.js +44 -49
- package/dist/discovery/governor-discovery.js.map +1 -1
- package/dist/discovery/security-council.d.ts +15 -0
- package/dist/discovery/security-council.d.ts.map +1 -1
- package/dist/discovery/security-council.js +42 -19
- package/dist/discovery/security-council.js.map +1 -1
- package/dist/discovery/timelock-discovery.d.ts.map +1 -1
- package/dist/discovery/timelock-discovery.js +62 -84
- package/dist/discovery/timelock-discovery.js.map +1 -1
- package/dist/election/contracts.d.ts.map +1 -1
- package/dist/election/contracts.js +4 -1
- package/dist/election/contracts.js.map +1 -1
- package/dist/election/details.d.ts.map +1 -1
- package/dist/election/details.js +35 -33
- package/dist/election/details.js.map +1 -1
- package/dist/election/index.d.ts +3 -6
- package/dist/election/index.d.ts.map +1 -1
- package/dist/election/index.js +7 -14
- package/dist/election/index.js.map +1 -1
- package/dist/election/params.d.ts +8 -1
- package/dist/election/params.d.ts.map +1 -1
- package/dist/election/params.js +48 -13
- package/dist/election/params.js.map +1 -1
- package/dist/election/participants.d.ts.map +1 -1
- package/dist/election/participants.js +19 -27
- package/dist/election/participants.js.map +1 -1
- package/dist/election/proposal-ids.d.ts +10 -0
- package/dist/election/proposal-ids.d.ts.map +1 -1
- package/dist/election/proposal-ids.js +42 -5
- package/dist/election/proposal-ids.js.map +1 -1
- package/dist/election/status.d.ts.map +1 -1
- package/dist/election/status.js +6 -0
- package/dist/election/status.js.map +1 -1
- package/dist/index.d.ts +24 -14
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +40 -16
- package/dist/index.js.map +1 -1
- package/dist/simulation/simulation-data.d.ts +2 -2
- package/dist/simulation/simulation-data.d.ts.map +1 -1
- package/dist/simulation/simulation-data.js +36 -26
- package/dist/simulation/simulation-data.js.map +1 -1
- package/dist/stages/builder.js +1 -1
- package/dist/stages/builder.js.map +1 -1
- package/dist/stages/l2-to-l1-message.d.ts.map +1 -1
- package/dist/stages/l2-to-l1-message.js +5 -11
- package/dist/stages/l2-to-l1-message.js.map +1 -1
- package/dist/stages/proposal-queued.d.ts.map +1 -1
- package/dist/stages/proposal-queued.js +4 -1
- package/dist/stages/proposal-queued.js.map +1 -1
- package/dist/stages/retryables.d.ts +4 -3
- package/dist/stages/retryables.d.ts.map +1 -1
- package/dist/stages/retryables.js +35 -57
- package/dist/stages/retryables.js.map +1 -1
- package/dist/stages/timelock.d.ts +4 -1
- package/dist/stages/timelock.d.ts.map +1 -1
- package/dist/stages/timelock.js +59 -67
- package/dist/stages/timelock.js.map +1 -1
- package/dist/stages/utils.d.ts +69 -5
- package/dist/stages/utils.d.ts.map +1 -1
- package/dist/stages/utils.js +152 -42
- package/dist/stages/utils.js.map +1 -1
- package/dist/tracker/bundled-cache.d.ts +127 -0
- package/dist/tracker/bundled-cache.d.ts.map +1 -0
- package/dist/tracker/bundled-cache.js +198 -0
- package/dist/tracker/bundled-cache.js.map +1 -0
- package/dist/tracker/checkpoint-helpers.d.ts +20 -1
- package/dist/tracker/checkpoint-helpers.d.ts.map +1 -1
- package/dist/tracker/checkpoint-helpers.js +41 -7
- package/dist/tracker/checkpoint-helpers.js.map +1 -1
- package/dist/tracker/discovery.d.ts.map +1 -1
- package/dist/tracker/discovery.js +60 -43
- package/dist/tracker/discovery.js.map +1 -1
- package/dist/tracker/pipeline.d.ts +25 -6
- package/dist/tracker/pipeline.d.ts.map +1 -1
- package/dist/tracker/pipeline.js +428 -211
- package/dist/tracker/pipeline.js.map +1 -1
- package/dist/tracker/query.d.ts +21 -0
- package/dist/tracker/query.d.ts.map +1 -1
- package/dist/tracker/query.js +86 -9
- package/dist/tracker/query.js.map +1 -1
- package/dist/tracker/stage-runner.d.ts +62 -0
- package/dist/tracker/stage-runner.d.ts.map +1 -0
- package/dist/tracker/stage-runner.js +80 -0
- package/dist/tracker/stage-runner.js.map +1 -0
- package/dist/tracker/state.d.ts +65 -0
- package/dist/tracker/state.d.ts.map +1 -1
- package/dist/tracker/state.js +194 -14
- package/dist/tracker/state.js.map +1 -1
- package/dist/tracker.d.ts +36 -8
- package/dist/tracker.d.ts.map +1 -1
- package/dist/tracker.js +264 -201
- package/dist/tracker.js.map +1 -1
- package/dist/types/config.d.ts +39 -3
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/core.d.ts +3 -2
- package/dist/types/core.d.ts.map +1 -1
- package/dist/types/core.js +3 -2
- package/dist/types/core.js.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/types/simulation.d.ts +2 -2
- package/dist/types/simulation.d.ts.map +1 -1
- package/dist/types/tracking.d.ts +11 -0
- package/dist/types/tracking.d.ts.map +1 -1
- package/dist/utils/log-filters.d.ts.map +1 -1
- package/dist/utils/log-filters.js +5 -9
- package/dist/utils/log-filters.js.map +1 -1
- package/dist/utils/multicall.d.ts +0 -1
- package/dist/utils/multicall.d.ts.map +1 -1
- package/dist/utils/rpc-utils.d.ts +11 -0
- package/dist/utils/rpc-utils.d.ts.map +1 -1
- package/dist/utils/rpc-utils.js +18 -1
- package/dist/utils/rpc-utils.js.map +1 -1
- package/dist/utils/stage-metadata.d.ts +19 -0
- package/dist/utils/stage-metadata.d.ts.map +1 -1
- package/dist/utils/stage-metadata.js +44 -0
- package/dist/utils/stage-metadata.js.map +1 -1
- package/dist/utils/timing.d.ts +11 -4
- package/dist/utils/timing.d.ts.map +1 -1
- package/dist/utils/timing.js +45 -15
- package/dist/utils/timing.js.map +1 -1
- package/package.json +7 -6
- package/dist/cli/tui/utils/calldata-formatter.d.ts +0 -7
- package/dist/cli/tui/utils/calldata-formatter.d.ts.map +0 -1
- package/dist/cli/tui/utils/calldata-formatter.js +0 -14
- package/dist/cli/tui/utils/calldata-formatter.js.map +0 -1
- package/dist/cli/tui/utils/stage-formatter.d.ts +0 -7
- package/dist/cli/tui/utils/stage-formatter.d.ts.map +0 -1
- package/dist/cli/tui/utils/stage-formatter.js +0 -14
- package/dist/cli/tui/utils/stage-formatter.js.map +0 -1
- package/dist/cli/tui/utils/text.d.ts +0 -7
- package/dist/cli/tui/utils/text.d.ts.map +0 -1
- package/dist/cli/tui/utils/text.js +0 -12
- package/dist/cli/tui/utils/text.js.map +0 -1
- package/dist/election/prepare.d.ts +0 -10
- package/dist/election/prepare.d.ts.map +0 -1
- package/dist/election/prepare.js +0 -52
- package/dist/election/prepare.js.map +0 -1
- package/dist/election/tracking.d.ts +0 -28
- package/dist/election/tracking.d.ts.map +0 -1
- package/dist/election/tracking.js +0 -412
- package/dist/election/tracking.js.map +0 -1
package/dist/tracker.js
CHANGED
|
@@ -27,74 +27,101 @@ const governor_discovery_1 = require("./discovery/governor-discovery");
|
|
|
27
27
|
const timelock_discovery_1 = require("./discovery/timelock-discovery");
|
|
28
28
|
const utils_1 = require("./stages/utils");
|
|
29
29
|
const { tracker: logTracker, discovery: logDiscovery } = logger_1.loggers;
|
|
30
|
-
/**
|
|
31
|
-
* Build a TrackingContext with current block numbers and timestamp.
|
|
32
|
-
* Called once at the start of a tracking session for consistent state.
|
|
33
|
-
*/
|
|
34
|
-
async function buildTrackingContext(options) {
|
|
35
|
-
const { l2Provider, l1Provider, novaProvider, chunkSize, skipCache } = options;
|
|
36
|
-
const l2BlockInfo = await (0, timing_1.getCurrentBlockInfo)(l2Provider);
|
|
37
|
-
const context = {
|
|
38
|
-
l2BlockNumber: l2BlockInfo.blockNumber,
|
|
39
|
-
timestamp: l2BlockInfo.timestamp,
|
|
40
|
-
chunkSize,
|
|
41
|
-
skipCache,
|
|
42
|
-
};
|
|
43
|
-
logTracker("buildTrackingContext: l2Block=%d timestamp=%d", context.l2BlockNumber, context.timestamp);
|
|
44
|
-
if (l1Provider) {
|
|
45
|
-
try {
|
|
46
|
-
const l1Block = await (0, timing_1.getL1BlockNumberFromL2)(l2Provider);
|
|
47
|
-
context.l1BlockNumber = l1Block.toNumber();
|
|
48
|
-
logTracker("buildTrackingContext: l1Block=%d", context.l1BlockNumber);
|
|
49
|
-
}
|
|
50
|
-
catch (err) {
|
|
51
|
-
logTracker("buildTrackingContext: failed to get L1 block: %s", err.message);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
if (novaProvider) {
|
|
55
|
-
try {
|
|
56
|
-
const novaBlockInfo = await (0, timing_1.getCurrentBlockInfo)(novaProvider);
|
|
57
|
-
context.novaBlockNumber = novaBlockInfo.blockNumber;
|
|
58
|
-
logTracker("buildTrackingContext: novaBlock=%d", context.novaBlockNumber);
|
|
59
|
-
}
|
|
60
|
-
catch (err) {
|
|
61
|
-
logTracker("buildTrackingContext: failed to get Nova block: %s", err.message);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
return context;
|
|
65
|
-
}
|
|
66
30
|
// Import context and pipeline from tracker modules
|
|
67
31
|
const state_1 = require("./tracker/state");
|
|
68
32
|
const pipeline_1 = require("./tracker/pipeline");
|
|
33
|
+
const status_1 = require("./election/status");
|
|
34
|
+
const constants_2 = require("./constants");
|
|
69
35
|
// Import from focused modules
|
|
70
36
|
const cache_1 = require("./tracker/cache");
|
|
71
37
|
const discovery_1 = require("./tracker/discovery");
|
|
72
38
|
const discovery_2 = require("./tracker/discovery");
|
|
73
39
|
const query_1 = require("./tracker/query");
|
|
74
40
|
const execute_1 = require("./tracker/execute");
|
|
41
|
+
/**
|
|
42
|
+
* Build ElectionProposalStatus from TrackingState.
|
|
43
|
+
* This bridges the unified pipeline approach with the existing election API.
|
|
44
|
+
*/
|
|
45
|
+
function buildElectionStatusFromState(state) {
|
|
46
|
+
// Extract basic state with defaults
|
|
47
|
+
const electionIndex = (0, state_1.getElectionIndex)(state) ?? 0;
|
|
48
|
+
const nomineeProposalId = (0, state_1.getNomineeProposalId)(state) ?? null;
|
|
49
|
+
const memberProposalId = (0, state_1.getMemberProposalId)(state) ?? null;
|
|
50
|
+
const cohort = (0, state_1.getElectionCohort)(state) ?? 0;
|
|
51
|
+
const compliantNomineeCount = (0, state_1.getCompliantNomineeCount)(state) ?? 0;
|
|
52
|
+
const targetNomineeCount = (0, state_1.getTargetNomineeCount)(state) ?? constants_2.TIMING.SECURITY_COUNCIL_TARGET_NOMINEES;
|
|
53
|
+
const vettingDeadline = (0, state_1.getVettingDeadline)(state) ?? null;
|
|
54
|
+
// Stage lookups (typed for data access)
|
|
55
|
+
const createStage = (0, utils_1.findStage)(state.stages, "CREATE_ELECTION");
|
|
56
|
+
const nomineeStage = (0, utils_1.findStage)(state.stages, "NOMINEE_ELECTION");
|
|
57
|
+
const vettingStage = (0, utils_1.findStage)(state.stages, "NOMINEE_VETTING");
|
|
58
|
+
const memberStage = (0, utils_1.findStage)(state.stages, "MEMBER_ELECTION");
|
|
59
|
+
// Extract proposal states from typed stages
|
|
60
|
+
const nomineeProposalState = nomineeStage?.data
|
|
61
|
+
?.proposalState ?? null;
|
|
62
|
+
const memberProposalState = memberStage?.data
|
|
63
|
+
?.proposalState ?? null;
|
|
64
|
+
const isInVettingPeriod = vettingStage?.status === "PENDING";
|
|
65
|
+
// Determine failure from any failed stage using Map for O(1) lookup
|
|
66
|
+
const stageFailureReasons = new Map([
|
|
67
|
+
[nomineeStage, "Nominee election failed"],
|
|
68
|
+
[vettingStage, "Not enough compliant nominees"],
|
|
69
|
+
[memberStage, "Member election failed"],
|
|
70
|
+
]);
|
|
71
|
+
const failedStage = [nomineeStage, vettingStage, memberStage].find((s) => s?.status === "FAILED");
|
|
72
|
+
const failureReason = failedStage ? stageFailureReasons.get(failedStage) : undefined;
|
|
73
|
+
return {
|
|
74
|
+
electionIndex,
|
|
75
|
+
phase: (0, status_1.determineElectionPhase)(nomineeProposalState, memberProposalId, memberProposalState, isInVettingPeriod),
|
|
76
|
+
cohort,
|
|
77
|
+
nomineeProposalId,
|
|
78
|
+
memberProposalId,
|
|
79
|
+
nomineeProposalState,
|
|
80
|
+
memberProposalState,
|
|
81
|
+
compliantNomineeCount,
|
|
82
|
+
targetNomineeCount,
|
|
83
|
+
vettingDeadline,
|
|
84
|
+
isInVettingPeriod,
|
|
85
|
+
canProceedToMemberPhase: vettingStage?.status === "READY",
|
|
86
|
+
canExecuteMember: memberStage?.status === "READY",
|
|
87
|
+
stages: state.stages,
|
|
88
|
+
isFailed: failedStage ? true : undefined,
|
|
89
|
+
failureReason,
|
|
90
|
+
timelockOperationId: (0, state_1.getElectionTimelockOperationId)(state),
|
|
91
|
+
creationTxHash: createStage?.transactions?.[0]?.hash,
|
|
92
|
+
nomineeExecuteTxHash: vettingStage?.transactions?.[0]?.hash,
|
|
93
|
+
memberExecuteTxHash: memberStage?.transactions?.find((t) => t.description === "executed")?.hash,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
75
96
|
/**
|
|
76
97
|
* Extract TimelockLink from stages if PROPOSAL_QUEUED is completed
|
|
77
98
|
*/
|
|
78
99
|
function extractTimelockLink(stages) {
|
|
79
100
|
const queuedStage = (0, utils_1.findStage)(stages, "PROPOSAL_QUEUED");
|
|
80
|
-
if (
|
|
81
|
-
queuedStage.type !== "PROPOSAL_QUEUED" ||
|
|
82
|
-
queuedStage.status !== "COMPLETED") {
|
|
101
|
+
if (queuedStage?.status !== "COMPLETED" || queuedStage.type !== "PROPOSAL_QUEUED") {
|
|
83
102
|
return undefined;
|
|
84
103
|
}
|
|
85
|
-
const
|
|
86
|
-
const operationId = queuedStage.data
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
104
|
+
const tx = queuedStage.transactions[0];
|
|
105
|
+
const { operationId, timelockAddress } = queuedStage.data;
|
|
106
|
+
return tx?.hash && operationId && timelockAddress && tx.blockNumber
|
|
107
|
+
? { txHash: tx.hash, operationId, timelockAddress, queueBlockNumber: tx.blockNumber }
|
|
108
|
+
: undefined;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Resolve a provider option that can be either a Provider instance or an RPC URL string.
|
|
112
|
+
* If undefined and a default URL is provided, creates a provider from the default.
|
|
113
|
+
*/
|
|
114
|
+
function resolveProvider(providerOrUrl, defaultUrl) {
|
|
115
|
+
if (!providerOrUrl) {
|
|
116
|
+
if (!defaultUrl) {
|
|
117
|
+
throw new Error("Provider or RPC URL is required");
|
|
118
|
+
}
|
|
119
|
+
return new ethers_1.ethers.providers.StaticJsonRpcProvider(defaultUrl);
|
|
91
120
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
queueBlockNumber,
|
|
97
|
-
};
|
|
121
|
+
if (typeof providerOrUrl === "string") {
|
|
122
|
+
return new ethers_1.ethers.providers.StaticJsonRpcProvider(providerOrUrl);
|
|
123
|
+
}
|
|
124
|
+
return providerOrUrl;
|
|
98
125
|
}
|
|
99
126
|
/**
|
|
100
127
|
* Main proposal stage tracker class
|
|
@@ -124,15 +151,9 @@ function extractTimelockLink(stages) {
|
|
|
124
151
|
*/
|
|
125
152
|
class ProposalStageTracker {
|
|
126
153
|
constructor(options) {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
this.l1Provider = options.l1Provider;
|
|
131
|
-
// Use StaticJsonRpcProvider for defaults to avoid automatic chainId detection
|
|
132
|
-
this.l2Provider =
|
|
133
|
-
options.l2Provider ?? new ethers_1.ethers.providers.StaticJsonRpcProvider(constants_1.DEFAULT_RPC_URLS.ARB_ONE);
|
|
134
|
-
this.novaProvider =
|
|
135
|
-
options.novaProvider ?? new ethers_1.ethers.providers.StaticJsonRpcProvider(constants_1.DEFAULT_RPC_URLS.NOVA);
|
|
154
|
+
this.l1Provider = resolveProvider(options.l1Provider);
|
|
155
|
+
this.l2Provider = resolveProvider(options.l2Provider, constants_1.DEFAULT_RPC_URLS.ARB_ONE);
|
|
156
|
+
this.novaProvider = resolveProvider(options.novaProvider, constants_1.DEFAULT_RPC_URLS.NOVA);
|
|
136
157
|
this.onProgress = options.onProgress;
|
|
137
158
|
this.chunkingConfig = options.chunkingConfig ?? constants_1.DEFAULT_CHUNKING_CONFIG;
|
|
138
159
|
// Initialize cache: prefer direct cache adapter, fallback to cachePath
|
|
@@ -182,16 +203,15 @@ class ProposalStageTracker {
|
|
|
182
203
|
logTracker("cleared cache entry: %s", baseCacheKey);
|
|
183
204
|
cleared++;
|
|
184
205
|
}
|
|
185
|
-
// Clear all operation-specific keys for this tx
|
|
206
|
+
// Clear all operation-specific keys for this tx in parallel
|
|
186
207
|
const allKeys = await this.cache.keys(prefix);
|
|
187
208
|
const keys = Array.isArray(allKeys) ? allKeys : Array.from(allKeys);
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
}
|
|
209
|
+
const keysToDelete = keys.filter((key) => key.startsWith(prefix));
|
|
210
|
+
await Promise.all(keysToDelete.map(async (key) => {
|
|
211
|
+
await this.cache.delete(key);
|
|
212
|
+
logTracker("cleared cache entry: %s", key);
|
|
213
|
+
}));
|
|
214
|
+
cleared += keysToDelete.length;
|
|
195
215
|
return cleared;
|
|
196
216
|
}
|
|
197
217
|
// Watermark Management
|
|
@@ -221,7 +241,7 @@ class ProposalStageTracker {
|
|
|
221
241
|
* For COMPLETED elections, automatically fetches and caches nominee/member
|
|
222
242
|
* election details to enable zero-RPC reads for historical elections.
|
|
223
243
|
*
|
|
224
|
-
* @param electionStatus - Election status from
|
|
244
|
+
* @param electionStatus - Election status from trackElection()
|
|
225
245
|
* @param options.nomineeDetails - Pre-fetched nominee details (skips RPC fetch)
|
|
226
246
|
* @param options.memberDetails - Pre-fetched member details (skips RPC fetch)
|
|
227
247
|
*/
|
|
@@ -369,6 +389,17 @@ class ProposalStageTracker {
|
|
|
369
389
|
async getStats(maxErrorCount = 5) {
|
|
370
390
|
return (0, query_1.getStats)(this.cache, maxErrorCount);
|
|
371
391
|
}
|
|
392
|
+
/**
|
|
393
|
+
* Get the highest Security Council nonce from incomplete checkpoints.
|
|
394
|
+
*
|
|
395
|
+
* Used to determine if lower-nonce SC operations should be skipped
|
|
396
|
+
* (superseded by higher nonce operations).
|
|
397
|
+
*
|
|
398
|
+
* @returns The highest SC nonce found, or null if no SC operations exist
|
|
399
|
+
*/
|
|
400
|
+
async getHighestScNonce() {
|
|
401
|
+
return (0, query_1.getHighestScNonceFromCheckpoints)(this.cache);
|
|
402
|
+
}
|
|
372
403
|
// Main Tracking Entry Points
|
|
373
404
|
/**
|
|
374
405
|
* Track from transaction hash (primary tracking entry point)
|
|
@@ -412,7 +443,7 @@ class ProposalStageTracker {
|
|
|
412
443
|
logTracker("loaded checkpoint from cache: %s", opCacheKey);
|
|
413
444
|
}
|
|
414
445
|
}
|
|
415
|
-
// Fall back to base cache key (
|
|
446
|
+
// Fall back to base cache key (governor proposals or pre-modular cache entries)
|
|
416
447
|
if (!checkpoint) {
|
|
417
448
|
checkpoint = (await this.cache.get(baseCacheKey)) ?? undefined;
|
|
418
449
|
if (checkpoint) {
|
|
@@ -516,31 +547,85 @@ class ProposalStageTracker {
|
|
|
516
547
|
logTracker("no proposal or timelock operations found in tx");
|
|
517
548
|
return [];
|
|
518
549
|
}
|
|
550
|
+
// ============================================================================
|
|
551
|
+
// Unified Pipeline Tracking
|
|
552
|
+
// ============================================================================
|
|
519
553
|
/**
|
|
520
|
-
*
|
|
554
|
+
* Unified pipeline tracking method.
|
|
555
|
+
* Handles all common tracking patterns: state creation, pipeline execution,
|
|
556
|
+
* checkpoint management, and timelockOpKey derivation.
|
|
521
557
|
*/
|
|
522
|
-
async
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
558
|
+
async runTrackingPipeline(config) {
|
|
559
|
+
// Load linked timelock checkpoint if configured and available
|
|
560
|
+
let linkedTimelockCheckpoint;
|
|
561
|
+
if (config.loadLinkedTimelock && this.cache && config.checkpoint?.metadata?.timelockOpKey) {
|
|
562
|
+
linkedTimelockCheckpoint =
|
|
563
|
+
(await this.cache.get(config.checkpoint.metadata.timelockOpKey)) ??
|
|
564
|
+
undefined;
|
|
565
|
+
if (linkedTimelockCheckpoint) {
|
|
566
|
+
logTracker("loaded linked timelock checkpoint: %s", config.checkpoint.metadata.timelockOpKey);
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
// Create tracking state
|
|
530
570
|
const initialState = (0, state_1.createTrackingState)({
|
|
531
571
|
providers: {
|
|
532
572
|
l2: this.l2Provider,
|
|
533
573
|
l1: this.l1Provider,
|
|
534
574
|
nova: this.novaProvider,
|
|
535
575
|
},
|
|
536
|
-
input,
|
|
576
|
+
input: config.input,
|
|
537
577
|
onProgress: this.onProgress,
|
|
538
578
|
chunkingConfig: this.chunkingConfig,
|
|
579
|
+
checkpoint: config.checkpoint,
|
|
580
|
+
linkedTimelockCheckpoint,
|
|
581
|
+
cacheKey: config.cacheKey,
|
|
582
|
+
callScheduledData: config.callScheduledData,
|
|
583
|
+
});
|
|
584
|
+
// Run the pipeline
|
|
585
|
+
let finalState = await config.pipeline(initialState);
|
|
586
|
+
// Derive and set timelockOpKey if configured
|
|
587
|
+
if (config.timelockKeySource && !finalState.timelockOpKey) {
|
|
588
|
+
const { stageType, txDescription } = config.timelockKeySource;
|
|
589
|
+
const operationId = stageType === "MEMBER_ELECTION"
|
|
590
|
+
? (0, state_1.getElectionTimelockOperationId)(finalState)
|
|
591
|
+
: (0, state_1.getOperationId)(finalState);
|
|
592
|
+
const stage = finalState.stages.find((s) => s.type === stageType);
|
|
593
|
+
const txHash = stage?.transactions?.find((t) => t.description === txDescription)?.hash;
|
|
594
|
+
if (operationId && txHash) {
|
|
595
|
+
const timelockOpKey = (0, checkpoint_helpers_1.timelockOpCacheKey)(txHash, operationId);
|
|
596
|
+
finalState = (0, state_1.setTimelockOpKey)(finalState, timelockOpKey);
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
// Save checkpoints (unless caller handles caching)
|
|
600
|
+
if (!config.skipCaching && this.cache && config.cacheKey) {
|
|
601
|
+
if (config.modularCaching) {
|
|
602
|
+
await this.saveModularCheckpoints(finalState, config.cacheKey);
|
|
603
|
+
}
|
|
604
|
+
else {
|
|
605
|
+
const checkpoint = (0, state_1.createCheckpoint)(finalState);
|
|
606
|
+
checkpoint.metadata = { errorCount: 0, lastTrackedAt: Date.now() };
|
|
607
|
+
await this.cache.set(config.cacheKey, checkpoint);
|
|
608
|
+
logTracker("saved checkpoint to cache: %s", config.cacheKey);
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
return finalState;
|
|
612
|
+
}
|
|
613
|
+
/**
|
|
614
|
+
* Track governor proposal using TrackingState (stateful tracking)
|
|
615
|
+
* Uses modular caching: parent stages saved separately from timelock stages.
|
|
616
|
+
*/
|
|
617
|
+
async trackGovernorWithPipeline(governorAddress, proposalId, creationTxHash, checkpoint, cacheKey) {
|
|
618
|
+
// Run unified pipeline (with skipCaching - we handle election case specially)
|
|
619
|
+
const finalState = await this.runTrackingPipeline({
|
|
620
|
+
input: { type: "governor", governorAddress, proposalId, creationTxHash },
|
|
539
621
|
checkpoint,
|
|
540
622
|
cacheKey,
|
|
623
|
+
pipeline: pipeline_1.trackGovernorPipeline,
|
|
624
|
+
loadLinkedTimelock: true,
|
|
625
|
+
modularCaching: true,
|
|
626
|
+
skipCaching: true,
|
|
627
|
+
timelockKeySource: { stageType: "PROPOSAL_QUEUED", txDescription: "queued" },
|
|
541
628
|
});
|
|
542
|
-
// Run the governor pipeline (stages 1-7)
|
|
543
|
-
const finalState = await (0, pipeline_1.trackGovernorPipeline)(initialState);
|
|
544
629
|
// Build result from state
|
|
545
630
|
const result = this.buildResultFromState(finalState);
|
|
546
631
|
// Track election status if this is an election governor proposal
|
|
@@ -556,14 +641,11 @@ class ProposalStageTracker {
|
|
|
556
641
|
}
|
|
557
642
|
return result;
|
|
558
643
|
}
|
|
559
|
-
// If election tracking failed, fall through to save tx:* checkpoint for retry
|
|
560
644
|
logTracker("election tracking failed, saving tx:* checkpoint for retry");
|
|
561
645
|
}
|
|
562
|
-
// Save
|
|
646
|
+
// Save checkpoints using modular caching
|
|
563
647
|
if (this.cache && cacheKey) {
|
|
564
|
-
|
|
565
|
-
await this.cache.set(cacheKey, result.checkpoint);
|
|
566
|
-
logTracker("saved checkpoint to cache: %s", cacheKey);
|
|
648
|
+
await this.saveModularCheckpoints(finalState, cacheKey);
|
|
567
649
|
}
|
|
568
650
|
return result;
|
|
569
651
|
}
|
|
@@ -571,37 +653,55 @@ class ProposalStageTracker {
|
|
|
571
653
|
* Track timelock operation using TrackingState (stateful tracking)
|
|
572
654
|
*/
|
|
573
655
|
async trackTimelockWithPipeline(timelockAddress, operationId, scheduledTxHash, checkpoint, cacheKey, callScheduledEvent) {
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
timelockAddress,
|
|
577
|
-
operationId,
|
|
578
|
-
scheduledTxHash,
|
|
579
|
-
};
|
|
580
|
-
// Create tracking context with bootstrap data
|
|
581
|
-
const initialState = (0, state_1.createTrackingState)({
|
|
582
|
-
providers: {
|
|
583
|
-
l2: this.l2Provider,
|
|
584
|
-
l1: this.l1Provider,
|
|
585
|
-
nova: this.novaProvider,
|
|
586
|
-
},
|
|
587
|
-
input,
|
|
588
|
-
onProgress: this.onProgress,
|
|
589
|
-
chunkingConfig: this.chunkingConfig,
|
|
656
|
+
// Run unified pipeline
|
|
657
|
+
const finalState = await this.runTrackingPipeline({
|
|
658
|
+
input: { type: "timelock", timelockAddress, operationId, scheduledTxHash },
|
|
590
659
|
checkpoint,
|
|
591
660
|
cacheKey,
|
|
661
|
+
pipeline: pipeline_1.trackTimelockPipeline,
|
|
662
|
+
loadLinkedTimelock: false,
|
|
663
|
+
modularCaching: false,
|
|
592
664
|
callScheduledData: callScheduledEvent ? [callScheduledEvent] : undefined,
|
|
593
665
|
});
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
666
|
+
return this.buildResultFromState(finalState);
|
|
667
|
+
}
|
|
668
|
+
/**
|
|
669
|
+
* Track election using TrackingState (stateful tracking)
|
|
670
|
+
*
|
|
671
|
+
* This is the unified pipeline version that tracks elections through the
|
|
672
|
+
* same stage-based approach as proposals and timelock operations.
|
|
673
|
+
* Uses modular caching: election stages saved separately from timelock stages.
|
|
674
|
+
*/
|
|
675
|
+
async trackElectionWithPipeline(electionIndex, checkpoint, cacheKey) {
|
|
676
|
+
// Run unified pipeline (caller handles caching)
|
|
677
|
+
const finalState = await this.runTrackingPipeline({
|
|
678
|
+
input: { type: "election", electionIndex },
|
|
679
|
+
checkpoint,
|
|
680
|
+
cacheKey,
|
|
681
|
+
pipeline: pipeline_1.trackElectionPipeline,
|
|
682
|
+
loadLinkedTimelock: true,
|
|
683
|
+
modularCaching: true,
|
|
684
|
+
skipCaching: true,
|
|
685
|
+
timelockKeySource: { stageType: "MEMBER_ELECTION", txDescription: "executed" },
|
|
686
|
+
});
|
|
687
|
+
return { status: buildElectionStatusFromState(finalState), finalState };
|
|
688
|
+
}
|
|
689
|
+
/**
|
|
690
|
+
* Save checkpoints using modular caching.
|
|
691
|
+
* Saves parent stages and timelock stages in separate checkpoints.
|
|
692
|
+
*/
|
|
693
|
+
async saveModularCheckpoints(state, parentCacheKey) {
|
|
694
|
+
if (!this.cache)
|
|
695
|
+
return;
|
|
696
|
+
const { parentCheckpoint, timelockCheckpoint, timelockOpKey } = (0, state_1.createModularCheckpoints)(state, parentCacheKey);
|
|
697
|
+
// Save parent checkpoint
|
|
698
|
+
await this.cache.set(parentCacheKey, parentCheckpoint);
|
|
699
|
+
logTracker("saved parent checkpoint: %s", parentCacheKey);
|
|
700
|
+
// Save timelock checkpoint if we have one
|
|
701
|
+
if (timelockCheckpoint && timelockOpKey) {
|
|
702
|
+
await this.cache.set(timelockOpKey, timelockCheckpoint);
|
|
703
|
+
logTracker("saved linked timelock checkpoint: %s", timelockOpKey);
|
|
603
704
|
}
|
|
604
|
-
return result;
|
|
605
705
|
}
|
|
606
706
|
/**
|
|
607
707
|
* Build TrackingResult from TrackingState
|
|
@@ -639,38 +739,29 @@ class ProposalStageTracker {
|
|
|
639
739
|
* ```
|
|
640
740
|
*/
|
|
641
741
|
async trackFromCheckpoint(checkpoint) {
|
|
642
|
-
const input = checkpoint
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
throw new Error("Governor checkpoint missing creationTxHash");
|
|
646
|
-
}
|
|
647
|
-
const results = await this.trackByTxHash(input.creationTxHash);
|
|
742
|
+
const { input } = checkpoint;
|
|
743
|
+
const trackAndWarn = async (txHash, entityType) => {
|
|
744
|
+
const results = await this.trackByTxHash(txHash);
|
|
648
745
|
if (results.length === 0) {
|
|
649
|
-
throw new Error(`No
|
|
746
|
+
throw new Error(`No ${entityType} found in tx ${txHash}`);
|
|
650
747
|
}
|
|
651
748
|
if (results.length > 1) {
|
|
652
749
|
logTracker("WARNING: trackFromCheckpoint found %d results in tx %s, returning first only. " +
|
|
653
|
-
"Use trackByTxHash() to get all results.", results.length,
|
|
750
|
+
"Use trackByTxHash() to get all results.", results.length, txHash);
|
|
654
751
|
}
|
|
655
752
|
return results[0];
|
|
753
|
+
};
|
|
754
|
+
if (input.type === "governor") {
|
|
755
|
+
if (!input.creationTxHash)
|
|
756
|
+
throw new Error("Governor checkpoint missing creationTxHash");
|
|
757
|
+
return trackAndWarn(input.creationTxHash, "proposal");
|
|
656
758
|
}
|
|
657
|
-
|
|
658
|
-
if (!input.scheduledTxHash)
|
|
759
|
+
if (input.type === "timelock") {
|
|
760
|
+
if (!input.scheduledTxHash)
|
|
659
761
|
throw new Error("Timelock checkpoint missing scheduledTxHash");
|
|
660
|
-
|
|
661
|
-
const results = await this.trackByTxHash(input.scheduledTxHash);
|
|
662
|
-
if (results.length === 0) {
|
|
663
|
-
throw new Error(`No timelock operation found in tx ${input.scheduledTxHash}`);
|
|
664
|
-
}
|
|
665
|
-
if (results.length > 1) {
|
|
666
|
-
logTracker("WARNING: trackFromCheckpoint found %d results in tx %s, returning first only. " +
|
|
667
|
-
"Use trackByTxHash() to get all results.", results.length, input.scheduledTxHash);
|
|
668
|
-
}
|
|
669
|
-
return results[0];
|
|
670
|
-
}
|
|
671
|
-
else {
|
|
672
|
-
throw new Error(`Unsupported checkpoint input type: ${input.type}`);
|
|
762
|
+
return trackAndWarn(input.scheduledTxHash, "timelock operation");
|
|
673
763
|
}
|
|
764
|
+
throw new Error(`Unsupported checkpoint input type: ${input.type}`);
|
|
674
765
|
}
|
|
675
766
|
// Transaction Preparation
|
|
676
767
|
/**
|
|
@@ -728,7 +819,7 @@ class ProposalStageTracker {
|
|
|
728
819
|
* Track election status for a given proposal ID.
|
|
729
820
|
*
|
|
730
821
|
* Searches through elections to find the one containing this proposal,
|
|
731
|
-
* then tracks the full election lifecycle.
|
|
822
|
+
* then tracks the full election lifecycle using the unified pipeline.
|
|
732
823
|
*/
|
|
733
824
|
async trackElectionStatus(proposalId) {
|
|
734
825
|
logTracker("trackElectionStatus for proposal %s", proposalId);
|
|
@@ -741,9 +832,8 @@ class ProposalStageTracker {
|
|
|
741
832
|
return null;
|
|
742
833
|
}
|
|
743
834
|
logTracker("found election index %d for proposal %s", electionIndex, proposalId);
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
});
|
|
835
|
+
// Use unified pipeline via trackElection
|
|
836
|
+
return this.trackElection(electionIndex);
|
|
747
837
|
}
|
|
748
838
|
catch (error) {
|
|
749
839
|
// Election tracking is non-critical - log and return null
|
|
@@ -763,35 +853,36 @@ class ProposalStageTracker {
|
|
|
763
853
|
* - Incomplete elections: Makes fresh RPC calls and updates cache
|
|
764
854
|
* - No cache: Always makes fresh RPC calls
|
|
765
855
|
*
|
|
856
|
+
* To force fresh tracking, clear the cache before calling this method.
|
|
857
|
+
*
|
|
766
858
|
* @param electionIndex - Election index (0-based)
|
|
767
|
-
* @param options.force - Force fresh tracking even for completed elections
|
|
768
859
|
* @returns Election status
|
|
769
860
|
*/
|
|
770
|
-
async trackElection(electionIndex
|
|
771
|
-
logTracker("trackElection for index %d
|
|
861
|
+
async trackElection(electionIndex) {
|
|
862
|
+
logTracker("trackElection for index %d", electionIndex);
|
|
863
|
+
const cacheKey = `election:${electionIndex}`;
|
|
772
864
|
// Check cache first for completed elections (skip RPC calls)
|
|
773
|
-
if (this.cache
|
|
865
|
+
if (this.cache) {
|
|
774
866
|
const cached = await this.getElectionCheckpoint(electionIndex);
|
|
775
867
|
if (cached && cached.status.phase === "COMPLETED") {
|
|
776
868
|
logTracker("returning cached COMPLETED election %d (0 RPC calls)", electionIndex);
|
|
777
869
|
return cached.status;
|
|
778
870
|
}
|
|
779
871
|
}
|
|
780
|
-
//
|
|
781
|
-
|
|
782
|
-
l2Provider: this.l2Provider,
|
|
783
|
-
l1Provider: this.l1Provider,
|
|
784
|
-
novaProvider: this.novaProvider,
|
|
785
|
-
skipCache: options.force,
|
|
786
|
-
});
|
|
787
|
-
// Track fresh for incomplete elections or cache miss
|
|
788
|
-
const status = await (0, election_1.trackElectionProposal)(electionIndex, this.l2Provider, this.l1Provider, {
|
|
789
|
-
novaProvider: this.novaProvider,
|
|
790
|
-
l2BlockNumber: context.l2BlockNumber,
|
|
791
|
-
timestamp: context.timestamp,
|
|
792
|
-
skipCache: context.skipCache,
|
|
793
|
-
});
|
|
872
|
+
// Load checkpoint from cache for resume
|
|
873
|
+
let checkpoint;
|
|
794
874
|
if (this.cache) {
|
|
875
|
+
checkpoint = (await this.cache.get(cacheKey)) ?? undefined;
|
|
876
|
+
if (checkpoint) {
|
|
877
|
+
logTracker("loaded election checkpoint from cache: %s", cacheKey);
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
// Track using the unified pipeline
|
|
881
|
+
const { status, finalState } = await this.trackElectionWithPipeline(electionIndex, checkpoint, cacheKey);
|
|
882
|
+
// Save checkpoints using modular caching
|
|
883
|
+
if (this.cache) {
|
|
884
|
+
await this.saveModularCheckpoints(finalState, cacheKey);
|
|
885
|
+
// Also save election-specific data
|
|
795
886
|
await this.saveElectionCheckpoint(status);
|
|
796
887
|
}
|
|
797
888
|
return status;
|
|
@@ -803,59 +894,31 @@ class ProposalStageTracker {
|
|
|
803
894
|
* - COMPLETED elections: Returns cached data immediately (0 RPC calls)
|
|
804
895
|
* - Incomplete elections: Makes fresh RPC calls and updates cache
|
|
805
896
|
*
|
|
897
|
+
* To force fresh tracking, clear the cache before calling this method.
|
|
898
|
+
*
|
|
806
899
|
* @param options.includeNext - Include the "next" election slot (default: true)
|
|
807
|
-
* @param options.force - Force fresh tracking for all elections
|
|
808
900
|
* @returns Array of election statuses
|
|
809
901
|
*/
|
|
810
902
|
async trackAllElections(options = {}) {
|
|
811
|
-
logTracker("trackAllElections (includeNext=%s
|
|
812
|
-
// Build context once at the start for consistent state across all elections
|
|
813
|
-
const context = await buildTrackingContext({
|
|
814
|
-
l2Provider: this.l2Provider,
|
|
815
|
-
l1Provider: this.l1Provider,
|
|
816
|
-
novaProvider: this.novaProvider,
|
|
817
|
-
skipCache: options.force,
|
|
818
|
-
});
|
|
903
|
+
logTracker("trackAllElections (includeNext=%s)", options.includeNext ?? true);
|
|
819
904
|
const status = await (0, election_1.checkElectionStatus)(this.l2Provider, this.l1Provider);
|
|
820
905
|
const electionCount = status.electionCount;
|
|
821
906
|
const results = [];
|
|
822
|
-
// Track existing elections (indices 0 to electionCount-1)
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
continue;
|
|
832
|
-
}
|
|
833
|
-
}
|
|
834
|
-
// Track with shared context
|
|
835
|
-
const electionStatus = await (0, election_1.trackElectionProposal)(i, this.l2Provider, this.l1Provider, {
|
|
836
|
-
novaProvider: this.novaProvider,
|
|
837
|
-
l2BlockNumber: context.l2BlockNumber,
|
|
838
|
-
timestamp: context.timestamp,
|
|
839
|
-
skipCache: context.skipCache,
|
|
840
|
-
});
|
|
841
|
-
results.push(electionStatus);
|
|
842
|
-
if (this.cache) {
|
|
843
|
-
await this.saveElectionCheckpoint(electionStatus);
|
|
844
|
-
}
|
|
845
|
-
}
|
|
846
|
-
catch (err) {
|
|
847
|
-
logTracker("Failed to track election %d: %s", i, err);
|
|
848
|
-
}
|
|
907
|
+
// Track existing elections in parallel (indices 0 to electionCount-1)
|
|
908
|
+
const electionPromises = Array.from({ length: electionCount }, (_, i) => this.trackElection(i).catch((err) => {
|
|
909
|
+
logTracker("Failed to track election %d: %s", i, (0, rpc_utils_1.getErrorMessage)(err));
|
|
910
|
+
return null;
|
|
911
|
+
}));
|
|
912
|
+
const electionResults = await Promise.all(electionPromises);
|
|
913
|
+
for (const result of electionResults) {
|
|
914
|
+
if (result)
|
|
915
|
+
results.push(result);
|
|
849
916
|
}
|
|
850
917
|
// Optionally track the next election (not yet created) for createElection preparation
|
|
851
918
|
if (options.includeNext ?? true) {
|
|
852
919
|
try {
|
|
853
|
-
// Next election
|
|
854
|
-
const nextElectionStatus = await
|
|
855
|
-
novaProvider: this.novaProvider,
|
|
856
|
-
l2BlockNumber: context.l2BlockNumber,
|
|
857
|
-
timestamp: context.timestamp,
|
|
858
|
-
});
|
|
920
|
+
// Next election won't have cache data since it doesn't exist yet
|
|
921
|
+
const nextElectionStatus = await this.trackElection(electionCount);
|
|
859
922
|
results.push({
|
|
860
923
|
...nextElectionStatus,
|
|
861
924
|
canCreateElection: status.canCreateElection,
|
|
@@ -865,7 +928,7 @@ class ProposalStageTracker {
|
|
|
865
928
|
// Don't cache the "next" election since it doesn't exist yet
|
|
866
929
|
}
|
|
867
930
|
catch (err) {
|
|
868
|
-
logTracker("Failed to track next election %d: %s", electionCount, err);
|
|
931
|
+
logTracker("Failed to track next election %d: %s", electionCount, (0, rpc_utils_1.getErrorMessage)(err));
|
|
869
932
|
}
|
|
870
933
|
}
|
|
871
934
|
logTracker("Tracked %d elections", results.length);
|