1 | "use strict";
|
2 | var __importDefault = (this && this.__importDefault) || function (mod) {
|
3 | return (mod && mod.__esModule) ? mod : { "default": mod };
|
4 | };
|
5 | Object.defineProperty(exports, "__esModule", { value: true });
|
6 | exports.SHAMap = exports.Leaf = exports.InnerNode = exports.Node = exports.NodeType = void 0;
|
7 | const hash_prefix_1 = __importDefault(require("./hash-prefix"));
|
8 | const sha512Half_1 = __importDefault(require("./sha512Half"));
|
9 | const HEX_ZERO = '0000000000000000000000000000000000000000000000000000000000000000';
|
10 | var NodeType;
|
11 | (function (NodeType) {
|
12 | NodeType[NodeType["INNER"] = 1] = "INNER";
|
13 | NodeType[NodeType["TRANSACTION_NO_METADATA"] = 2] = "TRANSACTION_NO_METADATA";
|
14 | NodeType[NodeType["TRANSACTION_METADATA"] = 3] = "TRANSACTION_METADATA";
|
15 | NodeType[NodeType["ACCOUNT_STATE"] = 4] = "ACCOUNT_STATE";
|
16 | })(NodeType = exports.NodeType || (exports.NodeType = {}));
|
17 | class Node {
|
18 | constructor() { }
|
19 | addItem(_tag, _node) {
|
20 | throw new Error('Called unimplemented virtual method SHAMapTreeNode#addItem.');
|
21 | }
|
22 | get hash() {
|
23 | throw new Error('Called unimplemented virtual method SHAMapTreeNode#hash.');
|
24 | }
|
25 | }
|
26 | exports.Node = Node;
|
27 | class InnerNode extends Node {
|
28 | constructor(depth = 0) {
|
29 | super();
|
30 | this.leaves = {};
|
31 | this.type = NodeType.INNER;
|
32 | this.depth = depth;
|
33 | this.empty = true;
|
34 | }
|
35 | addItem(tag, node) {
|
36 | const existingNode = this.getNode(parseInt(tag[this.depth], 16));
|
37 | if (existingNode) {
|
38 | if (existingNode instanceof InnerNode) {
|
39 | existingNode.addItem(tag, node);
|
40 | }
|
41 | else if (existingNode instanceof Leaf) {
|
42 | if (existingNode.tag === tag) {
|
43 | throw new Error('Tried to add a node to a SHAMap that was already in there.');
|
44 | }
|
45 | else {
|
46 | const newInnerNode = new InnerNode(this.depth + 1);
|
47 | newInnerNode.addItem(existingNode.tag, existingNode);
|
48 | newInnerNode.addItem(tag, node);
|
49 | this.setNode(parseInt(tag[this.depth], 16), newInnerNode);
|
50 | }
|
51 | }
|
52 | }
|
53 | else {
|
54 | this.setNode(parseInt(tag[this.depth], 16), node);
|
55 | }
|
56 | }
|
57 | setNode(slot, node) {
|
58 | if (slot < 0 || slot > 15) {
|
59 | throw new Error('Invalid slot: slot must be between 0-15.');
|
60 | }
|
61 | this.leaves[slot] = node;
|
62 | this.empty = false;
|
63 | }
|
64 | getNode(slot) {
|
65 | if (slot < 0 || slot > 15) {
|
66 | throw new Error('Invalid slot: slot must be between 0-15.');
|
67 | }
|
68 | return this.leaves[slot];
|
69 | }
|
70 | get hash() {
|
71 | if (this.empty)
|
72 | return HEX_ZERO;
|
73 | let hex = '';
|
74 | for (let i = 0; i < 16; i++) {
|
75 | hex += this.leaves[i] ? this.leaves[i].hash : HEX_ZERO;
|
76 | }
|
77 | const prefix = hash_prefix_1.default.INNER_NODE.toString(16);
|
78 | return sha512Half_1.default(prefix + hex);
|
79 | }
|
80 | }
|
81 | exports.InnerNode = InnerNode;
|
82 | class Leaf extends Node {
|
83 | constructor(tag, data, type) {
|
84 | super();
|
85 | this.tag = tag;
|
86 | this.type = type;
|
87 | this.data = data;
|
88 | }
|
89 | get hash() {
|
90 | switch (this.type) {
|
91 | case NodeType.ACCOUNT_STATE: {
|
92 | const leafPrefix = hash_prefix_1.default.LEAF_NODE.toString(16);
|
93 | return sha512Half_1.default(leafPrefix + this.data + this.tag);
|
94 | }
|
95 | case NodeType.TRANSACTION_NO_METADATA: {
|
96 | const txIDPrefix = hash_prefix_1.default.TRANSACTION_ID.toString(16);
|
97 | return sha512Half_1.default(txIDPrefix + this.data);
|
98 | }
|
99 | case NodeType.TRANSACTION_METADATA: {
|
100 | const txNodePrefix = hash_prefix_1.default.TRANSACTION_NODE.toString(16);
|
101 | return sha512Half_1.default(txNodePrefix + this.data + this.tag);
|
102 | }
|
103 | default:
|
104 | throw new Error('Tried to hash a SHAMap node of unknown type.');
|
105 | }
|
106 | }
|
107 | }
|
108 | exports.Leaf = Leaf;
|
109 | class SHAMap {
|
110 | constructor() {
|
111 | this.root = new InnerNode(0);
|
112 | }
|
113 | addItem(tag, data, type) {
|
114 | this.root.addItem(tag, new Leaf(tag, data, type));
|
115 | }
|
116 | get hash() {
|
117 | return this.root.hash;
|
118 | }
|
119 | }
|
120 | exports.SHAMap = SHAMap;
|
121 |
|
\ | No newline at end of file |