@aeternity/aepp-sdk
Version:
SDK for the æternity blockchain
198 lines (170 loc) • 6.88 kB
JavaScript
import _slicedToArray from "@babel/runtime-corejs3/helpers/slicedToArray";
import _classCallCheck from "@babel/runtime-corejs3/helpers/classCallCheck";
import _createClass from "@babel/runtime-corejs3/helpers/createClass";
import _Object$fromEntries from "@babel/runtime-corejs3/core-js-stable/object/from-entries";
import _mapInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/map";
import _forEachInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/for-each";
import _Object$entries from "@babel/runtime-corejs3/core-js-stable/object/entries";
import _filterInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/filter";
import _sliceInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/slice";
import _parseInt from "@babel/runtime-corejs3/core-js-stable/parse-int";
import _includesInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/includes";
/*
* ISC License (ISC)
* Copyright (c) 2021 aeternity developers
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
import { encode as rlpEncode } from 'rlp';
import { hash } from './crypto-ts';
var NodeType;
(function (NodeType) {
NodeType[NodeType["Branch"] = 0] = "Branch";
NodeType[NodeType["Extension"] = 1] = "Extension";
NodeType[NodeType["Leaf"] = 2] = "Leaf";
})(NodeType || (NodeType = {}));
var MPTree = /*#__PURE__*/function () {
/**
* Deserialize Merkle Patricia Tree
* @rtype (binary: Array) => MPTree
* @param {Array} binary - Binary
* @return {MPTree} Merkle Patricia Tree
*/
function MPTree(binary) {
var _context,
_context2,
_this = this;
_classCallCheck(this, MPTree);
this.rootHash = binary[0].toString('hex');
this.nodes = _Object$fromEntries(_mapInstanceProperty(_context = binary[1]).call(_context, function (node) {
return [node[0].toString('hex'), node[1]];
}));
if (this.nodes[this.rootHash] === undefined) throw new Error('Can\'t find a node by root hash');
_forEachInstanceProperty(_context2 = _Object$entries(this.nodes)).call(_context2, function (_ref) {
var _context3, _context4;
var _ref2 = _slicedToArray(_ref, 2),
key = _ref2[0],
node = _ref2[1];
if (MPTree.nodeHash(node) !== key) throw new Error('Node hash is not equal to provided one');
var _MPTree$parseNode = MPTree.parseNode(node),
type = _MPTree$parseNode.type,
payload = _MPTree$parseNode.payload;
switch (type) {
case NodeType.Branch:
_forEachInstanceProperty(_context3 = _filterInstanceProperty(_context4 = _sliceInstanceProperty(payload).call(payload, 0, 16)).call(_context4, function (n) {
return n.length;
})).call(_context3, function (n) {
if (_this.nodes[n.toString('hex')] === undefined) {
throw new Error('Can\'t find a node by hash in branch node');
}
});
break;
case NodeType.Extension:
if (_this.nodes[payload[0].toString('hex')] === undefined) {
throw new Error('Can\'t find a node by hash in extension node');
}
}
});
}
_createClass(MPTree, [{
key: "isEqual",
value: function isEqual(tree) {
return this.rootHash === tree.rootHash;
}
}, {
key: "serialize",
value:
/**
* Serialize Merkle Patricia Tree
* @rtype () => Array
* @return {Array} Binary
*/
function serialize() {
var _context5;
return [Buffer.from(this.rootHash, 'hex'), _mapInstanceProperty(_context5 = _Object$entries(this.nodes)).call(_context5, function (_ref3) {
var _ref4 = _slicedToArray(_ref3, 2),
mptHash = _ref4[0],
value = _ref4[1];
return [Buffer.from(mptHash, 'hex'), value];
})];
}
/**
* Retrieve value from Merkle Patricia Tree
* @rtype (key: String) => Buffer
* @param {String} key - The key of the element to retrieve
* @return {Buffer} Value associated to the specified key
*/
}, {
key: "get",
value: function get(key) {
var searchFrom = this.rootHash;
while (true) {
var _MPTree$parseNode2 = MPTree.parseNode(this.nodes[searchFrom]),
type = _MPTree$parseNode2.type,
payload = _MPTree$parseNode2.payload,
path = _MPTree$parseNode2.path;
switch (type) {
case NodeType.Branch:
if (key.length === 0) return payload[16];
searchFrom = payload[_parseInt(key[0], 16)].toString('hex');
key = key.substr(1);
break;
case NodeType.Extension:
if (key.substr(0, path === null || path === void 0 ? void 0 : path.length) !== path) return undefined;
searchFrom = payload[0].toString('hex');
key = key.substr(path.length);
break;
case NodeType.Leaf:
if (path !== key) return undefined;
return payload[0];
}
}
}
}], [{
key: "nodeHash",
value: function nodeHash(node) {
return Buffer.from(hash(rlpEncode(node))).toString('hex');
}
}, {
key: "parseNode",
value: function parseNode(node) {
switch (node.length) {
case 17:
return {
type: NodeType.Branch,
payload: node,
path: null
};
case 2:
{
var _context6;
var path = node[0].toString('hex');
var nibble = _parseInt(path[0], 16);
if (nibble > 3) throw new Error("Unknown path nibble: ".concat(nibble));
var type = nibble <= 1 ? NodeType.Extension : NodeType.Leaf;
var slice = _includesInstanceProperty(_context6 = [0, 2]).call(_context6, nibble) ? 2 : 1;
return {
type: type,
payload: [node[1]],
path: _sliceInstanceProperty(path).call(path, slice)
};
}
default:
throw new Error("Unknown node length: ".concat(node.length));
}
}
}]);
return MPTree;
}();
export { MPTree as default };
//# sourceMappingURL=mptree.js.map