@dignetwork/dig-sdk 0.0.1-alpha.8 → 0.0.1-alpha.80

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.
Files changed (64) hide show
  1. package/dist/DataIntegrityTree/DataIntegrityTree.d.ts +5 -2
  2. package/dist/DataIntegrityTree/DataIntegrityTree.d.ts.map +1 -1
  3. package/dist/DataIntegrityTree/DataIntegrityTree.js +93 -34
  4. package/dist/DigNetwork/ContentServer.d.ts +9 -4
  5. package/dist/DigNetwork/ContentServer.d.ts.map +1 -1
  6. package/dist/DigNetwork/ContentServer.js +55 -19
  7. package/dist/DigNetwork/DigNetwork.d.ts +3 -9
  8. package/dist/DigNetwork/DigNetwork.d.ts.map +1 -1
  9. package/dist/DigNetwork/DigNetwork.js +102 -189
  10. package/dist/DigNetwork/DigPeer.d.ts +8 -3
  11. package/dist/DigNetwork/DigPeer.d.ts.map +1 -1
  12. package/dist/DigNetwork/DigPeer.js +65 -114
  13. package/dist/DigNetwork/PropagationServer.d.ts +67 -33
  14. package/dist/DigNetwork/PropagationServer.d.ts.map +1 -1
  15. package/dist/DigNetwork/PropagationServer.js +476 -365
  16. package/dist/blockchain/DataStore.d.ts +17 -6
  17. package/dist/blockchain/DataStore.d.ts.map +1 -1
  18. package/dist/blockchain/DataStore.js +74 -97
  19. package/dist/blockchain/DataStoreSerializer.d.ts +1 -1
  20. package/dist/blockchain/DataStoreSerializer.d.ts.map +1 -1
  21. package/dist/blockchain/FullNodePeer.d.ts +9 -1
  22. package/dist/blockchain/FullNodePeer.d.ts.map +1 -1
  23. package/dist/blockchain/FullNodePeer.js +38 -10
  24. package/dist/blockchain/ServerCoin.d.ts +11 -3
  25. package/dist/blockchain/ServerCoin.d.ts.map +1 -1
  26. package/dist/blockchain/ServerCoin.js +51 -17
  27. package/dist/blockchain/Wallet.d.ts +2 -2
  28. package/dist/blockchain/Wallet.d.ts.map +1 -1
  29. package/dist/blockchain/Wallet.js +2 -2
  30. package/dist/blockchain/coins.d.ts +1 -1
  31. package/dist/blockchain/coins.d.ts.map +1 -1
  32. package/dist/blockchain/coins.js +1 -1
  33. package/dist/types.d.ts +1 -0
  34. package/dist/types.d.ts.map +1 -1
  35. package/dist/utils/ContentScanner.d.ts +63 -0
  36. package/dist/utils/ContentScanner.d.ts.map +1 -0
  37. package/dist/utils/ContentScanner.js +175 -0
  38. package/dist/utils/FileTransfer.d.ts +47 -0
  39. package/dist/utils/FileTransfer.d.ts.map +1 -0
  40. package/dist/utils/FileTransfer.js +209 -0
  41. package/dist/utils/StoreArchiveManager.d.ts +45 -0
  42. package/dist/utils/StoreArchiveManager.d.ts.map +1 -0
  43. package/dist/utils/StoreArchiveManager.js +153 -0
  44. package/dist/utils/asyncPool.d.ts +9 -0
  45. package/dist/utils/asyncPool.d.ts.map +1 -0
  46. package/dist/utils/asyncPool.js +23 -0
  47. package/dist/utils/config.d.ts +1 -1
  48. package/dist/utils/config.d.ts.map +1 -1
  49. package/dist/utils/config.js +2 -3
  50. package/dist/utils/directoryUtils.d.ts +0 -6
  51. package/dist/utils/directoryUtils.d.ts.map +1 -1
  52. package/dist/utils/directoryUtils.js +30 -11
  53. package/dist/utils/index.d.ts +0 -1
  54. package/dist/utils/index.d.ts.map +1 -1
  55. package/dist/utils/index.js +0 -1
  56. package/dist/utils/merkle.d.ts +2 -0
  57. package/dist/utils/merkle.d.ts.map +1 -0
  58. package/dist/utils/merkle.js +28 -0
  59. package/dist/utils/network.d.ts.map +1 -1
  60. package/dist/utils/network.js +0 -1
  61. package/package.json +13 -3
  62. package/dist/utils/deltaUtils.d.ts +0 -2
  63. package/dist/utils/deltaUtils.d.ts.map +0 -1
  64. package/dist/utils/deltaUtils.js +0 -83
@@ -1,4 +1,4 @@
1
- import { DataStore as DataStoreDriver, DataStoreMetadata } from "datalayer-driver";
1
+ import { DataStore as DataStoreDriver, DataStoreMetadata } from "@dignetwork/datalayer-driver";
2
2
  import { RootHistoryItem } from "../types";
3
3
  import { DataIntegrityTree, DataIntegrityTreeOptions } from "../DataIntegrityTree";
4
4
  import { CreateStoreUserInputs } from "../types";
