@dignetwork/dig-sdk 0.0.1-alpha.150 → 0.0.1-alpha.151

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.
@@ -7,17 +7,17 @@ export declare class DigNetwork {
7
7
  private static networkSyncMap;
8
8
  constructor(storeId: string);
9
9
  static subscribeToStore(storeId: string): Promise<void>;
10
+ static getAllNetworkDataStoreIds(): string[];
10
11
  static getUdiContent(udi: string): Promise<void>;
11
12
  /**
12
- * Find a peer that has the store key and root hash.
13
+ * Find a peer that has the store key and root hash, using ranked peers first and searching in groups of 5.
13
14
  *
14
15
  * @param {string} storeId - The ID of the store.
15
16
  * @param {string} rootHash - The root hash of the store.
16
17
  * @param {string} [key] - Optional key to check for in the store.
17
- * @param {string[]} [initialBlackList] - Initial list of blacklisted peer IPs.
18
18
  * @returns {Promise<DigPeer | null>} - A valid peer or null if none found.
19
19
  */
20
- static findPeerWithStoreKey(storeId: string, rootHash: string, key?: string, initialBlackList?: string[]): Promise<DigPeer | null>;
20
+ static findPeerWithStoreKey(storeId: string, rootHash: string, key?: string): Promise<DigPeer | null>;
21
21
  static unsubscribeFromStore(storeId: string): void;
22
22
  static pingNetworkOfUpdate(storeId: string, rootHash: string): Promise<void>;
23
23
  syncStoreFromPeers(prioritizedPeer?: DigPeer, 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;AAKpC,qBAAa,UAAU;IACrB,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,aAAa,CAA2B;IAChD,OAAO,CAAC,MAAM,CAAC,cAAc,CAAmC;gBAEpD,OAAO,EAAE,MAAM;WAOP,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;WAQhD,aAAa,CAAC,GAAG,EAAE,MAAM;IAI7C;;;;;;;;OAQG;WACiB,oBAAoB,CACtC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,GAAG,CAAC,EAAE,MAAM,EACZ,gBAAgB,GAAE,MAAM,EAAO,GAC9B,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;WA6EZ,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;WAOrC,mBAAmB,CACrC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC;IAcH,kBAAkB,CAC7B,eAAe,CAAC,EAAE,OAAO,EACzB,iBAAiB,CAAC,EAAE,MAAM,GACzB,OAAO,CAAC,IAAI,CAAC;IAgHH,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;AAKpC,qBAAa,UAAU;IACrB,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,aAAa,CAA2B;IAChD,OAAO,CAAC,MAAM,CAAC,cAAc,CAAmC;gBAEpD,OAAO,EAAE,MAAM;WAOP,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;WAQtD,yBAAyB,IAAI,MAAM,EAAE;WAI/B,aAAa,CAAC,GAAG,EAAE,MAAM;IAI7C;;;;;;;OAOG;WACiB,oBAAoB,CACtC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,GAAG,CAAC,EAAE,MAAM,GACX,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;WAsFZ,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;WAOrC,mBAAmB,CACrC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC;IAcH,kBAAkB,CAC7B,eAAe,CAAC,EAAE,OAAO,EACzB,iBAAiB,CAAC,EAAE,MAAM,GACzB,OAAO,CAAC,IAAI,CAAC;IAqFH,mBAAmB,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;CAUvD"}
@@ -44,74 +44,75 @@ class DigNetwork {
44
44
  const digNetwork = new DigNetwork(storeId);
45
45
  await digNetwork.syncStoreFromPeers();
46
46
  }
47
+ static getAllNetworkDataStoreIds() {
48
+ throw new Error("Method not implemented.");
49
+ }
47
50
  static async getUdiContent(udi) {
48
- // TODO: Implement this method
51
+ throw new Error("Method not implemented.");
49
52
  }
50
53
  /**
51
- * Find a peer that has the store key and root hash.
54
+ * Find a peer that has the store key and root hash, using ranked peers first and searching in groups of 5.
52
55
  *
53
56
  * @param {string} storeId - The ID of the store.
54
57
  * @param {string} rootHash - The root hash of the store.
55
58
  * @param {string} [key] - Optional key to check for in the store.
56
- * @param {string[]} [initialBlackList] - Initial list of blacklisted peer IPs.
57
59
  * @returns {Promise<DigPeer | null>} - A valid peer or null if none found.
58
60
  */
59
- static async findPeerWithStoreKey(storeId, rootHash, key, initialBlackList = []) {
60
- const peerBlackList = new Set(initialBlackList);
61
+ static async findPeerWithStoreKey(storeId, rootHash, key) {
61
62
  const serverCoin = new blockchain_1.ServerCoin(storeId);
62
- while (true) {
63
- try {
64
- // Sample 10 peers from the current epoch excluding blacklisted peers
65
- const digPeers = await serverCoin.sampleCurrentEpoch(10, Array.from(peerBlackList));
66
- // If no peers are returned, break out of the loop
67
- if (digPeers.length === 0) {
68
- console.log("No more peers found.");
69
- break;
70
- }
71
- // Create a race of promises for all peers
72
- const peerPromises = digPeers.map((peerIp) => {
73
- return new Promise(async (resolve) => {
74
- try {
75
- const digPeer = new DigPeer_1.DigPeer(peerIp, storeId);
76
- const { storeExists, rootHashExists } = await digPeer.propagationServer.checkStoreExists(rootHash);
77
- // Check if the store and root hash exist on the peer
78
- if (storeExists && rootHashExists) {
79
- console.log(`Found Peer at ${peerIp} for storeId: ${storeId}, root hash ${rootHash}`);
80
- // If no key is provided, resolve the peer
81
- if (!key) {
82
- return resolve(digPeer);
83
- }
84
- // If key is provided, check if the peer has it
85
- const keyResponse = await digPeer.contentServer.headKey(key, rootHash);
86
- if (keyResponse.headers?.["x-key-exists"] === "true") {
87
- return resolve(digPeer);
88
- }
89
- }
63
+ try {
64
+ // Fetch all active peers for the current epoch
65
+ const digPeers = await serverCoin.getActiveEpochPeers();
66
+ // If no peers are returned, exit early
67
+ if (digPeers.length === 0) {
68
+ console.log("No peers found.");
69
+ return null;
70
+ }
71
+ // Initialize PeerRanker with the list of digPeers (IP addresses)
72
+ const peerRanker = new utils_1.PeerRanker(digPeers);
73
+ // Rank the peers based on latency and bandwidth
74
+ const rankedPeers = await peerRanker.rankPeers();
75
+ // If no peers are returned after ranking, exit early
76
+ if (rankedPeers.length === 0) {
77
+ console.log("No valid peers found after ranking.");
78
+ return null;
79
+ }
80
+ // Define the iterator function to process each peer
81
+ const iteratorFn = async (peerMetrics) => {
82
+ const peerIp = peerMetrics.ip;
83
+ try {
84
+ const digPeer = new DigPeer_1.DigPeer(peerIp, storeId);
85
+ // Wrap the store check with a 10-second timeout
86
+ const { storeExists, rootHashExists } = await (0, utils_1.withTimeout)(digPeer.propagationServer.checkStoreExists(rootHash), 10000, `Timeout while checking store on peer ${peerIp}`);
87
+ // Check if the store and root hash exist on the peer
88
+ if (storeExists && rootHashExists) {
89
+ console.log(`Found Peer at ${peerIp} for storeId: ${storeId}, root hash ${rootHash}`);
90
+ // If no key is provided, return the peer
91
+ if (!key) {
92
+ return digPeer;
90
93
  }
91
- catch (error) {
92
- console.error(`Error connecting to DIG Peer ${peerIp}.`);
94
+ // If key is provided, wrap key check with a 10-second timeout
95
+ const keyResponse = await (0, utils_1.withTimeout)(digPeer.contentServer.headKey(key, rootHash), 10000, `Timeout while checking key on peer ${peerIp}`);
96
+ if (keyResponse.headers?.["x-key-exists"] === "true") {
97
+ return digPeer;
93
98
  }
94
- // If the peer does not meet the criteria, resolve with null
95
- resolve(null);
96
- });
97
- });
98
- // Wait for the first valid peer that resolves
99
- const firstValidPeer = await Promise.race(peerPromises);
100
- // If a valid peer is found, return it
101
- if (firstValidPeer) {
102
- return firstValidPeer;
99
+ }
103
100
  }
104
- // If none of the peers were valid, add them to the blacklist
105
- digPeers.forEach((peerIp) => peerBlackList.add(peerIp));
106
- // Retry with the next set of peers
107
- console.log("No valid peers found, retrying with new peers...");
108
- }
109
- catch (error) {
110
- console.error("Error sampling peers. Resampling...");
111
- }
101
+ catch (error) {
102
+ console.error(`Error connecting to DIG Peer ${peerIp}:`, error.message);
103
+ }
104
+ // If the peer does not meet the criteria, return null
105
+ return null;
106
+ };
107
+ // Use Promise.race to return the first valid peer found
108
+ const validPeer = await Promise.race(rankedPeers.map((peer) => iteratorFn(peer)));
109
+ // Return the first valid peer or null if none is found
110
+ return validPeer || null;
111
+ }
112
+ catch (error) {
113
+ console.error("Error sampling peers:", error);
114
+ return null;
112
115
  }
113
- // Return null if no valid peer was found after all attempts
114
- return null;
115
116
  }
116
117
  static unsubscribeFromStore(storeId) {
117
118
  fs.rmdirSync(path.join(config_1.DIG_FOLDER_PATH, "stores", storeId), {
@@ -135,7 +136,6 @@ class DigNetwork {
135
136
  }
136
137
  console.log("Starting network sync for store:", this.dataStore.StoreId);
137
138
  DigNetwork.networkSyncMap.set(this.dataStore.StoreId, true);
138
- let peerBlackList = [];
139
139
  try {
140
140
  const rootHistory = await this.dataStore.getRootHistory();
141
141
  if (!rootHistory.length) {
@@ -156,41 +156,24 @@ class DigNetwork {
156
156
  : rootHistoryFiltered;
157
157
  // Process the root hashes sequentially
158
158
  for (const rootInfo of rootsToProcess) {
159
- let selectedPeer = null;
160
- while (true) {
161
- try {
162
- // Find a peer with the store and root hash
163
- if (prioritizedPeer) {
164
- selectedPeer = prioritizedPeer;
165
- }
166
- else {
167
- selectedPeer = await DigNetwork.findPeerWithStoreKey(this.dataStore.StoreId, rootInfo.root_hash, undefined, peerBlackList);
168
- }
169
- if (!selectedPeer) {
170
- console.error(`No peer found with root hash ${rootInfo.root_hash}. Moving to next root.`);
171
- break; // Exit the while loop to proceed to the next rootInfo
172
- }
173
- // Check if the selected peer has the store and root hash
174
- const { storeExists, rootHashExists } = await selectedPeer.propagationServer.checkStoreExists(rootInfo.root_hash);
175
- if (!storeExists || !rootHashExists) {
176
- console.warn(`Peer ${selectedPeer.IpAddress} does not have the required store or root hash. Trying another peer...`);
177
- peerBlackList.push(selectedPeer.IpAddress); // Blacklist and retry
178
- continue;
179
- }
180
- // Download the store root and associated data
181
- await selectedPeer.downloadStoreRoot(rootInfo.root_hash);
182
- // Clear the blacklist upon successful download
183
- peerBlackList = [];
184
- // Break after successful download to proceed to next root hash
185
- break;
159
+ try {
160
+ let selectedPeer = prioritizedPeer || null;
161
+ if (!selectedPeer) {
162
+ // Use the `findPeerWithStoreKey` method to find a peer with the store and root hash
163
+ selectedPeer = await DigNetwork.findPeerWithStoreKey(this.dataStore.StoreId, rootInfo.root_hash);
186
164
  }
187
- catch (error) {
188
- if (error.message)
189
- console.error(`Error downloading from peer ${selectedPeer?.IpAddress}. Retrying with another peer.`, error);
190
- if (selectedPeer) {
191
- peerBlackList.push(selectedPeer.IpAddress); // Blacklist and retry
192
- }
165
+ if (!selectedPeer) {
166
+ console.error(`No peer found with root hash ${rootInfo.root_hash}. Moving to next root.`);
167
+ continue; // Move to the next rootInfo
193
168
  }
169
+ // Download the store root and associated data
170
+ await selectedPeer.downloadStoreRoot(rootInfo.root_hash);
171
+ // Break after successful download to proceed to next root hash
172
+ }
173
+ catch (error) {
174
+ if (error.message)
175
+ console.error(`Error downloading from peer ${prioritizedPeer?.IpAddress}. Retrying with another peer.`, error);
176
+ // Continue to next rootInfo in case of error
194
177
  }
195
178
  }
196
179
  console.log("Syncing store complete.");
@@ -102,7 +102,7 @@ class StoreMonitorRegistry {
102
102
  */
103
103
  async startMonitor(storeId, callback) {
104
104
  let retryCount = 0;
105
- const maxRetryDelay = 60000; // 60 seconds
105
+ const maxRetryDelay = 1000; // 60 seconds
106
106
  while (this.activeMonitors.has(storeId)) {
107
107
  try {
108
108
  await this.monitorStore(storeId, callback);
@@ -22,12 +22,14 @@ export declare class PeerRanker {
22
22
  /**
23
23
  * Measures the latency of a given IP address using an HTTPS request.
24
24
  * Tries HEAD first, then falls back to GET if HEAD is not supported.
25
+ * If the latency is cached, returns the cached value.
25
26
  * @param ip - The IP address of the peer.
26
27
  * @returns Promise resolving to the latency in milliseconds or rejecting if the peer fails.
27
28
  */
28
29
  private measureLatency;
29
30
  /**
30
31
  * Measures the upload bandwidth of a given IP address by sending random data.
32
+ * If the bandwidth is cached, returns the cached value.
31
33
  * @param ip - The IP address of the peer.
32
34
  * @returns Promise resolving to the upload bandwidth in bytes per second or rejecting if the peer fails.
33
35
  */
@@ -1 +1 @@
1
- {"version":3,"file":"PeerRanker.d.ts","sourceRoot":"","sources":["../../src/utils/PeerRanker.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,WAAW,CAAW;IAC9B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAS;IAChC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAS;IAC/B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,cAAc,CAAS;IAG/B,OAAO,CAAC,WAAW,CAAqB;IACxC,OAAO,CAAC,YAAY,CAAa;IAEjC;;;OAGG;gBACS,WAAW,EAAE,MAAM,EAAE,EAAE,OAAO,GAAE,MAAa,EAAE,cAAc,GAAE,MAAoB;IAW/F;;;;;OAKG;YACW,cAAc;IA2C5B;;;;OAIG;YACW,gBAAgB;IAmC9B;;;;;OAKG;IACU,SAAS,CAAC,QAAQ,GAAE,MAAY,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAmCtE;;;;OAIG;IACI,eAAe,IAAI,WAAW,GAAG,IAAI;IAW5C;;OAEG;IACI,aAAa,IAAI,IAAI;CAG7B"}
1
+ {"version":3,"file":"PeerRanker.d.ts","sourceRoot":"","sources":["../../src/utils/PeerRanker.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,WAAW,CAAW;IAC9B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAS;IAChC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAS;IAC/B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,cAAc,CAAS;IAG/B,OAAO,CAAC,WAAW,CAAqB;IACxC,OAAO,CAAC,YAAY,CAAa;IAEjC;;;OAGG;gBACS,WAAW,EAAE,MAAM,EAAE,EAAE,OAAO,GAAE,MAAa,EAAE,cAAc,GAAE,MAAoB;IAW/F;;;;;;OAMG;YACW,cAAc;IAoD5B;;;;;OAKG;YACW,gBAAgB;IA6C9B;;;;;OAKG;IACU,SAAS,CAAC,QAAQ,GAAE,MAAY,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAmCtE;;;;OAIG;IACI,eAAe,IAAI,WAAW,GAAG,IAAI;IAW5C;;OAEG;IACI,aAAa,IAAI,IAAI;CAG7B"}
@@ -7,8 +7,11 @@ exports.PeerRanker = void 0;
7
7
  const axios_1 = __importDefault(require("axios"));
8
8
  const fs_1 = __importDefault(require("fs"));
9
9
  const https_1 = __importDefault(require("https"));
10
+ const node_cache_1 = __importDefault(require("node-cache")); // Import node-cache
10
11
  const ssl_1 = require("./ssl");
11
12
  const promiseUtils_1 = require("./promiseUtils");
13
+ // Cache with TTL of 1 day (86400 seconds)
14
+ const peerCache = new node_cache_1.default({ stdTTL: 86400 });
12
15
  /**
13
16
  * Utility class to rank peers based on latency and upload bandwidth using HTTPS with mTLS.
14
17
  */
@@ -32,10 +35,16 @@ class PeerRanker {
32
35
  /**
33
36
  * Measures the latency of a given IP address using an HTTPS request.
34
37
  * Tries HEAD first, then falls back to GET if HEAD is not supported.
38
+ * If the latency is cached, returns the cached value.
35
39
  * @param ip - The IP address of the peer.
36
40
  * @returns Promise resolving to the latency in milliseconds or rejecting if the peer fails.
37
41
  */
38
42
  async measureLatency(ip) {
43
+ const cachedMetrics = peerCache.get(ip);
44
+ if (cachedMetrics && cachedMetrics.latency) {
45
+ console.log(`Latency for IP ${ip} retrieved from cache.`);
46
+ return cachedMetrics.latency;
47
+ }
39
48
  const url = `https://${ip}:4159/diagnostics/ping`;
40
49
  const configHead = {
41
50
  url: url,
@@ -69,6 +78,8 @@ class PeerRanker {
69
78
  await (0, axios_1.default)(configGet);
70
79
  }
71
80
  const latency = Date.now() - startTime;
81
+ // Cache the latency for the IP
82
+ peerCache.set(ip, { ...cachedMetrics, latency });
72
83
  return latency;
73
84
  }
74
85
  catch (error) {
@@ -78,10 +89,16 @@ class PeerRanker {
78
89
  }
79
90
  /**
80
91
  * Measures the upload bandwidth of a given IP address by sending random data.
92
+ * If the bandwidth is cached, returns the cached value.
81
93
  * @param ip - The IP address of the peer.
82
94
  * @returns Promise resolving to the upload bandwidth in bytes per second or rejecting if the peer fails.
83
95
  */
84
96
  async measureBandwidth(ip) {
97
+ const cachedMetrics = peerCache.get(ip);
98
+ if (cachedMetrics && cachedMetrics.bandwidth) {
99
+ console.log(`Bandwidth for IP ${ip} retrieved from cache.`);
100
+ return cachedMetrics.bandwidth;
101
+ }
85
102
  const url = `https://${ip}:4159/diagnostics/bandwidth`;
86
103
  const randomData = Buffer.alloc(this.uploadTestSize, 'a');
87
104
  const config = {
@@ -106,6 +123,8 @@ class PeerRanker {
106
123
  await (0, axios_1.default)(config);
107
124
  const timeElapsed = (Date.now() - startTime) / 1000;
108
125
  const bandwidth = this.uploadTestSize / timeElapsed;
126
+ // Cache the bandwidth for the IP
127
+ peerCache.set(ip, { ...cachedMetrics, bandwidth });
109
128
  return bandwidth;
110
129
  }
111
130
  catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dignetwork/dig-sdk",
3
- "version": "0.0.1-alpha.150",
3
+ "version": "0.0.1-alpha.151",
4
4
  "description": "",
5
5
  "type": "commonjs",
6
6
  "main": "./dist/index.js",