@tokamak-private-dapps/private-state-cli 0.1.3 → 0.1.4
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/CHANGELOG.md +5 -0
- package/package.json +1 -1
- package/private-state-bridge-cli.mjs +58 -13
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.4 - 2026-04-28
|
|
4
|
+
|
|
5
|
+
- Paced chunked log recovery queries at five requests per second to avoid RPC throughput bursts.
|
|
6
|
+
- Combined channel manager recovery log scans and filtered wallet note recovery scans to reduce RPC usage.
|
|
7
|
+
|
|
3
8
|
## 0.1.3 - 2026-04-28
|
|
4
9
|
|
|
5
10
|
- Installed the Groth16 runtime during `private-state-cli --install` and reported Groth16 readiness from `--doctor`.
|
package/package.json
CHANGED
|
@@ -152,6 +152,9 @@ const JUBJUB_D = jubjub.CURVE.d;
|
|
|
152
152
|
const BLS12_381_SCALAR_FIELD_MODULUS =
|
|
153
153
|
hexToBigInt(addHexPrefix("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001"));
|
|
154
154
|
const DEFAULT_LOG_CHUNK_SIZE = 2000;
|
|
155
|
+
const DEFAULT_LOG_REQUESTS_PER_SECOND = 5;
|
|
156
|
+
const LOG_REQUEST_INTERVAL_MS = Math.ceil(1000 / DEFAULT_LOG_REQUESTS_PER_SECOND);
|
|
157
|
+
let lastLogRequestStartedAtMs = 0;
|
|
155
158
|
|
|
156
159
|
async function prepareDeploymentArtifacts(chainId) {
|
|
157
160
|
const normalizedChainId = Number(chainId);
|
|
@@ -2030,6 +2033,7 @@ async function recoverDeliveredNotesFromEventLogs({
|
|
|
2030
2033
|
const nullifierUsedSlot = ethers.toBigInt(findStorageSlot(storageLayoutManifest, "PrivateStateController", "nullifierUsed"));
|
|
2031
2034
|
const observedLogs = await fetchLogsChunked(provider, {
|
|
2032
2035
|
address: context.workspace.channelManager,
|
|
2036
|
+
topics: [NOTE_VALUE_ENCRYPTED_TOPIC],
|
|
2033
2037
|
fromBlock: scanStartBlock,
|
|
2034
2038
|
toBlock: latestBlock,
|
|
2035
2039
|
});
|
|
@@ -3854,30 +3858,39 @@ async function reconstructChannelSnapshot({
|
|
|
3854
3858
|
provider,
|
|
3855
3859
|
);
|
|
3856
3860
|
const latestBlock = await provider.getBlockNumber();
|
|
3857
|
-
const
|
|
3858
|
-
|
|
3859
|
-
|
|
3861
|
+
const currentRootVectorObservedTopic =
|
|
3862
|
+
normalizeBytes32Hex(channelManager.interface.getEvent("CurrentRootVectorObserved").topicHash);
|
|
3863
|
+
const channelManagerLogs = await fetchLogsChunked(provider, {
|
|
3864
|
+
address: channelInfo.manager,
|
|
3865
|
+
topics: [[
|
|
3866
|
+
currentRootVectorObservedTopic,
|
|
3867
|
+
CONTROLLER_STORAGE_KEY_OBSERVED_TOPIC,
|
|
3868
|
+
VAULT_STORAGE_WRITE_OBSERVED_TOPIC,
|
|
3869
|
+
]],
|
|
3860
3870
|
fromBlock: genesisBlockNumber,
|
|
3861
3871
|
toBlock: latestBlock,
|
|
3862
3872
|
});
|
|
3873
|
+
const channelManagerEvents = channelManagerLogs.map((log) => {
|
|
3874
|
+
const topic0 = log.topics[0] ? normalizeBytes32Hex(log.topics[0]) : null;
|
|
3875
|
+
if (topic0 !== null && ethers.toBigInt(topic0) === ethers.toBigInt(currentRootVectorObservedTopic)) {
|
|
3876
|
+
const parsed = channelManager.interface.parseLog(log);
|
|
3877
|
+
return {
|
|
3878
|
+
...log,
|
|
3879
|
+
args: parsed.args,
|
|
3880
|
+
fragment: parsed.fragment,
|
|
3881
|
+
};
|
|
3882
|
+
}
|
|
3883
|
+
return log;
|
|
3884
|
+
});
|
|
3863
3885
|
const vaultStorageWriteEvents = await queryContractEventsChunked({
|
|
3864
3886
|
contract: bridgeTokenVault,
|
|
3865
3887
|
eventName: "StorageWriteObserved",
|
|
3866
3888
|
fromBlock: genesisBlockNumber,
|
|
3867
3889
|
toBlock: latestBlock,
|
|
3868
3890
|
});
|
|
3869
|
-
const observedStorageLogs = await fetchLogsChunked(provider, {
|
|
3870
|
-
address: channelInfo.manager,
|
|
3871
|
-
topics: [[
|
|
3872
|
-
CONTROLLER_STORAGE_KEY_OBSERVED_TOPIC,
|
|
3873
|
-
VAULT_STORAGE_WRITE_OBSERVED_TOPIC,
|
|
3874
|
-
]],
|
|
3875
|
-
fromBlock: genesisBlockNumber,
|
|
3876
|
-
toBlock: latestBlock,
|
|
3877
|
-
});
|
|
3878
3891
|
|
|
3879
3892
|
const groupedEvents = new Map();
|
|
3880
|
-
for (const event of [...
|
|
3893
|
+
for (const event of [...channelManagerEvents, ...vaultStorageWriteEvents]) {
|
|
3881
3894
|
const key = event.transactionHash;
|
|
3882
3895
|
const group = groupedEvents.get(key) ?? [];
|
|
3883
3896
|
group.push(event);
|
|
@@ -4000,6 +4013,7 @@ async function fetchLogsChunked(provider, {
|
|
|
4000
4013
|
while (cursor <= resolvedToBlock) {
|
|
4001
4014
|
const chunkToBlock = Math.min(resolvedToBlock, cursor + chunkSize - 1);
|
|
4002
4015
|
try {
|
|
4016
|
+
await throttleLogRequest();
|
|
4003
4017
|
const logs = await provider.getLogs({
|
|
4004
4018
|
address,
|
|
4005
4019
|
topics,
|
|
@@ -4009,6 +4023,12 @@ async function fetchLogsChunked(provider, {
|
|
|
4009
4023
|
aggregatedLogs.push(...logs);
|
|
4010
4024
|
cursor = chunkToBlock + 1;
|
|
4011
4025
|
} catch (error) {
|
|
4026
|
+
if (isRateLimitError(error)) {
|
|
4027
|
+
throw new Error(
|
|
4028
|
+
`RPC log query rate limit exceeded. Log chunk requests are paced at ${DEFAULT_LOG_REQUESTS_PER_SECOND} requests per second.`,
|
|
4029
|
+
{ cause: error },
|
|
4030
|
+
);
|
|
4031
|
+
}
|
|
4012
4032
|
const suggestedChunkSize = deriveRecommendedLogChunkSize(error, chunkSize);
|
|
4013
4033
|
if (suggestedChunkSize >= chunkSize) {
|
|
4014
4034
|
throw error;
|
|
@@ -4020,6 +4040,31 @@ async function fetchLogsChunked(provider, {
|
|
|
4020
4040
|
return aggregatedLogs;
|
|
4021
4041
|
}
|
|
4022
4042
|
|
|
4043
|
+
async function throttleLogRequest() {
|
|
4044
|
+
const elapsedMs = Date.now() - lastLogRequestStartedAtMs;
|
|
4045
|
+
if (elapsedMs < LOG_REQUEST_INTERVAL_MS) {
|
|
4046
|
+
await sleep(LOG_REQUEST_INTERVAL_MS - elapsedMs);
|
|
4047
|
+
}
|
|
4048
|
+
lastLogRequestStartedAtMs = Date.now();
|
|
4049
|
+
}
|
|
4050
|
+
|
|
4051
|
+
function sleep(ms) {
|
|
4052
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
4053
|
+
}
|
|
4054
|
+
|
|
4055
|
+
function isRateLimitError(error) {
|
|
4056
|
+
const serializedError = [
|
|
4057
|
+
error?.code,
|
|
4058
|
+
error?.status,
|
|
4059
|
+
error?.message,
|
|
4060
|
+
error?.shortMessage,
|
|
4061
|
+
error?.info?.responseStatus,
|
|
4062
|
+
error?.info?.responseBody,
|
|
4063
|
+
].filter((value) => value !== undefined && value !== null).join("\n");
|
|
4064
|
+
|
|
4065
|
+
return /\b429\b|too many requests|rate limit|compute units/i.test(serializedError);
|
|
4066
|
+
}
|
|
4067
|
+
|
|
4023
4068
|
function deriveRecommendedLogChunkSize(error, currentChunkSize) {
|
|
4024
4069
|
const serializedError = [
|
|
4025
4070
|
error?.message,
|