jaelis-node 1.7.0 → 1.8.0
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/README.md +16 -0
- package/bin/jaelis-node.js +3 -3
- package/config/default.json +1 -3
- package/config/testnet.json +1 -3
- package/lib/index.js +54 -19
- package/package.json +12 -11
package/README.md
CHANGED
|
@@ -440,6 +440,22 @@ JAELIS implements three patent-pending systems:
|
|
|
440
440
|
- Address poisoning detection
|
|
441
441
|
- No trusted setup for privacy features
|
|
442
442
|
|
|
443
|
+
## AI Integration (MCP)
|
|
444
|
+
|
|
445
|
+
JAELIS is AI-native. Claude Desktop users can interact with the blockchain through MCP (Model Context Protocol):
|
|
446
|
+
|
|
447
|
+
```json
|
|
448
|
+
{
|
|
449
|
+
"mcpServers": {
|
|
450
|
+
"jaelis": {
|
|
451
|
+
"url": "https://mcp.jaelis.io/sse"
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
Add this to your Claude Desktop config and get 274+ JAELIS tools automatically - create wallets, send transactions, deploy contracts, query balances, and more.
|
|
458
|
+
|
|
443
459
|
## Links
|
|
444
460
|
|
|
445
461
|
- SDK: [npmjs.com/package/jaelis.js](https://www.npmjs.com/package/jaelis.js)
|
package/bin/jaelis-node.js
CHANGED
|
@@ -42,10 +42,10 @@ const NETWORKS = {
|
|
|
42
42
|
name: 'JAELIS Testnet',
|
|
43
43
|
symbol: 'tJAELIS',
|
|
44
44
|
rpcUrl: 'https://rpc.jaelis.io',
|
|
45
|
+
// Bootstrap via DNS - rpc.jaelis.io resolves to 73.116.51.60
|
|
46
|
+
// No peer ID needed - learned during libp2p handshake
|
|
45
47
|
bootstrapNodes: [
|
|
46
|
-
'/dns4/rpc.jaelis.io/tcp/
|
|
47
|
-
'/dns4/rpc.jaelis.io/tcp/30306/p2p/QmBootstrap2',
|
|
48
|
-
'/dns4/rpc.jaelis.io/tcp/30307/p2p/QmBootstrap3'
|
|
48
|
+
'/dns4/rpc.jaelis.io/tcp/30303'
|
|
49
49
|
]
|
|
50
50
|
},
|
|
51
51
|
mainnet: {
|
package/config/default.json
CHANGED
|
@@ -8,9 +8,7 @@
|
|
|
8
8
|
"name": "testnet",
|
|
9
9
|
"chainId": 4545,
|
|
10
10
|
"bootstrapNodes": [
|
|
11
|
-
"/dns4/rpc.jaelis.io/tcp/
|
|
12
|
-
"/dns4/rpc.jaelis.io/tcp/30306/p2p/QmBootstrap2",
|
|
13
|
-
"/dns4/rpc.jaelis.io/tcp/30307/p2p/QmBootstrap3"
|
|
11
|
+
"/dns4/rpc.jaelis.io/tcp/30303"
|
|
14
12
|
]
|
|
15
13
|
},
|
|
16
14
|
"rpc": {
|
package/config/testnet.json
CHANGED
|
@@ -8,9 +8,7 @@
|
|
|
8
8
|
"https://rpc.jaelis.io"
|
|
9
9
|
],
|
|
10
10
|
"bootstrapNodes": [
|
|
11
|
-
"/dns4/rpc.jaelis.io/tcp/
|
|
12
|
-
"/dns4/rpc.jaelis.io/tcp/30306/p2p/QmBootstrap2",
|
|
13
|
-
"/dns4/rpc.jaelis.io/tcp/30307/p2p/QmBootstrap3"
|
|
11
|
+
"/dns4/rpc.jaelis.io/tcp/30303"
|
|
14
12
|
],
|
|
15
13
|
"genesis": {
|
|
16
14
|
"timestamp": 1731398400000,
|
package/lib/index.js
CHANGED
|
@@ -762,7 +762,8 @@ class JaelisNode extends EventEmitter {
|
|
|
762
762
|
method: 'POST',
|
|
763
763
|
headers: {
|
|
764
764
|
'Content-Type': 'application/json',
|
|
765
|
-
'Content-Length': Buffer.byteLength(data)
|
|
765
|
+
'Content-Length': Buffer.byteLength(data),
|
|
766
|
+
'User-Agent': 'JAELIS-Node/1.7.0' // Identifies us as a node - gets priority treatment
|
|
766
767
|
}
|
|
767
768
|
};
|
|
768
769
|
|
|
@@ -825,7 +826,8 @@ class JaelisNode extends EventEmitter {
|
|
|
825
826
|
method: 'POST',
|
|
826
827
|
headers: {
|
|
827
828
|
'Content-Type': 'application/json',
|
|
828
|
-
'Content-Length': Buffer.byteLength(data)
|
|
829
|
+
'Content-Length': Buffer.byteLength(data),
|
|
830
|
+
'User-Agent': 'JAELIS-Node/1.7.0' // Identifies us as a node - gets priority treatment
|
|
829
831
|
}
|
|
830
832
|
};
|
|
831
833
|
|
|
@@ -1102,23 +1104,46 @@ class EmbeddedBlockchain {
|
|
|
1102
1104
|
* Validates the block before adding to chain
|
|
1103
1105
|
*/
|
|
1104
1106
|
async addBlock(block) {
|
|
1105
|
-
if (!block ||
|
|
1107
|
+
if (!block || block.number === undefined) {
|
|
1106
1108
|
throw new Error('Invalid block');
|
|
1107
1109
|
}
|
|
1108
1110
|
|
|
1111
|
+
// Normalize block number - could be hex string (0x1) or decimal
|
|
1112
|
+
let blockNumber = block.number;
|
|
1113
|
+
if (typeof blockNumber === 'string') {
|
|
1114
|
+
if (blockNumber.startsWith('0x')) {
|
|
1115
|
+
blockNumber = parseInt(blockNumber, 16);
|
|
1116
|
+
} else {
|
|
1117
|
+
blockNumber = parseInt(blockNumber, 10);
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1109
1121
|
const expectedNumber = this.chain.length;
|
|
1110
|
-
if (
|
|
1122
|
+
if (blockNumber !== expectedNumber) {
|
|
1111
1123
|
// Skip if we already have this block or it's out of order
|
|
1112
|
-
if (
|
|
1124
|
+
if (blockNumber < expectedNumber) {
|
|
1113
1125
|
return { status: 'skipped', reason: 'already_have' };
|
|
1114
1126
|
}
|
|
1115
|
-
throw new Error(`Block out of order: expected ${expectedNumber}, got ${
|
|
1127
|
+
throw new Error(`Block out of order: expected ${expectedNumber}, got ${blockNumber}`);
|
|
1116
1128
|
}
|
|
1117
1129
|
|
|
1118
|
-
//
|
|
1130
|
+
// Store normalized block number for consistency
|
|
1131
|
+
block.number = blockNumber;
|
|
1132
|
+
|
|
1133
|
+
// Validate parent hash (skip for first sync - genesis hash may differ)
|
|
1134
|
+
// Like Ethereum "fast sync" - we trust the RPC source initially
|
|
1119
1135
|
const parentBlock = this.getLatestBlock();
|
|
1120
|
-
if (
|
|
1121
|
-
|
|
1136
|
+
if (blockNumber > 1 && block.parentHash && parentBlock.hash) {
|
|
1137
|
+
// Only validate parent hash for blocks after genesis
|
|
1138
|
+
// During initial sync, parent hashes are validated by the remote node
|
|
1139
|
+
if (block.parentHash !== parentBlock.hash) {
|
|
1140
|
+
// Check if this is initial sync (chain is mostly empty)
|
|
1141
|
+
if (this.chain.length > 10) {
|
|
1142
|
+
throw new Error('Invalid parent hash - possible chain reorg');
|
|
1143
|
+
}
|
|
1144
|
+
// During initial sync, log but continue
|
|
1145
|
+
console.log(`[SYNC] Accepting block ${blockNumber} (trusting remote during initial sync)`);
|
|
1146
|
+
}
|
|
1122
1147
|
}
|
|
1123
1148
|
|
|
1124
1149
|
// Add block to chain
|
|
@@ -1215,9 +1240,10 @@ class EmbeddedNetwork {
|
|
|
1215
1240
|
const { tcp } = await import('@libp2p/tcp');
|
|
1216
1241
|
const { noise } = await import('@chainsafe/libp2p-noise');
|
|
1217
1242
|
const { yamux } = await import('@chainsafe/libp2p-yamux');
|
|
1218
|
-
const { bootstrap } = await import('@libp2p/bootstrap');
|
|
1219
1243
|
const { identify } = await import('@libp2p/identify');
|
|
1220
1244
|
|
|
1245
|
+
// Create libp2p node - JAELIS user node
|
|
1246
|
+
// Like Ethereum: start listening, bootstrap nodes come later via DHT
|
|
1221
1247
|
const config = {
|
|
1222
1248
|
addresses: {
|
|
1223
1249
|
listen: [`/ip4/${this.host}/tcp/${this.port}`]
|
|
@@ -1230,17 +1256,11 @@ class EmbeddedNetwork {
|
|
|
1230
1256
|
}
|
|
1231
1257
|
};
|
|
1232
1258
|
|
|
1233
|
-
// Add bootstrap if we have nodes
|
|
1234
|
-
if (this.bootstrapNodes.length > 0) {
|
|
1235
|
-
const validBootstrap = this.bootstrapNodes.filter(n => n.includes('/p2p/'));
|
|
1236
|
-
if (validBootstrap.length > 0) {
|
|
1237
|
-
config.peerDiscovery = [bootstrap({ list: validBootstrap })];
|
|
1238
|
-
}
|
|
1239
|
-
}
|
|
1240
|
-
|
|
1241
1259
|
this.libp2p = await createLibp2p(config);
|
|
1242
1260
|
await this.libp2p.start();
|
|
1243
1261
|
|
|
1262
|
+
console.log(`[P2P] Node started with ID: ${this.libp2p.peerId.toString().slice(0, 16)}...`);
|
|
1263
|
+
|
|
1244
1264
|
// Track peers
|
|
1245
1265
|
this.libp2p.addEventListener('peer:connect', (evt) => {
|
|
1246
1266
|
const peerId = evt.detail.toString();
|
|
@@ -1253,6 +1273,20 @@ class EmbeddedNetwork {
|
|
|
1253
1273
|
this.peers.delete(peerId);
|
|
1254
1274
|
console.log(`[P2P] Peer disconnected (${this.peers.size} remaining)`);
|
|
1255
1275
|
});
|
|
1276
|
+
|
|
1277
|
+
// Try to dial bootstrap nodes directly (without peer ID)
|
|
1278
|
+
// Like Ethereum: we connect via TCP, then learn peer ID during handshake
|
|
1279
|
+
for (const addr of this.bootstrapNodes) {
|
|
1280
|
+
try {
|
|
1281
|
+
const { multiaddr } = await import('@multiformats/multiaddr');
|
|
1282
|
+
const ma = multiaddr(addr);
|
|
1283
|
+
await this.libp2p.dial(ma);
|
|
1284
|
+
console.log(`[P2P] Connected to bootstrap: ${addr}`);
|
|
1285
|
+
} catch (err) {
|
|
1286
|
+
// Bootstrap unavailable - this is OK, we'll use RPC fallback
|
|
1287
|
+
console.log(`[P2P] Bootstrap ${addr.slice(0, 30)}... unavailable`);
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1256
1290
|
}
|
|
1257
1291
|
|
|
1258
1292
|
async _startRPCFallback() {
|
|
@@ -1287,7 +1321,8 @@ class EmbeddedNetwork {
|
|
|
1287
1321
|
method: 'POST',
|
|
1288
1322
|
headers: {
|
|
1289
1323
|
'Content-Type': 'application/json',
|
|
1290
|
-
'Content-Length': Buffer.byteLength(data)
|
|
1324
|
+
'Content-Length': Buffer.byteLength(data),
|
|
1325
|
+
'User-Agent': 'JAELIS-Node/1.7.0' // Node sync traffic - exempt from rate limits
|
|
1291
1326
|
}
|
|
1292
1327
|
}, (res) => {
|
|
1293
1328
|
let body = '';
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jaelis-node",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "Official JAELIS Blockchain Node - Universal VM (6 languages), LevelDB state persistence, native jaelis_* RPC, multi-ecosystem compatibility (eth/solana/move/ton/btc/wasm/starknet), Cross-Chain Settlement (30+ chains!)",
|
|
3
|
+
"version": "1.8.0",
|
|
4
|
+
"description": "Official JAELIS Blockchain Node - Universal VM (6 languages), LevelDB state persistence, native jaelis_* RPC, multi-ecosystem compatibility (eth/solana/move/ton/btc/wasm/starknet), Cross-Chain Settlement (30+ chains!), AI-native MCP integration",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"jaelis-node": "./bin/jaelis-node.js"
|
|
@@ -60,17 +60,18 @@
|
|
|
60
60
|
"node": ">=18.0.0"
|
|
61
61
|
},
|
|
62
62
|
"dependencies": {
|
|
63
|
+
"@chainsafe/libp2p-noise": "^15.1.2",
|
|
64
|
+
"@chainsafe/libp2p-yamux": "^6.0.2",
|
|
65
|
+
"@libp2p/bootstrap": "^10.1.5",
|
|
66
|
+
"@libp2p/identify": "^1.0.21",
|
|
67
|
+
"@libp2p/tcp": "^9.1.6",
|
|
68
|
+
"@multiformats/multiaddr": "^13.0.1",
|
|
69
|
+
"chalk": "^4.1.2",
|
|
70
|
+
"commander": "^11.1.0",
|
|
71
|
+
"cors": "^2.8.5",
|
|
72
|
+
"express": "^4.18.2",
|
|
63
73
|
"level": "^8.0.0",
|
|
64
74
|
"libp2p": "^1.2.0",
|
|
65
|
-
"@libp2p/tcp": "^9.0.0",
|
|
66
|
-
"@libp2p/bootstrap": "^10.0.0",
|
|
67
|
-
"@libp2p/identify": "^1.0.0",
|
|
68
|
-
"@chainsafe/libp2p-noise": "^15.0.0",
|
|
69
|
-
"@chainsafe/libp2p-yamux": "^6.0.0",
|
|
70
|
-
"express": "^4.18.2",
|
|
71
|
-
"cors": "^2.8.5",
|
|
72
|
-
"commander": "^11.1.0",
|
|
73
|
-
"chalk": "^4.1.2",
|
|
74
75
|
"ora": "^5.4.1"
|
|
75
76
|
},
|
|
76
77
|
"files": [
|