@dignetwork/dig-sdk 0.0.1-alpha.4 → 0.0.1-alpha.6

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.
@@ -0,0 +1,160 @@
1
+ import { MerkleTree } from "merkletreejs";
2
+ import { Readable } from "stream";
3
+ export interface DataIntegrityTreeOptions {
4
+ storeDir?: string;
5
+ storageMode?: "local" | "unified";
6
+ rootHash?: string;
7
+ disableInitialize?: boolean;
8
+ }
9
+ /**
10
+ * DataStoreManager class to manage Merkle tree operations.
11
+ */
12
+ declare class DataIntegrityTree {
13
+ private storeId;
14
+ private storeBaseDir;
15
+ private storeDir;
16
+ private dataDir;
17
+ files: Map<string, {
18
+ hash: string;
19
+ sha256: string;
20
+ }>;
21
+ private tree;
22
+ constructor(storeId: string, options?: DataIntegrityTreeOptions);
23
+ static from(storeId: string, options: DataIntegrityTreeOptions): DataIntegrityTree;
24
+ /**
25
+ * Load the manifest file.
26
+ * @private
27
+ */
28
+ private _loadManifest;
29
+ /**
30
+ * Load the latest tree from the manifest file.
31
+ * @private
32
+ */
33
+ private _loadLatestTree;
34
+ /**
35
+ * Save a binary stream to the store's data directory.
36
+ * @param sha256 - The SHA-256 hash of the buffer.
37
+ * @returns The write stream for the file.
38
+ */
39
+ private _createWriteStream;
40
+ /**
41
+ * Stream file from one path to another.
42
+ * @param src - The source file path.
43
+ * @param dest - The destination file path.
44
+ */
45
+ private _streamFile;
46
+ /**
47
+ * Upsert a key with a binary stream to the Merkle tree.
48
+ * Compresses the file, calculates the SHA-256 of the uncompressed file, and stores it.
49
+ * @param readStream - The binary data stream.
50
+ * @param key - The hexadecimal key for the binary data.
51
+ */
52
+ upsertKey(readStream: Readable, key: string): Promise<void>;
53
+ /**
54
+ * Delete a key from the Merkle tree.
55
+ * @param key - The hexadecimal key to delete.
56
+ */
57
+ deleteKey(key: string): void;
58
+ /**
59
+ * List all keys in the Merkle tree.
60
+ * @param rootHash - The root hash of the tree. Defaults to the latest root hash.
61
+ * @returns The list of keys.
62
+ */
63
+ listKeys(rootHash?: string | null): string[];
64
+ /**
65
+ * Rebuild the Merkle tree from the current files.
66
+ * @private
67
+ */
68
+ private _rebuildTree;
69
+ /**
70
+ * Get the root of the Merkle tree.
71
+ * @param rootHash - The root hash of the tree. Defaults to the latest root hash.
72
+ * @returns The Merkle root.
73
+ */
74
+ getRoot(): string;
75
+ /**
76
+ * Serialize the Merkle tree to a JSON object.
77
+ * @param rootHash - The root hash of the tree. Defaults to the latest root hash.
78
+ * @returns The serialized Merkle tree.
79
+ */
80
+ serialize(rootHash?: string | null): object;
81
+ /**
82
+ * Deserialize a JSON object to a Merkle tree.
83
+ * @param rootHash - The root hash of the tree.
84
+ * @returns The deserialized Merkle tree.
85
+ */
86
+ deserializeTree(rootHash: string): MerkleTree;
87
+ private appendRootHashToManifest;
88
+ /**
89
+ * Commit the current state of the Merkle tree.
90
+ */
91
+ commit(): string | undefined;
92
+ /**
93
+ * Clear pending changes and revert to the latest committed state.
94
+ */
95
+ clearPendingRoot(): void;
96
+ /**
97
+ * Check if a file exists for a given key.
98
+ * @param hexKey - The hexadecimal key of the file.
99
+ * @param rootHash - The root hash of the tree. Defaults to the latest root hash.
100
+ * @returns A boolean indicating if the file exists.
101
+ */
102
+ hasKey(hexKey: string, rootHash?: string | null): boolean;
103
+ /**
104
+ * Get a readable stream for a file based on its key, with decompression.
105
+ * @param hexKey - The hexadecimal key of the file.
106
+ * @param rootHash - The root hash of the tree. Defaults to the latest root hash.
107
+ * @returns The readable stream for the file.
108
+ */
109
+ getValueStream(hexKey: string, rootHash?: string | null): Readable;
110
+ /**
111
+ * Delete all leaves from the Merkle tree.
112
+ */
113
+ deleteAllLeaves(): void;
114
+ getSHA256(hexKey: string, rootHash?: string): string | undefined;
115
+ /**
116
+ * Get a proof for a file based on its key and SHA-256 hash.
117
+ * @param hexKey - The hexadecimal key of the file.
118
+ * @param sha256 - The SHA-256 hash of the file.
119
+ * @param rootHash - The root hash of the tree. Defaults to the latest root hash.
120
+ * @returns The proof for the file as a hex string.
121
+ */
122
+ getProof(hexKey: string, sha256: string, rootHash?: string | null): string;
123
+ /**
124
+ * Verify a proof for a file against the Merkle tree.
125
+ * @param proofObjectHex - The proof object as a hex string.
126
+ * @param sha256 - The SHA-256 hash of the file.
127
+ * @returns True if the proof is valid, false otherwise.
128
+ */
129
+ verifyProof(proofObjectHex: string, sha256: string): boolean;
130
+ /**
131
+ * Get the difference between two Merkle tree roots.
132
+ * @param rootHash1 - The first root hash.
133
+ * @param rootHash2 - The second root hash.
134
+ * @returns An object containing the added and deleted keys and their SHA-256 hashes.
135
+ */
136
+ getRootDiff(rootHash1: string, rootHash2: string): {
137
+ added: Map<string, string>;
138
+ deleted: Map<string, string>;
139
+ };
140
+ /**
141
+ * Verify the integrity of a file based on its SHA-256 hash and check if it is in the specified Merkle root.
142
+ * @param sha256 - The SHA-256 hash of the file.
143
+ * @param root - The root hash to check against.
144
+ * @returns True if the file integrity is verified and it is in the Merkle root, false otherwise.
145
+ */
146
+ verifyKeyIntegrity(sha256: string, rootHash: string): Promise<boolean>;
147
+ /**
148
+ * Static method to validate key integrity using a foreign Merkle tree.
149
+ * Verifies if a given SHA-256 hash for a key exists within the foreign tree and checks if the root hash matches.
150
+ *
151
+ * @param key - The hexadecimal key of the file.
152
+ * @param sha256 - The SHA-256 hash of the file.
153
+ * @param serializedTree - The foreign serialized Merkle tree.
154
+ * @param expectedRootHash - The expected root hash of the Merkle tree.
155
+ * @returns A boolean indicating if the SHA-256 is present in the foreign tree and the root hash matches.
156
+ */
157
+ static validateKeyIntegrityWithForeignTree(key: string, sha256: string, serializedTree: object, expectedRootHash: string): boolean;
158
+ }
159
+ export { DataIntegrityTree };
160
+ //# sourceMappingURL=DataIntegrityTree.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DataIntegrityTree.d.ts","sourceRoot":"","sources":["../../src/DataIntegrityTree/DataIntegrityTree.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,648 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.DataIntegrityTree = void 0;
30
+ const fs = __importStar(require("fs"));
31
+ const path = __importStar(require("path"));
32
+ const crypto = __importStar(require("crypto"));
33
+ const zlib = __importStar(require("zlib"));
34
+ const crypto_js_1 = require("crypto-js");
35
+ const merkletreejs_1 = require("merkletreejs");
36
+ const util_1 = require("util");
37
+ const DataLayerError_1 = __importDefault(require("./DataLayerError"));
38
+ const unlink = (0, util_1.promisify)(fs.unlink);
39
+ /**
40
+ * Convert a string to hexadecimal representation.
41
+ * @param str - The input string.
42
+ * @returns The hexadecimal representation of the input string.
43
+ */
44
+ const toHex = (str) => {
45
+ return Buffer.from(str).toString("hex");
46
+ };
47
+ /**
48
+ * Remove empty directories recursively.
49
+ * @param dir - The directory path.
50
+ */
51
+ const removeEmptyDirectories = (dir) => {
52
+ if (fs.existsSync(dir)) {
53
+ const files = fs.readdirSync(dir);
54
+ if (files.length === 0) {
55
+ fs.rmdirSync(dir);
56
+ const parentDir = path.dirname(dir);
57
+ removeEmptyDirectories(parentDir);
58
+ }
59
+ }
60
+ };
61
+ /**
62
+ * Check if a string is a valid hexadecimal string.
63
+ * @param str - The string to validate.
64
+ * @returns True if the string is a valid hex string, false otherwise.
65
+ */
66
+ const isHexString = (str) => {
67
+ return /^[0-9a-fA-F]+$/.test(str) && str.length % 2 === 0;
68
+ };
69
+ /**
70
+ * DataStoreManager class to manage Merkle tree operations.
71
+ */
72
+ class DataIntegrityTree {
73
+ constructor(storeId, options = {}) {
74
+ if (!isHexString(storeId) || storeId.length !== 64) {
75
+ throw new Error("storeId must be a 64 char hex string");
76
+ }
77
+ this.storeId = storeId;
78
+ this.storeBaseDir = options.storeDir || "./";
79
+ if (!fs.existsSync(this.storeBaseDir)) {
80
+ fs.mkdirSync(this.storeBaseDir, { recursive: true });
81
+ }
82
+ if (options.storageMode === "unified") {
83
+ this.dataDir = path.join(this.storeBaseDir, "data");
84
+ }
85
+ else {
86
+ this.dataDir = path.join(this.storeBaseDir, this.storeId, "data");
87
+ }
88
+ this.storeDir = path.join(this.storeBaseDir, this.storeId);
89
+ if (!fs.existsSync(this.storeDir)) {
90
+ fs.mkdirSync(this.storeDir, { recursive: true });
91
+ }
92
+ if (!fs.existsSync(this.dataDir)) {
93
+ fs.mkdirSync(this.dataDir, { recursive: true });
94
+ }
95
+ this.files = new Map();
96
+ if (options.rootHash) {
97
+ const manifest = this._loadManifest();
98
+ if (manifest.includes(options.rootHash)) {
99
+ this.tree = this.deserializeTree(options.rootHash);
100
+ }
101
+ else {
102
+ throw new DataLayerError_1.default(404, `Root hash ${options.rootHash} not found`);
103
+ }
104
+ }
105
+ else {
106
+ this.tree = this._loadLatestTree();
107
+ }
108
+ // Commit the empty Merkle tree immediately upon creation
109
+ if (!options.disableInitialize && this.tree.getLeafCount() === 0) {
110
+ this.commit();
111
+ }
112
+ }
113
+ static from(storeId, options) {
114
+ return new DataIntegrityTree(storeId, { ...options, disableInitialize: true });
115
+ }
116
+ /**
117
+ * Load the manifest file.
118
+ * @private
119
+ */
120
+ _loadManifest() {
121
+ const manifestPath = path.join(this.storeDir, "manifest.dat");
122
+ if (fs.existsSync(manifestPath)) {
123
+ return fs.readFileSync(manifestPath, "utf8").trim().split("\n");
124
+ }
125
+ return [];
126
+ }
127
+ /**
128
+ * Load the latest tree from the manifest file.
129
+ * @private
130
+ */
131
+ _loadLatestTree() {
132
+ const manifest = this._loadManifest();
133
+ if (manifest.length > 0) {
134
+ const latestRootHash = manifest[manifest.length - 1];
135
+ return this.deserializeTree(latestRootHash);
136
+ }
137
+ else {
138
+ return new merkletreejs_1.MerkleTree([], crypto_js_1.SHA256, { sortPairs: true });
139
+ }
140
+ }
141
+ /**
142
+ * Save a binary stream to the store's data directory.
143
+ * @param sha256 - The SHA-256 hash of the buffer.
144
+ * @returns The write stream for the file.
145
+ */
146
+ _createWriteStream(sha256) {
147
+ const subDirs = sha256.match(/.{1,2}/g) || [];
148
+ const fileDir = path.join(this.dataDir, ...subDirs.slice(0, -1));
149
+ const fileName = subDirs[subDirs.length - 1];
150
+ const fileSavePath = path.join(fileDir, fileName);
151
+ if (!fs.existsSync(fileDir)) {
152
+ fs.mkdirSync(fileDir, { recursive: true });
153
+ }
154
+ return fs.createWriteStream(fileSavePath);
155
+ }
156
+ /**
157
+ * Stream file from one path to another.
158
+ * @param src - The source file path.
159
+ * @param dest - The destination file path.
160
+ */
161
+ async _streamFile(src, dest) {
162
+ return new Promise((resolve, reject) => {
163
+ const readStream = fs.createReadStream(src);
164
+ const writeStream = fs.createWriteStream(dest);
165
+ readStream.pipe(writeStream);
166
+ writeStream.on("finish", resolve);
167
+ writeStream.on("error", reject);
168
+ readStream.on("error", reject);
169
+ });
170
+ }
171
+ /**
172
+ * Upsert a key with a binary stream to the Merkle tree.
173
+ * Compresses the file, calculates the SHA-256 of the uncompressed file, and stores it.
174
+ * @param readStream - The binary data stream.
175
+ * @param key - The hexadecimal key for the binary data.
176
+ */
177
+ async upsertKey(readStream, key) {
178
+ if (!isHexString(key)) {
179
+ throw new Error(`key must be a valid hex string: ${key}`);
180
+ }
181
+ const uncompressedHash = crypto.createHash("sha256");
182
+ const gzip = zlib.createGzip();
183
+ let sha256;
184
+ const tempDir = path.join(this.storeDir, "tmp");
185
+ if (!fs.existsSync(tempDir)) {
186
+ fs.mkdirSync(tempDir, { recursive: true });
187
+ }
188
+ const tempFilePath = path.join(tempDir, `${crypto.randomUUID()}.gz`);
189
+ return new Promise((resolve, reject) => {
190
+ const tempWriteStream = fs.createWriteStream(tempFilePath);
191
+ readStream.on("data", (chunk) => {
192
+ uncompressedHash.update(chunk);
193
+ });
194
+ readStream.pipe(gzip).pipe(tempWriteStream);
195
+ tempWriteStream.on("finish", async () => {
196
+ sha256 = uncompressedHash.digest("hex");
197
+ const finalWriteStream = this._createWriteStream(sha256);
198
+ const finalPath = finalWriteStream.path;
199
+ // Ensure the directory exists before copying the file
200
+ const finalDir = path.dirname(finalPath);
201
+ if (!fs.existsSync(finalDir)) {
202
+ fs.mkdirSync(finalDir, { recursive: true });
203
+ }
204
+ try {
205
+ await this._streamFile(tempFilePath, finalPath);
206
+ await unlink(tempFilePath);
207
+ const combinedHash = crypto
208
+ .createHash("sha256")
209
+ .update(`${key}/${sha256}`)
210
+ .digest("hex");
211
+ if (Array.from(this.files.values()).some((file) => file.hash === combinedHash)) {
212
+ console.log(`No changes detected for key: ${key}`);
213
+ return resolve();
214
+ }
215
+ if (this.files.has(key)) {
216
+ this.deleteKey(key);
217
+ }
218
+ console.log(`Inserted key: ${key}`);
219
+ this.files.set(key, {
220
+ hash: combinedHash,
221
+ sha256: sha256,
222
+ });
223
+ this._rebuildTree();
224
+ resolve();
225
+ }
226
+ catch (err) {
227
+ reject(err);
228
+ }
229
+ });
230
+ tempWriteStream.on("error", (err) => {
231
+ reject(err);
232
+ });
233
+ readStream.on("error", (err) => {
234
+ reject(err);
235
+ });
236
+ });
237
+ }
238
+ /**
239
+ * Delete a key from the Merkle tree.
240
+ * @param key - The hexadecimal key to delete.
241
+ */
242
+ deleteKey(key) {
243
+ if (!isHexString(key)) {
244
+ throw new Error("key must be a valid hex string");
245
+ }
246
+ if (this.files.has(key)) {
247
+ this.files.delete(key);
248
+ this._rebuildTree();
249
+ console.log(`Deleted key: ${key}`);
250
+ }
251
+ }
252
+ /**
253
+ * List all keys in the Merkle tree.
254
+ * @param rootHash - The root hash of the tree. Defaults to the latest root hash.
255
+ * @returns The list of keys.
256
+ */
257
+ listKeys(rootHash = null) {
258
+ if (rootHash && !isHexString(rootHash)) {
259
+ throw new Error("rootHash must be a valid hex string");
260
+ }
261
+ if (rootHash) {
262
+ const tree = this.deserializeTree(rootHash);
263
+ // @ts-ignore
264
+ return Array.from(tree.files.keys());
265
+ }
266
+ return Array.from(this.files.keys());
267
+ }
268
+ /**
269
+ * Rebuild the Merkle tree from the current files.
270
+ * @private
271
+ */
272
+ _rebuildTree() {
273
+ const leaves = Array.from(this.files.values()).map(({ hash }) => Buffer.from(hash, "hex"));
274
+ this.tree = new merkletreejs_1.MerkleTree(leaves, crypto_js_1.SHA256, { sortPairs: true });
275
+ }
276
+ /**
277
+ * Get the root of the Merkle tree.
278
+ * @param rootHash - The root hash of the tree. Defaults to the latest root hash.
279
+ * @returns The Merkle root.
280
+ */
281
+ getRoot() {
282
+ return this.tree.getRoot().toString("hex");
283
+ }
284
+ /**
285
+ * Serialize the Merkle tree to a JSON object.
286
+ * @param rootHash - The root hash of the tree. Defaults to the latest root hash.
287
+ * @returns The serialized Merkle tree.
288
+ */
289
+ serialize(rootHash = null) {
290
+ if (rootHash && !isHexString(rootHash)) {
291
+ throw new Error("rootHash must be a valid hex string");
292
+ }
293
+ if (rootHash) {
294
+ const tree = this.deserializeTree(rootHash);
295
+ return {
296
+ root: tree.getRoot().toString("hex"),
297
+ leaves: tree.getLeaves().map((leaf) => leaf.toString("hex")),
298
+ // @ts-ignore
299
+ files: Object.fromEntries(tree.files),
300
+ };
301
+ }
302
+ return {
303
+ root: this.getRoot(),
304
+ leaves: this.tree.getLeaves().map((leaf) => leaf.toString("hex")),
305
+ files: Object.fromEntries(this.files),
306
+ };
307
+ }
308
+ /**
309
+ * Deserialize a JSON object to a Merkle tree.
310
+ * @param rootHash - The root hash of the tree.
311
+ * @returns The deserialized Merkle tree.
312
+ */
313
+ deserializeTree(rootHash) {
314
+ if (!isHexString(rootHash)) {
315
+ throw new Error("rootHash must be a valid hex string");
316
+ }
317
+ const treeFilePath = path.join(this.storeDir, `${rootHash}.dat`);
318
+ if (!fs.existsSync(treeFilePath)) {
319
+ throw new Error(`Tree file ${treeFilePath} does not exist`);
320
+ }
321
+ const data = JSON.parse(fs.readFileSync(treeFilePath, "utf8"));
322
+ const leaves = data.leaves.map((leaf) => Buffer.from(leaf, "hex"));
323
+ const tree = new merkletreejs_1.MerkleTree(leaves, crypto_js_1.SHA256, { sortPairs: true });
324
+ // @ts-ignore
325
+ tree.files = new Map(Object.entries(data.files).map(([key, value]) => [
326
+ key,
327
+ { hash: value.hash, sha256: value.sha256 },
328
+ ]));
329
+ // @ts-ignore
330
+ this.files = tree.files;
331
+ return tree;
332
+ }
333
+ appendRootHashToManifest(rootHash) {
334
+ const manifestPath = path.join(this.storeDir, "manifest.dat");
335
+ // Read the current manifest file
336
+ const manifestContent = fs.existsSync(manifestPath)
337
+ ? fs.readFileSync(manifestPath, "utf-8").trim().split("\n")
338
+ : [];
339
+ // Check if the last entry is the same as the rootHash to avoid duplicates
340
+ const latestRootHash = manifestContent.length > 0 ? manifestContent[manifestContent.length - 1] : null;
341
+ if (latestRootHash !== rootHash) {
342
+ // Append the new rootHash if it is not the same as the last one
343
+ fs.appendFileSync(manifestPath, `${rootHash}\n`);
344
+ }
345
+ else {
346
+ console.log(`Root hash ${rootHash} is already at the end of the file. Skipping append.`);
347
+ }
348
+ }
349
+ /**
350
+ * Commit the current state of the Merkle tree.
351
+ */
352
+ commit() {
353
+ const emptyRootHash = "0000000000000000000000000000000000000000000000000000000000000000";
354
+ const rootHash = this.tree.getLeafCount() === 0 ? emptyRootHash : this.getRoot();
355
+ const manifest = this._loadManifest();
356
+ const latestRootHash = manifest.length > 0 ? manifest[manifest.length - 1] : null;
357
+ if (rootHash === latestRootHash && rootHash !== emptyRootHash) {
358
+ console.log("No changes to commit. Aborting commit.");
359
+ return undefined;
360
+ }
361
+ this.appendRootHashToManifest(rootHash);
362
+ const treeFilePath = path.join(this.storeDir, `${rootHash}.dat`);
363
+ if (!fs.existsSync(path.dirname(treeFilePath))) {
364
+ fs.mkdirSync(path.dirname(treeFilePath), { recursive: true });
365
+ }
366
+ const serializedTree = this.serialize();
367
+ if (rootHash === emptyRootHash) {
368
+ serializedTree.root = emptyRootHash;
369
+ }
370
+ fs.writeFileSync(treeFilePath, JSON.stringify(serializedTree));
371
+ console.log(`Committed new root`);
372
+ console.log(this.tree.toString());
373
+ return rootHash;
374
+ }
375
+ /**
376
+ * Clear pending changes and revert to the latest committed state.
377
+ */
378
+ clearPendingRoot() {
379
+ this.tree = this._loadLatestTree();
380
+ }
381
+ /**
382
+ * Check if a file exists for a given key.
383
+ * @param hexKey - The hexadecimal key of the file.
384
+ * @param rootHash - The root hash of the tree. Defaults to the latest root hash.
385
+ * @returns A boolean indicating if the file exists.
386
+ */
387
+ hasKey(hexKey, rootHash = null) {
388
+ if (!isHexString(hexKey)) {
389
+ throw new Error("key must be a valid hex string");
390
+ }
391
+ if (rootHash && !isHexString(rootHash)) {
392
+ throw new Error("rootHash must be a valid hex string");
393
+ }
394
+ let sha256;
395
+ if (rootHash) {
396
+ const tree = this.deserializeTree(rootHash);
397
+ // @ts-ignore
398
+ sha256 = tree.files.get(hexKey)?.sha256;
399
+ }
400
+ else {
401
+ sha256 = this.files.get(hexKey)?.sha256;
402
+ }
403
+ if (!sha256) {
404
+ return false;
405
+ }
406
+ const filePath = path.join(this.dataDir, sha256.match(/.{1,2}/g).join("/"));
407
+ // Check if the file exists at the calculated path
408
+ return fs.existsSync(filePath);
409
+ }
410
+ /**
411
+ * Get a readable stream for a file based on its key, with decompression.
412
+ * @param hexKey - The hexadecimal key of the file.
413
+ * @param rootHash - The root hash of the tree. Defaults to the latest root hash.
414
+ * @returns The readable stream for the file.
415
+ */
416
+ getValueStream(hexKey, rootHash = null) {
417
+ if (!isHexString(hexKey)) {
418
+ throw new Error("key must be a valid hex string");
419
+ }
420
+ if (rootHash && !isHexString(rootHash)) {
421
+ throw new Error("rootHash must be a valid hex string");
422
+ }
423
+ let sha256;
424
+ if (rootHash) {
425
+ const tree = this.deserializeTree(rootHash);
426
+ // @ts-ignore
427
+ sha256 = tree.files.get(hexKey)?.sha256;
428
+ }
429
+ else {
430
+ sha256 = this.files.get(hexKey)?.sha256;
431
+ }
432
+ if (!sha256) {
433
+ throw new Error(`File with key ${hexKey} not found.`);
434
+ }
435
+ const filePath = path.join(this.dataDir, sha256.match(/.{1,2}/g).join("/"));
436
+ if (!fs.existsSync(filePath)) {
437
+ throw new Error(`File at path ${filePath} does not exist`);
438
+ }
439
+ // Create a read stream and pipe it through a decompression stream using the same algorithm (gzip)
440
+ const readStream = fs.createReadStream(filePath);
441
+ const decompressStream = zlib.createGunzip();
442
+ // Return the combined stream as a generic Readable stream
443
+ return readStream.pipe(decompressStream);
444
+ }
445
+ /**
446
+ * Delete all leaves from the Merkle tree.
447
+ */
448
+ deleteAllLeaves() {
449
+ this.files.clear();
450
+ this._rebuildTree();
451
+ }
452
+ getSHA256(hexKey, rootHash) {
453
+ if (!rootHash) {
454
+ return this.files.get(hexKey)?.sha256;
455
+ }
456
+ const tree = this.deserializeTree(rootHash);
457
+ // @ts-ignore
458
+ return tree.files.get(hexKey)?.sha256;
459
+ }
460
+ /**
461
+ * Get a proof for a file based on its key and SHA-256 hash.
462
+ * @param hexKey - The hexadecimal key of the file.
463
+ * @param sha256 - The SHA-256 hash of the file.
464
+ * @param rootHash - The root hash of the tree. Defaults to the latest root hash.
465
+ * @returns The proof for the file as a hex string.
466
+ */
467
+ getProof(hexKey, sha256, rootHash = null) {
468
+ if (!isHexString(hexKey)) {
469
+ throw new Error("key must be a valid hex string");
470
+ }
471
+ if (!isHexString(sha256)) {
472
+ throw new Error("sha256 must be a valid hex string");
473
+ }
474
+ if (rootHash && !isHexString(rootHash)) {
475
+ throw new Error("rootHash must be a valid hex string");
476
+ }
477
+ if (!rootHash) {
478
+ const manifest = this._loadManifest();
479
+ rootHash = manifest[manifest.length - 1];
480
+ }
481
+ const tree = this.deserializeTree(rootHash);
482
+ const combinedHash = (0, crypto_js_1.SHA256)(`${hexKey}/${sha256}`).toString();
483
+ const leaf = Buffer.from(combinedHash, "hex");
484
+ const proof = tree.getProof(leaf);
485
+ // Convert the proof to a single hex string
486
+ const proofHex = proof.map((p) => p.data.toString("hex")).join("");
487
+ // Create an object with the key, rootHash, and proofHex
488
+ const proofObject = {
489
+ key: hexKey,
490
+ rootHash: rootHash,
491
+ proof: proofHex,
492
+ };
493
+ // Convert the proofObject to JSON and then to a hex string
494
+ const proofObjectHex = Buffer.from(JSON.stringify(proofObject)).toString("hex");
495
+ return proofObjectHex;
496
+ }
497
+ /**
498
+ * Verify a proof for a file against the Merkle tree.
499
+ * @param proofObjectHex - The proof object as a hex string.
500
+ * @param sha256 - The SHA-256 hash of the file.
501
+ * @returns True if the proof is valid, false otherwise.
502
+ */
503
+ verifyProof(proofObjectHex, sha256) {
504
+ if (!isHexString(proofObjectHex)) {
505
+ throw new Error("proofObjectHex must be a valid hex string");
506
+ }
507
+ if (!isHexString(sha256)) {
508
+ throw new Error("sha256 must be a valid hex string");
509
+ }
510
+ // Convert the proofObjectHex back to a proof object
511
+ const proofObject = JSON.parse(Buffer.from(proofObjectHex, "hex").toString("utf8"));
512
+ const { key, rootHash, proof } = proofObject;
513
+ const tree = this.deserializeTree(rootHash);
514
+ const combinedHash = (0, crypto_js_1.SHA256)(`${key}/${sha256}`).toString();
515
+ const leaf = Buffer.from(combinedHash, "hex");
516
+ // Convert the proofHex string back to the proof array
517
+ const proofBufferArray = [];
518
+ for (let i = 0; i < proof.length; i += 64) {
519
+ proofBufferArray.push(Buffer.from(proof.slice(i, i + 64), "hex"));
520
+ }
521
+ const proofArray = proofBufferArray.map((data) => ({ data }));
522
+ return tree.verify(proofArray, leaf, Buffer.from(rootHash, "hex"));
523
+ }
524
+ /**
525
+ * Get the difference between two Merkle tree roots.
526
+ * @param rootHash1 - The first root hash.
527
+ * @param rootHash2 - The second root hash.
528
+ * @returns An object containing the added and deleted keys and their SHA-256 hashes.
529
+ */
530
+ getRootDiff(rootHash1, rootHash2) {
531
+ if (!isHexString(rootHash1) || !isHexString(rootHash2)) {
532
+ throw new Error("rootHash1 and rootHash2 must be valid hex strings");
533
+ }
534
+ const tree1 = this.deserializeTree(rootHash1);
535
+ const tree2 = this.deserializeTree(rootHash2);
536
+ // @ts-ignore
537
+ const files1 = tree1.files;
538
+ // @ts-ignore
539
+ const files2 = tree2.files;
540
+ const added = new Map();
541
+ const deleted = new Map();
542
+ files1.forEach((value, key) => {
543
+ if (!files2.has(key)) {
544
+ deleted.set(key, value.sha256);
545
+ }
546
+ });
547
+ files2.forEach((value, key) => {
548
+ if (!files1.has(key)) {
549
+ added.set(key, value.sha256);
550
+ }
551
+ });
552
+ return { added, deleted };
553
+ }
554
+ /**
555
+ * Verify the integrity of a file based on its SHA-256 hash and check if it is in the specified Merkle root.
556
+ * @param sha256 - The SHA-256 hash of the file.
557
+ * @param root - The root hash to check against.
558
+ * @returns True if the file integrity is verified and it is in the Merkle root, false otherwise.
559
+ */
560
+ async verifyKeyIntegrity(sha256, rootHash) {
561
+ if (!isHexString(sha256)) {
562
+ throw new Error("sha256 must be a valid hex string");
563
+ }
564
+ if (!isHexString(rootHash)) {
565
+ throw new Error("rootHash must be a valid hex string");
566
+ }
567
+ const filePath = path.join(this.dataDir, sha256.match(/.{1,2}/g).join("/"));
568
+ if (!fs.existsSync(filePath)) {
569
+ throw new Error(`File at path ${filePath} does not exist`);
570
+ }
571
+ const compressedReadStream = fs.createReadStream(filePath);
572
+ const decompressStream = zlib.createGunzip();
573
+ const hash = crypto.createHash("sha256");
574
+ return new Promise((resolve, reject) => {
575
+ compressedReadStream.pipe(decompressStream);
576
+ decompressStream.on("data", (chunk) => {
577
+ hash.update(chunk);
578
+ });
579
+ decompressStream.on("end", () => {
580
+ const uncompressedSha256 = hash.digest("hex");
581
+ const isValid = uncompressedSha256 === sha256;
582
+ console.log(`SHA-256 of uncompressed file: ${uncompressedSha256}`);
583
+ if (!isValid) {
584
+ return resolve(false);
585
+ }
586
+ const tree = this.deserializeTree(rootHash);
587
+ const combinedHash = crypto
588
+ .createHash("sha256")
589
+ .update(`${toHex(sha256)}/${sha256}`)
590
+ .digest("hex");
591
+ const leaf = Buffer.from(combinedHash, "hex");
592
+ const isInTree = tree.getLeafIndex(leaf) !== -1;
593
+ resolve(isInTree);
594
+ });
595
+ decompressStream.on("error", (err) => {
596
+ reject(err);
597
+ });
598
+ compressedReadStream.on("error", (err) => {
599
+ reject(err);
600
+ });
601
+ });
602
+ }
603
+ /**
604
+ * Static method to validate key integrity using a foreign Merkle tree.
605
+ * Verifies if a given SHA-256 hash for a key exists within the foreign tree and checks if the root hash matches.
606
+ *
607
+ * @param key - The hexadecimal key of the file.
608
+ * @param sha256 - The SHA-256 hash of the file.
609
+ * @param serializedTree - The foreign serialized Merkle tree.
610
+ * @param expectedRootHash - The expected root hash of the Merkle tree.
611
+ * @returns A boolean indicating if the SHA-256 is present in the foreign tree and the root hash matches.
612
+ */
613
+ static validateKeyIntegrityWithForeignTree(key, sha256, serializedTree, expectedRootHash) {
614
+ if (!isHexString(key)) {
615
+ throw new Error("key must be a valid hex string");
616
+ }
617
+ if (!isHexString(sha256)) {
618
+ throw new Error("sha256 must be a valid hex string");
619
+ }
620
+ if (!isHexString(expectedRootHash)) {
621
+ throw new Error("expectedRootHash must be a valid hex string");
622
+ }
623
+ // Deserialize the foreign tree
624
+ const leaves = serializedTree.leaves.map((leaf) => Buffer.from(leaf, "hex"));
625
+ const tree = new merkletreejs_1.MerkleTree(leaves, crypto_js_1.SHA256, { sortPairs: true });
626
+ // Verify that the deserialized tree's root matches the expected root hash
627
+ const treeRootHash = tree.getRoot().toString("hex");
628
+ if (treeRootHash !== expectedRootHash) {
629
+ console.warn(`Expected root hash ${expectedRootHash}, but got ${treeRootHash}`);
630
+ return false;
631
+ }
632
+ // Rebuild the files map from the serialized tree
633
+ // @ts-ignore
634
+ tree.files = new Map(Object.entries(serializedTree.files).map(([key, value]) => [
635
+ key,
636
+ { hash: value.hash, sha256: value.sha256 },
637
+ ]));
638
+ // Check if the SHA-256 exists in the foreign tree's files
639
+ const combinedHash = crypto
640
+ .createHash("sha256")
641
+ .update(`${toHex(key)}/${sha256}`)
642
+ .digest("hex");
643
+ const leaf = Buffer.from(combinedHash, "hex");
644
+ const isInTree = tree.getLeafIndex(leaf) !== -1;
645
+ return isInTree;
646
+ }
647
+ }
648
+ exports.DataIntegrityTree = DataIntegrityTree;
@@ -0,0 +1,6 @@
1
+ declare class DataLayerError extends Error {
2
+ code: number;
3
+ constructor(code: number, message: string);
4
+ }
5
+ export default DataLayerError;
6
+ //# sourceMappingURL=DataLayerError.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DataLayerError.d.ts","sourceRoot":"","sources":["../../src/DataIntegrityTree/DataLayerError.ts"],"names":[],"mappings":"AAAA,cAAM,cAAe,SAAQ,KAAK;IAC9B,IAAI,EAAE,MAAM,CAAC;gBAED,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAe1C;AAED,eAAe,cAAc,CAAC"}
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ class DataLayerError extends Error {
4
+ constructor(code, message) {
5
+ // Call the parent constructor with the message
6
+ super(message);
7
+ // Set the name of the error to the class name
8
+ this.name = this.constructor.name;
9
+ // Assign the custom code
10
+ this.code = code;
11
+ // Capture the stack trace (if available in the environment)
12
+ if (Error.captureStackTrace) {
13
+ Error.captureStackTrace(this, this.constructor);
14
+ }
15
+ }
16
+ }
17
+ exports.default = DataLayerError;
@@ -0,0 +1,2 @@
1
+ export * from './DataIntegrityTree';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/DataIntegrityTree/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC"}
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./DataIntegrityTree"), exports);
@@ -1 +1 @@
1
- {"version":3,"file":"DigNetwork.d.ts","sourceRoot":"","sources":["../../src/DigNetwork/DigNetwork.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,qBAAa,UAAU;IACrB,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,aAAa,CAA2B;gBAEpC,OAAO,EAAE,MAAM;YAOb,eAAe;IA8ChB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAsDhD,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;WA+BrC,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;WAQtD,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAQ5C,aAAa,CACxB,aAAa,GAAE,OAAe,EAC9B,iBAAiB,GAAE,OAAc,EACjC,QAAQ,GAAE,OAAe,GACxB,OAAO,CAAC,IAAI,CAAC;YAqFF,mBAAmB;YAWnB,kBAAkB;YASlB,oBAAoB;YASpB,qBAAqB;YAuErB,cAAc;CAuB7B"}
1
+ {"version":3,"file":"DigNetwork.d.ts","sourceRoot":"","sources":["../../src/DigNetwork/DigNetwork.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,qBAAa,UAAU;IACrB,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,aAAa,CAA2B;gBAEpC,OAAO,EAAE,MAAM;YAOb,eAAe;IA8ChB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAsDhD,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;WA6BrC,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;WAQtD,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAQ5C,aAAa,CACxB,aAAa,GAAE,OAAe,EAC9B,iBAAiB,GAAE,OAAc,EACjC,QAAQ,GAAE,OAAe,GACxB,OAAO,CAAC,IAAI,CAAC;YAqFF,mBAAmB;YAWnB,kBAAkB;YASlB,oBAAoB;YASpB,qBAAqB;YAuErB,cAAc;CAoB7B"}
@@ -101,7 +101,6 @@ class DigNetwork {
101
101
  async uploadStore(digPeer) {
102
102
  const { generationIndex } = await this.uploadPreflight(digPeer);
103
103
  const filesToUpload = await (0, deltaUtils_1.getDeltaFiles)(this.dataStore.StoreId, generationIndex, path.resolve(config_1.DIG_FOLDER_PATH, "stores"));
104
- console.log(filesToUpload);
105
104
  if (!filesToUpload.length) {
106
105
  console.log("No files to upload.");
107
106
  return;
@@ -246,8 +245,6 @@ class DigNetwork {
246
245
  }
247
246
  async runProgressBar(total, name, task) {
248
247
  // Using 'any' to work around TypeScript issues
249
- const oldConsoleLog = console.log;
250
- console.log = () => { }; // Suppress console.log output
251
248
  const multiBar = new cli_progress_1.MultiBar({
252
249
  clearOnComplete: false,
253
250
  hideCursor: true,
@@ -257,7 +254,6 @@ class DigNetwork {
257
254
  const progress = multiBar.create(total, 0, { name });
258
255
  await task(progress).finally(() => {
259
256
  multiBar.stop();
260
- console.log = oldConsoleLog; // Restore console.log
261
257
  });
262
258
  }
263
259
  }
@@ -9,7 +9,7 @@ const ContentServer_1 = require("./ContentServer");
9
9
  const PropagationServer_1 = require("./PropagationServer");
10
10
  const IncentiveServer_1 = require("./IncentiveServer");
11
11
  const blockchain_1 = require("../blockchain");
12
- const data_integrity_tree_1 = require("@dignetwork/data-integrity-tree");
12
+ const DataIntegrityTree_1 = require("../DataIntegrityTree");
13
13
  const datalayer_driver_1 = require("datalayer-driver");
14
14
  const blockchain_2 = require("../blockchain");
15
15
  const blockchain_3 = require("../blockchain");
@@ -97,7 +97,7 @@ class DigPeer {
97
97
  });
98
98
  });
99
99
  // Perform tree integrity validation using the datFileContent and the root hash
100
- const treeCheck = data_integrity_tree_1.DataIntegrityTree.validateKeyIntegrityWithForeignTree(key, fileData.sha256, datFileContent, rootHash);
100
+ const treeCheck = DataIntegrityTree_1.DataIntegrityTree.validateKeyIntegrityWithForeignTree(key, fileData.sha256, datFileContent, rootHash);
101
101
  if (!treeCheck) {
102
102
  console.error(`Tree validation failed for file ${key}.`);
103
103
  filesIntegrityIntact = false;
@@ -1,6 +1,6 @@
1
1
  import { DataStore as DataStoreDriver, DataStoreMetadata } from "datalayer-driver";
2
2
  import { RootHistoryItem } from "../types";
3
- import { DataIntegrityTree, DataIntegrityTreeOptions } from "@dignetwork/data-integrity-tree";
3
+ import { DataIntegrityTree, DataIntegrityTreeOptions } from "../DataIntegrityTree";
4
4
  import { CreateStoreUserInputs } from "../types";
5
5
  export declare class DataStore {
6
6
  private storeId;
@@ -1 +1 @@
1
- {"version":3,"file":"DataStore.d.ts","sourceRoot":"","sources":["../../src/blockchain/DataStore.ts"],"names":[],"mappings":"AAEA,OAAO,EAOL,SAAS,IAAI,eAAe,EAE5B,iBAAiB,EAIlB,MAAM,kBAAkB,CAAC;AAY1B,OAAO,EAAE,eAAe,EAAW,MAAM,UAAU,CAAC;AAGpD,OAAO,EACL,iBAAiB,EACjB,wBAAwB,EACzB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AASjD,qBAAa,SAAS;IACpB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,IAAI,CAAoB;gBAEpB,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,wBAAwB;IAiB/D,IAAW,OAAO,IAAI,MAAM,CAE3B;IAED,IAAW,IAAI,IAAI,iBAAiB,CAEnC;IAEM,QAAQ,IAAI,MAAM;IAIlB,QAAQ,IAAI,MAAM;IAIlB,SAAS,IAAI,MAAM;WAMN,cAAc,IAAI,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;WAOtD,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS;WAK1C,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;WAYnC,MAAM,CACxB,MAAM,GAAE,qBAA0B,GACjC,OAAO,CAAC,SAAS,CAAC;mBAyCA,IAAI;IA4FzB;;;OAGG;IACU,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC;IAK5C;;;OAGG;WACiB,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC;IAIxD;;;;OAIG;mBACkB,mBAAmB;WAqB1B,YAAY,IAAI,SAAS,EAAE;IAW5B,aAAa,IAAI,OAAO,CAAC;QACpC,WAAW,EAAE,eAAe,CAAC;QAC7B,YAAY,EAAE,MAAM,CAAC;QACrB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;IAyGW,iBAAiB,IAAI,OAAO,CAAC;QACxC,eAAe,EAAE,MAAM,CAAC;QACxB,aAAa,EAAE,MAAM,CAAC;KACvB,CAAC;YA0BY,iBAAiB;IAYlB,cAAc,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;IAsB5C,mBAAmB,IAAI,OAAO,CAAC,eAAe,EAAE,GAAG,SAAS,CAAC;IAiB7D,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC;IA+E5B,WAAW,IAAI,OAAO,CAAC,iBAAiB,CAAC;IAKzC,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC;IAgB5B,uBAAuB,CAClC,kBAAkB,CAAC,EAAE,MAAM,GAC1B,OAAO,CAAC,OAAO,CAAC;IAkBN,cAAc,CACzB,QAAQ,EAAE,iBAAiB,GAC1B,OAAO,CAAC,eAAe,CAAC;IA+Cd,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAiChE,iBAAiB,IAAI,MAAM,EAAE;CAUrC"}
1
+ {"version":3,"file":"DataStore.d.ts","sourceRoot":"","sources":["../../src/blockchain/DataStore.ts"],"names":[],"mappings":"AAEA,OAAO,EAOL,SAAS,IAAI,eAAe,EAE5B,iBAAiB,EAIlB,MAAM,kBAAkB,CAAC;AAY1B,OAAO,EAAE,eAAe,EAAW,MAAM,UAAU,CAAC;AAGpD,OAAO,EACL,iBAAiB,EACjB,wBAAwB,EACzB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AASjD,qBAAa,SAAS;IACpB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,IAAI,CAAoB;gBAEpB,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,wBAAwB;IAiB/D,IAAW,OAAO,IAAI,MAAM,CAE3B;IAED,IAAW,IAAI,IAAI,iBAAiB,CAEnC;IAEM,QAAQ,IAAI,MAAM;IAIlB,QAAQ,IAAI,MAAM;IAIlB,SAAS,IAAI,MAAM;WAMN,cAAc,IAAI,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;WAOtD,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS;WAK1C,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;WAYnC,MAAM,CACxB,MAAM,GAAE,qBAA0B,GACjC,OAAO,CAAC,SAAS,CAAC;mBAyCA,IAAI;IA4FzB;;;OAGG;IACU,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC;IAK5C;;;OAGG;WACiB,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC;IAIxD;;;;OAIG;mBACkB,mBAAmB;WAqB1B,YAAY,IAAI,SAAS,EAAE;IAW5B,aAAa,IAAI,OAAO,CAAC;QACpC,WAAW,EAAE,eAAe,CAAC;QAC7B,YAAY,EAAE,MAAM,CAAC;QACrB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;IAyGW,iBAAiB,IAAI,OAAO,CAAC;QACxC,eAAe,EAAE,MAAM,CAAC;QACxB,aAAa,EAAE,MAAM,CAAC;KACvB,CAAC;YA0BY,iBAAiB;IAYlB,cAAc,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;IAsB5C,mBAAmB,IAAI,OAAO,CAAC,eAAe,EAAE,GAAG,SAAS,CAAC;IAiB7D,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC;IA+E5B,WAAW,IAAI,OAAO,CAAC,iBAAiB,CAAC;IAKzC,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC;IAgB5B,uBAAuB,CAClC,kBAAkB,CAAC,EAAE,MAAM,GAC1B,OAAO,CAAC,OAAO,CAAC;IAkBN,cAAc,CACzB,QAAQ,EAAE,iBAAiB,GAC1B,OAAO,CAAC,eAAe,CAAC;IA+Cd,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAiChE,iBAAiB,IAAI,MAAM,EAAE;CAUrC"}
@@ -14,7 +14,7 @@ const config_1 = require("../utils/config");
14
14
  const coins_1 = require("./coins");
15
15
  const utils_1 = require("../utils");
16
16
  const hashUtils_1 = require("../utils/hashUtils");
17
- const data_integrity_tree_1 = require("@dignetwork/data-integrity-tree");
17
+ const DataIntegrityTree_1 = require("../DataIntegrityTree");
18
18
  const prompts_1 = require("../prompts");
19
19
  const FileCache_1 = require("../utils/FileCache");
20
20
  const DataStoreSerializer_1 = require("./DataStoreSerializer");
@@ -33,7 +33,7 @@ class DataStore {
33
33
  storeDir: config_1.STORE_PATH,
34
34
  };
35
35
  }
36
- this.tree = new data_integrity_tree_1.DataIntegrityTree(storeId, _options);
36
+ this.tree = new DataIntegrityTree_1.DataIntegrityTree(storeId, _options);
37
37
  }
38
38
  get StoreId() {
39
39
  return this.storeId;
@@ -1 +1 @@
1
- {"version":3,"file":"FullNodePeer.d.ts","sourceRoot":"","sources":["../../src/blockchain/FullNodePeer.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAmBxC,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAC,UAAU,CAAkD;IAC3E,OAAO,CAAC,MAAM,CAAC,uBAAuB,CAA0B;IAChE,OAAO,CAAC,IAAI,CAAO;IAQnB,OAAO;WAIa,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAK5C,OAAO,CAAC,MAAM,CAAC,eAAe;IAiB9B,OAAO,CAAC,MAAM,CAAC,gBAAgB;mBAOV,eAAe;mBAkDf,UAAU;IAyB/B,OAAO,CAAC,MAAM,CAAC,eAAe;mBA4BT,WAAW;IAgGzB,OAAO,IAAI,IAAI;WAIF,mBAAmB,CACrC,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,OAAO,CAAC;CAwBpB"}
1
+ {"version":3,"file":"FullNodePeer.d.ts","sourceRoot":"","sources":["../../src/blockchain/FullNodePeer.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAmBxC,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAC,UAAU,CAAkD;IAC3E,OAAO,CAAC,MAAM,CAAC,uBAAuB,CAA0B;IAChE,OAAO,CAAC,IAAI,CAAO;IAQnB,OAAO;WAIa,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAK5C,OAAO,CAAC,MAAM,CAAC,eAAe;IAiB9B,OAAO,CAAC,MAAM,CAAC,gBAAgB;mBAOV,eAAe;mBAkDf,UAAU;IAyB/B,OAAO,CAAC,MAAM,CAAC,eAAe;mBA8CT,WAAW;IAgGzB,OAAO,IAAI,IAAI;WAIF,mBAAmB,CACrC,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,OAAO,CAAC;CAwBpB"}
@@ -107,17 +107,35 @@ class FullNodePeer {
107
107
  }
108
108
  return FullNodePeer.memoizedFetchNewPeerIPs();
109
109
  }
110
- static createPeerProxy(peer, certFile, keyFile) {
110
+ static createPeerProxy(peer) {
111
111
  return new Proxy(peer, {
112
112
  get: (target, prop) => {
113
113
  const originalMethod = target[prop];
114
114
  if (typeof originalMethod === "function") {
115
115
  return async (...args) => {
116
+ let timeoutId;
117
+ // Start the timeout to forget the peer after 1 minute
118
+ const timeoutPromise = new Promise((_, reject) => {
119
+ timeoutId = setTimeout(() => {
120
+ FullNodePeer.cachedPeer = null;
121
+ reject(new Error("Operation timed out. Reconnecting to a new peer."));
122
+ }, 60000); // 1 minute
123
+ });
116
124
  try {
117
- return await originalMethod.apply(target, args);
125
+ // Run the original method and race it against the timeout
126
+ const result = await Promise.race([
127
+ originalMethod.apply(target, args),
128
+ timeoutPromise,
129
+ ]);
130
+ // Clear the timeout if the operation succeeded
131
+ if (timeoutId) {
132
+ clearTimeout(timeoutId);
133
+ }
134
+ return result;
118
135
  }
119
136
  catch (error) {
120
- if (error.message.includes("WebSocket")) {
137
+ // If the error is WebSocket-related or timeout, reset the peer
138
+ if (error.message.includes("WebSocket") || error.message.includes("Operation timed out")) {
121
139
  FullNodePeer.cachedPeer = null;
122
140
  const newPeer = await FullNodePeer.getBestPeer();
123
141
  return newPeer[prop](...args);
@@ -149,7 +167,7 @@ class FullNodePeer {
149
167
  if (ip) {
150
168
  try {
151
169
  const peer = await datalayer_driver_1.Peer.new(`${ip}:${FULLNODE_PORT}`, false, certFile, keyFile);
152
- return FullNodePeer.createPeerProxy(peer, certFile, keyFile);
170
+ return FullNodePeer.createPeerProxy(peer);
153
171
  }
154
172
  catch (error) {
155
173
  console.error(`Failed to create peer for IP ${ip}: ${error.message}`);
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export * from './blockchain';
2
2
  export * from './DigNetwork';
3
3
  export * from './utils';
4
- export * from '@dignetwork/data-integrity-tree';
4
+ export * from './DataIntegrityTree';
5
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,SAAS,CAAC;AACxB,cAAc,iCAAiC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,SAAS,CAAC;AACxB,cAAc,qBAAqB,CAAC"}
package/dist/index.js CHANGED
@@ -17,4 +17,4 @@ Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./blockchain"), exports);
18
18
  __exportStar(require("./DigNetwork"), exports);
19
19
  __exportStar(require("./utils"), exports);
20
- __exportStar(require("@dignetwork/data-integrity-tree"), exports);
20
+ __exportStar(require("./DataIntegrityTree"), exports);
@@ -1,4 +1,4 @@
1
- import { DataIntegrityTree } from "@dignetwork/data-integrity-tree";
1
+ import { DataIntegrityTree } from "../DataIntegrityTree";
2
2
  /**
3
3
  * Recursively add all files in a directory to the Merkle tree, skipping the .dig, .git folders, and files in .gitignore.
4
4
  * @param datalayer - The DataStoreManager instance.
@@ -1 +1 @@
1
- {"version":3,"file":"directoryUtils.d.ts","sourceRoot":"","sources":["../../src/utils/directoryUtils.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAEpE;;;;;GAKG;AACH,eAAO,MAAM,YAAY,cACZ,iBAAiB,WACnB,MAAM,YACN,MAAM,KACd,OAAO,CAAC,IAAI,CAmCd,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,eAAgB,MAAM,KAAG,MAiBxD,CAAC"}
1
+ {"version":3,"file":"directoryUtils.d.ts","sourceRoot":"","sources":["../../src/utils/directoryUtils.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAEzD;;;;;GAKG;AACH,eAAO,MAAM,YAAY,cACZ,iBAAiB,WACnB,MAAM,YACN,MAAM,KACd,OAAO,CAAC,IAAI,CAmCd,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,eAAgB,MAAM,KAAG,MAiBxD,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dignetwork/dig-sdk",
3
- "version": "0.0.1-alpha.4",
3
+ "version": "0.0.1-alpha.6",
4
4
  "description": "",
5
5
  "type": "commonjs",
6
6
  "main": "./dist/index.js",
@@ -25,7 +25,6 @@
25
25
  "LICENSE"
26
26
  ],
27
27
  "dependencies": {
28
- "@dignetwork/data-integrity-tree": "^0.0.22",
29
28
  "bip39": "^3.1.0",
30
29
  "chia-bls": "^1.0.2",
31
30
  "chia-config-loader": "^1.0.1",