|
1 |
| -import {getNodesAtDepth, Node, packedNodeRootsToBytes, packedRootsBytesToNode} from "@chainsafe/persistent-merkle-tree"; |
2 |
| -import {mixInLength, maxChunksToDepth} from "../util/merkleize.js"; |
| 1 | +import { |
| 2 | + getNodesAtDepth, |
| 3 | + Node, |
| 4 | + packedNodeRootsToBytes, |
| 5 | + packedRootsBytesToNode, |
| 6 | + merkleizeBlocksBytes, |
| 7 | + merkleizeBlockArray, |
| 8 | +} from "@chainsafe/persistent-merkle-tree"; |
| 9 | +import {allocUnsafe} from "@chainsafe/as-sha256"; |
| 10 | +import {maxChunksToDepth} from "../util/merkleize.js"; |
3 | 11 | import {Require} from "../util/types.js";
|
4 | 12 | import {namedClass} from "../util/named.js";
|
5 | 13 | import {addLengthNode, getChunksNodeFromRootNode, getLengthFromRootNode} from "./arrayBasic.js";
|
6 | 14 | import {ByteViews} from "./composite.js";
|
7 | 15 | import {ByteArrayType, ByteArray} from "./byteArray.js";
|
8 |
| - |
9 | 16 | /* eslint-disable @typescript-eslint/member-ordering */
|
10 | 17 |
|
11 | 18 | export interface ByteListOptions {
|
@@ -34,6 +41,14 @@ export class ByteListType extends ByteArrayType {
|
34 | 41 | readonly maxSize: number;
|
35 | 42 | readonly maxChunkCount: number;
|
36 | 43 | readonly isList = true;
|
| 44 | + readonly blockArray: Uint8Array[] = []; |
| 45 | + private blockBytesLen = 0; |
| 46 | + readonly mixInLengthBlockBytes = new Uint8Array(64); |
| 47 | + readonly mixInLengthBuffer = Buffer.from( |
| 48 | + this.mixInLengthBlockBytes.buffer, |
| 49 | + this.mixInLengthBlockBytes.byteOffset, |
| 50 | + this.mixInLengthBlockBytes.byteLength |
| 51 | + ); |
37 | 52 |
|
38 | 53 | constructor(readonly limitBytes: number, opts?: ByteListOptions) {
|
39 | 54 | super();
|
@@ -89,7 +104,49 @@ export class ByteListType extends ByteArrayType {
|
89 | 104 | // Merkleization: inherited from ByteArrayType
|
90 | 105 |
|
91 | 106 | hashTreeRoot(value: ByteArray): Uint8Array {
|
92 |
| - return mixInLength(super.hashTreeRoot(value), value.length); |
| 107 | + const root = allocUnsafe(32); |
| 108 | + this.hashTreeRootInto(value, root, 0); |
| 109 | + return root; |
| 110 | + } |
| 111 | + |
| 112 | + /** |
| 113 | + * Use merkleizeBlockArray() instead of merkleizeBlocksBytes() to avoid big memory allocation |
| 114 | + */ |
| 115 | + hashTreeRootInto(value: Uint8Array, output: Uint8Array, offset: number): void { |
| 116 | + // should not call super.hashTreeRoot() here |
| 117 | + // use merkleizeBlockArray() instead of merkleizeBlocksBytes() to avoid big memory allocation |
| 118 | + // reallocate this.blockArray if needed |
| 119 | + if (value.length > this.blockBytesLen) { |
| 120 | + const newBlockCount = Math.ceil(value.length / 64); |
| 121 | + // this.blockBytesLen should be a multiple of 64 |
| 122 | + const oldBlockCount = Math.ceil(this.blockBytesLen / 64); |
| 123 | + const blockDiff = newBlockCount - oldBlockCount; |
| 124 | + const newBlocksBytes = new Uint8Array(blockDiff * 64); |
| 125 | + for (let i = 0; i < blockDiff; i++) { |
| 126 | + this.blockArray.push(newBlocksBytes.subarray(i * 64, (i + 1) * 64)); |
| 127 | + this.blockBytesLen += 64; |
| 128 | + } |
| 129 | + } |
| 130 | + |
| 131 | + // populate this.blockArray |
| 132 | + for (let i = 0; i < value.length; i += 64) { |
| 133 | + const block = this.blockArray[i / 64]; |
| 134 | + // zero out the last block if it's over value.length |
| 135 | + if (i + 64 > value.length) { |
| 136 | + block.fill(0); |
| 137 | + } |
| 138 | + block.set(value.subarray(i, Math.min(i + 64, value.length))); |
| 139 | + } |
| 140 | + |
| 141 | + // compute hashTreeRoot |
| 142 | + const blockLimit = Math.ceil(value.length / 64); |
| 143 | + merkleizeBlockArray(this.blockArray, blockLimit, this.maxChunkCount, this.mixInLengthBlockBytes, 0); |
| 144 | + |
| 145 | + // mixInLength |
| 146 | + this.mixInLengthBuffer.writeUIntLE(value.length, 32, 6); |
| 147 | + // one for hashTreeRoot(value), one for length |
| 148 | + const chunkCount = 2; |
| 149 | + merkleizeBlocksBytes(this.mixInLengthBlockBytes, chunkCount, output, offset); |
93 | 150 | }
|
94 | 151 |
|
95 | 152 | // Proofs: inherited from BitArrayType
|
|
0 commit comments