jaelis-node 1.9.0 → 2.0.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.
Files changed (173) hide show
  1. package/README.md +147 -433
  2. package/bin/jaelis-node.js +79 -504
  3. package/lib/index.js +31 -2740
  4. package/lib/node.js +271 -0
  5. package/lib/rpc.js +315 -0
  6. package/lib/storage.js +198 -0
  7. package/lib/sync.js +366 -0
  8. package/package.json +19 -53
  9. package/config/default.json +0 -74
  10. package/config/mainnet.json +0 -30
  11. package/config/testnet.json +0 -26
  12. package/lib/JAELIS-VM/lib/adapters/evm-adapter.js +0 -454
  13. package/lib/JAELIS-VM/lib/adapters/index.js +0 -411
  14. package/lib/JAELIS-VM/lib/adapters/svm-adapter.js +0 -457
  15. package/lib/JAELIS-VM/lib/compiler/jir-compiler.js +0 -1097
  16. package/lib/JAELIS-VM/lib/execution/engine.js +0 -1183
  17. package/lib/JAELIS-VM/lib/index.js +0 -440
  18. package/lib/JAELIS-VM/lib/integration/jaelis-integration.js +0 -543
  19. package/lib/JAELIS-VM/lib/serialization/serializer.js +0 -819
  20. package/lib/JAELIS-VM/lib/state/state-manager.js +0 -1116
  21. package/lib/JAELIS-VM/lib/translator/bytecode-translator.js +0 -1222
  22. package/lib/JAELIS-VM/lib/unified/cross-chain-deploy.js +0 -1678
  23. package/lib/JAELIS-VM/lib/unified/cross-chain-state.js +0 -836
  24. package/lib/JAELIS-VM/lib/unified/dynamic-contracts.js +0 -1127
  25. package/lib/JAELIS-VM/lib/unified/index.js +0 -456
  26. package/lib/JAELIS-VM/lib/unified/jaelis-abi.js +0 -1150
  27. package/lib/JAELIS-VM/lib/unified/unified-compiler.js +0 -1350
  28. package/lib/JAELIS-VM/node_modules/.bin/download-cbor-prebuilds +0 -12
  29. package/lib/JAELIS-VM/node_modules/.bin/download-cbor-prebuilds.cmd +0 -17
  30. package/lib/JAELIS-VM/node_modules/.bin/download-cbor-prebuilds.ps1 +0 -28
  31. package/lib/JAELIS-VM/node_modules/.bin/download-msgpackr-prebuilds +0 -12
  32. package/lib/JAELIS-VM/node_modules/.bin/download-msgpackr-prebuilds.cmd +0 -17
  33. package/lib/JAELIS-VM/node_modules/.bin/download-msgpackr-prebuilds.ps1 +0 -28
  34. package/lib/JAELIS-VM/node_modules/.bin/node-gyp-build-optional-packages +0 -12
  35. package/lib/JAELIS-VM/node_modules/.bin/node-gyp-build-optional-packages-optional +0 -12
  36. package/lib/JAELIS-VM/node_modules/.bin/node-gyp-build-optional-packages-optional.cmd +0 -17
  37. package/lib/JAELIS-VM/node_modules/.bin/node-gyp-build-optional-packages-optional.ps1 +0 -28
  38. package/lib/JAELIS-VM/node_modules/.bin/node-gyp-build-optional-packages-test +0 -12
  39. package/lib/JAELIS-VM/node_modules/.bin/node-gyp-build-optional-packages-test.cmd +0 -17
  40. package/lib/JAELIS-VM/node_modules/.bin/node-gyp-build-optional-packages-test.ps1 +0 -28
  41. package/lib/JAELIS-VM/node_modules/.bin/node-gyp-build-optional-packages.cmd +0 -17
  42. package/lib/JAELIS-VM/node_modules/.bin/node-gyp-build-optional-packages.ps1 +0 -28
  43. package/lib/JAELIS-VM/node_modules/.package-lock.json +0 -127
  44. package/lib/JAELIS-VM/node_modules/@cbor-extract/cbor-extract-win32-x64/README.md +0 -1
  45. package/lib/JAELIS-VM/node_modules/@cbor-extract/cbor-extract-win32-x64/index.js +0 -0
  46. package/lib/JAELIS-VM/node_modules/@cbor-extract/cbor-extract-win32-x64/node.abi115.node +0 -0
  47. package/lib/JAELIS-VM/node_modules/@cbor-extract/cbor-extract-win32-x64/node.napi.node +0 -0
  48. package/lib/JAELIS-VM/node_modules/@cbor-extract/cbor-extract-win32-x64/package.json +0 -17
  49. package/lib/JAELIS-VM/node_modules/@msgpackr-extract/msgpackr-extract-win32-x64/README.md +0 -1
  50. package/lib/JAELIS-VM/node_modules/@msgpackr-extract/msgpackr-extract-win32-x64/index.js +0 -0
  51. package/lib/JAELIS-VM/node_modules/@msgpackr-extract/msgpackr-extract-win32-x64/node.abi115.node +0 -0
  52. package/lib/JAELIS-VM/node_modules/@msgpackr-extract/msgpackr-extract-win32-x64/node.napi.node +0 -0
  53. package/lib/JAELIS-VM/node_modules/@msgpackr-extract/msgpackr-extract-win32-x64/package.json +0 -17
  54. package/lib/JAELIS-VM/node_modules/cbor-extract/LICENSE +0 -21
  55. package/lib/JAELIS-VM/node_modules/cbor-extract/README.md +0 -5
  56. package/lib/JAELIS-VM/node_modules/cbor-extract/bin/download-prebuilds.js +0 -11
  57. package/lib/JAELIS-VM/node_modules/cbor-extract/binding.gyp +0 -60
  58. package/lib/JAELIS-VM/node_modules/cbor-extract/index.js +0 -1
  59. package/lib/JAELIS-VM/node_modules/cbor-extract/package.json +0 -50
  60. package/lib/JAELIS-VM/node_modules/cbor-extract/src/extract.cpp +0 -198
  61. package/lib/JAELIS-VM/node_modules/cbor-x/LICENSE +0 -21
  62. package/lib/JAELIS-VM/node_modules/cbor-x/README.md +0 -380
  63. package/lib/JAELIS-VM/node_modules/cbor-x/SECURITY.md +0 -11
  64. package/lib/JAELIS-VM/node_modules/cbor-x/benchmark.md +0 -73
  65. package/lib/JAELIS-VM/node_modules/cbor-x/browser.js +0 -11
  66. package/lib/JAELIS-VM/node_modules/cbor-x/decode.d.ts +0 -2
  67. package/lib/JAELIS-VM/node_modules/cbor-x/decode.js +0 -1300
  68. package/lib/JAELIS-VM/node_modules/cbor-x/dist/decode-no-eval.cjs +0 -1244
  69. package/lib/JAELIS-VM/node_modules/cbor-x/dist/decode-no-eval.cjs.map +0 -1
  70. package/lib/JAELIS-VM/node_modules/cbor-x/dist/index-no-eval.cjs +0 -2509
  71. package/lib/JAELIS-VM/node_modules/cbor-x/dist/index-no-eval.cjs.map +0 -1
  72. package/lib/JAELIS-VM/node_modules/cbor-x/dist/index-no-eval.min.js +0 -2
  73. package/lib/JAELIS-VM/node_modules/cbor-x/dist/index-no-eval.min.js.map +0 -1
  74. package/lib/JAELIS-VM/node_modules/cbor-x/dist/index.js +0 -2508
  75. package/lib/JAELIS-VM/node_modules/cbor-x/dist/index.js.map +0 -1
  76. package/lib/JAELIS-VM/node_modules/cbor-x/dist/index.min.js +0 -2
  77. package/lib/JAELIS-VM/node_modules/cbor-x/dist/index.min.js.map +0 -1
  78. package/lib/JAELIS-VM/node_modules/cbor-x/dist/node.cjs +0 -2629
  79. package/lib/JAELIS-VM/node_modules/cbor-x/dist/node.cjs.map +0 -1
  80. package/lib/JAELIS-VM/node_modules/cbor-x/dist/test.js +0 -3343
  81. package/lib/JAELIS-VM/node_modules/cbor-x/dist/test.js.map +0 -1
  82. package/lib/JAELIS-VM/node_modules/cbor-x/encode.d.ts +0 -1
  83. package/lib/JAELIS-VM/node_modules/cbor-x/encode.js +0 -1231
  84. package/lib/JAELIS-VM/node_modules/cbor-x/index.d.ts +0 -79
  85. package/lib/JAELIS-VM/node_modules/cbor-x/index.js +0 -3
  86. package/lib/JAELIS-VM/node_modules/cbor-x/iterators.js +0 -85
  87. package/lib/JAELIS-VM/node_modules/cbor-x/node-index.js +0 -24
  88. package/lib/JAELIS-VM/node_modules/cbor-x/package.json +0 -94
  89. package/lib/JAELIS-VM/node_modules/cbor-x/rollup.config.js +0 -88
  90. package/lib/JAELIS-VM/node_modules/cbor-x/stream.js +0 -61
  91. package/lib/JAELIS-VM/node_modules/cbor-x/webpack.config.js +0 -19
  92. package/lib/JAELIS-VM/node_modules/detect-libc/LICENSE +0 -201
  93. package/lib/JAELIS-VM/node_modules/detect-libc/README.md +0 -163
  94. package/lib/JAELIS-VM/node_modules/detect-libc/index.d.ts +0 -14
  95. package/lib/JAELIS-VM/node_modules/detect-libc/lib/detect-libc.js +0 -313
  96. package/lib/JAELIS-VM/node_modules/detect-libc/lib/elf.js +0 -39
  97. package/lib/JAELIS-VM/node_modules/detect-libc/lib/filesystem.js +0 -51
  98. package/lib/JAELIS-VM/node_modules/detect-libc/lib/process.js +0 -24
  99. package/lib/JAELIS-VM/node_modules/detect-libc/package.json +0 -44
  100. package/lib/JAELIS-VM/node_modules/msgpackr/LICENSE +0 -21
  101. package/lib/JAELIS-VM/node_modules/msgpackr/README.md +0 -372
  102. package/lib/JAELIS-VM/node_modules/msgpackr/SECURITY.md +0 -11
  103. package/lib/JAELIS-VM/node_modules/msgpackr/benchmark.md +0 -67
  104. package/lib/JAELIS-VM/node_modules/msgpackr/dist/index-no-eval.cjs +0 -2407
  105. package/lib/JAELIS-VM/node_modules/msgpackr/dist/index-no-eval.cjs.map +0 -1
  106. package/lib/JAELIS-VM/node_modules/msgpackr/dist/index-no-eval.min.js +0 -2
  107. package/lib/JAELIS-VM/node_modules/msgpackr/dist/index-no-eval.min.js.map +0 -1
  108. package/lib/JAELIS-VM/node_modules/msgpackr/dist/index.js +0 -2406
  109. package/lib/JAELIS-VM/node_modules/msgpackr/dist/index.js.map +0 -1
  110. package/lib/JAELIS-VM/node_modules/msgpackr/dist/index.min.js +0 -2
  111. package/lib/JAELIS-VM/node_modules/msgpackr/dist/index.min.js.map +0 -1
  112. package/lib/JAELIS-VM/node_modules/msgpackr/dist/node.cjs +0 -3320
  113. package/lib/JAELIS-VM/node_modules/msgpackr/dist/node.cjs.map +0 -1
  114. package/lib/JAELIS-VM/node_modules/msgpackr/dist/test.js +0 -4540
  115. package/lib/JAELIS-VM/node_modules/msgpackr/dist/test.js.map +0 -1
  116. package/lib/JAELIS-VM/node_modules/msgpackr/dist/unpack-no-eval.cjs +0 -1250
  117. package/lib/JAELIS-VM/node_modules/msgpackr/dist/unpack-no-eval.cjs.map +0 -1
  118. package/lib/JAELIS-VM/node_modules/msgpackr/index.d.cts +0 -91
  119. package/lib/JAELIS-VM/node_modules/msgpackr/index.d.ts +0 -91
  120. package/lib/JAELIS-VM/node_modules/msgpackr/index.js +0 -5
  121. package/lib/JAELIS-VM/node_modules/msgpackr/iterators.js +0 -87
  122. package/lib/JAELIS-VM/node_modules/msgpackr/node-index.js +0 -25
  123. package/lib/JAELIS-VM/node_modules/msgpackr/pack.d.cts +0 -1
  124. package/lib/JAELIS-VM/node_modules/msgpackr/pack.d.ts +0 -1
  125. package/lib/JAELIS-VM/node_modules/msgpackr/pack.js +0 -1141
  126. package/lib/JAELIS-VM/node_modules/msgpackr/package.json +0 -104
  127. package/lib/JAELIS-VM/node_modules/msgpackr/rollup.config.js +0 -88
  128. package/lib/JAELIS-VM/node_modules/msgpackr/stream.js +0 -57
  129. package/lib/JAELIS-VM/node_modules/msgpackr/struct.js +0 -815
  130. package/lib/JAELIS-VM/node_modules/msgpackr/test-worker.js +0 -3
  131. package/lib/JAELIS-VM/node_modules/msgpackr/unpack.d.cts +0 -2
  132. package/lib/JAELIS-VM/node_modules/msgpackr/unpack.d.ts +0 -2
  133. package/lib/JAELIS-VM/node_modules/msgpackr/unpack.js +0 -1221
  134. package/lib/JAELIS-VM/node_modules/msgpackr-extract/LICENSE +0 -21
  135. package/lib/JAELIS-VM/node_modules/msgpackr-extract/README.md +0 -5
  136. package/lib/JAELIS-VM/node_modules/msgpackr-extract/bin/download-prebuilds.js +0 -13
  137. package/lib/JAELIS-VM/node_modules/msgpackr-extract/binding.gyp +0 -63
  138. package/lib/JAELIS-VM/node_modules/msgpackr-extract/index.js +0 -1
  139. package/lib/JAELIS-VM/node_modules/msgpackr-extract/node_modules/.bin/node-gyp-build-optional-packages +0 -12
  140. package/lib/JAELIS-VM/node_modules/msgpackr-extract/node_modules/.bin/node-gyp-build-optional-packages-optional +0 -12
  141. package/lib/JAELIS-VM/node_modules/msgpackr-extract/node_modules/.bin/node-gyp-build-optional-packages-optional.cmd +0 -17
  142. package/lib/JAELIS-VM/node_modules/msgpackr-extract/node_modules/.bin/node-gyp-build-optional-packages-optional.ps1 +0 -28
  143. package/lib/JAELIS-VM/node_modules/msgpackr-extract/node_modules/.bin/node-gyp-build-optional-packages-test +0 -12
  144. package/lib/JAELIS-VM/node_modules/msgpackr-extract/node_modules/.bin/node-gyp-build-optional-packages-test.cmd +0 -17
  145. package/lib/JAELIS-VM/node_modules/msgpackr-extract/node_modules/.bin/node-gyp-build-optional-packages-test.ps1 +0 -28
  146. package/lib/JAELIS-VM/node_modules/msgpackr-extract/node_modules/.bin/node-gyp-build-optional-packages.cmd +0 -17
  147. package/lib/JAELIS-VM/node_modules/msgpackr-extract/node_modules/.bin/node-gyp-build-optional-packages.ps1 +0 -28
  148. package/lib/JAELIS-VM/node_modules/msgpackr-extract/node_modules/node-gyp-build-optional-packages/LICENSE +0 -21
  149. package/lib/JAELIS-VM/node_modules/msgpackr-extract/node_modules/node-gyp-build-optional-packages/README.md +0 -58
  150. package/lib/JAELIS-VM/node_modules/msgpackr-extract/node_modules/node-gyp-build-optional-packages/bin.js +0 -82
  151. package/lib/JAELIS-VM/node_modules/msgpackr-extract/node_modules/node-gyp-build-optional-packages/build-test.js +0 -19
  152. package/lib/JAELIS-VM/node_modules/msgpackr-extract/node_modules/node-gyp-build-optional-packages/index.js +0 -6
  153. package/lib/JAELIS-VM/node_modules/msgpackr-extract/node_modules/node-gyp-build-optional-packages/node-gyp-build.js +0 -236
  154. package/lib/JAELIS-VM/node_modules/msgpackr-extract/node_modules/node-gyp-build-optional-packages/optional.js +0 -7
  155. package/lib/JAELIS-VM/node_modules/msgpackr-extract/node_modules/node-gyp-build-optional-packages/package.json +0 -32
  156. package/lib/JAELIS-VM/node_modules/msgpackr-extract/package.json +0 -50
  157. package/lib/JAELIS-VM/node_modules/msgpackr-extract/src/extract.cpp +0 -274
  158. package/lib/JAELIS-VM/node_modules/node-gyp-build-optional-packages/LICENSE +0 -21
  159. package/lib/JAELIS-VM/node_modules/node-gyp-build-optional-packages/README.md +0 -58
  160. package/lib/JAELIS-VM/node_modules/node-gyp-build-optional-packages/bin.js +0 -77
  161. package/lib/JAELIS-VM/node_modules/node-gyp-build-optional-packages/build-test.js +0 -19
  162. package/lib/JAELIS-VM/node_modules/node-gyp-build-optional-packages/index.js +0 -224
  163. package/lib/JAELIS-VM/node_modules/node-gyp-build-optional-packages/optional.js +0 -7
  164. package/lib/JAELIS-VM/node_modules/node-gyp-build-optional-packages/package.json +0 -32
  165. package/lib/JAELIS-VM/package-lock.json +0 -284
  166. package/lib/JAELIS-VM/package.json +0 -38
  167. package/lib/JAELIS-VM/test/comprehensive.test.js +0 -267
  168. package/lib/JAELIS-VM/test/cross-chain-test.js +0 -470
  169. package/lib/JAELIS-VM/test/unified-vm-test.js +0 -459
  170. package/lib/JAELIS-VM/test/unified.test.js +0 -166
  171. package/lib/JAELIS-VM/test/vm.test.js +0 -599
  172. package/lib/settlement-server.js +0 -999
  173. package/lib/vm/index.js +0 -397
