@dignetwork/dig-sdk 0.0.1-alpha.142 → 0.0.1-alpha.143
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.
|
@@ -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;WAIzB,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;
|
|
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;WAIzB,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;WA2EZ,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;IA8GH,mBAAmB,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;CAUvD"}
|
|
@@ -50,6 +50,7 @@ class DigNetwork {
|
|
|
50
50
|
static async findPeerWithStoreKey(storeId, rootHash, key, initialBlackList = []) {
|
|
51
51
|
const peerBlackList = initialBlackList;
|
|
52
52
|
const serverCoin = new blockchain_1.ServerCoin(storeId);
|
|
53
|
+
const allPeers = await serverCoin.getActiveEpochPeers();
|
|
53
54
|
while (true) {
|
|
54
55
|
try {
|
|
55
56
|
// Sample 10 peers from the current epoch
|
|
@@ -426,21 +426,3 @@ FullNodePeer.peerInfos = new Map();
|
|
|
426
426
|
FullNodePeer.peerIPCache = new node_cache_1.default({ stdTTL: CACHE_DURATION / 1000 });
|
|
427
427
|
// Map to store rate limiters per peer IP
|
|
428
428
|
FullNodePeer.peerLimiters = new Map();
|
|
429
|
-
/**
|
|
430
|
-
* Usage Example
|
|
431
|
-
*/
|
|
432
|
-
async function main() {
|
|
433
|
-
try {
|
|
434
|
-
// Connect to the best available peer
|
|
435
|
-
const fullNodePeer = await FullNodePeer.connect();
|
|
436
|
-
// Example parentCoinInfo buffer (replace with actual data)
|
|
437
|
-
const parentCoinInfo = Buffer.from("your_parent_coin_info_here", "hex");
|
|
438
|
-
// Wait for coin confirmation
|
|
439
|
-
const isConfirmed = await FullNodePeer.waitForConfirmation(parentCoinInfo);
|
|
440
|
-
console.log(`Coin confirmed: ${isConfirmed}`);
|
|
441
|
-
}
|
|
442
|
-
catch (error) {
|
|
443
|
-
console.error(`Error: ${error.message}`);
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
main();
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interface representing the metrics of a peer.
|
|
3
|
+
*/
|
|
4
|
+
export interface PeerMetrics {
|
|
5
|
+
ip: string;
|
|
6
|
+
latency: number;
|
|
7
|
+
bandwidth: number;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Configuration options for the PeerRanker.
|
|
11
|
+
*/
|
|
12
|
+
interface PeerRankerOptions {
|
|
13
|
+
clientCertPath: string;
|
|
14
|
+
clientKeyPath: string;
|
|
15
|
+
bandwidthTestPath: string;
|
|
16
|
+
pingPath?: string;
|
|
17
|
+
timeout?: number;
|
|
18
|
+
bandwidthTestSize?: number;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Utility class to rank peers based on latency and bandwidth using HTTPS with mTLS.
|
|
22
|
+
*/
|
|
23
|
+
export declare class PeerRanker {
|
|
24
|
+
private ipAddresses;
|
|
25
|
+
private static certPath;
|
|
26
|
+
private static keyPath;
|
|
27
|
+
private bandwidthTestPath;
|
|
28
|
+
private pingPath;
|
|
29
|
+
private timeout;
|
|
30
|
+
private bandwidthTestSize;
|
|
31
|
+
private sortedPeers;
|
|
32
|
+
private currentIndex;
|
|
33
|
+
/**
|
|
34
|
+
* Constructs a PeerRanker instance.
|
|
35
|
+
* @param ipAddresses - Array of IP addresses to rank.
|
|
36
|
+
* @param options - Configuration options including paths to client certificates.
|
|
37
|
+
*/
|
|
38
|
+
constructor(ipAddresses: string[], options: PeerRankerOptions);
|
|
39
|
+
/**
|
|
40
|
+
* Measures the latency of a given IP address using an HTTPS request.
|
|
41
|
+
* Tries HEAD first, then falls back to GET if HEAD is not supported.
|
|
42
|
+
* @param ip - The IP address of the peer.
|
|
43
|
+
* @returns Promise resolving to the latency in milliseconds.
|
|
44
|
+
*/
|
|
45
|
+
private measureLatency;
|
|
46
|
+
/**
|
|
47
|
+
* Measures the bandwidth of a given IP address by downloading a file and calculating throughput.
|
|
48
|
+
* @param ip - The IP address of the peer.
|
|
49
|
+
* @returns Promise resolving to the bandwidth in bytes per second.
|
|
50
|
+
*/
|
|
51
|
+
private measureBandwidth;
|
|
52
|
+
/**
|
|
53
|
+
* Ranks the peers based on measured latency and bandwidth.
|
|
54
|
+
* @returns Promise resolving to an array of PeerMetrics sorted by latency and bandwidth.
|
|
55
|
+
*/
|
|
56
|
+
rankPeers(): Promise<PeerMetrics[]>;
|
|
57
|
+
/**
|
|
58
|
+
* Returns the next best peer based on the ranking.
|
|
59
|
+
* Cycles through the list, resetting to the beginning once the end is reached.
|
|
60
|
+
* @returns The next PeerMetrics object or null if no peers are available.
|
|
61
|
+
*/
|
|
62
|
+
GetNextBestPeer(): PeerMetrics | null;
|
|
63
|
+
/**
|
|
64
|
+
* Resets the internal iterator to start from the beginning of the sorted list.
|
|
65
|
+
*/
|
|
66
|
+
resetIterator(): void;
|
|
67
|
+
}
|
|
68
|
+
export {};
|
|
69
|
+
//# sourceMappingURL=PeerRanker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PeerRanker.d.ts","sourceRoot":"","sources":["../../src/utils/PeerRanker.ts"],"names":[],"mappings":"AAOA;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,UAAU,iBAAiB;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;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,iBAAiB,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,iBAAiB,CAAS;IAGlC,OAAO,CAAC,WAAW,CAAqB;IACxC,OAAO,CAAC,YAAY,CAAa;IAEjC;;;;OAIG;gBACS,WAAW,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,iBAAiB;IAY7D;;;;;OAKG;YACW,cAAc;IA8C5B;;;;OAIG;YACW,gBAAgB;IA2C9B;;;OAGG;IACU,SAAS,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;IA4BhD;;;;OAIG;IACI,eAAe,IAAI,WAAW,GAAG,IAAI;IAW5C;;OAEG;IACI,aAAa,IAAI,IAAI;CAG7B"}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// src/PeerRanker.ts
|
|
3
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
+
};
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.PeerRanker = void 0;
|
|
8
|
+
const axios_1 = __importDefault(require("axios"));
|
|
9
|
+
const fs_1 = __importDefault(require("fs"));
|
|
10
|
+
const https_1 = __importDefault(require("https"));
|
|
11
|
+
const ssl_1 = require("./ssl");
|
|
12
|
+
/**
|
|
13
|
+
* Utility class to rank peers based on latency and bandwidth using HTTPS with mTLS.
|
|
14
|
+
*/
|
|
15
|
+
class PeerRanker {
|
|
16
|
+
/**
|
|
17
|
+
* Constructs a PeerRanker instance.
|
|
18
|
+
* @param ipAddresses - Array of IP addresses to rank.
|
|
19
|
+
* @param options - Configuration options including paths to client certificates.
|
|
20
|
+
*/
|
|
21
|
+
constructor(ipAddresses, options) {
|
|
22
|
+
// Internal properties for iteration
|
|
23
|
+
this.sortedPeers = [];
|
|
24
|
+
this.currentIndex = 0;
|
|
25
|
+
this.ipAddresses = ipAddresses;
|
|
26
|
+
this.bandwidthTestPath = options.bandwidthTestPath;
|
|
27
|
+
this.pingPath = options.pingPath || '/'; // Default to root path if not provided
|
|
28
|
+
this.timeout = options.timeout || 5000; // Default timeout: 5 seconds
|
|
29
|
+
this.bandwidthTestSize = options.bandwidthTestSize || 1024 * 1024; // Default: 1MB
|
|
30
|
+
const { certPath, keyPath } = (0, ssl_1.getOrCreateSSLCerts)();
|
|
31
|
+
PeerRanker.certPath = certPath;
|
|
32
|
+
PeerRanker.keyPath = keyPath;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Measures the latency of a given IP address using an HTTPS request.
|
|
36
|
+
* Tries HEAD first, then falls back to GET if HEAD is not supported.
|
|
37
|
+
* @param ip - The IP address of the peer.
|
|
38
|
+
* @returns Promise resolving to the latency in milliseconds.
|
|
39
|
+
*/
|
|
40
|
+
async measureLatency(ip) {
|
|
41
|
+
const path = this.pingPath;
|
|
42
|
+
const url = `https://${ip}${path}`;
|
|
43
|
+
// Configuration for HEAD request
|
|
44
|
+
const configHead = {
|
|
45
|
+
url: url,
|
|
46
|
+
method: 'HEAD',
|
|
47
|
+
httpsAgent: new https_1.default.Agent({
|
|
48
|
+
cert: fs_1.default.readFileSync(PeerRanker.certPath),
|
|
49
|
+
key: fs_1.default.readFileSync(PeerRanker.keyPath),
|
|
50
|
+
rejectUnauthorized: false, // Set to true in production
|
|
51
|
+
}),
|
|
52
|
+
timeout: this.timeout,
|
|
53
|
+
validateStatus: (status) => status < 500, // Resolve only if status is less than 500
|
|
54
|
+
};
|
|
55
|
+
const startTime = Date.now();
|
|
56
|
+
try {
|
|
57
|
+
const response = await (0, axios_1.default)(configHead);
|
|
58
|
+
if (response.status === 405) { // Method Not Allowed
|
|
59
|
+
// Fallback to GET with Range header to minimize data transfer
|
|
60
|
+
const configGet = {
|
|
61
|
+
url: url,
|
|
62
|
+
method: 'GET',
|
|
63
|
+
httpsAgent: new https_1.default.Agent({
|
|
64
|
+
cert: fs_1.default.readFileSync(PeerRanker.certPath),
|
|
65
|
+
key: fs_1.default.readFileSync(PeerRanker.keyPath),
|
|
66
|
+
rejectUnauthorized: false, // Set to true in production
|
|
67
|
+
}),
|
|
68
|
+
timeout: this.timeout,
|
|
69
|
+
headers: {
|
|
70
|
+
'Range': 'bytes=0-0', // Request only the first byte
|
|
71
|
+
},
|
|
72
|
+
validateStatus: (status) => status < 500,
|
|
73
|
+
};
|
|
74
|
+
await (0, axios_1.default)(configGet);
|
|
75
|
+
}
|
|
76
|
+
const latency = Date.now() - startTime;
|
|
77
|
+
return latency;
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
console.error(`Latency measurement failed for IP ${ip}:`, error.message);
|
|
81
|
+
return Infinity; // Indicate unreachable or unresponsive peer
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Measures the bandwidth of a given IP address by downloading a file and calculating throughput.
|
|
86
|
+
* @param ip - The IP address of the peer.
|
|
87
|
+
* @returns Promise resolving to the bandwidth in bytes per second.
|
|
88
|
+
*/
|
|
89
|
+
async measureBandwidth(ip) {
|
|
90
|
+
const url = `https://${ip}${this.bandwidthTestPath}`;
|
|
91
|
+
const config = {
|
|
92
|
+
url: url,
|
|
93
|
+
method: 'GET',
|
|
94
|
+
responseType: 'stream',
|
|
95
|
+
httpsAgent: new https_1.default.Agent({
|
|
96
|
+
cert: fs_1.default.readFileSync(PeerRanker.certPath),
|
|
97
|
+
key: fs_1.default.readFileSync(PeerRanker.keyPath),
|
|
98
|
+
rejectUnauthorized: false, // Set to true in production
|
|
99
|
+
}),
|
|
100
|
+
timeout: this.timeout,
|
|
101
|
+
};
|
|
102
|
+
return new Promise((resolve) => {
|
|
103
|
+
const startTime = Date.now();
|
|
104
|
+
let bytesReceived = 0;
|
|
105
|
+
(0, axios_1.default)(config)
|
|
106
|
+
.then((response) => {
|
|
107
|
+
response.data.on('data', (chunk) => {
|
|
108
|
+
bytesReceived += chunk.length;
|
|
109
|
+
});
|
|
110
|
+
response.data.on('end', () => {
|
|
111
|
+
const timeElapsed = (Date.now() - startTime) / 1000; // seconds
|
|
112
|
+
const bandwidth = bytesReceived / timeElapsed; // bytes per second
|
|
113
|
+
resolve(bandwidth);
|
|
114
|
+
});
|
|
115
|
+
response.data.on('error', (err) => {
|
|
116
|
+
console.error(`Bandwidth measurement error for IP ${ip}:`, err.message);
|
|
117
|
+
resolve(0); // Indicate failure in measuring bandwidth
|
|
118
|
+
});
|
|
119
|
+
})
|
|
120
|
+
.catch((error) => {
|
|
121
|
+
console.error(`Bandwidth measurement failed for IP ${ip}:`, error.message);
|
|
122
|
+
resolve(0); // Indicate failure in measuring bandwidth
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Ranks the peers based on measured latency and bandwidth.
|
|
128
|
+
* @returns Promise resolving to an array of PeerMetrics sorted by latency and bandwidth.
|
|
129
|
+
*/
|
|
130
|
+
async rankPeers() {
|
|
131
|
+
const metricsPromises = this.ipAddresses.map(async (ip) => {
|
|
132
|
+
const [latency, bandwidth] = await Promise.all([
|
|
133
|
+
this.measureLatency(ip),
|
|
134
|
+
this.measureBandwidth(ip),
|
|
135
|
+
]);
|
|
136
|
+
return { ip, latency, bandwidth };
|
|
137
|
+
});
|
|
138
|
+
const peerMetrics = await Promise.all(metricsPromises);
|
|
139
|
+
// Sort by lowest latency first, then by highest bandwidth
|
|
140
|
+
peerMetrics.sort((a, b) => {
|
|
141
|
+
if (a.latency === b.latency) {
|
|
142
|
+
return b.bandwidth - a.bandwidth; // Higher bandwidth is better
|
|
143
|
+
}
|
|
144
|
+
return a.latency - b.latency; // Lower latency is better
|
|
145
|
+
});
|
|
146
|
+
// Update the internal sorted list
|
|
147
|
+
this.sortedPeers = peerMetrics;
|
|
148
|
+
// Reset the iterator index
|
|
149
|
+
this.currentIndex = 0;
|
|
150
|
+
return peerMetrics;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Returns the next best peer based on the ranking.
|
|
154
|
+
* Cycles through the list, resetting to the beginning once the end is reached.
|
|
155
|
+
* @returns The next PeerMetrics object or null if no peers are available.
|
|
156
|
+
*/
|
|
157
|
+
GetNextBestPeer() {
|
|
158
|
+
if (this.sortedPeers.length === 0) {
|
|
159
|
+
console.warn('Peer list is empty. Please run rankPeers() first.');
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
const peer = this.sortedPeers[this.currentIndex];
|
|
163
|
+
this.currentIndex = (this.currentIndex + 1) % this.sortedPeers.length;
|
|
164
|
+
return peer;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Resets the internal iterator to start from the beginning of the sorted list.
|
|
168
|
+
*/
|
|
169
|
+
resetIterator() {
|
|
170
|
+
this.currentIndex = 0;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
exports.PeerRanker = PeerRanker;
|