parsec-lib
Version:
transaction and block implementation
136 lines (103 loc) • 8.44 kB
JavaScript
;Object.defineProperty(exports, "__esModule", { value: true });var _createClass = function () {function defineProperties(target, props) {for (var i = 0; i < props.length; i++) {var descriptor = props[i];descriptor.enumerable = descriptor.enumerable || false;descriptor.configurable = true;if ("value" in descriptor) descriptor.writable = true;Object.defineProperty(target, descriptor.key, descriptor);}}return function (Constructor, protoProps, staticProps) {if (protoProps) defineProperties(Constructor.prototype, protoProps);if (staticProps) defineProperties(Constructor, staticProps);return Constructor;};}();
/**
* Copyright (c) 2018-present, Parsec Labs (parseclabs.org)
*
* This source code is licensed under the GNU Affero General Public License,
* version 3, found in the LICENSE file in the root directory of this source
* tree.
*/
// Adopted from: https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/test/helpers/merkleTree.js
// Changes:
// - Removed sorting and deduplication
// - Added padding to even number of elements
var _ethereumjsUtil = require('ethereumjs-util');function _classCallCheck(instance, Constructor) {if (!(instance instanceof Constructor)) {throw new TypeError("Cannot call a class as a function");}}
/* eslint-disable class-methods-use-this */var
MerkleTree = function () {
function MerkleTree(elements) {_classCallCheck(this, MerkleTree);
// Filter empty strings and hash elements
this.elements = elements.filter(function (el) {return el;});
if (this.elements.length % 2 !== 0) {
this.elements.push(Buffer.alloc(32, 0));
}
// Create layers
this.layers = this.getLayers(this.elements);
}_createClass(MerkleTree, [{ key: 'getLayers', value: function getLayers(
elements) {
if (elements.length === 0) {
return [['']];
}
var layers = [];
layers.push(elements);
// Get next layer until we reach the root
while (layers[layers.length - 1].length > 1) {
layers.push(this.getNextLayer(layers[layers.length - 1]));
}
return layers;
} }, { key: 'getNextLayer', value: function getNextLayer(
elements) {var _this = this;
return elements.reduce(function (layer, el, idx, arr) {
if (idx % 2 === 0) {
// Hash the current element with its pair element
layer.push(_this.combinedHash(el, arr[idx + 1]));
}
return layer;
}, []);
} }, { key: 'combinedHash', value: function combinedHash(
first, second) {
if (!first) {return second;}
if (!second) {return first;}
return (0, _ethereumjsUtil.keccak256)(Buffer.concat([first, second]));
} }, { key: 'getRoot', value: function getRoot()
{
return this.layers[this.layers.length - 1][0];
} }, { key: 'getHexRoot', value: function getHexRoot()
{
return (0, _ethereumjsUtil.bufferToHex)(this.getRoot());
} }, { key: 'getProof', value: function getProof(
el) {var _this2 = this;
var idx = this.bufIndexOf(el, this.elements);
if (idx === -1) {
throw new Error('Element does not exist in Merkle tree');
}
return this.layers.reduce(function (proof, layer) {
var pairElement = _this2.getPairElement(idx, layer);
if (pairElement) {
proof.push(pairElement);
}
idx = Math.floor(idx / 2);
return proof;
}, []);
} }, { key: 'getHexProof', value: function getHexProof(
el) {
var proof = this.getProof(el);
return this.bufArrToHexArr(proof);
} }, { key: 'getPairElement', value: function getPairElement(
idx, layer) {
var pairIdx = idx % 2 === 0 ? idx + 1 : idx - 1;
if (pairIdx < layer.length) {
return layer[pairIdx];
}
return null;
} }, { key: 'bufIndexOf', value: function bufIndexOf(
el, arr) {
var hash = void 0;
// Convert element to 32 byte hash if it is not one already
if (el.length !== 32 || !Buffer.isBuffer(el)) {
hash = (0, _ethereumjsUtil.keccak256)(el);
} else {
hash = el;
}
for (var i = 0; i < arr.length; i++) {
if (hash.equals(arr[i])) {
return i;
}
}
return -1;
} }, { key: 'bufArrToHexArr', value: function bufArrToHexArr(
arr) {
if (arr.some(function (el) {return !Buffer.isBuffer(el);})) {
throw new Error('Array is not an array of buffers');
}
return arr.map(function (el) {return '0x' + el.toString('hex');});
} }]);return MerkleTree;}();
/* eslint-enable class-methods-use-this */exports.default = MerkleTree;module.exports = exports['default'];