@osmura/merkletreejs 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +232 -0
- package/dist/Base.d.ts +212 -0
- package/dist/Base.js +379 -0
- package/dist/IncrementalMerkleTree.d.ts +36 -0
- package/dist/IncrementalMerkleTree.js +252 -0
- package/dist/MerkleMountainRange.d.ts +95 -0
- package/dist/MerkleMountainRange.js +436 -0
- package/dist/MerkleRadixTree.d.ts +33 -0
- package/dist/MerkleRadixTree.js +152 -0
- package/dist/MerkleSumTree.d.ts +37 -0
- package/dist/MerkleSumTree.js +138 -0
- package/dist/MerkleTree.d.ts +570 -0
- package/dist/MerkleTree.js +1326 -0
- package/dist/UnifiedBinaryTree.d.ts +454 -0
- package/dist/UnifiedBinaryTree.js +829 -0
- package/dist/functional.d.ts +255 -0
- package/dist/functional.js +360 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +30 -0
- package/merkletree.js +1 -0
- package/package.json +155 -0
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
/**
|
|
3
|
+
* Type aliases for fixed-length byte sequences used throughout the codebase.
|
|
4
|
+
* These help maintain type safety and clarify the expected byte lengths.
|
|
5
|
+
*/
|
|
6
|
+
export declare type Address = Buffer;
|
|
7
|
+
export declare type Address32 = Buffer;
|
|
8
|
+
export declare type Bytes32 = Buffer;
|
|
9
|
+
/**
|
|
10
|
+
* Constants used for key derivation and tree organization.
|
|
11
|
+
* These define the structure and layout of the binary tree.
|
|
12
|
+
*/
|
|
13
|
+
export declare const BASIC_DATA_LEAF_KEY = 0;
|
|
14
|
+
export declare const CODE_HASH_LEAF_KEY = 1;
|
|
15
|
+
export declare const HEADER_STORAGE_OFFSET = 64;
|
|
16
|
+
export declare const CODE_OFFSET = 128;
|
|
17
|
+
export declare const STEM_SUBTREE_WIDTH = 256;
|
|
18
|
+
export declare const MAIN_STORAGE_OFFSET = 256;
|
|
19
|
+
export declare const pushOffset = 95;
|
|
20
|
+
export declare const push1: number;
|
|
21
|
+
export declare const push32: number;
|
|
22
|
+
/** Function type for hash operations */
|
|
23
|
+
export declare type HashFunction = (data: any) => any;
|
|
24
|
+
/**
|
|
25
|
+
* Converts a 20-byte Ethereum address to a 32-byte address by left-padding with zeros.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* const addr20 = Buffer.from('1234567890123456789012345678901234567890', 'hex')
|
|
30
|
+
* const addr32 = oldStyleAddressToAddress32(addr20)
|
|
31
|
+
* // addr32 = 0x000000000000123456789012345678901234567890 (32 bytes)
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export declare function oldStyleAddressToAddress32(address: Address): Address32;
|
|
35
|
+
/**
|
|
36
|
+
* Applies a hash function to input data with proper buffering.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```typescript
|
|
40
|
+
* const input = Buffer.from('Hello World')
|
|
41
|
+
* const hashFn = (data) => blake3.hash(data)
|
|
42
|
+
* const hash = treeHash(input, hashFn)
|
|
43
|
+
* // hash = 32-byte BLAKE3 hash of 'Hello World'
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export declare function treeHash(input: Buffer, hashFn: HashFunction): Bytes32;
|
|
47
|
+
/**
|
|
48
|
+
* Derives a tree key from an address and indices using a hash function.
|
|
49
|
+
* Used to generate unique keys for different parts of the tree structure.
|
|
50
|
+
* The resulting key is composed of a 31-byte stem (derived from address and treeIndex)
|
|
51
|
+
* and a 1-byte subIndex.
|
|
52
|
+
*
|
|
53
|
+
* @param address - A 32-byte address to derive the key from
|
|
54
|
+
* @param treeIndex - Primary index used to derive different trees for the same address
|
|
55
|
+
* @param subIndex - Secondary index used to derive different keys within the same tree
|
|
56
|
+
* @param hashFn - Hash function to use for key derivation
|
|
57
|
+
* @returns A 32-byte key that uniquely identifies this storage slot
|
|
58
|
+
* @throws Error if address is not 32 bytes
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```typescript
|
|
62
|
+
* const addr32 = oldStyleAddressToAddress32(address)
|
|
63
|
+
* const treeKey = getTreeKey(addr32, 0, 1, blake3.hash)
|
|
64
|
+
* // Returns a unique key for this address's tree at index 0, subIndex 1
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
export declare function getTreeKey(address: Address32, treeIndex: number, subIndex: number, hashFn: HashFunction): Address32;
|
|
68
|
+
/**
|
|
69
|
+
* Derives a key for storing an account's basic data (nonce, balance, etc.).
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```typescript
|
|
73
|
+
* const addr32 = oldStyleAddressToAddress32(address)
|
|
74
|
+
* const basicDataKey = getTreeKeyForBasicData(addr32, hashFn)
|
|
75
|
+
* tree.insert(basicDataKey, accountData)
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
export declare function getTreeKeyForBasicData(address: Address32, hashFn: HashFunction): Address32;
|
|
79
|
+
/**
|
|
80
|
+
* Derives a key for storing a contract's code hash.
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```typescript
|
|
84
|
+
* const addr32 = oldStyleAddressToAddress32(contractAddress)
|
|
85
|
+
* const codeHashKey = getTreeKeyForCodeHash(addr32, hashFn)
|
|
86
|
+
* tree.insert(codeHashKey, codeHash)
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
export declare function getTreeKeyForCodeHash(address: Address32, hashFn: HashFunction): Address32;
|
|
90
|
+
/**
|
|
91
|
+
* Derives a tree key for a storage slot in a contract's storage.
|
|
92
|
+
* Handles two types of storage:
|
|
93
|
+
* 1. Header storage (slots 0-63): Used for contract metadata and special storage
|
|
94
|
+
* 2. Main storage (slots 256+): Used for regular contract storage
|
|
95
|
+
*
|
|
96
|
+
* The storage layout is:
|
|
97
|
+
* - Header storage: slots [0, 63] mapped to positions [64, 127]
|
|
98
|
+
* - Main storage: slots [256+] mapped to positions [384+]
|
|
99
|
+
* This creates gaps in the tree to allow for future extensions.
|
|
100
|
+
*
|
|
101
|
+
* @param address - The 32-byte contract address
|
|
102
|
+
* @param storageKey - The storage slot number to access
|
|
103
|
+
* @param hashFn - Hash function to use for key derivation
|
|
104
|
+
* @returns A 32-byte key that uniquely identifies this storage slot
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```typescript
|
|
108
|
+
* const addr32 = oldStyleAddressToAddress32(contractAddress)
|
|
109
|
+
* // Get key for a header storage slot (0-63)
|
|
110
|
+
* const headerKey = getTreeKeyForStorageSlot(addr32, 5, blake3.hash)
|
|
111
|
+
* // Get key for a main storage slot (256+)
|
|
112
|
+
* const mainKey = getTreeKeyForStorageSlot(addr32, 300, blake3.hash)
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
115
|
+
export declare function getTreeKeyForStorageSlot(address: Address32, storageKey: number, hashFn: HashFunction): Address32;
|
|
116
|
+
/**
|
|
117
|
+
* Derives a key for storing a chunk of contract code.
|
|
118
|
+
* Used when contract code is split into 32-byte chunks.
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* ```typescript
|
|
122
|
+
* const addr32 = oldStyleAddressToAddress32(contractAddress)
|
|
123
|
+
* const chunks = chunkifyCode(contractCode)
|
|
124
|
+
* chunks.forEach((chunk, i) => {
|
|
125
|
+
* const key = getTreeKeyForCodeChunk(addr32, i, hashFn)
|
|
126
|
+
* tree.insert(key, chunk)
|
|
127
|
+
* })
|
|
128
|
+
* ```
|
|
129
|
+
*/
|
|
130
|
+
export declare function getTreeKeyForCodeChunk(address: Address32, chunkId: number, hashFn: HashFunction): Address32;
|
|
131
|
+
/**
|
|
132
|
+
* Splits EVM bytecode into 31-byte chunks with metadata.
|
|
133
|
+
* Each chunk is prefixed with a byte indicating the number of bytes
|
|
134
|
+
* that are part of PUSH data in the next chunk.
|
|
135
|
+
*
|
|
136
|
+
* @example
|
|
137
|
+
* ```typescript
|
|
138
|
+
* const code = Buffer.from('6001600201', 'hex') // PUSH1 01 PUSH1 02 ADD
|
|
139
|
+
* const chunks = chunkifyCode(code)
|
|
140
|
+
* // chunks[0] = [0x01, 0x60, 0x01, 0x60, 0x02, 0x01, 0x00...] (32 bytes)
|
|
141
|
+
* ```
|
|
142
|
+
*/
|
|
143
|
+
export declare function chunkifyCode(code: Buffer): Bytes32[];
|
|
144
|
+
/**
|
|
145
|
+
* Node types in the binary tree.
|
|
146
|
+
* - StemNode: Leaf node containing up to 256 values
|
|
147
|
+
* - InternalNode: Internal node with left and right children
|
|
148
|
+
*/
|
|
149
|
+
export declare type BinaryTreeNode = StemNode | InternalNode;
|
|
150
|
+
/**
|
|
151
|
+
* Leaf node in the binary tree that stores actual values.
|
|
152
|
+
* Contains a 31-byte stem and an array of 256 possible values.
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* ```typescript
|
|
156
|
+
* const stem = Buffer.alloc(31, 0)
|
|
157
|
+
* const node = new StemNode(stem)
|
|
158
|
+
* node.setValue(0, Buffer.alloc(32).fill(1)) // Set value at index 0
|
|
159
|
+
* ```
|
|
160
|
+
*/
|
|
161
|
+
export declare class StemNode {
|
|
162
|
+
stem: Buffer;
|
|
163
|
+
values: Array<Buffer | null>;
|
|
164
|
+
nodeType: 'stem';
|
|
165
|
+
/**
|
|
166
|
+
* Creates a new StemNode with the given stem.
|
|
167
|
+
*
|
|
168
|
+
* @param stem - The 31-byte stem for this node.
|
|
169
|
+
*/
|
|
170
|
+
constructor(stem: Buffer);
|
|
171
|
+
/**
|
|
172
|
+
* Sets the value at the given index.
|
|
173
|
+
*
|
|
174
|
+
* @param index - The index to set the value at.
|
|
175
|
+
* @param value - The 32-byte value to set.
|
|
176
|
+
*/
|
|
177
|
+
setValue(index: number, value: Buffer): void;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Internal node in the binary tree with left and right children.
|
|
181
|
+
* Used to create the tree structure based on key bit patterns.
|
|
182
|
+
*
|
|
183
|
+
* @example
|
|
184
|
+
* ```typescript
|
|
185
|
+
* const node = new InternalNode()
|
|
186
|
+
* node.left = new StemNode(Buffer.alloc(31, 0))
|
|
187
|
+
* node.right = new StemNode(Buffer.alloc(31, 1))
|
|
188
|
+
* ```
|
|
189
|
+
*/
|
|
190
|
+
export declare class InternalNode {
|
|
191
|
+
left: BinaryTreeNode | null;
|
|
192
|
+
right: BinaryTreeNode | null;
|
|
193
|
+
nodeType: 'internal';
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Main binary tree implementation that stores key-value pairs.
|
|
197
|
+
* Uses a configurable hash function and supports various operations.
|
|
198
|
+
*
|
|
199
|
+
* @example
|
|
200
|
+
* ```typescript
|
|
201
|
+
* const tree = new BinaryTree(blake3.hash)
|
|
202
|
+
* tree.insert(key, value)
|
|
203
|
+
* const root = tree.merkelize()
|
|
204
|
+
* const serialized = tree.serialize()
|
|
205
|
+
* ```
|
|
206
|
+
*/
|
|
207
|
+
export declare class UnifiedBinaryTree {
|
|
208
|
+
root: BinaryTreeNode | null;
|
|
209
|
+
hashFn: HashFunction;
|
|
210
|
+
/**
|
|
211
|
+
* Creates a new BinaryTree instance with the given hash function.
|
|
212
|
+
*
|
|
213
|
+
* @param hashFn - The hash function to use for key derivation.
|
|
214
|
+
*/
|
|
215
|
+
constructor(hashFn: HashFunction);
|
|
216
|
+
/**
|
|
217
|
+
* Inserts a key-value pair into the binary tree.
|
|
218
|
+
* The key is split into two parts:
|
|
219
|
+
* - stem (first 31 bytes): Determines the path in the tree
|
|
220
|
+
* - subIndex (last byte): Determines the position within a leaf node
|
|
221
|
+
*
|
|
222
|
+
* If this is the first insertion, creates a new leaf node.
|
|
223
|
+
* Otherwise, recursively traverses or builds the tree structure.
|
|
224
|
+
*
|
|
225
|
+
* @param key - A 32-byte key that determines where to store the value
|
|
226
|
+
* @param value - A 32-byte value to store
|
|
227
|
+
* @throws Error if key or value is not exactly 32 bytes
|
|
228
|
+
*
|
|
229
|
+
* @example
|
|
230
|
+
* ```typescript
|
|
231
|
+
* const tree = new BinaryTree(hashFn)
|
|
232
|
+
* const key = getTreeKey(address, 0, 1, hashFn)
|
|
233
|
+
* const value = Buffer.alloc(32).fill(1)
|
|
234
|
+
* tree.insert(key, value)
|
|
235
|
+
* ```
|
|
236
|
+
*/
|
|
237
|
+
insert(key: Buffer, value: Buffer): void;
|
|
238
|
+
/**
|
|
239
|
+
* Recursively inserts a key-value pair into the tree.
|
|
240
|
+
* This method handles three cases:
|
|
241
|
+
* 1. Empty node: Creates a new leaf node
|
|
242
|
+
* 2. Stem node: Either updates value or splits into internal node
|
|
243
|
+
* 3. Internal node: Recursively traverses left or right based on stem bits
|
|
244
|
+
*
|
|
245
|
+
* @param node - Current node in traversal (null if empty)
|
|
246
|
+
* @param stem - The 31-byte path component of the key
|
|
247
|
+
* @param subIndex - The leaf position component of the key
|
|
248
|
+
* @param value - The 32-byte value to store
|
|
249
|
+
* @param depth - Current depth in the tree (max 247 to prevent hash collisions)
|
|
250
|
+
* @returns The new or updated node
|
|
251
|
+
* @throws Error if tree depth exceeds 247 levels
|
|
252
|
+
*/
|
|
253
|
+
private insertRecursive;
|
|
254
|
+
/**
|
|
255
|
+
* Converts a byte array to an array of individual bits.
|
|
256
|
+
* Each byte is converted to 8 bits, maintaining the most-significant-bit first order.
|
|
257
|
+
* Used for making path decisions in the binary tree based on stem bytes.
|
|
258
|
+
*
|
|
259
|
+
* @param data - Buffer containing bytes to convert
|
|
260
|
+
* @returns Array of bits (0s and 1s) in MSB-first order
|
|
261
|
+
*
|
|
262
|
+
* @example
|
|
263
|
+
* ```typescript
|
|
264
|
+
* const bytes = Buffer.from([0xA5]) // Binary: 10100101
|
|
265
|
+
* const bits = bytesToBits(bytes)
|
|
266
|
+
* // bits = [1,0,1,0,0,1,0,1]
|
|
267
|
+
* // ^ MSB LSB ^
|
|
268
|
+
* ```
|
|
269
|
+
*
|
|
270
|
+
* Process for each byte:
|
|
271
|
+
* 1. Right shift by (7-i) positions to get desired bit to LSB
|
|
272
|
+
* 2. AND with 1 to isolate that bit
|
|
273
|
+
* 3. Push result (0 or 1) to output array
|
|
274
|
+
*/
|
|
275
|
+
private bytesToBits;
|
|
276
|
+
/**
|
|
277
|
+
* Converts an array of bits back into a Buffer of bytes.
|
|
278
|
+
* This is the inverse operation of bytesToBits.
|
|
279
|
+
* Processes bits in groups of 8, maintaining MSB-first order.
|
|
280
|
+
*
|
|
281
|
+
* @param bits - Array of 0s and 1s to convert to bytes
|
|
282
|
+
* @returns Buffer containing the reconstructed bytes
|
|
283
|
+
* @throws Error if the number of bits is not divisible by 8
|
|
284
|
+
*
|
|
285
|
+
* @example
|
|
286
|
+
* ```typescript
|
|
287
|
+
* const bits = [1,0,1,0,0,1,0,1] // Represents binary 10100101
|
|
288
|
+
* const bytes = bitsToBytes(bits)
|
|
289
|
+
* // bytes = Buffer.from([0xA5])
|
|
290
|
+
* ```
|
|
291
|
+
*
|
|
292
|
+
* Process for each byte:
|
|
293
|
+
* 1. Take 8 bits at a time
|
|
294
|
+
* 2. For each bit:
|
|
295
|
+
* - Shift it left to its correct position (7-j positions)
|
|
296
|
+
* - OR it with the accumulating byte value
|
|
297
|
+
* 3. Add completed byte to array
|
|
298
|
+
*/
|
|
299
|
+
private bitsToBytes;
|
|
300
|
+
/**
|
|
301
|
+
* Applies the hash function to the given data with special handling for null values.
|
|
302
|
+
* Used primarily for Merkle tree calculations and node hashing.
|
|
303
|
+
*
|
|
304
|
+
* Special cases:
|
|
305
|
+
* - null input -> returns 32-byte zero buffer
|
|
306
|
+
* - 64-byte zero buffer -> returns 32-byte zero buffer
|
|
307
|
+
* This handling ensures consistent treatment of empty/uninitialized nodes.
|
|
308
|
+
*
|
|
309
|
+
* @param data - Buffer to hash, must be either 32 or 64 bytes, or null
|
|
310
|
+
* @returns A 32-byte hash of the data, or zero32 for empty cases
|
|
311
|
+
* @throws Error if data length is not 32 or 64 bytes
|
|
312
|
+
*
|
|
313
|
+
* @example
|
|
314
|
+
* ```typescript
|
|
315
|
+
* // Regular hashing
|
|
316
|
+
* const hash1 = hashData(nodeBuffer) // Returns hash of data
|
|
317
|
+
*
|
|
318
|
+
* // Empty cases - all return 32 zeros
|
|
319
|
+
* const hash2 = hashData(null)
|
|
320
|
+
* const hash3 = hashData(Buffer.alloc(64, 0))
|
|
321
|
+
* ```
|
|
322
|
+
*/
|
|
323
|
+
private hashData;
|
|
324
|
+
/**
|
|
325
|
+
* Computes the Merkle root of the entire tree.
|
|
326
|
+
* The Merkle root is a single 32-byte hash that uniquely represents the entire tree state.
|
|
327
|
+
*
|
|
328
|
+
* The computation follows these rules:
|
|
329
|
+
* 1. For Internal nodes: hash(leftChild || rightChild)
|
|
330
|
+
* 2. For Stem nodes: hash(stem || 0x00 || merkleOfValues)
|
|
331
|
+
* 3. For empty nodes: return 32 bytes of zeros
|
|
332
|
+
*
|
|
333
|
+
* @returns A 32-byte Buffer containing the Merkle root
|
|
334
|
+
*
|
|
335
|
+
* @example
|
|
336
|
+
* ```typescript
|
|
337
|
+
* const tree = new BinaryTree(hashFn)
|
|
338
|
+
* tree.insert(key1, value1)
|
|
339
|
+
* tree.insert(key2, value2)
|
|
340
|
+
* const root = tree.merkelize()
|
|
341
|
+
* // root now contains a 32-byte hash representing the entire tree
|
|
342
|
+
* ```
|
|
343
|
+
*/
|
|
344
|
+
merkelize(): Buffer;
|
|
345
|
+
/**
|
|
346
|
+
* Incrementally updates the value for an existing key.
|
|
347
|
+
* For our implementation, update is the same as insert.
|
|
348
|
+
*
|
|
349
|
+
* @param key - A 32-byte key.
|
|
350
|
+
* @param value - A 32-byte value.
|
|
351
|
+
*/
|
|
352
|
+
update(key: Buffer, value: Buffer): void;
|
|
353
|
+
/**
|
|
354
|
+
* Performs a batch insertion of key-value pairs.
|
|
355
|
+
*
|
|
356
|
+
* @param entries - An array of objects with 'key' and 'value' properties.
|
|
357
|
+
*/
|
|
358
|
+
insertBatch(entries: {
|
|
359
|
+
key: Buffer;
|
|
360
|
+
value: Buffer;
|
|
361
|
+
}[]): void;
|
|
362
|
+
/**
|
|
363
|
+
* Serializes the entire tree structure into a JSON Buffer.
|
|
364
|
+
* Converts the tree into a format that can be stored or transmitted,
|
|
365
|
+
* preserving the complete structure and all values.
|
|
366
|
+
*
|
|
367
|
+
* The serialized format for each node type is:
|
|
368
|
+
* 1. Stem Node:
|
|
369
|
+
* ```json
|
|
370
|
+
* {
|
|
371
|
+
* "nodeType": "stem",
|
|
372
|
+
* "stem": "hex string of 31 bytes",
|
|
373
|
+
* "values": ["hex string or null", ...] // 256 entries
|
|
374
|
+
* }
|
|
375
|
+
* ```
|
|
376
|
+
* 2. Internal Node:
|
|
377
|
+
* ```json
|
|
378
|
+
* {
|
|
379
|
+
* "nodeType": "internal",
|
|
380
|
+
* "left": <node or null>,
|
|
381
|
+
* "right": <node or null>
|
|
382
|
+
* }
|
|
383
|
+
* ```
|
|
384
|
+
*
|
|
385
|
+
* @returns Buffer containing the JSON string representation of the tree
|
|
386
|
+
*
|
|
387
|
+
* @example
|
|
388
|
+
* ```typescript
|
|
389
|
+
* const tree = new BinaryTree(hashFn)
|
|
390
|
+
* tree.insert(key, value)
|
|
391
|
+
* const serialized = tree.serialize()
|
|
392
|
+
* // Save to file or transmit
|
|
393
|
+
* const newTree = UnifiedBinaryTree.deserialize(serialized, hashFn)
|
|
394
|
+
* ```
|
|
395
|
+
*/
|
|
396
|
+
serialize(): Buffer;
|
|
397
|
+
/**
|
|
398
|
+
* Reconstructs a BinaryTree from its serialized form.
|
|
399
|
+
* This is the inverse operation of serialize().
|
|
400
|
+
*
|
|
401
|
+
* Expected input format:
|
|
402
|
+
* ```json
|
|
403
|
+
* {
|
|
404
|
+
* "root": {
|
|
405
|
+
* "nodeType": "internal"|"stem",
|
|
406
|
+
* // For stem nodes:
|
|
407
|
+
* "stem": "hex string",
|
|
408
|
+
* "values": ["hex string"|null, ...],
|
|
409
|
+
* // For internal nodes:
|
|
410
|
+
* "left": <node|null>,
|
|
411
|
+
* "right": <node|null>
|
|
412
|
+
* }
|
|
413
|
+
* }
|
|
414
|
+
* ```
|
|
415
|
+
*
|
|
416
|
+
* @param data - Buffer containing the JSON serialized tree
|
|
417
|
+
* @param hashFn - Hash function to use for the reconstructed tree
|
|
418
|
+
* @returns A new BinaryTree instance with the deserialized structure
|
|
419
|
+
* @throws Error if JSON parsing fails or format is invalid
|
|
420
|
+
*
|
|
421
|
+
* @example
|
|
422
|
+
* ```typescript
|
|
423
|
+
* const serialized = existingTree.serialize()
|
|
424
|
+
* const newTree = UnifiedBinaryTree.deserialize(serialized, hashFn)
|
|
425
|
+
* // newTree is now identical to existingTree
|
|
426
|
+
* ```
|
|
427
|
+
*/
|
|
428
|
+
static deserialize(data: Buffer, hashFn: HashFunction): UnifiedBinaryTree;
|
|
429
|
+
/**
|
|
430
|
+
* Splits a leaf node when inserting a new key with a different stem.
|
|
431
|
+
* This method handles two cases:
|
|
432
|
+
* 1. Matching bits at current depth: Continue splitting recursively
|
|
433
|
+
* 2. Different bits at current depth: Create new internal node and arrange leaves
|
|
434
|
+
*
|
|
435
|
+
* The process ensures that keys with different stems are properly distributed
|
|
436
|
+
* in the tree based on their binary representation.
|
|
437
|
+
*
|
|
438
|
+
* @param leaf - The existing leaf node to split
|
|
439
|
+
* @param stemBits - Binary representation of the new stem
|
|
440
|
+
* @param existingStemBits - Binary representation of the existing stem
|
|
441
|
+
* @param subIndex - Position within leaf node for new value
|
|
442
|
+
* @param value - Value to store at the new position
|
|
443
|
+
* @param depth - Current depth in the tree
|
|
444
|
+
* @returns A new internal node containing both the existing and new data
|
|
445
|
+
*
|
|
446
|
+
* Example:
|
|
447
|
+
* If stems differ at bit 3:
|
|
448
|
+
* - New stem: [1,0,1,0,...]
|
|
449
|
+
* - Existing stem: [1,0,1,1,...]
|
|
450
|
+
* ^ split here
|
|
451
|
+
* Creates an internal node with the leaf nodes arranged based on bit 3
|
|
452
|
+
*/
|
|
453
|
+
private splitLeaf;
|
|
454
|
+
}
|