@dignetwork/dig-sdk 0.0.1-alpha.124 → 0.0.1-alpha.126

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.
@@ -6,6 +6,7 @@ export declare class DigNetwork {
6
6
  private peerBlacklist;
7
7
  constructor(storeId: string);
8
8
  static subscribeToStore(storeId: string): Promise<void>;
9
+ static getUdiContent(udi: string): Promise<void>;
9
10
  static findPeerWithStoreKey(storeId: string, rootHash: string, key?: string, intialBlackList?: string[]): Promise<DigPeer | null>;
10
11
  static unsubscribeFromStore(storeId: string): void;
11
12
  syncStoreFromPeers(maxRootsToProcess?: number): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"DigNetwork.d.ts","sourceRoot":"","sources":["../../src/DigNetwork/DigNetwork.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASpC,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;WAOP,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;WAQhD,oBAAoB,CACtC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,GAAG,CAAC,EAAE,MAAM,EACZ,eAAe,GAAE,MAAM,EAAO,GAC7B,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;WA2DZ,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAO5C,kBAAkB,CAAC,iBAAiB,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiG7D,mBAAmB,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;CAUvD"}
1
+ {"version":3,"file":"DigNetwork.d.ts","sourceRoot":"","sources":["../../src/DigNetwork/DigNetwork.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASpC,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;WAOP,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;WAQhD,aAAa,CAAC,GAAG,EAAE,MAAM;WAIzB,oBAAoB,CACtC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,GAAG,CAAC,EAAE,MAAM,EACZ,eAAe,GAAE,MAAM,EAAO,GAC7B,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;WA2DZ,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAO5C,kBAAkB,CAAC,iBAAiB,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiG7D,mBAAmB,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;CAUvD"}
@@ -46,6 +46,9 @@ class DigNetwork {
46
46
  const digNetwork = new DigNetwork(storeId);
47
47
  await digNetwork.syncStoreFromPeers();
48
48
  }
49
+ static async getUdiContent(udi) {
50
+ // TODO: Implement this method
51
+ }
49
52
  static async findPeerWithStoreKey(storeId, rootHash, key, intialBlackList = []) {
50
53
  const peerBlackList = intialBlackList;
51
54
  const serverCoin = new blockchain_1.ServerCoin(storeId);
@@ -35,13 +35,11 @@ export declare class DataStore {
35
35
  private static calculateFolderSize;
36
36
  static getAllStores(): DataStore[];
37
37
  /**
38
- * Monitors the store indefinitely by syncing it with a peer.
39
- * Logs store retrieval and caching operations. If an error occurs, logs the error and restarts the process after a short delay.
40
- * Only one monitor can be active per storeId.
41
- * @param {string} storeId - The store identifier to monitor.
42
- * @returns {Promise<void>} Never resolves; runs indefinitely.
43
- */
44
- static monitorStoreIndefinitely(storeId: string): Promise<void>;
38
+ * Fetches the latest coin information using the StoreMonitorRegistry.
39
+ * Registers the storeId if it's not already registered, retrieves the cached value, and returns it.
40
+ *
41
+ * @returns {Promise<{ latestStore: DataStoreDriver; latestHeight: number; latestHash: Buffer }>}
42
+ */
45
43
  fetchCoinInfo(): Promise<{
46
44
  latestStore: DataStoreDriver;
47
45
  latestHeight: number;
@@ -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,8BAA8B,CAAC;AAYtC,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;AAgBjD,qBAAa,SAAS;IACpB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,IAAI,CAAoB;IAChC,OAAO,CAAC,MAAM,CAAC,cAAc,CAAmC;gBAEpD,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,wBAAwB;IAqB/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;IAWxC;;;;;;MAME;WACkB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA4HhE,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,CAAC,SAAS,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IA4C/D,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;IAgD3B;;;;;OAKG;IACU,qBAAqB,CAChC,QAAQ,EAAE,MAAM,EAChB,kBAAkB,GAAE,OAAe,GAClC,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CA6C7C"}
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,EAAE,MAAM,UAAU,CAAC;AAG3C,OAAO,EACL,iBAAiB,EACjB,wBAAwB,EACzB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAcjD,qBAAa,SAAS;IACpB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,IAAI,CAAoB;IAChC,OAAO,CAAC,MAAM,CAAC,cAAc,CAAmC;gBAEpD,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;IAWzC;;;;;OAKG;IACU,aAAa,IAAI,OAAO,CAAC;QACpC,WAAW,EAAE,eAAe,CAAC;QAC7B,YAAY,EAAE,MAAM,CAAC;QACrB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;IAkCW,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,CAAC,SAAS,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IA4C/D,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;IAgD3B;;;;;OAKG;IACU,qBAAqB,CAChC,QAAQ,EAAE,MAAM,EAChB,kBAAkB,GAAE,OAAe,GAClC,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CA6C7C"}
@@ -20,7 +20,7 @@ const FileCache_1 = require("../utils/FileCache");
20
20
  const DataStoreSerializer_1 = require("./DataStoreSerializer");
21
21
  const node_cache_1 = __importDefault(require("node-cache"));
22
22
  const config_2 = require("../utils/config");
23
- const utils_1 = require("../utils");
23
+ const StoreMonitorRegistry_1 = require("./StoreMonitorRegistry");
24
24
  // Initialize the cache with a TTL of 180 seconds (3 minutes)
25
25
  const rootHistoryCache = new node_cache_1.default({ stdTTL: 180 });
26
26
  const stat = (0, util_1.promisify)(fs_1.default.stat);
@@ -39,9 +39,6 @@ class DataStore {
39
39
  };
40
40
  }
41
41
  this.tree = new DataIntegrityTree_1.DataIntegrityTree(storeId, _options);
42
- if (!utils_1.Environment.CLI_MODE) {
43
- DataStore.monitorStoreIndefinitely(this.storeId);
44
- }
45
42
  }
46
43
  get StoreId() {
47
44
  return this.storeId;
@@ -205,143 +202,36 @@ class DataStore {
205
202
  return storIds.map((storeId) => DataStore.from(storeId));
206
203
  }
207
204
  /**
208
- * Monitors the store indefinitely by syncing it with a peer.
209
- * Logs store retrieval and caching operations. If an error occurs, logs the error and restarts the process after a short delay.
210
- * Only one monitor can be active per storeId.
211
- * @param {string} storeId - The store identifier to monitor.
212
- * @returns {Promise<void>} Never resolves; runs indefinitely.
213
- */
214
- static async monitorStoreIndefinitely(storeId) {
215
- // Check if a monitor is already running for this storeId
216
- if (this.activeMonitors.get(storeId)) {
217
- console.log("Monitor:", `Monitor already running for storeId: ${storeId}`);
218
- return;
219
- }
220
- // Set the monitor as active
221
- this.activeMonitors.set(storeId, true);
222
- const storeCoinCache = new FileCache_1.FileCache(`stores`);
223
- // Clear the cache at the start
224
- console.log("Monitor:", `Clearing cache for storeId: ${storeId}`);
225
- storeCoinCache.delete(storeId);
226
- while (true) {
227
- try {
228
- console.log("Monitor:", `Connecting to peer for storeId: ${storeId}`);
229
- const peer = await FullNodePeer_1.FullNodePeer.connect();
230
- const cachedInfo = storeCoinCache.get(storeId);
231
- if (cachedInfo) {
232
- // Log cached store info retrieval
233
- console.log("Monitor:", `Cached store info found for storeId: ${storeId}, syncing...`);
234
- // Deserialize cached info and wait for the coin to be spent
235
- const previousStore = DataStoreSerializer_1.DataStoreSerializer.deserialize({
236
- latestStore: cachedInfo.latestStore,
237
- latestHeight: cachedInfo.latestHeight.toString(),
238
- latestHash: cachedInfo.latestHash,
239
- });
240
- console.log("Monitor:", `Waiting for coin to be spent for storeId: ${storeId}...`);
241
- const dataStore = DataStore.from(storeId);
242
- const { createdAtHeight, createdAtHash } = await dataStore.getCreationHeight();
243
- await peer.waitForCoinToBeSpent((0, datalayer_driver_1.getCoinId)(previousStore.latestStore.coin), createdAtHeight, createdAtHash);
244
- // Sync store and get updated details
245
- console.log("Monitor:", `Syncing store for storeId: ${storeId}`);
246
- const { latestStore, latestHeight } = await peer.syncStore(previousStore.latestStore, createdAtHeight, createdAtHash, false);
247
- const latestHash = await peer.getHeaderHash(latestHeight);
248
- console.log("Monitor:", `Store synced for storeId: ${storeId}, coin id: ${(0, datalayer_driver_1.getCoinId)(latestStore.coin).toString("hex")}`);
249
- // Serialize and cache the updated store info
250
- const serializedLatestStore = new DataStoreSerializer_1.DataStoreSerializer(latestStore, latestHeight, latestHash).serialize();
251
- console.log("Monitor:", `Caching updated store info for storeId: ${storeId}`);
252
- storeCoinCache.set(storeId, {
253
- latestStore: serializedLatestStore,
254
- latestHeight,
255
- latestHash: latestHash.toString("hex"),
256
- });
257
- continue; // Continue monitoring
258
- }
259
- // If no cached info exists, log and sync from the creation height
260
- console.log("Monitor:", `No cached info found for storeId: ${storeId}. Retrieving creation height.`);
261
- const dataStore = DataStore.from(storeId);
262
- const { createdAtHeight, createdAtHash } = await dataStore.getCreationHeight();
263
- // Sync store from the peer using launcher ID
264
- console.log("Monitor:", `Syncing store from launcher ID for storeId: ${storeId}`);
265
- const { latestStore, latestHeight } = await peer.syncStoreFromLauncherId(Buffer.from(storeId, "hex"), createdAtHeight, createdAtHash, false);
266
- const latestHash = await peer.getHeaderHash(latestHeight);
267
- // Serialize and cache the new store info
268
- const serializedLatestStore = new DataStoreSerializer_1.DataStoreSerializer(latestStore, latestHeight, latestHash).serialize();
269
- console.log("Monitor:", `Caching new store info for storeId: ${storeId}`);
270
- storeCoinCache.set(storeId, {
271
- latestStore: serializedLatestStore,
272
- latestHeight,
273
- latestHash: latestHash.toString("hex"),
274
- });
275
- }
276
- catch (error) {
277
- console.error("Monitor:", `Error in monitorStoreIndefinitely for storeId: ${storeId} - ${error.message}`);
278
- // Delay before restarting to avoid rapid retries
279
- await new Promise((resolve) => setTimeout(resolve, 5000));
280
- }
281
- }
282
- }
205
+ * Fetches the latest coin information using the StoreMonitorRegistry.
206
+ * Registers the storeId if it's not already registered, retrieves the cached value, and returns it.
207
+ *
208
+ * @returns {Promise<{ latestStore: DataStoreDriver; latestHeight: number; latestHash: Buffer }>}
209
+ */
283
210
  async fetchCoinInfo() {
211
+ const storeMonitor = StoreMonitorRegistry_1.StoreMonitorRegistry.getInstance();
284
212
  try {
285
- // Initialize the cache for the current storeId's coin info
286
- const storeCoinCache = new FileCache_1.FileCache(`stores`);
287
- // Try to get cached store info
288
- const cachedInfo = storeCoinCache.get(this.storeId);
289
- if (cachedInfo) {
290
- try {
291
- const { latestStore: serializedStore, latestHeight: previousHeight, latestHash: previousHash, } = cachedInfo;
292
- // Deserialize the stored data using DataStoreSerializer
293
- const { latestStore: previousInfo } = DataStoreSerializer_1.DataStoreSerializer.deserialize({
294
- latestStore: serializedStore,
295
- latestHeight: previousHeight.toString(),
296
- latestHash: previousHash,
297
- });
298
- // Sync with peer if necessary
299
- const peer = await FullNodePeer_1.FullNodePeer.connect();
300
- const { latestStore, latestHeight } = await peer.syncStore(previousInfo, previousHeight, Buffer.from(previousHash, "hex"), false);
301
- const latestHash = await peer.getHeaderHash(latestHeight);
302
- // Serialize the store data for caching
303
- const serializedLatestStore = new DataStoreSerializer_1.DataStoreSerializer(latestStore, latestHeight, latestHash).serialize();
304
- // Cache updated store info
305
- storeCoinCache.set(this.storeId, {
306
- latestStore: serializedLatestStore,
307
- latestHeight,
308
- latestHash: latestHash.toString("hex"),
309
- });
310
- return { latestStore, latestHeight, latestHash };
311
- }
312
- catch {
313
- // Return cached info if sync fails
314
- const { latestStore, latestHeight, latestHash } = DataStoreSerializer_1.DataStoreSerializer.deserialize({
315
- latestStore: cachedInfo.latestStore,
316
- latestHeight: cachedInfo.latestHeight.toString(),
317
- latestHash: cachedInfo.latestHash,
318
- });
319
- return {
320
- latestStore,
321
- latestHeight,
322
- latestHash: latestHash,
323
- };
324
- }
213
+ // Register the storeId with a no-op callback. If already registered, the registry will handle it.
214
+ await storeMonitor.registerStore(this.storeId, () => {
215
+ // No operation callback since we're fetching the cache directly
216
+ });
217
+ // Retrieve the latest cached store information
218
+ const cachedInfo = await storeMonitor.getLatestCache(this.storeId);
219
+ if (!cachedInfo) {
220
+ throw new Error(`No cached info found for storeId: ${this.storeId}`);
325
221
  }
326
- // Use getCreationHeight to retrieve height and hash information
327
- const { createdAtHeight, createdAtHash } = await this.getCreationHeight();
328
- // Sync store from peer
329
- const peer = await FullNodePeer_1.FullNodePeer.connect();
330
- const { latestStore, latestHeight } = await peer.syncStoreFromLauncherId(Buffer.from(this.storeId, "hex"), createdAtHeight, createdAtHash, false);
331
- const latestHash = await peer.getHeaderHash(latestHeight);
332
- // Serialize the latest store info for caching
333
- const serializedLatestStore = new DataStoreSerializer_1.DataStoreSerializer(latestStore, latestHeight, latestHash).serialize();
334
- // Cache the latest store info
335
- storeCoinCache.set(this.storeId, {
336
- latestStore: serializedLatestStore,
337
- latestHeight,
338
- latestHash: latestHash.toString("hex"),
222
+ const deserializedStore = DataStoreSerializer_1.DataStoreSerializer.deserialize({
223
+ latestStore: cachedInfo.latestStore,
224
+ latestHeight: cachedInfo.latestHeight.toString(),
225
+ latestHash: cachedInfo.latestHash
339
226
  });
340
- return { latestStore, latestHeight, latestHash };
227
+ return {
228
+ latestStore: deserializedStore.latestStore,
229
+ latestHeight: deserializedStore.latestHeight,
230
+ latestHash: deserializedStore.latestHash,
231
+ };
341
232
  }
342
233
  catch (error) {
343
- console.trace("Failed to fetch coin info", error);
344
- throw error;
234
+ throw new Error(`Failed to fetch coin info for storeId ${this.storeId}: ${error.message}`);
345
235
  }
346
236
  }
347
237
  async cacheStoreCreationHeight() {
@@ -0,0 +1,85 @@
1
+ import { DataStoreSerializer } from "./DataStoreSerializer";
2
+ /**
3
+ * Represents the structure of cached store information.
4
+ */
5
+ interface StoreCacheEntry {
6
+ latestStore: ReturnType<DataStoreSerializer["serialize"]>;
7
+ latestHeight: number;
8
+ latestHash: string;
9
+ }
10
+ /**
11
+ * Callback type to be invoked when the store is updated.
12
+ */
13
+ type StoreUpdateCallback = (storeId: string, updatedStore: StoreCacheEntry) => void;
14
+ /**
15
+ * StoreMonitorRegistry manages monitoring of multiple storeIds.
16
+ * It encapsulates cache management and ensures only one monitor runs per storeId.
17
+ */
18
+ export declare class StoreMonitorRegistry {
19
+ private static instance;
20
+ private activeMonitors;
21
+ private storeCoinCache;
22
+ private cachePopulationPromises;
23
+ /**
24
+ * Private constructor to enforce singleton pattern.
25
+ */
26
+ private constructor();
27
+ /**
28
+ * Retrieves the singleton instance of the registry.
29
+ * @returns {StoreMonitorRegistry} The singleton instance.
30
+ */
31
+ static getInstance(): StoreMonitorRegistry;
32
+ /**
33
+ * Registers a storeId with a callback to be invoked upon updates.
34
+ * Immediately updates the cache and invokes the callback before starting the monitor.
35
+ * @param {string} storeId - The store identifier to monitor.
36
+ * @param {StoreUpdateCallback} callback - The callback to execute when the store is updated.
37
+ */
38
+ registerStore(storeId: string, callback: StoreUpdateCallback): Promise<void>;
39
+ /**
40
+ * Retrieves the latest cached entry for a given storeId.
41
+ * If no cache exists, it fetches and caches the store info before returning.
42
+ * @param {string} storeId - The store identifier.
43
+ * @returns {Promise<StoreCacheEntry>} The latest cached entry.
44
+ */
45
+ getLatestCache(storeId: string): Promise<StoreCacheEntry>;
46
+ /**
47
+ * Starts the monitor for a specific storeId.
48
+ * Ensures that the monitor restarts upon any error.
49
+ * Implements an exponential backoff strategy for retries.
50
+ * @param {string} storeId - The store identifier to monitor.
51
+ * @param {StoreUpdateCallback} callback - The callback to invoke upon updates.
52
+ */
53
+ private startMonitor;
54
+ /**
55
+ * Monitors a single store indefinitely.
56
+ * Executes a single iteration of the monitoring logic.
57
+ * @param {string} storeId - The store identifier to monitor.
58
+ * @param {StoreUpdateCallback} callback - The callback to invoke upon updates.
59
+ */
60
+ private monitorStore;
61
+ /**
62
+ * Fetches the latest store information and updates the cache.
63
+ * @param {string} storeId - The store identifier.
64
+ * @returns {Promise<StoreCacheEntry>} The latest store information.
65
+ */
66
+ private fetchAndCacheStoreInfo;
67
+ /**
68
+ * Utility method to introduce a delay.
69
+ * @param {number} ms - The delay duration in milliseconds.
70
+ * @returns {Promise<void>} Resolves after the specified delay.
71
+ */
72
+ private delay;
73
+ /**
74
+ * Unregisters a storeId, stopping its monitor.
75
+ * @param {string} storeId - The store identifier to stop monitoring.
76
+ */
77
+ unregisterStore(storeId: string): void;
78
+ /**
79
+ * Stops all active monitors and clears the registry.
80
+ * Useful for graceful shutdowns.
81
+ */
82
+ stopAllMonitors(): void;
83
+ }
84
+ export {};
85
+ //# sourceMappingURL=StoreMonitorRegistry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StoreMonitorRegistry.d.ts","sourceRoot":"","sources":["../../src/blockchain/StoreMonitorRegistry.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAK5D;;GAEG;AACH,UAAU,eAAe;IACvB,WAAW,EAAE,UAAU,CAAC,mBAAmB,CAAC,WAAW,CAAC,CAAC,CAAC;IAC1D,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,KAAK,mBAAmB,GAAG,CACzB,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,eAAe,KAC1B,IAAI,CAAC;AAEV;;;GAGG;AACH,qBAAa,oBAAoB;IAE/B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAuB;IAG9C,OAAO,CAAC,cAAc,CAAmC;IAGzD,OAAO,CAAC,cAAc,CAA6B;IAGnD,OAAO,CAAC,uBAAuB,CAAwC;IAEvE;;OAEG;IACH,OAAO;IASP;;;OAGG;WACW,WAAW,IAAI,oBAAoB;IAOjD;;;;;OAKG;IACU,aAAa,CACxB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,mBAAmB,GAC5B,OAAO,CAAC,IAAI,CAAC;IAiChB;;;;;OAKG;IACU,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAkCtE;;;;;;OAMG;YACW,YAAY;IA4B1B;;;;;OAKG;YACW,YAAY;IAuG1B;;;;OAIG;YACW,sBAAsB;IAkDpC;;;;OAIG;YACW,KAAK;IAInB;;;OAGG;IACI,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAS7C;;;OAGG;IACI,eAAe,IAAI,IAAI;CAI/B"}
@@ -0,0 +1,242 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.StoreMonitorRegistry = void 0;
4
+ const FullNodePeer_1 = require("./FullNodePeer");
5
+ const utils_1 = require("../utils");
6
+ const DataStoreSerializer_1 = require("./DataStoreSerializer");
7
+ const DataStore_1 = require("./DataStore");
8
+ const datalayer_driver_1 = require("@dignetwork/datalayer-driver");
9
+ const utils_2 = require("../utils");
10
+ /**
11
+ * StoreMonitorRegistry manages monitoring of multiple storeIds.
12
+ * It encapsulates cache management and ensures only one monitor runs per storeId.
13
+ */
14
+ class StoreMonitorRegistry {
15
+ /**
16
+ * Private constructor to enforce singleton pattern.
17
+ */
18
+ constructor() {
19
+ this.activeMonitors = new Map();
20
+ this.storeCoinCache = new utils_1.FileCache("stores", utils_1.USER_DIR_PATH);
21
+ this.cachePopulationPromises = new Map();
22
+ }
23
+ /**
24
+ * Retrieves the singleton instance of the registry.
25
+ * @returns {StoreMonitorRegistry} The singleton instance.
26
+ */
27
+ static getInstance() {
28
+ if (!StoreMonitorRegistry.instance) {
29
+ StoreMonitorRegistry.instance = new StoreMonitorRegistry();
30
+ }
31
+ return StoreMonitorRegistry.instance;
32
+ }
33
+ /**
34
+ * Registers a storeId with a callback to be invoked upon updates.
35
+ * Immediately updates the cache and invokes the callback before starting the monitor.
36
+ * @param {string} storeId - The store identifier to monitor.
37
+ * @param {StoreUpdateCallback} callback - The callback to execute when the store is updated.
38
+ */
39
+ async registerStore(storeId, callback) {
40
+ if (this.activeMonitors.has(storeId)) {
41
+ console.log(`Registry: Monitor already running for storeId: ${storeId}`);
42
+ return;
43
+ }
44
+ console.log(`Registry: Registering monitor for storeId: ${storeId}`);
45
+ this.activeMonitors.set(storeId, callback);
46
+ try {
47
+ // Immediately fetch and cache the latest store info
48
+ const initialStore = await this.fetchAndCacheStoreInfo(storeId);
49
+ // Invoke the callback with the initial store info
50
+ callback(storeId, initialStore);
51
+ }
52
+ catch (error) {
53
+ console.error(`Registry: Failed to perform initial cache update for storeId: ${storeId} - ${error.message}`);
54
+ // Decide whether to unregister the monitor or proceed
55
+ // For this example, we'll proceed to start the monitor
56
+ }
57
+ // No monitoring in cli mode
58
+ if (!utils_2.Environment.CLI_MODE) {
59
+ // Start monitoring asynchronously
60
+ this.startMonitor(storeId, callback).catch((error) => {
61
+ console.error(`Registry: Unexpected error in startMonitor for storeId: ${storeId} - ${error.message}`);
62
+ });
63
+ }
64
+ }
65
+ /**
66
+ * Retrieves the latest cached entry for a given storeId.
67
+ * If no cache exists, it fetches and caches the store info before returning.
68
+ * @param {string} storeId - The store identifier.
69
+ * @returns {Promise<StoreCacheEntry>} The latest cached entry.
70
+ */
71
+ async getLatestCache(storeId) {
72
+ // if in CLI mode, always fetch the latest store info directly
73
+ if (!utils_2.Environment.CLI_MODE) {
74
+ let cachedInfo = this.storeCoinCache.get(storeId);
75
+ if (cachedInfo) {
76
+ return cachedInfo;
77
+ }
78
+ // If cache is missing, fetch and cache it
79
+ console.log(`getLatestCache: No cache found for storeId: ${storeId}. Fetching...`);
80
+ // Prevent duplicate fetches for the same storeId
81
+ if (this.cachePopulationPromises.has(storeId)) {
82
+ return this.cachePopulationPromises.get(storeId);
83
+ }
84
+ }
85
+ const fetchPromise = this.fetchAndCacheStoreInfo(storeId)
86
+ .then((store) => {
87
+ this.cachePopulationPromises.delete(storeId);
88
+ return store;
89
+ })
90
+ .catch((error) => {
91
+ this.cachePopulationPromises.delete(storeId);
92
+ throw error;
93
+ });
94
+ this.cachePopulationPromises.set(storeId, fetchPromise);
95
+ return fetchPromise;
96
+ }
97
+ /**
98
+ * Starts the monitor for a specific storeId.
99
+ * Ensures that the monitor restarts upon any error.
100
+ * Implements an exponential backoff strategy for retries.
101
+ * @param {string} storeId - The store identifier to monitor.
102
+ * @param {StoreUpdateCallback} callback - The callback to invoke upon updates.
103
+ */
104
+ async startMonitor(storeId, callback) {
105
+ let retryCount = 0;
106
+ const maxRetryDelay = 60000; // 60 seconds
107
+ while (this.activeMonitors.has(storeId)) {
108
+ try {
109
+ await this.monitorStore(storeId, callback);
110
+ retryCount = 0; // Reset on success
111
+ }
112
+ catch (error) {
113
+ console.error(`Registry: Monitor for storeId: ${storeId} encountered an error: ${error.message}. Restarting monitor...`);
114
+ const delayTime = maxRetryDelay;
115
+ console.log(`Registry: Waiting for ${delayTime / 1000} seconds before retrying...`);
116
+ await this.delay(delayTime);
117
+ retryCount++;
118
+ }
119
+ }
120
+ console.log(`Registry: Monitor for storeId: ${storeId} has been stopped.`);
121
+ }
122
+ /**
123
+ * Monitors a single store indefinitely.
124
+ * Executes a single iteration of the monitoring logic.
125
+ * @param {string} storeId - The store identifier to monitor.
126
+ * @param {StoreUpdateCallback} callback - The callback to invoke upon updates.
127
+ */
128
+ async monitorStore(storeId, callback) {
129
+ console.log(`Monitor: Starting monitor iteration for storeId: ${storeId}`);
130
+ try {
131
+ console.log(`Monitor: Connecting to peer for storeId: ${storeId}`);
132
+ const peer = await FullNodePeer_1.FullNodePeer.connect();
133
+ const cachedInfo = this.storeCoinCache.get(storeId);
134
+ if (cachedInfo) {
135
+ // Log cached store info retrieval
136
+ console.log(`Monitor: Cached store info found for storeId: ${storeId}, syncing...`);
137
+ // Deserialize cached info and wait for the coin to be spent
138
+ const previousStore = DataStoreSerializer_1.DataStoreSerializer.deserialize({
139
+ latestStore: cachedInfo.latestStore,
140
+ latestHeight: cachedInfo.latestHeight.toString(),
141
+ latestHash: cachedInfo.latestHash,
142
+ });
143
+ console.log(`Monitor: Waiting for coin to be spent for storeId: ${storeId}...`);
144
+ const dataStore = DataStore_1.DataStore.from(storeId);
145
+ const { createdAtHeight, createdAtHash } = await dataStore.getCreationHeight();
146
+ await peer.waitForCoinToBeSpent((0, datalayer_driver_1.getCoinId)(previousStore.latestStore.coin), createdAtHeight, createdAtHash);
147
+ // Sync store and get updated details
148
+ console.log(`Monitor: Syncing store for storeId: ${storeId}`);
149
+ const { latestStore, latestHeight } = await peer.syncStore(previousStore.latestStore, createdAtHeight, createdAtHash, false);
150
+ const latestHash = await peer.getHeaderHash(latestHeight);
151
+ console.log(`Monitor: Store synced for storeId: ${storeId}, coin id: ${(0, datalayer_driver_1.getCoinId)(latestStore.coin).toString("hex")}`);
152
+ // Serialize and cache the updated store info
153
+ const serializedLatestStore = new DataStoreSerializer_1.DataStoreSerializer(latestStore, latestHeight, latestHash).serialize();
154
+ console.log(`Monitor: Caching updated store info for storeId: ${storeId}`);
155
+ this.storeCoinCache.set(storeId, {
156
+ latestStore: serializedLatestStore,
157
+ latestHeight,
158
+ latestHash: latestHash.toString("hex"),
159
+ });
160
+ // Invoke the callback with updated store info
161
+ const updatedStore = this.storeCoinCache.get(storeId);
162
+ if (updatedStore) {
163
+ callback(storeId, updatedStore);
164
+ }
165
+ else {
166
+ console.warn(`Monitor: Updated store info for storeId: ${storeId} is missing after caching.`);
167
+ }
168
+ return; // Successful iteration
169
+ }
170
+ // If no cached info exists, fetch initial store info
171
+ console.log(`Monitor: No cached info found for storeId: ${storeId}. Fetching initial store info.`);
172
+ // Fetch and cache the latest store info
173
+ const newStore = await this.fetchAndCacheStoreInfo(storeId);
174
+ // Invoke the callback with the new store info
175
+ callback(storeId, newStore);
176
+ }
177
+ catch (error) {
178
+ console.error(`Monitor: Error monitoring storeId: ${storeId} - ${error.message}`);
179
+ // Propagate the error to trigger a restart in startMonitor
180
+ throw error;
181
+ }
182
+ }
183
+ /**
184
+ * Fetches the latest store information and updates the cache.
185
+ * @param {string} storeId - The store identifier.
186
+ * @returns {Promise<StoreCacheEntry>} The latest store information.
187
+ */
188
+ async fetchAndCacheStoreInfo(storeId) {
189
+ console.log(`Monitor: Fetching and caching latest store info for storeId: ${storeId}`);
190
+ const peer = await FullNodePeer_1.FullNodePeer.connect();
191
+ const dataStore = DataStore_1.DataStore.from(storeId);
192
+ const { createdAtHeight, createdAtHash } = await dataStore.getCreationHeight();
193
+ // Sync store from the peer using launcher ID
194
+ console.log(`Monitor: Syncing store from launcher ID for storeId: ${storeId}`);
195
+ const { latestStore, latestHeight } = await peer.syncStoreFromLauncherId(Buffer.from(storeId, "hex"), createdAtHeight, createdAtHash, false);
196
+ const latestHash = await peer.getHeaderHash(latestHeight);
197
+ // Serialize and cache the new store info
198
+ const serializedLatestStore = new DataStoreSerializer_1.DataStoreSerializer(latestStore, latestHeight, latestHash).serialize();
199
+ console.log(`Monitor: Caching new store info for storeId: ${storeId}`);
200
+ this.storeCoinCache.set(storeId, {
201
+ latestStore: serializedLatestStore,
202
+ latestHeight,
203
+ latestHash: latestHash.toString("hex"),
204
+ });
205
+ // Return the cached store info
206
+ const newStore = this.storeCoinCache.get(storeId);
207
+ if (!newStore) {
208
+ throw new Error(`Failed to cache store info for storeId: ${storeId} after fetching.`);
209
+ }
210
+ return newStore;
211
+ }
212
+ /**
213
+ * Utility method to introduce a delay.
214
+ * @param {number} ms - The delay duration in milliseconds.
215
+ * @returns {Promise<void>} Resolves after the specified delay.
216
+ */
217
+ async delay(ms) {
218
+ return new Promise((resolve) => setTimeout(resolve, ms));
219
+ }
220
+ /**
221
+ * Unregisters a storeId, stopping its monitor.
222
+ * @param {string} storeId - The store identifier to stop monitoring.
223
+ */
224
+ unregisterStore(storeId) {
225
+ if (this.activeMonitors.has(storeId)) {
226
+ this.activeMonitors.delete(storeId);
227
+ console.log(`Registry: Unregistered monitor for storeId: ${storeId}`);
228
+ }
229
+ else {
230
+ console.log(`Registry: No active monitor found for storeId: ${storeId}`);
231
+ }
232
+ }
233
+ /**
234
+ * Stops all active monitors and clears the registry.
235
+ * Useful for graceful shutdowns.
236
+ */
237
+ stopAllMonitors() {
238
+ this.activeMonitors.clear();
239
+ console.log(`Registry: All monitors have been stopped.`);
240
+ }
241
+ }
242
+ exports.StoreMonitorRegistry = StoreMonitorRegistry;
@@ -5,4 +5,5 @@ export * from './FullNodePeer';
5
5
  export * from './DataStoreSerializer';
6
6
  export * from './ServerCoin';
7
7
  export * from "./Wallet";
8
+ export * from './StoreMonitorRegistry';
8
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/blockchain/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,OAAO,KAAK,KAAK,MAAM,SAAS,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAa,gBAAgB,CAAC;AAC9B,cAAc,uBAAuB,CAAC;AACtC,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/blockchain/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,OAAO,KAAK,KAAK,MAAM,SAAS,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAa,gBAAgB,CAAC;AAC9B,cAAc,uBAAuB,CAAC;AACtC,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,wBAAwB,CAAC"}
@@ -34,3 +34,4 @@ __exportStar(require("./FullNodePeer"), exports);
34
34
  __exportStar(require("./DataStoreSerializer"), exports);
35
35
  __exportStar(require("./ServerCoin"), exports);
36
36
  __exportStar(require("./Wallet"), exports);
37
+ __exportStar(require("./StoreMonitorRegistry"), exports);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dignetwork/dig-sdk",
3
- "version": "0.0.1-alpha.124",
3
+ "version": "0.0.1-alpha.126",
4
4
  "description": "",
5
5
  "type": "commonjs",
6
6
  "main": "./dist/index.js",
@@ -26,6 +26,7 @@
26
26
  ],
27
27
  "dependencies": {
28
28
  "@dignetwork/datalayer-driver": "^0.1.29",
29
+ "@dignetwork/dig-sdk": "^0.0.1-alpha.124",
29
30
  "archiver": "^7.0.1",
30
31
  "axios": "^1.7.7",
31
32
  "bip39": "^3.1.0",
@@ -1,16 +0,0 @@
1
- export declare class StoreInfoCacheUpdater {
2
- private static instance;
3
- private storeCoinCache;
4
- private monitors;
5
- private lockFilePath;
6
- private releaseLock;
7
- private isMonitoring;
8
- private lockRenewalInterval;
9
- private constructor();
10
- static initInstance(): StoreInfoCacheUpdater;
11
- private startMonitors;
12
- private renewLock;
13
- private monitorStore;
14
- private isUnrecoverableError;
15
- }
16
- //# sourceMappingURL=StoreInfoCacheUpdater.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"StoreInfoCacheUpdater.d.ts","sourceRoot":"","sources":["../../src/blockchain/StoreInfoCacheUpdater.ts"],"names":[],"mappings":"AAcA,qBAAa,qBAAqB;IAChC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAwB;IAC/C,OAAO,CAAC,cAAc,CAIsB;IAC5C,OAAO,CAAC,QAAQ,CAAyC;IACzD,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,WAAW,CAAsC;IACzD,OAAO,CAAC,YAAY,CAAiB;IACrC,OAAO,CAAC,mBAAmB,CAA+B;IAE1D,OAAO;WAiBO,YAAY,IAAI,qBAAqB;YAQrC,aAAa;IA6E3B,OAAO,CAAC,SAAS;YA0BH,YAAY;IAyI1B,OAAO,CAAC,oBAAoB;CAG7B"}
@@ -1,242 +0,0 @@
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.StoreInfoCacheUpdater = void 0;
30
- const fs_1 = __importDefault(require("fs"));
31
- const FullNodePeer_1 = require("./FullNodePeer");
32
- const utils_1 = require("../utils");
33
- const DataStoreSerializer_1 = require("./DataStoreSerializer");
34
- const utils_2 = require("../utils");
35
- const lockfile = __importStar(require("proper-lockfile"));
36
- const path = __importStar(require("path"));
37
- const datalayer_driver_1 = require("@dignetwork/datalayer-driver");
38
- class StoreInfoCacheUpdater {
39
- constructor() {
40
- this.storeCoinCache = new utils_1.FileCache(`stores`, utils_1.USER_DIR_PATH);
41
- this.monitors = new Map();
42
- this.releaseLock = null;
43
- this.isMonitoring = true;
44
- this.lockRenewalInterval = null;
45
- console.log("Constructor: Initializing StoreInfoCacheUpdater");
46
- // Construct lock file path using the path module
47
- this.lockFilePath = path.join(utils_1.USER_DIR_PATH, "store-info-cache.lock");
48
- console.log("Lock file path:", this.lockFilePath);
49
- const lockDir = path.dirname(this.lockFilePath);
50
- if (!fs_1.default.existsSync(lockDir)) {
51
- console.log(`Creating lock directory: ${lockDir}`);
52
- fs_1.default.mkdirSync(lockDir, { recursive: true });
53
- }
54
- // Start monitors for existing storeIds
55
- this.startMonitors();
56
- }
57
- static initInstance() {
58
- if (!StoreInfoCacheUpdater.instance) {
59
- console.log("Initializing DataStore Monitor");
60
- StoreInfoCacheUpdater.instance = new StoreInfoCacheUpdater();
61
- }
62
- return StoreInfoCacheUpdater.instance;
63
- }
64
- async startMonitors() {
65
- try {
66
- console.log("Checking if lockfile exists...");
67
- // Check if the lock file exists
68
- if (!fs_1.default.existsSync(this.lockFilePath)) {
69
- console.log("Lockfile does not exist. Proceeding without lock.");
70
- }
71
- else {
72
- // Check if the lockfile is already held
73
- const isLocked = await lockfile.check(this.lockFilePath, {
74
- realpath: false,
75
- });
76
- if (isLocked) {
77
- console.log("Another process is already running the StoreInfoCacheUpdater.");
78
- return;
79
- }
80
- }
81
- // Attempt to acquire the lock
82
- console.log("Attempting to acquire lock...");
83
- this.releaseLock = await lockfile.lock(this.lockFilePath, {
84
- retries: {
85
- retries: 0, // No retries since we only need one lock
86
- },
87
- stale: 60000, // Lock expires after 1 minute
88
- realpath: false, // Ensure lockfile uses the exact path
89
- });
90
- console.log("Lock acquired, starting monitors...");
91
- // Renew the lock every minute by reacquiring it
92
- this.renewLock();
93
- const storeIds = this.storeCoinCache.getCachedKeys();
94
- console.log(`Found ${storeIds.length} store IDs in cache:`, storeIds);
95
- for (const storeId of storeIds) {
96
- // Check if a monitor is already running for this storeId
97
- if (!this.monitors.has(storeId)) {
98
- console.log(`Starting monitor for storeId: ${storeId}`);
99
- // Start monitoring in the background
100
- const monitorPromise = this.monitorStore(storeId);
101
- this.monitors.set(storeId, monitorPromise);
102
- }
103
- else {
104
- console.log(`Monitor already exists for storeId: ${storeId}`);
105
- }
106
- }
107
- this.isMonitoring = true;
108
- // Wait for all monitors to settle
109
- const monitorPromises = Array.from(this.monitors.values());
110
- console.log("Waiting for all monitor promises to settle...");
111
- await Promise.all(monitorPromises);
112
- }
113
- catch (error) {
114
- console.error("Monitor system encountered an error:", error);
115
- }
116
- finally {
117
- // Release the lock
118
- if (this.releaseLock) {
119
- try {
120
- console.log("Releasing lock...");
121
- await this.releaseLock();
122
- console.log("Lock released successfully.");
123
- }
124
- catch (releaseError) {
125
- console.error("Error releasing the lock:", releaseError);
126
- }
127
- }
128
- // Clear the lock renewal interval
129
- if (this.lockRenewalInterval) {
130
- clearInterval(this.lockRenewalInterval);
131
- this.lockRenewalInterval = null;
132
- }
133
- }
134
- }
135
- renewLock() {
136
- // Set up a renewal process that releases and reacquires the lock every minute
137
- this.lockRenewalInterval = setInterval(async () => {
138
- try {
139
- if (this.releaseLock) {
140
- console.log("Releasing the lock for renewal...");
141
- await this.releaseLock();
142
- console.log("Lock released for renewal.");
143
- }
144
- // Reacquire the lock
145
- this.releaseLock = await lockfile.lock(this.lockFilePath, {
146
- retries: {
147
- retries: 0, // No retries since we only need one lock
148
- },
149
- stale: 60000, // Lock expires after 1 minute
150
- realpath: false, // Ensure lockfile uses the exact path
151
- });
152
- console.log("Lock reacquired for renewal.");
153
- }
154
- catch (error) {
155
- console.error("Error renewing the lock:", error);
156
- }
157
- }, 60000); // Renew the lock every 60 seconds
158
- }
159
- // Monitor a single store's coin
160
- async monitorStore(storeId) {
161
- while (this.isMonitoring) {
162
- let peer = null;
163
- try {
164
- console.log(`Monitoring store ${storeId}`);
165
- // Connect to a peer
166
- peer = await (0, utils_2.withTimeout)(FullNodePeer_1.FullNodePeer.connect(), 60000, "Timeout connecting to FullNodePeer");
167
- // Get the latest store info (from cache if available)
168
- const cachedInfo = this.storeCoinCache.get(storeId);
169
- if (!cachedInfo) {
170
- // If no cached info, skip and wait before retrying
171
- console.error(`No cached info for storeId ${storeId}`);
172
- await new Promise((resolve) => setTimeout(resolve, 5000));
173
- continue;
174
- }
175
- const { latestStore: serializedStore, latestHeight, latestHash, } = cachedInfo;
176
- const { latestStore } = DataStoreSerializer_1.DataStoreSerializer.deserialize({
177
- latestStore: serializedStore,
178
- latestHeight: latestHeight.toString(),
179
- latestHash: latestHash,
180
- });
181
- // Get the coinId associated with the store
182
- const coinId = (0, datalayer_driver_1.getCoinId)(latestStore.coin);
183
- console.log(`Waiting for coin to be spent: ${coinId.toString("hex")}`);
184
- try {
185
- // Wait for the coin to be spent
186
- await peer.waitForCoinToBeSpent(coinId, latestHeight, Buffer.from(latestHash, "hex"));
187
- }
188
- catch {
189
- const genesisChallenge = await (0, datalayer_driver_1.getMainnetGenesisChallenge)();
190
- const storeInfo = await (0, utils_2.withTimeout)(peer.syncStore(latestStore, null, genesisChallenge, false), 60000, `Timeout syncing store for storeId ${storeId}`);
191
- const headerHash = await peer.getHeaderHash(storeInfo.latestHeight);
192
- await peer.waitForCoinToBeSpent((0, datalayer_driver_1.getCoinId)(storeInfo.latestStore.coin), storeInfo.latestHeight, headerHash);
193
- }
194
- console.log(`Detected Coin Spend: ${coinId.toString("hex")}`);
195
- let updatedStore, newHeight;
196
- try {
197
- // When resolved, sync the store
198
- const storeInfo = await (0, utils_2.withTimeout)(peer.syncStore(latestStore, latestHeight, Buffer.from(latestHash, "hex"), false // withHistory
199
- ), 60000, `Timeout syncing store for storeId ${storeId}`);
200
- updatedStore = storeInfo.latestStore;
201
- newHeight = storeInfo.latestHeight;
202
- }
203
- catch {
204
- const genesisChallenge = await (0, datalayer_driver_1.getMainnetGenesisChallenge)();
205
- const storeInfo = await (0, utils_2.withTimeout)(peer.syncStore(latestStore, null, genesisChallenge, false), 60000, `Timeout syncing store for storeId ${storeId}`);
206
- updatedStore = storeInfo.latestStore;
207
- newHeight = storeInfo.latestHeight;
208
- }
209
- // Get the latest header hash
210
- const latestHashBuffer = await (0, utils_2.withTimeout)(peer.getHeaderHash(newHeight), 60000, `Timeout getting header hash for height ${newHeight}`);
211
- // Serialize the updated store data for caching
212
- const serializedLatestStore = new DataStoreSerializer_1.DataStoreSerializer(updatedStore, newHeight, latestHashBuffer).serialize();
213
- // Update the cache
214
- this.storeCoinCache.set(storeId, {
215
- latestStore: serializedLatestStore,
216
- latestHeight: newHeight,
217
- latestHash: latestHashBuffer.toString("hex"),
218
- });
219
- peer = null;
220
- // Continue monitoring
221
- }
222
- catch (error) {
223
- console.error(`Error monitoring store ${storeId}:`, error);
224
- // Close the peer connection if it's open
225
- if (peer) {
226
- peer = null;
227
- }
228
- // Determine if the error is unrecoverable
229
- if (this.isUnrecoverableError(error)) {
230
- this.isMonitoring = false; // Signal other monitors to stop
231
- throw error; // Propagate error up to stop monitoring
232
- }
233
- // Wait before retrying
234
- await new Promise((resolve) => setTimeout(resolve, 5000));
235
- }
236
- }
237
- }
238
- isUnrecoverableError(error) {
239
- return true;
240
- }
241
- }
242
- exports.StoreInfoCacheUpdater = StoreInfoCacheUpdater;