package/lib/index.js CHANGED
@@ -1,2763 +1,54 @@
1
1
  /**
2
- * JAELIS Node Library
3
- * Core node implementation for the JAELIS blockchain
2
+ * JAELIS External Node
4
3
  *
5
- * This module provides the JaelisNode class which wraps the core blockchain
6
- * implementation for easy deployment as a standalone node.
4
+ * A lightweight node that connects to the JAELIS network, syncs blocks,
5
+ * and exposes local RPC for dApps. Like running geth light mode.
7
6
  *
8
- * ═══════════════════════════════════════════════════════════════════════════════
9
- * RPC ARCHITECTURE (v1.4.0+)
10
- * ═══════════════════════════════════════════════════════════════════════════════
7
+ * Architecture:
8
+ * - WebSocket connection to JAELIS main network
9
+ * - Local LevelDB for block/state storage
10
+ * - JSON-RPC server for local dApp access
11
+ * - NO internal JAELIS code - just network protocol
11
12
  *
12
- * LAYER 1 - NATIVE JAELIS (PRIMARY):
13
- * jaelis_* Native JAELIS methods - rich responses, zero-gas semantics
14
- *
15
- * LAYER 2 - COMPATIBILITY (PROXIES):
16
- * eth_* Ethereum JSON-RPC compat (MetaMask, ethers.js, web3.js)
17
- * solana_* Solana-compatible methods (Rust/SPL developers)
18
- * move_* Move-compatible methods (Aptos/Sui developers)
19
- * ton_* TON-compatible methods (FunC/Telegram developers)
20
- *
21
- * All compatibility methods PROXY to native jaelis_* implementations.
22
- * This follows Solana/Cosmos/Polkadot patterns for multi-ecosystem support.
23
- * ═══════════════════════════════════════════════════════════════════════════════
24
- *
25
- * @version 1.4.0
26
- * @author JAELIS Foundation
27
- */
28
-
29
- const path = require('path');
30
- const fs = require('fs');
31
- const crypto = require('crypto');
32
- const EventEmitter = require('events');
33
-
34
- // ═══════════════════════════════════════════════════════════════════════════
35
- // MULTI-CHAIN ADDRESS UTILITIES
36
- // Supports: EVM (0x...), Solana (base58), Bitcoin (P2PKH/bech32), etc.
37
- // JAELIS accepts ANY chain's address format - TRUE multi-chain!
38
- // ═══════════════════════════════════════════════════════════════════════════
39
-
40
- const ADDRESS_FORMATS = {
41
- // EVM chains (Ethereum, Polygon, Arbitrum, etc.)
42
- evm: {
43
- pattern: /^0x[a-fA-F0-9]{40}$/,
44
- name: 'EVM (Ethereum, Polygon, etc.)',
45
- example: '0x742d35Cc6634C0532925a3b844Bc9e7595f...'
46
- },
47
- // Solana (base58)
48
- solana: {
49
- pattern: /^[1-9A-HJ-NP-Za-km-z]{32,44}$/,
50
- name: 'Solana',
51
- example: '7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZ...'
52
- },
53
- // Bitcoin P2PKH (starts with 1 or 3)
54
- bitcoin_legacy: {
55
- pattern: /^[13][a-km-zA-HJ-NP-Z1-9]{25,34}$/,
56
- name: 'Bitcoin (Legacy)',
57
- example: '1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2'
58
- },
59
- // Bitcoin bech32 (starts with bc1)
60
- bitcoin_bech32: {
61
- pattern: /^bc1[a-z0-9]{39,59}$/,
62
- name: 'Bitcoin (SegWit)',
63
- example: 'bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq'
64
- },
65
- // TON (base64url)
66
- ton: {
67
- pattern: /^[A-Za-z0-9_-]{48}$/,
68
- name: 'TON',
69
- example: 'EQCD39VS5jcptHL8vMjEXrzGaRcCVYto7HUn4bpAOg8xqB2N'
70
- },
71
- // Aptos/Sui (hex with 0x, 64 chars)
72
- move: {
73
- pattern: /^0x[a-fA-F0-9]{64}$/,
74
- name: 'Move (Aptos/Sui)',
75
- example: '0x1234567890abcdef...'
76
- },
77
- // JAELIS native (same as EVM for now, but could be extended)
78
- jaelis: {
79
- pattern: /^0x[a-fA-F0-9]{40}$/,
80
- name: 'JAELIS Native',
81
- example: '0x742d35Cc6634C0532925a3b844Bc9e7595f...'
82
- }
83
- };
84
-
85
- /**
86
- * Detect the chain type from an address
87
- */
88
- function detectAddressType(address) {
89
- if (!address || typeof address !== 'string') {
90
- return null;
91
- }
92
-
93
- // Check each format
94
- for (const [type, config] of Object.entries(ADDRESS_FORMATS)) {
95
- if (config.pattern.test(address)) {
96
- return { type, ...config };
97
- }
98
- }
99
-
100
- return null;
101
- }
102
-
103
- /**
104
- * Validate any chain address
13
+ * @version 2.0.0
14
+ * @license MIT
105
15
  */
106
- function validateAddress(address) {
107
- const detected = detectAddressType(address);
108
- if (!detected) {
109
- return {
110
- valid: false,
111
- error: 'Unknown address format',
112
- supportedFormats: Object.keys(ADDRESS_FORMATS)
113
- };
114
- }
115
- return {
116
- valid: true,
117
- type: detected.type,
118
- name: detected.name
119
- };
120
- }
121
-
122
- /**
123
- * Convert any address to canonical form for internal storage
124
- * EVM addresses are lowercased, others kept as-is
125
- */
126
- function toCanonicalAddress(address) {
127
- const detected = detectAddressType(address);
128
- if (!detected) {
129
- throw new Error('Invalid address format');
130
- }
131
-
132
- // EVM addresses are case-insensitive, normalize to lowercase
133
- if (detected.type === 'evm' || detected.type === 'jaelis') {
134
- return address.toLowerCase();
135
- }
136
-
137
- // Other formats are case-sensitive
138
- return address;
139
- }
140
16
 
141
- // ═══════════════════════════════════════════════════════════════════════════
142
- // NODE WALLET CONFIGURATION (Like Geth --suggested-fee-recipient)
143
- // Stores the node operator's wallet for receiving rewards
144
- // NO STAKING REQUIRED - JAELIS doesn't hold your funds!
145
- // ═══════════════════════════════════════════════════════════════════════════
146
-
147
- class NodeWalletConfig {
148
- constructor(dataDir) {
149
- this.dataDir = dataDir;
150
- this.configPath = path.join(dataDir, 'node-wallet.json');
151
- this.config = null;
152
- }
153
-
154
- /**
155
- * Load wallet configuration from disk
156
- */
157
- load() {
158
- try {
159
- if (fs.existsSync(this.configPath)) {
160
- const data = fs.readFileSync(this.configPath, 'utf8');
161
- this.config = JSON.parse(data);
162
- return this.config;
163
- }
164
- } catch (e) {
165
- console.warn('[WALLET] Failed to load wallet config:', e.message);
166
- }
167
- return null;
168
- }
169
-
170
- /**
171
- * Save wallet configuration to disk
172
- */
173
- save() {
174
- try {
175
- // Ensure directory exists
176
- if (!fs.existsSync(this.dataDir)) {
177
- fs.mkdirSync(this.dataDir, { recursive: true });
178
- }
179
- fs.writeFileSync(this.configPath, JSON.stringify(this.config, null, 2));
180
- return true;
181
- } catch (e) {
182
- console.error('[WALLET] Failed to save wallet config:', e.message);
183
- return false;
184
- }
185
- }
186
-
187
- /**
188
- * Set the reward recipient wallet (ANY chain address!)
189
- * Like Geth's --suggested-fee-recipient
190
- */
191
- setRewardRecipient(address) {
192
- const validation = validateAddress(address);
193
- if (!validation.valid) {
194
- throw new Error(`Invalid address: ${validation.error}`);
195
- }
196
-
197
- if (!this.config) {
198
- this.config = { createdAt: Date.now() };
199
- }
200
-
201
- this.config.rewardRecipient = {
202
- address: toCanonicalAddress(address),
203
- originalFormat: address,
204
- type: validation.type,
205
- typeName: validation.name,
206
- setAt: Date.now()
207
- };
208
-
209
- this.save();
210
- console.log(`[WALLET] Reward recipient set: ${address} (${validation.name})`);
211
- return this.config.rewardRecipient;
212
- }
213
-
214
- /**
215
- * Get the reward recipient address
216
- */
217
- getRewardRecipient() {
218
- if (!this.config) this.load();
219
- return this.config?.rewardRecipient || null;
220
- }
221
-
222
- /**
223
- * Add an additional wallet (for multi-wallet nodes)
224
- */
225
- addWallet(name, address, options = {}) {
226
- const validation = validateAddress(address);
227
- if (!validation.valid) {
228
- throw new Error(`Invalid address: ${validation.error}`);
229
- }
230
-
231
- if (!this.config) {
232
- this.config = { createdAt: Date.now() };
233
- }
234
-
235
- if (!this.config.wallets) {
236
- this.config.wallets = [];
237
- }
238
-
239
- // Check for duplicates
240
- const existing = this.config.wallets.find(w =>
241
- toCanonicalAddress(w.address) === toCanonicalAddress(address)
242
- );
243
- if (existing) {
244
- throw new Error(`Wallet already exists: ${existing.name}`);
245
- }
246
-
247
- const wallet = {
248
- name,
249
- address: toCanonicalAddress(address),
250
- originalFormat: address,
251
- type: validation.type,
252
- typeName: validation.name,
253
- purpose: options.purpose || 'general',
254
- addedAt: Date.now()
255
- };
256
-
257
- this.config.wallets.push(wallet);
258
- this.save();
259
- console.log(`[WALLET] Added wallet: ${name} (${validation.name})`);
260
- return wallet;
261
- }
262
-
263
- /**
264
- * Remove a wallet by name or address
265
- */
266
- removeWallet(nameOrAddress) {
267
- if (!this.config?.wallets) {
268
- throw new Error('No wallets configured');
269
- }
270
-
271
- const canonical = nameOrAddress.startsWith('0x') || nameOrAddress.startsWith('bc1')
272
- ? toCanonicalAddress(nameOrAddress)
273
- : null;
274
-
275
- const index = this.config.wallets.findIndex(w =>
276
- w.name === nameOrAddress ||
277
- (canonical && toCanonicalAddress(w.address) === canonical)
278
- );
279
-
280
- if (index === -1) {
281
- throw new Error(`Wallet not found: ${nameOrAddress}`);
282
- }
283
-
284
- const removed = this.config.wallets.splice(index, 1)[0];
285
- this.save();
286
- console.log(`[WALLET] Removed wallet: ${removed.name}`);
287
- return removed;
288
- }
289
-
290
- /**
291
- * List all configured wallets
292
- */
293
- listWallets() {
294
- if (!this.config) this.load();
295
- return {
296
- rewardRecipient: this.config?.rewardRecipient || null,
297
- wallets: this.config?.wallets || []
298
- };
299
- }
300
-
301
- /**
302
- * Get node identity (generates one if not exists)
303
- * Like Solana's identity keypair
304
- */
305
- getNodeIdentity() {
306
- if (!this.config) this.load();
307
- if (!this.config) {
308
- this.config = { createdAt: Date.now() };
309
- }
310
-
311
- if (!this.config.nodeIdentity) {
312
- // Generate a node identity (not a wallet, just an ID)
313
- const nodeId = crypto.randomBytes(32).toString('hex');
314
- this.config.nodeIdentity = {
315
- id: nodeId,
316
- publicKey: '0x' + crypto.createHash('sha256').update(nodeId).digest('hex').slice(0, 40),
317
- createdAt: Date.now()
318
- };
319
- this.save();
320
- console.log(`[WALLET] Generated node identity: ${this.config.nodeIdentity.publicKey}`);
321
- }
322
-
323
- return this.config.nodeIdentity;
324
- }
17
+ 'use strict';
325
18
 
326
- /**
327
- * Get full configuration
328
- */
329
- getConfig() {
330
- if (!this.config) this.load();
331
- return this.config;
332
- }
333
- }
19
+ const { JaelisNode } = require('./node');
20
+ const { SyncManager } = require('./sync');
21
+ const { RPCServer } = require('./rpc');
22
+ const { Storage } = require('./storage');
334
23
 
