diff --git a/cloudflare/mock/durableObject.js b/cloudflare/mock/durableObject.js index a5b37bd..46b4471 100644 --- a/cloudflare/mock/durableObject.js +++ b/cloudflare/mock/durableObject.js @@ -22,6 +22,13 @@ class DurableObjectState { return Promise.resolve(map); }, + /** + * @override + * + * @param {string|!Object} keys + * @param {*=} val + * @return {!Promise} + */ put: (keys, val) => { if (typeof keys === 'string') this.mem[keys] = val; diff --git a/mina/merkleTree.js b/mina/merkleTree.js index 335f1b5..6218f42 100644 --- a/mina/merkleTree.js +++ b/mina/merkleTree.js @@ -23,13 +23,13 @@ class MinaMerkleTree { * @const {!Object} */ this.nodes = {}; - /** @const {!Array} */ + /** @const {!Array} */ const zeros = Array(height + 1); - /** @const {!Array} */ + /** @const {!Array} */ zeros[height] = 0n; for (let i = height; i > 0; --i) zeros[i - 1] = poseidon([zeros[i], zeros[i]]); - /** @const {!Array} */ + /** @const {!Array} */ this.zeros = zeros; } @@ -51,15 +51,15 @@ class MinaMerkleTree { * @return {Value} the root after insertion */ setLeaf(key, val) { - /** @const {number} */ - const h = this.height; + /** @type {number} */ + let h = this.height; key = hex.toBinary(key).padStart(h, "0").slice(0, h); - for (; ;) { + for (; ; --h) { this.nodes[key] = val; if (!key) return val; const isLeft = key.charCodeAt(key.length - 1) == 48; key = key.slice(0, -1); - const sibling = this.getNode(key + +isLeft); + const sibling = this.nodes[key + +isLeft] || this.zeros[h]; val = poseidon(isLeft ? [val, sibling] : [sibling, val]); } } @@ -81,7 +81,7 @@ class MinaMerkleTree { key = key.slice(0, -1); witness[d] = { isLeft, - sibling: this.nodes[key] || this.zeros[h - d], + sibling: this.nodes[key + (+isLeft)] || this.zeros[h - d], }; } return witness; diff --git a/mina/test/merkleTree.compiled-test.js b/mina/test/merkleTree.compiled-test.js index e503a0b..bab34ae 100644 --- a/mina/test/merkleTree.compiled-test.js +++ b/mina/test/merkleTree.compiled-test.js @@ -36,13 +36,66 @@ const testGetWitness = () => { const zeroWitness = tree.zeros.slice(1).reverse(); assertArrayEq( - tree - .getWitness(HexKey("00000000")) - .map((/** @type {WitnessElem} */ w) => w.sibling), + tree.getWitness(HexKey("00000000")).map((/** @type {WitnessElem} */ w) => w.sibling), zeroWitness ); + + const t4 = new MinaMerkleTree(4); + t4.setLeaf(HexKey("E"), 31n); + + assertArrayEq( + t4.getWitness(HexKey("F")).map((/** @type {WitnessElem} */ w) => w.sibling), + [31n, t4.zeros[3], t4.zeros[2], t4.zeros[1]] + ); + + t4.setLeaf(HexKey("D"), 30n); + + assertArrayEq( + t4.getWitness(HexKey("F")).map((/** @type {WitnessElem} */ w) => w.sibling), + [31n, poseidon([0n, 30n]), t4.zeros[2], t4.zeros[1]] + ); + + t4.setLeaf(HexKey("B"), 28n); + + assertArrayEq( + t4.getWitness(HexKey("F")).map((/** @type {WitnessElem} */ w) => w.sibling), + [31n, poseidon([0n, 30n]), poseidon([t4.zeros[3], poseidon([0n, 28n])]), t4.zeros[1]] + ); + + assertArrayEq( + t4.getWitness(HexKey("E")).map((/** @type {WitnessElem} */ w) => w.sibling), + [0n, poseidon([0n, 30n]), poseidon([t4.zeros[3], poseidon([0n, 28n])]), t4.zeros[1]] + ); + + assertArrayEq( + t4.getWitness(HexKey("E")).map((/** @type {WitnessElem} */ w) => w.isLeft), + [true, false, false, false] + ); }; +// const testRoot = () => { +// const tree = new MerkleTree(2); + +// tree.setLeaf("00", 12n); +// const root = tree.setLeaf("01", 13n); + +// assertEq(tree.getNode(""), root); +// assertEq( +// tree.getNode(""), +// 24761230160490995408576941661835661171884064004388554675853100205564068190570n +// ); + +// tree.setLeaf("10", 69n); +// const root2 = tree.setLeaf("11", 31n); + +// assertEq( +// root2, +// 19896916020666948695671743788555051064473578822640662440592176193110027392115n +// ); +// assertEq(tree.getNode(""), root2); +// }; + testSetGetLeaf(); testNodeConsistency(); testGetWitness(); +// testRoot();