@@ -13,7 +13,7 @@ export declare class DataStore {
13
13
  serialize(): string;
14
14
  static getActiveStore(): Promise<DataStore | undefined>;
15
15
  static deserialize(serialized: string): DataStore;
16
- static from(storeId: string | Buffer): DataStore;
16
+ static from(storeId: string | Buffer, rootHash?: string): DataStore;
17
17
  static create(inputs?: CreateStoreUserInputs): Promise<DataStore>;
18
18
  private static mint;
19
19
  /**
@@ -38,19 +38,30 @@ export declare class DataStore {
38
38
  latestHeight: number;
39
39
  latestHash: Buffer;
40
40
  }>;
41
+ cacheStoreCreationHeight(): Promise<{
42
+ createdAtHeight: number;
43
+ createdAtHash: Buffer;
44
+ }>;
41
45
  getCreationHeight(): Promise<{
42
46
  createdAtHeight: number;
43
47
  createdAtHash: Buffer;
44
48
  }>;
45
49
  private setCreationHeight;
46
50
  getRootHistory(): Promise<RootHistoryItem[]>;
47
- getLocalRootHistory(): Promise<RootHistoryItem[] | undefined>;
48
- validate(): Promise<boolean>;
51
+ generateManifestFile(folderPath?: string): Promise<void>;
49
52
  getMetaData(): Promise<DataStoreMetadata>;
50
53
  isSynced(): Promise<boolean>;
51
54
  hasMetaWritePermissions(publicSyntheticKey?: Buffer): Promise<boolean>;
52
55
  updateMetadata(metadata: DataStoreMetadata): Promise<DataStoreDriver>;
53
- getFileSetForRootHash(rootHash: string): Promise<string[]>;
54
- getManifestHashes(): string[];
56
+ /**
57
+ * Retrieve the file set for a given root hash and validate file integrity.
58
+ *
59
+ * @param {string} rootHash - The root hash to fetch the file set.
60
+ * @returns {Promise<{ fileName: string, file: string }[]>} - An array of unique file objects.
61
+ */
62
+ getFileSetForRootHash(rootHash: string): Promise<{
63
+ name: string;
64
+ path: string;
65
+ }[]>;
55
66
  }
56
67
  //# sourceMappingURL=DataStore.d.ts.map
@@ -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,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"}
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,8BAA8B,CAAC;AAWtC,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;AAajD,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,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS;WAiBtD,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,wBAAwB,IAAI,OAAO,CAAC;QAC/C,eAAe,EAAE,MAAM,CAAC;QACxB,aAAa,EAAE,MAAM,CAAC;KACvB,CAAC;IAiBW,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;IAwC5C,oBAAoB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAexD,WAAW,IAAI,OAAO,CAAC,iBAAiB,CAAC;IAKzC,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC;IAM5B,uBAAuB,CAClC,kBAAkB,CAAC,EAAE,MAAM,GAC1B,OAAO,CAAC,OAAO,CAAC;IAkBN,cAAc,CACzB,QAAQ,EAAE,iBAAiB,GAC1B,OAAO,CAAC,eAAe,CAAC;IA+C3B;;;;;OAKG;IACU,qBAAqB,CAChC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAyC7C"}
@@ -6,18 +6,22 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.DataStore = void 0;
7
7
  const fs_1 = __importDefault(require("fs"));
8
8
  const path_1 = __importDefault(require("path"));
9
- const datalayer_driver_1 = require("datalayer-driver");
9
+ const datalayer_driver_1 = require("@dignetwork/datalayer-driver");
10
10
  const util_1 = require("util");
11
11
  const FullNodePeer_1 = require("./FullNodePeer");
12
12
  const Wallet_1 = require("./Wallet");
13
13
  const config_1 = require("../utils/config");
14
14
  const coins_1 = require("./coins");
15
- const utils_1 = require("../utils");
15
+ const colorette_1 = require("colorette");
16
16
  const hashUtils_1 = require("../utils/hashUtils");
17
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");
21
+ const node_cache_1 = __importDefault(require("node-cache"));
22
+ const config_2 = require("../utils/config");
23
+ // Initialize the cache with a TTL of 180 seconds (3 minutes)
24
+ const rootHistoryCache = new node_cache_1.default({ stdTTL: 180 });
21
25
  const stat = (0, util_1.promisify)(fs_1.default.stat);
22
26
  const readdir = (0, util_1.promisify)(fs_1.default.readdir);
