UNPKG

@chainsafe/eth2.0-utils

Version:

Utilities required across multiple lodestar packages

136 lines (100 loc) 3.34 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ProgressiveMerkleTree = void 0; var _assert = _interopRequireDefault(require("assert")); var _crypto = require("../crypto"); var _math = require("../math"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } class ProgressiveMerkleTree { constructor(depth, tree, serialization) { _defineProperty(this, "_depth", void 0); _defineProperty(this, "_zerohashes", void 0); _defineProperty(this, "serialization", void 0); _defineProperty(this, "_tree", void 0); _defineProperty(this, "_dirty", void 0); (0, _assert.default)(depth > 1 && depth <= 52, "tree depth must be between 1 and 53"); this._depth = depth; this._tree = tree; this._zerohashes = this.generateZeroHashes(); this._dirty = false; this.serialization = serialization; } static deserialize(data, serialization) { const value = serialization.deserializeTree(data); return new ProgressiveMerkleTree(value.depth, value.tree, serialization); } static empty(depth, serialization) { const tree = Array.from({ length: depth + 1 }, () => []); return new ProgressiveMerkleTree(depth, tree, serialization); } depth() { return this._depth; } push(item) { this._dirty = true; this._tree[0].push(item); } add(index, item) { this._dirty = true; this._tree[0][index] = item; } getProof(index) { this.calculateBranchesIfNecessary(); const proof = []; for (let i = 0; i < this._depth; i++) { index = index % 2 === 1 ? index - 1 : index + 1; if (index < this._tree[i].length) { proof.push(this._tree[i][index]); } else { proof.push(this._zerohashes[i]); } index = (0, _math.intDiv)(index, 2); } proof.push(this.serialization.serializeLength(this._tree[0].length)); return proof; } root() { this.calculateBranchesIfNecessary(); return this._tree[this._depth][0]; } toObject() { return { depth: this._depth, tree: this._tree }; } calculateBranchesIfNecessary() { if (this._dirty) { this.calculateBranches(); } } calculateBranches() { for (let i = 0; i < this._depth; i++) { const parent = this._tree[i + 1]; const child = this._tree[i]; for (let j = 0; j < child.length; j += 2) { const left = child[j]; const right = j + 1 < child.length ? child[j + 1] : this._zerohashes[i]; parent[j / 2] = (0, _crypto.hash)(Buffer.concat([left, right])); } //unnecessary but makes clearer this._tree[i + 1] = parent; } this._dirty = false; } generateZeroHashes() { const zerohashes = Array.from({ length: this._depth }, () => Buffer.alloc(32)); for (let i = 0; i < this._depth - 1; i++) { zerohashes[i + 1] = (0, _crypto.hash)(Buffer.concat([zerohashes[i], zerohashes[i]])); } return zerohashes; } } exports.ProgressiveMerkleTree = ProgressiveMerkleTree; //# sourceMappingURL=merkleTree.js.map