@leofcoin/chain 1.7.73 → 1.7.75
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.
- package/exports/browser/chain.js +170 -5
- package/exports/browser/{client-DD7vhDK_-UAymLS2i.js → client-DD7vhDK_-BdNAdRzV.js} +1 -1
- package/exports/browser/{messages-CW17jRdc-c9cSXiiQ.js → messages-CW17jRdc-Dtrj-vba.js} +1 -1
- package/exports/browser/{node-browser-BvxzAdLe.js → node-browser-DMmrhyQS.js} +3 -3
- package/exports/browser/node-browser.js +1 -1
- package/exports/chain.js +170 -5
- package/exports/connection-monitor.d.ts +13 -0
- package/exports/sync-controller.d.ts +3 -2
- package/package.json +1 -1
package/exports/browser/chain.js
CHANGED
|
@@ -5201,6 +5201,12 @@ class State extends Contract {
|
|
|
5201
5201
|
get shouldSync() {
|
|
5202
5202
|
if (this.#chainSyncing)
|
|
5203
5203
|
return false;
|
|
5204
|
+
// Check if we have any connected peers with the same version
|
|
5205
|
+
const compatiblePeers = Object.values(globalThis.peernet.connections || {}).filter((peer) => peer.connected && peer.version === this.version);
|
|
5206
|
+
if (compatiblePeers.length === 0) {
|
|
5207
|
+
debug$1('No compatible peers available for sync');
|
|
5208
|
+
return false;
|
|
5209
|
+
}
|
|
5204
5210
|
if (!this.#chainSyncing ||
|
|
5205
5211
|
this.#resolveErrored ||
|
|
5206
5212
|
this.#syncState === 'errored' ||
|
|
@@ -5209,6 +5215,25 @@ class State extends Contract {
|
|
|
5209
5215
|
return true;
|
|
5210
5216
|
return false;
|
|
5211
5217
|
}
|
|
5218
|
+
async #waitForPeers(timeoutMs = 30000) {
|
|
5219
|
+
return new Promise((resolve) => {
|
|
5220
|
+
const checkPeers = () => {
|
|
5221
|
+
const peers = Object.values(globalThis.peernet.connections || {}).filter((peer) => peer.connected && peer.version === this.version);
|
|
5222
|
+
if (peers.length > 0) {
|
|
5223
|
+
resolve(true);
|
|
5224
|
+
}
|
|
5225
|
+
};
|
|
5226
|
+
// Check immediately
|
|
5227
|
+
checkPeers();
|
|
5228
|
+
// Set up interval to check periodically
|
|
5229
|
+
const interval = setInterval(checkPeers, 1000);
|
|
5230
|
+
// Set timeout
|
|
5231
|
+
setTimeout(() => {
|
|
5232
|
+
clearInterval(interval);
|
|
5233
|
+
resolve(false);
|
|
5234
|
+
}, timeoutMs);
|
|
5235
|
+
});
|
|
5236
|
+
}
|
|
5212
5237
|
async triggerSync() {
|
|
5213
5238
|
const latest = await this.#getLatestBlock();
|
|
5214
5239
|
return this.syncChain(latest);
|
|
@@ -5268,6 +5293,114 @@ class VersionControl extends State {
|
|
|
5268
5293
|
}
|
|
5269
5294
|
}
|
|
5270
5295
|
|
|
5296
|
+
/**
|
|
5297
|
+
* Connection Monitor - Monitors peer connections and handles reconnection logic
|
|
5298
|
+
*/
|
|
5299
|
+
class ConnectionMonitor {
|
|
5300
|
+
#isMonitoring = false;
|
|
5301
|
+
#checkInterval = null;
|
|
5302
|
+
#reconnectAttempts = 0;
|
|
5303
|
+
#maxReconnectAttempts = 10;
|
|
5304
|
+
#reconnectDelay = 5000;
|
|
5305
|
+
#healthCheckInterval = 10000;
|
|
5306
|
+
#version;
|
|
5307
|
+
get isMonitoring() {
|
|
5308
|
+
return this.#isMonitoring;
|
|
5309
|
+
}
|
|
5310
|
+
get connectedPeers() {
|
|
5311
|
+
return Object.values(globalThis.peernet?.connections || {}).filter((peer) => peer.connected);
|
|
5312
|
+
}
|
|
5313
|
+
get compatiblePeers() {
|
|
5314
|
+
return this.connectedPeers.filter((peer) => peer.version === this.#version);
|
|
5315
|
+
}
|
|
5316
|
+
constructor(version) {
|
|
5317
|
+
this.#version = version;
|
|
5318
|
+
console.log(`🔗 Connection Monitor initialized for version: ${this.#version}`);
|
|
5319
|
+
}
|
|
5320
|
+
start() {
|
|
5321
|
+
if (this.#isMonitoring)
|
|
5322
|
+
return;
|
|
5323
|
+
this.#isMonitoring = true;
|
|
5324
|
+
console.log('🔄 Starting connection monitor...');
|
|
5325
|
+
this.#checkInterval = setInterval(() => {
|
|
5326
|
+
this.#healthCheck();
|
|
5327
|
+
}, this.#healthCheckInterval);
|
|
5328
|
+
// Initial health check
|
|
5329
|
+
this.#healthCheck();
|
|
5330
|
+
}
|
|
5331
|
+
stop() {
|
|
5332
|
+
if (!this.#isMonitoring)
|
|
5333
|
+
return;
|
|
5334
|
+
this.#isMonitoring = false;
|
|
5335
|
+
if (this.#checkInterval) {
|
|
5336
|
+
clearInterval(this.#checkInterval);
|
|
5337
|
+
this.#checkInterval = null;
|
|
5338
|
+
}
|
|
5339
|
+
console.log('⏹️ Connection monitor stopped');
|
|
5340
|
+
}
|
|
5341
|
+
async #healthCheck() {
|
|
5342
|
+
const connectedPeers = this.connectedPeers;
|
|
5343
|
+
const compatiblePeers = this.compatiblePeers;
|
|
5344
|
+
console.log(`🔍 Health check: ${connectedPeers.length} connected, ${compatiblePeers.length} compatible`);
|
|
5345
|
+
if (connectedPeers.length === 0) {
|
|
5346
|
+
console.warn('⚠️ No peer connections detected');
|
|
5347
|
+
await this.#attemptReconnection();
|
|
5348
|
+
}
|
|
5349
|
+
else if (compatiblePeers.length === 0) {
|
|
5350
|
+
console.warn('⚠️ No compatible peers found');
|
|
5351
|
+
// Could attempt to find compatible peers or trigger version negotiation
|
|
5352
|
+
}
|
|
5353
|
+
else {
|
|
5354
|
+
// Reset reconnect attempts on successful connection
|
|
5355
|
+
this.#reconnectAttempts = 0;
|
|
5356
|
+
}
|
|
5357
|
+
// Publish connection status
|
|
5358
|
+
globalThis.pubsub?.publish('connection-status', {
|
|
5359
|
+
connected: connectedPeers.length,
|
|
5360
|
+
compatible: compatiblePeers.length,
|
|
5361
|
+
healthy: compatiblePeers.length > 0
|
|
5362
|
+
});
|
|
5363
|
+
}
|
|
5364
|
+
async #attemptReconnection() {
|
|
5365
|
+
if (this.#reconnectAttempts >= this.#maxReconnectAttempts) {
|
|
5366
|
+
console.error('❌ Max reconnection attempts reached');
|
|
5367
|
+
return;
|
|
5368
|
+
}
|
|
5369
|
+
this.#reconnectAttempts++;
|
|
5370
|
+
console.log(`🔄 Attempting reconnection ${this.#reconnectAttempts}/${this.#maxReconnectAttempts}`);
|
|
5371
|
+
try {
|
|
5372
|
+
// Try to restart the network
|
|
5373
|
+
if (globalThis.peernet?.start) {
|
|
5374
|
+
await globalThis.peernet.start();
|
|
5375
|
+
}
|
|
5376
|
+
// Wait a bit before next check
|
|
5377
|
+
await new Promise((resolve) => setTimeout(resolve, this.#reconnectDelay));
|
|
5378
|
+
}
|
|
5379
|
+
catch (error) {
|
|
5380
|
+
console.error('❌ Reconnection failed:', error.message);
|
|
5381
|
+
// Exponential backoff
|
|
5382
|
+
this.#reconnectDelay = Math.min(this.#reconnectDelay * 1.5, 30000);
|
|
5383
|
+
}
|
|
5384
|
+
}
|
|
5385
|
+
async waitForPeers(timeoutMs = 30000) {
|
|
5386
|
+
return new Promise((resolve) => {
|
|
5387
|
+
const startTime = Date.now();
|
|
5388
|
+
const checkPeers = () => {
|
|
5389
|
+
if (this.compatiblePeers.length > 0) {
|
|
5390
|
+
resolve(true);
|
|
5391
|
+
return;
|
|
5392
|
+
}
|
|
5393
|
+
if (Date.now() - startTime >= timeoutMs) {
|
|
5394
|
+
resolve(false);
|
|
5395
|
+
return;
|
|
5396
|
+
}
|
|
5397
|
+
setTimeout(checkPeers, 1000);
|
|
5398
|
+
};
|
|
5399
|
+
checkPeers();
|
|
5400
|
+
});
|
|
5401
|
+
}
|
|
5402
|
+
}
|
|
5403
|
+
|
|
5271
5404
|
const debug = globalThis.createDebugger('leofcoin/chain');
|
|
5272
5405
|
// check if browser or local
|
|
5273
5406
|
class Chain extends VersionControl {
|
|
@@ -5280,6 +5413,10 @@ class Chain extends VersionControl {
|
|
|
5280
5413
|
#participants;
|
|
5281
5414
|
#participating;
|
|
5282
5415
|
#jail;
|
|
5416
|
+
#peerConnectionRetries;
|
|
5417
|
+
#maxPeerRetries;
|
|
5418
|
+
#peerRetryDelay;
|
|
5419
|
+
#connectionMonitor;
|
|
5283
5420
|
constructor(config) {
|
|
5284
5421
|
super(config);
|
|
5285
5422
|
this.#slotTime = 10000;
|
|
@@ -5291,6 +5428,9 @@ class Chain extends VersionControl {
|
|
|
5291
5428
|
this.#participants = [];
|
|
5292
5429
|
this.#participating = false;
|
|
5293
5430
|
this.#jail = [];
|
|
5431
|
+
this.#peerConnectionRetries = new Map();
|
|
5432
|
+
this.#maxPeerRetries = 5;
|
|
5433
|
+
this.#peerRetryDelay = 5000;
|
|
5294
5434
|
this.#addTransaction = async (message) => {
|
|
5295
5435
|
const transaction = new TransactionMessage(message);
|
|
5296
5436
|
const hash = await transaction.hash();
|
|
@@ -5365,6 +5505,7 @@ class Chain extends VersionControl {
|
|
|
5365
5505
|
// this.node = await new Node()
|
|
5366
5506
|
this.#participants = [];
|
|
5367
5507
|
this.#participating = false;
|
|
5508
|
+
this.#connectionMonitor = new ConnectionMonitor(this.version);
|
|
5368
5509
|
const initialized = await globalThis.contractStore.has(addresses.contractFactory);
|
|
5369
5510
|
if (!initialized)
|
|
5370
5511
|
await this.#setup();
|
|
@@ -5372,8 +5513,11 @@ class Chain extends VersionControl {
|
|
|
5372
5513
|
// this.#state = new State()
|
|
5373
5514
|
// todo some functions rely on state
|
|
5374
5515
|
await super.init();
|
|
5516
|
+
// Start connection monitoring
|
|
5517
|
+
this.#connectionMonitor.start();
|
|
5375
5518
|
await globalThis.peernet.addRequestHandler('bw-request-message', () => {
|
|
5376
|
-
|
|
5519
|
+
const bw = globalThis.peernet.client?.bw || { up: 0, down: 0 };
|
|
5520
|
+
return new BWMessage(bw);
|
|
5377
5521
|
});
|
|
5378
5522
|
// await globalThis.peernet.addRequestHandler('peerId', () => {
|
|
5379
5523
|
// let node =
|
|
@@ -5454,7 +5598,7 @@ class Chain extends VersionControl {
|
|
|
5454
5598
|
}
|
|
5455
5599
|
}
|
|
5456
5600
|
if (this.wantList.length > 0) {
|
|
5457
|
-
const promises = await Promise.allSettled(this.wantList.map((hash) => peernet.get(hash)));
|
|
5601
|
+
const promises = await Promise.allSettled(this.wantList.map((hash) => peernet.get(hash, 'block')));
|
|
5458
5602
|
for (let i = 0; i < promises.length; i++) {
|
|
5459
5603
|
const result = promises[i];
|
|
5460
5604
|
if (result.status === 'fulfilled')
|
|
@@ -5781,7 +5925,7 @@ class Chain extends VersionControl {
|
|
|
5781
5925
|
* @returns
|
|
5782
5926
|
*/
|
|
5783
5927
|
internalCall(sender, contract, method, parameters) {
|
|
5784
|
-
globalThis.msg = this.#createMessage(sender, contract)
|
|
5928
|
+
// globalThis.msg = this.#createMessage(sender, contract) // Debug line removed
|
|
5785
5929
|
return this.machine.execute(contract, method, parameters);
|
|
5786
5930
|
}
|
|
5787
5931
|
/**
|
|
@@ -5792,11 +5936,11 @@ class Chain extends VersionControl {
|
|
|
5792
5936
|
* @returns
|
|
5793
5937
|
*/
|
|
5794
5938
|
call(contract, method, parameters) {
|
|
5795
|
-
globalThis.msg = this.#createMessage(peernet.selectedAccount, contract)
|
|
5939
|
+
// globalThis.msg = this.#createMessage(peernet.selectedAccount, contract) // Debug line removed
|
|
5796
5940
|
return this.machine.execute(contract, method, parameters);
|
|
5797
5941
|
}
|
|
5798
5942
|
staticCall(contract, method, parameters) {
|
|
5799
|
-
globalThis.msg = this.#createMessage(peernet.selectedAccount, contract)
|
|
5943
|
+
// globalThis.msg = this.#createMessage(peernet.selectedAccount, contract) // Debug line removed
|
|
5800
5944
|
return this.machine.get(contract, method, parameters);
|
|
5801
5945
|
}
|
|
5802
5946
|
mint(to, amount) {
|
|
@@ -5826,6 +5970,27 @@ class Chain extends VersionControl {
|
|
|
5826
5970
|
lookup(name) {
|
|
5827
5971
|
return this.call(addresses.nameService, 'lookup', [name]);
|
|
5828
5972
|
}
|
|
5973
|
+
#monitorPeerConnections() {
|
|
5974
|
+
setInterval(() => {
|
|
5975
|
+
const connectedPeers = Object.values(globalThis.peernet.connections).filter((peer) => peer.connected);
|
|
5976
|
+
debug(`Connected peers: ${connectedPeers.length}`);
|
|
5977
|
+
if (connectedPeers.length === 0) {
|
|
5978
|
+
debug('No peers connected, attempting to reconnect...');
|
|
5979
|
+
this.#attemptPeerReconnection();
|
|
5980
|
+
}
|
|
5981
|
+
}, 10000); // Check every 10 seconds
|
|
5982
|
+
}
|
|
5983
|
+
async #attemptPeerReconnection() {
|
|
5984
|
+
try {
|
|
5985
|
+
// Try to reconnect to star servers
|
|
5986
|
+
if (globalThis.peernet && globalThis.peernet.start) {
|
|
5987
|
+
await globalThis.peernet.start();
|
|
5988
|
+
}
|
|
5989
|
+
}
|
|
5990
|
+
catch (error) {
|
|
5991
|
+
console.warn('Failed to reconnect to peers:', error.message);
|
|
5992
|
+
}
|
|
5993
|
+
}
|
|
5829
5994
|
}
|
|
5830
5995
|
|
|
5831
5996
|
export { Chain as default };
|
|
@@ -8495,7 +8495,7 @@ class Peernet {
|
|
|
8495
8495
|
this.root = options.root;
|
|
8496
8496
|
const { RequestMessage, ResponseMessage, PeerMessage, PeerMessageResponse, PeernetMessage, DHTMessage, DHTMessageResponse, DataMessage, DataMessageResponse, PsMessage, ChatMessage, PeernetFile
|
|
8497
8497
|
// FolderMessageResponse
|
|
8498
|
-
} = await import(/* webpackChunkName: "messages" */ './messages-CW17jRdc-
|
|
8498
|
+
} = await import(/* webpackChunkName: "messages" */ './messages-CW17jRdc-Dtrj-vba.js');
|
|
8499
8499
|
/**
|
|
8500
8500
|
* proto Object containing protos
|
|
8501
8501
|
* @type {Object}
|
|
@@ -8589,7 +8589,7 @@ class Peernet {
|
|
|
8589
8589
|
if (this.#starting || this.#started)
|
|
8590
8590
|
return;
|
|
8591
8591
|
this.#starting = true;
|
|
8592
|
-
const importee = await import('./client-DD7vhDK_-
|
|
8592
|
+
const importee = await import('./client-DD7vhDK_-BdNAdRzV.js');
|
|
8593
8593
|
/**
|
|
8594
8594
|
* @access public
|
|
8595
8595
|
* @type {PeernetClient}
|
|
@@ -9078,7 +9078,7 @@ globalThis.Peernet = Peernet;
|
|
|
9078
9078
|
var networks = {
|
|
9079
9079
|
leofcoin: {
|
|
9080
9080
|
peach: {
|
|
9081
|
-
stars: ['wss://star.leofcoin.org'] //
|
|
9081
|
+
stars: ['wss://star-testnet.leofcoin.org', 'wss://star.leofcoin.org'] // Separate testnet stars
|
|
9082
9082
|
}
|
|
9083
9083
|
}
|
|
9084
9084
|
};
|
package/exports/chain.js
CHANGED
|
@@ -1347,6 +1347,12 @@ class State extends Contract {
|
|
|
1347
1347
|
get shouldSync() {
|
|
1348
1348
|
if (this.#chainSyncing)
|
|
1349
1349
|
return false;
|
|
1350
|
+
// Check if we have any connected peers with the same version
|
|
1351
|
+
const compatiblePeers = Object.values(globalThis.peernet.connections || {}).filter((peer) => peer.connected && peer.version === this.version);
|
|
1352
|
+
if (compatiblePeers.length === 0) {
|
|
1353
|
+
debug$1('No compatible peers available for sync');
|
|
1354
|
+
return false;
|
|
1355
|
+
}
|
|
1350
1356
|
if (!this.#chainSyncing ||
|
|
1351
1357
|
this.#resolveErrored ||
|
|
1352
1358
|
this.#syncState === 'errored' ||
|
|
@@ -1355,6 +1361,25 @@ class State extends Contract {
|
|
|
1355
1361
|
return true;
|
|
1356
1362
|
return false;
|
|
1357
1363
|
}
|
|
1364
|
+
async #waitForPeers(timeoutMs = 30000) {
|
|
1365
|
+
return new Promise((resolve) => {
|
|
1366
|
+
const checkPeers = () => {
|
|
1367
|
+
const peers = Object.values(globalThis.peernet.connections || {}).filter((peer) => peer.connected && peer.version === this.version);
|
|
1368
|
+
if (peers.length > 0) {
|
|
1369
|
+
resolve(true);
|
|
1370
|
+
}
|
|
1371
|
+
};
|
|
1372
|
+
// Check immediately
|
|
1373
|
+
checkPeers();
|
|
1374
|
+
// Set up interval to check periodically
|
|
1375
|
+
const interval = setInterval(checkPeers, 1000);
|
|
1376
|
+
// Set timeout
|
|
1377
|
+
setTimeout(() => {
|
|
1378
|
+
clearInterval(interval);
|
|
1379
|
+
resolve(false);
|
|
1380
|
+
}, timeoutMs);
|
|
1381
|
+
});
|
|
1382
|
+
}
|
|
1358
1383
|
async triggerSync() {
|
|
1359
1384
|
const latest = await this.#getLatestBlock();
|
|
1360
1385
|
return this.syncChain(latest);
|
|
@@ -1414,6 +1439,114 @@ class VersionControl extends State {
|
|
|
1414
1439
|
}
|
|
1415
1440
|
}
|
|
1416
1441
|
|
|
1442
|
+
/**
|
|
1443
|
+
* Connection Monitor - Monitors peer connections and handles reconnection logic
|
|
1444
|
+
*/
|
|
1445
|
+
class ConnectionMonitor {
|
|
1446
|
+
#isMonitoring = false;
|
|
1447
|
+
#checkInterval = null;
|
|
1448
|
+
#reconnectAttempts = 0;
|
|
1449
|
+
#maxReconnectAttempts = 10;
|
|
1450
|
+
#reconnectDelay = 5000;
|
|
1451
|
+
#healthCheckInterval = 10000;
|
|
1452
|
+
#version;
|
|
1453
|
+
get isMonitoring() {
|
|
1454
|
+
return this.#isMonitoring;
|
|
1455
|
+
}
|
|
1456
|
+
get connectedPeers() {
|
|
1457
|
+
return Object.values(globalThis.peernet?.connections || {}).filter((peer) => peer.connected);
|
|
1458
|
+
}
|
|
1459
|
+
get compatiblePeers() {
|
|
1460
|
+
return this.connectedPeers.filter((peer) => peer.version === this.#version);
|
|
1461
|
+
}
|
|
1462
|
+
constructor(version) {
|
|
1463
|
+
this.#version = version;
|
|
1464
|
+
console.log(`🔗 Connection Monitor initialized for version: ${this.#version}`);
|
|
1465
|
+
}
|
|
1466
|
+
start() {
|
|
1467
|
+
if (this.#isMonitoring)
|
|
1468
|
+
return;
|
|
1469
|
+
this.#isMonitoring = true;
|
|
1470
|
+
console.log('🔄 Starting connection monitor...');
|
|
1471
|
+
this.#checkInterval = setInterval(() => {
|
|
1472
|
+
this.#healthCheck();
|
|
1473
|
+
}, this.#healthCheckInterval);
|
|
1474
|
+
// Initial health check
|
|
1475
|
+
this.#healthCheck();
|
|
1476
|
+
}
|
|
1477
|
+
stop() {
|
|
1478
|
+
if (!this.#isMonitoring)
|
|
1479
|
+
return;
|
|
1480
|
+
this.#isMonitoring = false;
|
|
1481
|
+
if (this.#checkInterval) {
|
|
1482
|
+
clearInterval(this.#checkInterval);
|
|
1483
|
+
this.#checkInterval = null;
|
|
1484
|
+
}
|
|
1485
|
+
console.log('⏹️ Connection monitor stopped');
|
|
1486
|
+
}
|
|
1487
|
+
async #healthCheck() {
|
|
1488
|
+
const connectedPeers = this.connectedPeers;
|
|
1489
|
+
const compatiblePeers = this.compatiblePeers;
|
|
1490
|
+
console.log(`🔍 Health check: ${connectedPeers.length} connected, ${compatiblePeers.length} compatible`);
|
|
1491
|
+
if (connectedPeers.length === 0) {
|
|
1492
|
+
console.warn('⚠️ No peer connections detected');
|
|
1493
|
+
await this.#attemptReconnection();
|
|
1494
|
+
}
|
|
1495
|
+
else if (compatiblePeers.length === 0) {
|
|
1496
|
+
console.warn('⚠️ No compatible peers found');
|
|
1497
|
+
// Could attempt to find compatible peers or trigger version negotiation
|
|
1498
|
+
}
|
|
1499
|
+
else {
|
|
1500
|
+
// Reset reconnect attempts on successful connection
|
|
1501
|
+
this.#reconnectAttempts = 0;
|
|
1502
|
+
}
|
|
1503
|
+
// Publish connection status
|
|
1504
|
+
globalThis.pubsub?.publish('connection-status', {
|
|
1505
|
+
connected: connectedPeers.length,
|
|
1506
|
+
compatible: compatiblePeers.length,
|
|
1507
|
+
healthy: compatiblePeers.length > 0
|
|
1508
|
+
});
|
|
1509
|
+
}
|
|
1510
|
+
async #attemptReconnection() {
|
|
1511
|
+
if (this.#reconnectAttempts >= this.#maxReconnectAttempts) {
|
|
1512
|
+
console.error('❌ Max reconnection attempts reached');
|
|
1513
|
+
return;
|
|
1514
|
+
}
|
|
1515
|
+
this.#reconnectAttempts++;
|
|
1516
|
+
console.log(`🔄 Attempting reconnection ${this.#reconnectAttempts}/${this.#maxReconnectAttempts}`);
|
|
1517
|
+
try {
|
|
1518
|
+
// Try to restart the network
|
|
1519
|
+
if (globalThis.peernet?.start) {
|
|
1520
|
+
await globalThis.peernet.start();
|
|
1521
|
+
}
|
|
1522
|
+
// Wait a bit before next check
|
|
1523
|
+
await new Promise((resolve) => setTimeout(resolve, this.#reconnectDelay));
|
|
1524
|
+
}
|
|
1525
|
+
catch (error) {
|
|
1526
|
+
console.error('❌ Reconnection failed:', error.message);
|
|
1527
|
+
// Exponential backoff
|
|
1528
|
+
this.#reconnectDelay = Math.min(this.#reconnectDelay * 1.5, 30000);
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
async waitForPeers(timeoutMs = 30000) {
|
|
1532
|
+
return new Promise((resolve) => {
|
|
1533
|
+
const startTime = Date.now();
|
|
1534
|
+
const checkPeers = () => {
|
|
1535
|
+
if (this.compatiblePeers.length > 0) {
|
|
1536
|
+
resolve(true);
|
|
1537
|
+
return;
|
|
1538
|
+
}
|
|
1539
|
+
if (Date.now() - startTime >= timeoutMs) {
|
|
1540
|
+
resolve(false);
|
|
1541
|
+
return;
|
|
1542
|
+
}
|
|
1543
|
+
setTimeout(checkPeers, 1000);
|
|
1544
|
+
};
|
|
1545
|
+
checkPeers();
|
|
1546
|
+
});
|
|
1547
|
+
}
|
|
1548
|
+
}
|
|
1549
|
+
|
|
1417
1550
|
const debug = globalThis.createDebugger('leofcoin/chain');
|
|
1418
1551
|
// check if browser or local
|
|
1419
1552
|
class Chain extends VersionControl {
|
|
@@ -1426,6 +1559,10 @@ class Chain extends VersionControl {
|
|
|
1426
1559
|
#participants;
|
|
1427
1560
|
#participating;
|
|
1428
1561
|
#jail;
|
|
1562
|
+
#peerConnectionRetries;
|
|
1563
|
+
#maxPeerRetries;
|
|
1564
|
+
#peerRetryDelay;
|
|
1565
|
+
#connectionMonitor;
|
|
1429
1566
|
constructor(config) {
|
|
1430
1567
|
super(config);
|
|
1431
1568
|
this.#slotTime = 10000;
|
|
@@ -1437,6 +1574,9 @@ class Chain extends VersionControl {
|
|
|
1437
1574
|
this.#participants = [];
|
|
1438
1575
|
this.#participating = false;
|
|
1439
1576
|
this.#jail = [];
|
|
1577
|
+
this.#peerConnectionRetries = new Map();
|
|
1578
|
+
this.#maxPeerRetries = 5;
|
|
1579
|
+
this.#peerRetryDelay = 5000;
|
|
1440
1580
|
this.#addTransaction = async (message) => {
|
|
1441
1581
|
const transaction = new TransactionMessage(message);
|
|
1442
1582
|
const hash = await transaction.hash();
|
|
@@ -1511,6 +1651,7 @@ class Chain extends VersionControl {
|
|
|
1511
1651
|
// this.node = await new Node()
|
|
1512
1652
|
this.#participants = [];
|
|
1513
1653
|
this.#participating = false;
|
|
1654
|
+
this.#connectionMonitor = new ConnectionMonitor(this.version);
|
|
1514
1655
|
const initialized = await globalThis.contractStore.has(addresses.contractFactory);
|
|
1515
1656
|
if (!initialized)
|
|
1516
1657
|
await this.#setup();
|
|
@@ -1518,8 +1659,11 @@ class Chain extends VersionControl {
|
|
|
1518
1659
|
// this.#state = new State()
|
|
1519
1660
|
// todo some functions rely on state
|
|
1520
1661
|
await super.init();
|
|
1662
|
+
// Start connection monitoring
|
|
1663
|
+
this.#connectionMonitor.start();
|
|
1521
1664
|
await globalThis.peernet.addRequestHandler('bw-request-message', () => {
|
|
1522
|
-
|
|
1665
|
+
const bw = globalThis.peernet.client?.bw || { up: 0, down: 0 };
|
|
1666
|
+
return new BWMessage(bw);
|
|
1523
1667
|
});
|
|
1524
1668
|
// await globalThis.peernet.addRequestHandler('peerId', () => {
|
|
1525
1669
|
// let node =
|
|
@@ -1600,7 +1744,7 @@ class Chain extends VersionControl {
|
|
|
1600
1744
|
}
|
|
1601
1745
|
}
|
|
1602
1746
|
if (this.wantList.length > 0) {
|
|
1603
|
-
const promises = await Promise.allSettled(this.wantList.map((hash) => peernet.get(hash)));
|
|
1747
|
+
const promises = await Promise.allSettled(this.wantList.map((hash) => peernet.get(hash, 'block')));
|
|
1604
1748
|
for (let i = 0; i < promises.length; i++) {
|
|
1605
1749
|
const result = promises[i];
|
|
1606
1750
|
if (result.status === 'fulfilled')
|
|
@@ -1927,7 +2071,7 @@ class Chain extends VersionControl {
|
|
|
1927
2071
|
* @returns
|
|
1928
2072
|
*/
|
|
1929
2073
|
internalCall(sender, contract, method, parameters) {
|
|
1930
|
-
globalThis.msg = this.#createMessage(sender, contract)
|
|
2074
|
+
// globalThis.msg = this.#createMessage(sender, contract) // Debug line removed
|
|
1931
2075
|
return this.machine.execute(contract, method, parameters);
|
|
1932
2076
|
}
|
|
1933
2077
|
/**
|
|
@@ -1938,11 +2082,11 @@ class Chain extends VersionControl {
|
|
|
1938
2082
|
* @returns
|
|
1939
2083
|
*/
|
|
1940
2084
|
call(contract, method, parameters) {
|
|
1941
|
-
globalThis.msg = this.#createMessage(peernet.selectedAccount, contract)
|
|
2085
|
+
// globalThis.msg = this.#createMessage(peernet.selectedAccount, contract) // Debug line removed
|
|
1942
2086
|
return this.machine.execute(contract, method, parameters);
|
|
1943
2087
|
}
|
|
1944
2088
|
staticCall(contract, method, parameters) {
|
|
1945
|
-
globalThis.msg = this.#createMessage(peernet.selectedAccount, contract)
|
|
2089
|
+
// globalThis.msg = this.#createMessage(peernet.selectedAccount, contract) // Debug line removed
|
|
1946
2090
|
return this.machine.get(contract, method, parameters);
|
|
1947
2091
|
}
|
|
1948
2092
|
mint(to, amount) {
|
|
@@ -1972,6 +2116,27 @@ class Chain extends VersionControl {
|
|
|
1972
2116
|
lookup(name) {
|
|
1973
2117
|
return this.call(addresses.nameService, 'lookup', [name]);
|
|
1974
2118
|
}
|
|
2119
|
+
#monitorPeerConnections() {
|
|
2120
|
+
setInterval(() => {
|
|
2121
|
+
const connectedPeers = Object.values(globalThis.peernet.connections).filter((peer) => peer.connected);
|
|
2122
|
+
debug(`Connected peers: ${connectedPeers.length}`);
|
|
2123
|
+
if (connectedPeers.length === 0) {
|
|
2124
|
+
debug('No peers connected, attempting to reconnect...');
|
|
2125
|
+
this.#attemptPeerReconnection();
|
|
2126
|
+
}
|
|
2127
|
+
}, 10000); // Check every 10 seconds
|
|
2128
|
+
}
|
|
2129
|
+
async #attemptPeerReconnection() {
|
|
2130
|
+
try {
|
|
2131
|
+
// Try to reconnect to star servers
|
|
2132
|
+
if (globalThis.peernet && globalThis.peernet.start) {
|
|
2133
|
+
await globalThis.peernet.start();
|
|
2134
|
+
}
|
|
2135
|
+
}
|
|
2136
|
+
catch (error) {
|
|
2137
|
+
console.warn('Failed to reconnect to peers:', error.message);
|
|
2138
|
+
}
|
|
2139
|
+
}
|
|
1975
2140
|
}
|
|
1976
2141
|
|
|
1977
2142
|
export { Chain as default };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Connection Monitor - Monitors peer connections and handles reconnection logic
|
|
3
|
+
*/
|
|
4
|
+
export default class ConnectionMonitor {
|
|
5
|
+
#private;
|
|
6
|
+
get isMonitoring(): boolean;
|
|
7
|
+
get connectedPeers(): import("@netpeer/swarm/peer").default[];
|
|
8
|
+
get compatiblePeers(): import("@netpeer/swarm/peer").default[];
|
|
9
|
+
constructor(version: string);
|
|
10
|
+
start(): void;
|
|
11
|
+
stop(): void;
|
|
12
|
+
waitForPeers(timeoutMs?: number): Promise<boolean>;
|
|
13
|
+
}
|
|
@@ -7,7 +7,8 @@ export default class SyncController {
|
|
|
7
7
|
get fullyLoaded(): boolean;
|
|
8
8
|
constructor();
|
|
9
9
|
/**
|
|
10
|
-
* Resolves/rejects a promise or rejects on timeout
|
|
10
|
+
* Resolves/rejects a promise or rejects on timeout with retry logic
|
|
11
11
|
*/
|
|
12
|
-
resolve():
|
|
12
|
+
resolve(operation: () => Promise<any>, timeoutMs?: number): Promise<any>;
|
|
13
|
+
stop(): void;
|
|
13
14
|
}
|