From 5e33fe978a820049d80a3ae50313e460be29c281 Mon Sep 17 00:00:00 2001 From: devchenyan Date: Thu, 9 Nov 2023 22:41:57 +0800 Subject: [PATCH 01/15] fix: address input issue (#2918) * fix: address input issue * fix --- .../neuron-ui/src/widgets/TextField/index.tsx | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/packages/neuron-ui/src/widgets/TextField/index.tsx b/packages/neuron-ui/src/widgets/TextField/index.tsx index 2f86f88783..3f2208d302 100644 --- a/packages/neuron-ui/src/widgets/TextField/index.tsx +++ b/packages/neuron-ui/src/widgets/TextField/index.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useRef, useState } from 'react' +import React, { useCallback, useRef, useState, useEffect } from 'react' import Alert from 'widgets/Alert' import { ReactComponent as Edit } from 'widgets/Icons/Edit.svg' import { EyesClose, EyesOpen } from 'widgets/Icons/icon' @@ -55,11 +55,28 @@ const TextField = React.forwardRef( ref: React.LegacyRef ) => { const [isPasswordHidden, setIsPasswordHidden] = useState(true) + const inputRef = useRef<(HTMLTextAreaElement & HTMLInputElement) | null>(null) + const rowsRef = useRef(rows) const changePasswordHide = useCallback(() => { setIsPasswordHidden(v => !v) }, [setIsPasswordHidden]) // FIXME: label should be limited to a string because it has its own semantic meaning const labelStr = typeof label === 'string' ? label : field + + useEffect(() => { + if (rowsRef.current === rows) { + return + } + + rowsRef.current = rows + if (!inputRef.current) { + return + } + inputRef.current.focus() + const position = value?.length || 0 + inputRef.current.setSelectionRange(position, position) + }, [rows]) + return (
Date: Tue, 14 Nov 2023 14:06:10 +0800 Subject: [PATCH 02/15] fix: Click current network button to switch type. (#2926) * fix: Click current network button to switch type. * fix: Better experience for switching network type --- .../src/components/NetworkSetting/index.tsx | 33 +++++++++---------- .../NetworkSetting/networkSetting.module.scss | 14 ++++---- 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/packages/neuron-ui/src/components/NetworkSetting/index.tsx b/packages/neuron-ui/src/components/NetworkSetting/index.tsx index d50225539c..e82447e235 100644 --- a/packages/neuron-ui/src/components/NetworkSetting/index.tsx +++ b/packages/neuron-ui/src/components/NetworkSetting/index.tsx @@ -99,35 +99,32 @@ const NetworkSetting = ({ chain = chainState, settings: { networks = [] } }: Sta itemClassName={styles.radioItem} options={showNetworks.map(network => ({ value: network.id, - label: - currentId === network.id && network.type === NetworkType.Light ? ( -
-

{`${network.name} (${network.remote})`}

+ label: ( +
+

{`${network.name} (${network.remote})`}

+
{t(getNetworkLabelI18nkey(network.chain))}
+
+ ), + suffix: ( +
+ {currentId === network.id && network.type === NetworkType.Light ? ( +
{t('settings.network.switch-network-type', { type: network.chain === LIGHT_CLIENT_MAINNET ? 'testnet' : 'mainnet', })} - +
} placement="top" showTriangle + className={styles.switch} > -
- {t(getNetworkLabelI18nkey(network.chain))} +
+
-
- ) : ( -
-

{`${network.name} (${network.remote})`}

-
{t(getNetworkLabelI18nkey(network.chain))}
-
- ), - suffix: ( -
+ ) : null} {network.readonly ? null : ( ) } diff --git a/packages/neuron-ui/src/tests/validators/outputs/index.test.ts b/packages/neuron-ui/src/tests/validators/outputs/index.test.ts index 90c56798a0..8c9827c364 100644 --- a/packages/neuron-ui/src/tests/validators/outputs/index.test.ts +++ b/packages/neuron-ui/src/tests/validators/outputs/index.test.ts @@ -15,7 +15,7 @@ describe(`Test outputs validator`, () => { expect(e).not.toBeUndefined() } } else { - expect(validateOutputs()).toBeTruthy() + expect(validateOutputs(outputs, false, ignoreLastAmount)).toBeTruthy() } }) }) diff --git a/packages/neuron-ui/src/utils/const.ts b/packages/neuron-ui/src/utils/const.ts index 238c4be8b8..95db79fe67 100644 --- a/packages/neuron-ui/src/utils/const.ts +++ b/packages/neuron-ui/src/utils/const.ts @@ -81,3 +81,5 @@ export const MILLISECONDS = HOURS_PER_EPOCH * 60 * 60 * 1000 export const ADDRESS_MIN_LENGTH = 86 export const ADDRESS_HEAD_TAIL_LENGTH = 34 + +export const PlaceHolderArgs = `0x${'00'.repeat(21)}` From c69258f18684ca7d95d7b5271e54f7d7135f0982 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=A5=E5=9B=BD=E5=AE=87?= <841185308@qq.com> Date: Fri, 17 Nov 2023 11:19:31 +0800 Subject: [PATCH 07/15] feat: Add light client compatible and change to json. (#2916) * feat: Add light client compatible and change to json. * fix: update compatible.json as fs.write * fix: Use compatible.json and add action to update it. --- .../workflows/update_neuron_compatible.yml | 51 +++++++++++++++++ compatible.csv | 6 -- compatible.json | 57 +++++++++++++++++++ package.json | 1 + packages/neuron-wallet/electron-builder.yml | 2 +- packages/neuron-wallet/src/services/node.ts | 27 ++++----- .../neuron-wallet/tests/services/node.test.ts | 42 +++++++++----- ...d-neuron-version-in-compatibility-table.js | 27 +++++++++ scripts/update-ckb-client-versions.js | 40 +++++++++++++ 9 files changed, 218 insertions(+), 35 deletions(-) create mode 100644 .github/workflows/update_neuron_compatible.yml delete mode 100644 compatible.csv create mode 100644 compatible.json create mode 100644 scripts/add-neuron-version-in-compatibility-table.js diff --git a/.github/workflows/update_neuron_compatible.yml b/.github/workflows/update_neuron_compatible.yml new file mode 100644 index 0000000000..c95d5751c7 --- /dev/null +++ b/.github/workflows/update_neuron_compatible.yml @@ -0,0 +1,51 @@ +name: Update Neuron compatibility table + +on: + push: + branches: + - 'rc/**' + paths: + - 'package.json' + +jobs: + update-neuron-compatible: + name: Update Neuron compatibility table + runs-on: ubuntu-latest + permissions: + pull-requests: write # open PR + contents: write # update version files + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: 20.x + + - name: Update versions + id: update_versions + run: | + npm run update:neuron-compatible + git add compatible.json + + - name: Set GPG + if: ${{ success() }} + uses: crazy-max/ghaction-import-gpg@v5 + with: + gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} + passphrase: ${{ secrets.GPG_PASSPHRASE }} + git_user_signingkey: true + git_commit_gpgsign: true + + - name: Open PR to RC branch + if: ${{ success() }} + uses: peter-evans/create-pull-request@v5 + with: + title: Update Neuron compatibility table + commit-message: 'feat: Update Neuron compatibility table' + body: 'Update Neuron compatibility table for a new release' + committer: Chen Yu + branch: update-neuron-compatible + base: ${{ github.ref_name }} diff --git a/compatible.csv b/compatible.csv deleted file mode 100644 index f39484153b..0000000000 --- a/compatible.csv +++ /dev/null @@ -1,6 +0,0 @@ -CKB,0.111,0.110,0.109,0.108,0.107,0.106,0.105,0.104,0.103 -Neuron,,,,,,,,, -0.111,yes,yes,yes,no,no,no,no,no,no -0.110,yes,yes,yes,no,no,no,no,no,no -0.106,no,no,no,yes,yes,yes,yes,no,no -0.103,no,no,no,no,no,no,no,yes,yes diff --git a/compatible.json b/compatible.json new file mode 100644 index 0000000000..732472a581 --- /dev/null +++ b/compatible.json @@ -0,0 +1,57 @@ +{ + "fullVersions": [ + "0.111", + "0.110", + "0.109", + "0.108", + "0.107", + "0.106", + "0.105", + "0.104", + "0.103" + ], + "lightVersions": [ + "0.3", + "0.2" + ], + "compatible": { + "0.111": { + "full": [ + "0.111", + "0.110", + "0.109" + ], + "light": [ + "0.3", + "0.2" + ] + }, + "0.110": { + "full": [ + "0.111", + "0.110", + "0.109" + ], + "light": [ + "0.3", + "0.2" + ] + }, + "0.106": { + "full": [ + "0.108", + "0.107", + "0.106", + "0.105" + ], + "light": [] + }, + "0.103": { + "full": [ + "0.104", + "0.103" + ], + "light": [] + } + } +} diff --git a/package.json b/package.json index 90c0bf91d2..143b5c5396 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "postinstall": "husky install", "db:chain": "node ./node_modules/.bin/typeorm", "update:valid-target": "node ./scripts/update-valid-target.js", + "update:neuron-compatible": "node ./scripts/add-neuron-version-in-compatibility-table.js", "update:client-versions": "node ./scripts/update-ckb-client-versions.js" }, "devDependencies": { diff --git a/packages/neuron-wallet/electron-builder.yml b/packages/neuron-wallet/electron-builder.yml index 4b3de23b0f..514c724ef2 100644 --- a/packages/neuron-wallet/electron-builder.yml +++ b/packages/neuron-wallet/electron-builder.yml @@ -13,7 +13,7 @@ afterSign: scripts/notarize.js files: - from: "../.." to: "." - filter: ["!**/*", ".ckb-version", ".ckb-light-version", "ormconfig.json", "compatible.csv"] + filter: ["!**/*", ".ckb-version", ".ckb-light-version", "ormconfig.json", "compatible.json"] - package.json - dist - ".env" diff --git a/packages/neuron-wallet/src/services/node.ts b/packages/neuron-wallet/src/services/node.ts index 42ad0d2387..f59d6e035e 100644 --- a/packages/neuron-wallet/src/services/node.ts +++ b/packages/neuron-wallet/src/services/node.ts @@ -231,23 +231,20 @@ class NodeService { private getNeuronCompatibilityCKB() { const appPath = electronApp.isPackaged ? electronApp.getAppPath() : path.join(__dirname, '../../../..') - const compatiblePath = path.join(appPath, 'compatible.csv') + const compatiblePath = path.join(appPath, 'compatible.json') if (fs.existsSync(compatiblePath)) { try { - const content = fs.readFileSync(compatiblePath, 'utf8')?.split('\n') - const ckbVersions = content?.[0]?.split(',')?.slice(1) - const neuronCompatible = content?.slice(2) - const result: Record> = {} - for (let index = 0; index < neuronCompatible.length; index++) { - const [neuronVersion, ...campatibleValues] = neuronCompatible[index].split(',') - result[neuronVersion] = {} - campatibleValues.forEach((v, idx) => { - result[neuronVersion][ckbVersions[idx]] = v === 'yes' - }) - } - return result + // eslint-disable-next-line @typescript-eslint/no-var-requires + const content = require(compatiblePath) + return (content?.compatible ?? {}) as Record< + string, + { + full: string[] + light: string[] + } + > } catch (err) { - logger.error('App\t: get compatible table failed') + logger.error('App\t: get compatible failed', err) } } } @@ -256,7 +253,7 @@ class NodeService { const compatibilities = this.getNeuronCompatibilityCKB() const neuronCompatibleVersion = neuronVersion.split('.').slice(0, 2).join('.') const externalCKBCompatibleVersion = externalCKBVersion.split('.').slice(0, 2).join('.') - return compatibilities?.[neuronCompatibleVersion]?.[externalCKBCompatibleVersion] + return compatibilities?.[neuronCompatibleVersion]?.full?.includes(externalCKBCompatibleVersion) } private verifyCKbNodeShouldUpdate(neuronCKBVersion: string, externalCKBVersion: string) { diff --git a/packages/neuron-wallet/tests/services/node.test.ts b/packages/neuron-wallet/tests/services/node.test.ts index aebdbf01ba..726423e026 100644 --- a/packages/neuron-wallet/tests/services/node.test.ts +++ b/packages/neuron-wallet/tests/services/node.test.ts @@ -28,6 +28,8 @@ describe('NodeService', () => { const rpcRequestMock = jest.fn() const getChainMock = jest.fn() const getLocalNodeInfoMock = jest.fn() + const pathJoinMock = jest.fn() + const redistCheckMock = jest.fn() const fakeHTTPUrl = 'http://fakeurl' @@ -54,6 +56,8 @@ describe('NodeService', () => { getLocalNodeInfoMock.mockReset() stubbedStartLightNode.mockReset() stubbedStopLightNode.mockReset() + pathJoinMock.mockReset() + redistCheckMock.mockReset() } beforeEach(() => { @@ -173,6 +177,12 @@ describe('NodeService', () => { } }) + jest.doMock('path', () => ({ + join: pathJoinMock, + })) + + jest.doMock('utils/redist-check', () => redistCheckMock) + stubbedRxjsDebounceTime.mockReturnValue((x: any) => x) getChainMock.mockRejectedValue('no chain') }) @@ -345,6 +355,7 @@ describe('NodeService', () => { nodeService.ckb.node.url = bundledNodeUrl }) stubbedStartCKBNode.mockResolvedValue(true) + redistCheckMock.mockResolvedValue(true) stubbedNetworsServiceGet.mockReturnValue({ remote: bundledNodeUrl, readonly: true }) getLocalNodeInfoMock.mockRejectedValue('not start') await nodeService.tryStartNodeOnDefaultURI() @@ -409,10 +420,7 @@ describe('NodeService', () => { nodeService = new NodeService() nodeService.getNeuronCompatibilityCKB = () => ({ '0.110': { - '0.110': true, - '0.109': true, - '0.108': false, - '0.107': false, + full: ['0.110', '0.109'], }, }) stubbedNetworsServiceGet.mockReturnValue({ remote: BUNDLED_CKB_URL, readonly: true }) @@ -456,10 +464,7 @@ describe('NodeService', () => { nodeService = new NodeService() nodeService.getNeuronCompatibilityCKB = () => ({ '0.110': { - '0.110': true, - '0.109': true, - '0.108': false, - '0.107': false, + full: ['0.110', '0.109'], }, }) stubbedNetworsServiceGet.mockReturnValueOnce({ remote: BUNDLED_CKB_URL, readonly: true }) @@ -525,21 +530,32 @@ describe('NodeService', () => { }) it('read file error', () => { existsSyncMock.mockReturnValue(true) - readFileSyncMock.mockReturnValue(new Error('read failed')) + pathJoinMock.mockReturnValue('./not-exist.json') expect(nodeService.getNeuronCompatibilityCKB()).toBeUndefined() }) it('ckb version content is wrong', async () => { existsSyncMock.mockReturnValue(true) - readFileSyncMock.mockReturnValue('') + pathJoinMock.mockReturnValue('exist.json') + jest.doMock('exist.json', () => ({}), { virtual: true }) expect(nodeService.getNeuronCompatibilityCKB()).toStrictEqual({}) }) it('success', async () => { existsSyncMock.mockReturnValue(true) - readFileSyncMock.mockReturnValue('ckb,0.110,0.109\nNeuron,,\n0.109,yes,no') + pathJoinMock.mockReturnValue('success.json') + jest.doMock( + 'success.json', + () => ({ + compatible: { + '0.109': { + full: ['0.108'], + }, + }, + }), + { virtual: true } + ) expect(nodeService.getNeuronCompatibilityCKB()).toStrictEqual({ '0.109': { - '0.110': true, - '0.109': false, + full: ['0.108'], }, }) }) diff --git a/scripts/add-neuron-version-in-compatibility-table.js b/scripts/add-neuron-version-in-compatibility-table.js new file mode 100644 index 0000000000..b2d2772754 --- /dev/null +++ b/scripts/add-neuron-version-in-compatibility-table.js @@ -0,0 +1,27 @@ +const fs = require('node:fs') +const path = require('node:path') + +const exec = () => { + const compatiblePath = path.resolve(__dirname, '../compatible.json') + const info = require(compatiblePath) + const packagePath = path.resolve(__dirname, '../package.json') + const neuronReleaseVersion = require(packagePath).version + const newNeuronVersion = neuronReleaseVersion.slice(0, neuronReleaseVersion.lastIndexOf('.')) + + const lastNeuronVersion = Object.keys(info.compatible).sort((a, b) => { + const [aMajor, aMinor] = a.split('.')?.map(v => +v) ?? [] + const [bMajor, bMinor] = b.split('.')?.map(v => +v) ?? [] + if (aMajor !== bMajor) return bMajor - aMajor + return bMinor - aMinor + })[0] + + if (newNeuronVersion && lastNeuronVersion !== newNeuronVersion) { + info.compatible[newNeuronVersion] = info.compatible[lastNeuronVersion] + fs.writeFileSync(compatiblePath, `${JSON.stringify(info, null, 2)}\r\n`) + } else { + process.exit(1) + } +} + +exec() + diff --git a/scripts/update-ckb-client-versions.js b/scripts/update-ckb-client-versions.js index 323ff3ab64..0071385017 100644 --- a/scripts/update-ckb-client-versions.js +++ b/scripts/update-ckb-client-versions.js @@ -31,17 +31,57 @@ const fetchBuiltinCkbVersion = async () => { } } +const getMajorAndMinorVersion = (full) => { + // v0.3.0 -> 0.3 + return full.slice(1, full.lastIndexOf('.')) +} + +const updateCompatible = ({ + node, + lightClient, +}) => { + const compatiblePath = path.resolve(__dirname, '../compatible.json') + const info = require(compatiblePath) + const lastFullVersion = info.fullVersions[0] + if (node && lastFullVersion !== node) { + info.fullVersions.unshift(node) + Object.values(info.compatible).forEach(v => { + if (v.full.includes(lastFullVersion)) { + v.full.unshift(node) + } + }) + } + const lastLightVersion = info.lightVersions[0] + if (lightClient && lastLightVersion !== lightClient) { + info.lightVersions.unshift(lightClient) + Object.values(info.compatible).forEach(v => { + if (v.light.includes(lastLightVersion)) { + v.light.unshift(lightClient) + } + }) + } + fs.writeFileSync(compatiblePath, `${JSON.stringify(info, null, 2)}\r\n`) +} + const exec = async () => { const latestVersions = await fetchCkbLatestVersion() const builtinVersions = await fetchBuiltinCkbVersion() + const compatibleUpdaterParams = { + node: undefined, + lightClient: undefined, + } if (latestVersions.node !== builtinVersions.node) { fs.writeFileSync(BUILTIN_VERSION_PATH.node, `${latestVersions.node}\n`) + compatibleUpdaterParams.node = getMajorAndMinorVersion(latestVersions.node) } if (latestVersions.lightClient !== builtinVersions.lightClient) { fs.writeFileSync(BUILTIN_VERSION_PATH.lightClient, `${latestVersions.lightClient}\n`) + compatibleUpdaterParams.lightClient = getMajorAndMinorVersion(latestVersions.lightClient) } + + updateCompatible(compatibleUpdaterParams) } exec() From d168e735e972785f0509cb400ab153c60ae64c31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=A5=E5=9B=BD=E5=AE=87?= <841185308@qq.com> Date: Mon, 20 Nov 2023 08:29:44 +0800 Subject: [PATCH 08/15] fix: It's unnecessary to use process.exit to skip create PR. (#2947) --- .github/workflows/update_ckb_client_versions.yml | 2 +- .github/workflows/update_neuron_compatible.yml | 2 -- compatible.json | 2 +- scripts/add-neuron-version-in-compatibility-table.js | 2 -- 4 files changed, 2 insertions(+), 6 deletions(-) diff --git a/.github/workflows/update_ckb_client_versions.yml b/.github/workflows/update_ckb_client_versions.yml index 9f978ded31..e661523a23 100644 --- a/.github/workflows/update_ckb_client_versions.yml +++ b/.github/workflows/update_ckb_client_versions.yml @@ -25,7 +25,7 @@ jobs: id: update_versions run: | npm run update:client-versions - git add .ckb-version .ckb-light-version + git add .ckb-version .ckb-light-version compatible.json - name: Set GPG uses: crazy-max/ghaction-import-gpg@v5 diff --git a/.github/workflows/update_neuron_compatible.yml b/.github/workflows/update_neuron_compatible.yml index c95d5751c7..19363afadd 100644 --- a/.github/workflows/update_neuron_compatible.yml +++ b/.github/workflows/update_neuron_compatible.yml @@ -31,7 +31,6 @@ jobs: git add compatible.json - name: Set GPG - if: ${{ success() }} uses: crazy-max/ghaction-import-gpg@v5 with: gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} @@ -40,7 +39,6 @@ jobs: git_commit_gpgsign: true - name: Open PR to RC branch - if: ${{ success() }} uses: peter-evans/create-pull-request@v5 with: title: Update Neuron compatibility table diff --git a/compatible.json b/compatible.json index 732472a581..4d1db91ee1 100644 --- a/compatible.json +++ b/compatible.json @@ -54,4 +54,4 @@ "light": [] } } -} +} diff --git a/scripts/add-neuron-version-in-compatibility-table.js b/scripts/add-neuron-version-in-compatibility-table.js index b2d2772754..28d755a3cd 100644 --- a/scripts/add-neuron-version-in-compatibility-table.js +++ b/scripts/add-neuron-version-in-compatibility-table.js @@ -18,8 +18,6 @@ const exec = () => { if (newNeuronVersion && lastNeuronVersion !== newNeuronVersion) { info.compatible[newNeuronVersion] = info.compatible[lastNeuronVersion] fs.writeFileSync(compatiblePath, `${JSON.stringify(info, null, 2)}\r\n`) - } else { - process.exit(1) } } From 170f6e48798c95e87883ff11e965684e2c916eec Mon Sep 17 00:00:00 2001 From: homura Date: Mon, 20 Nov 2023 17:51:45 +0800 Subject: [PATCH 09/15] refactor: make withdraw compatible with the light client (#2945) * refactor: make withdraw compatible with the light client * test: ci failed because of unmock methods * chore: unifying and fixing lumos version --- packages/neuron-wallet/package.json | 17 ++++++----- .../src/services/transaction-sender.ts | 24 ++++++++++++--- .../services/tx/transaction-sender.test.ts | 12 +++++++- yarn.lock | 30 ++++++++++++++----- 4 files changed, 62 insertions(+), 21 deletions(-) diff --git a/packages/neuron-wallet/package.json b/packages/neuron-wallet/package.json index 2fbc19f631..db9ddb637f 100644 --- a/packages/neuron-wallet/package.json +++ b/packages/neuron-wallet/package.json @@ -42,14 +42,15 @@ ] }, "dependencies": { - "@ckb-lumos/base": "^0.21.0-next.1", - "@ckb-lumos/bi": "^0.21.0-next.1", - "@ckb-lumos/ckb-indexer": "^0.21.0-next.1", - "@ckb-lumos/codec": "^0.21.0-next.1", - "@ckb-lumos/config-manager": "^0.21.0-next.1", - "@ckb-lumos/hd": "^0.21.0-next.1", - "@ckb-lumos/helpers": "^0.21.0-next.1", - "@ckb-lumos/rpc": "^0.21.0-next.1", + "@ckb-lumos/base": "0.21.0-next.1", + "@ckb-lumos/bi": "0.21.0-next.1", + "@ckb-lumos/ckb-indexer": "0.21.0-next.1", + "@ckb-lumos/codec": "0.21.0-next.1", + "@ckb-lumos/common-scripts": "0.21.0-next.1", + "@ckb-lumos/config-manager": "0.21.0-next.1", + "@ckb-lumos/hd": "0.21.0-next.1", + "@ckb-lumos/helpers": "0.21.0-next.1", + "@ckb-lumos/rpc": "0.21.0-next.1", "@iarna/toml": "2.2.5", "@ledgerhq/hw-transport-node-hid": "6.27.16", "@spore-sdk/core": "0.1.0-beta.9", diff --git a/packages/neuron-wallet/src/services/transaction-sender.ts b/packages/neuron-wallet/src/services/transaction-sender.ts index 65eaa02ccd..e25bc57611 100644 --- a/packages/neuron-wallet/src/services/transaction-sender.ts +++ b/packages/neuron-wallet/src/services/transaction-sender.ts @@ -41,11 +41,11 @@ import { getMultisigStatus } from '../utils/multisig' import { SignStatus } from '../models/offline-sign' import NetworksService from './networks' import { generateRPC } from '../utils/ckb-rpc' -import { CKBRPC } from '@ckb-lumos/rpc' import CellsService from './cells' import hd from '@ckb-lumos/hd' import { getClusterCellByOutPoint } from '@spore-sdk/core' import CellDep, { DepType } from '../models/chain/cell-dep' +import { dao } from '@ckb-lumos/common-scripts' interface SignInfo { witnessArgs: WitnessArgs @@ -840,9 +840,25 @@ export default class TransactionSender { withdrawBlockHash: string ): Promise => { const currentNetwork = NetworksService.getInstance().getCurrent() - const ckb = new CKBRPC(currentNetwork.remote) - const result = await ckb.calculateDaoMaximumWithdraw(depositOutPoint.toSDK(), withdrawBlockHash) - return BigInt(result) + const rpc = generateRPC(currentNetwork.remote, currentNetwork.type) + + let tx = await rpc.getTransaction(depositOutPoint.txHash) + if (tx.txStatus.status !== 'committed') throw new Error('Transaction is not committed yet') + const depositBlockHash = tx.txStatus.blockHash + + const cellOutput = tx.transaction.outputs[+depositOutPoint.index] + const cellOutputData = tx.transaction.outputsData[+depositOutPoint.index] + + const [depositHeader, withDrawHeader] = await Promise.all([ + rpc.getHeader(depositBlockHash), + rpc.getHeader(withdrawBlockHash), + ]) + + return dao.calculateMaximumWithdraw( + { outPoint: depositOutPoint.toSDK(), data: cellOutputData, cellOutput: cellOutput }, + depositHeader.dao, + withDrawHeader.dao + ) } private parseEpoch = (epoch: bigint) => { diff --git a/packages/neuron-wallet/tests/services/tx/transaction-sender.test.ts b/packages/neuron-wallet/tests/services/tx/transaction-sender.test.ts index fae1b30919..692208d273 100644 --- a/packages/neuron-wallet/tests/services/tx/transaction-sender.test.ts +++ b/packages/neuron-wallet/tests/services/tx/transaction-sender.test.ts @@ -158,10 +158,20 @@ jest.doMock('@ckb-lumos/rpc', () => { } }) +jest.doMock('@ckb-lumos/common-scripts', () => { + return { + dao: { + calculateMaximumWithdraw: stubbedCalculateDaoMaximumWithdraw, + }, + } +}) + jest.doMock('utils/ckb-rpc.ts', () => ({ generateRPC() { return { sendTransaction: stubbedSendTransaction, + getTransaction: stubbedGetTransaction, + getHeader: stubbedGetHeader, } }, })) @@ -802,7 +812,7 @@ describe('TransactionSender Test', () => { } stubbedGetHeader.mockResolvedValue(withdrawBlockHeader) - stubbedCalculateDaoMaximumWithdraw.mockResolvedValue(10300000000) + stubbedCalculateDaoMaximumWithdraw.mockResolvedValue(BigInt(10300000000)) stubbedGetNextAddress.mockReturnValue({ address: fakeAddress1, }) diff --git a/yarn.lock b/yarn.lock index 7457799bb0..8a2996bbc2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1703,7 +1703,7 @@ js-xxhash "^1.0.4" lodash.isequal "^4.5.0" -"@ckb-lumos/base@0.21.0-next.1", "@ckb-lumos/base@^0.21.0-next.1": +"@ckb-lumos/base@0.21.0-next.1": version "0.21.0-next.1" resolved "https://registry.yarnpkg.com/@ckb-lumos/base/-/base-0.21.0-next.1.tgz#ad82d0147c479b84bc0e80c3e32ad6a39ee75285" integrity sha512-dJL3pqa28oJcNfYLNOuWRIJCeWhUq9l7l2/SZItb9wIT4MX5pD0Z1tA8/s9qbvwmmsab+QGKaLCHXNNeOvS0hg== @@ -1724,7 +1724,7 @@ dependencies: jsbi "^4.1.0" -"@ckb-lumos/bi@0.21.0-next.1", "@ckb-lumos/bi@^0.21.0-next.1": +"@ckb-lumos/bi@0.21.0-next.1": version "0.21.0-next.1" resolved "https://registry.yarnpkg.com/@ckb-lumos/bi/-/bi-0.21.0-next.1.tgz#357b8da31882ab5e3e3f8aca54c30dd576e4544d" integrity sha512-FaMKBbtr826upcEVYt9/K/hutxHySD21t7ut5yv8lfj6LYcg6hWjtrbCM2INVV6/8HatfAf8YV2KsNRaluyt3A== @@ -1743,7 +1743,7 @@ cross-fetch "^3.1.5" events "^3.3.0" -"@ckb-lumos/ckb-indexer@^0.21.0-next.1": +"@ckb-lumos/ckb-indexer@0.21.0-next.1": version "0.21.0-next.1" resolved "https://registry.yarnpkg.com/@ckb-lumos/ckb-indexer/-/ckb-indexer-0.21.0-next.1.tgz#bc2fd6fcd2c482040565c255d7a9f8fd9269b462" integrity sha512-ftT8Rodv/oXIOZLfsXEOLQnHy05c8Wj3h6QasXPlZlRGMdtWrThGz+XVI6lz4VSIfVMPSbwnYT+Dv7bf8fDfdw== @@ -1763,7 +1763,7 @@ dependencies: "@ckb-lumos/bi" "0.20.0" -"@ckb-lumos/codec@0.21.0-next.1", "@ckb-lumos/codec@^0.21.0-next.1": +"@ckb-lumos/codec@0.21.0-next.1": version "0.21.0-next.1" resolved "https://registry.yarnpkg.com/@ckb-lumos/codec/-/codec-0.21.0-next.1.tgz#a75f5331026039799afb4f3419bea388e220d26c" integrity sha512-b1w4wbIAbuYngNTKtu6np93EYgnmM4tb6NGdaYN0vZ3kyunlODkLWyRHyMo+FGeBdWQjBwBbmxGNyXwDxtTEGQ== @@ -1784,6 +1784,20 @@ "@ckb-lumos/toolkit" "0.20.0" immutable "^4.0.0-rc.12" +"@ckb-lumos/common-scripts@0.21.0-next.1": + version "0.21.0-next.1" + resolved "https://registry.yarnpkg.com/@ckb-lumos/common-scripts/-/common-scripts-0.21.0-next.1.tgz#92e0295f9e123f3fdfe80e02706cc08c6310ffca" + integrity sha512-KhnWbNY1fNKTxp9CR4GAGyWsjjN1eOvidNLFwltLY03n8er2jtoHRbx3t944fIhUMtIwUVkWBi43SqpUCgSJbw== + dependencies: + "@ckb-lumos/base" "0.21.0-next.1" + "@ckb-lumos/bi" "0.21.0-next.1" + "@ckb-lumos/codec" "0.21.0-next.1" + "@ckb-lumos/config-manager" "0.21.0-next.1" + "@ckb-lumos/helpers" "0.21.0-next.1" + "@ckb-lumos/rpc" "0.21.0-next.1" + "@ckb-lumos/toolkit" "0.21.0-next.1" + immutable "^4.3.0" + "@ckb-lumos/config-manager@0.20.0", "@ckb-lumos/config-manager@^0.20.0": version "0.20.0" resolved "https://registry.yarnpkg.com/@ckb-lumos/config-manager/-/config-manager-0.20.0.tgz#f24946971005f62df62e22c3306947b5e820c181" @@ -1795,7 +1809,7 @@ "@types/deep-freeze-strict" "^1.1.0" deep-freeze-strict "^1.1.1" -"@ckb-lumos/config-manager@0.21.0-next.1", "@ckb-lumos/config-manager@^0.21.0-next.1": +"@ckb-lumos/config-manager@0.21.0-next.1": version "0.21.0-next.1" resolved "https://registry.yarnpkg.com/@ckb-lumos/config-manager/-/config-manager-0.21.0-next.1.tgz#927e21a5d9450155ebf766422a707fd3b0856a14" integrity sha512-G8CO+q1RH/Gt8ou8p/N99AUh5hIdU+MZcTZHwABOa4CLbXk2xFenRfeGhHv4u4ddYZ3SLx1zND7pSnbImmrh2A== @@ -1819,7 +1833,7 @@ sha3 "^2.1.3" uuid "^8.3.0" -"@ckb-lumos/hd@^0.21.0-next.1": +"@ckb-lumos/hd@0.21.0-next.1": version "0.21.0-next.1" resolved "https://registry.yarnpkg.com/@ckb-lumos/hd/-/hd-0.21.0-next.1.tgz#ffa4b80b974187982bbfa280138ca1dab0b2df0e" integrity sha512-gISrSs4OWoBVecRnYMfjYQc83aE0Khjjs1KmAkAg1J53PWGeU3kjbUQSCHjF6poFL5ylEARX9vOKixRfm6nktg== @@ -1844,7 +1858,7 @@ bech32 "^2.0.0" immutable "^4.0.0-rc.12" -"@ckb-lumos/helpers@^0.21.0-next.1": +"@ckb-lumos/helpers@0.21.0-next.1": version "0.21.0-next.1" resolved "https://registry.yarnpkg.com/@ckb-lumos/helpers/-/helpers-0.21.0-next.1.tgz#f0f2d9e231f5a266d53df0c60e7b7610b87e10b5" integrity sha512-lSvn2L97be7IlONFTdjjz+/jG6QlpEGyETyrcSfJxeOOtgjicPFaLXLnaTBIt/IElRZ2ZpclbTFvSNcbVOvKdQ== @@ -1883,7 +1897,7 @@ axios "0.27.2" tslib "2.3.1" -"@ckb-lumos/rpc@0.21.0-next.1", "@ckb-lumos/rpc@^0.21.0-next.1": +"@ckb-lumos/rpc@0.21.0-next.1": version "0.21.0-next.1" resolved "https://registry.yarnpkg.com/@ckb-lumos/rpc/-/rpc-0.21.0-next.1.tgz#f31610fc1713ae63e25475d3653ee8cc3eeabc0f" integrity sha512-6IjnME2wGg1rmVnajQ7CTBqbLnXkdNqRERRmnD1J9EnoHBc+onSYSfkC58ZCVCOe0xZIR2vNKmOUQ++dmlKKiQ== From dffd921b3f11e33968cac032d271a8e03f1aacce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=A5=E5=9B=BD=E5=AE=87?= <841185308@qq.com> Date: Wed, 22 Nov 2023 09:07:03 +0800 Subject: [PATCH 10/15] fix: Avoid unexpected dialog shown. (#2928) * fix: Avoid unexpected dialog shown. * fix: Use Object.is to check whether is the same process. * fix: Add annotation --- .../src/components/NervosDAO/index.tsx | 1 + .../src/states/stateProvider/reducer.ts | 1 + packages/neuron-ui/src/utils/getSyncStatus.ts | 12 ++++++- .../src/controllers/export-debug.ts | 12 ++++--- .../neuron-wallet/src/services/ckb-runner.ts | 20 +++++++----- .../src/services/light-runner.ts | 31 ++++++++++++------- packages/neuron-wallet/src/services/node.ts | 21 ++++++++----- .../tests/controllers/export-debug.test.ts | 4 ++- .../neuron-wallet/tests/services/node.test.ts | 10 ++---- 9 files changed, 72 insertions(+), 40 deletions(-) diff --git a/packages/neuron-ui/src/components/NervosDAO/index.tsx b/packages/neuron-ui/src/components/NervosDAO/index.tsx index f1918d5c00..0246117032 100644 --- a/packages/neuron-ui/src/components/NervosDAO/index.tsx +++ b/packages/neuron-ui/src/components/NervosDAO/index.tsx @@ -113,6 +113,7 @@ const NervosDAO = () => { cacheTipBlockNumber, currentTimestamp: Date.now(), url: getCurrentUrl(networkID, networks), + networkID, }) const MemoizedRecords = useMemo(() => { diff --git a/packages/neuron-ui/src/states/stateProvider/reducer.ts b/packages/neuron-ui/src/states/stateProvider/reducer.ts index 74a316aab5..082db564b8 100644 --- a/packages/neuron-ui/src/states/stateProvider/reducer.ts +++ b/packages/neuron-ui/src/states/stateProvider/reducer.ts @@ -209,6 +209,7 @@ export const reducer = produce((state: Draft, action: cacheTipBlockNumber: action.payload.cacheTipBlockNumber, currentTimestamp: Date.now(), url: getCurrentUrl(state.chain.networkID, state.settings.networks), + networkID: state.chain.networkID, }), } break diff --git a/packages/neuron-ui/src/utils/getSyncStatus.ts b/packages/neuron-ui/src/utils/getSyncStatus.ts index 1059b52f33..9067d65a9f 100644 --- a/packages/neuron-ui/src/utils/getSyncStatus.ts +++ b/packages/neuron-ui/src/utils/getSyncStatus.ts @@ -5,6 +5,7 @@ const TEN_MINS = 10 * 60 * 1000 let blockNumber10MinAgo: number = -1 let timestamp10MinAgo: number | undefined let prevUrl: string | undefined +let prevNetworkID: string | undefined export const getSyncStatus = ({ bestKnownBlockNumber, @@ -12,17 +13,26 @@ export const getSyncStatus = ({ cacheTipBlockNumber, currentTimestamp, url, + networkID, }: { bestKnownBlockNumber: number bestKnownBlockTimestamp: number cacheTipBlockNumber: number currentTimestamp: number url: string | undefined + networkID: string }) => { - if ((!timestamp10MinAgo && bestKnownBlockNumber >= 0) || (prevUrl && url !== prevUrl && bestKnownBlockNumber >= 0)) { + if ( + // !timestamp10MinAgo means start sync for the first time + (!timestamp10MinAgo && bestKnownBlockNumber >= 0) || + // prevUrl for change the network remote(change network or eidt the network) + // prevNetworkID for change the network, sometime change network the remote is same. light client mainnet -> testnet + (((prevUrl && url !== prevUrl) || (prevNetworkID && prevNetworkID !== networkID)) && bestKnownBlockNumber >= 0) + ) { timestamp10MinAgo = currentTimestamp blockNumber10MinAgo = bestKnownBlockNumber prevUrl = url + prevNetworkID = networkID } const now = Math.floor(currentTimestamp / 1000) * 1000 diff --git a/packages/neuron-wallet/src/controllers/export-debug.ts b/packages/neuron-wallet/src/controllers/export-debug.ts index 76c0a995e0..38c9af3d38 100644 --- a/packages/neuron-wallet/src/controllers/export-debug.ts +++ b/packages/neuron-wallet/src/controllers/export-debug.ts @@ -12,6 +12,7 @@ import redistCheck from '../utils/redist-check' import SettingsService from '../services/settings' import { generateRPC } from '../utils/ckb-rpc' import { CKBLightRunner } from '../services/light-runner' +import { LIGHT_CLIENT_MAINNET, LIGHT_CLIENT_TESTNET } from '../utils/const' export default class ExportDebugController { #I18N_PATH = 'export-debug-info' @@ -162,10 +163,13 @@ export default class ExportDebugController { } private addBundledCKBLightClientLog() { - const logPath = CKBLightRunner.getInstance().logPath - if (!fs.existsSync(logPath)) { - return + const mainnetLogPath = CKBLightRunner.getInstance().getLogPath(LIGHT_CLIENT_MAINNET) + const testnetLogPath = CKBLightRunner.getInstance().getLogPath(LIGHT_CLIENT_TESTNET) + if (fs.existsSync(mainnetLogPath)) { + this.archive.file(mainnetLogPath, { name: 'bundled-ckb-lignt-client-mainnet.log' }) + } + if (fs.existsSync(testnetLogPath)) { + this.archive.file(testnetLogPath, { name: 'bundled-ckb-lignt-client-testnet.log' }) } - this.archive.file(logPath, { name: 'bundled-ckb-lignt-client.log' }) } } diff --git a/packages/neuron-wallet/src/services/ckb-runner.ts b/packages/neuron-wallet/src/services/ckb-runner.ts index 1aa9ba5c3e..0439e1c9fd 100644 --- a/packages/neuron-wallet/src/services/ckb-runner.ts +++ b/packages/neuron-wallet/src/services/ckb-runner.ts @@ -119,16 +119,16 @@ export const startCkbNode = async () => { stdio[1] = 'pipe' } logger.info(`CKB:\tckb full node will with rpc port ${rpcPort}, listen port ${listenPort}, with options`, options) - ckb = spawn(ckbBinary(), options, { stdio }) + const currentProcess = spawn(ckbBinary(), options, { stdio }) - ckb.stderr?.on('data', data => { + currentProcess.stderr?.on('data', data => { const dataString: string = data.toString() logger.error('CKB:\trun fail:', dataString) if (dataString.includes('CKB wants to migrate the data into new format')) { MigrateSubject.next({ type: 'need-migrate' }) } }) - ckb.stdout?.on('data', data => { + currentProcess.stdout?.on('data', data => { const dataString: string = data.toString() if ( dataString.includes( @@ -142,18 +142,24 @@ export const startCkbNode = async () => { } }) - ckb.on('error', error => { + currentProcess.on('error', error => { logger.error('CKB:\trun fail:', error) isLookingValidTarget = false - ckb = null + if (Object.is(ckb, currentProcess)) { + ckb = null + } }) - ckb.on('close', () => { + currentProcess.on('close', () => { logger.info('CKB:\tprocess closed') isLookingValidTarget = false - ckb = null + if (Object.is(ckb, currentProcess)) { + ckb = null + } }) + ckb = currentProcess + removeOldIndexerIfRunSuccess() } diff --git a/packages/neuron-wallet/src/services/light-runner.ts b/packages/neuron-wallet/src/services/light-runner.ts index 59c1b6d0fb..72f1d0a032 100644 --- a/packages/neuron-wallet/src/services/light-runner.ts +++ b/packages/neuron-wallet/src/services/light-runner.ts @@ -65,7 +65,7 @@ abstract class NodeRunner { async stop() { return new Promise(resolve => { if (this.runnerProcess) { - logger.info('Runner:\tkilling node') + logger.info('Runner:\tkilling node', this.runnerProcess.pid) this.runnerProcess.once('close', () => resolve()) this.runnerProcess.kill() this.runnerProcess = undefined @@ -79,7 +79,7 @@ abstract class NodeRunner { export class CKBLightRunner extends NodeRunner { protected networkType: NetworkType = NetworkType.Light protected binaryName: string = 'ckb-light-client' - protected logStream?: fs.WriteStream + protected logStream: Map = new Map() protected _port: number = 9000 static getInstance(): CKBLightRunner { @@ -143,34 +143,41 @@ export class CKBLightRunner extends NodeRunner { }) this.runnerProcess = runnerProcess - if (!this.logStream) { - this.logStream = fs.createWriteStream(this.logPath) + const network = NetworksService.getInstance().getCurrent() + if (!this.logStream.get(network.id)) { + this.logStream.set(network.id, fs.createWriteStream(this.getLogPath())) } + const logStream = this.logStream.get(network.id) runnerProcess.stderr && runnerProcess.stderr.on('data', data => { const dataString: string = data.toString() logger.error('CKB Light Runner:\trun fail:', dataString) - this.logStream?.write(data) + logStream?.write(data) }) runnerProcess.stdout && runnerProcess.stdout.on('data', data => { - this.logStream?.write(data) + logStream?.write(data) }) - runnerProcess.on('error', error => { + runnerProcess.once('error', error => { logger.error('CKB Light Runner:\trun fail:', error) - this.runnerProcess = undefined + if (Object.is(this.runnerProcess, runnerProcess)) { + this.runnerProcess = undefined + } }) - runnerProcess.on('close', () => { + runnerProcess.once('close', () => { logger.info('CKB Light Runner:\tprocess closed') - this.runnerProcess = undefined + if (Object.is(this.runnerProcess, runnerProcess)) { + this.runnerProcess = undefined + } }) } - get logPath() { - return path.join(logger.transports.file.getFile().path, '..', 'light_client_run.log') + getLogPath(chain?: string) { + const fileName = chain ?? NetworksService.getInstance().getCurrent().chain + return path.join(logger.transports.file.getFile().path, '..', `${fileName}.log`) } async clearNodeCache(): Promise { diff --git a/packages/neuron-wallet/src/services/node.ts b/packages/neuron-wallet/src/services/node.ts index f59d6e035e..37e302e4d9 100644 --- a/packages/neuron-wallet/src/services/node.ts +++ b/packages/neuron-wallet/src/services/node.ts @@ -3,7 +3,7 @@ import path from 'path' import { BI } from '@ckb-lumos/bi' import { app as electronApp, dialog, shell, app } from 'electron' import { t } from 'i18next' -import { interval, BehaviorSubject, merge } from 'rxjs' +import { interval, BehaviorSubject, merge, Subject } from 'rxjs' import { distinctUntilChanged, sampleTime, flatMap, delay, retry, debounceTime } from 'rxjs/operators' import env from '../env' import { ConnectionStatusSubject } from '../models/subjects/node' @@ -42,6 +42,7 @@ class NodeService { public tipNumberSubject = new BehaviorSubject('0') public connectionStatusSubject = new BehaviorSubject(false) + #startNodeSubject = new Subject() private _tipBlockNumber: string = '0' #startedBundledNode: boolean = false @@ -53,6 +54,7 @@ class NodeService { this.start() this.syncConnectionStatus() CurrentNetworkIDSubject.subscribe(this.whenNetworkUpdate) + this.#startNodeSubject.pipe(debounceTime(1000)).subscribe(this.startNode) } public get tipBlockNumber(): string { @@ -77,17 +79,19 @@ class NodeService { } private whenNetworkUpdate = () => { + this.stop?.() this.#startedBundledNode = false this.tipNumberSubject.next('0') this.connectionStatusSubject.next(false) } public start = () => { - const { unsubscribe } = this.tipNumber() - this.stop = unsubscribe + this.stop?.() + const subscribe = this.tipNumber() + this.stop = subscribe.unsubscribe.bind(subscribe) } - public stop: (() => void) | null = null + public stop?: () => void public tipNumber = () => { return interval(this.intervalTime) @@ -122,8 +126,7 @@ class NodeService { if (this.delayTime < 10 * this.intervalTime) { this.delayTime = 2 * this.intervalTime } - const { unsubscribe } = this.tipNumber() - this.stop = unsubscribe + this.start() } ) } @@ -134,11 +137,12 @@ class NodeService { if (isDefaultCKBNeedStart) { logger.info('CKB:\texternal RPC on default uri not detected, starting bundled CKB node.') const redistReady = await redistCheck() - await (redistReady ? this.startNode() : this.showGuideDialog()) + await (redistReady ? this.#startNodeSubject.next() : this.showGuideDialog()) await startMonitor() } else { logger.info('CKB:\texternal RPC on default uri detected, skip starting bundled CKB node.') } + this.start() } public async verifyExternalCkbNode() { @@ -170,7 +174,7 @@ class NodeService { } } - public async startNode() { + public startNode = async () => { try { const network = NetworksService.getInstance().getCurrent() if (network.type === NetworkType.Light) { @@ -191,6 +195,7 @@ class NodeService { public async startNodeIgnoreExternal() { logger.info('CKB:\tignore running external node, and start node with another port') await stopMonitor('ckb') + this.start() const redistReady = await redistCheck() await (redistReady ? this.startNode() : this.showGuideDialog()) await startMonitor() diff --git a/packages/neuron-wallet/tests/controllers/export-debug.test.ts b/packages/neuron-wallet/tests/controllers/export-debug.test.ts index 3d25983003..1bbfbac015 100644 --- a/packages/neuron-wallet/tests/controllers/export-debug.test.ts +++ b/packages/neuron-wallet/tests/controllers/export-debug.test.ts @@ -78,7 +78,9 @@ jest.mock('../../src/services/light-runner', () => { CKBLightRunner: { getInstance() { return { - logPath: '', + getLogPath() { + return '' + }, } }, }, diff --git a/packages/neuron-wallet/tests/services/node.test.ts b/packages/neuron-wallet/tests/services/node.test.ts index 726423e026..12eaadb52b 100644 --- a/packages/neuron-wallet/tests/services/node.test.ts +++ b/packages/neuron-wallet/tests/services/node.test.ts @@ -1,6 +1,7 @@ import { distinctUntilChanged, sampleTime, flatMap, delay, retry } from 'rxjs/operators' import { BUNDLED_CKB_URL, START_WITHOUT_INDEXER } from '../../src/utils/const' import { NetworkType } from '../../src/models/network' +import { scheduler } from 'timers/promises' describe('NodeService', () => { let nodeService: any @@ -9,7 +10,6 @@ describe('NodeService', () => { const stubbedStartLightNode = jest.fn() const stubbedStopLightNode = jest.fn() const stubbedConnectionStatusSubjectNext = jest.fn() - const stubbedCKBSetNode = jest.fn() const stubbedGetTipBlockNumber = jest.fn() const stubbedRxjsDebounceTime = jest.fn() const stubbedCurrentNetworkIDSubjectSubscribe = jest.fn() @@ -37,7 +37,6 @@ describe('NodeService', () => { stubbedStartCKBNode.mockReset() stubbedStopCkbNode.mockReset() stubbedConnectionStatusSubjectNext.mockReset() - stubbedCKBSetNode.mockReset() stubbedGetTipBlockNumber.mockReset() stubbedCurrentNetworkIDSubjectSubscribe.mockReset() stubbedNetworsServiceGet.mockReset() @@ -351,19 +350,16 @@ describe('NodeService', () => { describe('targets to bundled node', () => { const bundledNodeUrl = 'http://127.0.0.1:8114' beforeEach(async () => { - stubbedCKBSetNode.mockImplementation(() => { - nodeService.ckb.node.url = bundledNodeUrl - }) stubbedStartCKBNode.mockResolvedValue(true) redistCheckMock.mockResolvedValue(true) stubbedNetworsServiceGet.mockReturnValue({ remote: bundledNodeUrl, readonly: true }) getLocalNodeInfoMock.mockRejectedValue('not start') await nodeService.tryStartNodeOnDefaultURI() - + await scheduler.wait(1500) jest.advanceTimersByTime(10000) }) it('sets startedBundledNode to true in ConnectionStatusSubject', () => { - expect(stubbedConnectionStatusSubjectNext).toHaveBeenCalledWith({ + expect(stubbedConnectionStatusSubjectNext).toHaveBeenLastCalledWith({ url: bundledNodeUrl, connected: false, isBundledNode: true, From 1f53a2890df35a6de7793f9da13c92d27900f409 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=A5=E5=9B=BD=E5=AE=87?= <841185308@qq.com> Date: Wed, 22 Nov 2023 16:10:22 +0800 Subject: [PATCH 11/15] fix: Fix light client sync slow when fetch much transactions. (#2944) * fix: Fix light client sync slow when fetch much transactions. * fix: Add message send to avoid the tx db has not submit finish yet. * Add annotation Co-authored-by: homura --------- Co-authored-by: homura --- .../sync/light-connector.ts | 24 +++++++++++++++++-- .../src/block-sync-renderer/sync/queue.ts | 6 ++++- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/packages/neuron-wallet/src/block-sync-renderer/sync/light-connector.ts b/packages/neuron-wallet/src/block-sync-renderer/sync/light-connector.ts index 272c510bf3..46a9ad4d59 100644 --- a/packages/neuron-wallet/src/block-sync-renderer/sync/light-connector.ts +++ b/packages/neuron-wallet/src/block-sync-renderer/sync/light-connector.ts @@ -1,7 +1,7 @@ import { BI } from '@ckb-lumos/bi' import { Subject } from 'rxjs' import { queue, QueueObject } from 'async' -import { HexString, QueryOptions } from '@ckb-lumos/base' +import type { HexString, QueryOptions, TransactionWithStatus } from '@ckb-lumos/base' import { Indexer as CkbIndexer, CellCollector } from '@ckb-lumos/ckb-indexer' import logger from '../../utils/logger' import { Address } from '../../models/address' @@ -18,6 +18,7 @@ import AssetAccountInfo from '../../models/asset-account-info' import { DepType } from '../../models/chain/cell-dep' import { molecule } from '@ckb-lumos/codec' import { blockchain } from '@ckb-lumos/base' +import type { Base } from '@ckb-lumos/rpc/lib/Base' interface SyncQueueParam { script: CKBComponents.Script @@ -232,7 +233,9 @@ export default class LightConnector extends Connector { }) return } - this.transactionsSubject.next({ txHashes: result.txs.map(v => v.txHash), params: syncProgress.hash }) + const txHashes = result.txs.map(v => v.txHash) + await this.fetchPreviousOutputs(txHashes) + this.transactionsSubject.next({ txHashes, params: syncProgress.hash }) this.syncInQueue.set(syncProgress.hash, { blockStartNumber: result.lastCursor === '0x' ? parseInt(blockRange[1]) : parseInt(blockRange[0]), blockEndNumber: parseInt(blockRange[1]), @@ -240,6 +243,23 @@ export default class LightConnector extends Connector { }) } + private async fetchPreviousOutputs(txHashes: string[]) { + const transactions = await this.lightRpc + .createBatchRequest<'getTransaction', string[], TransactionWithStatus[]>(txHashes.map(v => ['getTransaction', v])) + .exec() + const previousTxHashes = new Set() + transactions + .flatMap(tx => tx.transaction.inputs) + .forEach(input => { + const previousTxHash = input.previousOutput!.txHash + // exclude the cell base transaction in a block + if (previousTxHash !== `0x${'0'.repeat(64)}`) { + previousTxHashes.add(previousTxHash) + } + }) + await this.lightRpc.createBatchRequest([...previousTxHashes].map(v => ['fetchTransaction' as keyof Base, v])).exec() + } + private async collectLiveCellsByScript(query: LumosCellQuery) { const { lock, type, data } = query if (!lock && !type) { 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 3d3bb0cea1..e53df531d4 100644 --- a/packages/neuron-wallet/src/block-sync-renderer/sync/queue.ts +++ b/packages/neuron-wallet/src/block-sync-renderer/sync/queue.ts @@ -90,6 +90,7 @@ export default class Queue { while (true) { try { await this.#checkAndSave(txHashes) + process.send?.({ channel: 'tx-db-changed' }) break } catch (error) { logger.error('retry saving transactions in 2 seconds due to error:', error) @@ -171,7 +172,10 @@ export default class Queue { }, 1) const drainFetchTxQueue = new Promise((resolve, reject) => { - fetchTxQueue.error(reject) + fetchTxQueue.error(err => { + fetchTxQueue.kill() + reject(err) + }) fetchTxQueue.drain(() => resolve(0)) }) From 3c72ac14054b9ca18c100b04f1ec89c66a83d50c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 23 Nov 2023 08:38:59 +0800 Subject: [PATCH 12/15] Update ckb client versions (#2953) feat: update ckb client versions Co-authored-by: Keith-CY --- .ckb-light-version | 2 +- .ckb-version | 2 +- compatible.json | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.ckb-light-version b/.ckb-light-version index 268b0334e6..937cd78462 100644 --- a/.ckb-light-version +++ b/.ckb-light-version @@ -1 +1 @@ -v0.3.0 +v0.3.1 diff --git a/.ckb-version b/.ckb-version index 2b23e8a911..bfe1211ecc 100644 --- a/.ckb-version +++ b/.ckb-version @@ -1 +1 @@ -v0.111.0 +v0.112.1 diff --git a/compatible.json b/compatible.json index 4d1db91ee1..14fd093098 100644 --- a/compatible.json +++ b/compatible.json @@ -1,5 +1,6 @@ { "fullVersions": [ + "0.112", "0.111", "0.110", "0.109", @@ -17,6 +18,7 @@ "compatible": { "0.111": { "full": [ + "0.112", "0.111", "0.110", "0.109" @@ -28,6 +30,7 @@ }, "0.110": { "full": [ + "0.112", "0.111", "0.110", "0.109" From 163ddf7893f5c420beff110e2664c9fec78069d4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 23 Nov 2023 06:51:12 +0000 Subject: [PATCH 13/15] chore: Update ckb node assume valid target for rc/v0.112.0. --- packages/neuron-wallet/.env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/neuron-wallet/.env b/packages/neuron-wallet/.env index 5c7ab981bd..a7ccb9c69f 100644 --- a/packages/neuron-wallet/.env +++ b/packages/neuron-wallet/.env @@ -117,4 +117,4 @@ DAO_CODE_HASH=0x82d76d1b75fe2fd9a27dfbaa65a039221a380d76c926f378d3f81cf3e7e13f2e MULTISIG_CODE_HASH=0x5c5069eb0857efc65e1bca0c07df34c31663b3622fd3876c876320fc9634e2a8 # CKB NODE OPTIONS -CKB_NODE_ASSUME_VALID_TARGET='0x79cecdd6f41361e2474290224751284312a018528d1d92f4e18dd6d542feddfe' +CKB_NODE_ASSUME_VALID_TARGET='0xef2e2f0ee78e8fcf5bb5ad16892a49724e5f2d4fbc2779396e3d6c93100b9275' From 9fad3b720d8af32535dd180b11a4fe43b5b70f6c Mon Sep 17 00:00:00 2001 From: Keith Date: Thu, 23 Nov 2023 16:08:58 +0900 Subject: [PATCH 14/15] chore: update versions and changelogs --- CHANGELOG.md | 30 +++++++++++++++++++++++++++++ lerna.json | 2 +- package.json | 2 +- packages/neuron-ui/package.json | 2 +- packages/neuron-wallet/package.json | 4 ++-- 5 files changed, 35 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b693e98026..5992c87d9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,33 @@ +# 0.112.0 (2023-11-27) + +### CKB Node & Light Client + +- [CKB@v0.112.1](https://github.com/nervosnetwork/ckb/releases/tag/v0.112.1) was released on Nov. 21st, 2023. This version of CKB node is now bundled and preconfigured in Neuron. +- [CKB Light Client@v0.3.1](https://github.com/nervosnetwork/ckb-light-client/releases/tag/v0.3.1) was released on Nov. 22nd, 2023. This version of CKB Light Client is now bundled and preconfigured in Neuron + +### Assumed valid target + +Block before `0xef2e2f0ee78e8fcf5bb5ad16892a49724e5f2d4fbc2779396e3d6c93100b9275`(at height `11,373,036`) will be skipped in validation.(https://github.com/nervosnetwork/neuron/pull/2955) + +--- + +## New features + +- #2810: Support Spore Protocol.(@homura) +- #2916: Add light client in compatibility table.(@yanguoyu) +- #2926: Refactor switch between light client mainnet and light client testnet to make it more intuitive.(@yanguoyu) + +## Bug fixes + +- #2928: Fix condition of compatibility alert.(@yanguoyu) +- #2935: Fix migration settings.(@yanguoyu) +- #2945: Fix Nervos DAO withdrawal on light client mode.(@homura) +- #2944: Fix requests jam when a synced transaction includes cellbase cells.(@yanguoyu) + + +**Full Changelog**: https://github.com/nervosnetwork/neuron/compare/v0.111.1...v0.112.0 + + # 0.111.1 (2023-11-08) ### CKB Node & Light Client diff --git a/lerna.json b/lerna.json index 0284582121..8fd1da0d48 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "packages": ["packages/*"], - "version": "0.111.1", + "version": "0.112.0", "npmClient": "yarn", "$schema": "node_modules/lerna/schemas/lerna-schema.json" } diff --git a/package.json b/package.json index 143b5c5396..4af4b2de5e 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "neuron", "productName": "Neuron", "description": "CKB Neuron Wallet", - "version": "0.111.1", + "version": "0.112.0", "private": true, "author": { "name": "Nervos Core Dev", diff --git a/packages/neuron-ui/package.json b/packages/neuron-ui/package.json index c2a3713dbc..32eb4e8ed6 100644 --- a/packages/neuron-ui/package.json +++ b/packages/neuron-ui/package.json @@ -1,6 +1,6 @@ { "name": "neuron-ui", - "version": "0.111.1", + "version": "0.112.0", "private": true, "author": { "name": "Nervos Core Dev", diff --git a/packages/neuron-wallet/package.json b/packages/neuron-wallet/package.json index db9ddb637f..03a5eb3e2c 100644 --- a/packages/neuron-wallet/package.json +++ b/packages/neuron-wallet/package.json @@ -3,7 +3,7 @@ "productName": "Neuron", "description": "CKB Neuron Wallet", "homepage": "https://www.nervos.org/", - "version": "0.111.1", + "version": "0.112.0", "private": true, "author": { "name": "Nervos Core Dev", @@ -97,7 +97,7 @@ "electron-builder": "23.6.0", "electron-devtools-installer": "3.2.0", "jest-when": "3.5.2", - "neuron-ui": "0.111.1", + "neuron-ui": "0.112.0", "typescript": "5.0.4" } } From 880607f1d7ec5a1578a50b962eef38cd087a598b Mon Sep 17 00:00:00 2001 From: Keith-CY Date: Thu, 23 Nov 2023 08:25:39 +0000 Subject: [PATCH 15/15] feat: Update Neuron compatibility table --- compatible.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/compatible.json b/compatible.json index 14fd093098..204a2ddda4 100644 --- a/compatible.json +++ b/compatible.json @@ -55,6 +55,18 @@ "0.103" ], "light": [] + }, + "0.112": { + "full": [ + "0.112", + "0.111", + "0.110", + "0.109" + ], + "light": [ + "0.3", + "0.2" + ] } } }