Skip to content

Commit 8123784

Browse files
Merge pull request #144 from DIG-Network/release/v0.0.1-alpha.160
Release/v0.0.1 alpha.160
2 parents 5b2bc13 + 5616ae8 commit 8123784

File tree

5 files changed

+54
-62
lines changed

5 files changed

+54
-62
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22

33
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
44

5+
### [0.0.1-alpha.160](https://github.com/DIG-Network/dig-chia-sdk/compare/v0.0.1-alpha.159...v0.0.1-alpha.160) (2024-10-07)
6+
7+
8+
### Features
9+
10+
* fullnode peer improvements ([ba02ee2](https://github.com/DIG-Network/dig-chia-sdk/commit/ba02ee216d95e8295e4138035d823cf9f4cd5480))
11+
512
### [0.0.1-alpha.159](https://github.com/DIG-Network/dig-chia-sdk/compare/v0.0.1-alpha.158...v0.0.1-alpha.159) (2024-10-07)
613

714

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@dignetwork/dig-sdk",
3-
"version": "0.0.1-alpha.159",
3+
"version": "0.0.1-alpha.160",
44
"description": "",
55
"type": "commonjs",
66
"main": "./dist/index.js",

src/DigNetwork/PropagationServer.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,9 @@ export class PropagationServer {
105105

106106
try {
107107
const response = await axios.get(url, config);
108-
console.log(green(`✔ Successfully pinged peer: ${this.ipAddress}`));
109108

110109
return response.data;
111110
} catch (error: any) {
112-
console.error(red(`✖ Failed to ping peer: ${this.ipAddress}`));
113111
console.error(red(error.message));
114112
throw error;
115113
}
@@ -164,7 +162,7 @@ export class PropagationServer {
164162

165163
return response.data;
166164
} catch (error: any) {
167-
console.error(red(`✖ Failed to ping peer: ${this.ipAddress}`));
165+
console.error(red(`✖ Failed to ping peer: ${this.ipAddress}`), error.message);
168166
console.error(red(error.message));
169167
throw error;
170168
}

src/blockchain/FullNodePeer.ts

Lines changed: 43 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
// FullNodePeer.ts
2-
31
import path from "path";
42
import os from "os";
53
import fs from "fs";
@@ -12,7 +10,6 @@ import { Environment } from "../utils/Environment";
1210
import NodeCache from "node-cache";
1311
import Bottleneck from "bottleneck";
1412

15-
// Constants
1613
const FULLNODE_PORT = 8444;
1714
const LOCALHOST = "127.0.0.1";
1815
const CHIA_NODES_HOST = "chia-nodes";
@@ -24,9 +21,8 @@ const DNS_HOSTS = [
2421
];
2522
const CONNECTION_TIMEOUT = 2000; // in milliseconds
2623
const CACHE_DURATION = 30000; // in milliseconds
27-
const COOLDOWN_DURATION = 60000; // in milliseconds
24+
const COOLDOWN_DURATION = 600000; // 10 minutes in milliseconds
2825
const MAX_PEERS_TO_FETCH = 5; // Maximum number of peers to fetch from DNS
29-
const MAX_RETRIES = 3; // Maximum number of retry attempts
3026
const MAX_REQUESTS_PER_MINUTE = 100; // Per-peer rate limit
3127

3228
/**
@@ -45,12 +41,12 @@ export class FullNodePeer {
4541
// Singleton instance
4642
private static instance: FullNodePeer | null = null;
4743

48-
// Cached peer with timestamp
49-
private static cachedPeer: { peer: Peer; timestamp: number } | null = null;
50-
5144
// Cooldown cache to exclude faulty peers temporarily
5245
private static cooldownCache = new NodeCache({ stdTTL: COOLDOWN_DURATION / 1000 });
5346

47+
// Failed DNS hosts cooldown cache
48+
private static failedDNSCache = new NodeCache({ stdTTL: COOLDOWN_DURATION / 1000 });
49+
5450
// Peer reliability weights
5551
private static peerWeights: Map<string, number> = new Map();
5652

@@ -66,6 +62,9 @@ export class FullNodePeer {
6662
// Map to store rate limiters per peer IP
6763
private static peerLimiters: Map<string, Bottleneck> = new Map();
6864

65+
// Round-robin index
66+
private static roundRobinIndex: number = 0;
67+
6968
// Private constructor for singleton pattern
7069
private constructor(private peer: Peer) {}
7170

@@ -91,7 +90,7 @@ export class FullNodePeer {
9190
this.peer = bestPeer;
9291
FullNodePeer.instance = this; // Assign the initialized instance
9392
} catch (error: any) {
94-
console.error(`Initialization failed: ${error.message}`);
93+
console.error(`Fullnode Initialization failed: ${error.message}`);
9594
throw error;
9695
}
9796
}
@@ -103,6 +102,8 @@ export class FullNodePeer {
103102
*/
104103
public static async connect(): Promise<Peer> {
105104
const instance = FullNodePeer.getInstance();
105+
// Remove cached peer to ensure a new connection each time
106+
FullNodePeer.cachedPeer = null;
106107
await instance.initialize();
107108
return instance.peer;
108109
}
@@ -216,6 +217,12 @@ export class FullNodePeer {
216217
// Fetch peers from DNS introducers
217218
const fetchedPeers: string[] = [];
218219
for (const DNS_HOST of DNS_HOSTS) {
220+
// Check if DNS_HOST is in failedDNSCache
221+
if (FullNodePeer.failedDNSCache.has(DNS_HOST)) {
222+
console.warn(`Skipping DNS host ${DNS_HOST} due to recent failure.`);
223+
continue;
224+
}
225+
219226
try {
220227
const ips = await resolve4(DNS_HOST);
221228
if (ips && ips.length > 0) {
@@ -238,6 +245,8 @@ export class FullNodePeer {
238245
}
239246
} catch (error: any) {
240247
console.error(`Failed to resolve IPs from ${DNS_HOST}: ${error.message}`);
248+
// Add DNS_HOST to failedDNSCache for cooldown
249+
FullNodePeer.failedDNSCache.set(DNS_HOST, true);
241250
}
242251
}
243252

@@ -286,32 +295,22 @@ export class FullNodePeer {
286295
}
287296

288297
/**
289-
* Selects a peer based on weighted random selection.
290-
* Prioritized peers have higher weights.
298+
* Selects the next peer based on round-robin selection.
291299
* @returns {string} The selected peer IP.
292300
*/
293-
private static selectPeerByWeight(): string {
294-
const peers = Array.from(FullNodePeer.peerWeights.entries())
295-
.filter(([ip, _]) => !FullNodePeer.cooldownCache.has(ip))
296-
.map(([ip, weight]) => ({ ip, weight }));
297-
298-
const totalWeight = peers.reduce((sum, peer) => sum + peer.weight, 0);
299-
if (totalWeight === 0) {
300-
throw new Error("All peers are in cooldown.");
301-
}
301+
private static selectPeerRoundRobin(): string {
302+
const peers = Array.from(FullNodePeer.peerWeights.keys()).filter(
303+
(ip) => !FullNodePeer.cooldownCache.has(ip)
304+
);
302305

303-
const random = Math.random() * totalWeight;
304-
let cumulative = 0;
305-
306-
for (const peer of peers) {
307-
cumulative += peer.weight;
308-
if (random < cumulative) {
309-
return peer.ip;
310-
}
306+
if (peers.length === 0) {
307+
throw new Error("All fullnode peers are in cooldown.");
311308
}
312309

313-
// Fallback
314-
return peers[peers.length - 1].ip;
310+
// Round-robin selection
311+
const selectedPeer = peers[FullNodePeer.roundRobinIndex % peers.length];
312+
FullNodePeer.roundRobinIndex += 1;
313+
return selectedPeer;
315314
}
316315

317316
/**
@@ -332,32 +331,26 @@ export class FullNodePeer {
332331
}
333332

334333
/**
335-
* Connects to the best available peer based on weighted selection and reliability.
334+
* Connects to the best available peer based on round-robin selection and reliability.
336335
* @returns {Promise<Peer>} The connected Peer instance.
337336
*/
338337
private async getBestPeer(): Promise<Peer> {
339338
const now = Date.now();
340339

341-
// Refresh cachedPeer if expired
342-
if (
343-
FullNodePeer.cachedPeer &&
344-
now - FullNodePeer.cachedPeer.timestamp < CACHE_DURATION
345-
) {
346-
return FullNodePeer.cachedPeer.peer;
347-
}
340+
// Removed cachedPeer logic to ensure a new connection each time
348341

349342
// Fetch peer IPs
350343
const peerIPs = await FullNodePeer.getPeerIPs();
351344

352345
// Setup peer weights with prioritization
353346
FullNodePeer.setupPeers(peerIPs);
354347

355-
// Weighted random selection
348+
// Round-robin selection
356349
let selectedPeerIP: string;
357350
try {
358-
selectedPeerIP = FullNodePeer.selectPeerByWeight();
351+
selectedPeerIP = FullNodePeer.selectPeerRoundRobin();
359352
} catch (error: any) {
360-
throw new Error(`Failed to select a peer: ${error.message}`);
353+
throw new Error(`Failed to select a fullnode peer: ${error.message}`);
361354
}
362355

363356
// Attempt to create a peer connection
@@ -376,7 +369,7 @@ export class FullNodePeer {
376369
peer = await Peer.new(`${selectedPeerIP}:${FULLNODE_PORT}`, false, tls);
377370
} catch (error: any) {
378371
console.error(
379-
`Failed to create peer for IP ${selectedPeerIP}: ${error.message}`
372+
`Failed to create fullnode peer for IP ${selectedPeerIP}: ${error.message}`
380373
);
381374
// Add to cooldown
382375
FullNodePeer.cooldownCache.set(selectedPeerIP, true);
@@ -387,7 +380,7 @@ export class FullNodePeer {
387380
} else {
388381
FullNodePeer.peerWeights.delete(selectedPeerIP);
389382
}
390-
throw new Error(`Unable to connect to peer ${selectedPeerIP}`);
383+
throw new Error(`Unable to connect to fullnode peer ${selectedPeerIP}`);
391384
}
392385

393386
// Create a Bottleneck limiter for this peer
@@ -407,9 +400,6 @@ export class FullNodePeer {
407400
FullNodePeer.peerLimiters.set(selectedPeerIP, limiter);
408401
const proxiedPeer = this.createPeerProxy(peer, selectedPeerIP);
409402

410-
// Cache the peer
411-
FullNodePeer.cachedPeer = { peer: peer, timestamp: now };
412-
413403
console.log(`Using Fullnode Peer: ${selectedPeerIP}`);
414404

415405
return proxiedPeer;
@@ -427,9 +417,8 @@ export class FullNodePeer {
427417
// Start the timeout to forget the peer after 1 minute
428418
const timeoutPromise = new Promise<null>((_, reject) => {
429419
timeoutId = setTimeout(() => {
430-
FullNodePeer.cachedPeer = null;
431420
reject(
432-
new Error("Operation timed out. Reconnecting to a new peer.")
421+
new Error("Operation timed out. Reconnecting to a new fullnode peer.")
433422
);
434423
}, 60000); // 1 minute
435424
});
@@ -453,9 +442,7 @@ export class FullNodePeer {
453442
error.message.includes("WebSocket") ||
454443
error.message.includes("Operation timed out")
455444
) {
456-
FullNodePeer.cachedPeer = null;
457-
458-
this.handlePeerDisconnection(peerIP);
445+
FullNodePeer.handlePeerDisconnection(peerIP);
459446
const newPeer = await this.getBestPeer();
460447
return (newPeer as any)[prop](...args);
461448
}
@@ -472,7 +459,7 @@ export class FullNodePeer {
472459
* Handles peer disconnection by marking it in cooldown and updating internal states.
473460
* @param {string} peerIP - The IP address of the disconnected peer.
474461
*/
475-
public handlePeerDisconnection(peerIP: string): void {
462+
public static handlePeerDisconnection(peerIP: string): void {
476463
// Add the faulty peer to the cooldown cache
477464
FullNodePeer.cooldownCache.set(peerIP, true);
478465

@@ -490,7 +477,7 @@ export class FullNodePeer {
490477
// Remove the limiter
491478
FullNodePeer.peerLimiters.delete(peerIP);
492479

493-
console.warn(`Peer ${peerIP} has been marked as disconnected and is in cooldown.`);
480+
console.warn(`Fullnode Peer ${peerIP} has been marked as disconnected and is in cooldown.`);
494481
}
495482

496483
/**
@@ -521,21 +508,21 @@ export class FullNodePeer {
521508
try {
522509
peer = await FullNodePeer.connect();
523510
} catch (error: any) {
524-
spinner.error({ text: "Failed to connect to a peer." });
511+
spinner.error({ text: "Failed to connect to a fullnode peer." });
525512
console.error(`waitForConfirmation connection error: ${error.message}`);
526513
throw error;
527514
}
528515

529516
// Extract peer IP to access the corresponding limiter
530517
const peerIP = FullNodePeer.extractPeerIP(peer);
531518
if (!peerIP) {
532-
spinner.error({ text: "Failed to extract peer IP." });
519+
spinner.error({ text: "Failed to extract fullnode peer IP." });
533520
throw new Error("Failed to extract peer IP.");
534521
}
535522

536523
const limiter = FullNodePeer.peerLimiters.get(peerIP);
537524
if (!limiter) {
538-
spinner.error({ text: "No rate limiter found for the peer." });
525+
spinner.error({ text: "No rate limiter found for the fullnode peer." });
539526
throw new Error("No rate limiter found for the peer.");
540527
}
541528

0 commit comments

Comments
 (0)