@cfxdevkit/devnode 0.1.0 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js.map +1 -1
- package/dist/plugin.cjs.map +1 -1
- package/dist/plugin.js.map +1 -1
- package/package.json +25 -24
package/dist/plugin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/server-manager.ts","../src/types.ts","../src/plugin.ts"],"sourcesContent":["/*\n * Copyright 2025 Conflux DevKit Team\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// Server Manager for xcfx/node lifecycle management\n// Based on proven patterns from DevKit CLI, adapted for unified interface\n\nimport type { ChildProcess } from 'node:child_process';\nimport { randomBytes } from 'node:crypto';\nimport { promises as fs } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { defaultNetworkSelector } from '@cfxdevkit/core/config';\nimport {\n generateMnemonic as coreGenerateMnemonic,\n deriveAccount,\n deriveAccounts,\n deriveFaucetAccount,\n} from '@cfxdevkit/core/wallet';\nimport { createServer } from '@xcfx/node';\nimport type { TestClient } from 'cive';\nimport { privateKeyToAccount } from 'cive/accounts';\nimport { privateKeyToAccount as privateKeyToEvmAccount } from 'viem/accounts';\nimport {\n type AccountInfo,\n type FaucetBalances,\n type MiningStatus,\n NodeError,\n type ServerConfig,\n type ServerStatus,\n} from './types.js';\n\n// Port configuration\nconst DEFAULT_CORE_RPC_PORT = 12537;\nconst DEFAULT_EVM_RPC_PORT = 8545;\nconst DEFAULT_WS_PORT = 12536;\nconst DEFAULT_EVM_WS_PORT = 8546;\n\n/**\n * Server Manager for xcfx/node lifecycle management\n * Handles starting, stopping, and managing the Conflux development node\n */\nexport class ServerManager {\n private nodeProcess: ChildProcess | null = null;\n private server: Awaited<ReturnType<typeof createServer>> | null = null;\n private config: ServerConfig;\n private status: ServerStatus = 'stopped';\n private accounts: AccountInfo[] = [];\n private mnemonic: string = '';\n private miningAccount: AccountInfo | null = null;\n private miningStatus: MiningStatus;\n private miningTimer: NodeJS.Timeout | null = null;\n private testClient: TestClient | null = null;\n /** True while packMine() is running — auto-miner skips its tick to avoid concurrent mining RPCs. */\n private _packMining = false;\n\n constructor(config: ServerConfig) {\n this.config = {\n ...config,\n coreRpcPort: config.coreRpcPort || DEFAULT_CORE_RPC_PORT,\n evmRpcPort: config.evmRpcPort || DEFAULT_EVM_RPC_PORT,\n wsPort: config.wsPort || DEFAULT_WS_PORT,\n evmWsPort: config.evmWsPort || DEFAULT_EVM_WS_PORT,\n chainId: config.chainId || 2029, // Local Core chain ID\n evmChainId: config.evmChainId || 2030, // Local eSpace chain ID\n accounts: config.accounts || 10,\n balance: config.balance || '1000000',\n mnemonic: config.mnemonic,\n // Following xcfx-node test pattern: devPackTxImmediately should be false\n // All mining is managed via testClient.mine() calls\n devPackTxImmediately: false,\n };\n\n // Initialize mining status\n this.miningStatus = {\n isRunning: false,\n interval: 1000,\n blocksMined: 0,\n startTime: undefined,\n };\n\n // Generate or use provided mnemonic and immediately generate accounts\n // This ensures accounts are always available regardless of node state\n this.mnemonic = this.config.mnemonic || coreGenerateMnemonic(128);\n this.generateAccountsSync();\n this.generateMiningAccountSync();\n }\n\n /**\n * Return a sanitized copy of the server config with sensitive fields redacted.\n */\n private redactConfig(config: ServerConfig): Partial<ServerConfig> {\n type SafeConfig = Partial<ServerConfig> & {\n mnemonic?: string;\n accounts?: unknown;\n };\n const safe: SafeConfig = { ...(config as SafeConfig) };\n if (safe.mnemonic) safe.mnemonic = '[REDACTED]';\n // remove accounts and secrets to avoid leaking private keys\n if (safe.accounts) delete safe.accounts;\n return safe;\n }\n\n /**\n * Start the Conflux development node\n */\n async start(): Promise<void> {\n if (this.status === 'running') {\n throw new NodeError(\n 'Server is already running',\n 'SERVER_ALREADY_RUNNING'\n );\n }\n\n try {\n this.status = 'starting';\n\n // Mnemonic and accounts are already generated in constructor\n // Mining account is also already generated in constructor\n\n // Ensure data directory exists with proper permissions\n const dataDir =\n this.config.dataDir || join(homedir(), '.conflux-devkit', 'data');\n try {\n await fs.mkdir(dataDir, { recursive: true, mode: 0o755 });\n } catch (error) {\n console.warn('Failed to create data directory:', error);\n // Continue anyway, might still work if directory exists\n }\n\n // Create server instance with configuration\n const serverConfig = {\n // Correct property names according to @xcfx/node API\n jsonrpcHttpPort: this.config.coreRpcPort,\n jsonrpcHttpEthPort: this.config.evmRpcPort,\n jsonrpcWsPort: this.config.wsPort,\n jsonrpcWsEthPort: this.config.evmWsPort,\n chainId: this.config.chainId,\n evmChainId: this.config.evmChainId,\n // Specify data directory to avoid permission issues\n confluxDataDir: dataDir,\n // Genesis accounts configuration - include mining account for initial funding\n genesisSecrets: [\n ...this.accounts.map((acc) => acc.privateKey),\n this.requireMiningAccount().privateKey, // Add mining account to get initial funds\n ],\n genesisEvmSecrets: [\n ...this.accounts.map((acc) => acc.evmPrivateKey || acc.privateKey),\n this.requireMiningAccount().evmPrivateKey ||\n this.requireMiningAccount().privateKey, // Add mining account EVM key\n ],\n // Mining configuration - use config value or default to mining account address\n // 'auto' is a sentinel value meaning \"use the derived mining account address\"\n miningAuthor:\n this.config.miningAuthor && this.config.miningAuthor !== 'auto'\n ? this.config.miningAuthor\n : this.miningAccount?.coreAddress,\n // Following the reference test (xcfx-node/evmManualBlockGeneration.test.ts):\n // devPackTxImmediately: false — eSpace txs are ONLY packed by mine({ numTxs }),\n // never by mine({ blocks }). This flag only affects Core space.\n devPackTxImmediately: false,\n log: this.config.logging || false,\n // Genesis block initialization can take time; pass a generous timeout so\n // the native binary doesn't abort the startup handshake prematurely.\n timeout: 60000,\n retryInterval: 300,\n };\n\n this.server = await createServer(serverConfig);\n\n // Start the server - this is required!\n await this.server.start();\n\n this.status = 'running';\n\n // Update network selector with local chain URLs and notify it of node start\n defaultNetworkSelector.updateLocalChainUrls(\n this.config.coreRpcPort || DEFAULT_CORE_RPC_PORT,\n this.config.evmRpcPort || DEFAULT_EVM_RPC_PORT,\n this.config.wsPort || DEFAULT_WS_PORT\n );\n defaultNetworkSelector.onNodeStart(2029, 2030); // Core local, eSpace local\n\n // Set up cleanup handlers\n this.setupCleanupHandlers();\n\n // Auto-start mining at 2s intervals using mine({ numTxs:1 }).\n // With devPackTxImmediately:false (our config) mine({ blocks }) creates\n // empty blocks only; mine({ numTxs }) is the only call that packs pending\n // Core-Space and eSpace transactions, so we use it here so that user\n // wallet transactions are confirmed within one mining interval.\n await this.startMining(2000);\n } catch (error) {\n this.status = 'error';\n throw new NodeError(\n `Failed to start server: ${error instanceof Error ? error.message : String(error)}`,\n 'SERVER_START_ERROR',\n undefined,\n {\n config: this.redactConfig(this.config as ServerConfig),\n originalError: error,\n }\n );\n }\n }\n\n /**\n * Stop the Conflux development node\n */\n async stop(): Promise<void> {\n if (this.status === 'stopped') {\n return;\n }\n\n try {\n this.status = 'stopping';\n\n // Stop mining if running\n if (this.miningStatus.isRunning) {\n try {\n await this.stopMining();\n } catch (error) {\n console.warn('Failed to stop mining during server shutdown:', error);\n }\n }\n\n if (this.server) {\n await this.server.stop();\n this.server = null;\n }\n\n if (this.nodeProcess) {\n this.nodeProcess.kill('SIGTERM');\n this.nodeProcess = null;\n }\n\n // Clean up test client\n this.testClient = null;\n\n this.status = 'stopped';\n\n // Notify network selector that node has stopped\n defaultNetworkSelector.onNodeStop();\n } catch (error) {\n this.status = 'error';\n throw new NodeError(\n `Failed to stop server: ${error instanceof Error ? error.message : String(error)}`,\n 'SERVER_STOP_ERROR',\n undefined,\n { originalError: error }\n );\n }\n }\n\n /**\n * Restart the Conflux development node\n */\n async restart(): Promise<void> {\n await this.stop();\n await this.start();\n }\n\n /**\n * Get current server status\n */\n getStatus(): ServerStatus {\n return this.status;\n }\n\n /**\n * Get comprehensive node status including mining\n */\n getNodeStatus() {\n return {\n server: this.status,\n mining: this.getMiningStatus(),\n config: this.redactConfig(this.config as ServerConfig),\n accounts: this.accounts.length,\n rpcUrls: this.getRpcUrls(),\n };\n }\n\n /**\n * Check if server is running\n */\n isRunning(): boolean {\n return this.status === 'running';\n }\n\n /**\n * Get server configuration\n */\n getConfig(): ServerConfig {\n // Return a sanitized config to avoid exposing mnemonic/privkeys in logs or API\n return {\n ...(this.redactConfig(this.config as ServerConfig) as ServerConfig),\n };\n }\n\n /**\n * Get generated accounts\n */\n getAccounts(): AccountInfo[] {\n return [...this.accounts];\n }\n\n /**\n * Get the mnemonic phrase\n */\n getMnemonic(): string {\n return this.mnemonic;\n }\n\n /**\n * Get RPC URLs\n */\n getRpcUrls(): {\n core: string;\n evm: string;\n coreWs: string;\n evmWs: string;\n ws: string;\n } {\n const coreWs = `ws://localhost:${this.config.wsPort}`;\n return {\n core: `http://localhost:${this.config.coreRpcPort}`,\n evm: `http://localhost:${this.config.evmRpcPort}`,\n coreWs,\n evmWs: `ws://localhost:${this.config.evmWsPort}`,\n ws: coreWs, // backward-compat alias for Core WS\n };\n }\n\n /**\n * Add a new account to the server\n */\n async addAccount(privateKey?: string): Promise<AccountInfo> {\n const accountPrivateKey =\n privateKey || `0x${randomBytes(32).toString('hex')}`;\n\n const coreAccount = privateKeyToAccount(\n accountPrivateKey as `0x${string}`,\n {\n networkId: this.config.chainId || 1,\n }\n );\n const evmAccount = privateKeyToEvmAccount(\n accountPrivateKey as `0x${string}`\n );\n\n const accountInfo: AccountInfo = {\n index: this.accounts.length,\n privateKey: accountPrivateKey,\n coreAddress: coreAccount.address,\n evmAddress: evmAccount.address,\n mnemonic: this.mnemonic,\n path: `m/44'/503'/0'/0/${this.accounts.length}`,\n };\n\n this.accounts.push(accountInfo);\n\n // Note: @xcfx/node automatically funds genesis accounts\n // Additional funding would require separate RPC calls to the running node\n\n return accountInfo;\n }\n\n /**\n * Fund an account with CFX\n * Note: @xcfx/node doesn't provide direct funding methods.\n * This would require using RPC calls to send transactions from funded genesis accounts.\n */\n async fundAccount(\n address: string,\n amount: string,\n chainType: 'core' | 'evm' = 'core'\n ): Promise<void> {\n if (!this.isRunning() || !this.server) {\n throw new NodeError('Server is not running', 'SERVER_NOT_RUNNING');\n }\n\n // This functionality would need to be implemented using RPC calls\n // to transfer funds from genesis accounts to the target address\n throw new NodeError(\n 'Direct account funding not implemented. Genesis accounts are automatically funded by @xcfx/node.',\n 'NOT_IMPLEMENTED',\n chainType,\n { address, amount, chainType }\n );\n }\n\n /**\n * Set next block timestamp (for testing)\n * Note: @xcfx/node doesn't provide direct timestamp control.\n * Use createTestClient from 'cive' and connect to the running node's RPC.\n */\n async setNextBlockTimestamp(timestamp: number): Promise<void> {\n if (!this.isRunning() || !this.server) {\n throw new NodeError('Server is not running', 'SERVER_NOT_RUNNING');\n }\n\n // This functionality would need to be implemented using createTestClient\n // from 'cive' library connected to the running server's RPC endpoint\n throw new NodeError(\n 'Direct timestamp control not implemented. Use createTestClient from cive to control block timestamps via RPC.',\n 'NOT_IMPLEMENTED',\n 'core',\n { timestamp }\n );\n }\n\n /**\n * Get server logs\n * Note: @xcfx/node doesn't provide direct log access.\n * Logs would need to be captured during server startup or accessed via system logs.\n */\n async getLogs(lines: number = 50): Promise<string[]> {\n if (!this.isRunning() || !this.server) {\n throw new NodeError('Server is not running', 'SERVER_NOT_RUNNING');\n }\n\n // @xcfx/node doesn't provide log access methods\n // This would need to be implemented by capturing stdout/stderr during server startup\n // or by accessing system logs where the node process writes its output\n return [\n 'Log access not implemented for @xcfx/node.',\n 'Consider capturing server output during startup or checking system logs.',\n `Requested ${lines} lines of logs.`,\n ];\n }\n\n /**\n * Save server configuration to file\n */\n async saveConfig(filepath: string): Promise<void> {\n try {\n // Save a sanitized config file by redacting the mnemonic and removing private data\n const configData = {\n ...this.redactConfig(this.config as ServerConfig),\n mnemonic: '[REDACTED]',\n accounts: this.accounts.map((a) => ({\n index: a.index,\n coreAddress: a.coreAddress,\n evmAddress: a.evmAddress,\n path: a.path,\n })),\n rpcUrls: this.getRpcUrls(),\n };\n\n await fs.writeFile(filepath, JSON.stringify(configData, null, 2), 'utf8');\n } catch (error) {\n throw new NodeError(\n `Failed to save config: ${error instanceof Error ? error.message : String(error)}`,\n 'CONFIG_SAVE_ERROR',\n 'core',\n { filepath, originalError: error }\n );\n }\n }\n\n /**\n * Load server configuration from file\n */\n static async loadConfig(filepath: string): Promise<ServerConfig> {\n try {\n const configData = await fs.readFile(filepath, 'utf8');\n return JSON.parse(configData);\n } catch (error) {\n throw new NodeError(\n `Failed to load config: ${error instanceof Error ? error.message : String(error)}`,\n 'CONFIG_LOAD_ERROR',\n 'core',\n { filepath, originalError: error }\n );\n }\n }\n\n /**\n * Generate accounts from mnemonic using core wallet module\n * Called from constructor to ensure accounts are always available\n */\n private generateAccountsSync(): void {\n // Use core wallet module for account derivation\n const derivedAccounts = deriveAccounts(this.mnemonic, {\n count: this.config.accounts || 10,\n coreNetworkId: this.config.chainId || 2029,\n });\n\n this.accounts = derivedAccounts.map((account) => ({\n index: account.index,\n privateKey: account.corePrivateKey, // Keep Conflux private key as primary\n coreAddress: account.coreAddress,\n evmAddress: account.evmAddress,\n mnemonic: this.mnemonic,\n path: account.paths.core,\n // Store additional EVM-specific info\n evmPrivateKey: account.evmPrivateKey,\n evmPath: account.paths.evm,\n }));\n }\n\n /**\n * Generate dedicated mining account (separate from genesis accounts)\n * This account will receive mining rewards and serve as the faucet\n * Called synchronously from constructor to ensure always available\n */\n private generateMiningAccountSync(): void {\n // Use core wallet module for faucet/mining account derivation\n const faucetAccount = deriveFaucetAccount(\n this.mnemonic,\n this.config.chainId || 2029\n );\n\n this.miningAccount = {\n index: -1, // Special index for mining account\n privateKey: faucetAccount.corePrivateKey, // Core/Conflux private key\n coreAddress: faucetAccount.coreAddress,\n evmAddress: faucetAccount.evmAddress,\n mnemonic: this.mnemonic,\n path: faucetAccount.paths.core,\n // Store additional EVM-specific info\n evmPrivateKey: faucetAccount.evmPrivateKey,\n evmPath: faucetAccount.paths.evm,\n };\n\n console.log(\n `Generated mining account: Core=${this.miningAccount.coreAddress}, eSpace=${this.miningAccount.evmAddress}`\n );\n }\n\n /**\n * Returns the mining account, throwing if it has not been initialized.\n * In practice this is always set by generateMiningAccountSync() in the\n * constructor, so the throw is a safety net for unexpected states.\n */\n private requireMiningAccount(): AccountInfo {\n if (!this.miningAccount) {\n throw new Error('Mining account has not been initialized.');\n }\n return this.miningAccount;\n }\n\n // ===== MINING METHODS =====\n\n /**\n * Start automatic block mining using testClient\n * This creates an interval that mines blocks automatically\n * @param interval Mining interval in milliseconds (default: 2000ms)\n */\n async startMining(interval?: number): Promise<void> {\n if (!this.isRunning()) {\n throw new NodeError(\n 'Server must be running to start mining',\n 'SERVER_NOT_RUNNING'\n );\n }\n\n if (this.miningStatus.isRunning) {\n throw new NodeError(\n 'Mining is already running',\n 'MINING_ALREADY_RUNNING'\n );\n }\n\n // Initialize test client if not already created\n if (!this.testClient) {\n const { createTestClient, http } = await import('cive');\n this.testClient = createTestClient({\n transport: http(`http://localhost:${this.config.coreRpcPort}`, {\n timeout: 60_000,\n }),\n });\n }\n\n const miningInterval = interval || 2000; // Default 2s — empty blocks are fast\n\n this.miningStatus = {\n ...this.miningStatus,\n isRunning: true,\n interval: miningInterval,\n startTime: new Date(),\n };\n\n // Start the mining loop\n this.miningTimer = setInterval(async () => {\n try {\n if (this.testClient && !this._packMining) {\n // mine({ numTxs: 1 }) = test_generateOneBlock: packs ALL pending\n // Core-Space and eSpace transactions into a new block and generates\n // deferredStateEpochCount (default 5) blocks for deferred execution.\n // With devPackTxImmediately:false this is the ONLY mining call that\n // includes pending txs; mine({ blocks }) produces empty blocks only.\n await this.testClient.mine({ numTxs: 1 });\n this.miningStatus = {\n ...this.miningStatus,\n blocksMined: (this.miningStatus.blocksMined || 0) + 5,\n };\n }\n } catch (error) {\n console.error('Mining error:', error);\n // Continue mining even if a single block fails\n }\n }, miningInterval);\n\n console.log(`Mining started with ${miningInterval}ms interval`);\n }\n\n /**\n * Stop automatic block mining\n */\n async stopMining(): Promise<void> {\n if (!this.miningStatus.isRunning) {\n throw new NodeError('Mining is not running', 'MINING_NOT_RUNNING');\n }\n\n if (this.miningTimer) {\n clearInterval(this.miningTimer);\n this.miningTimer = null;\n }\n\n this.miningStatus = {\n ...this.miningStatus,\n isRunning: false,\n startTime: undefined,\n };\n\n console.log('Mining stopped');\n }\n\n /**\n * Change mining interval (stops and restarts mining with new interval)\n */\n async setMiningInterval(interval: number): Promise<void> {\n if (interval < 100) {\n throw new NodeError(\n 'Mining interval must be at least 100ms',\n 'INVALID_INTERVAL'\n );\n }\n\n const wasRunning = this.miningStatus.isRunning;\n\n if (wasRunning) {\n await this.stopMining();\n }\n\n // Update the status interval\n this.miningStatus = {\n ...this.miningStatus,\n interval,\n };\n\n if (wasRunning) {\n await this.startMining(interval);\n }\n\n console.log(`Mining interval set to ${interval}ms`);\n }\n\n /**\n * Mine a specific number of blocks immediately\n */\n async mine(blocks: number = 1): Promise<void> {\n if (!this.isRunning()) {\n throw new NodeError(\n 'Server must be running to mine blocks',\n 'SERVER_NOT_RUNNING'\n );\n }\n\n if (!this.testClient) {\n const { createTestClient, http } = await import('cive');\n this.testClient = createTestClient({\n transport: http(`http://localhost:${this.config.coreRpcPort}`, {\n timeout: 60_000,\n }),\n });\n }\n\n try {\n // mine({ blocks }) advances the chain by N empty blocks (no tx packing).\n // Useful after packMine()/test_generateOneBlock to satisfy the deferred\n // execution epoch requirement. With devPackTxImmediately:false it never\n // includes pending transactions on its own.\n await this.testClient.mine({ blocks });\n this.miningStatus = {\n ...this.miningStatus,\n blocksMined: (this.miningStatus.blocksMined || 0) + blocks,\n };\n console.log(`Mined ${blocks} empty block(s)`);\n } catch (error) {\n throw new NodeError(\n `Failed to mine blocks: ${error instanceof Error ? error.message : String(error)}`,\n 'MINING_ERROR',\n 'core',\n { blocks, originalError: error }\n );\n }\n }\n\n /**\n * Pack and mine: calls test_generateOneBlock (mine({ numTxs:1 })) which\n * forces pending eSpace/Core transactions into a block. Each call\n * internally generates deferredStateEpochCount (default 5) blocks.\n *\n * This is the ONLY way to include eSpace (EVM) transactions — mine({ blocks })\n * skips the txpool for eSpace. Uses a long timeout because\n * test_generateOneBlock can take several seconds on slow machines.\n */\n async packMine(): Promise<void> {\n if (!this.isRunning()) {\n throw new NodeError(\n 'Server must be running to mine blocks',\n 'SERVER_NOT_RUNNING'\n );\n }\n\n // Use a separate client with a generous timeout for this slow operation\n const { createTestClient, http } = await import('cive');\n const packClient = createTestClient({\n transport: http(`http://localhost:${this.config.coreRpcPort}`, {\n timeout: 120_000,\n }),\n });\n\n // Block the auto-miner interval so it does not fire a concurrent mining RPC\n // that would crash xcfx while test_generateOneBlock is running.\n this._packMining = true;\n try {\n await packClient.mine({ numTxs: 1 });\n this.miningStatus = {\n ...this.miningStatus,\n blocksMined: (this.miningStatus.blocksMined || 0) + 5, // generates 5 blocks internally\n };\n console.log('Pack-mined: 5 blocks generated, pending txs included');\n } catch (error) {\n throw new NodeError(\n `Failed to pack-mine: ${error instanceof Error ? error.message : String(error)}`,\n 'MINING_ERROR',\n 'core',\n { originalError: error }\n );\n } finally {\n this._packMining = false;\n }\n }\n\n /**\n * Get current mining status\n */\n getMiningStatus(): MiningStatus {\n return { ...this.miningStatus };\n }\n\n // ===== FAUCET METHODS =====\n\n /**\n * Get the faucet/mining account (dedicated mining account with separate derivation path)\n * This account receives mining rewards and serves as the faucet\n * Derivation paths: Core=m/44'/503'/1'/0/0, EVM=m/44'/60'/1'/0/0\n */\n getFaucetAccount(): AccountInfo {\n if (!this.miningAccount) {\n throw new NodeError(\n 'Mining account not available. Server must be started first.',\n 'NO_MINING_ACCOUNT'\n );\n }\n return this.miningAccount;\n }\n\n /**\n * Fund a Core Space account using the faucet account\n */\n async fundCoreAccount(\n targetAddress: string,\n amount: string\n ): Promise<string> {\n if (!this.isRunning()) {\n throw new NodeError(\n 'Server must be running to fund accounts',\n 'SERVER_NOT_RUNNING'\n );\n }\n\n const faucetAccount = this.getFaucetAccount();\n\n try {\n // Create wallet client for the faucet account\n const { createWalletClient, http } = await import('cive');\n const { privateKeyToAccount } = await import('cive/accounts');\n\n const account = privateKeyToAccount(\n faucetAccount.privateKey as `0x${string}`,\n {\n networkId: this.config.chainId || 1,\n }\n );\n\n const walletClient = createWalletClient({\n account,\n chain:\n (this.config.chainId || 1) === 1029\n ? {\n id: 1029,\n name: 'Conflux Core',\n nativeCurrency: {\n name: 'Conflux',\n symbol: 'CFX',\n decimals: 18,\n },\n rpcUrls: {\n default: {\n http: [`http://localhost:${this.config.coreRpcPort}`],\n },\n },\n }\n : {\n id: this.config.chainId || 1,\n name: 'Conflux Core Testnet',\n nativeCurrency: {\n name: 'Conflux',\n symbol: 'CFX',\n decimals: 18,\n },\n rpcUrls: {\n default: {\n http: [`http://localhost:${this.config.coreRpcPort}`],\n },\n },\n },\n transport: http(`http://localhost:${this.config.coreRpcPort}`),\n });\n\n const { parseCFX } = await import('cive');\n\n const hash = await walletClient.sendTransaction({\n account,\n to: targetAddress as `cfx:${string}`,\n value: parseCFX(amount),\n });\n\n console.log(\n `Funded Core account ${targetAddress} with ${amount} CFX. TX: ${hash}`\n );\n return hash;\n } catch (error) {\n throw new NodeError(\n `Failed to fund Core account: ${error instanceof Error ? error.message : String(error)}`,\n 'FAUCET_ERROR',\n 'core',\n {\n targetAddress,\n amount,\n faucetAccount: faucetAccount.coreAddress,\n originalError: error,\n }\n );\n }\n }\n\n /**\n * Fund an eSpace account from the Core-Space faucet/mining account.\n *\n * Funds ALWAYS originate from the Core-Space faucet wallet (which accumulates\n * mining rewards). For eSpace (0x…) targets the transfer is routed through the\n * Conflux internal cross-chain bridge contract (0x0888…0006 / transferEVM),\n * which locks CFX on Core and mints it on eSpace — no separate eSpace balance is\n * needed on the faucet account.\n */\n async fundEvmAccount(targetAddress: string, amount: string): Promise<string> {\n if (!this.isRunning()) {\n throw new NodeError(\n 'Server must be running to fund accounts',\n 'SERVER_NOT_RUNNING'\n );\n }\n\n const faucetAccount = this.getFaucetAccount();\n\n try {\n const { createWalletClient, http, parseCFX } = await import('cive');\n const { privateKeyToAccount } = await import('cive/accounts');\n const { hexAddressToBase32, encodeFunctionData, defineChain } =\n await import('cive/utils');\n\n const chainId = this.config.chainId || 2029;\n const chain = defineChain({\n id: chainId,\n name: 'Conflux Core Local',\n nativeCurrency: { decimals: 18, name: 'Conflux', symbol: 'CFX' },\n rpcUrls: {\n default: { http: [`http://localhost:${this.config.coreRpcPort}`] },\n },\n });\n\n const account = privateKeyToAccount(\n faucetAccount.privateKey as `0x${string}`,\n { networkId: chainId }\n );\n\n const walletClient = createWalletClient({\n account,\n chain,\n transport: http(`http://localhost:${this.config.coreRpcPort}`),\n });\n\n // Internal cross-chain bridge contract on Core Space\n const bridgeAddress = hexAddressToBase32({\n hexAddress: '0x0888000000000000000000000000000000000006',\n networkId: chainId,\n });\n\n const hash = await walletClient.sendTransaction({\n account,\n chain,\n to: bridgeAddress,\n value: parseCFX(amount),\n data: encodeFunctionData({\n abi: [\n {\n type: 'function',\n name: 'transferEVM',\n inputs: [{ name: 'to', type: 'bytes20' }],\n outputs: [{ name: 'output', type: 'bytes' }],\n stateMutability: 'payable',\n },\n ],\n functionName: 'transferEVM',\n args: [targetAddress as `0x${string}`],\n }),\n });\n\n console.log(\n `Funded eSpace account ${targetAddress} with ${amount} CFX via Core→eSpace bridge. TX: ${hash}`\n );\n return hash;\n } catch (error) {\n throw new NodeError(\n `Failed to fund eSpace account: ${error instanceof Error ? error.message : String(error)}`,\n 'FAUCET_ERROR',\n 'evm',\n {\n targetAddress,\n amount,\n faucetCoreAddress: faucetAccount.coreAddress,\n originalError: error,\n }\n );\n }\n }\n\n /**\n * Fund both Core and eSpace accounts for the same private key\n */\n async fundDualChainAccount(\n privateKey: string,\n coreAmount: string,\n evmAmount: string\n ): Promise<{\n coreHash: string;\n evmHash: string;\n coreAddress: string;\n evmAddress: string;\n }> {\n // Create accounts from private key\n const { privateKeyToAccount } = await import('cive/accounts');\n const { privateKeyToAccount: privateKeyToEvmAccount } = await import(\n 'viem/accounts'\n );\n\n const coreAccount = privateKeyToAccount(privateKey as `0x${string}`, {\n networkId: this.config.chainId || 1,\n });\n const evmAccount = privateKeyToEvmAccount(privateKey as `0x${string}`);\n\n // Fund both accounts\n const [coreHash, evmHash] = await Promise.all([\n this.fundCoreAccount(coreAccount.address, coreAmount),\n this.fundEvmAccount(evmAccount.address, evmAmount),\n ]);\n\n return {\n coreHash,\n evmHash,\n coreAddress: coreAccount.address,\n evmAddress: evmAccount.address,\n };\n }\n\n /**\n * Check faucet account balances on both chains\n */\n async getFaucetBalances(): Promise<FaucetBalances> {\n if (!this.isRunning()) {\n throw new NodeError(\n 'Server must be running to check balances',\n 'SERVER_NOT_RUNNING'\n );\n }\n\n const faucetAccount = this.getFaucetAccount();\n\n try {\n const [core, evm] = await Promise.all([\n this.getCoreBalance(faucetAccount.coreAddress),\n this.getEvmBalance(faucetAccount.evmAddress),\n ]);\n\n return { core, evm };\n } catch (error) {\n throw new NodeError(\n `Failed to get faucet balances: ${error instanceof Error ? error.message : String(error)}`,\n 'BALANCE_CHECK_ERROR',\n undefined,\n { faucetAccount, originalError: error }\n );\n }\n }\n\n /**\n * Check Core Space balance\n */\n private async getCoreBalance(address: string): Promise<string> {\n const { createPublicClient, http, formatCFX } = await import('cive');\n\n const publicClient = createPublicClient({\n chain:\n this.config.chainId === 1029\n ? {\n id: 1029,\n name: 'Conflux Core',\n nativeCurrency: { name: 'Conflux', symbol: 'CFX', decimals: 18 },\n rpcUrls: {\n default: {\n http: [`http://localhost:${this.config.coreRpcPort}`],\n },\n },\n }\n : {\n id: 1,\n name: 'Conflux Core Testnet',\n nativeCurrency: { name: 'Conflux', symbol: 'CFX', decimals: 18 },\n rpcUrls: {\n default: {\n http: [`http://localhost:${this.config.coreRpcPort}`],\n },\n },\n },\n transport: http(`http://localhost:${this.config.coreRpcPort}`),\n });\n\n const balance = await publicClient.getBalance({\n address: address as `cfx:${string}`,\n });\n return formatCFX(balance);\n }\n\n /**\n * Check eSpace balance\n */\n private async getEvmBalance(address: string): Promise<string> {\n const { createPublicClient, http, formatEther } = await import('viem');\n\n const publicClient = createPublicClient({\n chain: {\n id: this.config.evmChainId || 71,\n name: 'Conflux eSpace Local',\n nativeCurrency: { name: 'Conflux', symbol: 'CFX', decimals: 18 },\n rpcUrls: {\n default: { http: [`http://localhost:${this.config.evmRpcPort}`] },\n },\n },\n transport: http(`http://localhost:${this.config.evmRpcPort}`),\n });\n\n const balance = await publicClient.getBalance({\n address: address as `0x${string}`,\n });\n return formatEther(balance);\n }\n\n /**\n * Get Ethereum-compatible admin address derived from mnemonic\n * Uses the standard Ethereum derivation path: m/44'/60'/0'/0/0\n * This address will match what MetaMask and other Ethereum wallets derive\n */\n getEthereumAdminAddress(): string {\n // Use core wallet module for account derivation\n const account = deriveAccount(\n this.mnemonic,\n 0,\n this.config.chainId || 2029\n );\n\n return account.evmAddress.toLowerCase();\n }\n\n /**\n * Set up cleanup handlers for graceful shutdown\n */\n private setupCleanupHandlers(): void {\n const cleanup = async () => {\n if (this.isRunning()) {\n console.log('Shutting down Conflux development node...');\n await this.stop();\n }\n };\n\n process.on('SIGINT', cleanup);\n process.on('SIGTERM', cleanup);\n process.on('exit', cleanup);\n }\n}\n","/*\n * Copyright 2025 Conflux DevKit Team\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Types for DevNode Plugin\n * Re-exports types needed from @cfxdevkit/core\n */\n\n// Node Configuration\nexport interface NodeConfig {\n chainId?: number;\n evmChainId?: number;\n coreRpcPort?: number;\n evmRpcPort?: number;\n wsPort?: number; // Core Space WebSocket port\n evmWsPort?: number; // eSpace WebSocket port (default: 8546)\n dataDir?: string;\n mnemonic?: string;\n logging?: boolean;\n}\n\nexport interface ServerConfig extends NodeConfig {\n jsonrpcHttpPort?: number;\n jsonrpcHttpEthPort?: number;\n jsonrpcWsPort?: number;\n jsonrpcWsEthPort?: number;\n log?: boolean;\n accounts?: number;\n balance?: string;\n miningAuthor?: string; // Mining rewards recipient (Core address)\n // devPackTxImmediately should always be false - mining is managed via testClient\n devPackTxImmediately?: boolean;\n}\n\n// Start Options\nexport interface StartOptions {\n mining?: boolean;\n waitForBlocks?: boolean;\n}\n\n// Mining Status\nexport interface MiningStatus {\n isRunning: boolean;\n interval?: number;\n blocksMined?: number;\n blocksGenerated?: number;\n startTime?: Date;\n}\n\n// Account Info\nexport interface AccountInfo {\n index: number;\n coreAddress: string;\n evmAddress: string;\n privateKey: string;\n evmPrivateKey?: string;\n coreBalance?: string;\n evmBalance?: string;\n path?: string;\n evmPath?: string;\n mnemonic?: string;\n}\n\n// Faucet Balances\nexport interface FaucetBalances {\n core: string;\n evm: string;\n}\n\n// Chain Balances\nexport interface ChainBalances {\n core: string;\n evm: string;\n}\n\n// Server Status\nexport type ServerStatus =\n | 'stopped'\n | 'starting'\n | 'running'\n | 'stopping'\n | 'error';\n\n// Chain Type\nexport type ChainType = 'core' | 'evm';\n\n// Node Error Interface\nexport interface ConfluxNodeError {\n code: string;\n chain?: ChainType;\n context?: Record<string, unknown>;\n}\n\n// Node Error Class\nexport class NodeError extends Error implements ConfluxNodeError {\n public readonly code: string;\n public readonly chain?: ChainType;\n public readonly context?: Record<string, unknown>;\n\n constructor(\n message: string,\n code: string,\n chain?: ChainType,\n context?: Record<string, unknown>\n ) {\n super(message);\n this.name = 'NodeError';\n this.code = code;\n this.chain = chain;\n this.context = context;\n }\n}\n","/*\n * Copyright 2025 Conflux DevKit Team\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * DevNode Plugin - Optional @xcfx/node integration for local development\n *\n * This plugin extends DevKit with local node functionality:\n * - Local node lifecycle (start/stop)\n * - Mining controls (start/stop/mine)\n * - Faucet operations (fund accounts)\n * - Development-only features\n *\n * Usage:\n * ```typescript\n * import { DevKit } from '@conflux-devkit/node';\n * import { devNodePlugin } from '@cfxdevkit/devnode';\n *\n * // Production: Just use DevKit\n * const devkit = new DevKit({ coreRpc: '...', evmRpc: '...' });\n *\n * // Development: Use plugin for local node\n * const devkitWithNode = devNodePlugin.extendDevKit(new DevKit());\n * await devkitWithNode.startNode();\n * ```\n */\n\nimport { ServerManager } from './server-manager.js';\nimport type {\n AccountInfo,\n FaucetBalances,\n MiningStatus,\n NodeConfig,\n StartOptions,\n} from './types.js';\n\n/**\n * Base DevKit interface (subset needed for plugin)\n */\nexport interface BaseDevKit {\n getConfig(): NodeConfig;\n getRpcUrls(): { core: string; evm: string };\n}\n\n/**\n * Extended DevKit with local node capabilities\n */\nexport class DevKitWithDevNode {\n private server: ServerManager;\n private baseDevKit: BaseDevKit;\n\n constructor(baseDevKit: BaseDevKit, config: NodeConfig) {\n this.baseDevKit = baseDevKit;\n this.server = new ServerManager(config);\n }\n\n // Delegate to base DevKit\n getConfig(): NodeConfig {\n return this.baseDevKit.getConfig();\n }\n\n getRpcUrls(): { core: string; evm: string } {\n return this.baseDevKit.getRpcUrls();\n }\n\n // Node lifecycle methods\n async startNode(options: Partial<StartOptions> = {}): Promise<void> {\n await this.server.start();\n\n // Start mining if requested (default: true)\n if (options.mining !== false) {\n await this.server.startMining();\n }\n }\n\n async stopNode(): Promise<void> {\n await this.server.stop();\n }\n\n // Mining methods\n async startMining(): Promise<void> {\n await this.server.startMining();\n }\n\n async stopMining(): Promise<void> {\n await this.server.stopMining();\n }\n\n async mine(blocks: number = 1): Promise<void> {\n await this.server.mine(blocks);\n }\n\n getMiningStatus(): MiningStatus {\n return this.server.getMiningStatus();\n }\n\n async setMiningInterval(interval: number): Promise<void> {\n await this.server.setMiningInterval(interval);\n }\n\n // Faucet methods\n async getFaucetBalances(): Promise<FaucetBalances> {\n return await this.server.getFaucetBalances();\n }\n\n getFaucetAccount(): AccountInfo {\n return this.server.getFaucetAccount();\n }\n\n async fundAccount(\n address: string,\n amount: string,\n chain: 'core' | 'evm'\n ): Promise<string> {\n if (chain === 'core') {\n return await this.server.fundCoreAccount(address, amount);\n } else {\n return await this.server.fundEvmAccount(address, amount);\n }\n }\n\n // Account methods\n async addAccount(): Promise<AccountInfo> {\n return await this.server.addAccount();\n }\n\n getAccounts(): AccountInfo[] {\n return this.server.getAccounts();\n }\n\n // Utility methods\n getEthereumAdminAddress(): string {\n return this.server.getEthereumAdminAddress();\n }\n\n getServerStatus(): string {\n return this.server.getStatus();\n }\n\n isNodeRunning(): boolean {\n return this.server.isRunning();\n }\n}\n\n/**\n * Plugin interface\n */\nexport interface DevNodePlugin {\n name: 'devnode';\n version: string;\n extendDevKit(devkit: BaseDevKit, config: NodeConfig): DevKitWithDevNode;\n}\n\n/**\n * Default plugin export\n */\nexport const devNodePlugin: DevNodePlugin = {\n name: 'devnode',\n version: '0.1.0',\n\n extendDevKit(devkit: BaseDevKit, config: NodeConfig): DevKitWithDevNode {\n return new DevKitWithDevNode(devkit, config);\n },\n};\n"],"mappings":"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","names":["privateKeyToAccount","privateKeyToEvmAccount"]}
|
|
1
|
+
{"version":3,"sources":["../src/server-manager.ts","../src/types.ts","../src/plugin.ts"],"sourcesContent":["/*\n * Copyright 2025 Conflux DevKit Team\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// Server Manager for xcfx/node lifecycle management\n// Based on proven patterns from DevKit CLI, adapted for unified interface\n\nimport type { ChildProcess } from 'node:child_process';\nimport { randomBytes } from 'node:crypto';\nimport { promises as fs } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { defaultNetworkSelector } from '@cfxdevkit/core/config';\nimport {\n generateMnemonic as coreGenerateMnemonic,\n deriveAccount,\n deriveAccounts,\n deriveFaucetAccount,\n} from '@cfxdevkit/core/wallet';\nimport { createServer } from '@xcfx/node';\nimport type { TestClient } from 'cive';\nimport { privateKeyToAccount } from 'cive/accounts';\nimport { privateKeyToAccount as privateKeyToEvmAccount } from 'viem/accounts';\nimport {\n type AccountInfo,\n type FaucetBalances,\n type MiningStatus,\n NodeError,\n type ServerConfig,\n type ServerStatus,\n} from './types.js';\n\n// Port configuration\nconst DEFAULT_CORE_RPC_PORT = 12537;\nconst DEFAULT_EVM_RPC_PORT = 8545;\nconst DEFAULT_WS_PORT = 12536;\nconst DEFAULT_EVM_WS_PORT = 8546;\n\n/**\n * Server Manager for xcfx/node lifecycle management\n * Handles starting, stopping, and managing the Conflux development node\n */\nexport class ServerManager {\n private nodeProcess: ChildProcess | null = null;\n private server: Awaited<ReturnType<typeof createServer>> | null = null;\n private config: ServerConfig;\n private status: ServerStatus = 'stopped';\n private accounts: AccountInfo[] = [];\n private mnemonic: string = '';\n private miningAccount: AccountInfo | null = null;\n private miningStatus: MiningStatus;\n private miningTimer: NodeJS.Timeout | null = null;\n private testClient: TestClient | null = null;\n /** True while packMine() is running — auto-miner skips its tick to avoid concurrent mining RPCs. */\n private _packMining = false;\n\n constructor(config: ServerConfig) {\n this.config = {\n ...config,\n coreRpcPort: config.coreRpcPort || DEFAULT_CORE_RPC_PORT,\n evmRpcPort: config.evmRpcPort || DEFAULT_EVM_RPC_PORT,\n wsPort: config.wsPort || DEFAULT_WS_PORT,\n evmWsPort: config.evmWsPort || DEFAULT_EVM_WS_PORT,\n chainId: config.chainId || 2029, // Local Core chain ID\n evmChainId: config.evmChainId || 2030, // Local eSpace chain ID\n accounts: config.accounts || 10,\n balance: config.balance || '1000000',\n mnemonic: config.mnemonic,\n // Following xcfx-node test pattern: devPackTxImmediately should be false\n // All mining is managed via testClient.mine() calls\n devPackTxImmediately: false,\n };\n\n // Initialize mining status\n this.miningStatus = {\n isRunning: false,\n interval: 1000,\n blocksMined: 0,\n startTime: undefined,\n };\n\n // Generate or use provided mnemonic and immediately generate accounts\n // This ensures accounts are always available regardless of node state\n this.mnemonic = this.config.mnemonic || coreGenerateMnemonic(128);\n this.generateAccountsSync();\n this.generateMiningAccountSync();\n }\n\n /**\n * Return a sanitized copy of the server config with sensitive fields redacted.\n */\n private redactConfig(config: ServerConfig): Partial<ServerConfig> {\n type SafeConfig = Partial<ServerConfig> & {\n mnemonic?: string;\n accounts?: unknown;\n };\n const safe: SafeConfig = { ...(config as SafeConfig) };\n if (safe.mnemonic) safe.mnemonic = '[REDACTED]';\n // remove accounts and secrets to avoid leaking private keys\n if (safe.accounts) delete safe.accounts;\n return safe;\n }\n\n /**\n * Start the Conflux development node\n */\n async start(): Promise<void> {\n if (this.status === 'running') {\n throw new NodeError(\n 'Server is already running',\n 'SERVER_ALREADY_RUNNING'\n );\n }\n\n try {\n this.status = 'starting';\n\n // Mnemonic and accounts are already generated in constructor\n // Mining account is also already generated in constructor\n\n // Ensure data directory exists with proper permissions\n const dataDir =\n this.config.dataDir || join(homedir(), '.conflux-devkit', 'data');\n try {\n await fs.mkdir(dataDir, { recursive: true, mode: 0o755 });\n } catch (error) {\n console.warn('Failed to create data directory:', error);\n // Continue anyway, might still work if directory exists\n }\n\n // Create server instance with configuration\n const serverConfig = {\n // Correct property names according to @xcfx/node API\n jsonrpcHttpPort: this.config.coreRpcPort,\n jsonrpcHttpEthPort: this.config.evmRpcPort,\n jsonrpcWsPort: this.config.wsPort,\n jsonrpcWsEthPort: this.config.evmWsPort,\n chainId: this.config.chainId,\n evmChainId: this.config.evmChainId,\n // Specify data directory to avoid permission issues\n confluxDataDir: dataDir,\n // Genesis accounts configuration - include mining account for initial funding\n genesisSecrets: [\n ...this.accounts.map((acc) => acc.privateKey),\n this.requireMiningAccount().privateKey, // Add mining account to get initial funds\n ],\n genesisEvmSecrets: [\n ...this.accounts.map((acc) => acc.evmPrivateKey || acc.privateKey),\n this.requireMiningAccount().evmPrivateKey ||\n this.requireMiningAccount().privateKey, // Add mining account EVM key\n ],\n // Mining configuration - use config value or default to mining account address\n // 'auto' is a sentinel value meaning \"use the derived mining account address\"\n miningAuthor:\n this.config.miningAuthor && this.config.miningAuthor !== 'auto'\n ? this.config.miningAuthor\n : this.miningAccount?.coreAddress,\n // Following the reference test (xcfx-node/evmManualBlockGeneration.test.ts):\n // devPackTxImmediately: false — eSpace txs are ONLY packed by mine({ numTxs }),\n // never by mine({ blocks }). This flag only affects Core space.\n devPackTxImmediately: false,\n log: this.config.logging || false,\n // Genesis block initialization can take time; pass a generous timeout so\n // the native binary doesn't abort the startup handshake prematurely.\n timeout: 60000,\n retryInterval: 300,\n };\n\n this.server = await createServer(serverConfig);\n\n // Start the server - this is required!\n await this.server.start();\n\n this.status = 'running';\n\n // Update network selector with local chain URLs and notify it of node start\n defaultNetworkSelector.updateLocalChainUrls(\n this.config.coreRpcPort || DEFAULT_CORE_RPC_PORT,\n this.config.evmRpcPort || DEFAULT_EVM_RPC_PORT,\n this.config.wsPort || DEFAULT_WS_PORT\n );\n defaultNetworkSelector.onNodeStart(2029, 2030); // Core local, eSpace local\n\n // Set up cleanup handlers\n this.setupCleanupHandlers();\n\n // Auto-start mining at 2s intervals using mine({ numTxs:1 }).\n // With devPackTxImmediately:false (our config) mine({ blocks }) creates\n // empty blocks only; mine({ numTxs }) is the only call that packs pending\n // Core-Space and eSpace transactions, so we use it here so that user\n // wallet transactions are confirmed within one mining interval.\n await this.startMining(2000);\n } catch (error) {\n this.status = 'error';\n throw new NodeError(\n `Failed to start server: ${error instanceof Error ? error.message : String(error)}`,\n 'SERVER_START_ERROR',\n undefined,\n {\n config: this.redactConfig(this.config as ServerConfig),\n originalError: error,\n }\n );\n }\n }\n\n /**\n * Stop the Conflux development node\n */\n async stop(): Promise<void> {\n if (this.status === 'stopped') {\n return;\n }\n\n try {\n this.status = 'stopping';\n\n // Stop mining if running\n if (this.miningStatus.isRunning) {\n try {\n await this.stopMining();\n } catch (error) {\n console.warn('Failed to stop mining during server shutdown:', error);\n }\n }\n\n if (this.server) {\n await this.server.stop();\n this.server = null;\n }\n\n if (this.nodeProcess) {\n this.nodeProcess.kill('SIGTERM');\n this.nodeProcess = null;\n }\n\n // Clean up test client\n this.testClient = null;\n\n this.status = 'stopped';\n\n // Notify network selector that node has stopped\n defaultNetworkSelector.onNodeStop();\n } catch (error) {\n this.status = 'error';\n throw new NodeError(\n `Failed to stop server: ${error instanceof Error ? error.message : String(error)}`,\n 'SERVER_STOP_ERROR',\n undefined,\n { originalError: error }\n );\n }\n }\n\n /**\n * Restart the Conflux development node\n */\n async restart(): Promise<void> {\n await this.stop();\n await this.start();\n }\n\n /**\n * Get current server status\n */\n getStatus(): ServerStatus {\n return this.status;\n }\n\n /**\n * Get comprehensive node status including mining\n */\n getNodeStatus() {\n return {\n server: this.status,\n mining: this.getMiningStatus(),\n config: this.redactConfig(this.config as ServerConfig),\n accounts: this.accounts.length,\n rpcUrls: this.getRpcUrls(),\n };\n }\n\n /**\n * Check if server is running\n */\n isRunning(): boolean {\n return this.status === 'running';\n }\n\n /**\n * Get server configuration\n */\n getConfig(): ServerConfig {\n // Return a sanitized config to avoid exposing mnemonic/privkeys in logs or API\n return {\n ...(this.redactConfig(this.config as ServerConfig) as ServerConfig),\n };\n }\n\n /**\n * Get generated accounts\n */\n getAccounts(): AccountInfo[] {\n return [...this.accounts];\n }\n\n /**\n * Get the mnemonic phrase\n */\n getMnemonic(): string {\n return this.mnemonic;\n }\n\n /**\n * Get RPC URLs\n */\n getRpcUrls(): {\n core: string;\n evm: string;\n coreWs: string;\n evmWs: string;\n ws: string;\n } {\n const coreWs = `ws://localhost:${this.config.wsPort}`;\n return {\n core: `http://localhost:${this.config.coreRpcPort}`,\n evm: `http://localhost:${this.config.evmRpcPort}`,\n coreWs,\n evmWs: `ws://localhost:${this.config.evmWsPort}`,\n ws: coreWs, // backward-compat alias for Core WS\n };\n }\n\n /**\n * Add a new account to the server\n */\n async addAccount(privateKey?: string): Promise<AccountInfo> {\n const accountPrivateKey =\n privateKey || `0x${randomBytes(32).toString('hex')}`;\n\n const coreAccount = privateKeyToAccount(\n accountPrivateKey as `0x${string}`,\n {\n networkId: this.config.chainId || 1,\n }\n );\n const evmAccount = privateKeyToEvmAccount(\n accountPrivateKey as `0x${string}`\n );\n\n const accountInfo: AccountInfo = {\n index: this.accounts.length,\n privateKey: accountPrivateKey,\n coreAddress: coreAccount.address,\n evmAddress: evmAccount.address,\n mnemonic: this.mnemonic,\n path: `m/44'/503'/0'/0/${this.accounts.length}`,\n };\n\n this.accounts.push(accountInfo);\n\n // Note: @xcfx/node automatically funds genesis accounts\n // Additional funding would require separate RPC calls to the running node\n\n return accountInfo;\n }\n\n /**\n * Fund an account with CFX\n * Note: @xcfx/node doesn't provide direct funding methods.\n * This would require using RPC calls to send transactions from funded genesis accounts.\n */\n async fundAccount(\n address: string,\n amount: string,\n chainType: 'core' | 'evm' = 'core'\n ): Promise<void> {\n if (!this.isRunning() || !this.server) {\n throw new NodeError('Server is not running', 'SERVER_NOT_RUNNING');\n }\n\n // This functionality would need to be implemented using RPC calls\n // to transfer funds from genesis accounts to the target address\n throw new NodeError(\n 'Direct account funding not implemented. Genesis accounts are automatically funded by @xcfx/node.',\n 'NOT_IMPLEMENTED',\n chainType,\n { address, amount, chainType }\n );\n }\n\n /**\n * Set next block timestamp (for testing)\n * Note: @xcfx/node doesn't provide direct timestamp control.\n * Use createTestClient from 'cive' and connect to the running node's RPC.\n */\n async setNextBlockTimestamp(timestamp: number): Promise<void> {\n if (!this.isRunning() || !this.server) {\n throw new NodeError('Server is not running', 'SERVER_NOT_RUNNING');\n }\n\n // This functionality would need to be implemented using createTestClient\n // from 'cive' library connected to the running server's RPC endpoint\n throw new NodeError(\n 'Direct timestamp control not implemented. Use createTestClient from cive to control block timestamps via RPC.',\n 'NOT_IMPLEMENTED',\n 'core',\n { timestamp }\n );\n }\n\n /**\n * Get server logs\n * Note: @xcfx/node doesn't provide direct log access.\n * Logs would need to be captured during server startup or accessed via system logs.\n */\n async getLogs(lines: number = 50): Promise<string[]> {\n if (!this.isRunning() || !this.server) {\n throw new NodeError('Server is not running', 'SERVER_NOT_RUNNING');\n }\n\n // @xcfx/node doesn't provide log access methods\n // This would need to be implemented by capturing stdout/stderr during server startup\n // or by accessing system logs where the node process writes its output\n return [\n 'Log access not implemented for @xcfx/node.',\n 'Consider capturing server output during startup or checking system logs.',\n `Requested ${lines} lines of logs.`,\n ];\n }\n\n /**\n * Save server configuration to file\n */\n async saveConfig(filepath: string): Promise<void> {\n try {\n // Save a sanitized config file by redacting the mnemonic and removing private data\n const configData = {\n ...this.redactConfig(this.config as ServerConfig),\n mnemonic: '[REDACTED]',\n accounts: this.accounts.map((a) => ({\n index: a.index,\n coreAddress: a.coreAddress,\n evmAddress: a.evmAddress,\n path: a.path,\n })),\n rpcUrls: this.getRpcUrls(),\n };\n\n await fs.writeFile(filepath, JSON.stringify(configData, null, 2), 'utf8');\n } catch (error) {\n throw new NodeError(\n `Failed to save config: ${error instanceof Error ? error.message : String(error)}`,\n 'CONFIG_SAVE_ERROR',\n 'core',\n { filepath, originalError: error }\n );\n }\n }\n\n /**\n * Load server configuration from file\n */\n static async loadConfig(filepath: string): Promise<ServerConfig> {\n try {\n const configData = await fs.readFile(filepath, 'utf8');\n return JSON.parse(configData);\n } catch (error) {\n throw new NodeError(\n `Failed to load config: ${error instanceof Error ? error.message : String(error)}`,\n 'CONFIG_LOAD_ERROR',\n 'core',\n { filepath, originalError: error }\n );\n }\n }\n\n /**\n * Generate accounts from mnemonic using core wallet module\n * Called from constructor to ensure accounts are always available\n */\n private generateAccountsSync(): void {\n // Use core wallet module for account derivation\n const derivedAccounts = deriveAccounts(this.mnemonic, {\n count: this.config.accounts || 10,\n coreNetworkId: this.config.chainId || 2029,\n });\n\n this.accounts = derivedAccounts.map((account) => ({\n index: account.index,\n privateKey: account.corePrivateKey, // Keep Conflux private key as primary\n coreAddress: account.coreAddress,\n evmAddress: account.evmAddress,\n mnemonic: this.mnemonic,\n path: account.paths.core,\n // Store additional EVM-specific info\n evmPrivateKey: account.evmPrivateKey,\n evmPath: account.paths.evm,\n }));\n }\n\n /**\n * Generate dedicated mining account (separate from genesis accounts)\n * This account will receive mining rewards and serve as the faucet\n * Called synchronously from constructor to ensure always available\n */\n private generateMiningAccountSync(): void {\n // Use core wallet module for faucet/mining account derivation\n const faucetAccount = deriveFaucetAccount(\n this.mnemonic,\n this.config.chainId || 2029\n );\n\n this.miningAccount = {\n index: -1, // Special index for mining account\n privateKey: faucetAccount.corePrivateKey, // Core/Conflux private key\n coreAddress: faucetAccount.coreAddress,\n evmAddress: faucetAccount.evmAddress,\n mnemonic: this.mnemonic,\n path: faucetAccount.paths.core,\n // Store additional EVM-specific info\n evmPrivateKey: faucetAccount.evmPrivateKey,\n evmPath: faucetAccount.paths.evm,\n };\n\n console.log(\n `Generated mining account: Core=${this.miningAccount.coreAddress}, eSpace=${this.miningAccount.evmAddress}`\n );\n }\n\n /**\n * Returns the mining account, throwing if it has not been initialized.\n * In practice this is always set by generateMiningAccountSync() in the\n * constructor, so the throw is a safety net for unexpected states.\n */\n private requireMiningAccount(): AccountInfo {\n if (!this.miningAccount) {\n throw new Error('Mining account has not been initialized.');\n }\n return this.miningAccount;\n }\n\n // ===== MINING METHODS =====\n\n /**\n * Start automatic block mining using testClient\n * This creates an interval that mines blocks automatically\n * @param interval Mining interval in milliseconds (default: 2000ms)\n */\n async startMining(interval?: number): Promise<void> {\n if (!this.isRunning()) {\n throw new NodeError(\n 'Server must be running to start mining',\n 'SERVER_NOT_RUNNING'\n );\n }\n\n if (this.miningStatus.isRunning) {\n throw new NodeError(\n 'Mining is already running',\n 'MINING_ALREADY_RUNNING'\n );\n }\n\n // Initialize test client if not already created\n if (!this.testClient) {\n const { createTestClient, http } = await import('cive');\n this.testClient = createTestClient({\n transport: http(`http://localhost:${this.config.coreRpcPort}`, {\n timeout: 60_000,\n }),\n });\n }\n\n const miningInterval = interval || 2000; // Default 2s — empty blocks are fast\n\n this.miningStatus = {\n ...this.miningStatus,\n isRunning: true,\n interval: miningInterval,\n startTime: new Date(),\n };\n\n // Start the mining loop\n this.miningTimer = setInterval(async () => {\n try {\n if (this.testClient && !this._packMining) {\n // mine({ numTxs: 1 }) = test_generateOneBlock: packs ALL pending\n // Core-Space and eSpace transactions into a new block and generates\n // deferredStateEpochCount (default 5) blocks for deferred execution.\n // With devPackTxImmediately:false this is the ONLY mining call that\n // includes pending txs; mine({ blocks }) produces empty blocks only.\n await this.testClient.mine({ numTxs: 1 });\n this.miningStatus = {\n ...this.miningStatus,\n blocksMined: (this.miningStatus.blocksMined || 0) + 5,\n };\n }\n } catch (error) {\n console.error('Mining error:', error);\n // Continue mining even if a single block fails\n }\n }, miningInterval);\n\n console.log(`Mining started with ${miningInterval}ms interval`);\n }\n\n /**\n * Stop automatic block mining\n */\n async stopMining(): Promise<void> {\n if (!this.miningStatus.isRunning) {\n throw new NodeError('Mining is not running', 'MINING_NOT_RUNNING');\n }\n\n if (this.miningTimer) {\n clearInterval(this.miningTimer);\n this.miningTimer = null;\n }\n\n this.miningStatus = {\n ...this.miningStatus,\n isRunning: false,\n startTime: undefined,\n };\n\n console.log('Mining stopped');\n }\n\n /**\n * Change mining interval (stops and restarts mining with new interval)\n */\n async setMiningInterval(interval: number): Promise<void> {\n if (interval < 100) {\n throw new NodeError(\n 'Mining interval must be at least 100ms',\n 'INVALID_INTERVAL'\n );\n }\n\n const wasRunning = this.miningStatus.isRunning;\n\n if (wasRunning) {\n await this.stopMining();\n }\n\n // Update the status interval\n this.miningStatus = {\n ...this.miningStatus,\n interval,\n };\n\n if (wasRunning) {\n await this.startMining(interval);\n }\n\n console.log(`Mining interval set to ${interval}ms`);\n }\n\n /**\n * Mine a specific number of blocks immediately\n */\n async mine(blocks: number = 1): Promise<void> {\n if (!this.isRunning()) {\n throw new NodeError(\n 'Server must be running to mine blocks',\n 'SERVER_NOT_RUNNING'\n );\n }\n\n if (!this.testClient) {\n const { createTestClient, http } = await import('cive');\n this.testClient = createTestClient({\n transport: http(`http://localhost:${this.config.coreRpcPort}`, {\n timeout: 60_000,\n }),\n });\n }\n\n try {\n // mine({ blocks }) advances the chain by N empty blocks (no tx packing).\n // Useful after packMine()/test_generateOneBlock to satisfy the deferred\n // execution epoch requirement. With devPackTxImmediately:false it never\n // includes pending transactions on its own.\n await this.testClient.mine({ blocks });\n this.miningStatus = {\n ...this.miningStatus,\n blocksMined: (this.miningStatus.blocksMined || 0) + blocks,\n };\n console.log(`Mined ${blocks} empty block(s)`);\n } catch (error) {\n throw new NodeError(\n `Failed to mine blocks: ${error instanceof Error ? error.message : String(error)}`,\n 'MINING_ERROR',\n 'core',\n { blocks, originalError: error }\n );\n }\n }\n\n /**\n * Pack and mine: calls test_generateOneBlock (mine({ numTxs:1 })) which\n * forces pending eSpace/Core transactions into a block. Each call\n * internally generates deferredStateEpochCount (default 5) blocks.\n *\n * This is the ONLY way to include eSpace (EVM) transactions — mine({ blocks })\n * skips the txpool for eSpace. Uses a long timeout because\n * test_generateOneBlock can take several seconds on slow machines.\n */\n async packMine(): Promise<void> {\n if (!this.isRunning()) {\n throw new NodeError(\n 'Server must be running to mine blocks',\n 'SERVER_NOT_RUNNING'\n );\n }\n\n // Use a separate client with a generous timeout for this slow operation\n const { createTestClient, http } = await import('cive');\n const packClient = createTestClient({\n transport: http(`http://localhost:${this.config.coreRpcPort}`, {\n timeout: 120_000,\n }),\n });\n\n // Block the auto-miner interval so it does not fire a concurrent mining RPC\n // that would crash xcfx while test_generateOneBlock is running.\n this._packMining = true;\n try {\n await packClient.mine({ numTxs: 1 });\n this.miningStatus = {\n ...this.miningStatus,\n blocksMined: (this.miningStatus.blocksMined || 0) + 5, // generates 5 blocks internally\n };\n console.log('Pack-mined: 5 blocks generated, pending txs included');\n } catch (error) {\n throw new NodeError(\n `Failed to pack-mine: ${error instanceof Error ? error.message : String(error)}`,\n 'MINING_ERROR',\n 'core',\n { originalError: error }\n );\n } finally {\n this._packMining = false;\n }\n }\n\n /**\n * Get current mining status\n */\n getMiningStatus(): MiningStatus {\n return { ...this.miningStatus };\n }\n\n // ===== FAUCET METHODS =====\n\n /**\n * Get the faucet/mining account (dedicated mining account with separate derivation path)\n * This account receives mining rewards and serves as the faucet\n * Derivation paths: Core=m/44'/503'/1'/0/0, EVM=m/44'/60'/1'/0/0\n */\n getFaucetAccount(): AccountInfo {\n if (!this.miningAccount) {\n throw new NodeError(\n 'Mining account not available. Server must be started first.',\n 'NO_MINING_ACCOUNT'\n );\n }\n return this.miningAccount;\n }\n\n /**\n * Fund a Core Space account using the faucet account\n */\n async fundCoreAccount(\n targetAddress: string,\n amount: string\n ): Promise<string> {\n if (!this.isRunning()) {\n throw new NodeError(\n 'Server must be running to fund accounts',\n 'SERVER_NOT_RUNNING'\n );\n }\n\n const faucetAccount = this.getFaucetAccount();\n\n try {\n // Create wallet client for the faucet account\n const { createWalletClient, http } = await import('cive');\n const { privateKeyToAccount } = await import('cive/accounts');\n\n const account = privateKeyToAccount(\n faucetAccount.privateKey as `0x${string}`,\n {\n networkId: this.config.chainId || 1,\n }\n );\n\n const walletClient = createWalletClient({\n account,\n chain:\n (this.config.chainId || 1) === 1029\n ? {\n id: 1029,\n name: 'Conflux Core',\n nativeCurrency: {\n name: 'Conflux',\n symbol: 'CFX',\n decimals: 18,\n },\n rpcUrls: {\n default: {\n http: [`http://localhost:${this.config.coreRpcPort}`],\n },\n },\n }\n : {\n id: this.config.chainId || 1,\n name: 'Conflux Core Testnet',\n nativeCurrency: {\n name: 'Conflux',\n symbol: 'CFX',\n decimals: 18,\n },\n rpcUrls: {\n default: {\n http: [`http://localhost:${this.config.coreRpcPort}`],\n },\n },\n },\n transport: http(`http://localhost:${this.config.coreRpcPort}`),\n });\n\n const { parseCFX } = await import('cive');\n\n const hash = await walletClient.sendTransaction({\n account,\n to: targetAddress as `cfx:${string}`,\n value: parseCFX(amount),\n });\n\n console.log(\n `Funded Core account ${targetAddress} with ${amount} CFX. TX: ${hash}`\n );\n return hash;\n } catch (error) {\n throw new NodeError(\n `Failed to fund Core account: ${error instanceof Error ? error.message : String(error)}`,\n 'FAUCET_ERROR',\n 'core',\n {\n targetAddress,\n amount,\n faucetAccount: faucetAccount.coreAddress,\n originalError: error,\n }\n );\n }\n }\n\n /**\n * Fund an eSpace account from the Core-Space faucet/mining account.\n *\n * Funds ALWAYS originate from the Core-Space faucet wallet (which accumulates\n * mining rewards). For eSpace (0x…) targets the transfer is routed through the\n * Conflux internal cross-chain bridge contract (0x0888…0006 / transferEVM),\n * which locks CFX on Core and mints it on eSpace — no separate eSpace balance is\n * needed on the faucet account.\n */\n async fundEvmAccount(targetAddress: string, amount: string): Promise<string> {\n if (!this.isRunning()) {\n throw new NodeError(\n 'Server must be running to fund accounts',\n 'SERVER_NOT_RUNNING'\n );\n }\n\n const faucetAccount = this.getFaucetAccount();\n\n try {\n const { createWalletClient, http, parseCFX } = await import('cive');\n const { privateKeyToAccount } = await import('cive/accounts');\n const { hexAddressToBase32, encodeFunctionData, defineChain } =\n await import('cive/utils');\n\n const chainId = this.config.chainId || 2029;\n const chain = defineChain({\n id: chainId,\n name: 'Conflux Core Local',\n nativeCurrency: { decimals: 18, name: 'Conflux', symbol: 'CFX' },\n rpcUrls: {\n default: { http: [`http://localhost:${this.config.coreRpcPort}`] },\n },\n });\n\n const account = privateKeyToAccount(\n faucetAccount.privateKey as `0x${string}`,\n { networkId: chainId }\n );\n\n const walletClient = createWalletClient({\n account,\n chain,\n transport: http(`http://localhost:${this.config.coreRpcPort}`),\n });\n\n // Internal cross-chain bridge contract on Core Space\n const bridgeAddress = hexAddressToBase32({\n hexAddress: '0x0888000000000000000000000000000000000006',\n networkId: chainId,\n });\n\n const hash = await walletClient.sendTransaction({\n account,\n chain,\n to: bridgeAddress,\n value: parseCFX(amount),\n data: encodeFunctionData({\n abi: [\n {\n type: 'function',\n name: 'transferEVM',\n inputs: [{ name: 'to', type: 'bytes20' }],\n outputs: [{ name: 'output', type: 'bytes' }],\n stateMutability: 'payable',\n },\n ],\n functionName: 'transferEVM',\n args: [targetAddress as `0x${string}`],\n }),\n });\n\n console.log(\n `Funded eSpace account ${targetAddress} with ${amount} CFX via Core→eSpace bridge. TX: ${hash}`\n );\n return hash;\n } catch (error) {\n throw new NodeError(\n `Failed to fund eSpace account: ${error instanceof Error ? error.message : String(error)}`,\n 'FAUCET_ERROR',\n 'evm',\n {\n targetAddress,\n amount,\n faucetCoreAddress: faucetAccount.coreAddress,\n originalError: error,\n }\n );\n }\n }\n\n /**\n * Fund both Core and eSpace accounts for the same private key\n */\n async fundDualChainAccount(\n privateKey: string,\n coreAmount: string,\n evmAmount: string\n ): Promise<{\n coreHash: string;\n evmHash: string;\n coreAddress: string;\n evmAddress: string;\n }> {\n // Create accounts from private key\n const { privateKeyToAccount } = await import('cive/accounts');\n const { privateKeyToAccount: privateKeyToEvmAccount } = await import(\n 'viem/accounts'\n );\n\n const coreAccount = privateKeyToAccount(privateKey as `0x${string}`, {\n networkId: this.config.chainId || 1,\n });\n const evmAccount = privateKeyToEvmAccount(privateKey as `0x${string}`);\n\n // Fund both accounts\n const [coreHash, evmHash] = await Promise.all([\n this.fundCoreAccount(coreAccount.address, coreAmount),\n this.fundEvmAccount(evmAccount.address, evmAmount),\n ]);\n\n return {\n coreHash,\n evmHash,\n coreAddress: coreAccount.address,\n evmAddress: evmAccount.address,\n };\n }\n\n /**\n * Check faucet account balances on both chains\n */\n async getFaucetBalances(): Promise<FaucetBalances> {\n if (!this.isRunning()) {\n throw new NodeError(\n 'Server must be running to check balances',\n 'SERVER_NOT_RUNNING'\n );\n }\n\n const faucetAccount = this.getFaucetAccount();\n\n try {\n const [core, evm] = await Promise.all([\n this.getCoreBalance(faucetAccount.coreAddress),\n this.getEvmBalance(faucetAccount.evmAddress),\n ]);\n\n return { core, evm };\n } catch (error) {\n throw new NodeError(\n `Failed to get faucet balances: ${error instanceof Error ? error.message : String(error)}`,\n 'BALANCE_CHECK_ERROR',\n undefined,\n { faucetAccount, originalError: error }\n );\n }\n }\n\n /**\n * Check Core Space balance\n */\n async getCoreBalance(address: string): Promise<string> {\n const { createPublicClient, http, formatCFX } = await import('cive');\n\n const publicClient = createPublicClient({\n chain:\n this.config.chainId === 1029\n ? {\n id: 1029,\n name: 'Conflux Core',\n nativeCurrency: { name: 'Conflux', symbol: 'CFX', decimals: 18 },\n rpcUrls: {\n default: {\n http: [`http://localhost:${this.config.coreRpcPort}`],\n },\n },\n }\n : {\n id: 1,\n name: 'Conflux Core Testnet',\n nativeCurrency: { name: 'Conflux', symbol: 'CFX', decimals: 18 },\n rpcUrls: {\n default: {\n http: [`http://localhost:${this.config.coreRpcPort}`],\n },\n },\n },\n transport: http(`http://localhost:${this.config.coreRpcPort}`),\n });\n\n const balance = await publicClient.getBalance({\n address: address as `cfx:${string}`,\n });\n return formatCFX(balance);\n }\n\n /**\n * Check eSpace balance\n */\n async getEvmBalance(address: string): Promise<string> {\n const { createPublicClient, http, formatEther } = await import('viem');\n\n const publicClient = createPublicClient({\n chain: {\n id: this.config.evmChainId || 71,\n name: 'Conflux eSpace Local',\n nativeCurrency: { name: 'Conflux', symbol: 'CFX', decimals: 18 },\n rpcUrls: {\n default: { http: [`http://localhost:${this.config.evmRpcPort}`] },\n },\n },\n transport: http(`http://localhost:${this.config.evmRpcPort}`),\n });\n\n const balance = await publicClient.getBalance({\n address: address as `0x${string}`,\n });\n return formatEther(balance);\n }\n\n /**\n * Get Ethereum-compatible admin address derived from mnemonic\n * Uses the standard Ethereum derivation path: m/44'/60'/0'/0/0\n * This address will match what MetaMask and other Ethereum wallets derive\n */\n getEthereumAdminAddress(): string {\n // Use core wallet module for account derivation\n const account = deriveAccount(\n this.mnemonic,\n 0,\n this.config.chainId || 2029\n );\n\n return account.evmAddress.toLowerCase();\n }\n\n /**\n * Set up cleanup handlers for graceful shutdown\n */\n private setupCleanupHandlers(): void {\n const cleanup = async () => {\n if (this.isRunning()) {\n console.log('Shutting down Conflux development node...');\n await this.stop();\n }\n };\n\n process.on('SIGINT', cleanup);\n process.on('SIGTERM', cleanup);\n process.on('exit', cleanup);\n }\n}\n","/*\n * Copyright 2025 Conflux DevKit Team\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Types for DevNode Plugin\n * Re-exports types needed from @cfxdevkit/core\n */\n\n// Node Configuration\nexport interface NodeConfig {\n chainId?: number;\n evmChainId?: number;\n coreRpcPort?: number;\n evmRpcPort?: number;\n wsPort?: number; // Core Space WebSocket port\n evmWsPort?: number; // eSpace WebSocket port (default: 8546)\n dataDir?: string;\n mnemonic?: string;\n logging?: boolean;\n}\n\nexport interface ServerConfig extends NodeConfig {\n jsonrpcHttpPort?: number;\n jsonrpcHttpEthPort?: number;\n jsonrpcWsPort?: number;\n jsonrpcWsEthPort?: number;\n log?: boolean;\n accounts?: number;\n balance?: string;\n miningAuthor?: string; // Mining rewards recipient (Core address)\n // devPackTxImmediately should always be false - mining is managed via testClient\n devPackTxImmediately?: boolean;\n}\n\n// Start Options\nexport interface StartOptions {\n mining?: boolean;\n waitForBlocks?: boolean;\n}\n\n// Mining Status\nexport interface MiningStatus {\n isRunning: boolean;\n interval?: number;\n blocksMined?: number;\n blocksGenerated?: number;\n startTime?: Date;\n}\n\n// Account Info\nexport interface AccountInfo {\n index: number;\n coreAddress: string;\n evmAddress: string;\n privateKey: string;\n evmPrivateKey?: string;\n coreBalance?: string;\n evmBalance?: string;\n path?: string;\n evmPath?: string;\n mnemonic?: string;\n}\n\n// Faucet Balances\nexport interface FaucetBalances {\n core: string;\n evm: string;\n}\n\n// Chain Balances\nexport interface ChainBalances {\n core: string;\n evm: string;\n}\n\n// Server Status\nexport type ServerStatus =\n | 'stopped'\n | 'starting'\n | 'running'\n | 'stopping'\n | 'error';\n\n// Chain Type\nexport type ChainType = 'core' | 'evm';\n\n// Node Error Interface\nexport interface ConfluxNodeError {\n code: string;\n chain?: ChainType;\n context?: Record<string, unknown>;\n}\n\n// Node Error Class\nexport class NodeError extends Error implements ConfluxNodeError {\n public readonly code: string;\n public readonly chain?: ChainType;\n public readonly context?: Record<string, unknown>;\n\n constructor(\n message: string,\n code: string,\n chain?: ChainType,\n context?: Record<string, unknown>\n ) {\n super(message);\n this.name = 'NodeError';\n this.code = code;\n this.chain = chain;\n this.context = context;\n }\n}\n","/*\n * Copyright 2025 Conflux DevKit Team\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * DevNode Plugin - Optional @xcfx/node integration for local development\n *\n * This plugin extends DevKit with local node functionality:\n * - Local node lifecycle (start/stop)\n * - Mining controls (start/stop/mine)\n * - Faucet operations (fund accounts)\n * - Development-only features\n *\n * Usage:\n * ```typescript\n * import { DevKit } from '@conflux-devkit/node';\n * import { devNodePlugin } from '@cfxdevkit/devnode';\n *\n * // Production: Just use DevKit\n * const devkit = new DevKit({ coreRpc: '...', evmRpc: '...' });\n *\n * // Development: Use plugin for local node\n * const devkitWithNode = devNodePlugin.extendDevKit(new DevKit());\n * await devkitWithNode.startNode();\n * ```\n */\n\nimport { ServerManager } from './server-manager.js';\nimport type {\n AccountInfo,\n FaucetBalances,\n MiningStatus,\n NodeConfig,\n StartOptions,\n} from './types.js';\n\n/**\n * Base DevKit interface (subset needed for plugin)\n */\nexport interface BaseDevKit {\n getConfig(): NodeConfig;\n getRpcUrls(): { core: string; evm: string };\n}\n\n/**\n * Extended DevKit with local node capabilities\n */\nexport class DevKitWithDevNode {\n private server: ServerManager;\n private baseDevKit: BaseDevKit;\n\n constructor(baseDevKit: BaseDevKit, config: NodeConfig) {\n this.baseDevKit = baseDevKit;\n this.server = new ServerManager(config);\n }\n\n // Delegate to base DevKit\n getConfig(): NodeConfig {\n return this.baseDevKit.getConfig();\n }\n\n getRpcUrls(): { core: string; evm: string } {\n return this.baseDevKit.getRpcUrls();\n }\n\n // Node lifecycle methods\n async startNode(options: Partial<StartOptions> = {}): Promise<void> {\n await this.server.start();\n\n // Start mining if requested (default: true)\n if (options.mining !== false) {\n await this.server.startMining();\n }\n }\n\n async stopNode(): Promise<void> {\n await this.server.stop();\n }\n\n // Mining methods\n async startMining(): Promise<void> {\n await this.server.startMining();\n }\n\n async stopMining(): Promise<void> {\n await this.server.stopMining();\n }\n\n async mine(blocks: number = 1): Promise<void> {\n await this.server.mine(blocks);\n }\n\n getMiningStatus(): MiningStatus {\n return this.server.getMiningStatus();\n }\n\n async setMiningInterval(interval: number): Promise<void> {\n await this.server.setMiningInterval(interval);\n }\n\n // Faucet methods\n async getFaucetBalances(): Promise<FaucetBalances> {\n return await this.server.getFaucetBalances();\n }\n\n getFaucetAccount(): AccountInfo {\n return this.server.getFaucetAccount();\n }\n\n async fundAccount(\n address: string,\n amount: string,\n chain: 'core' | 'evm'\n ): Promise<string> {\n if (chain === 'core') {\n return await this.server.fundCoreAccount(address, amount);\n } else {\n return await this.server.fundEvmAccount(address, amount);\n }\n }\n\n // Account methods\n async addAccount(): Promise<AccountInfo> {\n return await this.server.addAccount();\n }\n\n getAccounts(): AccountInfo[] {\n return this.server.getAccounts();\n }\n\n // Utility methods\n getEthereumAdminAddress(): string {\n return this.server.getEthereumAdminAddress();\n }\n\n getServerStatus(): string {\n return this.server.getStatus();\n }\n\n isNodeRunning(): boolean {\n return this.server.isRunning();\n }\n}\n\n/**\n * Plugin interface\n */\nexport interface DevNodePlugin {\n name: 'devnode';\n version: string;\n extendDevKit(devkit: BaseDevKit, config: NodeConfig): DevKitWithDevNode;\n}\n\n/**\n * Default plugin export\n */\nexport const devNodePlugin: DevNodePlugin = {\n name: 'devnode',\n version: '0.1.0',\n\n extendDevKit(devkit: BaseDevKit, config: NodeConfig): DevKitWithDevNode {\n return new DevKitWithDevNode(devkit, config);\n },\n};\n"],"mappings":"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","names":["privateKeyToAccount","privateKeyToEvmAccount"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cfxdevkit/devnode",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.0.7",
|
|
4
4
|
"description": "Optional @xcfx/node plugin for Conflux DevKit - Local development features (dev-only)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -29,6 +29,23 @@
|
|
|
29
29
|
},
|
|
30
30
|
"./package.json": "./package.json"
|
|
31
31
|
},
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "tsup",
|
|
34
|
+
"build:watch": "tsup --watch",
|
|
35
|
+
"type-check": "tsc --noEmit",
|
|
36
|
+
"test": "vitest run --pass-with-no-tests",
|
|
37
|
+
"test:ui": "vitest --ui",
|
|
38
|
+
"test:run": "vitest --run",
|
|
39
|
+
"test:coverage": "vitest --run --coverage --pass-with-no-tests",
|
|
40
|
+
"test:watch": "vitest --watch",
|
|
41
|
+
"clean": "rm -rf dist",
|
|
42
|
+
"lint": "biome lint src/",
|
|
43
|
+
"lint:fix": "biome lint --write src/",
|
|
44
|
+
"format": "biome format src/",
|
|
45
|
+
"format:fix": "biome format --write src/",
|
|
46
|
+
"check": "biome check src/",
|
|
47
|
+
"check:fix": "biome check --write src/"
|
|
48
|
+
},
|
|
32
49
|
"dependencies": {
|
|
33
50
|
"@xcfx/node": "0.8.0",
|
|
34
51
|
"cive": "^0.8.1",
|
|
@@ -39,14 +56,14 @@
|
|
|
39
56
|
},
|
|
40
57
|
"devDependencies": {
|
|
41
58
|
"@biomejs/biome": "^2.3.10",
|
|
59
|
+
"@cfxdevkit/core": "workspace:*",
|
|
42
60
|
"@types/node": "^25.0.3",
|
|
43
61
|
"@vitest/coverage-v8": "^4.0.16",
|
|
44
62
|
"@vitest/ui": "^4.0.16",
|
|
45
63
|
"tsup": "^8.5.1",
|
|
46
64
|
"tsx": "^4.21.0",
|
|
47
65
|
"typescript": "^5.9.3",
|
|
48
|
-
"vitest": "^4.0.16"
|
|
49
|
-
"@cfxdevkit/core": "0.1.0"
|
|
66
|
+
"vitest": "^4.0.16"
|
|
50
67
|
},
|
|
51
68
|
"keywords": [
|
|
52
69
|
"conflux",
|
|
@@ -61,30 +78,14 @@
|
|
|
61
78
|
],
|
|
62
79
|
"author": "Conflux DevKit Team",
|
|
63
80
|
"license": "Apache-2.0",
|
|
81
|
+
"packageManager": "pnpm@10.11.0",
|
|
64
82
|
"repository": {
|
|
65
83
|
"type": "git",
|
|
66
|
-
"url": "git+https://github.com/cfxdevkit/
|
|
84
|
+
"url": "git+https://github.com/cfxdevkit/devkit.git",
|
|
67
85
|
"directory": "packages/plugin-devnode"
|
|
68
86
|
},
|
|
69
|
-
"homepage": "https://github.com/cfxdevkit/
|
|
87
|
+
"homepage": "https://github.com/cfxdevkit/devkit#readme",
|
|
70
88
|
"bugs": {
|
|
71
|
-
"url": "https://github.com/cfxdevkit/
|
|
72
|
-
},
|
|
73
|
-
"scripts": {
|
|
74
|
-
"build": "tsup",
|
|
75
|
-
"build:watch": "tsup --watch",
|
|
76
|
-
"type-check": "tsc --noEmit",
|
|
77
|
-
"test": "vitest run --pass-with-no-tests",
|
|
78
|
-
"test:ui": "vitest --ui",
|
|
79
|
-
"test:run": "vitest --run",
|
|
80
|
-
"test:coverage": "vitest --run --coverage",
|
|
81
|
-
"test:watch": "vitest --watch",
|
|
82
|
-
"clean": "rm -rf dist",
|
|
83
|
-
"lint": "biome lint src/",
|
|
84
|
-
"lint:fix": "biome lint --write src/",
|
|
85
|
-
"format": "biome format src/",
|
|
86
|
-
"format:fix": "biome format --write src/",
|
|
87
|
-
"check": "biome check src/",
|
|
88
|
-
"check:fix": "biome check --write src/"
|
|
89
|
+
"url": "https://github.com/cfxdevkit/devkit/issues"
|
|
89
90
|
}
|
|
90
|
-
}
|
|
91
|
+
}
|