UNPKG

@aeternity/aepp-sdk

Version:

SDK for the æternity blockchain

223 lines 8.99 kB
import { Buffer as _Buffer } from "buffer"; var _MPTree; function _classPrivateMethodInitSpec(e, a) { _checkPrivateRedeclaration(e, a), a.add(e); } function _classPrivateFieldInitSpec(e, t, a) { _checkPrivateRedeclaration(e, t), t.set(e, a); } function _checkPrivateRedeclaration(e, t) { if (t.has(e)) throw new TypeError("Cannot initialize the same private elements twice on an object"); } function _classPrivateFieldSet(s, a, r) { return s.set(_assertClassBrand(s, a), r), r; } function _classPrivateFieldGet(s, a) { return s.get(_assertClassBrand(s, a)); } function _assertClassBrand(e, t, n) { if ("function" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n; throw new TypeError("Private element is not present on this object"); } import { encode as rlpEncode } from 'rlp'; import { hash } from '../../../utils/crypto.js'; import { MerkleTreeHashMismatchError, MissingNodeInTreeError, UnknownPathNibbleError, UnexpectedTsError, UnknownNodeLengthError, InternalError } from '../../../utils/errors.js'; import { decode, encode, Encoding } from '../../../utils/encoder.js'; var NodeType = /*#__PURE__*/function (NodeType) { NodeType[NodeType["Branch"] = 0] = "Branch"; NodeType[NodeType["Extension"] = 1] = "Extension"; NodeType[NodeType["Leaf"] = 2] = "Leaf"; return NodeType; }(NodeType || {}); var _rootHash = /*#__PURE__*/new WeakMap(); var _isComplete = /*#__PURE__*/new WeakMap(); var _nodes = /*#__PURE__*/new WeakMap(); var _encoding = /*#__PURE__*/new WeakMap(); var _tag = /*#__PURE__*/new WeakMap(); var _unpackEntry = /*#__PURE__*/new WeakMap(); var _MPTree_brand = /*#__PURE__*/new WeakSet(); class MPTree { get isComplete() { return _classPrivateFieldGet(_isComplete, this); } /** * Deserialize Merkle Patricia Tree * @param binary - Binary * @param tag - Tag to use to decode value * @param unpEnt - Implementation of unpackEntry use to decode values * @returns Merkle Patricia Tree */ constructor(binary, encoding, tag, unpEnt) { /** * Retrieve value from Merkle Patricia Tree * @param _key - The key of the element to retrieve * @returns Value associated to the specified key */ _classPrivateMethodInitSpec(this, _MPTree_brand); _classPrivateFieldInitSpec(this, _rootHash, void 0); _classPrivateFieldInitSpec(this, _isComplete, true); _classPrivateFieldInitSpec(this, _nodes, void 0); _classPrivateFieldInitSpec(this, _encoding, void 0); _classPrivateFieldInitSpec(this, _tag, void 0); _classPrivateFieldInitSpec(this, _unpackEntry, void 0); _classPrivateFieldSet(_encoding, this, encoding); _classPrivateFieldSet(_tag, this, tag); _classPrivateFieldSet(_unpackEntry, this, unpEnt); _classPrivateFieldSet(_rootHash, this, binary[0].toString('hex')); _classPrivateFieldSet(_nodes, this, Object.fromEntries(binary[1].map(node => [node[0].toString('hex'), node[1]]))); if (_classPrivateFieldGet(_nodes, this)[_classPrivateFieldGet(_rootHash, this)] == null) { if (Object.keys(_classPrivateFieldGet(_nodes, this)).length !== 0) { throw new MissingNodeInTreeError("Can't find a node by root hash"); } _classPrivateFieldSet(_isComplete, this, false); return; } Object.entries(_classPrivateFieldGet(_nodes, this)).forEach(([key, node]) => { if (_nodeHash.call(MPTree, node) !== key) throw new MerkleTreeHashMismatchError(); const { type } = _parseNode.call(MPTree, node); switch (type) { case NodeType.Branch: node.slice(0, 16).filter(n => n.length).forEach(n => { // TODO: enable after resolving https://github.com/aeternity/aeternity/issues/4066 // if (n.length !== 32) { // throw new ArgumentError('MPTree branch item length', 32, n.length); // } if (_classPrivateFieldGet(_nodes, this)[n.toString('hex')] == null) _classPrivateFieldSet(_isComplete, this, false); }); break; case NodeType.Extension: if (_classPrivateFieldGet(_nodes, this)[node[1].toString('hex')] == null) { throw new MissingNodeInTreeError("Can't find a node by hash in extension node"); } break; case NodeType.Leaf: break; default: throw new InternalError(`Unknown MPTree node type: ${type}`); } }); } isEqual(tree) { return _classPrivateFieldGet(_rootHash, this) === _classPrivateFieldGet(_rootHash, tree); } /** * Serialize Merkle Patricia Tree * @returns Binary */ serialize() { return [_Buffer.from(_classPrivateFieldGet(_rootHash, this), 'hex'), Object.entries(_classPrivateFieldGet(_nodes, this)).map(([mptHash, value]) => [_Buffer.from(mptHash, 'hex'), value])]; } /** * Retrieve value from Merkle Patricia Tree * @param key - The key of the element to retrieve * @returns Value associated to the specified key */ get(key) { const d = _assertClassBrand(_MPTree_brand, this, _getRaw).call(this, decode(key).toString('hex')); if (d == null) return d; return _classPrivateFieldGet(_unpackEntry, this).call(this, encode(d, Encoding.Bytearray), _classPrivateFieldGet(_tag, this)); } toObject() { return Object.fromEntries(_assertClassBrand(_MPTree_brand, this, _entriesRaw).call(this) // TODO: remove after resolving https://github.com/aeternity/aeternity/issues/4066 .filter(([k]) => _classPrivateFieldGet(_encoding, this) !== Encoding.ContractAddress || k.length !== 66).map(([k, v]) => [encode(_Buffer.from(k, 'hex'), _classPrivateFieldGet(_encoding, this)), _classPrivateFieldGet(_unpackEntry, this).call(this, encode(v, Encoding.Bytearray), _classPrivateFieldGet(_tag, this))])); } } _MPTree = MPTree; function _nodeHash(node) { return _Buffer.from(hash(rlpEncode(node))).toString('hex'); } function _parseNode(node) { switch (node.length) { case 17: return { type: NodeType.Branch, ...(node[16].length !== 0 && { value: node[16] }) }; case 2: { const nibble = node[0][0] >> 4; // eslint-disable-line no-bitwise if (nibble > 3) throw new UnknownPathNibbleError(nibble); const type = nibble <= 1 ? NodeType.Extension : NodeType.Leaf; const slice = [0, 2].includes(nibble) ? 2 : 1; return { type, ...(type === NodeType.Leaf && { value: node[1] }), path: node[0].toString('hex').slice(slice) }; } default: throw new UnknownNodeLengthError(node.length); } } function _getRaw(_key) { let searchFrom = _classPrivateFieldGet(_rootHash, this); let key = _key; while (true) { // eslint-disable-line no-constant-condition const node = _classPrivateFieldGet(_nodes, this)[searchFrom]; if (node == null) { if (!this.isComplete) return undefined; throw new InternalError("Can't find node in complete tree"); } const { type, value, path } = _parseNode.call(_MPTree, node); switch (type) { case NodeType.Branch: if (key.length === 0) return value; searchFrom = node[+`0x${key[0]}`].toString('hex'); key = key.substring(1); break; case NodeType.Extension: if (key.substring(0, path?.length) !== path) return undefined; searchFrom = node[1].toString('hex'); key = key.substring(path.length); break; case NodeType.Leaf: if (path !== key) return undefined; return value; default: throw new InternalError(`Unknown MPTree node type: ${type}`); } } } function _entriesRaw() { const entries = []; const rec = (searchFrom, key) => { const node = _classPrivateFieldGet(_nodes, this)[searchFrom]; if (node == null) { if (!this.isComplete) return; throw new InternalError("Can't find node in complete tree"); } const { type, value, path } = _parseNode.call(_MPTree, node); switch (type) { case NodeType.Branch: node.slice(0, 16).map((t, idx) => [t, idx]).filter(([t]) => t.length).forEach(([t, idx]) => rec(t.toString('hex'), key + idx.toString(16))); if (value != null) entries.push([key, value]); break; case NodeType.Extension: rec(node[1].toString('hex'), key + path); break; case NodeType.Leaf: if (value == null) throw new UnexpectedTsError(); entries.push([key + path, value]); break; default: throw new InternalError(`Unknown MPTree node type: ${type}`); } }; rec(_classPrivateFieldGet(_rootHash, this), ''); return entries; } export default function genMPTreeField(encoding, tag) { return { serialize(value) { return value.serialize(); }, deserialize(value, { unpackEntry }) { return new MPTree(value, encoding, tag, unpackEntry); } }; } //# sourceMappingURL=mptree.js.map