Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Optimize light client external node detection #3165

Merged
merged 1 commit into from
May 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 47 additions & 29 deletions packages/neuron-ui/src/containers/Main/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ const MainContent = () => {
[network, networks]
)

const isLightClientNetwork = network?.type === 2
Keith-CY marked this conversation as resolved.
Show resolved Hide resolved

useSyncChainData({
chainURL: network?.remote ?? '',
dispatch,
Expand Down Expand Up @@ -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: (
<>
<span className={styles.chooseNetworkTip}>
{t('main.external-node-detected-dialog.body-tips-with-network')}
</span>
<div className={styles.networks}>
<RadioGroup
onChange={onChangeSelected}
options={sameUrlNetworks.map(v => ({
value: v.id,
label: `${v.name} (${v.remote})`,
}))}
inputIdPrefix="main-switch"
/>
</div>
<div className={styles.addNetwork}>
<Button type="text" onClick={onOpenEditorDialog}>
<AddSimple />
{t('main.external-node-detected-dialog.add-network')}
</Button>
</div>
</>
),
}
}
return {
onConfirm: onOpenEditorDialog,
confirmText: t('main.external-node-detected-dialog.add-network'),
children: t('main.external-node-detected-dialog.body-tips-without-network'),
}
})()

return (
<div onContextMenu={onContextMenu}>
<Outlet />
Expand All @@ -124,39 +168,13 @@ const MainContent = () => {
<Dialog
show={isSwitchNetworkShow}
onCancel={onCloseSwitchNetwork}
onConfirm={sameUrlNetworks.length ? onSwitchNetwork : onOpenEditorDialog}
confirmText={sameUrlNetworks.length ? undefined : t('main.external-node-detected-dialog.add-network')}
onConfirm={dialogProps.onConfirm}
confirmText={dialogProps.confirmText}
cancelText={t('main.external-node-detected-dialog.ignore-external-node')}
title={t('main.external-node-detected-dialog.title')}
className={styles.networkDialog}
>
{sameUrlNetworks.length ? (
<span className={styles.chooseNetworkTip}>
{t('main.external-node-detected-dialog.body-tips-with-network')}
</span>
) : (
t('main.external-node-detected-dialog.body-tips-without-network')
)}
{sameUrlNetworks.length ? (
<>
<div className={styles.networks}>
<RadioGroup
onChange={onChangeSelected}
options={sameUrlNetworks.map(v => ({
value: v.id,
label: `${v.name} (${v.remote})`,
}))}
inputIdPrefix="main-switch"
/>
</div>
<div className={styles.addNetwork}>
<Button type="text" onClick={onOpenEditorDialog}>
<AddSimple />
{t('main.external-node-detected-dialog.add-network')}
</Button>
</div>
</>
) : null}
{dialogProps.children}
</Dialog>
{showEditorDialog ? (
<NetworkEditorDialog
Expand Down
3 changes: 2 additions & 1 deletion packages/neuron-ui/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1212,7 +1212,8 @@
"body-tips-without-network": "\"Internal Node\" is reserved for the built-in CKB node, please add a new network option for the external node.",
"body-tips-with-network": "\"Internal Node\" is reserved for the built-in CKB node, please select from the following network options or add a new one for the external node.",
"add-network": "Add Network",
"ignore-external-node": "Ignore external node"
"ignore-external-node": "Ignore external node",
"external-node-is-light": "Neuron does not support external light client nodes due to different security assumptions for light clients. Would you like to connect to the \"Light Client\" ?"
},
"no-disk-space-dialog": {
"tip": "Due to insufficient disk space, synchronization has been stopped. <br /> Please allocate more disk space or migrate the data to another disk.",
Expand Down
3 changes: 2 additions & 1 deletion packages/neuron-ui/src/locales/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -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. <br /> Asigne más espacio en disco o migre los datos a otro disco.",
Expand Down
3 changes: 2 additions & 1 deletion packages/neuron-ui/src/locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -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. <br /> Veuillez allouer plus d'espace disque ou migrer les données vers un autre disque.",
Expand Down
3 changes: 2 additions & 1 deletion packages/neuron-ui/src/locales/zh-tw.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": "由於磁盤空間不足,同步已停止。 <br /> 請分配更多磁盤空間或將數據遷移到其他磁盤。",
Expand Down
3 changes: 2 additions & 1 deletion packages/neuron-ui/src/locales/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": "由于磁盘空间不足,同步已停止。 <br /> 请分配更多磁盘空间或将数据迁移到其他磁盘。",
Expand Down
3 changes: 1 addition & 2 deletions packages/neuron-wallet/src/block-sync-renderer/sync/queue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'

Expand Down Expand Up @@ -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)
Expand Down
8 changes: 6 additions & 2 deletions packages/neuron-wallet/src/services/ckb-runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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']
Expand Down
16 changes: 13 additions & 3 deletions packages/neuron-wallet/src/services/light-runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export class CKBLightRunner extends NodeRunner {
protected binaryName: string = 'ckb-light-client'
protected logStream: Map<string, fs.WriteStream> = new Map()
protected _port: number = 9000
protected listenPort: number = 8118

static getInstance(): CKBLightRunner {
if (!CKBLightRunner.instance) {
Expand Down Expand Up @@ -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}"`,
},
})
}

Expand Down
18 changes: 14 additions & 4 deletions packages/neuron-wallet/src/utils/toml.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import fs from 'fs'
import path from 'path'

export function updateToml(filePath: string, updateValue: Record<string, string>, newFilePath?: string) {
export function updateToml(
filePath: string,
updateValue: Record<string, Record<string, string>>,
newFilePath?: string
) {
const values = fs.readFileSync(filePath).toString().split('\n')
let field: string | undefined = undefined
const newValues = values.map(v => {
Expand All @@ -14,9 +18,15 @@ export function updateToml(filePath: string, updateValue: Record<string, string>
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
})
Expand Down
16 changes: 12 additions & 4 deletions packages/neuron-wallet/tests/services/ckb-runner.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand All @@ -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')
Expand Down
30 changes: 22 additions & 8 deletions packages/neuron-wallet/tests/services/light-runner.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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"`,
},
})
})
})
Expand Down
1 change: 1 addition & 0 deletions packages/neuron-wallet/tests/utils/toml/test.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 = []

Expand Down
Loading