23
27
  class DataStore {
@@ -62,12 +66,15 @@ class DataStore {
62
66
  const parsed = JSON.parse(serialized);
63
67
  return new DataStore(parsed.storeId);
64
68
  }
65
- static from(storeId) {
69
+ static from(storeId, rootHash) {
66
70
  const existingTreeOptions = {
67
71
  storageMode: "local",
68
72
  storeDir: config_1.STORE_PATH,
69
73
  disableInitialize: true,
70
74
  };
75
+ if (rootHash) {
76
+ existingTreeOptions.rootHash = rootHash;
77
+ }
71
78
  if (storeId instanceof Buffer) {
72
79
  return new DataStore(storeId.toString("hex"), existingTreeOptions);
73
80
  }
@@ -257,22 +264,31 @@ class DataStore {
257
264
  throw error;
258
265
  }
259
266
  }
267
+ async cacheStoreCreationHeight() {
268
+ const peer = await FullNodePeer_1.FullNodePeer.connect();
269
+ const createdAtHeight = await peer.getStoreCreationHeight(Buffer.from(this.storeId, "hex"), null, Buffer.from(config_2.MAIN_NET_GENISES_CHALLENGE, "hex"));
270
+ // Get just before created at height so we can find the coin
271
+ const justBeforeCreatedAtHeight = Number(createdAtHeight) - 1;
272
+ const createdAtHash = await peer.getHeaderHash(justBeforeCreatedAtHeight);
273
+ await this.setCreationHeight(justBeforeCreatedAtHeight, createdAtHash);
274
+ return { createdAtHeight: justBeforeCreatedAtHeight, createdAtHash };
275
+ }
260
276
  async getCreationHeight() {
261
- const defaultHeight = config_1.MIN_HEIGHT;
262
- const defaultHash = Buffer.from(config_1.MIN_HEIGHT_HEADER_HASH, "hex");
263
277
  // Initialize the FileCache for the height file
264
278
  const fileCache = new FileCache_1.FileCache(`stores/${this.storeId}`);
265
279
  // Try to retrieve the cached height information
266
280
  const cachedHeightInfo = fileCache.get("height");
267
281
  if (!cachedHeightInfo) {
268
- // If no cache, return the default values
269
- return { createdAtHeight: defaultHeight, createdAtHash: defaultHash };
282
+ // If no cache, regenerate the cache
283
+ return this.cacheStoreCreationHeight();
270
284
  }
271
285
  // Parse the cached height and hash values
272
286
  const { height, hash } = cachedHeightInfo;
287
+ const defaultHeight = config_1.MIN_HEIGHT;
288
+ const defaultHash = Buffer.from(config_1.MIN_HEIGHT_HEADER_HASH, "hex");
273
289
  return {
274
290
  createdAtHeight: height || defaultHeight,
275
- createdAtHash: Buffer.from(hash || config_1.MIN_HEIGHT_HEADER_HASH, "hex"),
291
+ createdAtHash: hash ? Buffer.from(hash, "hex") : defaultHash,
276
292
  };
277
293
  }
278
294
  async setCreationHeight(height, hash) {
@@ -284,97 +300,49 @@ class DataStore {
284
300
  });
285
301
  }
286
302
  async getRootHistory() {
303
+ // Check if the root history is cached for this storeId
304
+ const cachedHistory = rootHistoryCache.get(this.storeId);
305
+ if (cachedHistory) {
306
+ return cachedHistory;
307
+ }
308
+ // Fetch root history from peer if not cached
287
309
  const peer = await FullNodePeer_1.FullNodePeer.connect();
288
310
  const { createdAtHeight, createdAtHash } = await this.getCreationHeight();
289
311
  const { rootHashes, rootHashesTimestamps } = await peer.syncStoreFromLauncherId(Buffer.from(this.storeId, "hex"), createdAtHeight, createdAtHash, true);
290
312
  if (!rootHashes) {
291
313
  return [];
292
314
  }
293
- return rootHashes.map((rootHash, index) => ({
315
+ // Build the root history list
316
+ const rootHistory = rootHashes.map((rootHash, index) => ({
294
317
  root_hash: rootHash.toString("hex"),
295
318
  timestamp: Number(rootHashesTimestamps?.[index].toString()),
319
+ synced: fs_1.default.existsSync(path_1.default.join(config_1.STORE_PATH, this.storeId, `${rootHash.toString("hex")}.dat`)),
296
320
  }));
321
+ // Store the root history in the cache
322
+ rootHistoryCache.set(this.storeId, rootHistory);
323
+ return rootHistory;
297
324
  }
298
- async getLocalRootHistory() {
299
- const manifestFilePath = (0, config_1.getManifestFilePath)(this.storeId);
300
- if (!fs_1.default.existsSync(manifestFilePath)) {
301
- console.error("Manifest file not found", manifestFilePath);
302
- return undefined;
325
+ // Generates a fresh manifest file based on the current root history
326
+ // and what is currently on disk
327
+ async generateManifestFile(folderPath) {
328
+ if (!folderPath) {
329
+ folderPath = path_1.default.join(config_1.STORE_PATH, this.storeId, "data");
303
330
  }
304
- const manifestHashes = fs_1.default
305
- .readFileSync(manifestFilePath, "utf-8")
306
- .split("\n")
307
- .filter(Boolean);
308
- return manifestHashes.map((rootHash) => ({
309
- root_hash: rootHash,
310
- timestamp: 0, // Timestamps are not yet included in the manifest
311
- }));
312
- }
313
- async validate() {
314
331
  const rootHistory = await this.getRootHistory();
315
- const manifestFilePath = (0, config_1.getManifestFilePath)(this.storeId);
316
- if (!fs_1.default.existsSync(manifestFilePath)) {
317
- console.error("Manifest file not found", manifestFilePath);
318
- return false;
319
- }
320
- const manifestHashes = fs_1.default
321
- .readFileSync(manifestFilePath, "utf-8")
322
- .split("\n")
323
- .filter(Boolean);
324
- if (manifestHashes.length > rootHistory.length) {
325
- console.error("The store is corrupted: Manifest file has more hashes than the root history.");
326
- return false;
327
- }
328
- if (rootHistory.length > manifestHashes.length) {
329
- console.error("The store is not synced: Root history has more hashes than the manifest file.");
330
- return false;
331
- }
332
- for (let i = 0; i < manifestHashes.length; i++) {
333
- if (manifestHashes[i] !== rootHistory[i]?.root_hash) {
334
- console.error(`Root hash mismatch at position ${i}: expected ${manifestHashes[i]} but found ${rootHistory[i]?.root_hash}`);
335
- return false;
336
- }
337
- }
338
- let filesIntegrityIntact = true;
339
- for (const rootHash of manifestHashes) {
340
- const datFilePath = path_1.default.join(config_1.STORE_PATH, this.storeId, `${rootHash}.dat`);
341
- if (!fs_1.default.existsSync(datFilePath)) {
342
- console.error(`Data file for root hash ${rootHash} not found`);
343
- return false;
344
- }
345
- const datFileContent = JSON.parse(fs_1.default.readFileSync(datFilePath, "utf-8"));
346
- if (datFileContent.root !== rootHash) {
347
- console.error(`Root hash in data file does not match: ${datFileContent.root} !== ${rootHash}`);
348
- return false;
349
- }
350
- for (const [fileKey, fileData] of Object.entries(datFileContent.files)) {
351
- const integrityCheck = (0, utils_1.validateFileSha256)(fileData.sha256, path_1.default.join(config_1.STORE_PATH, this.storeId, "data"));
352
- if (!integrityCheck) {
353
- filesIntegrityIntact = false;
354
- }
355
- }
356
- }
357
- if (!filesIntegrityIntact) {
358
- console.error("Store Corrupted: Data failed SHA256 validation.");
359
- return false;
360
- }
361
- return true;
332
+ // Need this for the dataintegrity tree to work properly
333
+ fs_1.default.writeFileSync(path_1.default.join(folderPath, "manifest.dat"), rootHistory
334
+ .filter((root) => root.synced)
335
+ .map((root) => root.root_hash)
336
+ .join("\n"));
362
337
  }
363
338
  async getMetaData() {
364
339
  const { latestStore } = await this.fetchCoinInfo();
365
340
  return latestStore.metadata;
366
341
  }
367
342
  async isSynced() {
368
- const rootHistory = await this.getRootHistory();
369
- const manifestFilePath = (0, config_1.getManifestFilePath)(this.storeId);
370
- if (!fs_1.default.existsSync(manifestFilePath)) {
371
- return false;
372
- }
373
- const manifestHashes = fs_1.default
374
- .readFileSync(manifestFilePath, "utf-8")
375
- .split("\n")
376
- .filter(Boolean);
377
- return rootHistory.length === manifestHashes.length;
343
+ const dataStore = await DataStore.from(this.storeId);
344
+ const rootHistory = await dataStore.getRootHistory();
345
+ return !rootHistory.some((root) => !root.synced);
378
346
  }
379
347
  async hasMetaWritePermissions(publicSyntheticKey) {
380
348
  const wallet = await Wallet_1.Wallet.load("default");
@@ -407,27 +375,36 @@ class DataStore {
407
375
  }
408
376
  return updateStoreResponse.newStore;
409
377
  }
378
+ /**
379
+ * Retrieve the file set for a given root hash and validate file integrity.
380
+ *
381
+ * @param {string} rootHash - The root hash to fetch the file set.
382
+ * @returns {Promise<{ fileName: string, file: string }[]>} - An array of unique file objects.
383
+ */
410
384
  async getFileSetForRootHash(rootHash) {
411
385
  const datFilePath = path_1.default.join(config_1.STORE_PATH, this.storeId, `${rootHash}.dat`);
412
386
  const datFileContent = JSON.parse(fs_1.default.readFileSync(datFilePath, "utf-8"));
413
- const heightDatFilePath = path_1.default.join(config_1.STORE_PATH, this.storeId, "height.json");
414
- const manifestFilePath = path_1.default.join(config_1.STORE_PATH, this.storeId, "manifest.dat");
415
- const filesInvolved = [];
416
- filesInvolved.push(manifestFilePath);
417
- filesInvolved.push(datFilePath);
418
- filesInvolved.push(heightDatFilePath);
387
+ // Use a Set to ensure uniqueness
388
+ const filesInvolved = new Set();
389
+ // Iterate over each file and perform an integrity check
419
390
  for (const [fileKey, fileData] of Object.entries(datFileContent.files)) {
420
- const filepath = path_1.default.join(config_1.STORE_PATH, this.storeId, "data", fileKey);
421
- const filePath = (0, hashUtils_1.getFilePathFromSha256)(datFileContent.files[fileKey].sha256, path_1.default.join(config_1.STORE_PATH, this.storeId, "data"));
422
- filesInvolved.push(filePath);
391
+ const filePath = (0, hashUtils_1.getFilePathFromSha256)(datFileContent.files[fileKey].sha256, "data");
392
+ // Perform the integrity check
393
+ const integrityCheck = await DataIntegrityTree_1.DataIntegrityTree.validateKeyIntegrityWithForeignTree(fileKey, datFileContent.files[fileKey].sha256, datFileContent, rootHash, path_1.default.join(config_1.STORE_PATH, this.storeId, "data"));
394
+ if (integrityCheck) {
395
+ // Add the file to the Set
396
+ filesInvolved.add({
397
+ name: Buffer.from(fileKey, "hex").toString("utf-8"),
398
+ path: filePath,
399
+ });
400
+ }
401
+ else {
402
+ console.error((0, colorette_1.red)(`File ${fileKey} failed the integrity check.`));
403
+ throw new Error(`Integrity check failed for file: ${fileKey}. Aborting.`);
404
+ }
423
405
  }
424
- return filesInvolved;
425
- }
426
- getManifestHashes() {
427
- const manifestFilePath = path_1.default.join(config_1.STORE_PATH, this.storeId, "manifest.dat");
428
- return fs_1.default.existsSync(manifestFilePath)
429
- ? fs_1.default.readFileSync(manifestFilePath, "utf-8").split("\n").filter(Boolean)
430
- : [];
406
+ // Convert Set to Array and return
407
+ return Array.from(filesInvolved);
431
408
  }
432
409
  }
433
410
  exports.DataStore = DataStore;
@@ -1,4 +1,4 @@
1
- import { DataStore } from "datalayer-driver";
1
+ import { DataStore } from "@dignetwork/datalayer-driver";
2
2
  import { Buffer } from "buffer";
3
3
  export declare class DataStoreSerializer {
4
4
  private storeInfo;
@@ -1 +1 @@
1
- {"version":3,"file":"DataStoreSerializer.d.ts","sourceRoot":"","sources":["../../src/blockchain/DataStoreSerializer.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EAKV,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,UAAU,CAAS;gBAEf,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM;IAOnE,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WAgDF,WAAW,CACvB,IAAI,EAAE;QACJ,WAAW,EAAE,GAAG,CAAC;QACjB,YAAY,EAAE,MAAM,CAAC;QACrB,UAAU,EAAE,MAAM,CAAC;KACpB,GACA;QACD,WAAW,EAAE,SAAS,CAAC;QACvB,YAAY,EAAE,MAAM,CAAC;QACrB,UAAU,EAAE,MAAM,CAAC;KACpB;CAuEF"}
1
+ {"version":3,"file":"DataStoreSerializer.d.ts","sourceRoot":"","sources":["../../src/blockchain/DataStoreSerializer.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EAKV,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,UAAU,CAAS;gBAEf,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM;IAOnE,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WAgDF,WAAW,CACvB,IAAI,EAAE;QACJ,WAAW,EAAE,GAAG,CAAC;QACjB,YAAY,EAAE,MAAM,CAAC;QACrB,UAAU,EAAE,MAAM,CAAC;KACpB,GACA;QACD,WAAW,EAAE,SAAS,CAAC;QACvB,YAAY,EAAE,MAAM,CAAC;QACrB,UAAU,EAAE,MAAM,CAAC;KACpB;CAuEF"}
@@ -1,12 +1,20 @@
1
- import { Peer } from "datalayer-driver";
1
+ import { Peer } from "@dignetwork/datalayer-driver";
2
2
  export declare class FullNodePeer {
3
3
  private static cachedPeer;
4
4
  private static memoizedFetchNewPeerIPs;
5
5
  private peer;
6
+ private static deprioritizedIps;
6
7
  private constructor();
7
8
  static connect(): Promise<Peer>;
8
9
  private static isPortReachable;
9
10
  private static isValidIpAddress;
11
+ /**
12
+ * Retrieves the TRUSTED_FULLNODE IP from the environment
13
+ * and verifies if it is a valid IP address.
14
+ *
15
+ * @returns {string | null} The valid IP address or null if invalid
16
+ */
17
+ private static getTrustedFullNode;
10
18
  private static fetchNewPeerIPs;
11
19
  private static getPeerIPs;
12
20
  private static createPeerProxy;
@@ -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;mBA8CT,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,8BAA8B,CAAC;AAoBpD,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAC,UAAU,CAAkD;IAC3E,OAAO,CAAC,MAAM,CAAC,uBAAuB,CAA0B;IAChE,OAAO,CAAC,IAAI,CAAO;IACnB,OAAO,CAAC,MAAM,CAAC,gBAAgB,CAA0B;IAMzD,OAAO;WAIa,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAK5C,OAAO,CAAC,MAAM,CAAC,eAAe;IAiB9B,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAM/B;;;;;OAKG;IACH,OAAO,CAAC,MAAM,CAAC,kBAAkB;mBASZ,eAAe;mBA2Df,UAAU;IA2B/B,OAAO,CAAC,MAAM,CAAC,eAAe;mBAkDT,WAAW;IA+FzB,OAAO,IAAI,IAAI;WAIF,mBAAmB,CACrC,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,OAAO,CAAC;CAwBpB"}
@@ -7,7 +7,7 @@ exports.FullNodePeer = void 0;
7
7
  const path_1 = __importDefault(require("path"));
8
8
  const os_1 = __importDefault(require("os"));
9
9
  const fs_1 = __importDefault(require("fs"));
10
- const datalayer_driver_1 = require("datalayer-driver");
10
+ const datalayer_driver_1 = require("@dignetwork/datalayer-driver");
11
11
  const chia_server_coin_1 = require("chia-server-coin");
12
12
  const promises_1 = require("dns/promises");
13
13
  const net_1 = __importDefault(require("net"));
@@ -16,6 +16,7 @@ const nanospinner_1 = require("nanospinner");
16
16
  const config_1 = require("../utils/config");
17
17
  const FULLNODE_PORT = 8444;
18
18
  const LOCALHOST = "127.0.0.1";
19
+ const CHIA_NODES_HOST = "chia-nodes";
19
20
  const DNS_HOSTS = [
20
21
  "dns-introducer.chia.net",
21
22
  "chia.ctrlaltdel.ch",
@@ -48,19 +49,38 @@ class FullNodePeer {
48
49
  const ipv4Regex = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
49
50
  return ipv4Regex.test(ip);
50
51
  }
51
- static async fetchNewPeerIPs() {
52
+ /**
53
+ * Retrieves the TRUSTED_FULLNODE IP from the environment
54
+ * and verifies if it is a valid IP address.
55
+ *
56
+ * @returns {string | null} The valid IP address or null if invalid
57
+ */
58
+ static getTrustedFullNode() {
52
59
  const trustedNodeIp = process.env.TRUSTED_FULLNODE || null;
60
+ if (trustedNodeIp && FullNodePeer.isValidIpAddress(trustedNodeIp)) {
61
+ return trustedNodeIp;
62
+ }
63
+ return null;
64
+ }
65
+ static async fetchNewPeerIPs() {
66
+ const trustedNodeIp = FullNodePeer.getTrustedFullNode();
53
67
  const priorityIps = [];
54
- // Prioritize trustedNodeIp
68
+ // Prioritize trustedNodeIp unless it's deprioritized
55
69
  if (trustedNodeIp &&
56
- FullNodePeer.isValidIpAddress(trustedNodeIp) &&
70
+ !FullNodePeer.deprioritizedIps.has(trustedNodeIp) &&
57
71
  (await FullNodePeer.isPortReachable(trustedNodeIp, FULLNODE_PORT))) {
58
72
  priorityIps.push(trustedNodeIp);
59
73
  }
60
- // Prioritize LOCALHOST
61
- if (await FullNodePeer.isPortReachable(LOCALHOST, FULLNODE_PORT)) {
74
+ // Prioritize LOCALHOST unless it's deprioritized
75
+ if (!FullNodePeer.deprioritizedIps.has(LOCALHOST) &&
76
+ (await FullNodePeer.isPortReachable(LOCALHOST, FULLNODE_PORT))) {
62
77
  priorityIps.push(LOCALHOST);
63
78
  }
79
+ // Prioritize CHIA_NODES_HOST unless it's deprioritized
80
+ if (!FullNodePeer.deprioritizedIps.has(CHIA_NODES_HOST) &&
81
+ (await FullNodePeer.isPortReachable(CHIA_NODES_HOST, FULLNODE_PORT))) {
82
+ priorityIps.push(CHIA_NODES_HOST);
83
+ }
64
84
  if (priorityIps.length > 0) {
65
85
  return priorityIps;
66
86
  }
@@ -102,6 +122,8 @@ class FullNodePeer {
102
122
  }
103
123
  // @ts-ignore
104
124
  if (FullNodePeer.memoizedFetchNewPeerIPs?.cache?.clear) {
125
+ // Clear cache and reset deprioritized IPs when cache is cleared
126
+ FullNodePeer.deprioritizedIps.clear();
105
127
  // @ts-ignore
106
128
  FullNodePeer.memoizedFetchNewPeerIPs.cache.clear();
107
129
  }
@@ -137,6 +159,10 @@ class FullNodePeer {
137
159
  // If the error is WebSocket-related or timeout, reset the peer
138
160
  if (error.message.includes("WebSocket") || error.message.includes("Operation timed out")) {
139
161
  FullNodePeer.cachedPeer = null;
162
+ // @ts-ignore
163
+ FullNodePeer.memoizedFetchNewPeerIPs.cache.clear();
164
+ FullNodePeer.deprioritizedIps.clear();
165
+ console.info(`Fullnode Peer error, reconnecting to a new peer...`);
140
166
  const newPeer = await FullNodePeer.getBestPeer();
141
167
  return newPeer[prop](...args);
142
168
  }
@@ -192,16 +218,17 @@ class FullNodePeer {
192
218
  throw new Error("No valid peak heights obtained from any peer.");
193
219
  }
194
220
  const highestPeak = Math.max(...validHeights);
195
- // Prioritize LOCALHOST and TRUSTED_NODE_IP if they have the highest peak height
221
+ // Prioritize LOCALHOST, TRUSTED_NODE_IP, and CHIA_NODES_HOST if they have the highest peak height
196
222
  let bestPeerIndex = validHeights.findIndex((height, index) => height === highestPeak &&
197
- (peerIPs[index] === LOCALHOST || peerIPs[index] === trustedNodeIp));
198
- // If LOCALHOST or TRUSTED_NODE_IP don't have the highest peak, select any peer with the highest peak
223
+ !FullNodePeer.deprioritizedIps.has(peerIPs[index]) && // Exclude deprioritized IPs
224
+ (peerIPs[index] === LOCALHOST || peerIPs[index] === trustedNodeIp || peerIPs[index] === CHIA_NODES_HOST));
225
+ // If LOCALHOST, TRUSTED_NODE_IP, or CHIA_NODES_HOST don't have the highest peak, select any peer with the highest peak
199
226
  if (bestPeerIndex === -1) {
200
227
  bestPeerIndex = validHeights.findIndex((height) => height === highestPeak);
201
228
  }
202
229
  const bestPeer = peers[bestPeerIndex];
203
230
  FullNodePeer.cachedPeer = { peer: bestPeer, timestamp: now };
204
- console.log(`Using Peer: ${peerIPs[bestPeerIndex]}`);
231
+ console.log(`Using Fullnode Peer: ${peerIPs[bestPeerIndex]}`);
205
232
  return bestPeer;
206
233
  }
207
234
  getPeer() {
@@ -228,6 +255,7 @@ class FullNodePeer {
228
255
  }
229
256
  exports.FullNodePeer = FullNodePeer;
230
257
  FullNodePeer.cachedPeer = null;
258
+ FullNodePeer.deprioritizedIps = new Set(); // New set for deprioritized IPs
231
259
  (() => {
232
260
  FullNodePeer.memoizedFetchNewPeerIPs = (0, lodash_1.memoize)(FullNodePeer.fetchNewPeerIPs);
233
261
  })();
@@ -1,4 +1,4 @@
1
- import { ServerCoin as ServerCoinDriver } from "datalayer-driver";
1
+ import { ServerCoin as ServerCoinDriver } from "@dignetwork/datalayer-driver";
2
2
  import { NconfManager } from "../utils/NconfManager";
3
3
  export declare class ServerCoin {
4
4
  private storeId;
@@ -8,14 +8,22 @@ export declare class ServerCoin {
8
8
  saveServerCoinData(serverCoin: ServerCoinDriver, epoch: number, peerIp: string): Promise<void>;
9
9
  melt(epoch: number, peerIp: string): Promise<void>;
10
10
  private removeServerCoinData;
11
+ getAllEpochPeers(epoch: number, blacklist?: string[]): Promise<string[]>;
12
+ getActiveEpochPeers(blacklist?: string[]): Promise<string[]>;
11
13
  sampleCurrentEpoch(sampleSize?: number, blacklist?: string[]): Promise<string[]>;
12
14
  sampleServerCoinsByEpoch(epoch: number, sampleSize?: number, blacklist?: string[]): Promise<string[]>;
13
- static getCurrentEpoch(): number;
15
+ static getCurrentEpoch(): {
16
+ epoch: number;
17
+ round: number;
18
+ };
14
19
  ensureServerCoinExists(peerIp: string): Promise<void>;
15
20
  meltOutdatedEpochs(peerIp: string): Promise<void>;
16
21
  static meltUntrackedStoreCoins(): Promise<void>;
17
22
  private getServerCoinsForStore;
18
23
  hasEpochCoinBeenCreated(currentEpoch: number, peerIp: string): Promise<boolean>;
19
- static calculateEpoch(currentTimestampUTC: Date): number;
24
+ static calculateEpochAndRound(currentTimestampUTC: Date): {
25
+ epoch: number;
26
+ round: number;
27
+ };
20
28
  }
21
29
  //# sourceMappingURL=ServerCoin.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ServerCoin.d.ts","sourceRoot":"","sources":["../../src/blockchain/ServerCoin.ts"],"names":[],"mappings":"AACA,OAAO,EAML,UAAU,IAAI,gBAAgB,EAE/B,MAAM,kBAAkB,CAAC;AAI1B,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAMrD,qBAAa,UAAU;IACrB,OAAO,CAAC,OAAO,CAAS;IACxB,gBAAuB,iBAAiB,eAAwC;gBAGpE,OAAO,EAAE,MAAM;IAKd,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA2DzD,kBAAkB,CAC7B,UAAU,EAAE,gBAAgB,EAC5B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC;IAqBH,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAoDjD,oBAAoB;IAgBrB,kBAAkB,CAC7B,UAAU,GAAE,MAAU,EACtB,SAAS,GAAE,MAAM,EAAO,GACvB,OAAO,CAAC,MAAM,EAAE,CAAC;IAMP,wBAAwB,CACnC,KAAK,EAAE,MAAM,EACb,UAAU,GAAE,MAAU,EACtB,SAAS,GAAE,MAAM,EAAO,GACvB,OAAO,CAAC,MAAM,EAAE,CAAC;WAsCN,eAAe,IAAI,MAAM;IAK1B,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiDrD,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;WA+B1C,uBAAuB;YA4D7B,sBAAsB;IAWvB,uBAAuB,CAClC,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,OAAO,CAAC;WAuBL,cAAc,CAAC,mBAAmB,EAAE,IAAI,GAAG,MAAM;CAiBhE"}
1
+ {"version":3,"file":"ServerCoin.d.ts","sourceRoot":"","sources":["../../src/blockchain/ServerCoin.ts"],"names":[],"mappings":"AACA,OAAO,EAML,UAAU,IAAI,gBAAgB,EAE/B,MAAM,8BAA8B,CAAC;AAItC,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAWrD,qBAAa,UAAU;IACrB,OAAO,CAAC,OAAO,CAAS;IACxB,gBAAuB,iBAAiB,eAEtC;gBAEU,OAAO,EAAE,MAAM;IAKd,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA2DzD,kBAAkB,CAC7B,UAAU,EAAE,gBAAgB,EAC5B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC;IAqBH,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAoDjD,oBAAoB;IAerB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,GAAE,MAAM,EAAO,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IA0C5E,mBAAmB,CAC9B,SAAS,GAAE,MAAM,EAAO,GACvB,OAAO,CAAC,MAAM,EAAE,CAAC;IAMP,kBAAkB,CAC7B,UAAU,GAAE,MAAU,EACtB,SAAS,GAAE,MAAM,EAAO,GACvB,OAAO,CAAC,MAAM,EAAE,CAAC;IAMP,wBAAwB,CACnC,KAAK,EAAE,MAAM,EACb,UAAU,GAAE,MAAU,EACtB,SAAS,GAAE,MAAM,EAAO,GACvB,OAAO,CAAC,MAAM,EAAE,CAAC;WAeN,eAAe,IAAI;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE;IAKpD,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiDrD,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;WA+B1C,uBAAuB;YAkE7B,sBAAsB;IAWvB,uBAAuB,CAClC,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,OAAO,CAAC;WAuBL,sBAAsB,CAAC,mBAAmB,EAAE,IAAI,GAAG;QAC/D,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,CAAC;KACf;CA2BF"}
@@ -5,13 +5,17 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.ServerCoin = void 0;
7
7
  const lodash_1 = __importDefault(require("lodash"));
8
- const datalayer_driver_1 = require("datalayer-driver");
8
+ const datalayer_driver_1 = require("@dignetwork/datalayer-driver");
9
9
  const FullNodePeer_1 = require("./FullNodePeer");
10
10
  const coins_1 = require("./coins");
11
11
  const Wallet_1 = require("./Wallet");
12
12
  const NconfManager_1 = require("../utils/NconfManager");
13
13
  const DataStore_1 = require("./DataStore");
14
+ const node_cache_1 = __importDefault(require("node-cache"));
15
+ const network_1 = require("../utils/network");
14
16
  const serverCoinCollateral = 300000000;
17
+ // Initialize the cache with a TTL of 300 seconds (5 minutes)
18
+ const serverCoinPeersCache = new node_cache_1.default({ stdTTL: 300 });
15
19
  class ServerCoin {
16
20
  constructor(storeId) {
17
21
  this.storeId = storeId;
@@ -23,7 +27,7 @@ class ServerCoin {
23
27
  const wallet = await Wallet_1.Wallet.load("default");
24
28
  const publicSyntheticKey = await wallet.getPublicSyntheticKey();
25
29
  const serverCoinCreationCoins = await (0, coins_1.selectUnspentCoins)(peer, BigInt(serverCoinCollateral), BigInt(1000000));
26
- const currentEpoch = ServerCoin.getCurrentEpoch();
30
+ const { epoch: currentEpoch } = ServerCoin.getCurrentEpoch();
27
31
  const epochBasedHint = (0, datalayer_driver_1.morphLauncherId)(Buffer.from(this.storeId, "hex"), BigInt(currentEpoch));
28
32
  const newServerCoin = (0, datalayer_driver_1.createServerCoin)(publicSyntheticKey, serverCoinCreationCoins, epochBasedHint, [peerIp], BigInt(serverCoinCollateral), BigInt(1000000));
29
33
  const combinedCoinSpends = [...newServerCoin.coinSpends];
@@ -94,13 +98,13 @@ class ServerCoin {
94
98
  serverCoins = serverCoins.filter((coin) => coin.coin.parentCoinInfo !== serverCoin.parentCoinInfo);
95
99
  await ServerCoin.serverCoinManager.setConfigValue(`${this.storeId}:${peerIp}`, serverCoins);
96
100
  }
97
- // Sample server coins for the current epoch
98
- async sampleCurrentEpoch(sampleSize = 5, blacklist = []) {
99
- const epoch = ServerCoin.getCurrentEpoch();
100
- return this.sampleServerCoinsByEpoch(epoch, sampleSize, blacklist);
101
- }
102
- // Sample server coins by epoch
103
- async sampleServerCoinsByEpoch(epoch, sampleSize = 5, blacklist = []) {
101
+ async getAllEpochPeers(epoch, blacklist = []) {
102
+ const cacheKey = `serverCoinPeers-${this.storeId}-${epoch}`;
103
+ // Check if the result is already cached
104
+ const cachedPeers = serverCoinPeersCache.get(cacheKey);
105
+ if (cachedPeers) {
106
+ return cachedPeers;
107
+ }
104
108
  const epochBasedHint = (0, datalayer_driver_1.morphLauncherId)(Buffer.from(this.storeId, "hex"), BigInt(epoch));
105
109
  const peer = await FullNodePeer_1.FullNodePeer.connect();
106
110
  const maxClvmCost = BigInt(11000000000);
@@ -118,18 +122,42 @@ class ServerCoin {
118
122
  if (process.env.DIG_DEBUG === "1") {
119
123
  console.log("Server Coin Peers: ", serverCoinPeers);
120
124
  }
121
- // Convert the Set back to an array if needed
122
- return lodash_1.default.sampleSize(Array.from(serverCoinPeers), sampleSize);
125
+ const peerList = Array.from(serverCoinPeers);
126
+ // Cache the result
127
+ serverCoinPeersCache.set(cacheKey, peerList);
128
+ return peerList;
129
+ }
130
+ async getActiveEpochPeers(blacklist = []) {
131
+ const { epoch } = ServerCoin.getCurrentEpoch();
132
+ return this.getAllEpochPeers(epoch, blacklist);
133
+ }
134
+ // Sample server coins for the current epoch
135
+ async sampleCurrentEpoch(sampleSize = 5, blacklist = []) {
136
+ const { epoch } = ServerCoin.getCurrentEpoch();
137
+ return this.sampleServerCoinsByEpoch(epoch, sampleSize, blacklist);
138
+ }
139
+ // Sample server coins by epoch
140
+ async sampleServerCoinsByEpoch(epoch, sampleSize = 5, blacklist = []) {
141
+ // We dont want our own IP to be included
142
+ const myIp = await (0, network_1.getPublicIpAddress)();
143
+ if (myIp) {
144
+ blacklist.push(myIp);
145
+ }
146
+ const serverCoinPeers = await this.getAllEpochPeers(epoch, blacklist);
147
+ if (process.env.DIG_DEBUG === "1") {
148
+ console.log("Server Coin Peers: ", serverCoinPeers);
149
+ }
150
+ return lodash_1.default.sampleSize(serverCoinPeers, sampleSize);
123
151
  }
124
152
  // Get the current epoch based on the current timestamp
125
153
  static getCurrentEpoch() {
126
- return ServerCoin.calculateEpoch(new Date());
154
+ return ServerCoin.calculateEpochAndRound(new Date());
127
155
  }
128
156
  // Ensure server coin exists for the current epoch
129
157
  async ensureServerCoinExists(peerIp) {
130
158
  try {
131
159
  console.log(`Ensuring server coin exists for store ${this.storeId}...`);
132
- const currentEpoch = ServerCoin.getCurrentEpoch();
160
+ const { epoch: currentEpoch } = ServerCoin.getCurrentEpoch();
133
161
  const serverCoins = await this.getServerCoinsForStore(peerIp);
134
162
  // Check if a server coin already exists for the current epoch
135
163
  const existingCoin = serverCoins.find((coin) => coin.epoch === currentEpoch);
@@ -160,7 +188,7 @@ class ServerCoin {
160
188
  // Melt outdated server coins
161
189
  async meltOutdatedEpochs(peerIp) {
162
190
  try {
163
- const currentEpoch = ServerCoin.getCurrentEpoch();
191
+ const { epoch: currentEpoch } = ServerCoin.getCurrentEpoch();
164
192
  let serverCoins = await this.getServerCoinsForStore(peerIp);
165
193
  // Filter out coins that are not in the current epoch
166
194
  const outdatedCoins = serverCoins.filter((coin) => coin.epoch < currentEpoch);
@@ -244,17 +272,23 @@ class ServerCoin {
244
272
  }
245
273
  }
246
274
  // Static method to calculate the current epoch
247
- static calculateEpoch(currentTimestampUTC) {
275
+ static calculateEpochAndRound(currentTimestampUTC) {
248
276
  const firstEpochStart = new Date(Date.UTC(2024, 8, 3, 0, 0)); // Sept 3, 2024, 00:00 UTC
249
277
  // Convert the current timestamp to milliseconds
250
278
  const currentTimestampMillis = currentTimestampUTC.getTime();
251
279
  // Calculate the number of milliseconds in one epoch (7 days)
252
- const millisecondsInEpoch = 7 * 24 * 60 * 60 * 1000;
280
+ const millisecondsInEpoch = 7 * 24 * 60 * 60 * 1000; // 7 days in milliseconds
253
281
  // Calculate the difference in milliseconds between the current timestamp and the first epoch start
254
282
  const differenceMillis = currentTimestampMillis - firstEpochStart.getTime();
255
283
  // Calculate the current epoch number
256
284
  const epochNumber = Math.floor(differenceMillis / millisecondsInEpoch) + 1;
257
- return epochNumber;
285
+ // Calculate the milliseconds elapsed since the start of the current epoch
286
+ const elapsedMillisInCurrentEpoch = differenceMillis % millisecondsInEpoch;
287
+ // Calculate the number of milliseconds in a round (10 minutes)
288
+ const millisecondsInRound = 10 * 60 * 1000; // 10 minutes in milliseconds
289
+ // Calculate the current round number
290
+ const roundNumber = Math.floor(elapsedMillisInCurrentEpoch / millisecondsInRound) + 1;
291
+ return { epoch: epochNumber, round: roundNumber };
258
292
  }
259
293
  }
260
294
  exports.ServerCoin = ServerCoin;