snarky-smt
Version:
Sparse Merkle Tree for SnarkyJS
78 lines (77 loc) • 2.94 kB
JavaScript
import { Poseidon } from 'snarkyjs';
import { CSMTUtils } from './proofs';
import { CompactSparseMerkleTree } from './csmt';
export { CompactDeepSparseMerkleSubTree };
/**
* This is used to compute new roots for state transitions based on sideNodes.
*
* @class CompactSparseMerkleTree
* @extends {CompactDeepSparseMerkleSubTree<K, V>}
* @template K
* @template V
*/
class CompactDeepSparseMerkleSubTree extends CompactSparseMerkleTree {
/**
* Creates an instance of CompactDeepSparseMerkleSubTree.
* @param {Store<V>} store
* @param {Field} root
* @param {Provable<K>} keyType
* @param {Provable<V>} valueType
* @param {{ hasher?: Hasher; hashKey?: boolean; hashValue?: boolean }} [options={
* hasher: Poseidon.hash,
* hashKey: true,
* hashValue: true,
* }] hasher: The hash function to use, defaults to Poseidon.hash; hashKey:
* whether to hash the key, the default is true; hashValue: whether to hash the value,
* the default is true.
* @memberof CompactDeepSparseMerkleSubTree
*/
constructor(store, root, keyType, valueType, options = {
hasher: Poseidon.hash,
hashKey: true,
hashValue: true,
}) {
super(store, keyType, valueType, root, options);
}
/**
* Add a branch to the tree, a branch is generated by smt.prove.
*
* @param {CompactSparseMerkleProof} proof
* @param {K} key
* @param {V} [value]
* @memberof CompactDeepSparseMerkleSubTree
*/
async addBranch(proof, key, value) {
const { ok, updates } = CSMTUtils.verifyProofWithUpdates(proof, this.getRoot(), key, this.keyType, value, this.valueType, {
hasher: this.th.getHasher(),
hashKey: this.config.hashKey,
hashValue: this.config.hashValue,
});
if (!ok) {
throw new Error('Invalid proof');
}
if (value !== undefined) {
let path = null;
if (this.config.hashKey) {
path = this.th.path(key);
}
else {
let keyFields = this.keyType.toFields(key);
if (keyFields.length > 1) {
throw new Error(`The length of key fields is greater than 1, the key needs to be hashed before it can be processed, option 'hashKey' must be set to true`);
}
path = keyFields[0];
}
this.store.preparePutValue(path, value);
}
updates?.forEach((v) => {
this.store.preparePutNodes(v[0], v[1]);
});
if (!this.th.isEmptyData(proof.siblingData)) {
if (proof.sideNodes.length > 0) {
this.store.preparePutNodes(proof.sideNodes[0], proof.siblingData);
}
}
await this.store.commit();
}
}