@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/node.js
CHANGED
|
@@ -7189,15 +7189,17 @@ var MerkleEngine = class _MerkleEngine {
|
|
|
7189
7189
|
for (let i = 0; i < sorted.length; i++) {
|
|
7190
7190
|
if (sorted[i].cid !== i) throw new Error(`Non-contiguous persisted merkle leaves: expected cid=${i}, got cid=${sorted[i].cid}`);
|
|
7191
7191
|
}
|
|
7192
|
-
const
|
|
7193
|
-
const
|
|
7192
|
+
const storedTree = await this.storage?.getMerkleTree?.(chainId);
|
|
7193
|
+
const leafCount = sorted.length;
|
|
7194
|
+
const mergedFromLeaves = _MerkleEngine.totalElementsInTree(BigInt(leafCount));
|
|
7195
|
+
const mergedFromTree = typeof storedTree?.totalElements === "number" && storedTree.totalElements > 0 ? storedTree.totalElements : 0;
|
|
7196
|
+
const mergedElements = Math.max(mergedFromLeaves, mergedFromTree);
|
|
7194
7197
|
const pending = this.ensurePendingLeaves(chainId);
|
|
7195
7198
|
pending.length = 0;
|
|
7196
7199
|
state.mergedElements = mergedElements;
|
|
7197
|
-
if (
|
|
7200
|
+
if (leafCount > mergedElements) {
|
|
7198
7201
|
pending.push(...sorted.slice(mergedElements).map((l) => l.commitment));
|
|
7199
7202
|
}
|
|
7200
|
-
const storedTree = await this.storage?.getMerkleTree?.(chainId);
|
|
7201
7203
|
if (storedTree?.root) {
|
|
7202
7204
|
state.root = _MerkleEngine.normalizeHex32(storedTree.root, "merkleTree.root");
|
|
7203
7205
|
} else {
|
|
@@ -7247,7 +7249,10 @@ var MerkleEngine = class _MerkleEngine {
|
|
|
7247
7249
|
if (!leaves.length) return;
|
|
7248
7250
|
const sorted = [...leaves].sort((a, b) => a.index - b.index);
|
|
7249
7251
|
const persistLeaves = sorted.map((l) => ({ cid: l.index, commitment: l.commitment }));
|
|
7250
|
-
|
|
7252
|
+
try {
|
|
7253
|
+
await this.storage?.appendMerkleLeaves?.(chainId, persistLeaves);
|
|
7254
|
+
} catch {
|
|
7255
|
+
}
|
|
7251
7256
|
try {
|
|
7252
7257
|
let expected = state.mergedElements + pending.length;
|
|
7253
7258
|
for (const leaf of sorted) {
|
|
@@ -7289,6 +7294,90 @@ var MerkleEngine = class _MerkleEngine {
|
|
|
7289
7294
|
throw new SdkError("MERKLE", "Failed to ingest local merkle leaves", { chainId, leafCount: leaves.length }, error);
|
|
7290
7295
|
}
|
|
7291
7296
|
}
|
|
7297
|
+
/**
|
|
7298
|
+
* Roll back the local Merkle tree to a previous checkpoint.
|
|
7299
|
+
*
|
|
7300
|
+
* Reconstructs correct frontier state by replaying merges from stored subtree
|
|
7301
|
+
* roots (level-5 nodes). Cost: O(batches × depth) where batches = target / 32.
|
|
7302
|
+
*
|
|
7303
|
+
* @param targetMergedElements Must be a non-negative multiple of 32 (SUBTREE_SIZE).
|
|
7304
|
+
* Pass 0 to reset to the empty tree.
|
|
7305
|
+
* @returns true if rollback succeeded, false if required data (checkpoint or
|
|
7306
|
+
* subtree roots) is missing in storage.
|
|
7307
|
+
*/
|
|
7308
|
+
async rollbackTree(chainId, targetMergedElements) {
|
|
7309
|
+
if (targetMergedElements < 0 || targetMergedElements % SUBTREE_SIZE !== 0) {
|
|
7310
|
+
throw new SdkError("MERKLE", "rollbackTree target must be a non-negative multiple of 32", { targetMergedElements });
|
|
7311
|
+
}
|
|
7312
|
+
const state = this.ensureChainState(chainId);
|
|
7313
|
+
const pending = this.ensurePendingLeaves(chainId);
|
|
7314
|
+
if (targetMergedElements === 0) {
|
|
7315
|
+
state.mergedElements = 0;
|
|
7316
|
+
state.root = getZeroHash(this.treeDepth);
|
|
7317
|
+
pending.length = 0;
|
|
7318
|
+
await this.storage?.setMerkleTree?.(chainId, {
|
|
7319
|
+
chainId,
|
|
7320
|
+
root: state.root,
|
|
7321
|
+
totalElements: 0,
|
|
7322
|
+
lastUpdated: Date.now()
|
|
7323
|
+
});
|
|
7324
|
+
return true;
|
|
7325
|
+
}
|
|
7326
|
+
const checkpoint = await this.storage?.getMerkleNode?.(chainId, `checkpoint-${targetMergedElements}`);
|
|
7327
|
+
if (!checkpoint) return false;
|
|
7328
|
+
const numBatches = targetMergedElements / SUBTREE_SIZE;
|
|
7329
|
+
const subtreeRoots = [];
|
|
7330
|
+
for (let batch = 0; batch < numBatches; batch++) {
|
|
7331
|
+
const node = await this.storage?.getMerkleNode?.(chainId, `${SUBTREE_DEPTH}-${batch}`);
|
|
7332
|
+
if (!node) return false;
|
|
7333
|
+
subtreeRoots.push(node.hash);
|
|
7334
|
+
}
|
|
7335
|
+
const resetNodes = [];
|
|
7336
|
+
for (let level = SUBTREE_DEPTH; level < this.treeDepth; level++) {
|
|
7337
|
+
resetNodes.push({
|
|
7338
|
+
chainId,
|
|
7339
|
+
id: `frontier-${level}`,
|
|
7340
|
+
level,
|
|
7341
|
+
position: 0,
|
|
7342
|
+
hash: getZeroHash(level)
|
|
7343
|
+
});
|
|
7344
|
+
}
|
|
7345
|
+
await this.storage?.upsertMerkleNodes?.(chainId, resetNodes);
|
|
7346
|
+
let replayRoot = getZeroHash(this.treeDepth);
|
|
7347
|
+
for (let batch = 0; batch < numBatches; batch++) {
|
|
7348
|
+
const merged = await this.mergeSubtreeToMainTree({
|
|
7349
|
+
chainId,
|
|
7350
|
+
subtreeRoot: subtreeRoots[batch],
|
|
7351
|
+
newTotalElements: (batch + 1) * SUBTREE_SIZE
|
|
7352
|
+
});
|
|
7353
|
+
replayRoot = merged.finalRoot;
|
|
7354
|
+
await this.storage?.upsertMerkleNodes?.(chainId, merged.nodesToStore.map((n) => ({ ...n, chainId })));
|
|
7355
|
+
}
|
|
7356
|
+
const replayNorm = _MerkleEngine.normalizeHex32(replayRoot, "replay.root");
|
|
7357
|
+
const checkpointNorm = _MerkleEngine.normalizeHex32(checkpoint.hash, "checkpoint.root");
|
|
7358
|
+
if (replayNorm !== checkpointNorm) {
|
|
7359
|
+
return false;
|
|
7360
|
+
}
|
|
7361
|
+
state.mergedElements = targetMergedElements;
|
|
7362
|
+
state.root = checkpointNorm;
|
|
7363
|
+
pending.length = 0;
|
|
7364
|
+
this.hydratedChains.add(chainId);
|
|
7365
|
+
await this.storage?.setMerkleTree?.(chainId, {
|
|
7366
|
+
chainId,
|
|
7367
|
+
root: state.root,
|
|
7368
|
+
totalElements: targetMergedElements,
|
|
7369
|
+
lastUpdated: Date.now()
|
|
7370
|
+
});
|
|
7371
|
+
const updatedCheckpoint = {
|
|
7372
|
+
chainId,
|
|
7373
|
+
id: `checkpoint-${targetMergedElements}`,
|
|
7374
|
+
level: -1,
|
|
7375
|
+
position: 0,
|
|
7376
|
+
hash: checkpointNorm
|
|
7377
|
+
};
|
|
7378
|
+
await this.storage?.upsertMerkleNodes?.(chainId, [updatedCheckpoint]);
|
|
7379
|
+
return true;
|
|
7380
|
+
}
|
|
7292
7381
|
/**
|
|
7293
7382
|
* Convenience wrapper to request a single proof.
|
|
7294
7383
|
*/
|