@forestrie/merklelog 0.0.1
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 +83 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/massifs/indexformat.d.ts +146 -0
- package/dist/massifs/indexformat.d.ts.map +1 -0
- package/dist/massifs/indexformat.js +191 -0
- package/dist/massifs/logformat.d.ts +49 -0
- package/dist/massifs/logformat.d.ts.map +1 -0
- package/dist/massifs/logformat.js +49 -0
- package/dist/massifs/massif.d.ts +86 -0
- package/dist/massifs/massif.d.ts.map +1 -0
- package/dist/massifs/massif.js +143 -0
- package/dist/massifs/massiffull.d.ts +14 -0
- package/dist/massifs/massiffull.d.ts.map +1 -0
- package/dist/massifs/massiffull.js +21 -0
- package/dist/massifs/massiflogentries.d.ts +23 -0
- package/dist/massifs/massiflogentries.d.ts.map +1 -0
- package/dist/massifs/massiflogentries.js +31 -0
- package/dist/massifs/massifstart.d.ts +63 -0
- package/dist/massifs/massifstart.d.ts.map +1 -0
- package/dist/massifs/massifstart.js +39 -0
- package/dist/massifs/mmrindex.d.ts +15 -0
- package/dist/massifs/mmrindex.d.ts.map +1 -0
- package/dist/massifs/mmrindex.js +24 -0
- package/dist/massifs/peakstackend.d.ts +21 -0
- package/dist/massifs/peakstackend.d.ts.map +1 -0
- package/dist/massifs/peakstackend.js +29 -0
- package/dist/massifs/types.d.ts +20 -0
- package/dist/massifs/types.d.ts.map +1 -0
- package/dist/massifs/types.js +23 -0
- package/dist/massifs/urkleindex.d.ts +116 -0
- package/dist/massifs/urkleindex.d.ts.map +1 -0
- package/dist/massifs/urkleindex.js +169 -0
- package/dist/massifs/v2storagepaths.d.ts +17 -0
- package/dist/massifs/v2storagepaths.d.ts.map +1 -0
- package/dist/massifs/v2storagepaths.js +46 -0
- package/dist/mmr/algorithms-sync.d.ts +17 -0
- package/dist/mmr/algorithms-sync.d.ts.map +1 -0
- package/dist/mmr/algorithms-sync.js +42 -0
- package/dist/mmr/algorithms.d.ts +79 -0
- package/dist/mmr/algorithms.d.ts.map +1 -0
- package/dist/mmr/algorithms.js +155 -0
- package/dist/mmr/index.d.ts +37 -0
- package/dist/mmr/index.d.ts.map +1 -0
- package/dist/mmr/index.js +64 -0
- package/dist/mmr/math.d.ts +67 -0
- package/dist/mmr/math.d.ts.map +1 -0
- package/dist/mmr/math.js +172 -0
- package/dist/mmr/types.d.ts +37 -0
- package/dist/mmr/types.d.ts.map +1 -0
- package/dist/mmr/types.js +4 -0
- package/dist/uint64/index.d.ts +90 -0
- package/dist/uint64/index.d.ts.map +1 -0
- package/dist/uint64/index.js +149 -0
- package/dist/utils/arrays.d.ts +15 -0
- package/dist/utils/arrays.d.ts.map +1 -0
- package/dist/utils/arrays.js +24 -0
- package/package.json +41 -0
- package/src/index.ts +68 -0
- package/src/massifs/indexformat.ts +217 -0
- package/src/massifs/logformat.ts +54 -0
- package/src/massifs/massif.ts +182 -0
- package/src/massifs/massiffull.ts +28 -0
- package/src/massifs/massiflogentries.ts +40 -0
- package/src/massifs/massifstart.ts +67 -0
- package/src/massifs/mmrindex.ts +32 -0
- package/src/massifs/peakstackend.ts +34 -0
- package/src/massifs/types.ts +55 -0
- package/src/massifs/urkleindex.ts +273 -0
- package/src/massifs/v2storagepaths.ts +61 -0
- package/src/mmr/algorithms-sync.ts +46 -0
- package/src/mmr/algorithms.ts +194 -0
- package/src/mmr/index.ts +75 -0
- package/src/mmr/math.ts +190 -0
- package/src/mmr/types.ts +39 -0
- package/src/uint64/index.ts +164 -0
- package/src/utils/arrays.ts +25 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type { MassifStart } from "./massifstart.js";
|
|
2
|
+
/**
|
|
3
|
+
* Massif - Efficient buffer-based access to massif data
|
|
4
|
+
*
|
|
5
|
+
* Provides efficient access to massif start data based on a view of an
|
|
6
|
+
* in-memory buffer which holds the data. All operations work directly with
|
|
7
|
+
* the buffer without copying.
|
|
8
|
+
*/
|
|
9
|
+
export declare class Massif {
|
|
10
|
+
private readonly buffer;
|
|
11
|
+
/**
|
|
12
|
+
* Creates a new Massif instance from buffer data
|
|
13
|
+
* @param data - The massif data as ArrayBuffer, Uint8Array, or Buffer
|
|
14
|
+
*/
|
|
15
|
+
constructor(data: ArrayBuffer | Uint8Array | Buffer | {
|
|
16
|
+
buffer: ArrayBuffer;
|
|
17
|
+
byteOffset: number;
|
|
18
|
+
byteLength: number;
|
|
19
|
+
});
|
|
20
|
+
/**
|
|
21
|
+
* Returns a MassifStart instance populated by reading directly from the buffer
|
|
22
|
+
*
|
|
23
|
+
* Computes firstIndex using massif height and index (calls MMR function)
|
|
24
|
+
* Computes peakStackLen using massif index (calls MMR function)
|
|
25
|
+
*/
|
|
26
|
+
getStart(): MassifStart;
|
|
27
|
+
/**
|
|
28
|
+
* Returns a buffer view of the corresponding field at zero-based index
|
|
29
|
+
*
|
|
30
|
+
* Each field is 32 bytes (LogFormat.ValueBytes). Zero-based indexing, without regard
|
|
31
|
+
* to peakstack or trieindex structure.
|
|
32
|
+
*
|
|
33
|
+
* @param index - Zero-based field index (Number or BigInt)
|
|
34
|
+
* @param count - Number of consecutive fields to include in the view (defaults to 1)
|
|
35
|
+
* @returns Uint8Array view of the field(s) (32 bytes per field)
|
|
36
|
+
*/
|
|
37
|
+
fieldref(index: number | bigint, count?: number): Uint8Array;
|
|
38
|
+
/**
|
|
39
|
+
* Reads bytes from the buffer at the specified offset
|
|
40
|
+
*
|
|
41
|
+
* Returns a view of the buffer without copying. Efficient for reading
|
|
42
|
+
* arbitrary byte ranges that may span multiple 32-byte fields.
|
|
43
|
+
*
|
|
44
|
+
* @param offset - Byte offset into the buffer
|
|
45
|
+
* @param length - Number of bytes to read
|
|
46
|
+
* @returns Uint8Array view of the requested bytes
|
|
47
|
+
*/
|
|
48
|
+
readBytes(offset: number, length: number): Uint8Array;
|
|
49
|
+
/**
|
|
50
|
+
* Reads a big-endian uint64 from the buffer
|
|
51
|
+
*/
|
|
52
|
+
private readUint64BE;
|
|
53
|
+
/**
|
|
54
|
+
* Reads a big-endian uint32 from the buffer
|
|
55
|
+
*/
|
|
56
|
+
private readUint32BE;
|
|
57
|
+
/**
|
|
58
|
+
* Reads a big-endian uint16 from the buffer
|
|
59
|
+
*/
|
|
60
|
+
private readUint16BE;
|
|
61
|
+
/**
|
|
62
|
+
* Reserved field (bytes 0-7)
|
|
63
|
+
*/
|
|
64
|
+
get reserved(): bigint;
|
|
65
|
+
/**
|
|
66
|
+
* Last ID timestamp (bytes 8-15)
|
|
67
|
+
*/
|
|
68
|
+
get lastID(): bigint;
|
|
69
|
+
/**
|
|
70
|
+
* Version (bytes 21-22)
|
|
71
|
+
*/
|
|
72
|
+
get version(): number;
|
|
73
|
+
/**
|
|
74
|
+
* Commitment epoch (bytes 23-26)
|
|
75
|
+
*/
|
|
76
|
+
get commitmentEpoch(): number;
|
|
77
|
+
/**
|
|
78
|
+
* Massif height (byte 27)
|
|
79
|
+
*/
|
|
80
|
+
get massifHeight(): number;
|
|
81
|
+
/**
|
|
82
|
+
* Massif index (bytes 28-31)
|
|
83
|
+
*/
|
|
84
|
+
get massifIndex(): number;
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=massif.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"massif.d.ts","sourceRoot":"","sources":["../../src/massifs/massif.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAKpD;;;;;;GAMG;AACH,qBAAa,MAAM;IACjB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAa;IAEpC;;;OAGG;gBAED,IAAI,EACA,WAAW,GACX,UAAU,GACV,MAAM,GACN;QAAE,MAAM,EAAE,WAAW,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE;IAsBrE;;;;;OAKG;IACH,QAAQ,IAAI,WAAW;IAsBvB;;;;;;;;;OASG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,GAAE,MAAU,GAAG,UAAU;IAM/D;;;;;;;;;OASG;IACH,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU;IAIrD;;OAEG;IACH,OAAO,CAAC,YAAY;IASpB;;OAEG;IACH,OAAO,CAAC,YAAY;IASpB;;OAEG;IACH,OAAO,CAAC,YAAY;IASpB;;OAEG;IACH,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED;;OAEG;IACH,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED;;OAEG;IACH,IAAI,OAAO,IAAI,MAAM,CAEpB;IAED;;OAEG;IACH,IAAI,eAAe,IAAI,MAAM,CAE5B;IAED;;OAEG;IACH,IAAI,YAAY,IAAI,MAAM,CAEzB;IAED;;OAEG;IACH,IAAI,WAAW,IAAI,MAAM,CAExB;CACF"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { MassifStartFmt } from "./massifstart.js";
|
|
2
|
+
import { LogFormat } from "./logformat.js";
|
|
3
|
+
import { massifFirstLeaf, leafMinusSpurSum } from "../mmr/index.js";
|
|
4
|
+
/**
|
|
5
|
+
* Massif - Efficient buffer-based access to massif data
|
|
6
|
+
*
|
|
7
|
+
* Provides efficient access to massif start data based on a view of an
|
|
8
|
+
* in-memory buffer which holds the data. All operations work directly with
|
|
9
|
+
* the buffer without copying.
|
|
10
|
+
*/
|
|
11
|
+
export class Massif {
|
|
12
|
+
buffer;
|
|
13
|
+
/**
|
|
14
|
+
* Creates a new Massif instance from buffer data
|
|
15
|
+
* @param data - The massif data as ArrayBuffer, Uint8Array, or Buffer
|
|
16
|
+
*/
|
|
17
|
+
constructor(data) {
|
|
18
|
+
if (data instanceof ArrayBuffer) {
|
|
19
|
+
this.buffer = new Uint8Array(data);
|
|
20
|
+
}
|
|
21
|
+
else if (data instanceof Uint8Array) {
|
|
22
|
+
this.buffer = data;
|
|
23
|
+
}
|
|
24
|
+
else if ("buffer" in data &&
|
|
25
|
+
"byteOffset" in data &&
|
|
26
|
+
"byteLength" in data) {
|
|
27
|
+
// Node.js Buffer or similar
|
|
28
|
+
this.buffer = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
throw new Error("Unsupported buffer type");
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Returns a MassifStart instance populated by reading directly from the buffer
|
|
36
|
+
*
|
|
37
|
+
* Computes firstIndex using massif height and index (calls MMR function)
|
|
38
|
+
* Computes peakStackLen using massif index (calls MMR function)
|
|
39
|
+
*/
|
|
40
|
+
getStart() {
|
|
41
|
+
const massifHeight = this.massifHeight;
|
|
42
|
+
const massifIndex = this.massifIndex;
|
|
43
|
+
// Compute firstIndex using massif height and index
|
|
44
|
+
const firstIndex = massifFirstLeaf(massifHeight, massifIndex);
|
|
45
|
+
// Compute peakStackLen using massif index
|
|
46
|
+
const peakStackLen = leafMinusSpurSum(BigInt(massifIndex));
|
|
47
|
+
return {
|
|
48
|
+
reserved: this.reserved,
|
|
49
|
+
lastID: this.lastID,
|
|
50
|
+
version: this.version,
|
|
51
|
+
commitmentEpoch: this.commitmentEpoch,
|
|
52
|
+
massifHeight,
|
|
53
|
+
massifIndex,
|
|
54
|
+
firstIndex,
|
|
55
|
+
peakStackLen,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Returns a buffer view of the corresponding field at zero-based index
|
|
60
|
+
*
|
|
61
|
+
* Each field is 32 bytes (LogFormat.ValueBytes). Zero-based indexing, without regard
|
|
62
|
+
* to peakstack or trieindex structure.
|
|
63
|
+
*
|
|
64
|
+
* @param index - Zero-based field index (Number or BigInt)
|
|
65
|
+
* @param count - Number of consecutive fields to include in the view (defaults to 1)
|
|
66
|
+
* @returns Uint8Array view of the field(s) (32 bytes per field)
|
|
67
|
+
*/
|
|
68
|
+
fieldref(index, count = 1) {
|
|
69
|
+
const idx = typeof index === "bigint" ? Number(index) : index;
|
|
70
|
+
const offset = idx * LogFormat.ValueBytes;
|
|
71
|
+
return this.buffer.slice(offset, offset + count * LogFormat.ValueBytes);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Reads bytes from the buffer at the specified offset
|
|
75
|
+
*
|
|
76
|
+
* Returns a view of the buffer without copying. Efficient for reading
|
|
77
|
+
* arbitrary byte ranges that may span multiple 32-byte fields.
|
|
78
|
+
*
|
|
79
|
+
* @param offset - Byte offset into the buffer
|
|
80
|
+
* @param length - Number of bytes to read
|
|
81
|
+
* @returns Uint8Array view of the requested bytes
|
|
82
|
+
*/
|
|
83
|
+
readBytes(offset, length) {
|
|
84
|
+
return this.buffer.slice(offset, offset + length);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Reads a big-endian uint64 from the buffer
|
|
88
|
+
*/
|
|
89
|
+
readUint64BE(offset) {
|
|
90
|
+
const view = new DataView(this.buffer.buffer, this.buffer.byteOffset + offset, 8);
|
|
91
|
+
return view.getBigUint64(0, false); // false = big-endian
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Reads a big-endian uint32 from the buffer
|
|
95
|
+
*/
|
|
96
|
+
readUint32BE(offset) {
|
|
97
|
+
const view = new DataView(this.buffer.buffer, this.buffer.byteOffset + offset, 4);
|
|
98
|
+
return view.getUint32(0, false); // false = big-endian
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Reads a big-endian uint16 from the buffer
|
|
102
|
+
*/
|
|
103
|
+
readUint16BE(offset) {
|
|
104
|
+
const view = new DataView(this.buffer.buffer, this.buffer.byteOffset + offset, 2);
|
|
105
|
+
return view.getUint16(0, false); // false = big-endian
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Reserved field (bytes 0-7)
|
|
109
|
+
*/
|
|
110
|
+
get reserved() {
|
|
111
|
+
return this.readUint64BE(0);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Last ID timestamp (bytes 8-15)
|
|
115
|
+
*/
|
|
116
|
+
get lastID() {
|
|
117
|
+
return this.readUint64BE(MassifStartFmt.LastIdFirstByte);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Version (bytes 21-22)
|
|
121
|
+
*/
|
|
122
|
+
get version() {
|
|
123
|
+
return this.readUint16BE(MassifStartFmt.VersionFirstByte);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Commitment epoch (bytes 23-26)
|
|
127
|
+
*/
|
|
128
|
+
get commitmentEpoch() {
|
|
129
|
+
return this.readUint32BE(MassifStartFmt.EpochFirstByte);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Massif height (byte 27)
|
|
133
|
+
*/
|
|
134
|
+
get massifHeight() {
|
|
135
|
+
return this.buffer[MassifStartFmt.MassifHeightFirstByte];
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Massif index (bytes 28-31)
|
|
139
|
+
*/
|
|
140
|
+
get massifIndex() {
|
|
141
|
+
return this.readUint32BE(MassifStartFmt.MassifFirstByte);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Massif fullness determination functions
|
|
3
|
+
*
|
|
4
|
+
* Functions for determining if a massif is full based on its height and log entries.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Determine if a massif is full.
|
|
8
|
+
*
|
|
9
|
+
* @param massifHeight - Massif height (1-based)
|
|
10
|
+
* @param logEntries - Number of log entries (nodes) in the massif
|
|
11
|
+
* @returns True if the massif is full
|
|
12
|
+
*/
|
|
13
|
+
export declare function isMassifFull(massifHeight: number, logEntries: bigint): boolean;
|
|
14
|
+
//# sourceMappingURL=massiffull.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"massiffull.d.ts","sourceRoot":"","sources":["../../src/massifs/massiffull.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,GACjB,OAAO,CAWT"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Massif fullness determination functions
|
|
3
|
+
*
|
|
4
|
+
* Functions for determining if a massif is full based on its height and log entries.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Determine if a massif is full.
|
|
8
|
+
*
|
|
9
|
+
* @param massifHeight - Massif height (1-based)
|
|
10
|
+
* @param logEntries - Number of log entries (nodes) in the massif
|
|
11
|
+
* @returns True if the massif is full
|
|
12
|
+
*/
|
|
13
|
+
export function isMassifFull(massifHeight, logEntries) {
|
|
14
|
+
// Convert 1-based height to 0-based height index
|
|
15
|
+
const heightIndex = massifHeight - 1;
|
|
16
|
+
// Expected number of leaves for a full massif: f = 2^g = 1 << heightIndex
|
|
17
|
+
const expectedLeaves = BigInt(1 << heightIndex);
|
|
18
|
+
// Actual number of leaves: f = (n + 1) / 2
|
|
19
|
+
const actualLeaves = (logEntries + 1n) >> 1n;
|
|
20
|
+
return actualLeaves >= expectedLeaves;
|
|
21
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MassifLogEntries calculation for v2 massif format
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* MassifLogEntries calculates the number of log entries (nodes) in a blob from
|
|
6
|
+
* the length of the blob in bytes.
|
|
7
|
+
*
|
|
8
|
+
* It does this by accounting for the index data and other header data.
|
|
9
|
+
* If you know the FirstIndex from the massif start header you can get the
|
|
10
|
+
* overall mmr size by direct addition.
|
|
11
|
+
*
|
|
12
|
+
* Note: this function exists so we can compute the mmrSize from just the blob
|
|
13
|
+
* store metadata: we store the FirstIndex on a blob tag, and the blob
|
|
14
|
+
* metadata includes ContentLength. This means when we are checking if a root
|
|
15
|
+
* seal covers the current log head, we don't need to fetch the log massif blob.
|
|
16
|
+
*
|
|
17
|
+
* @param dataLen - Total length of the massif blob in bytes
|
|
18
|
+
* @param massifHeight - One-based massif height
|
|
19
|
+
* @returns Number of log entries (nodes) in the blob
|
|
20
|
+
* @throws Error if the data length is too short to contain the required headers
|
|
21
|
+
*/
|
|
22
|
+
export declare function massifLogEntries(dataLen: number, massifHeight: number): bigint;
|
|
23
|
+
//# sourceMappingURL=massiflogentries.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"massiflogentries.d.ts","sourceRoot":"","sources":["../../src/massifs/massiflogentries.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,GACnB,MAAM,CAWR"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MassifLogEntries calculation for v2 massif format
|
|
3
|
+
*/
|
|
4
|
+
import { LogFormat } from "./logformat.js";
|
|
5
|
+
import { peakStackEnd } from "./peakstackend.js";
|
|
6
|
+
/**
|
|
7
|
+
* MassifLogEntries calculates the number of log entries (nodes) in a blob from
|
|
8
|
+
* the length of the blob in bytes.
|
|
9
|
+
*
|
|
10
|
+
* It does this by accounting for the index data and other header data.
|
|
11
|
+
* If you know the FirstIndex from the massif start header you can get the
|
|
12
|
+
* overall mmr size by direct addition.
|
|
13
|
+
*
|
|
14
|
+
* Note: this function exists so we can compute the mmrSize from just the blob
|
|
15
|
+
* store metadata: we store the FirstIndex on a blob tag, and the blob
|
|
16
|
+
* metadata includes ContentLength. This means when we are checking if a root
|
|
17
|
+
* seal covers the current log head, we don't need to fetch the log massif blob.
|
|
18
|
+
*
|
|
19
|
+
* @param dataLen - Total length of the massif blob in bytes
|
|
20
|
+
* @param massifHeight - One-based massif height
|
|
21
|
+
* @returns Number of log entries (nodes) in the blob
|
|
22
|
+
* @throws Error if the data length is too short to contain the required headers
|
|
23
|
+
*/
|
|
24
|
+
export function massifLogEntries(dataLen, massifHeight) {
|
|
25
|
+
const stackEnd = peakStackEnd(massifHeight);
|
|
26
|
+
if (BigInt(dataLen) < stackEnd) {
|
|
27
|
+
throw new Error(`Massif data length ${dataLen} is too short. Minimum required: ${stackEnd} bytes`);
|
|
28
|
+
}
|
|
29
|
+
const mmrByteCount = BigInt(dataLen) - stackEnd;
|
|
30
|
+
return mmrByteCount / BigInt(LogFormat.ValueBytes);
|
|
31
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MassifStart - Header information for a massif blob
|
|
3
|
+
*
|
|
4
|
+
* The massif start is a 32-byte field encoding bookkeeping information
|
|
5
|
+
* required in a blob to allow for efficient correctness checks.
|
|
6
|
+
*/
|
|
7
|
+
export interface MassifStart {
|
|
8
|
+
/** Reserved field (bytes 0-7) */
|
|
9
|
+
reserved: bigint;
|
|
10
|
+
/** Last ID timestamp (bytes 8-15) */
|
|
11
|
+
lastID: bigint;
|
|
12
|
+
/** Version (bytes 21-22) */
|
|
13
|
+
version: number;
|
|
14
|
+
/** Commitment epoch (bytes 23-26) */
|
|
15
|
+
commitmentEpoch: number;
|
|
16
|
+
/** Massif height (byte 27) */
|
|
17
|
+
massifHeight: number;
|
|
18
|
+
/** Massif index (bytes 28-31) */
|
|
19
|
+
massifIndex: number;
|
|
20
|
+
/** First MMR index in this massif (computed) */
|
|
21
|
+
firstIndex: bigint;
|
|
22
|
+
/** Peak stack length (computed) */
|
|
23
|
+
peakStackLen: bigint;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* MassifStartFmt - Format constants for MassifStart fields
|
|
27
|
+
*
|
|
28
|
+
* Byte offsets and sizes for MassifStart fields.
|
|
29
|
+
* Matching the Go implementation in go-merklelog/massifs/massifstart.go
|
|
30
|
+
*/
|
|
31
|
+
export declare namespace MassifStartFmt {
|
|
32
|
+
/** Last ID timestamp field - first byte offset */
|
|
33
|
+
const LastIdFirstByte = 8;
|
|
34
|
+
/** Last ID timestamp field - size in bytes */
|
|
35
|
+
const LastIdSize = 8;
|
|
36
|
+
/** Last ID timestamp field - end byte offset */
|
|
37
|
+
const LastIdEnd: number;
|
|
38
|
+
/** Version field - first byte offset */
|
|
39
|
+
const VersionFirstByte = 21;
|
|
40
|
+
/** Version field - size in bytes */
|
|
41
|
+
const VersionSize = 2;
|
|
42
|
+
/** Version field - end byte offset */
|
|
43
|
+
const VersionEnd: number;
|
|
44
|
+
/** Commitment epoch field - first byte offset */
|
|
45
|
+
const EpochFirstByte: number;
|
|
46
|
+
/** Commitment epoch field - size in bytes */
|
|
47
|
+
const EpochSize = 4;
|
|
48
|
+
/** Commitment epoch field - end byte offset */
|
|
49
|
+
const EpochEnd: number;
|
|
50
|
+
/** Massif height field - first byte offset */
|
|
51
|
+
const MassifHeightFirstByte: number;
|
|
52
|
+
/** Massif height field - size in bytes */
|
|
53
|
+
const MassifHeightSize = 1;
|
|
54
|
+
/** Massif height field - end byte offset */
|
|
55
|
+
const MassifHeightEnd: number;
|
|
56
|
+
/** Massif index field - first byte offset */
|
|
57
|
+
const MassifFirstByte: number;
|
|
58
|
+
/** Massif index field - size in bytes */
|
|
59
|
+
const MassifSize = 4;
|
|
60
|
+
/** Massif index field - end byte offset */
|
|
61
|
+
const MassifEnd: number;
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=massifstart.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"massifstart.d.ts","sourceRoot":"","sources":["../../src/massifs/massifstart.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,iCAAiC;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,qCAAqC;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,4BAA4B;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,qCAAqC;IACrC,eAAe,EAAE,MAAM,CAAC;IACxB,8BAA8B;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,iCAAiC;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,gDAAgD;IAChD,UAAU,EAAE,MAAM,CAAC;IACnB,mCAAmC;IACnC,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;;;;GAKG;AACH,yBAAiB,cAAc,CAAC;IAC9B,kDAAkD;IAC3C,MAAM,eAAe,IAAI,CAAC;IACjC,8CAA8C;IACvC,MAAM,UAAU,IAAI,CAAC;IAC5B,gDAAgD;IACzC,MAAM,SAAS,QAA+B,CAAC;IAEtD,wCAAwC;IACjC,MAAM,gBAAgB,KAAK,CAAC;IACnC,oCAAoC;IAC7B,MAAM,WAAW,IAAI,CAAC;IAC7B,sCAAsC;IAC/B,MAAM,UAAU,QAAiC,CAAC;IAEzD,iDAAiD;IAC1C,MAAM,cAAc,QAAa,CAAC;IACzC,6CAA6C;IACtC,MAAM,SAAS,IAAI,CAAC;IAC3B,+CAA+C;IACxC,MAAM,QAAQ,QAA6B,CAAC;IAEnD,8CAA8C;IACvC,MAAM,qBAAqB,QAAW,CAAC;IAC9C,0CAA0C;IACnC,MAAM,gBAAgB,IAAI,CAAC;IAClC,4CAA4C;IACrC,MAAM,eAAe,QAA2C,CAAC;IAExE,6CAA6C;IACtC,MAAM,eAAe,QAAkB,CAAC;IAC/C,yCAAyC;IAClC,MAAM,UAAU,IAAI,CAAC;IAC5B,2CAA2C;IACpC,MAAM,SAAS,QAA+B,CAAC;CACvD"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MassifStartFmt - Format constants for MassifStart fields
|
|
3
|
+
*
|
|
4
|
+
* Byte offsets and sizes for MassifStart fields.
|
|
5
|
+
* Matching the Go implementation in go-merklelog/massifs/massifstart.go
|
|
6
|
+
*/
|
|
7
|
+
export var MassifStartFmt;
|
|
8
|
+
(function (MassifStartFmt) {
|
|
9
|
+
/** Last ID timestamp field - first byte offset */
|
|
10
|
+
MassifStartFmt.LastIdFirstByte = 8;
|
|
11
|
+
/** Last ID timestamp field - size in bytes */
|
|
12
|
+
MassifStartFmt.LastIdSize = 8;
|
|
13
|
+
/** Last ID timestamp field - end byte offset */
|
|
14
|
+
MassifStartFmt.LastIdEnd = MassifStartFmt.LastIdFirstByte + MassifStartFmt.LastIdSize;
|
|
15
|
+
/** Version field - first byte offset */
|
|
16
|
+
MassifStartFmt.VersionFirstByte = 21;
|
|
17
|
+
/** Version field - size in bytes */
|
|
18
|
+
MassifStartFmt.VersionSize = 2;
|
|
19
|
+
/** Version field - end byte offset */
|
|
20
|
+
MassifStartFmt.VersionEnd = MassifStartFmt.VersionFirstByte + MassifStartFmt.VersionSize;
|
|
21
|
+
/** Commitment epoch field - first byte offset */
|
|
22
|
+
MassifStartFmt.EpochFirstByte = MassifStartFmt.VersionEnd; // 23
|
|
23
|
+
/** Commitment epoch field - size in bytes */
|
|
24
|
+
MassifStartFmt.EpochSize = 4;
|
|
25
|
+
/** Commitment epoch field - end byte offset */
|
|
26
|
+
MassifStartFmt.EpochEnd = MassifStartFmt.EpochFirstByte + MassifStartFmt.EpochSize;
|
|
27
|
+
/** Massif height field - first byte offset */
|
|
28
|
+
MassifStartFmt.MassifHeightFirstByte = MassifStartFmt.EpochEnd; // 27
|
|
29
|
+
/** Massif height field - size in bytes */
|
|
30
|
+
MassifStartFmt.MassifHeightSize = 1;
|
|
31
|
+
/** Massif height field - end byte offset */
|
|
32
|
+
MassifStartFmt.MassifHeightEnd = MassifStartFmt.MassifHeightFirstByte + MassifStartFmt.MassifHeightSize;
|
|
33
|
+
/** Massif index field - first byte offset */
|
|
34
|
+
MassifStartFmt.MassifFirstByte = MassifStartFmt.MassifHeightEnd; // 28
|
|
35
|
+
/** Massif index field - size in bytes */
|
|
36
|
+
MassifStartFmt.MassifSize = 4;
|
|
37
|
+
/** Massif index field - end byte offset */
|
|
38
|
+
MassifStartFmt.MassifEnd = MassifStartFmt.MassifFirstByte + MassifStartFmt.MassifSize;
|
|
39
|
+
})(MassifStartFmt || (MassifStartFmt = {}));
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MMR index calculation functions for massifs
|
|
3
|
+
*
|
|
4
|
+
* Functions for computing MMR indices from massif metadata.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Compute the last MMR index in a massif.
|
|
8
|
+
*
|
|
9
|
+
* @param massifHeight - Massif height (1-based)
|
|
10
|
+
* @param massifIndex - Massif index
|
|
11
|
+
* @param blobSize - Size of the massif blob in bytes
|
|
12
|
+
* @returns The last MMR index in the massif
|
|
13
|
+
*/
|
|
14
|
+
export declare function computeLastMMRIndex(massifHeight: number, massifIndex: number, blobSize: number): bigint;
|
|
15
|
+
//# sourceMappingURL=mmrindex.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mmrindex.d.ts","sourceRoot":"","sources":["../../src/massifs/mmrindex.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GACf,MAAM,CAUR"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MMR index calculation functions for massifs
|
|
3
|
+
*
|
|
4
|
+
* Functions for computing MMR indices from massif metadata.
|
|
5
|
+
*/
|
|
6
|
+
import { massifLogEntries } from "./massiflogentries.js";
|
|
7
|
+
import { massifFirstLeaf } from "../mmr/index.js";
|
|
8
|
+
/**
|
|
9
|
+
* Compute the last MMR index in a massif.
|
|
10
|
+
*
|
|
11
|
+
* @param massifHeight - Massif height (1-based)
|
|
12
|
+
* @param massifIndex - Massif index
|
|
13
|
+
* @param blobSize - Size of the massif blob in bytes
|
|
14
|
+
* @returns The last MMR index in the massif
|
|
15
|
+
*/
|
|
16
|
+
export function computeLastMMRIndex(massifHeight, massifIndex, blobSize) {
|
|
17
|
+
// Calculate number of log entries (nodes) in the blob
|
|
18
|
+
// massifLogEntries expects 1-based height
|
|
19
|
+
const logEntries = massifLogEntries(blobSize, massifHeight);
|
|
20
|
+
// Get firstIndex using massifFirstLeaf (also expects 1-based height)
|
|
21
|
+
const firstIndex = massifFirstLeaf(massifHeight, massifIndex);
|
|
22
|
+
// Last index = firstIndex + logEntries - 1
|
|
23
|
+
return firstIndex + logEntries - 1n;
|
|
24
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PeakStackEnd calculation for v2 massif format
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* PeakStackEnd returns the first byte after the massif ancestor peak stack data
|
|
6
|
+
*
|
|
7
|
+
* The peak stack is fixed at MaxMmrHeight entries regardless of how many are
|
|
8
|
+
* actually needed. This makes it possible to trivially compute the node &
|
|
9
|
+
* leaf counts knowing only the byte size of the massif.
|
|
10
|
+
*
|
|
11
|
+
* V2 layout:
|
|
12
|
+
* StartHeader (256 bytes)
|
|
13
|
+
* IndexHeader (32 bytes) = BloomHeaderV1
|
|
14
|
+
* IndexData (bloom bitsets + frontier + leaf table + node store)
|
|
15
|
+
* PeakStack (MaxMmrHeight * ValueBytes = 2048 bytes)
|
|
16
|
+
*
|
|
17
|
+
* @param massifHeight - One-based massif height
|
|
18
|
+
* @returns Byte offset of the end of the peak stack
|
|
19
|
+
*/
|
|
20
|
+
export declare function peakStackEnd(massifHeight: number): bigint;
|
|
21
|
+
//# sourceMappingURL=peakstackend.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"peakstackend.d.ts","sourceRoot":"","sources":["../../src/massifs/peakstackend.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAUzD"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PeakStackEnd calculation for v2 massif format
|
|
3
|
+
*/
|
|
4
|
+
import { LogFormat } from "./logformat.js";
|
|
5
|
+
import { indexDataBytesV2, leafCountForMassifHeight } from "./indexformat.js";
|
|
6
|
+
/**
|
|
7
|
+
* PeakStackEnd returns the first byte after the massif ancestor peak stack data
|
|
8
|
+
*
|
|
9
|
+
* The peak stack is fixed at MaxMmrHeight entries regardless of how many are
|
|
10
|
+
* actually needed. This makes it possible to trivially compute the node &
|
|
11
|
+
* leaf counts knowing only the byte size of the massif.
|
|
12
|
+
*
|
|
13
|
+
* V2 layout:
|
|
14
|
+
* StartHeader (256 bytes)
|
|
15
|
+
* IndexHeader (32 bytes) = BloomHeaderV1
|
|
16
|
+
* IndexData (bloom bitsets + frontier + leaf table + node store)
|
|
17
|
+
* PeakStack (MaxMmrHeight * ValueBytes = 2048 bytes)
|
|
18
|
+
*
|
|
19
|
+
* @param massifHeight - One-based massif height
|
|
20
|
+
* @returns Byte offset of the end of the peak stack
|
|
21
|
+
*/
|
|
22
|
+
export function peakStackEnd(massifHeight) {
|
|
23
|
+
const fixedHeaderEnd = BigInt(LogFormat.StartHeaderSize);
|
|
24
|
+
const indexHeaderBytes = BigInt(LogFormat.IndexHeaderBytes);
|
|
25
|
+
const leafCount = leafCountForMassifHeight(massifHeight);
|
|
26
|
+
const indexDataBytes = indexDataBytesV2(leafCount);
|
|
27
|
+
const peakStackSize = BigInt(LogFormat.MaxMmrHeight * LogFormat.ValueBytes);
|
|
28
|
+
return fixedHeaderEnd + indexHeaderBytes + indexDataBytes + peakStackSize;
|
|
29
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Re-exports for massifs module types and constants
|
|
3
|
+
*
|
|
4
|
+
* This file serves as a convenience re-export point for external consumers.
|
|
5
|
+
* Types and interfaces are organized into individual files to:
|
|
6
|
+
* 1. Avoid circular dependencies
|
|
7
|
+
* 2. Avoid monolithic types.ts files
|
|
8
|
+
* 3. Keep related code (interfaces and their implementations) together
|
|
9
|
+
*/
|
|
10
|
+
export type { MassifStart } from "./massifstart.js";
|
|
11
|
+
export { MassifStartFmt } from "./massifstart.js";
|
|
12
|
+
export { LogFormat } from "./logformat.js";
|
|
13
|
+
export { Urkle, Bloom, IndexV2, leafCountForMassifHeight, leafTableBytes, nodeCountMax, nodeStoreBytes, bloomMBits, bloomBitsetBytes, bloomRegionBytes, indexDataBytesV2, } from "./indexformat.js";
|
|
14
|
+
export { peakStackEnd } from "./peakstackend.js";
|
|
15
|
+
export { massifLogEntries } from "./massiflogentries.js";
|
|
16
|
+
export { urkleLeafTableStartFieldIndex, urkleLeafTableStartByteOffset, createLeafEnumerator, leafComponentByteOffset, leafComponentSize, } from "./urkleindex.js";
|
|
17
|
+
export type { LeafComponent, LeafEnumeratorSpec, LeafEntry, } from "./urkleindex.js";
|
|
18
|
+
export { computeLastMMRIndex } from "./mmrindex.js";
|
|
19
|
+
export { isMassifFull } from "./massiffull.js";
|
|
20
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/massifs/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,YAAY,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAGlD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAG3C,OAAO,EACL,KAAK,EACL,KAAK,EACL,OAAO,EACP,wBAAwB,EACxB,cAAc,EACd,YAAY,EACZ,cAAc,EACd,UAAU,EACV,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAGzD,OAAO,EACL,6BAA6B,EAC7B,6BAA6B,EAC7B,oBAAoB,EACpB,uBAAuB,EACvB,iBAAiB,GAClB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,aAAa,EACb,kBAAkB,EAClB,SAAS,GACV,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAGpD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Re-exports for massifs module types and constants
|
|
3
|
+
*
|
|
4
|
+
* This file serves as a convenience re-export point for external consumers.
|
|
5
|
+
* Types and interfaces are organized into individual files to:
|
|
6
|
+
* 1. Avoid circular dependencies
|
|
7
|
+
* 2. Avoid monolithic types.ts files
|
|
8
|
+
* 3. Keep related code (interfaces and their implementations) together
|
|
9
|
+
*/
|
|
10
|
+
export { MassifStartFmt } from "./massifstart.js";
|
|
11
|
+
// Re-export log format constants
|
|
12
|
+
export { LogFormat } from "./logformat.js";
|
|
13
|
+
// Re-export index format constants and functions (v2)
|
|
14
|
+
export { Urkle, Bloom, IndexV2, leafCountForMassifHeight, leafTableBytes, nodeCountMax, nodeStoreBytes, bloomMBits, bloomBitsetBytes, bloomRegionBytes, indexDataBytesV2, } from "./indexformat.js";
|
|
15
|
+
// Re-export peakStackEnd and massifLogEntries
|
|
16
|
+
export { peakStackEnd } from "./peakstackend.js";
|
|
17
|
+
export { massifLogEntries } from "./massiflogentries.js";
|
|
18
|
+
// Re-export urkle index helpers
|
|
19
|
+
export { urkleLeafTableStartFieldIndex, urkleLeafTableStartByteOffset, createLeafEnumerator, leafComponentByteOffset, leafComponentSize, } from "./urkleindex.js";
|
|
20
|
+
// Re-export MMR index functions
|
|
21
|
+
export { computeLastMMRIndex } from "./mmrindex.js";
|
|
22
|
+
// Re-export massif fullness functions
|
|
23
|
+
export { isMassifFull } from "./massiffull.js";
|