@ocash/sdk 0.1.3 → 0.1.4-rc.1
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/dist/browser.cjs +94 -5
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.js +94 -5
- package/dist/browser.js.map +1 -1
- package/dist/index.cjs +94 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +94 -5
- package/dist/index.js.map +1 -1
- package/dist/node.cjs +94 -5
- package/dist/node.cjs.map +1 -1
- package/dist/node.js +94 -5
- package/dist/node.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -7256,15 +7256,17 @@ var MerkleEngine = class _MerkleEngine {
|
|
|
7256
7256
|
for (let i = 0; i < sorted.length; i++) {
|
|
7257
7257
|
if (sorted[i].cid !== i) throw new Error(`Non-contiguous persisted merkle leaves: expected cid=${i}, got cid=${sorted[i].cid}`);
|
|
7258
7258
|
}
|
|
7259
|
-
const
|
|
7260
|
-
const
|
|
7259
|
+
const storedTree = await this.storage?.getMerkleTree?.(chainId);
|
|
7260
|
+
const leafCount = sorted.length;
|
|
7261
|
+
const mergedFromLeaves = _MerkleEngine.totalElementsInTree(BigInt(leafCount));
|
|
7262
|
+
const mergedFromTree = typeof storedTree?.totalElements === "number" && storedTree.totalElements > 0 ? storedTree.totalElements : 0;
|
|
7263
|
+
const mergedElements = Math.max(mergedFromLeaves, mergedFromTree);
|
|
7261
7264
|
const pending = this.ensurePendingLeaves(chainId);
|
|
7262
7265
|
pending.length = 0;
|
|
7263
7266
|
state.mergedElements = mergedElements;
|
|
7264
|
-
if (
|
|
7267
|
+
if (leafCount > mergedElements) {
|
|
7265
7268
|
pending.push(...sorted.slice(mergedElements).map((l) => l.commitment));
|
|
7266
7269
|
}
|
|
7267
|
-
const storedTree = await this.storage?.getMerkleTree?.(chainId);
|
|
7268
7270
|
if (storedTree?.root) {
|
|
7269
7271
|
state.root = _MerkleEngine.normalizeHex32(storedTree.root, "merkleTree.root");
|
|
7270
7272
|
} else {
|
|
@@ -7314,7 +7316,10 @@ var MerkleEngine = class _MerkleEngine {
|
|
|
7314
7316
|
if (!leaves.length) return;
|
|
7315
7317
|
const sorted = [...leaves].sort((a, b) => a.index - b.index);
|
|
7316
7318
|
const persistLeaves = sorted.map((l) => ({ cid: l.index, commitment: l.commitment }));
|
|
7317
|
-
|
|
7319
|
+
try {
|
|
7320
|
+
await this.storage?.appendMerkleLeaves?.(chainId, persistLeaves);
|
|
7321
|
+
} catch {
|
|
7322
|
+
}
|
|
7318
7323
|
try {
|
|
7319
7324
|
let expected = state.mergedElements + pending.length;
|
|
7320
7325
|
for (const leaf of sorted) {
|
|
@@ -7356,6 +7361,90 @@ var MerkleEngine = class _MerkleEngine {
|
|
|
7356
7361
|
throw new SdkError("MERKLE", "Failed to ingest local merkle leaves", { chainId, leafCount: leaves.length }, error);
|
|
7357
7362
|
}
|
|
7358
7363
|
}
|
|
7364
|
+
/**
|
|
7365
|
+
* Roll back the local Merkle tree to a previous checkpoint.
|
|
7366
|
+
*
|
|
7367
|
+
* Reconstructs correct frontier state by replaying merges from stored subtree
|
|
7368
|
+
* roots (level-5 nodes). Cost: O(batches × depth) where batches = target / 32.
|
|
7369
|
+
*
|
|
7370
|
+
* @param targetMergedElements Must be a non-negative multiple of 32 (SUBTREE_SIZE).
|
|
7371
|
+
* Pass 0 to reset to the empty tree.
|
|
7372
|
+
* @returns true if rollback succeeded, false if required data (checkpoint or
|
|
7373
|
+
* subtree roots) is missing in storage.
|
|
7374
|
+
*/
|
|
7375
|
+
async rollbackTree(chainId, targetMergedElements) {
|
|
7376
|
+
if (targetMergedElements < 0 || targetMergedElements % SUBTREE_SIZE !== 0) {
|
|
7377
|
+
throw new SdkError("MERKLE", "rollbackTree target must be a non-negative multiple of 32", { targetMergedElements });
|
|
7378
|
+
}
|
|
7379
|
+
const state = this.ensureChainState(chainId);
|
|
7380
|
+
const pending = this.ensurePendingLeaves(chainId);
|
|
7381
|
+
if (targetMergedElements === 0) {
|
|
7382
|
+
state.mergedElements = 0;
|
|
7383
|
+
state.root = getZeroHash(this.treeDepth);
|
|
7384
|
+
pending.length = 0;
|
|
7385
|
+
await this.storage?.setMerkleTree?.(chainId, {
|
|
7386
|
+
chainId,
|
|
7387
|
+
root: state.root,
|
|
7388
|
+
totalElements: 0,
|
|
7389
|
+
lastUpdated: Date.now()
|
|
7390
|
+
});
|
|
7391
|
+
return true;
|
|
7392
|
+
}
|
|
7393
|
+
const checkpoint = await this.storage?.getMerkleNode?.(chainId, `checkpoint-${targetMergedElements}`);
|
|
7394
|
+
if (!checkpoint) return false;
|
|
7395
|
+
const numBatches = targetMergedElements / SUBTREE_SIZE;
|
|
7396
|
+
const subtreeRoots = [];
|
|
7397
|
+
for (let batch = 0; batch < numBatches; batch++) {
|
|
7398
|
+
const node = await this.storage?.getMerkleNode?.(chainId, `${SUBTREE_DEPTH}-${batch}`);
|
|
7399
|
+
if (!node) return false;
|
|
7400
|
+
subtreeRoots.push(node.hash);
|
|
7401
|
+
}
|
|
7402
|
+
const resetNodes = [];
|
|
7403
|
+
for (let level = SUBTREE_DEPTH; level < this.treeDepth; level++) {
|
|
7404
|
+
resetNodes.push({
|
|
7405
|
+
chainId,
|
|
7406
|
+
id: `frontier-${level}`,
|
|
7407
|
+
level,
|
|
7408
|
+
position: 0,
|
|
7409
|
+
hash: getZeroHash(level)
|
|
7410
|
+
});
|
|
7411
|
+
}
|
|
7412
|
+
await this.storage?.upsertMerkleNodes?.(chainId, resetNodes);
|
|
7413
|
+
let replayRoot = getZeroHash(this.treeDepth);
|
|
7414
|
+
for (let batch = 0; batch < numBatches; batch++) {
|
|
7415
|
+
const merged = await this.mergeSubtreeToMainTree({
|
|
7416
|
+
chainId,
|
|
7417
|
+
subtreeRoot: subtreeRoots[batch],
|
|
7418
|
+
newTotalElements: (batch + 1) * SUBTREE_SIZE
|
|
7419
|
+
});
|
|
7420
|
+
replayRoot = merged.finalRoot;
|
|
7421
|
+
await this.storage?.upsertMerkleNodes?.(chainId, merged.nodesToStore.map((n) => ({ ...n, chainId })));
|
|
7422
|
+
}
|
|
7423
|
+
const replayNorm = _MerkleEngine.normalizeHex32(replayRoot, "replay.root");
|
|
7424
|
+
const checkpointNorm = _MerkleEngine.normalizeHex32(checkpoint.hash, "checkpoint.root");
|
|
7425
|
+
if (replayNorm !== checkpointNorm) {
|
|
7426
|
+
return false;
|
|
7427
|
+
}
|
|
7428
|
+
state.mergedElements = targetMergedElements;
|
|
7429
|
+
state.root = checkpointNorm;
|
|
7430
|
+
pending.length = 0;
|
|
7431
|
+
this.hydratedChains.add(chainId);
|
|
7432
|
+
await this.storage?.setMerkleTree?.(chainId, {
|
|
7433
|
+
chainId,
|
|
7434
|
+
root: state.root,
|
|
7435
|
+
totalElements: targetMergedElements,
|
|
7436
|
+
lastUpdated: Date.now()
|
|
7437
|
+
});
|
|
7438
|
+
const updatedCheckpoint = {
|
|
7439
|
+
chainId,
|
|
7440
|
+
id: `checkpoint-${targetMergedElements}`,
|
|
7441
|
+
level: -1,
|
|
7442
|
+
position: 0,
|
|
7443
|
+
hash: checkpointNorm
|
|
7444
|
+
};
|
|
7445
|
+
await this.storage?.upsertMerkleNodes?.(chainId, [updatedCheckpoint]);
|
|
7446
|
+
return true;
|
|
7447
|
+
}
|
|
7359
7448
|
/**
|
|
7360
7449
|
* Convenience wrapper to request a single proof.
|
|
7361
7450
|
*/
|