@lodestar/era 1.36.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 +201 -0
- package/README.md +76 -0
- package/lib/e2s.d.ts +68 -0
- package/lib/e2s.d.ts.map +1 -0
- package/lib/e2s.js +129 -0
- package/lib/e2s.js.map +1 -0
- package/lib/era/index.d.ts +4 -0
- package/lib/era/index.d.ts.map +1 -0
- package/lib/era/index.js +4 -0
- package/lib/era/index.js.map +1 -0
- package/lib/era/reader.d.ts +43 -0
- package/lib/era/reader.d.ts.map +1 -0
- package/lib/era/reader.js +160 -0
- package/lib/era/reader.js.map +1 -0
- package/lib/era/util.d.ts +46 -0
- package/lib/era/util.d.ts.map +1 -0
- package/lib/era/util.js +92 -0
- package/lib/era/util.js.map +1 -0
- package/lib/era/writer.d.ts +48 -0
- package/lib/era/writer.d.ts.map +1 -0
- package/lib/era/writer.js +163 -0
- package/lib/era/writer.js.map +1 -0
- package/lib/index.d.ts +3 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +3 -0
- package/lib/index.js.map +1 -0
- package/lib/util.d.ts +19 -0
- package/lib/util.d.ts.map +1 -0
- package/lib/util.js +49 -0
- package/lib/util.js.map +1 -0
- package/package.json +49 -0
- package/src/e2s.ts +178 -0
- package/src/era/index.ts +3 -0
- package/src/era/reader.ts +196 -0
- package/src/era/util.ts +134 -0
- package/src/era/writer.ts +206 -0
- package/src/index.ts +2 -0
- package/src/util.ts +60 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { open } from "node:fs/promises";
|
|
2
|
+
import { basename } from "node:path";
|
|
3
|
+
import { PublicKey, Signature, verify } from "@chainsafe/blst";
|
|
4
|
+
import { createCachedGenesis } from "@lodestar/config";
|
|
5
|
+
import { DOMAIN_BEACON_PROPOSER, SLOTS_PER_HISTORICAL_ROOT } from "@lodestar/params";
|
|
6
|
+
import { ssz } from "@lodestar/types";
|
|
7
|
+
import { E2STORE_HEADER_SIZE, EntryType, readEntry, readVersion } from "../e2s.js";
|
|
8
|
+
import { snappyUncompress } from "../util.js";
|
|
9
|
+
import { computeEraNumberFromBlockSlot, parseEraName, readAllEraIndices, readSlotFromBeaconStateBytes, } from "./util.js";
|
|
10
|
+
/**
|
|
11
|
+
* EraReader is responsible for reading and validating ERA files.
|
|
12
|
+
*
|
|
13
|
+
* See https://github.com/eth-clients/e2store-format-specs/blob/main/formats/era.md
|
|
14
|
+
*/
|
|
15
|
+
export class EraReader {
|
|
16
|
+
config;
|
|
17
|
+
/** The underlying file handle */
|
|
18
|
+
fh;
|
|
19
|
+
/** The era number retrieved from the file name */
|
|
20
|
+
eraNumber;
|
|
21
|
+
/** The short historical root retrieved from the file name */
|
|
22
|
+
shortHistoricalRoot;
|
|
23
|
+
/** An array of state and block indices, one per group */
|
|
24
|
+
groups;
|
|
25
|
+
constructor(config, fh, eraNumber, shortHistoricalRoot, indices) {
|
|
26
|
+
this.config = config;
|
|
27
|
+
this.fh = fh;
|
|
28
|
+
this.eraNumber = eraNumber;
|
|
29
|
+
this.shortHistoricalRoot = shortHistoricalRoot;
|
|
30
|
+
this.groups = indices;
|
|
31
|
+
}
|
|
32
|
+
static async open(config, path) {
|
|
33
|
+
const fh = await open(path, "r");
|
|
34
|
+
const name = basename(path);
|
|
35
|
+
const { configName, eraNumber, shortHistoricalRoot } = parseEraName(name);
|
|
36
|
+
if (config.CONFIG_NAME !== configName) {
|
|
37
|
+
throw new Error(`Config name mismatch: expected ${config.CONFIG_NAME}, got ${configName}`);
|
|
38
|
+
}
|
|
39
|
+
const indices = await readAllEraIndices(fh);
|
|
40
|
+
return new EraReader(config, fh, eraNumber, shortHistoricalRoot, indices);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Close the underlying file descriptor
|
|
44
|
+
*
|
|
45
|
+
* No further actions can be taken after this operation
|
|
46
|
+
*/
|
|
47
|
+
async close() {
|
|
48
|
+
await this.fh.close();
|
|
49
|
+
}
|
|
50
|
+
async readCompressedState(eraNumber) {
|
|
51
|
+
eraNumber = eraNumber ?? this.eraNumber;
|
|
52
|
+
const index = this.groups.at(eraNumber - this.eraNumber);
|
|
53
|
+
if (!index) {
|
|
54
|
+
throw new Error(`No index found for era number ${eraNumber}`);
|
|
55
|
+
}
|
|
56
|
+
const entry = await readEntry(this.fh, index.stateIndex.recordStart + index.stateIndex.offsets[0]);
|
|
57
|
+
if (entry.type !== EntryType.CompressedBeaconState) {
|
|
58
|
+
throw new Error(`Expected CompressedBeaconState, got ${entry.type}`);
|
|
59
|
+
}
|
|
60
|
+
return entry.data;
|
|
61
|
+
}
|
|
62
|
+
async readSerializedState(eraNumber) {
|
|
63
|
+
const compressed = await this.readCompressedState(eraNumber);
|
|
64
|
+
return snappyUncompress(compressed);
|
|
65
|
+
}
|
|
66
|
+
async readState(eraNumber) {
|
|
67
|
+
const serialized = await this.readSerializedState(eraNumber);
|
|
68
|
+
const stateSlot = readSlotFromBeaconStateBytes(serialized);
|
|
69
|
+
return this.config.getForkTypes(stateSlot).BeaconState.deserialize(serialized);
|
|
70
|
+
}
|
|
71
|
+
async readCompressedBlock(slot) {
|
|
72
|
+
const slotEra = computeEraNumberFromBlockSlot(slot);
|
|
73
|
+
const index = this.groups.at(slotEra - this.eraNumber);
|
|
74
|
+
if (!index) {
|
|
75
|
+
throw new Error(`Slot ${slot} is out of range`);
|
|
76
|
+
}
|
|
77
|
+
if (!index.blocksIndex) {
|
|
78
|
+
throw new Error(`No block index found for era number ${slotEra}`);
|
|
79
|
+
}
|
|
80
|
+
// Calculate offset within the index
|
|
81
|
+
const indexOffset = slot - index.blocksIndex.startSlot;
|
|
82
|
+
const offset = index.blocksIndex.recordStart + index.blocksIndex.offsets[indexOffset];
|
|
83
|
+
if (offset === 0) {
|
|
84
|
+
return null; // Empty slot
|
|
85
|
+
}
|
|
86
|
+
const entry = await readEntry(this.fh, offset);
|
|
87
|
+
if (entry.type !== EntryType.CompressedSignedBeaconBlock) {
|
|
88
|
+
throw new Error(`Expected CompressedSignedBeaconBlock, got ${EntryType[entry.type] ?? "unknown"}`);
|
|
89
|
+
}
|
|
90
|
+
return entry.data;
|
|
91
|
+
}
|
|
92
|
+
async readSerializedBlock(slot) {
|
|
93
|
+
const compressed = await this.readCompressedBlock(slot);
|
|
94
|
+
if (compressed === null)
|
|
95
|
+
return null;
|
|
96
|
+
return snappyUncompress(compressed);
|
|
97
|
+
}
|
|
98
|
+
async readBlock(slot) {
|
|
99
|
+
const serialized = await this.readSerializedBlock(slot);
|
|
100
|
+
if (serialized === null)
|
|
101
|
+
return null;
|
|
102
|
+
return this.config.getForkTypes(slot).SignedBeaconBlock.deserialize(serialized);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Validate the era file.
|
|
106
|
+
* - e2s format correctness
|
|
107
|
+
* - era range correctness
|
|
108
|
+
* - network correctness for state and blocks
|
|
109
|
+
* - block root and signature matches
|
|
110
|
+
*/
|
|
111
|
+
async validate() {
|
|
112
|
+
for (let groupIndex = 0; groupIndex < this.groups.length; groupIndex++) {
|
|
113
|
+
const eraNumber = this.eraNumber + groupIndex;
|
|
114
|
+
const index = this.groups[groupIndex];
|
|
115
|
+
// validate version entry
|
|
116
|
+
const start = index.blocksIndex
|
|
117
|
+
? index.blocksIndex.recordStart + index.blocksIndex.offsets[0] - E2STORE_HEADER_SIZE
|
|
118
|
+
: index.stateIndex.recordStart + index.stateIndex.offsets[0] - E2STORE_HEADER_SIZE;
|
|
119
|
+
await readVersion(this.fh, start);
|
|
120
|
+
// validate state
|
|
121
|
+
// the state is loadable and consistent with the given runtime configuration
|
|
122
|
+
const state = await this.readState(eraNumber);
|
|
123
|
+
const cachedGenesis = createCachedGenesis(this.config, state.genesisValidatorsRoot);
|
|
124
|
+
if (eraNumber === 0 && index.blocksIndex) {
|
|
125
|
+
throw new Error("Genesis era (era 0) should not have blocks index");
|
|
126
|
+
}
|
|
127
|
+
if (eraNumber !== 0) {
|
|
128
|
+
if (!index.blocksIndex) {
|
|
129
|
+
throw new Error(`Era ${eraNumber} is missing blocks index`);
|
|
130
|
+
}
|
|
131
|
+
// validate blocks
|
|
132
|
+
for (let slot = index.blocksIndex.startSlot; slot < index.blocksIndex.startSlot + index.blocksIndex.offsets.length; slot++) {
|
|
133
|
+
const block = await this.readBlock(slot);
|
|
134
|
+
if (block === null) {
|
|
135
|
+
if (slot === index.blocksIndex.startSlot)
|
|
136
|
+
continue; // first slot in the era can't be easily validated
|
|
137
|
+
if (Buffer.compare(state.blockRoots[(slot - 1) % SLOTS_PER_HISTORICAL_ROOT], state.blockRoots[slot % SLOTS_PER_HISTORICAL_ROOT]) !== 0) {
|
|
138
|
+
throw new Error(`Block root mismatch at slot ${slot} for empty slot`);
|
|
139
|
+
}
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
const blockRoot = this.config.getForkTypes(slot).BeaconBlock.hashTreeRoot(block.message);
|
|
143
|
+
if (Buffer.compare(blockRoot, state.blockRoots[slot % SLOTS_PER_HISTORICAL_ROOT]) !== 0) {
|
|
144
|
+
throw new Error(`Block root mismatch at slot ${slot}`);
|
|
145
|
+
}
|
|
146
|
+
const msg = ssz.phase0.SigningData.hashTreeRoot({
|
|
147
|
+
objectRoot: blockRoot,
|
|
148
|
+
domain: cachedGenesis.getDomain(slot, DOMAIN_BEACON_PROPOSER),
|
|
149
|
+
});
|
|
150
|
+
const pk = PublicKey.fromBytes(state.validators[block.message.proposerIndex].pubkey);
|
|
151
|
+
const sig = Signature.fromBytes(block.signature);
|
|
152
|
+
if (!verify(msg, pk, sig, true, true)) {
|
|
153
|
+
throw new Error(`Block signature verification failed at slot ${slot}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=reader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reader.js","sourceRoot":"","sources":["../../src/era/reader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { FileHandle } from "node:fs/promises";
|
|
2
|
+
import { ChainForkConfig } from "@lodestar/config";
|
|
3
|
+
import { BeaconState, Slot } from "@lodestar/types";
|
|
4
|
+
import { SlotIndex } from "../e2s.ts";
|
|
5
|
+
/**
|
|
6
|
+
* Parsed components of an .era file name.
|
|
7
|
+
* Format: <config-name>-<era-number>-<short-historical-root>.era
|
|
8
|
+
*/
|
|
9
|
+
export interface EraFileName {
|
|
10
|
+
/** CONFIG_NAME field of runtime config (mainnet, sepolia, holesky, etc.) */
|
|
11
|
+
configName: string;
|
|
12
|
+
/** Number of the first era stored in file, 5-digit zero-padded (00000, 00001, etc.) */
|
|
13
|
+
eraNumber: number;
|
|
14
|
+
/** First 4 bytes of last historical root, lower-case hex-encoded (8 chars) */
|
|
15
|
+
shortHistoricalRoot: string;
|
|
16
|
+
}
|
|
17
|
+
export interface EraIndices {
|
|
18
|
+
stateIndex: SlotIndex;
|
|
19
|
+
blocksIndex?: SlotIndex;
|
|
20
|
+
}
|
|
21
|
+
/** Return true if `slot` is within the era range */
|
|
22
|
+
export declare function isSlotInRange(slot: Slot, eraNumber: number): boolean;
|
|
23
|
+
export declare function isValidEraStateSlot(slot: Slot, eraNumber: number): boolean;
|
|
24
|
+
export declare function computeEraNumberFromBlockSlot(slot: Slot): number;
|
|
25
|
+
export declare function computeStartBlockSlotFromEraNumber(eraNumber: number): Slot;
|
|
26
|
+
/**
|
|
27
|
+
* Parse era filename.
|
|
28
|
+
*
|
|
29
|
+
* Format: `<config-name>-<era-number>-<short-historical-root>.era`
|
|
30
|
+
*/
|
|
31
|
+
export declare function parseEraName(filename: string): {
|
|
32
|
+
configName: string;
|
|
33
|
+
eraNumber: number;
|
|
34
|
+
shortHistoricalRoot: string;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Read all indices from an era file.
|
|
38
|
+
*/
|
|
39
|
+
export declare function readAllEraIndices(fh: FileHandle): Promise<EraIndices[]>;
|
|
40
|
+
/**
|
|
41
|
+
* Read state and block SlotIndex entries from an era file and validate alignment.
|
|
42
|
+
*/
|
|
43
|
+
export declare function readEraIndexes(fh: FileHandle, end: number): Promise<EraIndices>;
|
|
44
|
+
export declare function readSlotFromBeaconStateBytes(beaconStateBytes: Uint8Array): Slot;
|
|
45
|
+
export declare function getShortHistoricalRoot(config: ChainForkConfig, state: BeaconState): string;
|
|
46
|
+
//# sourceMappingURL=util.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../src/era/util.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAC,eAAe,EAAC,MAAM,kBAAkB,CAAC;AAEjD,OAAO,EAAC,WAAW,EAAE,IAAI,EAAe,MAAM,iBAAiB,CAAC;AAChE,OAAO,EAAsB,SAAS,EAAgB,MAAM,WAAW,CAAC;AAGxE;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,4EAA4E;IAC5E,UAAU,EAAE,MAAM,CAAC;IACnB,uFAAuF;IACvF,SAAS,EAAE,MAAM,CAAC;IAClB,8EAA8E;IAC9E,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,SAAS,CAAC;IACtB,WAAW,CAAC,EAAE,SAAS,CAAC;CACzB;AAED,oDAAoD;AACpD,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAEpE;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAE1E;AAED,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAEhE;AAED,wBAAgB,kCAAkC,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAK1E;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,mBAAmB,EAAE,MAAM,CAAA;CAAC,CAUnH;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,EAAE,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAY7E;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CA2BrF;AAED,wBAAgB,4BAA4B,CAAC,gBAAgB,EAAE,UAAU,GAAG,IAAI,CAO/E;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,eAAe,EAAE,KAAK,EAAE,WAAW,GAAG,MAAM,CAa1F"}
|
package/lib/era/util.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { SLOTS_PER_HISTORICAL_ROOT, isForkPostCapella } from "@lodestar/params";
|
|
2
|
+
import { ssz } from "@lodestar/types";
|
|
3
|
+
import { E2STORE_HEADER_SIZE, readSlotIndex } from "../e2s.js";
|
|
4
|
+
import { readUint48 } from "../util.js";
|
|
5
|
+
/** Return true if `slot` is within the era range */
|
|
6
|
+
export function isSlotInRange(slot, eraNumber) {
|
|
7
|
+
return computeEraNumberFromBlockSlot(slot) === eraNumber;
|
|
8
|
+
}
|
|
9
|
+
export function isValidEraStateSlot(slot, eraNumber) {
|
|
10
|
+
return slot % SLOTS_PER_HISTORICAL_ROOT === 0 && slot / SLOTS_PER_HISTORICAL_ROOT === eraNumber;
|
|
11
|
+
}
|
|
12
|
+
export function computeEraNumberFromBlockSlot(slot) {
|
|
13
|
+
return Math.floor(slot / SLOTS_PER_HISTORICAL_ROOT) + 1;
|
|
14
|
+
}
|
|
15
|
+
export function computeStartBlockSlotFromEraNumber(eraNumber) {
|
|
16
|
+
if (eraNumber === 0) {
|
|
17
|
+
throw new Error("Genesis era (era 0) does not contain blocks");
|
|
18
|
+
}
|
|
19
|
+
return (eraNumber - 1) * SLOTS_PER_HISTORICAL_ROOT;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Parse era filename.
|
|
23
|
+
*
|
|
24
|
+
* Format: `<config-name>-<era-number>-<short-historical-root>.era`
|
|
25
|
+
*/
|
|
26
|
+
export function parseEraName(filename) {
|
|
27
|
+
const match = filename.match(/^(.*)-(\d{5})-([0-9a-f]{8})\.era$/);
|
|
28
|
+
if (!match) {
|
|
29
|
+
throw new Error(`Invalid era filename format: ${filename}`);
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
configName: match[1],
|
|
33
|
+
eraNumber: parseInt(match[2], 10),
|
|
34
|
+
shortHistoricalRoot: match[3],
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Read all indices from an era file.
|
|
39
|
+
*/
|
|
40
|
+
export async function readAllEraIndices(fh) {
|
|
41
|
+
let end = (await fh.stat()).size;
|
|
42
|
+
const indices = [];
|
|
43
|
+
while (end > E2STORE_HEADER_SIZE) {
|
|
44
|
+
const index = await readEraIndexes(fh, end);
|
|
45
|
+
indices.push(index);
|
|
46
|
+
end = index.blocksIndex
|
|
47
|
+
? index.blocksIndex.recordStart + index.blocksIndex.offsets[0] - E2STORE_HEADER_SIZE
|
|
48
|
+
: index.stateIndex.recordStart + index.stateIndex.offsets[0] - E2STORE_HEADER_SIZE;
|
|
49
|
+
}
|
|
50
|
+
return indices;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Read state and block SlotIndex entries from an era file and validate alignment.
|
|
54
|
+
*/
|
|
55
|
+
export async function readEraIndexes(fh, end) {
|
|
56
|
+
const stateIndex = await readSlotIndex(fh, end);
|
|
57
|
+
if (stateIndex.offsets.length !== 1) {
|
|
58
|
+
throw new Error(`State SlotIndex must have exactly one offset, got ${stateIndex.offsets.length}`);
|
|
59
|
+
}
|
|
60
|
+
// Read block index if not genesis era (era 0)
|
|
61
|
+
let blocksIndex;
|
|
62
|
+
if (stateIndex.startSlot > 0) {
|
|
63
|
+
blocksIndex = await readSlotIndex(fh, stateIndex.recordStart);
|
|
64
|
+
if (blocksIndex.offsets.length !== SLOTS_PER_HISTORICAL_ROOT) {
|
|
65
|
+
throw new Error(`Block SlotIndex must have exactly ${SLOTS_PER_HISTORICAL_ROOT} offsets, got ${blocksIndex.offsets.length}`);
|
|
66
|
+
}
|
|
67
|
+
// Validate block and state indices are properly aligned
|
|
68
|
+
const expectedBlockStartSlot = stateIndex.startSlot - SLOTS_PER_HISTORICAL_ROOT;
|
|
69
|
+
if (blocksIndex.startSlot !== expectedBlockStartSlot) {
|
|
70
|
+
throw new Error(`Block index alignment error: expected startSlot=${expectedBlockStartSlot}, ` +
|
|
71
|
+
`got startSlot=${blocksIndex.startSlot} (should be exactly one era before state)`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return { stateIndex, blocksIndex };
|
|
75
|
+
}
|
|
76
|
+
export function readSlotFromBeaconStateBytes(beaconStateBytes) {
|
|
77
|
+
// not technically a Uint48, but for practical purposes fits within 6 bytes
|
|
78
|
+
return readUint48(beaconStateBytes,
|
|
79
|
+
// slot is at offset 40: 8 (genesisTime) + 32 (genesisValidatorsRoot)
|
|
80
|
+
40);
|
|
81
|
+
}
|
|
82
|
+
export function getShortHistoricalRoot(config, state) {
|
|
83
|
+
return Buffer.from(state.slot === 0
|
|
84
|
+
? state.genesisValidatorsRoot
|
|
85
|
+
: // Post-Capella, historical_roots is replaced by historical_summaries
|
|
86
|
+
isForkPostCapella(config.getForkName(state.slot))
|
|
87
|
+
? ssz.capella.HistoricalSummary.hashTreeRoot(state.historicalSummaries.at(-1))
|
|
88
|
+
: state.historicalRoots.at(-1))
|
|
89
|
+
.subarray(0, 4)
|
|
90
|
+
.toString("hex");
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=util.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util.js","sourceRoot":"","sources":["../../src/era/util.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { type FileHandle } from "node:fs/promises";
|
|
2
|
+
import { ChainForkConfig } from "@lodestar/config";
|
|
3
|
+
import { BeaconState, SignedBeaconBlock, Slot } from "@lodestar/types";
|
|
4
|
+
declare enum WriterStateType {
|
|
5
|
+
InitGroup = 0,
|
|
6
|
+
WriteGroup = 1,
|
|
7
|
+
FinishedGroup = 2
|
|
8
|
+
}
|
|
9
|
+
type WriterState = {
|
|
10
|
+
type: WriterStateType.InitGroup;
|
|
11
|
+
eraNumber: number;
|
|
12
|
+
currentOffset: number;
|
|
13
|
+
} | {
|
|
14
|
+
type: WriterStateType.WriteGroup;
|
|
15
|
+
eraNumber: number;
|
|
16
|
+
currentOffset: number;
|
|
17
|
+
blockOffsets: number[];
|
|
18
|
+
lastSlot: Slot;
|
|
19
|
+
} | {
|
|
20
|
+
type: WriterStateType.FinishedGroup;
|
|
21
|
+
eraNumber: number;
|
|
22
|
+
currentOffset: number;
|
|
23
|
+
shortHistoricalRoot: string;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* EraWriter is responsible for writing ERA files.
|
|
27
|
+
*
|
|
28
|
+
* See https://github.com/eth-clients/e2store-format-specs/blob/main/formats/era.md
|
|
29
|
+
*/
|
|
30
|
+
export declare class EraWriter {
|
|
31
|
+
config: ChainForkConfig;
|
|
32
|
+
path: string;
|
|
33
|
+
fh: FileHandle;
|
|
34
|
+
eraNumber: number;
|
|
35
|
+
state: WriterState;
|
|
36
|
+
constructor(config: ChainForkConfig, path: string, fh: FileHandle, eraNumber: number);
|
|
37
|
+
static create(config: ChainForkConfig, path: string, eraNumber: number): Promise<EraWriter>;
|
|
38
|
+
finish(): Promise<string>;
|
|
39
|
+
writeVersion(): Promise<void>;
|
|
40
|
+
writeCompressedState(slot: Slot, shortHistoricalRoot: string, data: Uint8Array): Promise<void>;
|
|
41
|
+
writeSerializedState(slot: Slot, shortHistoricalRoot: string, data: Uint8Array): Promise<void>;
|
|
42
|
+
writeState(state: BeaconState): Promise<void>;
|
|
43
|
+
writeCompressedBlock(slot: Slot, data: Uint8Array): Promise<void>;
|
|
44
|
+
writeSerializedBlock(slot: Slot, data: Uint8Array): Promise<void>;
|
|
45
|
+
writeBlock(block: SignedBeaconBlock): Promise<void>;
|
|
46
|
+
}
|
|
47
|
+
export {};
|
|
48
|
+
//# sourceMappingURL=writer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writer.d.ts","sourceRoot":"","sources":["../../src/era/writer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,KAAK,UAAU,EAAe,MAAM,kBAAkB,CAAC;AAE/D,OAAO,EAAC,eAAe,EAAC,MAAM,kBAAkB,CAAC;AAEjD,OAAO,EAAC,WAAW,EAAE,iBAAiB,EAAE,IAAI,EAAC,MAAM,iBAAiB,CAAC;AAUrE,aAAK,eAAe;IAClB,SAAS,IAAA;IACT,UAAU,IAAA;IACV,aAAa,IAAA;CACd;AAED,KAAK,WAAW,GACZ;IACE,IAAI,EAAE,eAAe,CAAC,SAAS,CAAC;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;CACvB,GACD;IACE,IAAI,EAAE,eAAe,CAAC,UAAU,CAAC;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,QAAQ,EAAE,IAAI,CAAC;CAChB,GACD;IACE,IAAI,EAAE,eAAe,CAAC,aAAa,CAAC;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,mBAAmB,EAAE,MAAM,CAAC;CAC7B,CAAC;AAEN;;;;GAIG;AACH,qBAAa,SAAS;IACpB,MAAM,EAAE,eAAe,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,UAAU,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,WAAW,CAAC;gBAEP,MAAM,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM;WAYvE,MAAM,CAAC,MAAM,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IAK3F,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC;IAgBzB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAsB7B,oBAAoB,CAAC,IAAI,EAAE,IAAI,EAAE,mBAAmB,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IA+C9F,oBAAoB,CAAC,IAAI,EAAE,IAAI,EAAE,mBAAmB,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAK9F,UAAU,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ7C,oBAAoB,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IA2BjE,oBAAoB,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAKjE,UAAU,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;CAM1D"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { open, rename } from "node:fs/promises";
|
|
2
|
+
import { format, parse } from "node:path";
|
|
3
|
+
import { SLOTS_PER_HISTORICAL_ROOT } from "@lodestar/params";
|
|
4
|
+
import { E2STORE_HEADER_SIZE, EntryType, serializeSlotIndex, writeEntry } from "../e2s.js";
|
|
5
|
+
import { snappyCompress } from "../util.js";
|
|
6
|
+
import { computeStartBlockSlotFromEraNumber, getShortHistoricalRoot, isSlotInRange, isValidEraStateSlot, } from "./util.js";
|
|
7
|
+
var WriterStateType;
|
|
8
|
+
(function (WriterStateType) {
|
|
9
|
+
WriterStateType[WriterStateType["InitGroup"] = 0] = "InitGroup";
|
|
10
|
+
WriterStateType[WriterStateType["WriteGroup"] = 1] = "WriteGroup";
|
|
11
|
+
WriterStateType[WriterStateType["FinishedGroup"] = 2] = "FinishedGroup";
|
|
12
|
+
})(WriterStateType || (WriterStateType = {}));
|
|
13
|
+
/**
|
|
14
|
+
* EraWriter is responsible for writing ERA files.
|
|
15
|
+
*
|
|
16
|
+
* See https://github.com/eth-clients/e2store-format-specs/blob/main/formats/era.md
|
|
17
|
+
*/
|
|
18
|
+
export class EraWriter {
|
|
19
|
+
config;
|
|
20
|
+
path;
|
|
21
|
+
fh;
|
|
22
|
+
eraNumber;
|
|
23
|
+
state;
|
|
24
|
+
constructor(config, path, fh, eraNumber) {
|
|
25
|
+
this.config = config;
|
|
26
|
+
this.path = path;
|
|
27
|
+
this.fh = fh;
|
|
28
|
+
this.eraNumber = eraNumber;
|
|
29
|
+
this.state = {
|
|
30
|
+
type: WriterStateType.InitGroup,
|
|
31
|
+
eraNumber,
|
|
32
|
+
currentOffset: 0,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
static async create(config, path, eraNumber) {
|
|
36
|
+
const fh = await open(path, "w");
|
|
37
|
+
return new EraWriter(config, path, fh, eraNumber);
|
|
38
|
+
}
|
|
39
|
+
async finish() {
|
|
40
|
+
if (this.state.type !== WriterStateType.FinishedGroup) {
|
|
41
|
+
throw new Error("Writer has not been finished");
|
|
42
|
+
}
|
|
43
|
+
await this.fh.close();
|
|
44
|
+
const pathParts = parse(this.path);
|
|
45
|
+
const newPath = format({
|
|
46
|
+
...pathParts,
|
|
47
|
+
base: `${this.config.CONFIG_NAME}-${String(this.eraNumber).padStart(5, "0")}-${this.state.shortHistoricalRoot}.era`,
|
|
48
|
+
});
|
|
49
|
+
await rename(this.path, newPath);
|
|
50
|
+
return newPath;
|
|
51
|
+
}
|
|
52
|
+
async writeVersion() {
|
|
53
|
+
if (this.state.type === WriterStateType.FinishedGroup) {
|
|
54
|
+
this.state = {
|
|
55
|
+
type: WriterStateType.InitGroup,
|
|
56
|
+
eraNumber: this.state.eraNumber + 1,
|
|
57
|
+
currentOffset: this.state.currentOffset,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
if (this.state.type !== WriterStateType.InitGroup) {
|
|
61
|
+
throw new Error("Writer has already been initialized");
|
|
62
|
+
}
|
|
63
|
+
await writeEntry(this.fh, this.state.currentOffset, EntryType.Version, new Uint8Array(0));
|
|
64
|
+
// Move to writing blocks/state
|
|
65
|
+
this.state = {
|
|
66
|
+
type: WriterStateType.WriteGroup,
|
|
67
|
+
eraNumber: this.state.eraNumber,
|
|
68
|
+
currentOffset: this.state.currentOffset + E2STORE_HEADER_SIZE,
|
|
69
|
+
blockOffsets: [],
|
|
70
|
+
lastSlot: computeStartBlockSlotFromEraNumber(this.state.eraNumber) - 1,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
async writeCompressedState(slot, shortHistoricalRoot, data) {
|
|
74
|
+
if (this.state.type === WriterStateType.InitGroup) {
|
|
75
|
+
await this.writeVersion();
|
|
76
|
+
}
|
|
77
|
+
if (this.state.type !== WriterStateType.WriteGroup) {
|
|
78
|
+
throw new Error("unreachable");
|
|
79
|
+
}
|
|
80
|
+
const expectedSlot = this.state.eraNumber * SLOTS_PER_HISTORICAL_ROOT;
|
|
81
|
+
if (!isValidEraStateSlot(slot, this.state.eraNumber)) {
|
|
82
|
+
throw new Error(`State slot must be ${expectedSlot} for era ${this.eraNumber}, got ${slot}`);
|
|
83
|
+
}
|
|
84
|
+
for (let s = this.state.lastSlot + 1; s < slot; s++) {
|
|
85
|
+
this.state.blockOffsets.push(0); // Empty slot
|
|
86
|
+
}
|
|
87
|
+
const stateOffset = this.state.currentOffset;
|
|
88
|
+
await writeEntry(this.fh, this.state.currentOffset, EntryType.CompressedBeaconState, data);
|
|
89
|
+
this.state.currentOffset += E2STORE_HEADER_SIZE + data.length;
|
|
90
|
+
if (this.state.eraNumber !== 0) {
|
|
91
|
+
const blocksIndex = {
|
|
92
|
+
type: EntryType.SlotIndex,
|
|
93
|
+
startSlot: computeStartBlockSlotFromEraNumber(this.state.eraNumber),
|
|
94
|
+
offsets: this.state.blockOffsets.map((o) => o - this.state.currentOffset),
|
|
95
|
+
recordStart: this.state.currentOffset,
|
|
96
|
+
};
|
|
97
|
+
const blocksIndexPayload = serializeSlotIndex(blocksIndex);
|
|
98
|
+
await writeEntry(this.fh, this.state.currentOffset, EntryType.SlotIndex, blocksIndexPayload);
|
|
99
|
+
this.state.currentOffset += E2STORE_HEADER_SIZE + blocksIndexPayload.length;
|
|
100
|
+
}
|
|
101
|
+
const stateIndex = {
|
|
102
|
+
type: EntryType.SlotIndex,
|
|
103
|
+
startSlot: slot,
|
|
104
|
+
offsets: [stateOffset - this.state.currentOffset],
|
|
105
|
+
recordStart: this.state.currentOffset,
|
|
106
|
+
};
|
|
107
|
+
const stateIndexPayload = serializeSlotIndex(stateIndex);
|
|
108
|
+
await writeEntry(this.fh, this.state.currentOffset, EntryType.SlotIndex, stateIndexPayload);
|
|
109
|
+
this.state.currentOffset += E2STORE_HEADER_SIZE + stateIndexPayload.length;
|
|
110
|
+
this.state = {
|
|
111
|
+
type: WriterStateType.FinishedGroup,
|
|
112
|
+
eraNumber: this.state.eraNumber,
|
|
113
|
+
currentOffset: this.state.currentOffset,
|
|
114
|
+
shortHistoricalRoot,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
async writeSerializedState(slot, shortHistoricalRoot, data) {
|
|
118
|
+
const compressed = await snappyCompress(data);
|
|
119
|
+
await this.writeCompressedState(slot, shortHistoricalRoot, compressed);
|
|
120
|
+
}
|
|
121
|
+
async writeState(state) {
|
|
122
|
+
const slot = state.slot;
|
|
123
|
+
const shortHistoricalRoot = getShortHistoricalRoot(this.config, state);
|
|
124
|
+
const ssz = this.config.getForkTypes(slot).BeaconState.serialize(state);
|
|
125
|
+
await this.writeSerializedState(slot, shortHistoricalRoot, ssz);
|
|
126
|
+
}
|
|
127
|
+
async writeCompressedBlock(slot, data) {
|
|
128
|
+
if (this.state.type === WriterStateType.InitGroup) {
|
|
129
|
+
await this.writeVersion();
|
|
130
|
+
}
|
|
131
|
+
if (this.state.type !== WriterStateType.WriteGroup) {
|
|
132
|
+
throw new Error("Cannot write blocks after writing canonical state");
|
|
133
|
+
}
|
|
134
|
+
if (this.eraNumber === 0) {
|
|
135
|
+
throw new Error("Genesis era (era 0) does not contain blocks");
|
|
136
|
+
}
|
|
137
|
+
const blockEra = this.state.eraNumber;
|
|
138
|
+
if (!isSlotInRange(slot, blockEra)) {
|
|
139
|
+
throw new Error(`Slot ${slot} is not in valid block range for era ${blockEra}`);
|
|
140
|
+
}
|
|
141
|
+
if (slot <= this.state.lastSlot) {
|
|
142
|
+
throw new Error(`Slots must be written in ascending order. Last slot: ${this.state.lastSlot}, got: ${slot}`);
|
|
143
|
+
}
|
|
144
|
+
for (let s = this.state.lastSlot + 1; s < slot; s++) {
|
|
145
|
+
this.state.blockOffsets.push(0); // Empty slot
|
|
146
|
+
}
|
|
147
|
+
await writeEntry(this.fh, this.state.currentOffset, EntryType.CompressedSignedBeaconBlock, data);
|
|
148
|
+
this.state.blockOffsets.push(this.state.currentOffset);
|
|
149
|
+
this.state.currentOffset += E2STORE_HEADER_SIZE + data.length;
|
|
150
|
+
this.state.lastSlot = slot;
|
|
151
|
+
}
|
|
152
|
+
async writeSerializedBlock(slot, data) {
|
|
153
|
+
const compressed = await snappyCompress(data);
|
|
154
|
+
await this.writeCompressedBlock(slot, compressed);
|
|
155
|
+
}
|
|
156
|
+
async writeBlock(block) {
|
|
157
|
+
const slot = block.message.slot;
|
|
158
|
+
const types = this.config.getForkTypes(slot);
|
|
159
|
+
const ssz = types.SignedBeaconBlock.serialize(block);
|
|
160
|
+
await this.writeSerializedBlock(slot, ssz);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=writer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writer.js","sourceRoot":"","sources":["../../src/era/writer.ts"],"names":[],"mappings":"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"}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAChC,OAAO,KAAK,GAAG,MAAM,gBAAgB,CAAC"}
|
package/lib/index.js
ADDED
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAChC,OAAO,KAAK,GAAG,MAAM,gBAAgB,CAAC"}
|
package/lib/util.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** Read 48-bit signed integer (little-endian) at offset. */
|
|
2
|
+
export declare function readInt48(bytes: Uint8Array, offset: number): number;
|
|
3
|
+
/** Read 48-bit unsigned integer (little-endian) at offset. */
|
|
4
|
+
export declare function readUint48(bytes: Uint8Array, offset: number): number;
|
|
5
|
+
/** Read 16-bit unsigned integer (little-endian) at offset. */
|
|
6
|
+
export declare function readUint16(bytes: Uint8Array, offset: number): number;
|
|
7
|
+
/** Read 32-bit unsigned integer (little-endian) at offset. */
|
|
8
|
+
export declare function readUint32(bytes: Uint8Array, offset: number): number;
|
|
9
|
+
/** Write 48-bit signed integer (little-endian) into target at offset. */
|
|
10
|
+
export declare function writeInt48(target: Uint8Array, offset: number, v: number): void;
|
|
11
|
+
/** Write 16-bit unsigned integer (little-endian) into target at offset. */
|
|
12
|
+
export declare function writeUint16(target: Uint8Array, offset: number, v: number): void;
|
|
13
|
+
/** Write 32-bit unsigned integer (little-endian) into target at offset. */
|
|
14
|
+
export declare function writeUint32(target: Uint8Array, offset: number, v: number): void;
|
|
15
|
+
/** Decompress snappy-framed data */
|
|
16
|
+
export declare function snappyUncompress(compressedData: Uint8Array): Uint8Array;
|
|
17
|
+
/** Compress data using snappy framing */
|
|
18
|
+
export declare function snappyCompress(data: Uint8Array): Promise<Uint8Array>;
|
|
19
|
+
//# sourceMappingURL=util.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAGA,4DAA4D;AAC5D,wBAAgB,SAAS,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAEnE;AAED,8DAA8D;AAC9D,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAEpE;AAED,8DAA8D;AAC9D,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAEpE;AAED,8DAA8D;AAC9D,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAEpE;AAED,yEAAyE;AACzE,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAE9E;AAED,2EAA2E;AAC3E,wBAAgB,WAAW,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAE/E;AAED,2EAA2E;AAC3E,wBAAgB,WAAW,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAE/E;AAED,qCAAqC;AACrC,wBAAgB,gBAAgB,CAAC,cAAc,EAAE,UAAU,GAAG,UAAU,CAWvE;AAED,yCAAyC;AACzC,wBAAsB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAM1E"}
|
package/lib/util.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Uint8ArrayList } from "uint8arraylist";
|
|
2
|
+
import { SnappyFramesUncompress, encodeSnappy } from "@lodestar/reqresp/utils";
|
|
3
|
+
/** Read 48-bit signed integer (little-endian) at offset. */
|
|
4
|
+
export function readInt48(bytes, offset) {
|
|
5
|
+
return Buffer.prototype.readIntLE.call(bytes, offset, 6);
|
|
6
|
+
}
|
|
7
|
+
/** Read 48-bit unsigned integer (little-endian) at offset. */
|
|
8
|
+
export function readUint48(bytes, offset) {
|
|
9
|
+
return Buffer.prototype.readUintLE.call(bytes, offset, 6);
|
|
10
|
+
}
|
|
11
|
+
/** Read 16-bit unsigned integer (little-endian) at offset. */
|
|
12
|
+
export function readUint16(bytes, offset) {
|
|
13
|
+
return Buffer.prototype.readUint16LE.call(bytes, offset);
|
|
14
|
+
}
|
|
15
|
+
/** Read 32-bit unsigned integer (little-endian) at offset. */
|
|
16
|
+
export function readUint32(bytes, offset) {
|
|
17
|
+
return Buffer.prototype.readUint32LE.call(bytes, offset);
|
|
18
|
+
}
|
|
19
|
+
/** Write 48-bit signed integer (little-endian) into target at offset. */
|
|
20
|
+
export function writeInt48(target, offset, v) {
|
|
21
|
+
Buffer.prototype.writeIntLE.call(target, v, offset, 6);
|
|
22
|
+
}
|
|
23
|
+
/** Write 16-bit unsigned integer (little-endian) into target at offset. */
|
|
24
|
+
export function writeUint16(target, offset, v) {
|
|
25
|
+
Buffer.prototype.writeUint16LE.call(target, v, offset);
|
|
26
|
+
}
|
|
27
|
+
/** Write 32-bit unsigned integer (little-endian) into target at offset. */
|
|
28
|
+
export function writeUint32(target, offset, v) {
|
|
29
|
+
Buffer.prototype.writeUint32LE.call(target, v, offset);
|
|
30
|
+
}
|
|
31
|
+
/** Decompress snappy-framed data */
|
|
32
|
+
export function snappyUncompress(compressedData) {
|
|
33
|
+
const decompressor = new SnappyFramesUncompress();
|
|
34
|
+
const input = new Uint8ArrayList(compressedData);
|
|
35
|
+
const result = decompressor.uncompress(input);
|
|
36
|
+
if (result === null) {
|
|
37
|
+
throw new Error("Snappy decompression failed - no data returned");
|
|
38
|
+
}
|
|
39
|
+
return result.subarray();
|
|
40
|
+
}
|
|
41
|
+
/** Compress data using snappy framing */
|
|
42
|
+
export async function snappyCompress(data) {
|
|
43
|
+
const buffers = [];
|
|
44
|
+
for await (const chunk of encodeSnappy(Buffer.from(data.buffer, data.byteOffset, data.byteLength))) {
|
|
45
|
+
buffers.push(chunk);
|
|
46
|
+
}
|
|
47
|
+
return Buffer.concat(buffers);
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=util.js.map
|