@chainsafe/ssz
Version:
Simple Serialize
87 lines • 3.42 kB
JavaScript
import { HashComputationGroup, executeHashComputations } from "@chainsafe/persistent-merkle-tree";
import { TreeView } from "../view/abstract.js";
/**
* Always allocating a new HashComputationGroup for each hashTreeRoot() is not great for gc
* because a lot of ViewDUs are not changed and computed root already.
*/
const symbolCachedTreeRoot = Symbol("ssz_cached_tree_root");
/**
* A Deferred Update Tree View (`ViewDU`) is a wrapper around a type and
* a SSZ Node that contains:
* - data merkleized
* - some arbitrary caches to speed up data manipulation required by the type
*
* **ViewDU**
* - Best for complex usage where performance is important
* - Defers changes to when commit is called
* - Does NOT have a reference to the parent ViewDU
* - Has caches for fast get / set ops
*/
export class TreeViewDU extends TreeView {
/*
* By default use type to serialize ViewDU.
*/
serializeToBytes(output, offset) {
return this.type.tree_serializeToBytes(output, offset, this.node);
}
/**
* Merkleize view and compute its hashTreeRoot.
* Commits any pending changes before computing the root.
*
* See spec for definition of hashTreeRoot:
* https://github.com/ethereum/consensus-specs/blob/dev/ssz/simple-serialize.md#merkleization
*/
hashTreeRoot() {
this.commit();
return super.hashTreeRoot();
}
/**
* The same to hashTreeRoot() but with batch hash computation.
* Consumer can allocate and reuse a HashComputationGroup() if needed.
*/
batchHashTreeRoot(hcGroup = new HashComputationGroup()) {
// in ethereum consensus, the only type goes with TVDU is BeaconState and it's really more efficient to hash the tree in batch
const offset = 0;
hcGroup.reset();
this.commit(offset, hcGroup.byLevel);
hcGroup.clean();
const cachedRoot = this.node[symbolCachedTreeRoot];
if (cachedRoot) {
return cachedRoot;
}
executeHashComputations(hcGroup.byLevel);
// This makes sure the root node is computed by batch
if (this.node.h0 === null) {
throw Error("Root is not computed by batch");
}
const root = this.node.root;
this.node[symbolCachedTreeRoot] = root;
return root;
}
/**
* Serialize view to binary data.
* Commits any pending changes before computing the root.
* This calls commit() which evict all pending HashComputations. Consider calling hashTreeRoot() before this
*/
serialize() {
this.commit();
const output = new Uint8Array(this.type.tree_serializedSize(this.node));
const dataView = new DataView(output.buffer, output.byteOffset, output.byteLength);
this.serializeToBytes({ uint8Array: output, dataView }, 0);
return output;
}
/**
* Return a new ViewDU instance referencing the same internal `Node`.
*
* By default it will transfer the cache of this ViewDU to the new cloned instance. Set `dontTransferCache` to true
* to NOT transfer the cache to the cloned instance.
*/
clone(dontTransferCache) {
if (dontTransferCache)
return this.type.getViewDU(this.node);
const cache = this.cache;
this.clearCache();
return this.type.getViewDU(this.node, cache);
}
}
//# sourceMappingURL=abstract.js.map