From 5d4afb1494d127be297f21ee642378154a47e33c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=A5=E5=9B=BD=E5=AE=87?= <841185308@qq.com> Date: Thu, 30 May 2024 17:43:12 +0800 Subject: [PATCH] feat: Optimize light client external node detection (#3165) --- .../neuron-ui/src/containers/Main/index.tsx | 76 ++++++++++++------- packages/neuron-ui/src/locales/en.json | 3 +- packages/neuron-ui/src/locales/es.json | 3 +- packages/neuron-ui/src/locales/fr.json | 3 +- packages/neuron-ui/src/locales/zh-tw.json | 3 +- packages/neuron-ui/src/locales/zh.json | 3 +- .../src/block-sync-renderer/sync/queue.ts | 3 +- .../neuron-wallet/src/services/ckb-runner.ts | 8 +- .../src/services/light-runner.ts | 16 +++- packages/neuron-wallet/src/utils/toml.ts | 18 ++++- .../tests/services/ckb-runner.test.ts | 16 +++- .../tests/services/light-runner.test.ts | 30 ++++++-- .../neuron-wallet/tests/utils/toml/test.toml | 1 + .../tests/utils/toml/toml.test.ts | 33 +++++--- 14 files changed, 147 insertions(+), 69 deletions(-) diff --git a/packages/neuron-ui/src/containers/Main/index.tsx b/packages/neuron-ui/src/containers/Main/index.tsx index 038ca40a31..92b27d5cb3 100644 --- a/packages/neuron-ui/src/containers/Main/index.tsx +++ b/packages/neuron-ui/src/containers/Main/index.tsx @@ -37,6 +37,8 @@ const MainContent = () => { [network, networks] ) + const isLightClientNetwork = network?.type === 2 + useSyncChainData({ chainURL: network?.remote ?? '', dispatch, @@ -98,6 +100,48 @@ const MainContent = () => { } }, []) + const dialogProps = (function getDialogProps() { + if (isLightClientNetwork) { + return { + onConfirm: onCloseSwitchNetwork, + children: t('main.external-node-detected-dialog.external-node-is-light'), + } + } + if (sameUrlNetworks.length) { + return { + onConfirm: onSwitchNetwork, + children: ( + <> + + {t('main.external-node-detected-dialog.body-tips-with-network')} + +
+ ({ + value: v.id, + label: `${v.name} (${v.remote})`, + }))} + inputIdPrefix="main-switch" + /> +
+
+ +
+ + ), + } + } + return { + onConfirm: onOpenEditorDialog, + confirmText: t('main.external-node-detected-dialog.add-network'), + children: t('main.external-node-detected-dialog.body-tips-without-network'), + } + })() + return (
@@ -124,39 +168,13 @@ const MainContent = () => { - {sameUrlNetworks.length ? ( - - {t('main.external-node-detected-dialog.body-tips-with-network')} - - ) : ( - t('main.external-node-detected-dialog.body-tips-without-network') - )} - {sameUrlNetworks.length ? ( - <> -
- ({ - value: v.id, - label: `${v.name} (${v.remote})`, - }))} - inputIdPrefix="main-switch" - /> -
-
- -
- - ) : null} + {dialogProps.children}
{showEditorDialog ? ( Please allocate more disk space or migrate the data to another disk.", diff --git a/packages/neuron-ui/src/locales/es.json b/packages/neuron-ui/src/locales/es.json index 3ac8e1f57f..325880ce4e 100644 --- a/packages/neuron-ui/src/locales/es.json +++ b/packages/neuron-ui/src/locales/es.json @@ -1192,7 +1192,8 @@ "body-tips-without-network": "\"Internal Node\" está reservado para el nodo CKB incorporado, agregue una nueva opción de red para el nodo externo.", "body-tips-with-network": "\"Internal Node\" está reservado para el nodo CKB incorporado, seleccione una de las siguientes opciones de red o agregue una nueva para el nodo externo.", "add-network": "Agregar red", - "ignore-external-node": "Ignorar nodo externo" + "ignore-external-node": "Ignorar nodo externo", + "external-node-is-light": "Debido a las diferentes suposiciones de seguridad del cliente ligero, Neuron no admite nodos de cliente ligero externos. ¿Desea conectarse a un \"Light Client\" ?" }, "no-disk-space-dialog": { "tip": "La sincronización se ha detenido debido a falta de espacio en disco.
Asigne más espacio en disco o migre los datos a otro disco.", diff --git a/packages/neuron-ui/src/locales/fr.json b/packages/neuron-ui/src/locales/fr.json index a609830ca1..710b521d1c 100644 --- a/packages/neuron-ui/src/locales/fr.json +++ b/packages/neuron-ui/src/locales/fr.json @@ -1202,7 +1202,8 @@ "body-tips-without-network": "\"Noeud interne\" est réservé au noeud CKB intégré, veuillez ajouter une nouvelle option réseau pour le noeud externe.", "body-tips-with-network": "\"Noeud interne\" est réservé au noeud CKB intégré, veuillez sélectionner parmi les options réseau suivantes ou en ajouter une nouvelle pour le noeud externe.", "add-network": "Ajouter un réseau", - "ignore-external-node": "Ignorer le noeud externe" + "ignore-external-node": "Ignorer le noeud externe", + "external-node-is-light": "En raison de différentes hypothèses de sécurité du client léger, Neuron ne prend pas en charge les nœuds clients légers externes. Voulez-vous vous connecter à un \"Light Client\" ?" }, "no-disk-space-dialog": { "tip": "En raison d'un espace disque insuffisant, la synchronisation a été interrompue.
Veuillez allouer plus d'espace disque ou migrer les données vers un autre disque.", diff --git a/packages/neuron-ui/src/locales/zh-tw.json b/packages/neuron-ui/src/locales/zh-tw.json index 8e61fb1c5d..3d82319d84 100644 --- a/packages/neuron-ui/src/locales/zh-tw.json +++ b/packages/neuron-ui/src/locales/zh-tw.json @@ -1205,7 +1205,8 @@ "body-tips-without-network": "\"Internal Node\" 僅用於連接內置節點,請添加新的網絡選項以連接外部節點。", "body-tips-with-network": "\"Internal Node\" 僅用於連接內置節點,請選擇以下網絡選項或添加新的網絡選項以連接外部節點。", "add-network": "添加網絡", - "ignore-external-node": "忽略外部節點" + "ignore-external-node": "忽略外部節點", + "external-node-is-light": "由於輕客戶端的安全假設不同,Neuron 不支持外部輕客戶端節點。您想連接到 \"Light Client\" 嗎?" }, "no-disk-space-dialog": { "tip": "由於磁盤空間不足,同步已停止。
請分配更多磁盤空間或將數據遷移到其他磁盤。", diff --git a/packages/neuron-ui/src/locales/zh.json b/packages/neuron-ui/src/locales/zh.json index d0ad40e458..0854352928 100644 --- a/packages/neuron-ui/src/locales/zh.json +++ b/packages/neuron-ui/src/locales/zh.json @@ -1204,7 +1204,8 @@ "body-tips-without-network": "\"Internal Node\" 仅用于连接内置节点,请添加新的网络选项以连接外部节点。", "body-tips-with-network": "\"Internal Node\" 仅用于连接内置节点,请选择以下网络选项或添加新的网络选项以连接外部节点。", "add-network": "添加网络", - "ignore-external-node": "忽略外部节点" + "ignore-external-node": "忽略外部节点", + "external-node-is-light": "由于轻客户端的安全假设不同,Neuron 不支持外部轻客户端节点。您想连接到 \"Light Client\" 吗?" }, "no-disk-space-dialog": { "tip": "由于磁盘空间不足,同步已停止。
请分配更多磁盘空间或将数据迁移到其他磁盘。", diff --git a/packages/neuron-wallet/src/block-sync-renderer/sync/queue.ts b/packages/neuron-wallet/src/block-sync-renderer/sync/queue.ts index 2c5d5008a5..6ff88e8e90 100644 --- a/packages/neuron-wallet/src/block-sync-renderer/sync/queue.ts +++ b/packages/neuron-wallet/src/block-sync-renderer/sync/queue.ts @@ -20,7 +20,6 @@ import { ShouldInChildProcess } from '../../exceptions' import { AppendScript, BlockTips, Synchronizer } from './synchronizer' import LightSynchronizer from './light-synchronizer' import { generateRPC } from '../../utils/ckb-rpc' -import { BUNDLED_LIGHT_CKB_URL } from '../../utils/const' import { NetworkType } from '../../models/network' import WalletService from '../../services/wallets' @@ -65,7 +64,7 @@ export default class Queue { start = async () => { logger.info('Queue:\tstart') try { - if (this.#url === BUNDLED_LIGHT_CKB_URL) { + if (this.#nodeType === NetworkType.Light) { this.#indexerConnector = new LightSynchronizer(this.#addresses, this.#url) } else { this.#indexerConnector = new FullSynchronizer(this.#addresses, this.#url, this.#nodeType) diff --git a/packages/neuron-wallet/src/services/ckb-runner.ts b/packages/neuron-wallet/src/services/ckb-runner.ts index 003800312d..5eae7a91ef 100644 --- a/packages/neuron-wallet/src/services/ckb-runner.ts +++ b/packages/neuron-wallet/src/services/ckb-runner.ts @@ -115,8 +115,12 @@ export const startCkbNode = async () => { listenPort = await getUsablePort(rpcPort >= listenPort ? rpcPort + 1 : listenPort) updateToml(path.join(SettingsService.getInstance().getNodeDataPath(), 'ckb.toml'), { - rpc: `listen_address = "127.0.0.1:${rpcPort}"`, - network: `listen_addresses = ["/ip4/0.0.0.0/tcp/${listenPort}"]`, + rpc: { + listen_address: `"127.0.0.1:${rpcPort}"`, + }, + network: { + listen_addresses: `["/ip4/0.0.0.0/tcp/${listenPort}"]`, + }, }) const options = ['run', '-C', SettingsService.getInstance().getNodeDataPath(), '--indexer'] const stdio: (StdioNull | StdioPipe)[] = ['ignore', 'pipe', 'pipe'] diff --git a/packages/neuron-wallet/src/services/light-runner.ts b/packages/neuron-wallet/src/services/light-runner.ts index 1c05fbf38e..da93dd39d2 100644 --- a/packages/neuron-wallet/src/services/light-runner.ts +++ b/packages/neuron-wallet/src/services/light-runner.ts @@ -81,6 +81,7 @@ export class CKBLightRunner extends NodeRunner { protected binaryName: string = 'ckb-light-client' protected logStream: Map = new Map() protected _port: number = 9000 + protected listenPort: number = 8118 static getInstance(): CKBLightRunner { if (!CKBLightRunner.instance) { @@ -117,13 +118,22 @@ export class CKBLightRunner extends NodeRunner { async updateConfig() { const usablePort = await getUsablePort(this._port) + const listenPort = await getUsablePort(usablePort >= this._port ? this.listenPort + 1 : this.listenPort) this._port = usablePort + this.listenPort = listenPort const storePath = path.join(SettingsService.getInstance().getNodeDataPath(), './store') const networkPath = path.join(SettingsService.getInstance().getNodeDataPath(), './network') updateToml(this.configFile, { - store: `path = "${this.platform() === 'win' ? storePath.replace(/\\/g, '\\\\') : storePath}"`, - network: `path = "${this.platform() === 'win' ? networkPath.replace(/\\/g, '\\\\') : networkPath}"`, - rpc: `listen_address = "127.0.0.1:${usablePort}"`, + store: { + path: `"${this.platform() === 'win' ? storePath.replace(/\\/g, '\\\\') : storePath}"`, + }, + network: { + path: `"${this.platform() === 'win' ? networkPath.replace(/\\/g, '\\\\') : networkPath}"`, + listen_addresses: `["/ip4/0.0.0.0/tcp/${listenPort}"]`, + }, + rpc: { + listen_address: `"127.0.0.1:${usablePort}"`, + }, }) } diff --git a/packages/neuron-wallet/src/utils/toml.ts b/packages/neuron-wallet/src/utils/toml.ts index b0e724513f..97a57eef78 100644 --- a/packages/neuron-wallet/src/utils/toml.ts +++ b/packages/neuron-wallet/src/utils/toml.ts @@ -1,7 +1,11 @@ import fs from 'fs' import path from 'path' -export function updateToml(filePath: string, updateValue: Record, newFilePath?: string) { +export function updateToml( + filePath: string, + updateValue: Record>, + newFilePath?: string +) { const values = fs.readFileSync(filePath).toString().split('\n') let field: string | undefined = undefined const newValues = values.map(v => { @@ -14,9 +18,15 @@ export function updateToml(filePath: string, updateValue: Record return v } if (field && updateValue[field]) { - const newLine = updateValue[field] - field = undefined - return newLine + const equalIndex = v.indexOf('=') + if (equalIndex !== -1) { + const stringBeforeEqual = v.slice(0, equalIndex) + const key = stringBeforeEqual.trim() + if (updateValue[field][key]) { + const newLine = `${stringBeforeEqual}= ${updateValue[field][key]}` + return newLine + } + } } return v }) diff --git a/packages/neuron-wallet/tests/services/ckb-runner.test.ts b/packages/neuron-wallet/tests/services/ckb-runner.test.ts index 451d9b2462..067137a946 100644 --- a/packages/neuron-wallet/tests/services/ckb-runner.test.ts +++ b/packages/neuron-wallet/tests/services/ckb-runner.test.ts @@ -255,8 +255,12 @@ describe('ckb runner', () => { expect(getNodeUrl()).toBe('http://127.0.0.1:8114') expect(getUsablePortMock).toHaveBeenLastCalledWith(8115) expect(updateTomlMock).toBeCalledWith(path.join('/chains/mainnet', 'ckb.toml'), { - rpc: `listen_address = "127.0.0.1:8114"`, - network: `listen_addresses = ["/ip4/0.0.0.0/tcp/8115"]`, + rpc: { + listen_address: `"127.0.0.1:8114"`, + }, + network: { + listen_addresses: `["/ip4/0.0.0.0/tcp/8115"]`, + }, }) const promise = stopCkbNode() stubbedCkb.emit('close') @@ -270,8 +274,12 @@ describe('ckb runner', () => { expect(getNodeUrl()).toBe('http://127.0.0.1:8115') expect(getUsablePortMock).toHaveBeenLastCalledWith(8116) expect(updateTomlMock).toBeCalledWith(path.join('/chains/mainnet', 'ckb.toml'), { - rpc: `listen_address = "127.0.0.1:8115"`, - network: `listen_addresses = ["/ip4/0.0.0.0/tcp/8116"]`, + rpc: { + listen_address: `"127.0.0.1:8115"`, + }, + network: { + listen_addresses: `["/ip4/0.0.0.0/tcp/8116"]`, + }, }) let promise = stopCkbNode() stubbedCkb.emit('close') diff --git a/packages/neuron-wallet/tests/services/light-runner.test.ts b/packages/neuron-wallet/tests/services/light-runner.test.ts index a88ed7a1ec..1a2a2fe7ed 100644 --- a/packages/neuron-wallet/tests/services/light-runner.test.ts +++ b/packages/neuron-wallet/tests/services/light-runner.test.ts @@ -337,32 +337,46 @@ describe('test light runner', () => { describe('test update config', () => { it('port is used', async () => { - getUsablePortMock.mockResolvedValueOnce(9001) + getUsablePortMock.mockResolvedValueOnce(9001).mockResolvedValueOnce(8119) lightDataPathMock.mockReturnValue('lightDataPath') resolveMock.mockImplementation((...v: string[]) => v.join('')) joinMock.mockImplementation((...v: string[]) => v.join('')) await CKBLightRunner.getInstance().updateConfig() expect(CKBLightRunner.getInstance().port).toEqual(9001) expect(updateTomlMock).toHaveBeenCalledWith('lightDataPath./ckb_light.toml', { - store: `path = "lightDataPath./store"`, - network: `path = "lightDataPath./network"`, - rpc: `listen_address = "127.0.0.1:9001"`, + store: { + path: `"lightDataPath./store"`, + }, + network: { + listen_addresses: '["/ip4/0.0.0.0/tcp/8119"]', + path: `"lightDataPath./network"`, + }, + rpc: { + listen_address: `"127.0.0.1:9001"`, + }, }) //reset port getUsablePortMock.mockResolvedValueOnce(9000) await CKBLightRunner.getInstance().updateConfig() }) it('port is not used', async () => { - getUsablePortMock.mockResolvedValueOnce(9000) + getUsablePortMock.mockResolvedValueOnce(9000).mockResolvedValueOnce(8118) lightDataPathMock.mockReturnValue('lightDataPath') resolveMock.mockImplementation((...v: string[]) => v.join('')) joinMock.mockImplementation((...v: string[]) => v.join('')) await CKBLightRunner.getInstance().updateConfig() expect(CKBLightRunner.getInstance().port).toEqual(9000) expect(updateTomlMock).toHaveBeenCalledWith('lightDataPath./ckb_light.toml', { - store: `path = "lightDataPath./store"`, - network: `path = "lightDataPath./network"`, - rpc: `listen_address = "127.0.0.1:9000"`, + store: { + path: `"lightDataPath./store"`, + }, + network: { + listen_addresses: '["/ip4/0.0.0.0/tcp/8118"]', + path: `"lightDataPath./network"`, + }, + rpc: { + listen_address: `"127.0.0.1:9000"`, + }, }) }) }) diff --git a/packages/neuron-wallet/tests/utils/toml/test.toml b/packages/neuron-wallet/tests/utils/toml/test.toml index 7a693b7094..e5c6426928 100644 --- a/packages/neuron-wallet/tests/utils/toml/test.toml +++ b/packages/neuron-wallet/tests/utils/toml/test.toml @@ -17,6 +17,7 @@ log_to_stdout = true [network] network = 127 +listen_addresses = ["/ip4/0.0.0.0/tcp/8115"] ### Specify the public and routable network addresses # public_addresses = [] diff --git a/packages/neuron-wallet/tests/utils/toml/toml.test.ts b/packages/neuron-wallet/tests/utils/toml/toml.test.ts index 37ea295d0c..1184bcb430 100644 --- a/packages/neuron-wallet/tests/utils/toml/toml.test.ts +++ b/packages/neuron-wallet/tests/utils/toml/toml.test.ts @@ -27,41 +27,50 @@ describe('test toml', () => { resetMock() }) describe('test update toml', () => { - it('update skip comment', () => { + it('update skip non exist key', () => { const tomlPath = path.resolve(__dirname, './test.toml') updateToml(tomlPath, { - network: 'network = 127', + network: { + network1: '127', + }, }) - expect(writeFileSyncMock).toBeCalledWith( - tomlPath, - fs.readFileSync(tomlPath).toString().replace('listen_addresses = ["/ip4/0.0.0.0/tcp/8115"]', 'network = 127') - ) + expect(writeFileSyncMock).toBeCalledWith(tomlPath, fs.readFileSync(tomlPath).toString()) }) it('update multi values with new file and dir exist', () => { const tomlPath = path.resolve(__dirname, './test.toml') existsSyncMock.mockReturnValue(true) - updateToml(tomlPath, { network: 'network = 127', rpc: 'rpc = 8116' }, path.resolve(__dirname, './new.toml')) + updateToml( + tomlPath, + { network: { network: '126', listen_addresses: 'test' }, rpc: { listen_address: 'listen_address' } }, + path.resolve(__dirname, './new.toml') + ) expect(writeFileSyncMock).toBeCalledWith( path.resolve(__dirname, './new.toml'), fs .readFileSync(tomlPath) .toString() - .replace('listen_addresses = ["/ip4/0.0.0.0/tcp/8115"]', 'network = 127') - .replace('listen_address = "127.0.0.1:8114"', 'rpc = 8116') + .replace('network = 127', 'network = 126') + .replace('listen_addresses = ["/ip4/0.0.0.0/tcp/8115"]', 'listen_addresses = test') + .replace('listen_address = "127.0.0.1:8114"', 'listen_address = listen_address') ) }) it('update multi values with new file and dir not exist', () => { const tomlPath = path.resolve(__dirname, './test.toml') existsSyncMock.mockReturnValue(false) - updateToml(tomlPath, { network: 'network = 127', rpc: 'rpc = 8116' }, path.resolve(__dirname, './new.toml')) + updateToml( + tomlPath, + { network: { network: '126', listen_addresses: 'test' }, rpc: { listen_address: 'listen_address' } }, + path.resolve(__dirname, './new.toml') + ) expect(mkdirSyncMock).toBeCalledWith(__dirname, { recursive: true }) expect(writeFileSyncMock).toBeCalledWith( path.resolve(__dirname, './new.toml'), fs .readFileSync(tomlPath) .toString() - .replace('listen_addresses = ["/ip4/0.0.0.0/tcp/8115"]', 'network = 127') - .replace('listen_address = "127.0.0.1:8114"', 'rpc = 8116') + .replace('network = 127', 'network = 126') + .replace('listen_addresses = ["/ip4/0.0.0.0/tcp/8115"]', 'listen_addresses = test') + .replace('listen_address = "127.0.0.1:8114"', 'listen_address = listen_address') ) }) })