335
- // JAELIS Network Endpoints - users connect here automatically
336
- // Bootstrap nodes use libp2p multiaddr format: /dns4/host/tcp/port/p2p/PEER_ID
337
- // External nodes connect via DNS which resolves to the main node's public IP
338
- //
339
- // IMPORTANT: Peer ID is required for libp2p dialing!
340
- // The peer ID is generated on first run and persisted to disk.
341
- // Main node logs bootstrap info on startup - update this when it changes.
342
- const JAELIS_NETWORKS = {
24
+ // Network configurations (public endpoints only)
25
+ const NETWORKS = Object.freeze({
343
26
  testnet: {
344
27
  name: 'JAELIS Testnet',
345
28
  chainId: 4545,
346
29
  symbol: 'tJAELIS',
347
- rpcUrl: 'https://rpc.jaelis.io',
348
- wsUrl: 'wss://rpc.jaelis.io/ws',
349
- explorerUrl: 'https://explorer.jaelis.io',
350
- // Testnet uses port 30304 (mainnet uses 30303)
351
- // Peer ID will be added after main node first run
352
- // For now, P2P will fallback to RPC sync until peer ID is configured
353
- bootstrapNodes: [
354
- // Format: /dns4/rpc.jaelis.io/tcp/30304/p2p/PEER_ID
355
- // The main node outputs this on startup - update here when available
356
- ]
30
+ rpcEndpoint: 'https://rpc.jaelis.io',
31
+ wsEndpoint: 'wss://rpc.jaelis.io/ws',
32
+ explorerUrl: 'https://explorer.jaelis.io'
357
33
  },
358
34
  mainnet: {
359
35
  name: 'JAELIS Mainnet',
360
36
  chainId: 4547,
361
37
  symbol: 'JAELIS',
362
- rpcUrl: 'https://mainnet.jaelis.io',
363
- wsUrl: 'wss://mainnet.jaelis.io/ws',
364
- explorerUrl: 'https://explorer.jaelis.io',
365
- bootstrapNodes: [],
366
- status: 'coming-soon'
367
- }
368
- };
369
-
370
- /**
371
- * JaelisNode - Main node class for running a JAELIS blockchain node
372
- */
373
- class JaelisNode extends EventEmitter {
374
- constructor(options = {}) {
375
- super();
376
-
377
- // Get network config - defaults to testnet
378
- const networkName = options.network || 'testnet';
379
- const networkConfig = JAELIS_NETWORKS[networkName] || JAELIS_NETWORKS.testnet;
380
-
381
- this.options = {
382
- network: networkName,
383
- networkConfig: networkConfig,
384
- chainId: networkConfig.chainId,
385
- rpcPort: options.rpcPort || 8545,
386
- rpcHost: options.rpcHost || '0.0.0.0',
387
- p2pPort: options.p2pPort || 30303,
388
- dataDir: options.dataDir || './jaelis-data',
389
- syncMode: options.syncMode || 'full',
390
- enableRpc: options.enableRpc !== false,
391
- enableP2p: options.enableP2p !== false,
392
- bootstrapNodes: options.bootstrapNodes || networkConfig.bootstrapNodes,
393
- maxPeers: options.maxPeers || 50,
394
- // Remote RPC to sync from
395
- remoteRpc: options.remoteRpc || networkConfig.rpcUrl,
396
- ...options
397
- };
398
-
399
- this.blockchain = null;
400
- this.network = null;
401
- this.rpcServer = null;
402
- this.isRunning = false;
403
- this.startTime = null;
404
- this.peerCount = 0;
405
-
406
- // Initialize wallet configuration (like Geth's keystore)
407
- this.walletConfig = new NodeWalletConfig(this.options.dataDir);
408
- this.walletConfig.load();
409
-
410
- // Set reward recipient if provided via options (like --suggested-fee-recipient)
411
- if (options.rewardRecipient) {
412
- this.walletConfig.setRewardRecipient(options.rewardRecipient);
413
- }
414
- }
415
-
416
- /**
417
- * Get the wallet configuration manager
418
- */
419
- getWalletConfig() {
420
- return this.walletConfig;
421
- }
422
-
423
- /**
424
- * Set the reward recipient address (ANY chain format!)
425
- * Like Geth's --suggested-fee-recipient
426
- */
427
- setRewardRecipient(address) {
428
- return this.walletConfig.setRewardRecipient(address);
429
- }
430
-
431
- /**
432
- * Get the reward recipient address
433
- */
434
- getRewardRecipient() {
435
- return this.walletConfig.getRewardRecipient();
436
- }
437
-
438
- /**
439
- * Add a wallet to this node
440
- */
441
- addWallet(name, address, options = {}) {
442
- return this.walletConfig.addWallet(name, address, options);
443
- }
444
-
445
- /**
446
- * Remove a wallet from this node
447
- */
448
- removeWallet(nameOrAddress) {
449
- return this.walletConfig.removeWallet(nameOrAddress);
450
- }
451
-
452
- /**
453
- * List all configured wallets
454
- */
455
- listWallets() {
456
- return this.walletConfig.listWallets();
457
- }
458
-
459
- /**
460
- * Get node identity
461
- */
462
- getNodeIdentity() {
463
- return this.walletConfig.getNodeIdentity();
464
- }
465
-
466
- /**
467
- * Start the node
468
- */
469
- async start() {
470
- if (this.isRunning) {
471
- throw new Error('Node is already running');
472
- }
473
-
474
- console.log(`[JAELIS] Starting node on ${this.options.network}...`);
475
-
476
- // Ensure data directory exists
477
- if (!fs.existsSync(this.options.dataDir)) {
478
- fs.mkdirSync(this.options.dataDir, { recursive: true });
479
- }
480
-
481
- try {
482
- // Try to load from JAELIS core
483
- await this._loadCore();
484
-
485
- // Initialize blockchain
486
- await this._initBlockchain();
487
-
488
- // Start P2P networking
489
- if (this.options.enableP2p) {
490
- await this._initNetwork();
491
- }
492
-
493
- // Start RPC server
494
- if (this.options.enableRpc) {
495
- await this._initRpcServer();
496
- }
497
-
498
- // Start Settlement Server for cross-chain deployments
499
- await this._initSettlementServer();
500
-
501
- this.isRunning = true;
502
- this.startTime = Date.now();
503
-
504
- // Register with the JAELIS network for tracking
505
- await this._registerWithNetwork();
506
-
507
- // Start heartbeat to keep registration alive
508
- this._startHeartbeat();
509
-
510
- this.emit('started', {
511
- network: this.options.network,
512
- chainId: this.options.chainId,
513
- rpcPort: this.options.rpcPort,
514
- p2pPort: this.options.p2pPort
515
- });
516
-
517
- console.log(`[JAELIS] Node started successfully`);
518
-
519
- } catch (error) {
520
- console.error(`[JAELIS] Failed to start node: ${error.message}`);
521
- throw error;
522
- }
523
- }
524
-
525
- /**
526
- * Stop the node
527
- */
528
- async stop() {
529
- if (!this.isRunning) {
530
- return;
531
- }
532
-
533
- console.log('[JAELIS] Stopping node...');
534
-
535
- // Stop heartbeat first
536
- this._stopHeartbeat();
537
-
538
- // Stop Settlement server
539
- if (this.settlementServer) {
540
- await this._stopSettlementServer();
541
- }
542
-
543
- // Stop RPC server
544
- if (this.rpcServer) {
545
- await this._stopRpcServer();
546
- }
547
-
548
- // Stop P2P network
549
- if (this.network) {
550
- await this._stopNetwork();
551
- }
552
-
553
- // Save blockchain state
554
- if (this.blockchain) {
555
- await this._saveState();
556
- }
557
-
558
- this.isRunning = false;
559
- this.emit('stopped');
560
-
561
- console.log('[JAELIS] Node stopped');
562
- }
563
-
564
- /**
565
- * Initialize node modules - connects to JAELIS network
566
- */
567
- async _loadCore() {
568
- console.log(`[JAELIS] Connecting to ${this.options.networkConfig.name}...`);
569
- console.log(`[JAELIS] RPC: ${this.options.remoteRpc}`);
570
-
571
- // Use embedded light client that syncs from remote RPC
572
- this.JaelisBlockchain = EmbeddedBlockchain;
573
- this.JaelisNetwork = EmbeddedNetwork;
574
- this.JaelisRpcServer = EmbeddedRpcServer;
575
- this.JaelisStorage = EmbeddedStorage;
576
- }
577
-
578
- /**
579
- * Initialize blockchain
580
- */
581
- async _initBlockchain() {
582
- console.log('[JAELIS] Initializing blockchain...');
583
-
584
- const storagePath = path.join(this.options.dataDir, 'blockchain');
585
-
586
- if (this.JaelisBlockchain) {
587
- this.blockchain = new this.JaelisBlockchain({
588
- chainId: this.options.chainId,
589
- dataDir: storagePath,
590
- network: this.options.network
591
- });
592
-
593
- if (this.blockchain.initialize) {
594
- await this.blockchain.initialize();
595
- }
596
- }
597
-
598
- console.log(`[JAELIS] Blockchain initialized (Chain ID: ${this.options.chainId})`);
599
- }
600
-
601
- /**
602
- * Initialize P2P network
603
- */
604
- async _initNetwork() {
605
- console.log('[JAELIS] Initializing P2P network...');
606
-
607
- if (this.JaelisNetwork) {
608
- this.network = new this.JaelisNetwork({
609
- port: this.options.p2pPort,
610
- maxPeers: this.options.maxPeers,
611
- bootstrapNodes: this.options.bootstrapNodes,
612
- blockchain: this.blockchain,
613
- remoteRpc: this.options.remoteRpc
614
- });
615
-
616
- if (this.network.start) {
617
- await this.network.start();
618
- }
619
-
620
- // Track peer count
621
- if (this.network.on) {
622
- this.network.on('peer:connect', () => {
623
- this.peerCount++;
624
- this.emit('peer:connect', this.peerCount);
625
- });
626
-
627
- this.network.on('peer:disconnect', () => {
628
- this.peerCount = Math.max(0, this.peerCount - 1);
629
- this.emit('peer:disconnect', this.peerCount);
630
- });
631
- }
632
- }
633
-
634
- console.log(`[JAELIS] P2P network started on port ${this.options.p2pPort}`);
635
- }
636
-
637
- /**
638
- * Initialize RPC server
639
- */
640
- async _initRpcServer() {
641
- console.log('[JAELIS] Initializing RPC server...');
642
-
643
- if (this.JaelisRpcServer) {
644
- // Pass network reference for sync status reporting
645
- this.rpcServer = new this.JaelisRpcServer(this.blockchain, this.options.rpcPort, this.network);
646
-
647
- if (this.rpcServer.start) {
648
- await this.rpcServer.start();
649
- } else if (this.rpcServer.listen) {
650
- await this.rpcServer.listen(this.options.rpcPort, this.options.rpcHost);
651
- }
652
- }
653
-
654
- console.log(`[JAELIS] RPC server started on http://${this.options.rpcHost}:${this.options.rpcPort}`);
655
- }
656
-
657
- /**
658
- * Initialize Settlement Server for cross-chain deployments
659
- *
660
- * The Settlement Server handles propagating JAELIS contract deployments
661
- * to external chains. NO GAS - NO FEES - NO SANDBOX - NO WALLS!
662
- */
663
- async _initSettlementServer() {
664
- console.log('[JAELIS] Initializing Settlement Server...');
665
-
666
- try {
667
- // Load the settlement server module
668
- const settlementPath = path.join(__dirname, 'settlement-server.js');
669
-
670
- if (fs.existsSync(settlementPath)) {
671
- const { SettlementServer } = require(settlementPath);
672
-
673
- this.settlementServer = new SettlementServer({
674
- port: this.options.settlementPort || 3847,
675
- host: this.options.rpcHost || '0.0.0.0'
676
- });
677
-
678
- await this.settlementServer.start();
679
-
680
- console.log(`[JAELIS] Settlement Server started on port ${this.options.settlementPort || 3847}`);
681
- console.log('[JAELIS] Cross-chain deployments: ENABLED');
682
- console.log('[JAELIS] NO GAS - NO FEES - NO SANDBOX - NO WALLS!');
683
- } else {
684
- console.log('[JAELIS] Settlement Server not found, cross-chain disabled');
685
- }
686
- } catch (error) {
687
- // Don't fail node startup if settlement server fails
688
- console.error('[JAELIS] Settlement Server error:', error.message);
689
- console.log('[JAELIS] Continuing without cross-chain support...');
690
- }
691
- }
692
-
693
- /**
694
- * Stop Settlement Server
695
- */
696
- async _stopSettlementServer() {
697
- if (this.settlementServer && this.settlementServer.stop) {
698
- await this.settlementServer.stop();
699
- console.log('[JAELIS] Settlement Server stopped');
700
- }
701
- }
702
-
703
- /**
704
- * Stop RPC server
705
- */
706
- async _stopRpcServer() {
707
- if (this.rpcServer && this.rpcServer.stop) {
708
- await this.rpcServer.stop();
709
- }
710
- }
711
-
712
- /**
713
- * Stop P2P network
714
- */
715
- async _stopNetwork() {
716
- if (this.network && this.network.stop) {
717
- await this.network.stop();
718
- }
719
- }
720
-
721
- /**
722
- * Save blockchain state
723
- */
724
- async _saveState() {
725
- if (this.blockchain && this.blockchain.save) {
726
- await this.blockchain.save();
727
- }
728
- }
729
-
730
- /**
731
- * Register this node with the JAELIS network for tracking
732
- * Mario can see all nodes that connect! Lifetime tracking!
733
- */
734
- async _registerWithNetwork() {
735
- try {
736
- const https = require('https');
737
- const http = require('http');
738
-
739
- const identity = this.walletConfig.getNodeIdentity();
740
- const rewardRecipient = this.walletConfig.getRewardRecipient();
741
-
742
- const nodeInfo = {
743
- nodeId: identity.id,
744
- publicKey: identity.publicKey,
745
- network: this.options.network,
746
- chainId: this.options.chainId,
747
- version: '1.3.0',
748
- rewardAddress: rewardRecipient?.address || null,
749
- rewardChainType: rewardRecipient?.type || null,
750
- capabilities: ['full-node', 'rpc'],
751
- p2pPort: this.options.p2pPort,
752
- rpcPort: this.options.rpcPort
753
- };
754
-
755
- // Store for heartbeat
756
- this._nodeInfo = nodeInfo;
757
-
758
- const data = JSON.stringify({
759
- jsonrpc: '2.0',
760
- method: 'jaelis_node_register',
761
- params: [nodeInfo],
762
- id: 1
763
- });
764
-
765
- const url = new URL(this.options.remoteRpc);
766
- const protocol = url.protocol === 'https:' ? https : http;
767
-
768
- const options = {
769
- hostname: url.hostname,
770
- port: url.port || (url.protocol === 'https:' ? 443 : 80),
771
- path: url.pathname || '/',
772
- method: 'POST',
773
- headers: {
774
- 'Content-Type': 'application/json',
775
- 'Content-Length': Buffer.byteLength(data),
776
- 'User-Agent': 'JAELIS-Node/1.7.0' // Identifies us as a node - gets priority treatment
777
- }
778
- };
779
-
780
- await new Promise((resolve) => {
781
- const req = protocol.request(options, (res) => {
782
- let body = '';
783
- res.on('data', chunk => body += chunk);
784
- res.on('end', () => {
785
- try {
786
- const result = JSON.parse(body);
787
- if (result.result?.registered) {
788
- console.log(`[JAELIS] Node registered with network (ID: ${identity.publicKey.slice(0, 12)}...)`);
789
- }
790
- } catch (e) {
791
- // Silent - registration is best-effort
792
- }
793
- resolve();
794
- });
795
- });
796
-
797
- req.on('error', () => resolve()); // Silent fail - will retry on heartbeat
798
- req.write(data);
799
- req.end();
800
- });
801
-
802
- } catch (error) {
803
- // Registration is best-effort, don't fail node startup
804
- console.log('[JAELIS] Network registration pending (will retry)');
805
- }
806
- }
807
-
808
- /**
809
- * Start heartbeat to keep node registration alive
810
- * Sends heartbeat every 60 seconds
811
- */
812
- _startHeartbeat() {
813
- const HEARTBEAT_INTERVAL = 60000; // 60 seconds
814
-
815
- this._heartbeatInterval = setInterval(async () => {
816
- if (!this.isRunning || !this._nodeInfo) return;
817
-
818
- try {
819
- const https = require('https');
820
- const http = require('http');
821
-
822
- const data = JSON.stringify({
823
- jsonrpc: '2.0',
824
- method: 'jaelis_node_heartbeat',
825
- params: [this._nodeInfo.nodeId],
826
- id: 1
827
- });
828
-
829
- const url = new URL(this.options.remoteRpc);
830
- const protocol = url.protocol === 'https:' ? https : http;
831
-
832
- const options = {
833
- hostname: url.hostname,
834
- port: url.port || (url.protocol === 'https:' ? 443 : 80),
835
- path: url.pathname || '/',
836
- method: 'POST',
837
- headers: {
838
- 'Content-Type': 'application/json',
839
- 'Content-Length': Buffer.byteLength(data),
840
- 'User-Agent': 'JAELIS-Node/1.7.0' // Identifies us as a node - gets priority treatment
841
- }
842
- };
843
-
844
- const req = protocol.request(options, () => {});
845
- req.on('error', () => {}); // Silent
846
- req.write(data);
847
- req.end();
848
-
849
- } catch (e) {
850
- // Silent - heartbeat is best-effort
851
- }
852
- }, HEARTBEAT_INTERVAL);
853
-
854
- console.log('[JAELIS] Heartbeat started (60s interval)');
855
- }
856
-
857
- /**
858
- * Stop heartbeat
859
- */
860
- _stopHeartbeat() {
861
- if (this._heartbeatInterval) {
862
- clearInterval(this._heartbeatInterval);
863
- this._heartbeatInterval = null;
864
- }
865
- }
866
-
867
- /**
868
- * Get node status
869
- */
870
- getStatus() {
871
- return {
872
- running: this.isRunning,
873
- network: this.options.network,
874
- chainId: this.options.chainId,
875
- uptime: this.startTime ? Date.now() - this.startTime : 0,
876
- peers: this.peerCount,
877
- rpcPort: this.options.rpcPort,
878
- p2pPort: this.options.p2pPort,
879
- syncMode: this.options.syncMode,
880
- blockHeight: this.blockchain?.getHeight?.() || 0
881
- };
882
- }
883
- }
884
-
885
- /**
886
- * BootstrapNode - Lightweight node for peer discovery
887
- */
888
- class BootstrapNode extends EventEmitter {
889
- constructor(options = {}) {
890
- super();
891
- this.port = options.port || 30305;
892
- this.network = options.network || 'testnet';
893
- this.peers = new Map();
894
- this.server = null;
895
- }
896
-
897
- async start() {
898
- console.log(`[BOOTSTRAP] Starting on port ${this.port}...`);
899
-
900
- // Simple TCP server for peer discovery
901
- const net = require('net');
902
-
903
- this.server = net.createServer((socket) => {
904
- const peerId = `${socket.remoteAddress}:${socket.remotePort}`;
905
- this.peers.set(peerId, { socket, connectedAt: Date.now() });
906
-
907
- console.log(`[BOOTSTRAP] Peer connected: ${peerId} (${this.peers.size} total)`);
908
-
909
- socket.on('data', (data) => {
910
- // Handle peer discovery requests
911
- try {
912
- const msg = JSON.parse(data.toString());
913
- if (msg.type === 'getPeers') {
914
- const peerList = Array.from(this.peers.keys());
915
- socket.write(JSON.stringify({ type: 'peers', peers: peerList }));
916
- }
917
- } catch (e) {
918
- // Ignore invalid messages
919
- }
920
- });
921
-
922
- socket.on('close', () => {
923
- this.peers.delete(peerId);
924
- console.log(`[BOOTSTRAP] Peer disconnected: ${peerId} (${this.peers.size} remaining)`);
925
- });
926
-
927
- socket.on('error', () => {
928
- this.peers.delete(peerId);
929
- });
930
- });
931
-
932
- return new Promise((resolve, reject) => {
933
- this.server.listen(this.port, '0.0.0.0', () => {
934
- console.log(`[BOOTSTRAP] Listening on port ${this.port}`);
935
- resolve();
936
- });
937
-
938
- this.server.on('error', reject);
939
- });
940
- }
941
-
942
- async stop() {
943
- if (this.server) {
944
- this.server.close();
945
- }
946
- }
947
-
948
- getPeerCount() {
949
- return this.peers.size;
950
- }
951
- }
952
-
953
- // ============================================================
954
- // EMBEDDED IMPLEMENTATIONS WITH UNIFIED VM
955
- // ============================================================
956
-
957
- // Import VM Executor (UnifiedJaelisVM integration)
958
- let VMExecutor;
959
- try {
960
- VMExecutor = require('./vm').VMExecutor;
961
- } catch (e) {
962
- console.log('[JAELIS] VM module not loaded - running in light mode');
963
- }
964
-
965
- class EmbeddedBlockchain {
966
- constructor(options = {}) {
967
- this.chainId = options.chainId || 4545;
968
- this.chain = [];
969
- this.state = new Map();
970
- this.pendingTransactions = [];
971
-
972
- // Initialize VM Executor (UnifiedJaelisVM - NO BRIDGES!)
973
- this.vmExecutor = null;
974
- }
975
-
976
- async initialize() {
977
- // Create genesis block if needed
978
- if (this.chain.length === 0) {
979
- this.chain.push({
980
- number: 0,
981
- hash: '0x' + '0'.repeat(64),
982
- parentHash: '0x' + '0'.repeat(64),
983
- timestamp: Date.now(),
984
- transactions: [],
985
- stateRoot: '0x' + '0'.repeat(64)
986
- });
987
- }
988
-
989
- // Initialize the Unified VM
990
- if (VMExecutor) {
991
- this.vmExecutor = new VMExecutor(this, {
992
- debug: false
993
- });
994
- console.log('[BLOCKCHAIN] Unified VM initialized - TRUE cross-chain interop!');
995
- }
996
- }
997
-
998
- getHeight() {
999
- return this.chain.length - 1;
1000
- }
1001
-
1002
- getLatestBlock() {
1003
- return this.chain[this.chain.length - 1];
1004
- }
1005
-
1006
- getBlock(numberOrHash) {
1007
- if (typeof numberOrHash === 'number') {
1008
- return this.chain[numberOrHash];
1009
- }
1010
- return this.chain.find(b => b.hash === numberOrHash);
1011
- }
1012
-
1013
- /**
1014
- * Deploy a smart contract (ANY language!)
1015
- */
1016
- async deployContract(source, language, options = {}) {
1017
- if (!this.vmExecutor) {
1018
- throw new Error('VM not available - initialize blockchain first');
1019
- }
1020
- return this.vmExecutor.deployContract(source, language, options);
1021
- }
1022
-
1023
- /**
1024
- * Execute a contract call
1025
- */
1026
- async executeContract(to, functionName, args = [], options = {}) {
1027
- if (!this.vmExecutor) {
1028
- throw new Error('VM not available');
1029
- }
1030
- return this.vmExecutor.executeCall(to, functionName, args, options);
1031
- }
1032
-
1033
- /**
1034
- * Cross-contract call (NO BRIDGES!)
1035
- */
1036
- async crossContractCall(from, to, functionName, args = []) {
1037
- if (!this.vmExecutor) {
1038
- throw new Error('VM not available');
1039
- }
1040
- return this.vmExecutor.crossContractCall(from, to, functionName, args);
1041
- }
1042
-
1043
- /**
1044
- * Process a transaction
1045
- */
1046
- async processTransaction(tx) {
1047
- if (this.vmExecutor) {
1048
- return this.vmExecutor.processTransaction(tx);
1049
- }
1050
- // Fallback: just store in pending
1051
- this.pendingTransactions.push(tx);
1052
- return { status: 'pending' };
1053
- }
1054
-
1055
- /**
1056
- * Create a new block with pending transactions
1057
- */
1058
- async createBlock(validator) {
1059
- const crypto = require('crypto');
1060
- const parentBlock = this.getLatestBlock();
1061
-
1062
- const block = {
1063
- number: parentBlock.number + 1,
1064
- hash: null,
1065
- parentHash: parentBlock.hash,
1066
- timestamp: Date.now(),
1067
- validator: validator || '0x0',
1068
- transactions: [...this.pendingTransactions],
1069
- stateRoot: this._computeStateRoot(),
1070
- gasUsed: 0 // ZERO FEES!
1071
- };
1072
-
1073
- // Compute block hash
1074
- block.hash = '0x' + crypto.createHash('sha256')
1075
- .update(JSON.stringify({
1076
- number: block.number,
1077
- parentHash: block.parentHash,
1078
- timestamp: block.timestamp,
1079
- stateRoot: block.stateRoot
1080
- }))
1081
- .digest('hex');
1082
-
1083
- // Add to chain
1084
- this.chain.push(block);
1085
- this.pendingTransactions = [];
1086
-
1087
- console.log(`[BLOCKCHAIN] Block #${block.number} created with ${block.transactions.length} txs`);
1088
-
1089
- return block;
1090
- }
1091
-
1092
- _computeStateRoot() {
1093
- const crypto = require('crypto');
1094
- const stateData = JSON.stringify(Array.from(this.state.entries()));
1095
- return '0x' + crypto.createHash('sha256').update(stateData).digest('hex');
38
+ rpcEndpoint: 'https://mainnet.jaelis.io',
39
+ wsEndpoint: 'wss://mainnet.jaelis.io/ws',
40
+ explorerUrl: 'https://explorer.jaelis.io'
1096
41
  }
42
+ });
1097
43
 
1098
- /**
1099
- * Get VM stats
1100
- */
1101
- getVMStats() {
1102
- return this.vmExecutor?.getStats?.() || { vmAvailable: false };
1103
- }
1104
-
1105
- /**
1106
- * Get all deployed contracts
1107
- */
1108
- getContracts() {
1109
- return this.vmExecutor?.getAllContracts?.() || [];
1110
- }
1111
-
1112
- /**
1113
- * Add a block received from sync (RPC fallback or P2P)
1114
- * Validates the block before adding to chain
1115
- */
1116
- async addBlock(block) {
1117
- if (!block || block.number === undefined) {
1118
- throw new Error('Invalid block');
1119
- }
1120
-
1121
- // Normalize block number - could be hex string (0x1) or decimal
1122
- let blockNumber = block.number;
1123
- if (typeof blockNumber === 'string') {
1124
- if (blockNumber.startsWith('0x')) {
1125
- blockNumber = parseInt(blockNumber, 16);
1126
- } else {
1127
- blockNumber = parseInt(blockNumber, 10);
1128
- }
1129
- }
1130
-
1131
- const expectedNumber = this.chain.length;
1132
- if (blockNumber !== expectedNumber) {
1133
- // Skip if we already have this block or it's out of order
1134
- if (blockNumber < expectedNumber) {
1135
- return { status: 'skipped', reason: 'already_have' };
1136
- }
1137
- throw new Error(`Block out of order: expected ${expectedNumber}, got ${blockNumber}`);
1138
- }
1139
-
1140
- // Store normalized block number for consistency
1141
- block.number = blockNumber;
1142
-
1143
- // Validate parent hash (skip for first sync - genesis hash may differ)
1144
- // Like Ethereum "fast sync" - we trust the RPC source initially
1145
- const parentBlock = this.getLatestBlock();
1146
- if (blockNumber > 1 && block.parentHash && parentBlock.hash) {
1147
- // Only validate parent hash for blocks after genesis
1148
- // During initial sync, parent hashes are validated by the remote node
1149
- if (block.parentHash !== parentBlock.hash) {
1150
- // Check if this is initial sync (chain is mostly empty)
1151
- if (this.chain.length > 10) {
1152
- throw new Error('Invalid parent hash - possible chain reorg');
1153
- }
1154
- // During initial sync, log but continue
1155
- console.log(`[SYNC] Accepting block ${blockNumber} (trusting remote during initial sync)`);
1156
- }
1157
- }
1158
-
1159
- // Add block to chain
1160
- this.chain.push(block);
1161
-
1162
- // Process transactions in the block
1163
- if (block.transactions && Array.isArray(block.transactions)) {
1164
- for (const tx of block.transactions) {
1165
- // Update account states from transactions
1166
- if (tx.from && tx.to && tx.value) {
1167
- const value = BigInt(tx.value || '0');
1168
- const fromBalance = BigInt(this.state.get(tx.from)?.balance || '0');
1169
- const toBalance = BigInt(this.state.get(tx.to)?.balance || '0');
1170
-
1171
- // Debit sender, credit receiver
1172
- this.state.set(tx.from, {
1173
- ...this.state.get(tx.from),
1174
- balance: (fromBalance - value).toString(),
1175
- nonce: (parseInt(this.state.get(tx.from)?.nonce || '0') + 1).toString()
1176
- });
1177
- this.state.set(tx.to, {
1178
- ...this.state.get(tx.to),
1179
- balance: (toBalance + value).toString()
1180
- });
1181
- }
1182
- }
1183
- }
1184
-
1185
- console.log(`[BLOCKCHAIN] Synced block #${block.number} (${block.transactions?.length || 0} txs)`);
1186
-
1187
- return { status: 'added', blockNumber: block.number };
1188
- }
1189
-
1190
- /**
1191
- * Get sync status (jaelis_syncing compatible)
1192
- */
1193
- getSyncStatus(remoteHeight) {
1194
- const localHeight = this.getHeight();
1195
- const isSyncing = localHeight < remoteHeight;
1196
-
1197
- if (!isSyncing) {
1198
- return false; // Fully synced
1199
- }
1200
-
1201
- return {
1202
- startingBlock: '0x0',
1203
- currentBlock: '0x' + localHeight.toString(16),
1204
- highestBlock: '0x' + remoteHeight.toString(16),
1205
- syncedBlocks: localHeight,
1206
- remainingBlocks: remoteHeight - localHeight,
1207
- percentComplete: ((localHeight / remoteHeight) * 100).toFixed(2) + '%'
1208
- };
1209
- }
1210
-
1211
- async save() {
1212
- // Save blockchain state to disk
1213
- // TODO: Implement persistent storage
1214
- }
1215
- }
1216
-
1217
- class EmbeddedNetwork extends EventEmitter {
1218
- constructor(options = {}) {
1219
- super();
1220
- this.port = options.port || 30303;
1221
- this.host = options.host || '0.0.0.0';
1222
- this.maxPeers = options.maxPeers || 50;
1223
- this.bootstrapNodes = options.bootstrapNodes || [];
1224
- this.remoteRpc = options.remoteRpc || 'https://rpc.jaelis.io';
1225
- this.blockchain = options.blockchain;
1226
-
1227
- this.libp2p = null;
1228
- this.peers = new Map();
1229
- this.isP2PConnected = false;
1230
- this.isRPCFallback = false;
1231
- this.syncInterval = null;
1232
- }
1233
-
1234
- async start() {
1235
- // ALWAYS start RPC sync first - this is reliable through Cloudflare
1236
- // P2P is optional/additional for peer discovery
1237
- console.log(`[NETWORK] Starting RPC sync from ${this.remoteRpc}`);
1238
- await this._startRPCFallback();
1239
- this.isRPCFallback = true;
1240
-
1241
- // Try P2P alongside (optional - for peer discovery when bootstrap nodes available)
1242
- if (this.bootstrapNodes && this.bootstrapNodes.length > 0) {
1243
- try {
1244
- await this._startLibp2p();
1245
- this.isP2PConnected = true;
1246
- console.log(`[NETWORK] P2P network also started on port ${this.port}`);
1247
- } catch (err) {
1248
- console.log(`[NETWORK] P2P unavailable (${err.message}), continuing with RPC only`);
1249
- }
1250
- } else {
1251
- console.log(`[NETWORK] No bootstrap nodes configured - using RPC sync only`);
1252
- console.log(`[NETWORK] This is fine! RPC sync is reliable and works through firewalls.`);
1253
- }
1254
- }
1255
-
1256
- async _startLibp2p() {
1257
- // Dynamic imports for libp2p (ES modules)
1258
- const { createLibp2p } = await import('libp2p');
1259
- const { tcp } = await import('@libp2p/tcp');
1260
- const { noise } = await import('@chainsafe/libp2p-noise');
1261
- const { yamux } = await import('@chainsafe/libp2p-yamux');
1262
- const { identify } = await import('@libp2p/identify');
1263
-
1264
- // Create libp2p node - JAELIS user node
1265
- // Like Ethereum: start listening, bootstrap nodes come later via DHT
1266
- const config = {
1267
- addresses: {
1268
- listen: [`/ip4/${this.host}/tcp/${this.port}`]
1269
- },
1270
- transports: [tcp()],
1271
- connectionEncryption: [noise()],
1272
- streamMuxers: [yamux()],
1273
- services: {
1274
- identify: identify()
1275
- }
1276
- };
1277
-
1278
- this.libp2p = await createLibp2p(config);
1279
- await this.libp2p.start();
1280
-
1281
- console.log(`[P2P] Node started with ID: ${this.libp2p.peerId.toString().slice(0, 16)}...`);
1282
-
1283
- // Track peers
1284
- this.libp2p.addEventListener('peer:connect', (evt) => {
1285
- const peerId = evt.detail.toString();
1286
- this.peers.set(peerId, { connectedAt: Date.now() });
1287
- console.log(`[P2P] Peer connected: ${peerId.slice(0, 16)}... (${this.peers.size} total)`);
1288
- });
1289
-
1290
- this.libp2p.addEventListener('peer:disconnect', (evt) => {
1291
- const peerId = evt.detail.toString();
1292
- this.peers.delete(peerId);
1293
- console.log(`[P2P] Peer disconnected (${this.peers.size} remaining)`);
1294
- });
1295
-
1296
- // Try to dial bootstrap nodes directly (without peer ID)
1297
- // Like Ethereum: we connect via TCP, then learn peer ID during handshake
1298
- for (const addr of this.bootstrapNodes) {
1299
- try {
1300
- const { multiaddr } = await import('@multiformats/multiaddr');
1301
- const ma = multiaddr(addr);
1302
- await this.libp2p.dial(ma);
1303
- console.log(`[P2P] Connected to bootstrap: ${addr}`);
1304
- } catch (err) {
1305
- // Bootstrap unavailable - this is OK, we'll use RPC fallback
1306
- console.log(`[P2P] Bootstrap ${addr.slice(0, 30)}... unavailable`);
1307
- }
1308
- }
1309
- }
1310
-
1311
- async _startRPCFallback() {
1312
- // Track sync state
1313
- this.syncState = {
1314
- localHeight: 0,
1315
- remoteHeight: 0,
1316
- syncing: false,
1317
- lastSync: null,
1318
- blocksDownloaded: 0,
1319
- mode: 'polling' // 'websocket' or 'polling'
1320
- };
1321
-
1322
- // Helper to make RPC calls to remote node
1323
- const rpcCall = async (method, params = []) => {
1324
- return new Promise((resolve, reject) => {
1325
- const https = require('https');
1326
- const http = require('http');
1327
- const url = new URL(this.remoteRpc);
1328
- const protocol = url.protocol === 'https:' ? https : http;
1329
-
1330
- const data = JSON.stringify({
1331
- jsonrpc: '2.0',
1332
- method,
1333
- params,
1334
- id: Date.now()
1335
- });
1336
-
1337
- const req = protocol.request({
1338
- hostname: url.hostname,
1339
- port: url.port || (url.protocol === 'https:' ? 443 : 80),
1340
- path: url.pathname || '/',
1341
- method: 'POST',
1342
- headers: {
1343
- 'Content-Type': 'application/json',
1344
- 'Content-Length': Buffer.byteLength(data),
1345
- 'User-Agent': 'JAELIS-Node/1.8.0' // Node sync traffic
1346
- }
1347
- }, (res) => {
1348
- let body = '';
1349
- res.on('data', chunk => body += chunk);
1350
- res.on('end', () => {
1351
- try {
1352
- const json = JSON.parse(body);
1353
- if (json.error) reject(new Error(json.error.message));
1354
- else resolve(json.result);
1355
- } catch (e) { reject(e); }
1356
- });
1357
- });
1358
-
1359
- req.on('error', reject);
1360
- req.write(data);
1361
- req.end();
1362
- });
1363
- };
1364
-
1365
- // Fetch and add a specific block
1366
- const fetchBlock = async (blockNum) => {
1367
- const blockHex = '0x' + blockNum.toString(16);
1368
- const block = await rpcCall('jaelis_getBlockByNumber', [blockHex, true]);
1369
- if (block && this.blockchain?.addBlock) {
1370
- await this.blockchain.addBlock(block);
1371
- this.syncState.blocksDownloaded++;
1372
- return true;
1373
- }
1374
- return false;
1375
- };
1376
-
1377
- // Sync missing blocks (used for both initial sync and catching up)
1378
- const syncMissingBlocks = async () => {
1379
- if (this.syncState.syncing) return;
1380
- this.syncState.syncing = true;
1381
-
1382
- try {
1383
- const remoteHeightHex = await rpcCall('jaelis_blockNumber');
1384
- this.syncState.remoteHeight = parseInt(remoteHeightHex, 16);
1385
- this.syncState.localHeight = this.blockchain?.getHeight?.() || 0;
1386
-
1387
- // Loop until fully synced
1388
- while (this.syncState.localHeight < this.syncState.remoteHeight) {
1389
- const blocksToSync = this.syncState.remoteHeight - this.syncState.localHeight;
1390
-
1391
- // Batch size: larger during initial sync, smaller when near tip
1392
- const batchSize = blocksToSync > 50 ? 25 : (blocksToSync > 10 ? 10 : blocksToSync);
1393
-
1394
- if (blocksToSync > 1) {
1395
- console.log(`[SYNC] Syncing ${batchSize} blocks (${this.syncState.localHeight + 1} → ${this.syncState.localHeight + batchSize})`);
1396
- }
1397
-
1398
- for (let i = 1; i <= batchSize; i++) {
1399
- await fetchBlock(this.syncState.localHeight + i);
1400
- }
1401
-
1402
- this.syncState.localHeight += batchSize;
1403
-
1404
- if (batchSize > 1) {
1405
- console.log(`[SYNC] Local height: ${this.syncState.localHeight}/${this.syncState.remoteHeight}`);
1406
- }
1407
-
1408
- // Re-check remote height in case new blocks arrived during sync
1409
- const newRemoteHex = await rpcCall('jaelis_blockNumber');
1410
- this.syncState.remoteHeight = parseInt(newRemoteHex, 16);
1411
- }
1412
-
1413
- this.syncState.lastSync = Date.now();
1414
- this.emit('sync', this.syncState);
1415
-
1416
- } catch (err) {
1417
- console.error('[SYNC] Error:', err.message);
1418
- } finally {
1419
- this.syncState.syncing = false;
1420
- }
1421
- };
1422
-
1423
- // ============================================================
1424
- // WEBSOCKET SUBSCRIPTION (PREFERRED - like Ethereum newHeads)
1425
- // ============================================================
1426
- const tryWebSocketSync = async () => {
1427
- try {
1428
- const WebSocket = require('ws');
1429
- const wsUrl = this.remoteRpc.replace('https://', 'wss://').replace('http://', 'ws://') + '/ws';
1430
-
1431
- console.log(`[SYNC] Trying WebSocket subscription at ${wsUrl}`);
1432
-
1433
- return new Promise((resolve, reject) => {
1434
- const ws = new WebSocket(wsUrl, {
1435
- headers: { 'User-Agent': 'JAELIS-Node/1.8.0' }
1436
- });
1437
-
1438
- const timeout = setTimeout(() => {
1439
- ws.close();
1440
- reject(new Error('WebSocket connection timeout'));
1441
- }, 10000);
1442
-
1443
- ws.on('open', () => {
1444
- clearTimeout(timeout);
1445
- console.log('[SYNC] WebSocket connected! Subscribing to newHeads...');
1446
-
1447
- // Subscribe to new block headers
1448
- ws.send(JSON.stringify({
1449
- jsonrpc: '2.0',
1450
- method: 'jaelis_subscribe',
1451
- params: ['newHeads'],
1452
- id: 1
1453
- }));
1454
-
1455
- this.syncState.mode = 'websocket';
1456
- this.wsConnection = ws;
1457
- resolve(true);
1458
- });
1459
-
1460
- ws.on('message', async (data) => {
1461
- try {
1462
- const msg = JSON.parse(data.toString());
1463
-
1464
- // Subscription confirmation
1465
- if (msg.id === 1 && msg.result) {
1466
- console.log(`[SYNC] ✓ Subscribed to newHeads (id: ${msg.result})`);
1467
- console.log('[SYNC] Listening for new blocks via WebSocket...');
1468
- return;
1469
- }
1470
-
1471
- // New block notification
1472
- if (msg.method === 'jaelis_subscription' && msg.params?.result) {
1473
- const header = msg.params.result;
1474
- const blockNum = typeof header.number === 'string'
1475
- ? parseInt(header.number, 16)
1476
- : header.number;
1477
-
1478
- // Fetch and sync the new block
1479
- if (blockNum > this.syncState.localHeight) {
1480
- // If we're behind, catch up first
1481
- await syncMissingBlocks();
1482
- }
1483
-
1484
- this.syncState.remoteHeight = blockNum;
1485
- this.emit('newBlock', header);
1486
- }
1487
- } catch (e) {
1488
- // Ignore parse errors
1489
- }
1490
- });
1491
-
1492
- ws.on('error', (err) => {
1493
- clearTimeout(timeout);
1494
- reject(err);
1495
- });
1496
-
1497
- ws.on('close', () => {
1498
- console.log('[SYNC] WebSocket disconnected, falling back to polling...');
1499
- this.syncState.mode = 'polling';
1500
- this.wsConnection = null;
1501
- // Fall back to polling
1502
- startPolling();
1503
- });
1504
- });
1505
- } catch (err) {
1506
- // WebSocket module not available or connection failed
1507
- return false;
1508
- }
1509
- };
1510
-
1511
- // ============================================================
1512
- // HTTP POLLING FALLBACK (like traditional Geth sync)
1513
- // ============================================================
1514
- const SYNCED_INTERVAL = 6000; // Poll every 6s when synced (2x block time)
1515
- const CATCHUP_INTERVAL = 500; // Fast poll during catchup
1516
-
1517
- const startPolling = () => {
1518
- if (this.syncInterval) return; // Already polling
1519
-
1520
- console.log('[SYNC] Using HTTP polling mode');
1521
- this.syncState.mode = 'polling';
1522
-
1523
- let pollInterval = CATCHUP_INTERVAL;
1524
- let lastHeight = 0;
1525
-
1526
- const poll = async () => {
1527
- await syncMissingBlocks();
1528
-
1529
- // Adjust polling speed based on sync status
1530
- const isSynced = this.syncState.localHeight >= this.syncState.remoteHeight;
1531
- const heightChanged = this.syncState.remoteHeight !== lastHeight;
1532
-
1533
- if (isSynced && !heightChanged && pollInterval !== SYNCED_INTERVAL) {
1534
- // Synced and no new blocks - slow down
1535
- pollInterval = SYNCED_INTERVAL;
1536
- clearInterval(this.syncInterval);
1537
- this.syncInterval = setInterval(poll, pollInterval);
1538
- console.log(`[SYNC] ✓ Synced at block ${this.syncState.localHeight}. Polling every ${pollInterval/1000}s`);
1539
- } else if (!isSynced && pollInterval !== CATCHUP_INTERVAL) {
1540
- // Falling behind - speed up
1541
- pollInterval = CATCHUP_INTERVAL;
1542
- clearInterval(this.syncInterval);
1543
- this.syncInterval = setInterval(poll, pollInterval);
1544
- }
1545
-
1546
- lastHeight = this.syncState.remoteHeight;
1547
- };
1548
-
1549
- // Start polling
1550
- this.syncInterval = setInterval(poll, pollInterval);
1551
- };
1552
-
1553
- // ============================================================
1554
- // INITIAL SYNC
1555
- // ============================================================
1556
- console.log('[SYNC] Starting sync from', this.remoteRpc);
1557
-
1558
- // Do initial block sync first
1559
- await syncMissingBlocks();
1560
-
1561
- // Try WebSocket first (like Ethereum pub/sub), fall back to polling
1562
- const wsSuccess = await tryWebSocketSync().catch(() => false);
1563
-
1564
- if (!wsSuccess) {
1565
- console.log('[SYNC] WebSocket unavailable, using HTTP polling');
1566
- startPolling();
1567
- }
1568
- }
1569
-
1570
- async stop() {
1571
- // Close WebSocket connection if active
1572
- if (this.wsConnection) {
1573
- this.wsConnection.close();
1574
- this.wsConnection = null;
1575
- }
1576
- // Stop libp2p if active
1577
- if (this.libp2p) {
1578
- await this.libp2p.stop();
1579
- }
1580
- // Stop polling interval if active
1581
- if (this.syncInterval) {
1582
- clearInterval(this.syncInterval);
1583
- this.syncInterval = null;
1584
- }
1585
- }
1586
-
1587
- getPeerCount() {
1588
- return this.peers.size;
1589
- }
1590
-
1591
- getConnectionMode() {
1592
- if (this.isP2PConnected) return 'p2p';
1593
- if (this.isRPCFallback) return 'rpc-fallback';
1594
- return 'disconnected';
1595
- }
1596
- }
1597
-
1598
- class EmbeddedRpcServer {
1599
- constructor(blockchain, port, network = null) {
1600
- this.blockchain = blockchain;
1601
- this.port = port;
1602
- this.network = network; // Reference to EmbeddedNetwork for sync status
1603
- this.app = null;
1604
- }
1605
-
1606
- async start() {
1607
- const express = require('express');
1608
- const cors = require('cors');
1609
-
1610
- this.app = express();
1611
- this.app.use(cors());
1612
- this.app.use(express.json({ limit: '50mb' })); // Allow large contract deployments
1613
-
1614
- // Main RPC endpoint
1615
- this.app.post('/', async (req, res) => {
1616
- const { method, params, id } = req.body;
1617
-
1618
- try {
1619
- const result = await this._handleMethod(method, params || []);
1620
- res.json({ jsonrpc: '2.0', id, result });
1621
- } catch (error) {
1622
- res.json({
1623
- jsonrpc: '2.0',
1624
- id,
1625
- error: { code: -32000, message: error.message }
1626
- });
1627
- }
1628
- });
1629
-
1630
- // Health check
1631
- this.app.get('/', (req, res) => {
1632
- const vmStats = this.blockchain?.getVMStats?.() || {};
1633
- res.json({
1634
- status: 'online',
1635
- service: 'JAELIS Node',
1636
- chainId: this.blockchain?.chainId,
1637
- blockHeight: this.blockchain?.getHeight?.() || 0,
1638
- vm: {
1639
- available: vmStats.vmAvailable || false,
1640
- contractsDeployed: vmStats.contractsDeployed || 0,
1641
- crossContractCalls: vmStats.crossContractCalls || 0
1642
- },
1643
- features: [
1644
- 'ZERO_FEES',
1645
- 'UNIFIED_VM',
1646
- 'NO_BRIDGES',
1647
- 'CROSS_CHAIN_INTEROP'
1648
- ]
1649
- });
1650
- });
1651
-
1652
- return new Promise((resolve) => {
1653
- this.server = this.app.listen(this.port, '0.0.0.0', () => {
1654
- resolve();
1655
- });
1656
- });
1657
- }
1658
-
1659
- async _handleMethod(method, params) {
1660
- switch (method) {
1661
- // ═══════════════════════════════════════════════════════════════
1662
- // LAYER 1: NATIVE JAELIS METHODS (PRIMARY)
1663
- // ═══════════════════════════════════════════════════════════════
1664
- case 'jaelis_chainId':
1665
- return '0x' + (this.blockchain?.chainId || 4545).toString(16);
1666
-
1667
- case 'jaelis_blockNumber':
1668
- return '0x' + (this.blockchain?.getHeight?.() || 0).toString(16);
1669
-
1670
- case 'jaelis_syncing':
1671
- // Return sync status - false if fully synced, object if syncing
1672
- if (this.network?.syncState) {
1673
- return this.blockchain?.getSyncStatus?.(this.network.syncState.remoteHeight) || false;
1674
- }
1675
- return false;
1676
-
1677
- case 'jaelis_getBlockByNumber':
1678
- // Native JAELIS method - returns JAELIS-native block fields
1679
- const jaelisBlockNum = typeof params[0] === 'string' && params[0].startsWith('0x')
1680
- ? parseInt(params[0], 16)
1681
- : params[0];
1682
- const jaelisBlock = this.blockchain?.getBlock?.(jaelisBlockNum);
1683
- if (jaelisBlock) {
1684
- // Add JAELIS-specific fields
1685
- return {
1686
- ...jaelisBlock,
1687
- lodeUsed: '0x0', // ZERO FEES
1688
- consensus: 'PoEC', // Proof of Entropy Contribution
1689
- jaelisVersion: '1.0.0'
1690
- };
1691
- }
1692
- return null;
1693
-
1694
- case 'jaelis_getBlockByHash':
1695
- // Find block by hash
1696
- const targetHash = params[0];
1697
- const foundBlock = this.blockchain?.chain?.find(b => b.hash === targetHash);
1698
- return foundBlock || null;
1699
-
1700
- // ═══════════════════════════════════════════════════════════════
1701
- // LAYER 2: ETHEREUM COMPATIBILITY (PROXIES → jaelis_*)
1702
- // ═══════════════════════════════════════════════════════════════
1703
- case 'eth_chainId':
1704
- return this._handleMethod('jaelis_chainId', params);
1705
-
1706
- case 'eth_blockNumber':
1707
- return this._handleMethod('jaelis_blockNumber', params);
1708
-
1709
- case 'eth_getBlockByNumber':
1710
- const blockNum = parseInt(params[0], 16);
1711
- return this.blockchain?.getBlock?.(blockNum) || null;
1712
-
1713
- case 'eth_sendTransaction':
1714
- case 'eth_sendRawTransaction':
1715
- return this._sendTransaction(params[0]);
1716
-
1717
- case 'eth_call':
1718
- return this._call(params[0], params[1]);
1719
-
1720
- case 'eth_getTransactionReceipt':
1721
- return this.blockchain?.vmExecutor?.getReceipt?.(params[0]) || null;
1722
-
1723
- case 'eth_getCode':
1724
- // CRITICAL: This is how block explorers detect contracts!
1725
- // Returns bytecode at address, or '0x' for EOAs
1726
- return this._getCode(params[0], params[1] || 'latest');
1727
-
1728
- case 'eth_getBalance':
1729
- return this._getBalance(params[0], params[1] || 'latest');
1730
-
1731
- case 'eth_getTransactionCount':
1732
- return this._getTransactionCount(params[0], params[1] || 'latest');
1733
-
1734
- case 'eth_getStorageAt':
1735
- return this._getStorageAt(params[0], params[1], params[2] || 'latest');
1736
-
1737
- case 'eth_estimateGas':
1738
- // JAELIS has ZERO GAS - always return minimal
1739
- return '0x5208'; // 21000 in hex
1740
-
1741
- case 'eth_gasPrice':
1742
- // JAELIS has ZERO GAS
1743
- return '0x0';
1744
-
1745
- // ═══════════════════════════════════════════════════════════════
1746
- // JAELIS-SPECIFIC METHODS (Unified VM)
1747
- // ═══════════════════════════════════════════════════════════════
1748
- case 'jaelis_getCode':
1749
- // Native JAELIS method - returns contract bytecode
1750
- return this._getCode(params[0], params[1] || 'latest');
1751
-
1752
- case 'jaelis_getHealth':
1753
- return {
1754
- status: 'healthy',
1755
- chainId: this.blockchain?.chainId,
1756
- blockHeight: this.blockchain?.getHeight?.() || 0,
1757
- vmActive: !!this.blockchain?.vmExecutor
1758
- };
1759
-
1760
- case 'jaelis_deploy':
1761
- case 'jaelis_deployContract':
1762
- // Deploy contract in ANY language!
1763
- // params: [source, language, options]
1764
- return this._deployContract(params[0], params[1], params[2] || {});
1765
-
1766
- case 'jaelis_deployUnified':
1767
- // THE KEY INNOVATION: Deploy unified contract bundle!
1768
- // Compile MULTIPLE contracts from MULTIPLE languages into ONE bytecode!
1769
- // params: [{ from, sources: [{ code, language, name }...] }]
1770
- return this._deployUnified(params[0]);
1771
-
1772
- case 'jaelis_executeContract':
1773
- // Execute contract call
1774
- // params: [to, functionName, args, options]
1775
- return this._executeContract(params[0], params[1], params[2] || [], params[3] || {});
1776
-
1777
- case 'jaelis_crossContractCall':
1778
- // Cross-contract call (NO BRIDGES!)
1779
- // params: [fromContract, toContract, functionName, args]
1780
- return this._crossContractCall(params[0], params[1], params[2], params[3] || []);
1781
-
1782
- case 'jaelis_getContracts':
1783
- return this.blockchain?.getContracts?.() || [];
1784
-
1785
- case 'jaelis_getVMStats':
1786
- return this.blockchain?.getVMStats?.() || { vmAvailable: false };
1787
-
1788
- case 'jaelis_getSupportedLanguages':
1789
- return ['solidity', 'rust', 'move', 'func', 'cairo', 'vyper'];
1790
-
1791
- // ═══════════════════════════════════════════════════════════════
1792
- // CROSS-CHAIN DEPLOYMENT METHODS (NEW!)
1793
- // Query contract deployments across chains
1794
- // ═══════════════════════════════════════════════════════════════
1795
-
1796
- case 'jaelis_crossChain_getDeployment':
1797
- // Get deployment info for an address
1798
- // params: [address]
1799
- return this._getCrossChainDeployment(params[0]);
1800
-
1801
- case 'jaelis_crossChain_getChainDeployments':
1802
- // Get all deployments to a specific chain
1803
- // params: [chainId]
1804
- return this._getChainDeployments(params[0]);
1805
-
1806
- case 'jaelis_crossChain_getExplorerUrl':
1807
- // Get explorer URL for a deployment
1808
- // params: [chainId, address]
1809
- return this._getExplorerUrl(params[0], params[1]);
1810
-
1811
- case 'jaelis_crossChain_getDeploymentStats':
1812
- // Get deployment statistics
1813
- return this._getDeploymentStats();
1814
-
1815
- // ═══════════════════════════════════════════════════════════════
1816
- // MULTI-CHAIN SIGNATURE METHODS (Per-chain wallet authorization)
1817
- // ═══════════════════════════════════════════════════════════════
1818
-
1819
- case 'jaelis_crossChain_getSigningRequests':
1820
- // Get signing messages for each target chain
1821
- // params: [bytecode, targetChains[]]
1822
- // Returns array of { chainId, message, switchParams } for frontend
1823
- return this._getMultiChainSigningRequests(params[0], params[1]);
1824
-
1825
- case 'jaelis_crossChain_deployWithSignatures':
1826
- // Deploy with per-chain wallet signatures
1827
- // params: [{ from, bytecode, abi, targetChains, chainSignatures: {chainId: sig} }]
1828
- return this._deployWithMultiChainSignatures(params[0]);
1829
-
1830
- // ═══════════════════════════════════════════════════════════════
1831
- // CROSS-CHAIN SETTLEMENT METHODS (Universal State Layer!)
1832
- // ═══════════════════════════════════════════════════════════════
1833
-
1834
- case 'jaelis_crossChain_getChains':
1835
- // Get all registered chains
1836
- return this._getCrossChainRegistry();
1837
-
1838
- case 'jaelis_crossChain_getChainInfo':
1839
- // Get info for specific chain ID
1840
- return this._getCrossChainInfo(params[0]);
1841
-
1842
- case 'jaelis_crossChain_readState':
1843
- // Read settled state from external chain
1844
- // params: [chainId, contractAddress, variableName]
1845
- return this._readCrossChainState(params[0], params[1], params[2]);
1846
-
1847
- case 'jaelis_crossChain_settleState':
1848
- // Settle external chain state with proof
1849
- // params: [chainId, contractAddress, variableName, value, proof]
1850
- return this._settleCrossChainState(params[0], params[1], params[2], params[3], params[4]);
1851
-
1852
- case 'jaelis_crossChain_getStateDiff':
1853
- // Get state diff between two chains
1854
- // params: [chainId1, chainId2, contractAddress, variableNames]
1855
- return this._getCrossChainStateDiff(params[0], params[1], params[2], params[3]);
1856
-
1857
- case 'jaelis_crossChain_computeSlot':
1858
- // Compute namespaced storage slot
1859
- // params: [chainId, contractAddress, variableName]
1860
- return this._computeCrossChainSlot(params[0], params[1], params[2]);
1861
-
1862
- case 'jaelis_crossChain_getLightClientStatus':
1863
- // Get light client status for a chain
1864
- return this._getLightClientStatus(params[0]);
1865
-
1866
- case 'jaelis_crossChain_getSettlements':
1867
- // Get all settlements for a contract
1868
- // params: [chainId, contractAddress]
1869
- return this._getSettlements(params[0], params[1]);
1870
-
1871
- case 'jaelis_crossChain_getStats':
1872
- // Get cross-chain stats
1873
- return this._getCrossChainStats();
1874
-
1875
- // ═══════════════════════════════════════════════════════════════
1876
- // MCP SHORTHAND ALIASES (crosschain_* → jaelis_crossChain_*)
1877
- // Unified RPC - same methods, shorter names for AI agents
1878
- // ═══════════════════════════════════════════════════════════════
1879
- case 'crosschain_getChains':
1880
- return this._handleMethod('jaelis_crossChain_getChains', params);
1881
- case 'crosschain_getChainInfo':
1882
- return this._handleMethod('jaelis_crossChain_getChainInfo', params);
1883
- case 'crosschain_readState':
1884
- return this._handleMethod('jaelis_crossChain_readState', params);
1885
- case 'crosschain_settleState':
1886
- return this._handleMethod('jaelis_crossChain_settleState', params);
1887
- case 'crosschain_getStateDiff':
1888
- return this._handleMethod('jaelis_crossChain_getStateDiff', params);
1889
- case 'crosschain_computeSlot':
1890
- return this._handleMethod('jaelis_crossChain_computeSlot', params);
1891
- case 'crosschain_getLightClientStatus':
1892
- return this._handleMethod('jaelis_crossChain_getLightClientStatus', params);
1893
- case 'crosschain_getSettlements':
1894
- return this._handleMethod('jaelis_crossChain_getSettlements', params);
1895
- case 'crosschain_getStats':
1896
- return this._handleMethod('jaelis_crossChain_getStats', params);
1897
- case 'crosschain_getDeployment':
1898
- return this._handleMethod('jaelis_crossChain_getDeployment', params);
1899
- case 'crosschain_getExplorerUrl':
1900
- return this._handleMethod('jaelis_crossChain_getExplorerUrl', params);
1901
- case 'crosschain_getDeploymentStats':
1902
- return this._handleMethod('jaelis_crossChain_getDeploymentStats', params);
1903
- case 'crosschain_getSigningRequests':
1904
- return this._handleMethod('jaelis_crossChain_getSigningRequests', params);
1905
- case 'crosschain_deployWithSignatures':
1906
- return this._handleMethod('jaelis_crossChain_deployWithSignatures', params);
1907
- case 'crosschain_deployUnified':
1908
- return this._handleMethod('jaelis_deployUnified', params);
1909
- case 'crosschain_syncState':
1910
- return this._handleMethod('jaelis_crossChain_settleState', params);
1911
-
1912
- // ═══════════════════════════════════════════════════════════════
1913
- // LAYER 2: SOLANA COMPATIBILITY (PROXIES → jaelis_*)
1914
- // For Rust/SPL developers familiar with Solana RPC
1915
- // ═══════════════════════════════════════════════════════════════
1916
- case 'solana_getBalance':
1917
- // Convert to JAELIS format then back to Solana format
1918
- const jaelisBalance = await this._handleMethod('jaelis_getBalance', params);
1919
- return { value: BigInt(jaelisBalance || '0').toString() };
1920
-
1921
- case 'solana_getHealth':
1922
- return this._handleMethod('jaelis_getHealth', params);
1923
-
1924
- case 'solana_getSlot':
1925
- return this.blockchain?.getHeight?.() || 0;
1926
-
1927
- case 'solana_getBlockHeight':
1928
- return this.blockchain?.getHeight?.() || 0;
1929
-
1930
- case 'solana_getVersion':
1931
- return { 'solana-core': '1.17.0', 'feature-set': 4545 };
1932
-
1933
- case 'solana_getLatestBlockhash':
1934
- const block = this.blockchain?.getLatestBlock?.();
1935
- return { blockhash: block?.hash || '0x0', lastValidBlockHeight: block?.number || 0 };
1936
-
1937
- // ═══════════════════════════════════════════════════════════════
1938
- // LAYER 2: MOVE COMPATIBILITY (PROXIES → jaelis_*)
1939
- // For Aptos/Sui developers familiar with Move
1940
- // ═══════════════════════════════════════════════════════════════
1941
- case 'move_getLedgerInfo':
1942
- const height = this.blockchain?.getHeight?.() || 0;
1943
- return {
1944
- chain_id: this.blockchain?.chainId || 4545,
1945
- ledger_version: height.toString(),
1946
- block_height: height.toString()
1947
- };
1948
-
1949
- case 'move_getAccountResource':
1950
- return this._handleMethod('jaelis_getMoveResource', params);
1951
-
1952
- case 'move_getAccountModule':
1953
- return this._handleMethod('jaelis_getMoveModule', params);
1954
-
1955
- // ═══════════════════════════════════════════════════════════════
1956
- // LAYER 2: TON COMPATIBILITY (PROXIES → jaelis_*)
1957
- // For FunC/Telegram developers (900M+ users!)
1958
- // ═══════════════════════════════════════════════════════════════
1959
- case 'ton_getAddressBalance':
1960
- const tonBalance = await this._handleMethod('jaelis_getBalance', params);
1961
- return { balance: tonBalance || '0' };
1962
-
1963
- case 'ton_getMasterchainInfo':
1964
- const tonBlock = this.blockchain?.getLatestBlock?.();
1965
- return {
1966
- last: {
1967
- workchain: 0,
1968
- seqno: tonBlock?.number || 0,
1969
- root_hash: tonBlock?.hash || '0x0'
1970
- }
1971
- };
1972
-
1973
- case 'ton_getAccountState':
1974
- return this._handleMethod('jaelis_getTonAccount', params);
1975
-
1976
- case 'ton_runGetMethod':
1977
- return this._handleMethod('jaelis_callTonMethod', params);
1978
-
1979
- // ═══════════════════════════════════════════════════════════════
1980
- // LAYER 2: BITCOIN COMPATIBILITY (PROXIES → jaelis_*)
1981
- // For Bitcoin developers - familiar Bitcoin Core RPC methods
1982
- // ═══════════════════════════════════════════════════════════════
1983
- case 'btc_getbalance':
1984
- const btcBal = await this._handleMethod('jaelis_getBalance', params);
1985
- const satoshis = BigInt(btcBal?.jaelis || '0') / BigInt(10 ** 10);
1986
- return Number(satoshis) / 100000000;
1987
-
1988
- case 'btc_getblockcount':
1989
- return this.blockchain?.getHeight?.() || 0;
1990
-
1991
- case 'btc_getblockhash':
1992
- const btcBlock = this.blockchain?.getBlock?.(params[0]);
1993
- return btcBlock?.hash || null;
1994
-
1995
- case 'btc_getblock':
1996
- const blk = this.blockchain?.getBlockByHash?.(params[0]);
1997
- if (!blk) return null;
1998
- return {
1999
- hash: blk.hash,
2000
- confirmations: 1,
2001
- height: blk.number,
2002
- version: 1,
2003
- time: blk.timestamp,
2004
- tx: blk.transactions?.map(t => t.hash || t) || [],
2005
- previousblockhash: blk.parentHash
2006
- };
2007
-
2008
- case 'btc_gettransaction':
2009
- return this._handleMethod('jaelis_getTransactionByHash', params);
2010
-
2011
- case 'btc_sendrawtransaction':
2012
- return this._handleMethod('jaelis_sendRawTransaction', params);
2013
-
2014
- case 'btc_getblockchaininfo':
2015
- const btcHeight = this.blockchain?.getHeight?.() || 0;
2016
- return {
2017
- chain: (this.blockchain?.chainId || 4545) === 4545 ? 'test' : 'main',
2018
- blocks: btcHeight,
2019
- headers: btcHeight,
2020
- bestblockhash: this.blockchain?.getLatestBlock?.()?.hash,
2021
- difficulty: 1,
2022
- warnings: 'JAELIS Bitcoin compatibility - zero gas fees!'
2023
- };
2024
-
2025
- case 'btc_getnetworkinfo':
2026
- return {
2027
- version: 250000,
2028
- subversion: '/JAELIS:1.0.0/',
2029
- protocolversion: 70016,
2030
- warnings: 'JAELIS Bitcoin compatibility layer'
2031
- };
2032
-
2033
- case 'btc_getmempoolinfo':
2034
- return { loaded: true, size: 0, mempoolminfee: 0 };
2035
-
2036
- case 'btc_estimatesmartfee':
2037
- return { feerate: 0, blocks: params[0] || 1 }; // Zero fees!
2038
-
2039
- // ═══════════════════════════════════════════════════════════════
2040
- // LAYER 2: WASM COMPATIBILITY (PROXIES → jaelis_*)
2041
- // For CosmWasm/NEAR/Polkadot WASM developers
2042
- // ═══════════════════════════════════════════════════════════════
2043
- case 'wasm_call':
2044
- return this._handleMethod('jaelis_call', [{ to: params[0], data: JSON.stringify({ method: params[1], args: params[2] }) }]);
2045
-
2046
- case 'wasm_query':
2047
- return this._handleMethod('jaelis_call', [{ to: params[0], data: JSON.stringify(params[1]) }]);
2048
-
2049
- case 'wasm_deploy':
2050
- return this._handleMethod('jaelis_deployWasmContract', params);
2051
-
2052
- case 'wasm_instantiate':
2053
- return this._handleMethod('jaelis_deployWasmContract', [{ codeId: params[0], initMsg: params[1], label: params[2] }]);
2054
-
2055
- case 'wasm_execute':
2056
- return this._handleMethod('jaelis_sendTransaction', [{ to: params[0], data: JSON.stringify(params[1]), value: params[2] || '0x0' }]);
2057
-
2058
- case 'wasm_getCode':
2059
- return this._handleMethod('jaelis_getCode', params);
2060
-
2061
- case 'wasm_getContractInfo':
2062
- const wasmCode = await this._handleMethod('jaelis_getCode', params);
2063
- return { address: params[0], has_code: wasmCode && wasmCode !== '0x' };
2064
-
2065
- case 'wasm_getContractState':
2066
- return this._handleMethod('jaelis_getStorageAt', [params[0], params[1] || '0x0', 'latest']);
2067
-
2068
- // ═══════════════════════════════════════════════════════════════
2069
- // LAYER 2: STARKNET/CAIRO COMPATIBILITY (PROXIES → jaelis_*)
2070
- // For StarkNet/Cairo developers
2071
- // ═══════════════════════════════════════════════════════════════
2072
- case 'starknet_chainId':
2073
- return this._handleMethod('jaelis_chainId', params);
2074
-
2075
- case 'starknet_blockNumber':
2076
- return this.blockchain?.getHeight?.() || 0;
2077
-
2078
- case 'starknet_getBlockWithTxHashes':
2079
- const snBlock = this.blockchain?.getBlock?.(params[0]?.block_number || 'latest');
2080
- if (!snBlock) return null;
2081
- return {
2082
- block_hash: snBlock.hash,
2083
- parent_hash: snBlock.parentHash,
2084
- block_number: snBlock.number,
2085
- transactions: snBlock.transactions || [],
2086
- status: 'ACCEPTED_ON_L1'
2087
- };
2088
-
2089
- case 'starknet_getBlockWithTxs':
2090
- return this._handleMethod('starknet_getBlockWithTxHashes', params);
2091
-
2092
- case 'starknet_getTransactionByHash':
2093
- const snTx = await this._handleMethod('jaelis_getTransactionByHash', params);
2094
- if (!snTx) return null;
2095
- return { transaction_hash: snTx.hash, type: 'INVOKE', sender_address: snTx.from };
2096
-
2097
- case 'starknet_getTransactionReceipt':
2098
- const snReceipt = await this._handleMethod('jaelis_getTransactionReceipt', params);
2099
- if (!snReceipt) return null;
2100
- return {
2101
- transaction_hash: snReceipt.transactionHash,
2102
- actual_fee: '0x0',
2103
- status: snReceipt.status === '0x1' ? 'ACCEPTED_ON_L1' : 'REJECTED'
2104
- };
2105
-
2106
- case 'starknet_call':
2107
- return this._handleMethod('jaelis_call', [{ to: params[0]?.contract_address, data: '0x' }]);
2108
-
2109
- case 'starknet_estimateFee':
2110
- return { gas_consumed: '0x0', gas_price: '0x0', overall_fee: '0x0' }; // Zero fees!
2111
-
2112
- case 'starknet_addInvokeTransaction':
2113
- return this._handleMethod('jaelis_sendTransaction', [{ from: params[0]?.sender_address, to: params[0]?.calldata?.[0], data: '0x' }]);
2114
-
2115
- case 'starknet_addDeclareTransaction':
2116
- return this._handleMethod('jaelis_deploy', [{ data: params[0]?.contract_class, from: params[0]?.sender_address }]);
2117
-
2118
- case 'starknet_getClass':
2119
- case 'starknet_getClassAt':
2120
- const cairoCode = await this._handleMethod('jaelis_getCode', [params[1] || params[0]]);
2121
- return { program: cairoCode, entry_points_by_type: { CONSTRUCTOR: [], EXTERNAL: [], L1_HANDLER: [] } };
2122
-
2123
- default:
2124
- throw new Error(`Method not found: ${method}`);
2125
- }
2126
- }
2127
-
2128
- async _sendTransaction(tx) {
2129
- if (!this.blockchain) throw new Error('Blockchain not available');
2130
- const result = await this.blockchain.processTransaction(tx);
2131
- return result.transactionHash || '0x0';
2132
- }
2133
-
2134
- /**
2135
- * Get contract bytecode at address
2136
- *
2137
- * CRITICAL: This is how block explorers detect contracts!
2138
- * - Returns bytecode hex string if contract exists
2139
- * - Returns '0x' if address is an EOA or doesn't exist
2140
- *
2141
- * Block explorers use: eth_getCode(address) !== '0x' → it's a contract!
2142
- */
2143
- async _getCode(address, blockTag = 'latest') {
2144
- if (!this.blockchain) return '0x';
2145
-
2146
- try {
2147
- // Normalize address
2148
- const normalizedAddr = address.toLowerCase();
2149
-
2150
- // Try StateManager first (persistent LevelDB storage)
2151
- if (this.blockchain.stateManager) {
2152
- const code = await this.blockchain.stateManager.getCode(normalizedAddr);
2153
- if (code && code.length > 0) {
2154
- // Return as hex string
2155
- if (Buffer.isBuffer(code)) {
2156
- return '0x' + code.toString('hex');
2157
- }
2158
- if (typeof code === 'string') {
2159
- return code.startsWith('0x') ? code : '0x' + code;
2160
- }
2161
- return '0x' + Buffer.from(code).toString('hex');
2162
- }
2163
- }
2164
-
2165
- // Try VM Executor
2166
- if (this.blockchain.vmExecutor?.stateManager) {
2167
- const code = await this.blockchain.vmExecutor.stateManager.getCode(normalizedAddr);
2168
- if (code && code.length > 0) {
2169
- if (Buffer.isBuffer(code)) {
2170
- return '0x' + code.toString('hex');
2171
- }
2172
- return code.startsWith('0x') ? code : '0x' + code;
2173
- }
2174
- }
2175
-
2176
- // Try UnifiedVM contracts
2177
- if (this.blockchain.unifiedVM?.contractManager) {
2178
- const contract = this.blockchain.unifiedVM.contractManager.contracts.get(normalizedAddr);
2179
- if (contract?.bytecode) {
2180
- if (Buffer.isBuffer(contract.bytecode)) {
2181
- return '0x' + contract.bytecode.toString('hex');
2182
- }
2183
- return contract.bytecode.startsWith('0x') ? contract.bytecode : '0x' + contract.bytecode;
2184
- }
2185
- }
2186
-
2187
- // Try contracts Map directly
2188
- if (this.blockchain.contracts) {
2189
- const contract = this.blockchain.contracts.get(normalizedAddr);
2190
- if (contract?.bytecode) {
2191
- if (Buffer.isBuffer(contract.bytecode)) {
2192
- return '0x' + contract.bytecode.toString('hex');
2193
- }
2194
- return contract.bytecode.startsWith('0x') ? contract.bytecode : '0x' + contract.bytecode;
2195
- }
2196
- }
2197
-
2198
- // No bytecode found - it's an EOA or doesn't exist
2199
- return '0x';
2200
- } catch (error) {
2201
- console.error(`[RPC] _getCode error for ${address}:`, error.message);
2202
- return '0x';
2203
- }
2204
- }
2205
-
2206
- /**
2207
- * Get account balance
2208
- */
2209
- async _getBalance(address, blockTag = 'latest') {
2210
- if (!this.blockchain) return '0x0';
2211
-
2212
- try {
2213
- const normalizedAddr = address.toLowerCase();
2214
-
2215
- // Try StateManager
2216
- if (this.blockchain.stateManager) {
2217
- const account = await this.blockchain.stateManager.getAccount(normalizedAddr);
2218
- if (account?.balance !== undefined) {
2219
- const balance = BigInt(account.balance || 0);
2220
- return '0x' + balance.toString(16);
2221
- }
2222
- }
2223
-
2224
- // Default balance (JAELIS has no native token, but return 0)
2225
- return '0x0';
2226
- } catch (error) {
2227
- return '0x0';
2228
- }
2229
- }
2230
-
2231
- /**
2232
- * Get transaction count (nonce)
2233
- */
2234
- async _getTransactionCount(address, blockTag = 'latest') {
2235
- if (!this.blockchain) return '0x0';
2236
-
2237
- try {
2238
- const normalizedAddr = address.toLowerCase();
2239
-
2240
- // Try StateManager
2241
- if (this.blockchain.stateManager) {
2242
- const account = await this.blockchain.stateManager.getAccount(normalizedAddr);
2243
- if (account?.nonce !== undefined) {
2244
- const nonce = BigInt(account.nonce || 0);
2245
- return '0x' + nonce.toString(16);
2246
- }
2247
- }
2248
-
2249
- return '0x0';
2250
- } catch (error) {
2251
- return '0x0';
2252
- }
2253
- }
2254
-
2255
- /**
2256
- * Get storage value at slot
2257
- */
2258
- async _getStorageAt(address, slot, blockTag = 'latest') {
2259
- if (!this.blockchain) return '0x' + '0'.repeat(64);
2260
-
2261
- try {
2262
- const normalizedAddr = address.toLowerCase();
2263
-
2264
- // Try StateManager
2265
- if (this.blockchain.stateManager) {
2266
- const value = await this.blockchain.stateManager.getStorage(normalizedAddr, slot);
2267
- if (value !== undefined) {
2268
- const bigValue = BigInt(value || 0);
2269
- return '0x' + bigValue.toString(16).padStart(64, '0');
2270
- }
2271
- }
2272
-
2273
- // Try VM Executor StateManager
2274
- if (this.blockchain.vmExecutor?.stateManager) {
2275
- const value = await this.blockchain.vmExecutor.stateManager.getStorage(normalizedAddr, slot);
2276
- if (value !== undefined) {
2277
- const bigValue = BigInt(value || 0);
2278
- return '0x' + bigValue.toString(16).padStart(64, '0');
2279
- }
2280
- }
2281
-
2282
- return '0x' + '0'.repeat(64);
2283
- } catch (error) {
2284
- return '0x' + '0'.repeat(64);
2285
- }
2286
- }
2287
-
2288
- async _call(callObject) {
2289
- if (!this.blockchain?.vmExecutor) throw new Error('VM not available');
2290
- const result = await this.blockchain.vmExecutor.executeCall(
2291
- callObject.to,
2292
- callObject.data?.functionName || 'call',
2293
- callObject.data?.args || [],
2294
- { from: callObject.from }
2295
- );
2296
- return result.returnValue;
2297
- }
2298
-
2299
- async _deployContract(source, language, options) {
2300
- if (!this.blockchain) throw new Error('Blockchain not available');
2301
- console.log(`[RPC] Deploying ${language} contract...`);
2302
- const result = await this.blockchain.deployContract(source, language, options);
2303
- return {
2304
- address: result.address,
2305
- language,
2306
- gasUsed: 0 // ZERO FEES!
2307
- };
2308
- }
2309
-
2310
- /**
2311
- * Deploy unified contract bundle (THE KEY INNOVATION!)
2312
- *
2313
- * Compiles MULTIPLE contracts from MULTIPLE languages into ONE bytecode bundle.
2314
- * All contracts share memory and can call each other DIRECTLY - no bridges!
2315
- *
2316
- * NOW WITH CROSS-CHAIN PROPAGATION:
2317
- * - Contracts appear on ETH, SOL, and other block explorers!
2318
- * - Shadow contracts on external chains proxy to JAELIS
2319
- *
2320
- * @param {Object} params - { from, sources: [{ code, language, name }...], targetChains?: number[] }
2321
- */
2322
- async _deployUnified(params) {
2323
- if (!this.blockchain) throw new Error('Blockchain not available');
2324
- if (!this.blockchain.unifiedVM) throw new Error('Unified VM not available');
2325
-
2326
- const { from, sources, targetChains } = params;
2327
-
2328
- if (!sources || !Array.isArray(sources) || sources.length === 0) {
2329
- throw new Error('sources array is required for unified deployment');
2330
- }
2331
-
2332
- console.log(`[RPC] Deploying unified bundle with ${sources.length} contracts...`);
2333
- console.log(`[RPC] Languages: ${[...new Set(sources.map(s => s.language))].join(', ')}`);
2334
-
2335
- // Default target chains if not specified - ALL 30+ chains we support!
2336
- const defaultTargetChains = [
2337
- // EVM Mainnets
2338
- 1, // Ethereum Mainnet
2339
- 137, // Polygon PoS
2340
- 42161, // Arbitrum One
2341
- 42170, // Arbitrum Nova
2342
- 10, // OP Mainnet
2343
- 8453, // Base
2344
- 56, // BNB Smart Chain
2345
- 43114, // Avalanche C-Chain
2346
- 250, // Fantom Opera
2347
- 100, // Gnosis
2348
- 59144, // Linea
2349
- 324, // zkSync Era
2350
- 534352, // Scroll
2351
- 5000, // Mantle
2352
- 81457, // Blast
2353
-
2354
- // Solana
2355
- 101, // Solana Mainnet
2356
-
2357
- // Move chains (using type prefix to differentiate)
2358
- // Note: Aptos/Sui use same IDs but different networks
2359
-
2360
- // TON
2361
- -1, // TON Mainnet
2362
-
2363
- // StarkNet (using string identifier due to large chain ID)
2364
- 'starknet-main', // StarkNet Mainnet
2365
-
2366
- // Cosmos
2367
- 118, // Cosmos Hub
2368
- 119, // Osmosis
2369
-
2370
- // Bitcoin
2371
- 0 // Bitcoin Mainnet
2372
- ];
2373
- const chains = targetChains || defaultTargetChains;
2374
-
2375
- console.log(`[RPC] Target chains: ${chains.join(', ')}`);
2376
-
2377
- // Use the new deployUnifiedWithPropagation for cross-chain deployment
2378
- if (this.blockchain.unifiedVM.deployUnifiedWithPropagation) {
2379
- const result = await this.blockchain.unifiedVM.deployUnifiedWithPropagation({
2380
- from,
2381
- sources,
2382
- targetChains: chains
2383
- });
2384
-
2385
- // Build contracts map for response
2386
- const contractsMap = {};
2387
- for (const source of sources) {
2388
- contractsMap[source.name] = {
2389
- address: result.address,
2390
- language: source.language,
2391
- name: source.name
2392
- };
2393
- }
2394
-
2395
- console.log(`[RPC] Unified bundle deployed at ${result.address}`);
2396
- console.log(`[RPC] Chain deployments: ${result.deployments?.length || 0}`);
2397
-
2398
- // Log explorer URLs
2399
- if (result.explorerUrls) {
2400
- console.log(`[RPC] Explorer URLs:`);
2401
- for (const [chainId, url] of Object.entries(result.explorerUrls)) {
2402
- console.log(`[RPC] Chain ${chainId}: ${url}`);
2403
- }
2404
- }
2405
-
2406
- return {
2407
- address: result.address,
2408
- bytecode: result.bytecode,
2409
- abi: result.abi || [],
2410
- contracts: contractsMap,
2411
- deployments: result.deployments,
2412
- explorerUrls: result.explorerUrls,
2413
- metadata: result.metadata,
2414
- gasUsed: 0 // ZERO FEES!
2415
- };
2416
- }
2417
-
2418
- // Fallback: original local-only deployment
2419
- console.log(`[RPC] Fallback: local-only deployment (no cross-chain propagation)`);
2420
-
2421
- const compiled = await this.blockchain.unifiedVM.compileBundle(sources);
2422
- const address = '0x' + require('crypto').randomBytes(20).toString('hex');
2423
-
2424
- if (this.blockchain.contracts) {
2425
- this.blockchain.contracts.set(address, {
2426
- bytecode: compiled.bytecode,
2427
- abi: compiled.abi || [],
2428
- sources: sources.map(s => s.name),
2429
- languages: [...new Set(sources.map(s => s.language))],
2430
- deployedAt: Date.now(),
2431
- deployer: from
2432
- });
2433
- }
2434
-
2435
- const contractsMap = {};
2436
- for (const source of sources) {
2437
- contractsMap[source.name] = {
2438
- address: address,
2439
- language: source.language,
2440
- name: source.name
2441
- };
2442
- }
2443
-
2444
- return {
2445
- address,
2446
- bytecode: compiled.bytecode?.toString('hex'),
2447
- abi: compiled.abi || [],
2448
- contracts: contractsMap,
2449
- metadata: compiled.metadata,
2450
- gasUsed: 0 // ZERO FEES!
2451
- };
2452
- }
2453
-
2454
- async _executeContract(to, functionName, args, options) {
2455
- if (!this.blockchain) throw new Error('Blockchain not available');
2456
- return this.blockchain.executeContract(to, functionName, args, options);
2457
- }
2458
-
2459
- async _crossContractCall(from, to, functionName, args) {
2460
- if (!this.blockchain) throw new Error('Blockchain not available');
2461
- console.log(`[RPC] Cross-call: ${from.substring(0, 10)}... → ${to.substring(0, 10)}...::${functionName}`);
2462
- return this.blockchain.crossContractCall(from, to, functionName, args);
2463
- }
2464
-
2465
- // ═══════════════════════════════════════════════════════════════
2466
- // CROSS-CHAIN SETTLEMENT IMPLEMENTATIONS
2467
- // ═══════════════════════════════════════════════════════════════
2468
-
2469
- _getCrossChainRegistry() {
2470
- // Return the VM's cross-chain registry if available
2471
- if (this.blockchain?.vmExecutor?.vm?.getAllChains) {
2472
- return this.blockchain.vmExecutor.vm.getAllChains();
2473
- }
2474
- // Fallback: return hardcoded registry
2475
- return {
2476
- JAELIS_MAINNET: { id: 4547, name: 'JAELIS Mainnet', type: 'native', status: 'upcoming' },
2477
- JAELIS_TESTNET: { id: 4545, name: 'JAELIS Testnet', type: 'native', status: 'live' },
2478
- ETH_MAINNET: { id: 1, name: 'Ethereum Mainnet', type: 'evm' },
2479
- ETH_SEPOLIA: { id: 11155111, name: 'Ethereum Sepolia', type: 'evm' },
2480
- POLYGON: { id: 137, name: 'Polygon PoS', type: 'evm' },
2481
- ARBITRUM_ONE: { id: 42161, name: 'Arbitrum One', type: 'evm' },
2482
- OPTIMISM: { id: 10, name: 'OP Mainnet', type: 'evm' },
2483
- BASE: { id: 8453, name: 'Base', type: 'evm' },
2484
- AVALANCHE_C: { id: 43114, name: 'Avalanche C-Chain', type: 'evm' },
2485
- BSC: { id: 56, name: 'BNB Smart Chain', type: 'evm' },
2486
- SOLANA_MAINNET: { id: 101, name: 'Solana Mainnet', type: 'svm', cluster: 'mainnet-beta' },
2487
- SOLANA_DEVNET: { id: 102, name: 'Solana Devnet', type: 'svm', cluster: 'devnet' },
2488
- APTOS_MAINNET: { id: 1, name: 'Aptos Mainnet', type: 'move', network: 'aptos' },
2489
- SUI_MAINNET: { id: 1, name: 'Sui Mainnet', type: 'move', network: 'sui' },
2490
- TON_MAINNET: { id: -1, name: 'TON Mainnet', type: 'tvm', workchain: -1 }
2491
- };
2492
- }
2493
-
2494
- _getCrossChainInfo(chainId) {
2495
- const chains = this._getCrossChainRegistry();
2496
- const chain = Object.values(chains).find(c => c.id === chainId);
2497
- return chain || { error: 'Chain not found', chainId };
2498
- }
2499
-
2500
- async _readCrossChainState(chainId, contractAddress, variableName) {
2501
- if (this.blockchain?.vmExecutor?.vm?.readCrossChainState) {
2502
- const value = this.blockchain.vmExecutor.vm.readCrossChainState(chainId, contractAddress, variableName);
2503
- return {
2504
- chainId,
2505
- contractAddress,
2506
- variableName,
2507
- value: value ? '0x' + value.toString('hex') : '0x0',
2508
- settled: value ? true : false
2509
- };
2510
- }
2511
- return { error: 'Cross-chain state not available', chainId, contractAddress, variableName };
2512
- }
2513
-
2514
- async _settleCrossChainState(chainId, contractAddress, variableName, value, proof) {
2515
- if (this.blockchain?.vmExecutor?.vm?.settleExternalState) {
2516
- const valueBuffer = Buffer.from(value.replace('0x', ''), 'hex');
2517
- const result = await this.blockchain.vmExecutor.vm.settleExternalState(
2518
- chainId, contractAddress, variableName, valueBuffer, proof
2519
- );
2520
- console.log(`[RPC] Cross-chain settlement: Chain ${chainId} → ${variableName}`);
2521
- return {
2522
- success: true,
2523
- chainId,
2524
- contractAddress,
2525
- variableName,
2526
- slot: result.slot ? '0x' + result.slot.toString('hex') : null,
2527
- settlement: result.settlement
2528
- };
2529
- }
2530
- return { error: 'Cross-chain settlement not available' };
2531
- }
2532
-
2533
- _getCrossChainStateDiff(chainId1, chainId2, contractAddress, variableNames) {
2534
- if (this.blockchain?.vmExecutor?.vm?.getCrossChainStateDiff) {
2535
- return this.blockchain.vmExecutor.vm.getCrossChainStateDiff(
2536
- chainId1, chainId2, contractAddress, variableNames
2537
- );
2538
- }
2539
- return { error: 'State diff not available', chainId1, chainId2 };
2540
- }
2541
-
2542
- _computeCrossChainSlot(chainId, contractAddress, variableName) {
2543
- if (this.blockchain?.vmExecutor?.vm?.computeCrossChainSlot) {
2544
- const slot = this.blockchain.vmExecutor.vm.computeCrossChainSlot(chainId, contractAddress, variableName);
2545
- return '0x' + slot.toString('hex');
2546
- }
2547
- // Fallback: compute locally
2548
- const crypto = require('crypto');
2549
- const data = Buffer.concat([
2550
- Buffer.alloc(4), // chainId placeholder
2551
- Buffer.from(contractAddress.replace('0x', ''), 'hex'),
2552
- Buffer.from(variableName, 'utf8')
2553
- ]);
2554
- data.writeUInt32LE(chainId, 0);
2555
- return '0x' + crypto.createHash('sha256').update(data).digest('hex');
2556
- }
2557
-
2558
- _getLightClientStatus(chainId) {
2559
- if (this.blockchain?.vmExecutor?.vm?.crossChainManager?.stateStore?.lightClients) {
2560
- const client = this.blockchain.vmExecutor.vm.crossChainManager.stateStore.lightClients.get(chainId);
2561
- if (client) {
2562
- return {
2563
- chainId,
2564
- synced: client.synced || false,
2565
- latestBlock: client.latestBlock || 0,
2566
- stateRoot: client.latestStateRoot ? '0x' + client.latestStateRoot.toString('hex') : null
2567
- };
2568
- }
2569
- }
2570
- return { chainId, synced: false, error: 'Light client not available' };
2571
- }
2572
-
2573
- _getSettlements(chainId, contractAddress) {
2574
- if (this.blockchain?.vmExecutor?.vm?.crossChainManager?.stateStore?.settlementLog) {
2575
- const log = this.blockchain.vmExecutor.vm.crossChainManager.stateStore.settlementLog;
2576
- return log.filter(s => s.chainId === chainId && s.contractAddress === contractAddress);
2577
- }
2578
- return [];
2579
- }
2580
-
2581
- _getCrossChainStats() {
2582
- if (this.blockchain?.vmExecutor?.vm?.crossChainManager?.getStats) {
2583
- return this.blockchain.vmExecutor.vm.crossChainManager.getStats();
2584
- }
2585
- return {
2586
- totalSettlements: 0,
2587
- chainsActive: 0,
2588
- lightClientsRegistered: 0,
2589
- stateSize: 0
2590
- };
2591
- }
2592
-
2593
- // ═══════════════════════════════════════════════════════════════
2594
- // CROSS-CHAIN DEPLOYMENT QUERY IMPLEMENTATIONS
2595
- // ═══════════════════════════════════════════════════════════════
2596
-
2597
- _getCrossChainDeployment(address) {
2598
- if (this.blockchain?.unifiedVM?.deployManager?.getDeployment) {
2599
- const deployment = this.blockchain.unifiedVM.deployManager.getDeployment(address);
2600
- if (deployment) {
2601
- return deployment;
2602
- }
2603
- }
2604
- return { error: 'Deployment not found', address };
2605
- }
2606
-
2607
- _getChainDeployments(chainId) {
2608
- if (this.blockchain?.unifiedVM?.deployManager?.getChainDeployments) {
2609
- return this.blockchain.unifiedVM.deployManager.getChainDeployments(chainId);
2610
- }
2611
- return [];
2612
- }
2613
-
2614
- _getExplorerUrl(chainId, address) {
2615
- if (this.blockchain?.unifiedVM?.deployManager?.getExplorerUrl) {
2616
- const url = this.blockchain.unifiedVM.deployManager.getExplorerUrl(chainId, address);
2617
- return { chainId, address, url };
2618
- }
2619
- return { chainId, address, url: null, error: 'Deploy manager not available' };
2620
- }
2621
-
2622
- _getDeploymentStats() {
2623
- if (this.blockchain?.unifiedVM?.deployManager?.getStats) {
2624
- return this.blockchain.unifiedVM.deployManager.getStats();
2625
- }
2626
- return {
2627
- totalDeployments: 0,
2628
- pendingCount: 0,
2629
- failedCount: 0,
2630
- chainStats: {}
2631
- };
2632
- }
2633
-
2634
- // ═══════════════════════════════════════════════════════════════
2635
- // MULTI-CHAIN SIGNATURE IMPLEMENTATIONS
2636
- // For external chains to accept deployments, user signs per-chain
2637
- // ═══════════════════════════════════════════════════════════════
2638
-
2639
- /**
2640
- * Get signing requests for each target chain
2641
- *
2642
- * Frontend flow:
2643
- * 1. Get these messages
2644
- * 2. For each chain, switch wallet network and sign
2645
- * 3. Collect all signatures
2646
- * 4. Call deployWithSignatures
2647
- */
2648
- _getMultiChainSigningRequests(bytecode, targetChains) {
2649
- if (this.blockchain?.unifiedVM?.deployManager?.getMultiChainSigningRequests) {
2650
- return this.blockchain.unifiedVM.deployManager.getMultiChainSigningRequests(bytecode, targetChains);
2651
- }
2652
-
2653
- // Fallback implementation
2654
- const crypto = require('crypto');
2655
- const bytecodeHash = crypto.createHash('sha256')
2656
- .update(bytecode || '')
2657
- .digest('hex')
2658
- .substring(0, 16);
2659
-
2660
- const timestamp = Date.now();
2661
- const requests = [];
2662
-
2663
- for (const chainId of (targetChains || [])) {
2664
- const message = `JAELIS Cross-Chain Deploy Authorization
2665
-
2666
- Chain ID: ${chainId}
2667
- Bytecode Hash: ${bytecodeHash}
2668
- Timestamp: ${timestamp}
2669
-
2670
- I authorize JAELIS to deploy this contract.
2671
- ZERO FEES - No gas cost to me.`;
2672
-
2673
- requests.push({
2674
- chainId,
2675
- message,
2676
- messageHash: '0x' + crypto.createHash('sha256')
2677
- .update(`\x19Ethereum Signed Message:\n${message.length}${message}`)
2678
- .digest('hex'),
2679
- switchParams: { chainId: '0x' + chainId.toString(16) }
2680
- });
2681
- }
2682
-
2683
- return { requests, bytecodeHash, timestamp, totalChains: targetChains?.length || 0 };
2684
- }
2685
-
2686
- /**
2687
- * Deploy with per-chain wallet signatures
2688
- *
2689
- * Each chain that needs to recognize the deployment
2690
- * requires its own signature from the deployer's wallet.
2691
- */
2692
- async _deployWithMultiChainSignatures(params) {
2693
- const { from, bytecode, abi, targetChains, chainSignatures, metadata } = params;
2694
-
2695
- console.log(`[RPC] Multi-chain signature deployment from ${from}`);
2696
- console.log(`[RPC] Target chains: ${targetChains?.length || 0}`);
2697
- console.log(`[RPC] Signatures provided: ${Object.keys(chainSignatures || {}).length}`);
2698
-
2699
- if (this.blockchain?.unifiedVM?.deployManager?.deployWithMultiChainSignatures) {
2700
- return await this.blockchain.unifiedVM.deployManager.deployWithMultiChainSignatures({
2701
- from,
2702
- bytecode,
2703
- abi,
2704
- targetChains,
2705
- chainSignatures,
2706
- metadata
2707
- });
2708
- }
2709
-
2710
- // Fallback: regular deployment without chain signatures
2711
- console.log(`[RPC] Fallback: Deploy manager not available, using standard flow`);
2712
- return {
2713
- error: 'Multi-chain signatures not supported',
2714
- message: 'Deploy manager not initialized'
2715
- };
2716
- }
2717
-
2718
- async stop() {
2719
- if (this.server) {
2720
- this.server.close();
2721
- }
2722
- }
2723
- }
2724
-
2725
- class EmbeddedStorage {
2726
- constructor() {
2727
- this.data = new Map();
2728
- }
2729
-
2730
- async get(key) {
2731
- return this.data.get(key);
2732
- }
2733
-
2734
- async put(key, value) {
2735
- this.data.set(key, value);
2736
- }
2737
- }
2738
-
2739
- // ============================================================
2740
- // EXPORTS
2741
- // ============================================================
44
+ // Version
45
+ const VERSION = '2.0.0';
2742
46
 
2743
47
  module.exports = {
2744
48
  JaelisNode,
2745
- BootstrapNode,
2746
- EmbeddedBlockchain,
2747
- EmbeddedNetwork,
2748
- EmbeddedRpcServer,
2749
- EmbeddedStorage,
2750
-
2751
- // Wallet configuration (like Geth's keystore)
2752
- NodeWalletConfig,
2753
-
2754
- // Multi-chain address utilities
2755
- ADDRESS_FORMATS,
2756
- detectAddressType,
2757
- validateAddress,
2758
- toCanonicalAddress,
2759
-
2760
- // Convenience factory
2761
- createNode: (options) => new JaelisNode(options),
2762
- createBootstrap: (options) => new BootstrapNode(options)
49
+ SyncManager,
50
+ RPCServer,
51
+ Storage,
52
+ NETWORKS,
53
+ VERSION
2763
54
  };