@chainsafe/eth2.0-utils
Version:
Utilities required across multiple lodestar packages
136 lines (100 loc) • 3.34 kB
JavaScript
"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