From 7d86454ff5cff38848382674e4d9ceee6392e326 Mon Sep 17 00:00:00 2001 From: Keith Date: Mon, 18 Nov 2019 17:52:47 +0800 Subject: [PATCH 01/43] feat(neuron-ui): add copy address and copy tx hash context menus on the tx detail view. --- .../src/components/Transaction/index.tsx | 85 ++++++++++++++++++- packages/neuron-ui/src/locales/en.json | 4 +- packages/neuron-ui/src/locales/zh.json | 4 +- .../neuron-ui/src/services/remote/index.ts | 11 +++ 4 files changed, 99 insertions(+), 5 deletions(-) diff --git a/packages/neuron-ui/src/components/Transaction/index.tsx b/packages/neuron-ui/src/components/Transaction/index.tsx index 1c9136507f..e73e0b0536 100644 --- a/packages/neuron-ui/src/components/Transaction/index.tsx +++ b/packages/neuron-ui/src/components/Transaction/index.tsx @@ -2,7 +2,14 @@ import React, { useEffect, useState, useMemo, useCallback } from 'react' import { useTranslation } from 'react-i18next' import { Stack, DetailsList, Text, CheckboxVisibility, IColumn, Icon } from 'office-ui-fabric-react' import { currentWallet as currentWalletCache } from 'services/localCache' -import { getTransaction, showErrorMessage, getAllNetworks, getCurrentNetworkID, openExternal } from 'services/remote' +import { + getTransaction, + showErrorMessage, + getAllNetworks, + getCurrentNetworkID, + openExternal, + openContextMenu, +} from 'services/remote' import { ckbCore } from 'services/chain' import { transactionState } from 'states/initStates/chain' @@ -111,7 +118,7 @@ const Transaction = () => { name: t('transaction.index'), minWidth: 60, maxWidth: 60, - onRender: (item?: any | State.DetailedOutput) => { + onRender: (item?: State.DetailedOutput) => { if (item) { return item.outPoint.index } @@ -216,7 +223,7 @@ const Transaction = () => { return } getTransaction({ hash, walletID: currentWallet.id }) - .then((res: any) => { + .then(res => { if (res.status) { setTransaction(res.result) } else { @@ -270,6 +277,75 @@ const Transaction = () => { [t, transaction] ) + const onBasicInfoContextMenu = useCallback( + (property: { label: string; value: string }, index?: number) => { + if (index === 0 && property && property.value) { + const menuTemplate = [ + { + label: t('common.copy-tx-hash'), + click: () => { + window.clipboard.writeText(property.value) + }, + }, + ] + openContextMenu(menuTemplate) + } + }, + [t] + ) + + const onInputContextMenu = useCallback( + (input?: State.DetailedInput) => { + if (input && input.lock && input.lock.args) { + try { + const address = ckbCore.utils.bech32Address(input.lock.args, { + prefix: addressPrefix, + type: ckbCore.utils.AddressType.HashIdx, + codeHashOrCodeHashIndex: '0x00', + }) + const menuTemplate = [ + { + label: t('common.copy-address'), + click: () => { + window.clipboard.writeText(address) + }, + }, + ] + openContextMenu(menuTemplate) + } catch (err) { + console.error(err) + } + } + }, + [addressPrefix, t] + ) + + const onOutputContextMenu = useCallback( + (output?: State.DetailedOutput) => { + if (output && output.lock && output.lock.args) { + try { + const address = ckbCore.utils.bech32Address(output.lock.args, { + prefix: addressPrefix, + type: ckbCore.utils.AddressType.HashIdx, + codeHashOrCodeHashIndex: '0x00', + }) + const menuTemplate = [ + { + label: t('common.copy-address'), + click: () => { + window.clipboard.writeText(address) + }, + }, + ] + openContextMenu(menuTemplate) + } catch (err) { + console.error(err) + } + } + }, + [addressPrefix, t] + ) + if (error.code) { return ( @@ -290,6 +366,7 @@ const Transaction = () => { checkboxVisibility={CheckboxVisibility.hidden} compact isHeaderVisible={false} + onItemContextMenu={onBasicInfoContextMenu} /> @@ -303,6 +380,7 @@ const Transaction = () => { items={transaction.inputs} columns={inputColumns} checkboxVisibility={CheckboxVisibility.hidden} + onItemContextMenu={onInputContextMenu} compact isHeaderVisible /> @@ -317,6 +395,7 @@ const Transaction = () => { items={transaction.outputs} columns={outputColumns} checkboxVisibility={CheckboxVisibility.hidden} + onItemContextMenu={onOutputContextMenu} compact isHeaderVisible /> diff --git a/packages/neuron-ui/src/locales/en.json b/packages/neuron-ui/src/locales/en.json index 7521caf19c..41ee775adf 100644 --- a/packages/neuron-ui/src/locales/en.json +++ b/packages/neuron-ui/src/locales/en.json @@ -241,7 +241,9 @@ "toggle": { "on": "On", "off": "Off" - } + }, + "copy-tx-hash": "Copy transaction hash", + "copy-address": "Copy address" }, "notification-panel": { "title": "Notifications" diff --git a/packages/neuron-ui/src/locales/zh.json b/packages/neuron-ui/src/locales/zh.json index 4809dc1eae..09b33fc319 100644 --- a/packages/neuron-ui/src/locales/zh.json +++ b/packages/neuron-ui/src/locales/zh.json @@ -241,7 +241,9 @@ "toggle": { "on": "开", "off": "关" - } + }, + "copy-tx-hash": "复制交易 Hash", + "copy-address": "复制地址" }, "notification-panel": { "title": "通知中心" diff --git a/packages/neuron-ui/src/services/remote/index.ts b/packages/neuron-ui/src/services/remote/index.ts index 4d0f24c5ae..1e03678d54 100644 --- a/packages/neuron-ui/src/services/remote/index.ts +++ b/packages/neuron-ui/src/services/remote/index.ts @@ -81,6 +81,16 @@ export const openExternal = (url: string) => { } } +export const openContextMenu = (template: { label: string; click: Function }[]): void => { + if (!window.remote) { + window.alert(REMOTE_MODULE_NOT_FOUND) + } else { + const { Menu } = window.remote.require('electron') + const menu = Menu.buildFromTemplate(template) + menu.popup() + } +} + export default { getLocale, validateMnemonic, @@ -90,4 +100,5 @@ export default { showOpenDialog, getWinID, openExternal, + openContextMenu, } From f28d29ee1b34310a9e7209baa6a40cd61808916b Mon Sep 17 00:00:00 2001 From: Chen Yu Date: Mon, 18 Nov 2019 23:05:25 +0800 Subject: [PATCH 02/43] Update packages/neuron-ui/src/locales/en.json Co-Authored-By: James Chen --- packages/neuron-ui/src/locales/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/neuron-ui/src/locales/en.json b/packages/neuron-ui/src/locales/en.json index 41ee775adf..33bbb59cc8 100644 --- a/packages/neuron-ui/src/locales/en.json +++ b/packages/neuron-ui/src/locales/en.json @@ -242,7 +242,7 @@ "on": "On", "off": "Off" }, - "copy-tx-hash": "Copy transaction hash", + "copy-tx-hash": "Copy Transaction Hash", "copy-address": "Copy address" }, "notification-panel": { From 913341ba8ed9c75f74f50e3fdc7f4d9f3469e45f Mon Sep 17 00:00:00 2001 From: Chen Yu Date: Mon, 18 Nov 2019 23:05:37 +0800 Subject: [PATCH 03/43] Update packages/neuron-ui/src/locales/en.json Co-Authored-By: James Chen --- packages/neuron-ui/src/locales/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/neuron-ui/src/locales/en.json b/packages/neuron-ui/src/locales/en.json index 33bbb59cc8..90f8907dfd 100644 --- a/packages/neuron-ui/src/locales/en.json +++ b/packages/neuron-ui/src/locales/en.json @@ -243,7 +243,7 @@ "off": "Off" }, "copy-tx-hash": "Copy Transaction Hash", - "copy-address": "Copy address" + "copy-address": "Copy Address" }, "notification-panel": { "title": "Notifications" From 8af3bb1ba18d6704401426769eab80f15d663f18 Mon Sep 17 00:00:00 2001 From: classicalliu Date: Wed, 20 Nov 2019 14:15:43 +0800 Subject: [PATCH 04/43] chore: remove useless sendCapacity --- packages/neuron-wallet/src/controllers/api.ts | 15 ---- .../neuron-wallet/src/controllers/wallets.ts | 71 ++++++------------- .../neuron-wallet/src/services/wallets.ts | 16 ----- 3 files changed, 21 insertions(+), 81 deletions(-) diff --git a/packages/neuron-wallet/src/controllers/api.ts b/packages/neuron-wallet/src/controllers/api.ts index 7316bfbfd4..5aa1546cf2 100644 --- a/packages/neuron-wallet/src/controllers/api.ts +++ b/packages/neuron-wallet/src/controllers/api.ts @@ -158,21 +158,6 @@ export default class ApiController { return WalletsController.getAllAddresses(id) } - @MapApiResponse - public static async sendCapacity(params: { - id: string - walletID: string - items: { - address: string - capacity: string - }[] - password: string - fee: string - description?: string - }) { - return WalletsController.sendCapacity(params) - } - @MapApiResponse public static async sendTx(params: { walletID: string diff --git a/packages/neuron-wallet/src/controllers/wallets.ts b/packages/neuron-wallet/src/controllers/wallets.ts index 51c6e8d555..1ea1ca4f30 100644 --- a/packages/neuron-wallet/src/controllers/wallets.ts +++ b/packages/neuron-wallet/src/controllers/wallets.ts @@ -321,56 +321,6 @@ export default class WalletsController { } } - public static async sendCapacity(params: { - id: string - walletID: string - items: { - address: string - capacity: string - }[] - password: string - fee: string - description?: string - }) { - if (!params) { - throw new IsRequired('Parameters') - } - // set default feeRate - let feeRate = '0' - if (!params.fee || params.fee === '0') { - feeRate = '1000' - } - - const isMainnet = NetworksService.getInstance().isMainnet() - params.items.forEach(item => { - if (isMainnet && !item.address.startsWith('ckb')) { - throw new MainnetAddressRequired(item.address) - } - - if (!isMainnet && !item.address.startsWith('ckt')) { - throw new TestnetAddressRequired(item.address) - } - - if (!this.verifyAddress(item.address)) { - throw new InvalidAddress(item.address) - } - }) - - const walletsService = WalletsService.getInstance() - const hash = await walletsService.sendCapacity( - params.walletID, - params.items, - params.password, - params.fee, - feeRate, - params.description - ) - return { - status: ResponseCode.Success, - result: hash, - } - } - public static async sendTx(params: { walletID: string tx: TransactionWithoutHash @@ -380,6 +330,7 @@ export default class WalletsController { if (!params) { throw new IsRequired('Parameters') } + const walletsService = WalletsService.getInstance() const hash = await walletsService.sendTx( params.walletID, @@ -405,6 +356,9 @@ export default class WalletsController { if (!params) { throw new IsRequired('Parameters') } + const addresses: string[] = params.items.map(i => i.address) + WalletsController.checkAddresses(addresses) + const walletsService = WalletsService.getInstance() const tx = await walletsService.generateTx( params.walletID, @@ -522,6 +476,23 @@ export default class WalletsController { } } + private static checkAddresses = (addresses: string[]) => { + const isMainnet = NetworksService.getInstance().isMainnet() + addresses.forEach(address => { + if (isMainnet && !address.startsWith('ckb')) { + throw new MainnetAddressRequired(address) + } + + if (!isMainnet && !address.startsWith('ckt')) { + throw new TestnetAddressRequired(address) + } + + if (!WalletsController.verifyAddress(address)) { + throw new InvalidAddress(address) + } + }) + } + private static verifyAddress = (address: string): boolean => { if (typeof address !== 'string' || address.length !== 46) { return false diff --git a/packages/neuron-wallet/src/services/wallets.ts b/packages/neuron-wallet/src/services/wallets.ts index e8bf140b93..8ca0332b8e 100644 --- a/packages/neuron-wallet/src/services/wallets.ts +++ b/packages/neuron-wallet/src/services/wallets.ts @@ -329,22 +329,6 @@ export default class WalletService { this.listStore.clear() } - public sendCapacity = async ( - walletID: string = '', - items: { - address: string - capacity: string - }[] = [], - password: string = '', - fee: string = '0', - feeRate: string = '0', - description: string = '' - ): Promise => { - const tx = await this.generateTx(walletID, items, fee, feeRate) - - return this.sendTx(walletID, tx, password, description) - } - public sendTx = async (walletID: string = '', tx: TransactionWithoutHash, password: string = '', description: string = '') => { const wallet = this.get(walletID) if (!wallet) { From f94ea30650836400ab48b36258b6db41432acd3e Mon Sep 17 00:00:00 2001 From: classicalliu Date: Wed, 20 Nov 2019 14:20:18 +0800 Subject: [PATCH 05/43] chore: remove useless computeCycles --- packages/neuron-wallet/src/controllers/api.ts | 5 ----- .../neuron-wallet/src/controllers/wallets.ts | 12 ------------ .../neuron-wallet/src/services/wallets.ts | 19 ------------------- 3 files changed, 36 deletions(-) diff --git a/packages/neuron-wallet/src/controllers/api.ts b/packages/neuron-wallet/src/controllers/api.ts index 5aa1546cf2..de2256d98d 100644 --- a/packages/neuron-wallet/src/controllers/api.ts +++ b/packages/neuron-wallet/src/controllers/api.ts @@ -212,11 +212,6 @@ export default class ApiController { return WalletsController.withdrawFromDao(params) } - @MapApiResponse - public static async computeCycles(params: { walletID: string; capacities: string }) { - return WalletsController.computeCycles(params) - } - @MapApiResponse public static async updateAddressDescription(params: { walletID: string diff --git a/packages/neuron-wallet/src/controllers/wallets.ts b/packages/neuron-wallet/src/controllers/wallets.ts index 1ea1ca4f30..d6c632e3da 100644 --- a/packages/neuron-wallet/src/controllers/wallets.ts +++ b/packages/neuron-wallet/src/controllers/wallets.ts @@ -440,18 +440,6 @@ export default class WalletsController { } } - public static async computeCycles(params: { walletID: string; capacities: string }) { - if (!params) { - throw new IsRequired('Parameters') - } - const walletsService = WalletsService.getInstance() - const cycles = await walletsService.computeCycles(params.walletID, params.capacities) - return { - status: ResponseCode.Success, - result: cycles, - } - } - public static async updateAddressDescription({ walletID, address, diff --git a/packages/neuron-wallet/src/services/wallets.ts b/packages/neuron-wallet/src/services/wallets.ts index 8ca0332b8e..9263a7ad86 100644 --- a/packages/neuron-wallet/src/services/wallets.ts +++ b/packages/neuron-wallet/src/services/wallets.ts @@ -34,7 +34,6 @@ const fileService = FileService.getInstance() const MODULE_NAME = 'wallets' const DEBOUNCE_TIME = 200 -const SECP_CYCLES = BigInt('1440000') export interface Wallet { id: string @@ -751,24 +750,6 @@ export default class WalletService { return (BigInt(0x20) << BigInt(56)) + (length << BigInt(40)) + (index << BigInt(24)) + number } - public computeCycles = async (walletID: string = '', capacities: string): Promise => { - const wallet = this.get(walletID) - if (!wallet) { - throw new WalletNotFound(walletID) - } - - const addressInfos = this.getAddressInfos(walletID) - - const addresses: string[] = addressInfos.map(info => info.address) - - const lockHashes: string[] = new LockUtils(await LockUtils.systemScript()).addressesToAllLockHashes(addresses) - - const { inputs } = await CellsService.gatherInputs(capacities, lockHashes, '0') - const cycles = SECP_CYCLES * BigInt(inputs.length) - - return cycles.toString() - } - // path is a BIP44 full path such as "m/44'/309'/0'/0/0" public getAddressInfos = (walletID: string): AddressInterface[] => { const wallet = this.get(walletID) From 0f3e08f78e078ecfdd613767e5305f5c141b53cb Mon Sep 17 00:00:00 2001 From: classicalliu Date: Wed, 20 Nov 2019 14:24:58 +0800 Subject: [PATCH 06/43] chore: remove useless signWitness --- .../neuron-wallet/src/services/wallets.ts | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/packages/neuron-wallet/src/services/wallets.ts b/packages/neuron-wallet/src/services/wallets.ts index 9263a7ad86..795fd112be 100644 --- a/packages/neuron-wallet/src/services/wallets.ts +++ b/packages/neuron-wallet/src/services/wallets.ts @@ -764,26 +764,6 @@ export default class WalletService { return AddressService.nextUnusedChangeAddress(walletId)!.address } - public signWitness = ( - lock: string | undefined, - privateKey: string, - txHash: string, - inputType: string | undefined = undefined, - outputType: string | undefined = undefined - ): string => { - const witnessArg: CKBComponents.WitnessArgs = { - lock, - inputType, - outputType, - } - const result = core.signWitnesses(privateKey)({ - transactionHash: txHash, - witnesses: [witnessArg] - }) - - return result[0] as string - } - // Derive all child private keys for specified BIP44 paths. public getPrivateKeys = (wallet: Wallet, paths: string[], password: string): PathAndPrivateKey[] => { const masterPrivateKey = wallet.loadKeystore().extendedPrivateKey(password) From 5000eddd2ce00faed8761dd887ced9cdbb567dd9 Mon Sep 17 00:00:00 2001 From: classicalliu Date: Wed, 20 Nov 2019 14:36:30 +0800 Subject: [PATCH 07/43] fix: sign witnesses test --- .../neuron-wallet/tests/services/wallets.test.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/neuron-wallet/tests/services/wallets.test.ts b/packages/neuron-wallet/tests/services/wallets.test.ts index 0478b44101..7ffc0bbc03 100644 --- a/packages/neuron-wallet/tests/services/wallets.test.ts +++ b/packages/neuron-wallet/tests/services/wallets.test.ts @@ -3,6 +3,7 @@ import Keystore from '../../src/models/keys/keystore' import Keychain from '../../src/models/keys/keychain' import { mnemonicToSeedSync } from '../../src/models/keys/mnemonic' import { ExtendedPrivateKey, AccountExtendedPublicKey } from '../../src/models/keys/key' +import Core from '@nervosnetwork/ckb-sdk-core' describe('wallet service', () => { let walletService: WalletService @@ -164,14 +165,21 @@ describe('wallet service', () => { }) describe('sign witness', () => { - const witness: string = '' + const witness = { + lock: undefined, + inputType: undefined, + outputType: undefined, + } const privateKey: string = '0xe79f3207ea4980b7fed79956d5934249ceac4751a4fae01a0f7c4a96884bc4e3' const txHash = '0x00f5f31941964004d665a8762df8eb4fab53b5ef8437b7d34a38e018b1409054' - const expectedData = '0x5500000010000000550000005500000041000000aa6de884b0dd0378383cedddc39790b5cad66e42d5dc7655de728ee7eb3a53be071605d76641ad26766c6ed4864e67dbc2cd1526e006c9be7ccfa9b8cbf9e7c701' + const expectedData = ['0x5500000010000000550000005500000041000000aa6de884b0dd0378383cedddc39790b5cad66e42d5dc7655de728ee7eb3a53be071605d76641ad26766c6ed4864e67dbc2cd1526e006c9be7ccfa9b8cbf9e7c701'] it('success', () => { - const wallet = new WalletService() - const newWitness = wallet.signWitness(witness, privateKey, txHash) + const core = new Core('') + const newWitness = core.signWitnesses(privateKey)({ + witnesses: [witness], + transactionHash: txHash + }) expect(newWitness).toEqual(expectedData) }) }) From f3a999d00f02fb5d37b327a7e69cc1fdfea7a998 Mon Sep 17 00:00:00 2001 From: classicalliu Date: Thu, 21 Nov 2019 19:43:20 +0800 Subject: [PATCH 08/43] test: test for updateInputLock --- .../services/tx/indexer-transaction.test.ts | 108 ++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 packages/neuron-wallet/tests/services/tx/indexer-transaction.test.ts diff --git a/packages/neuron-wallet/tests/services/tx/indexer-transaction.test.ts b/packages/neuron-wallet/tests/services/tx/indexer-transaction.test.ts new file mode 100644 index 0000000000..b7d3f58ddf --- /dev/null +++ b/packages/neuron-wallet/tests/services/tx/indexer-transaction.test.ts @@ -0,0 +1,108 @@ +import TransactionEntity from '../../../src/database/chain/entities/transaction' +import OutputEntity from '../../../src/database/chain/entities/output' +import InputEntity from '../../../src/database/chain/entities/input' +import { getConnection } from 'typeorm' +import { TransactionStatus, ScriptHashType } from '../../../src/types/cell-types' +import initConnection from '../../../src/database/chain/ormconfig' +import IndexerTransaction from '../../../src/services/tx/indexer-transaction' +import { OutputStatus } from '../../../src/services/tx/params' + +describe('IndexerTransaction', () => { + const tx1: TransactionEntity = new TransactionEntity() + tx1.hash = '0x0001' + tx1.version = '0x0' + tx1.cellDeps = [] + tx1.headerDeps = [] + tx1.witnesses = [] + tx1.timestamp = (+new Date()).toString() + tx1.blockNumber = '0x1' + tx1.blockHash = '0x000001' + tx1.status = TransactionStatus.Success + tx1.inputs = [] + tx1.outputs = [] + + const tx1Input = new InputEntity() + tx1Input.outPointTxHash = '0x0000' + tx1Input.outPointIndex = '0' + tx1Input.since = '0' + tx1Input.lockHash = '0x' + tx1Input.capacity = '100' + tx1.inputs.push(tx1Input) + + const tx1Output: OutputEntity = new OutputEntity() + tx1Output.capacity = '100000000000' + tx1Output.outPointTxHash = tx1.hash + tx1Output.outPointIndex = '0' + tx1Output.lock = {"args":"0x94c1720fdff98d1c0100cfb0e7ae42e470b53019","codeHash":"0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8","hashType":"type" as ScriptHashType} + tx1Output.status = 'live' + tx1Output.lockHash = '0xb58a6fa6f2c57ed45fbdfc7fcebd5c79575590ecf190b72fa6e6a767d57cb105' + tx1Output.hasData = false + + tx1.outputs.push(tx1Output) + + + const tx2 = new TransactionEntity() + tx2.hash = '0x0002' + tx2.version = '0x0' + tx2.cellDeps = [] + tx2.headerDeps = [] + tx2.witnesses = [] + tx2.timestamp = (+new Date()).toString() + tx2.blockNumber = '0x2' + tx2.blockHash = '0x000002' + tx2.status = TransactionStatus.Success + tx2.inputs = [] + tx2.outputs = [] + + const tx2Input = new InputEntity() + tx2Input.outPointTxHash = tx1.hash + tx2Input.outPointIndex = '0' + tx2Input.since = '0' + tx2Input.lockHash = null // tx1Output.lockHash + tx2Input.capacity = null // tx1Output.capacity + tx2.inputs.push(tx2Input) + + const tx2Output = new OutputEntity() + tx2Output.capacity = '50000000000' + tx2Output.outPointTxHash = tx2.hash + tx2Output.outPointIndex = '0' + tx2Output.lock = {"args":"0x94c1720fdff98d1c0100cfb0e7ae42e470b53019","codeHash":"0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8","hashType":"type" as ScriptHashType} + tx2Output.status = 'live' + tx2Output.lockHash = '0xb58a6fa6f2c57ed45fbdfc7fcebd5c79575590ecf190b72fa6e6a767d57cb105' + tx2Output.hasData = false + tx2.outputs.push(tx2Output) + + beforeAll(async () => { + await initConnection('0x1234') + }) + + afterAll(async () => { + await getConnection().close() + }) + + it('updateInputLockHash', async () => { + await getConnection().manager.save([tx1, tx1Input, tx1Output, tx2, tx2Input, tx2Output]) + + await IndexerTransaction.updateInputLockHash(tx2Input.outPointTxHash!, tx2Input.outPointIndex!) + + await tx1Output.reload() + expect(tx1Output.status).toEqual(OutputStatus.Dead) + await tx2Input.reload() + expect(tx2Input.lockHash).toEqual(tx1Output.lockHash) + expect(tx2Input.capacity).toEqual(tx1Output.capacity) + + const inputCount: number = await getConnection() + .getRepository(InputEntity) + .createQueryBuilder('input') + .getCount() + + expect(inputCount).toEqual(2) + + const outputCount: number = await getConnection() + .getRepository(OutputEntity) + .createQueryBuilder('output') + .getCount() + + expect(outputCount).toEqual(2) + }) +}) From 60ec486bc0a27419ac34846b201d7254c672a6da Mon Sep 17 00:00:00 2001 From: classicalliu Date: Fri, 22 Nov 2019 15:10:51 +0800 Subject: [PATCH 09/43] fix: clean lock utils info and dao utils info when switch network --- packages/neuron-wallet/src/database/chain/cleaner.ts | 2 +- packages/neuron-wallet/src/models/dao-utils.ts | 4 ++++ packages/neuron-wallet/src/models/lock-utils.ts | 10 ++++++++-- .../src/startup/sync-block-task/create.ts | 5 +++++ 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/packages/neuron-wallet/src/database/chain/cleaner.ts b/packages/neuron-wallet/src/database/chain/cleaner.ts index 30ee82a673..28e0d0c28a 100644 --- a/packages/neuron-wallet/src/database/chain/cleaner.ts +++ b/packages/neuron-wallet/src/database/chain/cleaner.ts @@ -18,4 +18,4 @@ export default class ChainCleaner { } }) } -} \ No newline at end of file +} diff --git a/packages/neuron-wallet/src/models/dao-utils.ts b/packages/neuron-wallet/src/models/dao-utils.ts index 04d76060c5..921b18c1ba 100644 --- a/packages/neuron-wallet/src/models/dao-utils.ts +++ b/packages/neuron-wallet/src/models/dao-utils.ts @@ -45,6 +45,10 @@ export default class DaoUtils { return DaoUtils.daoScriptInfo } + static cleanInfoWhenSwitchNetwork(): void { + DaoUtils.daoScriptInfo = undefined + } + static setDaoScript(info: SystemScript) { DaoUtils.daoScriptInfo = info DaoUtils.previousURL = NodeService.getInstance().core.rpc.node.url diff --git a/packages/neuron-wallet/src/models/lock-utils.ts b/packages/neuron-wallet/src/models/lock-utils.ts index 2ef84f8e51..424bd43a54 100644 --- a/packages/neuron-wallet/src/models/lock-utils.ts +++ b/packages/neuron-wallet/src/models/lock-utils.ts @@ -21,9 +21,11 @@ const subscribed = (target: any, propertyName: string) => { let value: any Object.defineProperty(target, propertyName, { get: () => value, - set: (info: { codeHash: string }) => { - SystemScriptSubject.next({ codeHash: info.codeHash }) + set: (info: SystemScript | undefined) => { value = info + if (info) { + SystemScriptSubject.next({ codeHash: info.codeHash }) + } }, }) } @@ -75,6 +77,10 @@ export default class LockUtils { return LockUtils.systemScriptInfo } + static cleanInfoWhenSwitchNetwork(): void { + LockUtils.systemScriptInfo = undefined + } + static setSystemScript(info: SystemScript) { LockUtils.systemScriptInfo = info LockUtils.previousURL = NodeService.getInstance().core.rpc.node.url diff --git a/packages/neuron-wallet/src/startup/sync-block-task/create.ts b/packages/neuron-wallet/src/startup/sync-block-task/create.ts index 19b8d04fe9..3393964d72 100644 --- a/packages/neuron-wallet/src/startup/sync-block-task/create.ts +++ b/packages/neuron-wallet/src/startup/sync-block-task/create.ts @@ -12,6 +12,8 @@ import logger from 'utils/logger' import NodeService from 'services/node' import NetworksService from 'services/networks' import { distinctUntilChanged } from 'rxjs/operators' +import LockUtils from 'models/lock-utils' +import DaoUtils from 'models/dao-utils' export { genesisBlockHash } @@ -29,6 +31,9 @@ export interface DatabaseInitParams { // network switch or network connect const networkChange = async (network: NetworkWithID) => { await InitDatabase.getInstance().stopAndWait() + // clean LockUtils info and DaoUtils info + LockUtils.cleanInfoWhenSwitchNetwork() + DaoUtils.cleanInfoWhenSwitchNetwork() const info = await InitDatabase.getInstance().init(network) DataUpdateSubject.next({ From a0b247013f541e9596a246e6375b5accc70a1545 Mon Sep 17 00:00:00 2001 From: classicalliu Date: Fri, 22 Nov 2019 15:44:34 +0800 Subject: [PATCH 10/43] fix: also clean lock/dao info in renderer process --- .../neuron-wallet/src/models/lock-utils.ts | 18 ++---------------- .../src/startup/sync-block-task/indexer.ts | 5 +++++ .../src/startup/sync-block-task/sync.ts | 7 ++++++- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/packages/neuron-wallet/src/models/lock-utils.ts b/packages/neuron-wallet/src/models/lock-utils.ts index 424bd43a54..70b941d600 100644 --- a/packages/neuron-wallet/src/models/lock-utils.ts +++ b/packages/neuron-wallet/src/models/lock-utils.ts @@ -17,19 +17,6 @@ export interface SystemScript { hashType: ScriptHashType } -const subscribed = (target: any, propertyName: string) => { - let value: any - Object.defineProperty(target, propertyName, { - get: () => value, - set: (info: SystemScript | undefined) => { - value = info - if (info) { - SystemScriptSubject.next({ codeHash: info.codeHash }) - } - }, - }) -} - export default class LockUtils { systemScript: SystemScript @@ -37,10 +24,9 @@ export default class LockUtils { this.systemScript = systemScript } - @subscribed - static systemScriptInfo: SystemScript | undefined + private static systemScriptInfo: SystemScript | undefined - static previousURL: string | undefined + private static previousURL: string | undefined static async loadSystemScript(nodeURL: string): Promise { const core = new Core(nodeURL) diff --git a/packages/neuron-wallet/src/startup/sync-block-task/indexer.ts b/packages/neuron-wallet/src/startup/sync-block-task/indexer.ts index cef634c18e..ca84a99053 100644 --- a/packages/neuron-wallet/src/startup/sync-block-task/indexer.ts +++ b/packages/neuron-wallet/src/startup/sync-block-task/indexer.ts @@ -5,6 +5,7 @@ import IndexerQueue, { LockHashInfo } from 'services/indexer/queue' import { Address } from 'database/address/address-dao' import initConnection from 'database/chain/ormconfig' +import DaoUtils from 'models/dao-utils' const { nodeService, addressCreatedSubject, walletCreatedSubject } = remote.require('./startup/sync-block-task/params') @@ -24,6 +25,10 @@ export const switchNetwork = async (nodeURL: string, genesisBlockHash: string, _ await indexerQueue.stopAndWait() } + // clean LockUtils info and DaoUtils info + LockUtils.cleanInfoWhenSwitchNetwork() + DaoUtils.cleanInfoWhenSwitchNetwork() + // disconnect old connection and connect to new database await initConnection(genesisBlockHash) // load lockHashes diff --git a/packages/neuron-wallet/src/startup/sync-block-task/sync.ts b/packages/neuron-wallet/src/startup/sync-block-task/sync.ts index e0a05985a1..fcf3380c37 100644 --- a/packages/neuron-wallet/src/startup/sync-block-task/sync.ts +++ b/packages/neuron-wallet/src/startup/sync-block-task/sync.ts @@ -4,6 +4,7 @@ import LockUtils from 'models/lock-utils' import BlockListener from 'services/sync/block-listener' import { Address } from 'database/address/address-dao' import initConnection from 'database/chain/ormconfig' +import DaoUtils from 'models/dao-utils' const { nodeService, addressCreatedSubject, walletCreatedSubject } = remote.require('./startup/sync-block-task/params') @@ -31,6 +32,10 @@ export const switchNetwork = async (url: string, genesisBlockHash: string, _chai await blockListener.stopAndWait() } + // clean LockUtils info and DaoUtils info + LockUtils.cleanInfoWhenSwitchNetwork() + DaoUtils.cleanInfoWhenSwitchNetwork() + // disconnect old connection and connect to new database await initConnection(genesisBlockHash) // load lockHashes @@ -79,4 +84,4 @@ export const switchNetwork = async (url: string, genesisBlockHash: string, _chai }) blockListener.start() -} \ No newline at end of file +} From 763efb33de0d8a18ed18652c104f3db04662fbf4 Mon Sep 17 00:00:00 2001 From: Keith Date: Fri, 22 Nov 2019 16:07:27 +0800 Subject: [PATCH 11/43] refactor(neuron-ui): refactor the method of getting maximum withdraw --- .../components/NervosDAO/WithdrawDialog.tsx | 20 +++++++++---------- .../src/components/NervosDAO/index.tsx | 8 ++++---- packages/neuron-ui/src/services/chain.ts | 4 +++- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/packages/neuron-ui/src/components/NervosDAO/WithdrawDialog.tsx b/packages/neuron-ui/src/components/NervosDAO/WithdrawDialog.tsx index 02eac05dc7..238cd784c6 100644 --- a/packages/neuron-ui/src/components/NervosDAO/WithdrawDialog.tsx +++ b/packages/neuron-ui/src/components/NervosDAO/WithdrawDialog.tsx @@ -2,7 +2,7 @@ import React, { useState, useEffect } from 'react' import { Dialog, DialogFooter, DefaultButton, PrimaryButton, DialogType, Text } from 'office-ui-fabric-react' import { useTranslation } from 'react-i18next' import { shannonToCKBFormatter, localNumberFormatter } from 'utils/formatters' -import { ckbCore } from 'services/chain' +import { calculateDaoMaximumWithdraw, getBlock } from 'services/chain' import calculateTargetEpochNumber from 'utils/calculateClaimEpochNumber' import { epochParser } from 'utils/parsers' @@ -26,8 +26,7 @@ const WithdrawDialog = ({ if (!record) { return } - ckbCore.rpc - .getBlock(record.blockHash) + getBlock(record.blockHash) .then(b => { setDepositEpoch(b.header.epoch) }) @@ -40,14 +39,13 @@ const WithdrawDialog = ({ return } - ;(ckbCore.rpc as any) - .calculateDaoMaximumWithdraw( - { - txHash: record.outPoint.txHash, - index: `0x${BigInt(record.outPoint.index).toString(16)}`, - }, - tipBlockHash - ) + calculateDaoMaximumWithdraw( + { + txHash: record.outPoint.txHash, + index: `0x${BigInt(record.outPoint.index).toString(16)}`, + }, + tipBlockHash + ) .then((res: string) => { setWithdrawValue(res) }) diff --git a/packages/neuron-ui/src/components/NervosDAO/index.tsx b/packages/neuron-ui/src/components/NervosDAO/index.tsx index 6f9ab71f59..9f1ead3086 100644 --- a/packages/neuron-ui/src/components/NervosDAO/index.tsx +++ b/packages/neuron-ui/src/components/NervosDAO/index.tsx @@ -15,7 +15,7 @@ import { MIN_DEPOSIT_AMOUNT, MEDIUM_FEE_RATE, SHANNON_CKB_RATIO, MAX_DECIMAL_DIG import { verifyAmount } from 'utils/validators' import { generateDepositTx, generateWithdrawTx, generateClaimTx } from 'services/remote' -import { ckbCore, getHeaderByNumber } from 'services/chain' +import { getHeaderByNumber, calculateDaoMaximumWithdraw } from 'services/chain' import { epochParser } from 'utils/parsers' import DAORecord from 'components/CustomRows/DAORecordRow' @@ -246,13 +246,13 @@ const NervosDAO = ({ const formattedDepositOutPoint = depositOutPoint ? { txHash: depositOutPoint.txHash, - index: BigInt(depositOutPoint.index), + index: `0x${BigInt(depositOutPoint.index).toString(16)}`, } : { txHash: outPoint.txHash, - index: BigInt(outPoint.index), + index: `0x${BigInt(outPoint.index).toString(16)}`, } - return (ckbCore.rpc as any).calculateDaoMaximumWithdraw(formattedDepositOutPoint, withdrawBlockHash) as string + return calculateDaoMaximumWithdraw(formattedDepositOutPoint, withdrawBlockHash) }) ) .then(res => { diff --git a/packages/neuron-ui/src/services/chain.ts b/packages/neuron-ui/src/services/chain.ts index 8b2f08a3d0..e98285478a 100644 --- a/packages/neuron-ui/src/services/chain.ts +++ b/packages/neuron-ui/src/services/chain.ts @@ -1,11 +1,13 @@ import CKBCore from '@nervosnetwork/ckb-sdk-core' export const ckbCore = new CKBCore('') -export const { getBlockchainInfo, getTipHeader, getHeaderByNumber } = ckbCore.rpc +export const { getBlock, getBlockchainInfo, getTipHeader, getHeaderByNumber, calculateDaoMaximumWithdraw } = ckbCore.rpc export default { ckbCore, + getBlock, getBlockchainInfo, getTipHeader, getHeaderByNumber, + calculateDaoMaximumWithdraw, } From d11ec397357c316d55f8949eb2e420e0693977d0 Mon Sep 17 00:00:00 2001 From: classicalliu Date: Fri, 22 Nov 2019 20:30:05 +0800 Subject: [PATCH 12/43] chore: rename cleanInfoWhenSwitchNetwork --- packages/neuron-wallet/src/models/dao-utils.ts | 2 +- packages/neuron-wallet/src/models/lock-utils.ts | 2 +- packages/neuron-wallet/src/startup/sync-block-task/create.ts | 4 ++-- packages/neuron-wallet/src/startup/sync-block-task/indexer.ts | 4 ++-- packages/neuron-wallet/src/startup/sync-block-task/sync.ts | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/neuron-wallet/src/models/dao-utils.ts b/packages/neuron-wallet/src/models/dao-utils.ts index 921b18c1ba..07bb9bf5d5 100644 --- a/packages/neuron-wallet/src/models/dao-utils.ts +++ b/packages/neuron-wallet/src/models/dao-utils.ts @@ -45,7 +45,7 @@ export default class DaoUtils { return DaoUtils.daoScriptInfo } - static cleanInfoWhenSwitchNetwork(): void { + static cleanInfo(): void { DaoUtils.daoScriptInfo = undefined } diff --git a/packages/neuron-wallet/src/models/lock-utils.ts b/packages/neuron-wallet/src/models/lock-utils.ts index 70b941d600..1e01f42d57 100644 --- a/packages/neuron-wallet/src/models/lock-utils.ts +++ b/packages/neuron-wallet/src/models/lock-utils.ts @@ -63,7 +63,7 @@ export default class LockUtils { return LockUtils.systemScriptInfo } - static cleanInfoWhenSwitchNetwork(): void { + static cleanInfo(): void { LockUtils.systemScriptInfo = undefined } diff --git a/packages/neuron-wallet/src/startup/sync-block-task/create.ts b/packages/neuron-wallet/src/startup/sync-block-task/create.ts index 3393964d72..b0b2c5e62a 100644 --- a/packages/neuron-wallet/src/startup/sync-block-task/create.ts +++ b/packages/neuron-wallet/src/startup/sync-block-task/create.ts @@ -32,8 +32,8 @@ export interface DatabaseInitParams { const networkChange = async (network: NetworkWithID) => { await InitDatabase.getInstance().stopAndWait() // clean LockUtils info and DaoUtils info - LockUtils.cleanInfoWhenSwitchNetwork() - DaoUtils.cleanInfoWhenSwitchNetwork() + LockUtils.cleanInfo() + DaoUtils.cleanInfo() const info = await InitDatabase.getInstance().init(network) DataUpdateSubject.next({ diff --git a/packages/neuron-wallet/src/startup/sync-block-task/indexer.ts b/packages/neuron-wallet/src/startup/sync-block-task/indexer.ts index ca84a99053..d8da7ba553 100644 --- a/packages/neuron-wallet/src/startup/sync-block-task/indexer.ts +++ b/packages/neuron-wallet/src/startup/sync-block-task/indexer.ts @@ -26,8 +26,8 @@ export const switchNetwork = async (nodeURL: string, genesisBlockHash: string, _ } // clean LockUtils info and DaoUtils info - LockUtils.cleanInfoWhenSwitchNetwork() - DaoUtils.cleanInfoWhenSwitchNetwork() + LockUtils.cleanInfo() + DaoUtils.cleanInfo() // disconnect old connection and connect to new database await initConnection(genesisBlockHash) diff --git a/packages/neuron-wallet/src/startup/sync-block-task/sync.ts b/packages/neuron-wallet/src/startup/sync-block-task/sync.ts index fcf3380c37..799332d83a 100644 --- a/packages/neuron-wallet/src/startup/sync-block-task/sync.ts +++ b/packages/neuron-wallet/src/startup/sync-block-task/sync.ts @@ -33,8 +33,8 @@ export const switchNetwork = async (url: string, genesisBlockHash: string, _chai } // clean LockUtils info and DaoUtils info - LockUtils.cleanInfoWhenSwitchNetwork() - DaoUtils.cleanInfoWhenSwitchNetwork() + LockUtils.cleanInfo() + DaoUtils.cleanInfo() // disconnect old connection and connect to new database await initConnection(genesisBlockHash) From 73f1bf0a8f0e42ff62ce553b9a5b4ed276db57ab Mon Sep 17 00:00:00 2001 From: classicalliu Date: Sat, 23 Nov 2019 17:45:30 +0800 Subject: [PATCH 13/43] fix: initialize NetworksService in renderer process Reduce about `1100 ~ 1200` `TIME_WAIT` connections to about `20 ~ 30` --- .../models/subjects/network-switch-subject.ts | 10 +++++++ .../neuron-wallet/src/services/networks.ts | 28 +++++++++++++------ .../src/startup/sync-block-task/create.ts | 6 ++-- .../src/startup/sync-block-task/params.ts | 4 +-- 4 files changed, 34 insertions(+), 14 deletions(-) create mode 100644 packages/neuron-wallet/src/models/subjects/network-switch-subject.ts diff --git a/packages/neuron-wallet/src/models/subjects/network-switch-subject.ts b/packages/neuron-wallet/src/models/subjects/network-switch-subject.ts new file mode 100644 index 0000000000..d1a4e89ef6 --- /dev/null +++ b/packages/neuron-wallet/src/models/subjects/network-switch-subject.ts @@ -0,0 +1,10 @@ +import { BehaviorSubject } from 'rxjs' +import { NetworkWithID } from 'types/network' + +export default class NetworkSwitchSubject { + static subject = new BehaviorSubject(undefined) + + static getSubject() { + return this.subject + } +} diff --git a/packages/neuron-wallet/src/services/networks.ts b/packages/neuron-wallet/src/services/networks.ts index 0f499da69a..f994950538 100644 --- a/packages/neuron-wallet/src/services/networks.ts +++ b/packages/neuron-wallet/src/services/networks.ts @@ -1,7 +1,6 @@ import Core from '@nervosnetwork/ckb-sdk-core' import { v4 as uuid } from 'uuid' -import { BehaviorSubject } from 'rxjs' -import { LackOfDefaultNetwork, DefaultNetworkUnremovable } from 'exceptions/network' +import { DefaultNetworkUnremovable, LackOfDefaultNetwork } from 'exceptions/network' import Store from 'models/store' @@ -9,8 +8,21 @@ import { Validate, Required } from 'decorators' import { UsedName, NetworkNotFound, InvalidFormat } from 'exceptions' import { NetworkListSubject, CurrentNetworkIDSubject } from 'models/subjects/networks' import { MAINNET_GENESIS_HASH, EMPTY_GENESIS_HASH, NetworkID, NetworkName, NetworkRemote, NetworksKey, NetworkType, Network, NetworkWithID } from 'types/network' +import { remote } from 'electron' +import NetworkSwitchSubject from 'models/subjects/network-switch-subject' -export const networkSwitchSubject = new BehaviorSubject(undefined) +const isRenderer = process && process.type === 'renderer' +const networkSwitchSubject = isRenderer + ? remote.require('./models/subjects/network-switch-subject').default.getSubject() + : NetworkSwitchSubject.getSubject() + +const currentNetworkIDSubject = isRenderer + ? remote.require('./models/subjects/networks').default.CurrentNetworkIDSubject + : CurrentNetworkIDSubject + +const networkListSubject = isRenderer + ? remote.require('./models/subjects/networks').default.NetworkListSubject + : NetworkListSubject const presetNetworks: { selected: string, networks: NetworkWithID[] } = { selected: 'mainnet', @@ -40,7 +52,7 @@ export default class NetworksService extends Store { super('networks', 'index.json', JSON.stringify(presetNetworks)) const currentNetworkList = this.getAll() - NetworkListSubject.next({ currentNetworkList }) + networkListSubject.next({ currentNetworkList }) const currentNetwork = this.getCurrent() if (currentNetwork) { @@ -48,12 +60,12 @@ export default class NetworksService extends Store { this.update(currentNetwork.id, {}) // Update to trigger chain/genesis hash refresh } - CurrentNetworkIDSubject.next({ currentNetworkID: currentNetwork.id }) + currentNetworkIDSubject.next({ currentNetworkID: currentNetwork.id }) networkSwitchSubject.next(currentNetwork) } this.on(NetworksKey.List, async (_, currentNetworkList: NetworkWithID[] = []) => { - NetworkListSubject.next({ currentNetworkList }) + networkListSubject.next({ currentNetworkList }) const currentID = this.getCurrentID() if (currentNetworkList.find(network => network.id === currentID)) { @@ -72,7 +84,7 @@ export default class NetworksService extends Store { if (!currentNetwork) { throw new NetworkNotFound(currentNetworkID) } - CurrentNetworkIDSubject.next({ currentNetworkID }) + currentNetworkIDSubject.next({ currentNetworkID }) networkSwitchSubject.next(currentNetwork) }) } @@ -158,7 +170,7 @@ export default class NetworksService extends Store { this.updateAll(list) if (this.getCurrentID() === id) { - CurrentNetworkIDSubject.next({ currentNetworkID: id }) + currentNetworkIDSubject.next({ currentNetworkID: id }) networkSwitchSubject.next(network) } } diff --git a/packages/neuron-wallet/src/startup/sync-block-task/create.ts b/packages/neuron-wallet/src/startup/sync-block-task/create.ts index b0b2c5e62a..9255690102 100644 --- a/packages/neuron-wallet/src/startup/sync-block-task/create.ts +++ b/packages/neuron-wallet/src/startup/sync-block-task/create.ts @@ -1,7 +1,6 @@ import { BrowserWindow } from 'electron' import { ReplaySubject } from 'rxjs' import path from 'path' -import { networkSwitchSubject } from 'services/networks' import { NetworkWithID } from 'types/network' import env from 'env' import AddressService from 'services/addresses' @@ -14,6 +13,7 @@ import NetworksService from 'services/networks' import { distinctUntilChanged } from 'rxjs/operators' import LockUtils from 'models/lock-utils' import DaoUtils from 'models/dao-utils' +import NetworkSwitchSubject from 'models/subjects/network-switch-subject' export { genesisBlockHash } @@ -55,7 +55,7 @@ const networkChange = async (network: NetworkWithID) => { export const databaseInitSubject = new ReplaySubject(1) -networkSwitchSubject.subscribe(async (network: NetworkWithID | undefined) => { +NetworkSwitchSubject.getSubject().subscribe(async (network: NetworkWithID | undefined) => { if (network) { await networkChange(network) } @@ -77,8 +77,6 @@ NodeService const loadURL = `file://${path.join(__dirname, 'index.html')}` -export { networkSwitchSubject } - let syncBlockBackgroundWindow: BrowserWindow | null // create a background task to sync transactions diff --git a/packages/neuron-wallet/src/startup/sync-block-task/params.ts b/packages/neuron-wallet/src/startup/sync-block-task/params.ts index 7339c00e94..0c31a686ea 100644 --- a/packages/neuron-wallet/src/startup/sync-block-task/params.ts +++ b/packages/neuron-wallet/src/startup/sync-block-task/params.ts @@ -3,8 +3,7 @@ import { AddressesUsedSubject } from 'models/subjects/addresses-used-subject' import AddressDbChangedSubject from 'models/subjects/address-db-changed-subject' import WalletCreatedSubject from 'models/subjects/wallet-created-subject' import AddressCreatedSubject from 'models/subjects/address-created-subject' - -export { networkSwitchSubject } from 'services/networks' +import NetworkSwitchSubject from 'models/subjects/network-switch-subject' export { genesisBlockHash } from './create' export { databaseInitSubject } from './create' @@ -14,3 +13,4 @@ export const addressesUsedSubject = AddressesUsedSubject.getSubject() export const addressDbChangedSubject = AddressDbChangedSubject.getSubject() export const walletCreatedSubject = WalletCreatedSubject.getSubject() export const addressCreatedSubject = AddressCreatedSubject.getSubject() +export const networkSwitchSubject = NetworkSwitchSubject.getSubject() From 90beffd51aa998a8d2a6627a7dbb530ee24591fa Mon Sep 17 00:00:00 2001 From: James Chen Date: Tue, 26 Nov 2019 13:33:28 +0900 Subject: [PATCH 14/43] chore: Bump to v0.25.2 --- lerna.json | 2 +- package.json | 2 +- packages/neuron-ui/package.json | 2 +- packages/neuron-wallet/package.json | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lerna.json b/lerna.json index 91991a3759..7079de735e 100644 --- a/lerna.json +++ b/lerna.json @@ -2,7 +2,7 @@ "packages": [ "packages/*" ], - "version": "0.25.1", + "version": "0.25.2", "npmClient": "yarn", "useWorkspaces": true } diff --git a/package.json b/package.json index 1b7b788329..c199379971 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "neuron", "productName": "Neuron", "description": "CKB Neuron Wallet", - "version": "0.25.1", + "version": "0.25.2", "private": true, "author": { "name": "Nervos Core Dev", diff --git a/packages/neuron-ui/package.json b/packages/neuron-ui/package.json index 074933c3a6..d0d50c6964 100644 --- a/packages/neuron-ui/package.json +++ b/packages/neuron-ui/package.json @@ -1,6 +1,6 @@ { "name": "neuron-ui", - "version": "0.25.1", + "version": "0.25.2", "private": true, "author": { "name": "Nervos Core Dev", diff --git a/packages/neuron-wallet/package.json b/packages/neuron-wallet/package.json index a518cea225..16bdf2e515 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.25.1", + "version": "0.25.2", "private": true, "author": { "name": "Nervos Core Dev", @@ -64,7 +64,7 @@ "electron-devtools-installer": "2.2.4", "electron-notarize": "0.1.1", "lint-staged": "9.2.5", - "neuron-ui": "0.25.1", + "neuron-ui": "0.25.2", "rimraf": "3.0.0", "spectron": "8.0.0", "ts-transformer-imports": "0.4.3", From f1b0f725804c0b56f01e795590c5e9551db2481f Mon Sep 17 00:00:00 2001 From: classicalliu Date: Tue, 26 Nov 2019 13:35:29 +0800 Subject: [PATCH 15/43] fix: network switch event broadcast twice --- .../neuron-wallet/src/services/networks.ts | 40 +++++++++---------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/packages/neuron-wallet/src/services/networks.ts b/packages/neuron-wallet/src/services/networks.ts index f994950538..2a89f3973f 100644 --- a/packages/neuron-wallet/src/services/networks.ts +++ b/packages/neuron-wallet/src/services/networks.ts @@ -8,21 +8,9 @@ import { Validate, Required } from 'decorators' import { UsedName, NetworkNotFound, InvalidFormat } from 'exceptions' import { NetworkListSubject, CurrentNetworkIDSubject } from 'models/subjects/networks' import { MAINNET_GENESIS_HASH, EMPTY_GENESIS_HASH, NetworkID, NetworkName, NetworkRemote, NetworksKey, NetworkType, Network, NetworkWithID } from 'types/network' -import { remote } from 'electron' import NetworkSwitchSubject from 'models/subjects/network-switch-subject' -const isRenderer = process && process.type === 'renderer' -const networkSwitchSubject = isRenderer - ? remote.require('./models/subjects/network-switch-subject').default.getSubject() - : NetworkSwitchSubject.getSubject() - -const currentNetworkIDSubject = isRenderer - ? remote.require('./models/subjects/networks').default.CurrentNetworkIDSubject - : CurrentNetworkIDSubject - -const networkListSubject = isRenderer - ? remote.require('./models/subjects/networks').default.NetworkListSubject - : NetworkListSubject +const isMainProcess = process && process.type === 'browser' const presetNetworks: { selected: string, networks: NetworkWithID[] } = { selected: 'mainnet', @@ -52,7 +40,9 @@ export default class NetworksService extends Store { super('networks', 'index.json', JSON.stringify(presetNetworks)) const currentNetworkList = this.getAll() - networkListSubject.next({ currentNetworkList }) + if (isMainProcess) { + NetworkListSubject.next({ currentNetworkList }) + } const currentNetwork = this.getCurrent() if (currentNetwork) { @@ -60,12 +50,16 @@ export default class NetworksService extends Store { this.update(currentNetwork.id, {}) // Update to trigger chain/genesis hash refresh } - currentNetworkIDSubject.next({ currentNetworkID: currentNetwork.id }) - networkSwitchSubject.next(currentNetwork) + if (isMainProcess) { + CurrentNetworkIDSubject.next({ currentNetworkID: currentNetwork.id }) + NetworkSwitchSubject.getSubject().next(currentNetwork) + } } this.on(NetworksKey.List, async (_, currentNetworkList: NetworkWithID[] = []) => { - networkListSubject.next({ currentNetworkList }) + if (isMainProcess) { + NetworkListSubject.next({ currentNetworkList }) + } const currentID = this.getCurrentID() if (currentNetworkList.find(network => network.id === currentID)) { @@ -84,8 +78,10 @@ export default class NetworksService extends Store { if (!currentNetwork) { throw new NetworkNotFound(currentNetworkID) } - currentNetworkIDSubject.next({ currentNetworkID }) - networkSwitchSubject.next(currentNetwork) + if (isMainProcess) { + CurrentNetworkIDSubject.next({ currentNetworkID }) + NetworkSwitchSubject.getSubject().next(currentNetwork) + } }) } @@ -169,9 +165,9 @@ export default class NetworksService extends Store { this.updateAll(list) - if (this.getCurrentID() === id) { - currentNetworkIDSubject.next({ currentNetworkID: id }) - networkSwitchSubject.next(network) + if (this.getCurrentID() === id && isMainProcess) { + CurrentNetworkIDSubject.next({ currentNetworkID: id }) + NetworkSwitchSubject.getSubject().next(network) } } From 67dcb79adf4035c893d280e051d7e4be9a468f00 Mon Sep 17 00:00:00 2001 From: classicalliu Date: Tue, 26 Nov 2019 17:44:24 +0800 Subject: [PATCH 16/43] fix: pending in windows when network off --- packages/neuron-wallet/src/startup/sync-block-task/create.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/neuron-wallet/src/startup/sync-block-task/create.ts b/packages/neuron-wallet/src/startup/sync-block-task/create.ts index 9255690102..b9c1935d48 100644 --- a/packages/neuron-wallet/src/startup/sync-block-task/create.ts +++ b/packages/neuron-wallet/src/startup/sync-block-task/create.ts @@ -14,6 +14,8 @@ import { distinctUntilChanged } from 'rxjs/operators' import LockUtils from 'models/lock-utils' import DaoUtils from 'models/dao-utils' import NetworkSwitchSubject from 'models/subjects/network-switch-subject' +import { SyncedBlockNumberSubject } from 'models/subjects/node' +import BlockNumber from 'services/sync/block-number' export { genesisBlockHash } @@ -36,6 +38,8 @@ const networkChange = async (network: NetworkWithID) => { DaoUtils.cleanInfo() const info = await InitDatabase.getInstance().init(network) + const blockNumber = await (new BlockNumber()).getCurrent() + SyncedBlockNumberSubject.next(blockNumber.toString()) DataUpdateSubject.next({ dataType: 'transaction', actionType: 'update', From b714376eb4c48cc5c6212369ff6632a544b66249 Mon Sep 17 00:00:00 2001 From: Keith Date: Tue, 26 Nov 2019 21:16:06 +0800 Subject: [PATCH 17/43] fix(neuron-ui): show 0 if withdraw rpc returns errors --- packages/neuron-ui/src/components/NervosDAO/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/neuron-ui/src/components/NervosDAO/index.tsx b/packages/neuron-ui/src/components/NervosDAO/index.tsx index 9f1ead3086..43ad2b0ac1 100644 --- a/packages/neuron-ui/src/components/NervosDAO/index.tsx +++ b/packages/neuron-ui/src/components/NervosDAO/index.tsx @@ -252,7 +252,7 @@ const NervosDAO = ({ txHash: outPoint.txHash, index: `0x${BigInt(outPoint.index).toString(16)}`, } - return calculateDaoMaximumWithdraw(formattedDepositOutPoint, withdrawBlockHash) + return calculateDaoMaximumWithdraw(formattedDepositOutPoint, withdrawBlockHash).catch(() => null) }) ) .then(res => { From 5bac614d4608d0ef15d6a4ebca20505ebd7adf67 Mon Sep 17 00:00:00 2001 From: James Chen Date: Wed, 27 Nov 2019 13:57:50 +0900 Subject: [PATCH 18/43] chore: Bump ckb sdk to v0.25.0 --- packages/neuron-ui/package.json | 2 +- packages/neuron-wallet/package.json | 6 ++--- yarn.lock | 42 ++++++++++++++--------------- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/packages/neuron-ui/package.json b/packages/neuron-ui/package.json index d0d50c6964..7e0ae1e33d 100644 --- a/packages/neuron-ui/package.json +++ b/packages/neuron-ui/package.json @@ -43,7 +43,7 @@ "last 2 chrome versions" ], "dependencies": { - "@nervosnetwork/ckb-sdk-core": "0.25.0-alpha.0", + "@nervosnetwork/ckb-sdk-core": "0.25.0", "@uifabric/experiments": "7.16.1", "@uifabric/styling": "7.6.2", "canvg": "2.0.0", diff --git a/packages/neuron-wallet/package.json b/packages/neuron-wallet/package.json index 16bdf2e515..8d9caf8255 100644 --- a/packages/neuron-wallet/package.json +++ b/packages/neuron-wallet/package.json @@ -34,8 +34,8 @@ ] }, "dependencies": { - "@nervosnetwork/ckb-sdk-core": "0.25.0-alpha.0", - "@nervosnetwork/ckb-sdk-utils": "0.25.0-alpha.0", + "@nervosnetwork/ckb-sdk-core": "0.25.0", + "@nervosnetwork/ckb-sdk-utils": "0.25.0", "bn.js": "4.11.8", "chalk": "2.4.2", "electron-log": "3.0.7", @@ -51,7 +51,7 @@ "uuid": "3.3.3" }, "devDependencies": { - "@nervosnetwork/ckb-types": "0.25.0-alpha.0", + "@nervosnetwork/ckb-types": "0.25.0", "@types/electron-devtools-installer": "2.2.0", "@types/elliptic": "6.4.9", "@types/sqlite3": "3.1.5", diff --git a/yarn.lock b/yarn.lock index f766729822..624559c1e5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2059,36 +2059,36 @@ call-me-maybe "^1.0.1" glob-to-regexp "^0.3.0" -"@nervosnetwork/ckb-sdk-core@0.25.0-alpha.0": - version "0.25.0-alpha.0" - resolved "https://registry.yarnpkg.com/@nervosnetwork/ckb-sdk-core/-/ckb-sdk-core-0.25.0-alpha.0.tgz#55d3286edffa01cc29b6a1e05de07b46fcd5f605" - integrity sha512-7ygYqDYkdRYxn1gEWmQC1yYFvWCrNA6czsxgZwPI9LQdvzemMk+CgotXhT7uf5/zKTgrDDwFMTixqdkPMlL7Mw== +"@nervosnetwork/ckb-sdk-core@0.25.0": + version "0.25.0" + resolved "https://registry.yarnpkg.com/@nervosnetwork/ckb-sdk-core/-/ckb-sdk-core-0.25.0.tgz#0a9852f78272297f39f3a722d8ab59c24d9afe7e" + integrity sha512-tD/mKge4zd56jOqvgeWb4703HOSF8ELhFpg0ieHhkV2uMoqqdW9eHyhdIisxPpW/y//RiS2Vxra8AL4uVBwRjQ== dependencies: - "@nervosnetwork/ckb-sdk-rpc" "0.25.0-alpha.0" - "@nervosnetwork/ckb-sdk-utils" "0.25.0-alpha.0" - "@nervosnetwork/ckb-types" "0.25.0-alpha.0" + "@nervosnetwork/ckb-sdk-rpc" "0.25.0" + "@nervosnetwork/ckb-sdk-utils" "0.25.0" + "@nervosnetwork/ckb-types" "0.25.0" -"@nervosnetwork/ckb-sdk-rpc@0.25.0-alpha.0": - version "0.25.0-alpha.0" - resolved "https://registry.yarnpkg.com/@nervosnetwork/ckb-sdk-rpc/-/ckb-sdk-rpc-0.25.0-alpha.0.tgz#8f5009c8c67ef9e720ece0fb7c07b96f39f5af93" - integrity sha512-ZefPXjKHBDaESvk1upCarTnGvDf8amsa6D8Xhaam02OVGUnTxt5n6WteniBQAsrORmI69PE5bfHesYo8sQRQVQ== +"@nervosnetwork/ckb-sdk-rpc@0.25.0": + version "0.25.0" + resolved "https://registry.yarnpkg.com/@nervosnetwork/ckb-sdk-rpc/-/ckb-sdk-rpc-0.25.0.tgz#221cebe82da5c378c2e82fe8d8ca385f9ad4ca27" + integrity sha512-YwUmFd5YOR7OfWE0qxG8VWAmjf/lHxtW5U5ezYDecYV0Ey4qV70c/+yu3+o3koxSZwmZb2bJaEu5u4pXalyeHA== dependencies: - "@nervosnetwork/ckb-sdk-utils" "0.25.0-alpha.0" + "@nervosnetwork/ckb-sdk-utils" "0.25.0" axios "0.19.0" -"@nervosnetwork/ckb-sdk-utils@0.25.0-alpha.0": - version "0.25.0-alpha.0" - resolved "https://registry.yarnpkg.com/@nervosnetwork/ckb-sdk-utils/-/ckb-sdk-utils-0.25.0-alpha.0.tgz#8bce9f30b38ebe7776e756defb9f9111c7cfa8ad" - integrity sha512-VqXcC+C9LrOni+ljyripbzl2fAf6ILHFz//rJqLkWCDeAeT3kGs4xVBCAHRGbAetI9wyTg3+n6BuSLOtzT5goQ== +"@nervosnetwork/ckb-sdk-utils@0.25.0": + version "0.25.0" + resolved "https://registry.yarnpkg.com/@nervosnetwork/ckb-sdk-utils/-/ckb-sdk-utils-0.25.0.tgz#cc4708ecad678efc069d46aff5fcbecbd0f3a7fb" + integrity sha512-fFQBcnQTvvp7eLblY0ylZQaFWrIE7d/r+T/K7EAAG+XVdQhQXDJ6sb59kz7l0MWI/j4g9X5wZiFx/65VjotAJw== dependencies: - "@nervosnetwork/ckb-types" "0.25.0-alpha.0" + "@nervosnetwork/ckb-types" "0.25.0" blake2b-wasm "1.1.7" elliptic "6.5.1" -"@nervosnetwork/ckb-types@0.25.0-alpha.0": - version "0.25.0-alpha.0" - resolved "https://registry.yarnpkg.com/@nervosnetwork/ckb-types/-/ckb-types-0.25.0-alpha.0.tgz#7aafb57e99525d54f632601055fb66d4f3f0f9b1" - integrity sha512-xtSCjJkQjvuMcDqoMRCBtVc8W5jcsMlSwi7hAmDp5CIwNlMnU+xeUCTdnHX2Kt8vijhtUcIH90uEsdtzAPpWjQ== +"@nervosnetwork/ckb-types@0.25.0": + version "0.25.0" + resolved "https://registry.yarnpkg.com/@nervosnetwork/ckb-types/-/ckb-types-0.25.0.tgz#8e8292e672954420b1068c0a99b7b652487a9ff9" + integrity sha512-KSrewk0Nz2LEUPJQOjGYl6maoHxDwsCpAMoN8gCznyei77BiD6k8Mq9xh+XoetZszk4SCjttYMUWEP+z/Lvmjw== "@nodelib/fs.scandir@2.1.3": version "2.1.3" From 65e51dd622c866df0cb96be9038b006c854f6799 Mon Sep 17 00:00:00 2001 From: classicalliu Date: Wed, 27 Nov 2019 14:25:34 +0800 Subject: [PATCH 19/43] fix: balance not update after sent tx --- packages/neuron-wallet/src/services/wallets.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/neuron-wallet/src/services/wallets.ts b/packages/neuron-wallet/src/services/wallets.ts index 795fd112be..4127b62fb3 100644 --- a/packages/neuron-wallet/src/services/wallets.ts +++ b/packages/neuron-wallet/src/services/wallets.ts @@ -408,7 +408,8 @@ export default class WalletService { // update addresses txCount and balance const blake160s = TransactionsService.blake160sOfTx(tx) - const usedAddresses = blake160s.map(blake160 => LockUtils.blake160ToAddress(blake160)) + const prefix = NetworksService.getInstance().isMainnet() ? AddressPrefix.Mainnet : AddressPrefix.Testnet + const usedAddresses = blake160s.map(blake160 => LockUtils.blake160ToAddress(blake160, prefix)) AddressesUsedSubject.getSubject().next({ addresses: usedAddresses, url: core.rpc.node.url, From b97f6780b1677f5200f4f31e5ae39eead144b7f9 Mon Sep 17 00:00:00 2001 From: classicalliu Date: Wed, 27 Nov 2019 14:50:11 +0800 Subject: [PATCH 20/43] refactor: update updateTxCountAndBalance to updateTxCountAndBalances --- .../src/database/address/address-dao.ts | 39 +++++++++---------- .../neuron-wallet/src/services/addresses.ts | 12 +++--- 2 files changed, 23 insertions(+), 28 deletions(-) diff --git a/packages/neuron-wallet/src/database/address/address-dao.ts b/packages/neuron-wallet/src/database/address/address-dao.ts index a748b18907..02fe31f29c 100644 --- a/packages/neuron-wallet/src/database/address/address-dao.ts +++ b/packages/neuron-wallet/src/database/address/address-dao.ts @@ -54,38 +54,35 @@ export default class AddressDao { // pendingBalance means balance of OutputStatus.Pending cells (sent from me, but not committed) // so the final balance is (liveBalance + sentBalance - pendingBalance) // balance is the balance of the cells those who don't hold data or type script - public static updateTxCountAndBalance = async ( - address: string, + public static updateTxCountAndBalances = async ( + addresses: string[], url: string = NodeService.getInstance().core.rpc.node.url ): Promise => { const all = AddressStore.getAll() const toUpdate = all.filter(value => { - return value.address === address + return addresses.includes(value.address) }) const others = all.filter(value => { - return value.address !== address + return !addresses.includes(value.address) }) - const txCount: number = await TransactionsService.getCountByAddressAndStatus(address, [ - TransactionStatus.Pending, - TransactionStatus.Success, - ], url) const lockUtils = new LockUtils(await LockUtils.systemScript(url)) - const result = await Promise.all( - toUpdate.map(async entity => { - const item = entity - item.txCount = txCount - const lockHashes: string[] = lockUtils.addressToAllLockHashes(item.address) - item.liveBalance = await CellsService.getBalance(lockHashes, OutputStatus.Live) - item.sentBalance = await CellsService.getBalance(lockHashes, OutputStatus.Sent) - item.pendingBalance = await CellsService.getBalance(lockHashes, OutputStatus.Pending) - item.balance = (BigInt(item.liveBalance) + BigInt(item.sentBalance)).toString() - return item - }) - ) + for (const addr of toUpdate) { + const txCount: number = await TransactionsService.getCountByAddressAndStatus(addr.address, [ + TransactionStatus.Pending, + TransactionStatus.Success, + ], url) + addr.txCount = txCount + + const lockHashes: string[] = lockUtils.addressToAllLockHashes(addr.address) + addr.liveBalance = await CellsService.getBalance(lockHashes, OutputStatus.Live) + addr.sentBalance = await CellsService.getBalance(lockHashes, OutputStatus.Sent) + addr.pendingBalance = await CellsService.getBalance(lockHashes, OutputStatus.Pending) + addr.balance = (BigInt(addr.liveBalance) + BigInt(addr.sentBalance)).toString() + } AddressStore.updateAll(toUpdate.concat(others)) - return result + return toUpdate } public static nextUnusedAddress(walletId: string, version: AddressVersion): Address | undefined { diff --git a/packages/neuron-wallet/src/services/addresses.ts b/packages/neuron-wallet/src/services/addresses.ts index 9d876969d9..e5daa731c7 100644 --- a/packages/neuron-wallet/src/services/addresses.ts +++ b/packages/neuron-wallet/src/services/addresses.ts @@ -87,13 +87,11 @@ export default class AddressService { ) } - public static updateTxCountAndBalances = async (addresses: string[], url: string = NodeService.getInstance().core.rpc.node.url) => { - let result: Address[] = [] - for (const address of addresses) { - const updatedAddress = await AddressDao.updateTxCountAndBalance(address, url) - result = result.concat(updatedAddress) - } - return result + public static updateTxCountAndBalances = async ( + addresses: string[], + url: string = NodeService.getInstance().core.rpc.node.url + ): Promise => { + return AddressDao.updateTxCountAndBalances(addresses, url) } // Generate both receiving and change addresses. From d0718c7d2d17ff8736f48303217b791a54b885d3 Mon Sep 17 00:00:00 2001 From: James Chen Date: Wed, 27 Nov 2019 16:48:36 +0900 Subject: [PATCH 21/43] chore: Update react-router-dom to 5.1 --- packages/neuron-ui/package.json | 4 ++-- yarn.lock | 26 +++++++++++++------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/packages/neuron-ui/package.json b/packages/neuron-ui/package.json index 7e0ae1e33d..c70162ab30 100644 --- a/packages/neuron-ui/package.json +++ b/packages/neuron-ui/package.json @@ -54,7 +54,7 @@ "react": "16.9.0", "react-dom": "16.9.0", "react-i18next": "11.0.1", - "react-router-dom": "5.0.1", + "react-router-dom": "5.1.2", "react-scripts": "3.2.0", "styled-components": "5.0.0-beta.0" }, @@ -72,7 +72,7 @@ "@types/node": "12.7.4", "@types/react": "16.9.2", "@types/react-dom": "16.9.0", - "@types/react-router-dom": "4.3.5", + "@types/react-router-dom": "5.1.3", "@types/storybook-react-router": "1.0.0", "@types/storybook__addon-knobs": "5.0.3", "@types/storybook__addon-storyshots": "5.1.1", diff --git a/yarn.lock b/yarn.lock index 624559c1e5..1090fbfeb1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2920,10 +2920,10 @@ "@types/prop-types" "*" "@types/react" "*" -"@types/react-router-dom@4.3.5": - version "4.3.5" - resolved "https://registry.yarnpkg.com/@types/react-router-dom/-/react-router-dom-4.3.5.tgz#72f229967690c890d00f96e6b85e9ee5780db31f" - integrity sha512-eFajSUASYbPHg2BDM1G8Btx+YqGgvROPIg6sBhl3O4kbDdYXdFdfrgQFf/pcBuQVObjfT9AL/dd15jilR5DIEA== +"@types/react-router-dom@5.1.3": + version "5.1.3" + resolved "https://registry.yarnpkg.com/@types/react-router-dom/-/react-router-dom-5.1.3.tgz#b5d28e7850bd274d944c0fbbe5d57e6b30d71196" + integrity sha512-pCq7AkOvjE65jkGS5fQwQhvUp4+4PVD9g39gXLZViP2UqFiFzsEpB3PKf0O6mdbKsewSK8N14/eegisa/0CwnA== dependencies: "@types/history" "*" "@types/react" "*" @@ -14070,23 +14070,23 @@ react-resize-detector@^4.0.5: raf-schd "^4.0.2" resize-observer-polyfill "^1.5.1" -react-router-dom@5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.0.1.tgz#ee66f4a5d18b6089c361958e443489d6bab714be" - integrity sha512-zaVHSy7NN0G91/Bz9GD4owex5+eop+KvgbxXsP/O+iW1/Ln+BrJ8QiIR5a6xNPtrdTvLkxqlDClx13QO1uB8CA== +react-router-dom@5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.1.2.tgz#06701b834352f44d37fbb6311f870f84c76b9c18" + integrity sha512-7BPHAaIwWpZS074UKaw1FjVdZBSVWEk8IuDXdB+OkLb8vd/WRQIpA4ag9WQk61aEfQs47wHyjWUoUGGZxpQXew== dependencies: "@babel/runtime" "^7.1.2" history "^4.9.0" loose-envify "^1.3.1" prop-types "^15.6.2" - react-router "5.0.1" + react-router "5.1.2" tiny-invariant "^1.0.2" tiny-warning "^1.0.0" -react-router@5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.0.1.tgz#04ee77df1d1ab6cb8939f9f01ad5702dbadb8b0f" - integrity sha512-EM7suCPNKb1NxcTZ2LEOWFtQBQRQXecLxVpdsP4DW4PbbqYWeRiLyV/Tt1SdCrvT2jcyXAXmVTmzvSzrPR63Bg== +react-router@5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.1.2.tgz#6ea51d789cb36a6be1ba5f7c0d48dd9e817d3418" + integrity sha512-yjEuMFy1ONK246B+rsa0cUam5OeAQ8pyclRDgpxuSCrAlJ1qN9uZ5IgyKC7gQg0w8OM50NXHEegPh/ks9YuR2A== dependencies: "@babel/runtime" "^7.1.2" history "^4.9.0" From 98fe06cdc2abdec31c546e131d634e4b8eaa74b0 Mon Sep 17 00:00:00 2001 From: James Chen Date: Wed, 27 Nov 2019 17:27:25 +0900 Subject: [PATCH 22/43] feat: Adding check update to settings view --- .../src/components/GeneralSetting/index.tsx | 63 ++++++++++++++----- packages/neuron-ui/src/locales/en.json | 4 ++ packages/neuron-ui/src/locales/zh.json | 4 ++ packages/neuron-ui/src/services/remote/app.ts | 2 + packages/neuron-wallet/src/controllers/api.ts | 9 ++- .../neuron-wallet/src/controllers/app/menu.ts | 10 ++- .../neuron-wallet/src/controllers/update.ts | 7 ++- 7 files changed, 77 insertions(+), 22 deletions(-) diff --git a/packages/neuron-ui/src/components/GeneralSetting/index.tsx b/packages/neuron-ui/src/components/GeneralSetting/index.tsx index f535311820..b673a0be26 100644 --- a/packages/neuron-ui/src/components/GeneralSetting/index.tsx +++ b/packages/neuron-ui/src/components/GeneralSetting/index.tsx @@ -3,11 +3,21 @@ import { useTranslation } from 'react-i18next' import { Stack, PrimaryButton, Spinner, Text } from 'office-ui-fabric-react' import { StateWithDispatch } from 'states/stateProvider/reducer' import { addPopup } from 'states/stateProvider/actionCreators' -import { clearCellCache } from 'services/remote' +import { checkForUpdates, clearCellCache } from 'services/remote' const GeneralSetting = ({ dispatch }: React.PropsWithoutRef) => { const [t] = useTranslation() const [clearing, setClearing] = useState(false) + const [checkingUpdates, setCheckingUpdates] = useState(false) // TODO: checkingUpdates should be fetched from backend + + const checkUpdates = useCallback(() => { + setCheckingUpdates(true) + setTimeout(() => { + checkForUpdates().finally(() => { + setCheckingUpdates(false) + }) + }, 100) + }, [dispatch]) const clearCache = useCallback(() => { setClearing(true) @@ -21,23 +31,42 @@ const GeneralSetting = ({ dispatch }: React.PropsWithoutRef) return ( - - - {clearing ? : t('settings.general.clear-cache')} - + + + + {checkingUpdates ? : t('updates.check-updates')} + + + + + + + {t('settings.general.clear-cache-description')} + + + + {clearing ? : t('settings.general.clear-cache')} + + - - {t('settings.general.clear-cache-description')} - ) } diff --git a/packages/neuron-ui/src/locales/en.json b/packages/neuron-ui/src/locales/en.json index 90f8907dfd..cffcea49d9 100644 --- a/packages/neuron-ui/src/locales/en.json +++ b/packages/neuron-ui/src/locales/en.json @@ -343,6 +343,10 @@ "withdraw-alert": "Hint: these are only {{epochs}} epochs (~{{hours}} hours) until the end of your current lock period. If you wish to withdraw in current lock period, please send withdraw request in time. There are {{nextLeftEpochs}} epochs(~{{days}} days) until the end of your next lock period.", "insufficient-period-alert-title": "Referenced Header is Invalid", "insufficient-period-alert-message": "Only mature header can be referenced in transactions(Matureness requires 4 epochs)" + }, + "updates": { + "check-updates": "Check for Updates", + "download-update": "Download Update" } } } diff --git a/packages/neuron-ui/src/locales/zh.json b/packages/neuron-ui/src/locales/zh.json index 09b33fc319..06db116a9c 100644 --- a/packages/neuron-ui/src/locales/zh.json +++ b/packages/neuron-ui/src/locales/zh.json @@ -343,6 +343,10 @@ "withdraw-alert": "提示:本补贴申请距离 Nervos DAO 规则允许的最近一个锁定周期仅剩下 {{epochs}} 个 epoch (约 {{hours}} 小时)。 如果您希望在本锁定周期取出,请及时提交取出申请,以确保取出申请能在本锁定周期结束之前上链。下一个锁定周期的结束时间预计为 {{nextLeftEpochs}} 个 epochs (约 {{days}} 天)。", "insufficient-period-alert-title": "Header 引用无效", "insufficient-period-alert-message": "交易只能引用已成熟的 Header(成熟期为 4 个 epochs)" + }, + "updates": { + "check-updates": "检查更新", + "download-update": "下载更新" } } } diff --git a/packages/neuron-ui/src/services/remote/app.ts b/packages/neuron-ui/src/services/remote/app.ts index 238c302074..457a9b5d55 100644 --- a/packages/neuron-ui/src/services/remote/app.ts +++ b/packages/neuron-ui/src/services/remote/app.ts @@ -5,11 +5,13 @@ export const getNeuronWalletState = apiMethodWrapper(api => () => api.load export const handleViewError = apiMethodWrapper(api => errorMessage => api.handleViewError(errorMessage)) export const contextMenu = apiMethodWrapper<{ type: string; id: string }>(api => params => api.contextMenu(params)) +export const checkForUpdates = apiMethodWrapper(api => () => api.checkForUpdates()) export const clearCellCache = apiMethodWrapper(api => () => api.clearCellCache()) export default { getNeuronWalletState, handleViewError, contextMenu, + checkForUpdates, clearCellCache, } diff --git a/packages/neuron-wallet/src/controllers/api.ts b/packages/neuron-wallet/src/controllers/api.ts index de2256d98d..ea64242fa4 100644 --- a/packages/neuron-wallet/src/controllers/api.ts +++ b/packages/neuron-wallet/src/controllers/api.ts @@ -4,7 +4,7 @@ import env from 'env' import i18n from 'utils/i18n' import { popContextMenu } from './app/menu' import { showWindow } from './app/show-window' -import { TransactionsController, WalletsController, SyncController, NetworksController } from 'controllers' +import { TransactionsController, WalletsController, SyncController, NetworksController, UpdateController } from 'controllers' import { NetworkType, NetworkID, Network } from 'types/network' import NetworksService from 'services/networks' import WalletsService from 'services/wallets' @@ -271,6 +271,7 @@ export default class ApiController { } // Dao + @MapApiResponse public static async getDaoCells( params: Controller.Params.GetDaoCellsParams @@ -279,6 +280,12 @@ export default class ApiController { } // settings + + @MapApiResponse + public static async checkForUpdates() { + return new UpdateController().checkUpdates() + } + @MapApiResponse public static async clearCellCache() { await SyncController.stopSyncing() diff --git a/packages/neuron-wallet/src/controllers/app/menu.ts b/packages/neuron-wallet/src/controllers/app/menu.ts index f82ef2d9d0..82a9ae0bdc 100644 --- a/packages/neuron-wallet/src/controllers/app/menu.ts +++ b/packages/neuron-wallet/src/controllers/app/menu.ts @@ -79,7 +79,10 @@ const updateApplicationMenu = (mainWindow: BrowserWindow | null) => { { enabled: isMainWindow, label: i18n.t('application-menu.neuron.check-updates'), - click: (menuItem: MenuItem) => { new UpdateController().checkUpdates(menuItem) } + click: (menuItem: MenuItem) => { + new UpdateController().checkUpdates(menuItem) + navTo(URL.Preference) + } }, separator, { @@ -225,7 +228,10 @@ const updateApplicationMenu = (mainWindow: BrowserWindow | null) => { }) helpSubmenu.push({ label: i18n.t('application-menu.neuron.check-updates'), - click: (menuItem: MenuItem) => { new UpdateController().checkUpdates(menuItem) } + click: (menuItem: MenuItem) => { + new UpdateController().checkUpdates(menuItem) + navTo(URL.Preference) + } }) helpSubmenu.push({ id: 'about', diff --git a/packages/neuron-wallet/src/controllers/update.ts b/packages/neuron-wallet/src/controllers/update.ts index 139027982e..d8e8685709 100644 --- a/packages/neuron-wallet/src/controllers/update.ts +++ b/packages/neuron-wallet/src/controllers/update.ts @@ -12,9 +12,12 @@ export default class UpdateController { this.bindEvents() } - public checkUpdates(sender: { enabled: boolean }) { + // TODO: refactor: do not require sender + public checkUpdates(sender: { enabled: boolean } | null = null) { this.sender = sender - this.sender.enabled = false + if (this.sender) { + this.sender.enabled = false + } autoUpdater.checkForUpdates() } From cd82ca48b78b7ede73b414a82d38d9e0106d44d2 Mon Sep 17 00:00:00 2001 From: James Chen Date: Wed, 27 Nov 2019 22:28:12 +0900 Subject: [PATCH 23/43] feat: Different stage status of checking updates --- .../src/components/GeneralSetting/index.tsx | 96 +++++++++++++++---- packages/neuron-ui/src/locales/en.json | 9 +- packages/neuron-ui/src/locales/zh.json | 7 +- 3 files changed, 92 insertions(+), 20 deletions(-) diff --git a/packages/neuron-ui/src/components/GeneralSetting/index.tsx b/packages/neuron-ui/src/components/GeneralSetting/index.tsx index b673a0be26..1c691eac0e 100644 --- a/packages/neuron-ui/src/components/GeneralSetting/index.tsx +++ b/packages/neuron-ui/src/components/GeneralSetting/index.tsx @@ -1,21 +1,79 @@ import React, { useCallback, useState } from 'react' import { useTranslation } from 'react-i18next' -import { Stack, PrimaryButton, Spinner, Text } from 'office-ui-fabric-react' +import { Stack, PrimaryButton, Spinner, Text, ProgressIndicator } from 'office-ui-fabric-react' import { StateWithDispatch } from 'states/stateProvider/reducer' import { addPopup } from 'states/stateProvider/actionCreators' import { checkForUpdates, clearCellCache } from 'services/remote' +const UpdateDownloadStatus = ({ + progress = 0, + newVersion = '', +}: React.PropsWithoutRef<{ progress: number; newVersion: string }>) => { + const [t] = useTranslation() + const available = newVersion !== '' && progress <= 0 + const downloaded = progress >= 1 + + if (available) { + return ( + + + {t('updates.updates-found-do-you-want-to-update', { version: newVersion })} + + + + {t('updates.download-update')} + + + + ) + } + + if (downloaded) { + return ( + + + {t('updates.updates-downloaded-about-to-quit-and-install')} + + + + {t('updates.quit-and-install')} + + + + ) + } + + return ( + + ) +} + const GeneralSetting = ({ dispatch }: React.PropsWithoutRef) => { const [t] = useTranslation() const [clearing, setClearing] = useState(false) const [checkingUpdates, setCheckingUpdates] = useState(false) // TODO: checkingUpdates should be fetched from backend + const [downloadingUpdate] = useState(false) const checkUpdates = useCallback(() => { setCheckingUpdates(true) setTimeout(() => { - checkForUpdates().finally(() => { - setCheckingUpdates(false) - }) + checkForUpdates() }, 100) }, [dispatch]) @@ -33,18 +91,22 @@ const GeneralSetting = ({ dispatch }: React.PropsWithoutRef) - - {checkingUpdates ? : t('updates.check-updates')} - + {downloadingUpdate ? ( + + ) : ( + + {checkingUpdates ? : t('updates.check-updates')} + + )} @@ -59,7 +121,7 @@ const GeneralSetting = ({ dispatch }: React.PropsWithoutRef) ariaDescription="Clear cache" styles={{ root: { - minWidth: 150, + minWidth: 180, }, }} > diff --git a/packages/neuron-ui/src/locales/en.json b/packages/neuron-ui/src/locales/en.json index cffcea49d9..a13864f43b 100644 --- a/packages/neuron-ui/src/locales/en.json +++ b/packages/neuron-ui/src/locales/en.json @@ -178,7 +178,7 @@ "network": "Network" }, "general": { - "clear-cache": "Clear cache", + "clear-cache": "Clear Cache", "clear-cache-description": "Clear cache if you encounter data sync or balance display problems. Neuron will rescan block data.", "show": "Show", "hide": "Hide" @@ -346,7 +346,12 @@ }, "updates": { "check-updates": "Check for Updates", - "download-update": "Download Update" + "downloading-update": "Downloading update...", + "update-not-available": "There are currently no updates available.", + "updates-found-do-you-want-to-update": "An update ({{version}}) is available, do you want to download and update now?", + "download-update": "Download Update", + "updates-downloaded-about-to-quit-and-install": "Update downloaded. Neuron will quit and install the update...", + "quit-and-install": "Quit and Install" } } } diff --git a/packages/neuron-ui/src/locales/zh.json b/packages/neuron-ui/src/locales/zh.json index 06db116a9c..f44d578059 100644 --- a/packages/neuron-ui/src/locales/zh.json +++ b/packages/neuron-ui/src/locales/zh.json @@ -346,7 +346,12 @@ }, "updates": { "check-updates": "检查更新", - "download-update": "下载更新" + "downloading-update": "正在下载更新...", + "update-not-available": "没有可供升级的新版本。", + "updates-found-do-you-want-to-update": "有可供升级的新版本({{version}})。现在进行下载和升级吗?", + "download-update": "下载更新以升级", + "updates-downloaded-about-to-quit-and-install": "下载完成。Neuron 将退出并安装新版本...", + "quit-and-install": "退出并安装" } } } From 423109dcebd6d47b71136fe927bff3c22b99f6da Mon Sep 17 00:00:00 2001 From: James Chen Date: Wed, 27 Nov 2019 23:50:25 +0900 Subject: [PATCH 24/43] feat: Add app updater subject and state --- packages/neuron-ui/src/containers/Main/hooks.ts | 9 +++++++++ packages/neuron-ui/src/services/subjects.ts | 3 +++ packages/neuron-ui/src/states/initStates/index.ts | 3 +++ .../neuron-ui/src/states/initStates/updater.ts | 8 ++++++++ .../neuron-ui/src/states/stateProvider/reducer.ts | 14 ++++++++++++++ packages/neuron-ui/src/types/App/index.d.ts | 8 ++++++++ packages/neuron-ui/src/types/Subject/index.d.ts | 6 ++++++ .../neuron-wallet/src/controllers/app/subscribe.ts | 5 +++++ .../src/models/subjects/app-updater.ts | 10 ++++++++++ 9 files changed, 66 insertions(+) create mode 100644 packages/neuron-ui/src/states/initStates/updater.ts create mode 100644 packages/neuron-wallet/src/models/subjects/app-updater.ts diff --git a/packages/neuron-ui/src/containers/Main/hooks.ts b/packages/neuron-ui/src/containers/Main/hooks.ts index 1bd1a525ee..ada6f494e0 100644 --- a/packages/neuron-ui/src/containers/Main/hooks.ts +++ b/packages/neuron-ui/src/containers/Main/hooks.ts @@ -17,6 +17,7 @@ import { CurrentNetworkID as CurrentNetworkIDSubject, ConnectionStatus as ConnectionStatusSubject, SyncedBlockNumber as SyncedBlockNumberSubject, + AppUpdater as AppUpdaterSubject, Command as CommandSubject, } from 'services/subjects' import { ckbCore, getBlockchainInfo, getTipHeader } from 'services/chain' @@ -183,6 +184,13 @@ export const useSubscription = ({ }) }) + const appUpdaterSubscription = AppUpdaterSubject.subscribe(appUpdaterInfo => { + dispatch({ + type: NeuronWalletActions.UpdateAppUpdaterStatus, + payload: appUpdaterInfo, + }) + }) + const commandSubscription = CommandSubject.subscribe(({ winID, type, payload }: Subject.CommandMetaInfo) => { if (winID && getWinID() === winID) { switch (type) { @@ -223,6 +231,7 @@ export const useSubscription = ({ currentNetworkIDSubscription.unsubscribe() connectionStatusSubscription.unsubscribe() syncedBlockNumberSubscription.unsubscribe() + appUpdaterSubscription.unsubscribe() commandSubscription.unsubscribe() } }, [walletID, pageNo, pageSize, keywords, isAllowedToFetchList, history, dispatch]) diff --git a/packages/neuron-ui/src/services/subjects.ts b/packages/neuron-ui/src/services/subjects.ts index dc9566c05e..3152c613b9 100644 --- a/packages/neuron-ui/src/services/subjects.ts +++ b/packages/neuron-ui/src/services/subjects.ts @@ -21,6 +21,7 @@ const SubjectConstructor = ( | 'connection-status-updated' | 'synced-block-number-updated' | 'command' + | 'app-updater-updated' ) => { return window.ipcRenderer ? { @@ -45,6 +46,7 @@ export const NetworkList = SubjectConstructor('network-list export const CurrentNetworkID = SubjectConstructor('current-network-id-updated') export const ConnectionStatus = SubjectConstructor('connection-status-updated') export const SyncedBlockNumber = SubjectConstructor('synced-block-number-updated') +export const AppUpdater = SubjectConstructor('app-updater-updated') export const Command = SubjectConstructor('command') export default { @@ -56,5 +58,6 @@ export default { CurrentNetworkID, ConnectionStatus, SyncedBlockNumber, + AppUpdater, Command, } diff --git a/packages/neuron-ui/src/states/initStates/index.ts b/packages/neuron-ui/src/states/initStates/index.ts index 9cac8f7eee..f393cf795e 100644 --- a/packages/neuron-ui/src/states/initStates/index.ts +++ b/packages/neuron-ui/src/states/initStates/index.ts @@ -3,12 +3,14 @@ import chain from './chain' import wallet from './wallet' import settings from './settings' import nervosDAO from './nervosDAO' +import updater from './updater' export * from './app' export * from './chain' export * from './wallet' export * from './settings' export * from './nervosDAO' +export * from './updater' const initStates = { app, @@ -16,6 +18,7 @@ const initStates = { wallet, settings, nervosDAO, + updater, } export default initStates diff --git a/packages/neuron-ui/src/states/initStates/updater.ts b/packages/neuron-ui/src/states/initStates/updater.ts new file mode 100644 index 0000000000..487b8769c6 --- /dev/null +++ b/packages/neuron-ui/src/states/initStates/updater.ts @@ -0,0 +1,8 @@ +const appUpdaterState: State.AppUpdater = { + checking: false, + downloadProgress: -1, + version: '', + releaseNotes: '', +} + +export default appUpdaterState diff --git a/packages/neuron-ui/src/states/stateProvider/reducer.ts b/packages/neuron-ui/src/states/stateProvider/reducer.ts index 54ed5a328b..6a71bd17bd 100644 --- a/packages/neuron-ui/src/states/stateProvider/reducer.ts +++ b/packages/neuron-ui/src/states/stateProvider/reducer.ts @@ -20,6 +20,8 @@ export enum NeuronWalletActions { UpdateSyncedBlockNumber = 'updateSyncedBlockNumber', // dao UpdateNervosDaoData = 'updateNervosDaoData', + // updater + UpdateAppUpdaterStatus = 'updateAppUpdaterStatus', } export enum AppActions { UpdateTransactionID = 'updateTransactionID', @@ -97,6 +99,12 @@ export const reducer = ( networks, wallets, }, + updater: { + checking: false, + downloadProgress: -1, + version: '', + releaseNotes: '', + }, } } case NeuronWalletActions.UpdateCodeHash: { @@ -224,6 +232,12 @@ export const reducer = ( }, } } + case NeuronWalletActions.UpdateAppUpdaterStatus: { + return { + ...state, + updater: payload, + } + } case NeuronWalletActions.UpdateNervosDaoData: { return { ...state, diff --git a/packages/neuron-ui/src/types/App/index.d.ts b/packages/neuron-ui/src/types/App/index.d.ts index a8abf40fd5..227daa96b7 100644 --- a/packages/neuron-ui/src/types/App/index.d.ts +++ b/packages/neuron-ui/src/types/App/index.d.ts @@ -184,12 +184,20 @@ declare namespace State { records: NervosDAORecord[] } + interface AppUpdater { + checking: boolean + downloadProgress: number + version: string + releaseNotes: string + } + interface AppWithNeuronWallet { app: App chain: Chain settings: Settings wallet: Wallet nervosDAO: NervosDAO + updater: AppUpdater } } diff --git a/packages/neuron-ui/src/types/Subject/index.d.ts b/packages/neuron-ui/src/types/Subject/index.d.ts index b614627c1d..c141cf4b3f 100644 --- a/packages/neuron-ui/src/types/Subject/index.d.ts +++ b/packages/neuron-ui/src/types/Subject/index.d.ts @@ -29,4 +29,10 @@ declare namespace Subject { } type ConnectionStatus = boolean type BlockNumber = string + interface AppUpdater { + checking: boolean + downloadProgress: number + version: string + releaseNotes: string + } } diff --git a/packages/neuron-wallet/src/controllers/app/subscribe.ts b/packages/neuron-wallet/src/controllers/app/subscribe.ts index f0f9aa8bfd..a193555a93 100644 --- a/packages/neuron-wallet/src/controllers/app/subscribe.ts +++ b/packages/neuron-wallet/src/controllers/app/subscribe.ts @@ -7,6 +7,7 @@ import { DebouncedCurrentNetworkIDSubject, DebouncedNetworkListSubject } from 'm import { SampledSyncedBlockNumberSubject, DebouncedConnectionStatusSubject } from 'models/subjects/node' import { WalletListSubject, CurrentWalletSubject } from 'models/subjects/wallets' import dataUpdateSubject from 'models/subjects/data-update' +import AppUpdaterSubject from 'models/subjects/app-updater' interface AppResponder { sendMessage: (channel: string, arg: any) => void @@ -52,4 +53,8 @@ export const subscribe = (dispatcher: AppResponder) => { dataUpdateSubject.next({ dataType: 'current-wallet', actionType: 'update' }) } }) + + AppUpdaterSubject.subscribe(params => { + dispatcher.sendMessage('app-updater-updated', params) + }) } diff --git a/packages/neuron-wallet/src/models/subjects/app-updater.ts b/packages/neuron-wallet/src/models/subjects/app-updater.ts new file mode 100644 index 0000000000..c3bd1c55af --- /dev/null +++ b/packages/neuron-wallet/src/models/subjects/app-updater.ts @@ -0,0 +1,10 @@ +import { Subject } from 'rxjs' + +const AppUpdaterSubject = new Subject<{ + checking: boolean + downloadProgress: number, // -1: not started, 1: finished, 0~1: downloading + version: string, // "": no update, "v.x.y.z": version v.x.y.z available + releaseNotes: string +}>() + +export default AppUpdaterSubject From cd8e5d5a33fd171acb49f0aaa235f8e5aad65cf0 Mon Sep 17 00:00:00 2001 From: James Chen Date: Thu, 28 Nov 2019 08:55:50 +0900 Subject: [PATCH 25/43] feat: Trigger check updates menu item enabling/disabling --- .../neuron-wallet/src/controllers/app/menu.ts | 13 ++-- .../src/controllers/app/subscribe.ts | 1 + .../neuron-wallet/src/controllers/update.ts | 64 +++++++++---------- 3 files changed, 40 insertions(+), 38 deletions(-) diff --git a/packages/neuron-wallet/src/controllers/app/menu.ts b/packages/neuron-wallet/src/controllers/app/menu.ts index 82a9ae0bdc..b0e8a97e99 100644 --- a/packages/neuron-wallet/src/controllers/app/menu.ts +++ b/packages/neuron-wallet/src/controllers/app/menu.ts @@ -1,4 +1,4 @@ -import { app, shell, BrowserWindow, dialog, MenuItemConstructorOptions, clipboard, Menu, MenuItem, MessageBoxOptions, MessageBoxReturnValue } from 'electron' +import { app, shell, BrowserWindow, dialog, MenuItemConstructorOptions, clipboard, Menu, MessageBoxOptions, MessageBoxReturnValue } from 'electron' import { bech32Address, AddressPrefix, AddressType } from '@nervosnetwork/ckb-sdk-utils' import i18n from 'utils/i18n' import env from 'env' @@ -77,10 +77,10 @@ const updateApplicationMenu = (mainWindow: BrowserWindow | null) => { click: () => { showAbout() }, }, { - enabled: isMainWindow, label: i18n.t('application-menu.neuron.check-updates'), - click: (menuItem: MenuItem) => { - new UpdateController().checkUpdates(menuItem) + enabled: isMainWindow && !UpdateController.isChecking, + click: () => { + new UpdateController().checkUpdates() navTo(URL.Preference) } }, @@ -228,8 +228,9 @@ const updateApplicationMenu = (mainWindow: BrowserWindow | null) => { }) helpSubmenu.push({ label: i18n.t('application-menu.neuron.check-updates'), - click: (menuItem: MenuItem) => { - new UpdateController().checkUpdates(menuItem) + enabled: isMainWindow && !UpdateController.isChecking, + click: () => { + new UpdateController().checkUpdates() navTo(URL.Preference) } }) diff --git a/packages/neuron-wallet/src/controllers/app/subscribe.ts b/packages/neuron-wallet/src/controllers/app/subscribe.ts index a193555a93..0e7b3dd131 100644 --- a/packages/neuron-wallet/src/controllers/app/subscribe.ts +++ b/packages/neuron-wallet/src/controllers/app/subscribe.ts @@ -55,6 +55,7 @@ export const subscribe = (dispatcher: AppResponder) => { }) AppUpdaterSubject.subscribe(params => { + dispatcher.updateMenu() dispatcher.sendMessage('app-updater-updated', params) }) } diff --git a/packages/neuron-wallet/src/controllers/update.ts b/packages/neuron-wallet/src/controllers/update.ts index d8e8685709..04ecdf5e7b 100644 --- a/packages/neuron-wallet/src/controllers/update.ts +++ b/packages/neuron-wallet/src/controllers/update.ts @@ -1,25 +1,29 @@ import { dialog } from 'electron' import { autoUpdater, UpdateInfo } from 'electron-updater' import i18n from 'utils/i18n' +import AppUpdaterSubject from 'models/subjects/app-updater' export default class UpdateController { - sender: { enabled: boolean } | null + static isChecking = false // One instance is already running and checking constructor() { autoUpdater.autoDownload = false - this.sender = null - this.bindEvents() - } - - // TODO: refactor: do not require sender - public checkUpdates(sender: { enabled: boolean } | null = null) { - this.sender = sender - if (this.sender) { - this.sender.enabled = false + if (!UpdateController.isChecking) { + this.bindEvents() } + } + public checkUpdates() { + UpdateController.isChecking = true autoUpdater.checkForUpdates() + + AppUpdaterSubject.next({ + checking: true, + downloadProgress: -1, + version: '', + releaseNotes: '' + }) } bindEvents() { @@ -27,25 +31,14 @@ export default class UpdateController { autoUpdater.on('error', error => { dialog.showErrorBox('Error', error == null ? 'unknown' : (error.stack || error).toString()) - this.enableSender() + + UpdateController.isChecking = false + this.notify() }) autoUpdater.on('update-available', (info: UpdateInfo) => { - const { version } = info - dialog - .showMessageBox({ - type: 'info', - title: version, - message: i18n.t('updater.updates-found-do-you-want-to-update', { version }), - buttons: [i18n.t('updater.update-now'), i18n.t('common.no')], - }) - .then(returnValue => { - if (returnValue.response === 0) { - autoUpdater.downloadUpdate() - } else { - this.enableSender() - } - }) + UpdateController.isChecking = false + this.notify(-1, info.version, 'todo') }) autoUpdater.on('update-not-available', () => { @@ -54,7 +47,9 @@ export default class UpdateController { message: i18n.t('updater.update-not-available'), buttons: [i18n.t('common.ok')], }) - this.enableSender() + + UpdateController.isChecking = false + this.notify() }) autoUpdater.on('update-downloaded', () => { @@ -67,13 +62,18 @@ export default class UpdateController { .then(() => { setImmediate(() => autoUpdater.quitAndInstall()) }) + + UpdateController.isChecking = false + this.notify(1, 'toto', '') }) } - enableSender() { - if (this.sender) { - this.sender.enabled = true - } - this.sender = null + private notify(downloadProgress: number = -1, version = '', releaseNotes = '') { + AppUpdaterSubject.next({ + checking: UpdateController.isChecking, + downloadProgress, + version, + releaseNotes + }) } } From b8d24ca9f4d31c6fb0e7c3eee6744c0ce037638b Mon Sep 17 00:00:00 2001 From: James Chen Date: Thu, 28 Nov 2019 09:15:17 +0900 Subject: [PATCH 26/43] feat: Add API for downloading and installing updates --- .../src/components/GeneralSetting/index.tsx | 14 ++++++++++- packages/neuron-ui/src/services/remote/app.ts | 2 -- .../neuron-ui/src/services/remote/index.ts | 1 + .../neuron-ui/src/services/remote/updater.ts | 11 +++++++++ packages/neuron-wallet/src/controllers/api.ts | 12 +++++++++- .../neuron-wallet/src/controllers/update.ts | 24 +++++++++---------- 6 files changed, 47 insertions(+), 17 deletions(-) create mode 100644 packages/neuron-ui/src/services/remote/updater.ts diff --git a/packages/neuron-ui/src/components/GeneralSetting/index.tsx b/packages/neuron-ui/src/components/GeneralSetting/index.tsx index 1c691eac0e..adf6e8da9c 100644 --- a/packages/neuron-ui/src/components/GeneralSetting/index.tsx +++ b/packages/neuron-ui/src/components/GeneralSetting/index.tsx @@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next' import { Stack, PrimaryButton, Spinner, Text, ProgressIndicator } from 'office-ui-fabric-react' import { StateWithDispatch } from 'states/stateProvider/reducer' import { addPopup } from 'states/stateProvider/actionCreators' -import { checkForUpdates, clearCellCache } from 'services/remote' +import { checkForUpdates, downloadUpdate, installUpdate, clearCellCache } from 'services/remote' const UpdateDownloadStatus = ({ progress = 0, @@ -14,6 +14,10 @@ const UpdateDownloadStatus = ({ const downloaded = progress >= 1 if (available) { + const download = () => { + downloadUpdate() + } + return ( @@ -21,6 +25,8 @@ const UpdateDownloadStatus = ({ { + installUpdate() + } + return ( @@ -42,6 +52,8 @@ const UpdateDownloadStatus = ({ (api => () => api.load export const handleViewError = apiMethodWrapper(api => errorMessage => api.handleViewError(errorMessage)) export const contextMenu = apiMethodWrapper<{ type: string; id: string }>(api => params => api.contextMenu(params)) -export const checkForUpdates = apiMethodWrapper(api => () => api.checkForUpdates()) export const clearCellCache = apiMethodWrapper(api => () => api.clearCellCache()) export default { getNeuronWalletState, handleViewError, contextMenu, - checkForUpdates, clearCellCache, } diff --git a/packages/neuron-ui/src/services/remote/index.ts b/packages/neuron-ui/src/services/remote/index.ts index 1e03678d54..5e717365d7 100644 --- a/packages/neuron-ui/src/services/remote/index.ts +++ b/packages/neuron-ui/src/services/remote/index.ts @@ -2,6 +2,7 @@ export * from './app' export * from './wallets' export * from './networks' export * from './transactions' +export * from './updater' const REMOTE_MODULE_NOT_FOUND = 'The remote module is not found, please make sure the UI is running inside the Electron App' diff --git a/packages/neuron-ui/src/services/remote/updater.ts b/packages/neuron-ui/src/services/remote/updater.ts new file mode 100644 index 0000000000..ddf8207362 --- /dev/null +++ b/packages/neuron-ui/src/services/remote/updater.ts @@ -0,0 +1,11 @@ +import { apiMethodWrapper } from './apiMethodWrapper' + +export const checkForUpdates = apiMethodWrapper(api => () => api.checkForUpdates()) +export const downloadUpdate = apiMethodWrapper(api => () => api.downloadUpdate()) +export const installUpdate = apiMethodWrapper(api => () => api.quitAndInstall()) + +export default { + checkForUpdates, + downloadUpdate, + installUpdate, +} diff --git a/packages/neuron-wallet/src/controllers/api.ts b/packages/neuron-wallet/src/controllers/api.ts index ea64242fa4..59470a40c6 100644 --- a/packages/neuron-wallet/src/controllers/api.ts +++ b/packages/neuron-wallet/src/controllers/api.ts @@ -279,13 +279,23 @@ export default class ApiController { return DaoController.getDaoCells(params) } - // settings + // Settings @MapApiResponse public static async checkForUpdates() { return new UpdateController().checkUpdates() } + @MapApiResponse + public static async downloadUpdate() { + return new UpdateController(false).downloadUpdate() + } + + @MapApiResponse + public static async quitAndInstall() { + return new UpdateController(false).quitAndInstall() + } + @MapApiResponse public static async clearCellCache() { await SyncController.stopSyncing() diff --git a/packages/neuron-wallet/src/controllers/update.ts b/packages/neuron-wallet/src/controllers/update.ts index 04ecdf5e7b..7330708c8e 100644 --- a/packages/neuron-wallet/src/controllers/update.ts +++ b/packages/neuron-wallet/src/controllers/update.ts @@ -6,10 +6,10 @@ import AppUpdaterSubject from 'models/subjects/app-updater' export default class UpdateController { static isChecking = false // One instance is already running and checking - constructor() { + constructor(check: boolean = true) { autoUpdater.autoDownload = false - if (!UpdateController.isChecking) { + if (check && !UpdateController.isChecking) { this.bindEvents() } } @@ -26,7 +26,15 @@ export default class UpdateController { }) } - bindEvents() { + public quitAndInstall() { + autoUpdater.quitAndInstall() + } + + public downloadUpdate() { + autoUpdater.downloadUpdate() + } + + private bindEvents() { autoUpdater.removeAllListeners() autoUpdater.on('error', error => { @@ -53,16 +61,6 @@ export default class UpdateController { }) autoUpdater.on('update-downloaded', () => { - dialog - .showMessageBox({ - type: 'info', - message: i18n.t('updater.updates-downloaded-about-to-quit-and-install'), - buttons: [i18n.t('common.ok')], - }) - .then(() => { - setImmediate(() => autoUpdater.quitAndInstall()) - }) - UpdateController.isChecking = false this.notify(1, 'toto', '') }) From bcafce881a71efdbea709f12daf24486a2771886 Mon Sep 17 00:00:00 2001 From: James Chen Date: Thu, 28 Nov 2019 09:35:18 +0900 Subject: [PATCH 27/43] feat: Delete unused updater translations --- packages/neuron-wallet/src/locales/en.ts | 3 --- packages/neuron-wallet/src/locales/zh.ts | 3 --- 2 files changed, 6 deletions(-) diff --git a/packages/neuron-wallet/src/locales/en.ts b/packages/neuron-wallet/src/locales/en.ts index a437ec3d14..c38c5a8d5d 100644 --- a/packages/neuron-wallet/src/locales/en.ts +++ b/packages/neuron-wallet/src/locales/en.ts @@ -143,9 +143,6 @@ export default { }, updater: { 'update-not-available': 'There are currently no updates available.', - 'updates-found-do-you-want-to-update': 'An update ({{version}}) is available, do you want to update now?', - 'update-now': 'Update now', - 'updates-downloaded-about-to-quit-and-install': 'Update downloaded. Neuron will quit and install the update...', }, common: { yes: 'Yes', diff --git a/packages/neuron-wallet/src/locales/zh.ts b/packages/neuron-wallet/src/locales/zh.ts index c77849b7c2..7dc69d8408 100644 --- a/packages/neuron-wallet/src/locales/zh.ts +++ b/packages/neuron-wallet/src/locales/zh.ts @@ -142,9 +142,6 @@ export default { }, updater: { 'update-not-available': '没有可供升级的新版本。', - 'updates-found-do-you-want-to-update': '有可供升级的新版本({{version}})。现在进行升级吗?', - 'update-now': '马上升级', - 'updates-downloaded-about-to-quit-and-install': '下载完成。Neuron 将退出并安装新版本...', }, common: { yes: '是', From b2673213ceb94a5a93052c241b54646add383456 Mon Sep 17 00:00:00 2001 From: James Chen Date: Thu, 28 Nov 2019 10:29:57 +0900 Subject: [PATCH 28/43] feat: Connect updater events to UI --- .../src/components/GeneralSetting/index.tsx | 33 +++++++++---------- packages/neuron-ui/src/locales/en.json | 2 +- packages/neuron-ui/src/locales/zh.json | 2 +- .../neuron-wallet/src/controllers/update.ts | 14 +++++--- 4 files changed, 26 insertions(+), 25 deletions(-) diff --git a/packages/neuron-ui/src/components/GeneralSetting/index.tsx b/packages/neuron-ui/src/components/GeneralSetting/index.tsx index adf6e8da9c..9cb9cd7671 100644 --- a/packages/neuron-ui/src/components/GeneralSetting/index.tsx +++ b/packages/neuron-ui/src/components/GeneralSetting/index.tsx @@ -1,6 +1,7 @@ -import React, { useCallback, useState } from 'react' +import React, { useContext, useCallback, useState } from 'react' import { useTranslation } from 'react-i18next' import { Stack, PrimaryButton, Spinner, Text, ProgressIndicator } from 'office-ui-fabric-react' +import { NeuronWalletContext } from 'states/stateProvider' import { StateWithDispatch } from 'states/stateProvider/reducer' import { addPopup } from 'states/stateProvider/actionCreators' import { checkForUpdates, downloadUpdate, installUpdate, clearCellCache } from 'services/remote' @@ -26,7 +27,7 @@ const UpdateDownloadStatus = ({ ) => { const [t] = useTranslation() - const [clearing, setClearing] = useState(false) - const [checkingUpdates, setCheckingUpdates] = useState(false) // TODO: checkingUpdates should be fetched from backend - const [downloadingUpdate] = useState(false) + const { updater } = useContext(NeuronWalletContext) + const [clearingCache, setClearingCache] = useState(false) const checkUpdates = useCallback(() => { - setCheckingUpdates(true) - setTimeout(() => { - checkForUpdates() - }, 100) - }, [dispatch]) + checkForUpdates() + }, []) const clearCache = useCallback(() => { - setClearing(true) + setClearingCache(true) setTimeout(() => { clearCellCache().finally(() => { addPopup('clear-cache-successfully')(dispatch) - setClearing(false) + setClearingCache(false) }) }, 100) }, [dispatch]) @@ -103,12 +100,12 @@ const GeneralSetting = ({ dispatch }: React.PropsWithoutRef) - {downloadingUpdate ? ( - + {updater.version !== '' || updater.downloadProgress >= 0 ? ( + ) : ( ) }, }} > - {checkingUpdates ? : t('updates.check-updates')} + {updater.checking ? : t('updates.check-updates')} )} @@ -129,7 +126,7 @@ const GeneralSetting = ({ dispatch }: React.PropsWithoutRef) ) }, }} > - {clearing ? : t('settings.general.clear-cache')} + {clearingCache ? : t('settings.general.clear-cache')} diff --git a/packages/neuron-ui/src/locales/en.json b/packages/neuron-ui/src/locales/en.json index a13864f43b..c6c62c4e2f 100644 --- a/packages/neuron-ui/src/locales/en.json +++ b/packages/neuron-ui/src/locales/en.json @@ -350,7 +350,7 @@ "update-not-available": "There are currently no updates available.", "updates-found-do-you-want-to-update": "An update ({{version}}) is available, do you want to download and update now?", "download-update": "Download Update", - "updates-downloaded-about-to-quit-and-install": "Update downloaded. Neuron will quit and install the update...", + "updates-downloaded-about-to-quit-and-install": "Update downloaded. Please quit to install the update.", "quit-and-install": "Quit and Install" } } diff --git a/packages/neuron-ui/src/locales/zh.json b/packages/neuron-ui/src/locales/zh.json index f44d578059..7290777955 100644 --- a/packages/neuron-ui/src/locales/zh.json +++ b/packages/neuron-ui/src/locales/zh.json @@ -350,7 +350,7 @@ "update-not-available": "没有可供升级的新版本。", "updates-found-do-you-want-to-update": "有可供升级的新版本({{version}})。现在进行下载和升级吗?", "download-update": "下载更新以升级", - "updates-downloaded-about-to-quit-and-install": "下载完成。Neuron 将退出并安装新版本...", + "updates-downloaded-about-to-quit-and-install": "下载完成。请退出并安装新版本。", "quit-and-install": "退出并安装" } } diff --git a/packages/neuron-wallet/src/controllers/update.ts b/packages/neuron-wallet/src/controllers/update.ts index 7330708c8e..a966b956d4 100644 --- a/packages/neuron-wallet/src/controllers/update.ts +++ b/packages/neuron-wallet/src/controllers/update.ts @@ -38,10 +38,10 @@ export default class UpdateController { autoUpdater.removeAllListeners() autoUpdater.on('error', error => { - dialog.showErrorBox('Error', error == null ? 'unknown' : (error.stack || error).toString()) - UpdateController.isChecking = false this.notify() + + dialog.showErrorBox('Error', error == null ? 'unknown' : (error.stack || error).toString()) }) autoUpdater.on('update-available', (info: UpdateInfo) => { @@ -50,19 +50,23 @@ export default class UpdateController { }) autoUpdater.on('update-not-available', () => { + UpdateController.isChecking = false + this.notify() + dialog.showMessageBox({ type: 'info', message: i18n.t('updater.update-not-available'), buttons: [i18n.t('common.ok')], }) + }) - UpdateController.isChecking = false - this.notify() + autoUpdater.on('download-progress', progress => { + this.notify(progress.percent / 100) }) autoUpdater.on('update-downloaded', () => { UpdateController.isChecking = false - this.notify(1, 'toto', '') + this.notify(1) }) } From 8cf95811ecfca2ad71858646ec161a39f56ec98c Mon Sep 17 00:00:00 2001 From: James Chen Date: Thu, 28 Nov 2019 11:56:56 +0900 Subject: [PATCH 29/43] feat: Show release notes when there's update available --- .../src/components/GeneralSetting/index.tsx | 22 ++++++++++++++++--- .../GeneralSetting/style.module.scss | 21 ++++++++++++++++++ packages/neuron-ui/src/locales/en.json | 1 + packages/neuron-ui/src/locales/zh.json | 1 + .../neuron-wallet/src/controllers/update.ts | 3 ++- 5 files changed, 44 insertions(+), 4 deletions(-) create mode 100644 packages/neuron-ui/src/components/GeneralSetting/style.module.scss diff --git a/packages/neuron-ui/src/components/GeneralSetting/index.tsx b/packages/neuron-ui/src/components/GeneralSetting/index.tsx index 9cb9cd7671..e2accd625b 100644 --- a/packages/neuron-ui/src/components/GeneralSetting/index.tsx +++ b/packages/neuron-ui/src/components/GeneralSetting/index.tsx @@ -5,13 +5,15 @@ import { NeuronWalletContext } from 'states/stateProvider' import { StateWithDispatch } from 'states/stateProvider/reducer' import { addPopup } from 'states/stateProvider/actionCreators' import { checkForUpdates, downloadUpdate, installUpdate, clearCellCache } from 'services/remote' +import { releaseNotesStyle } from './style.module.scss' const UpdateDownloadStatus = ({ progress = 0, newVersion = '', -}: React.PropsWithoutRef<{ progress: number; newVersion: string }>) => { + releaseNotes = '', +}: React.PropsWithoutRef<{ progress: number; newVersion: string; releaseNotes: string }>) => { const [t] = useTranslation() - const available = newVersion !== '' && progress <= 0 + const available = newVersion !== '' && progress < 0 const downloaded = progress >= 1 if (available) { @@ -19,11 +21,21 @@ const UpdateDownloadStatus = ({ downloadUpdate() } + const releaseNotesHtml = () => { + return { __html: releaseNotes } + } + + /* eslint-disable react/no-danger */ + return ( {t('updates.updates-found-do-you-want-to-update', { version: newVersion })} +

{t('updates.release-notes')}

+
+
+
) {updater.version !== '' || updater.downloadProgress >= 0 ? ( - + ) : ( { UpdateController.isChecking = false - this.notify(-1, info.version, 'todo') + this.notify(-1, info.version, info.releaseNotes as string) }) autoUpdater.on('update-not-available', () => { From af45f0c7afa8c36481e6182eee282d5a8bcb7bfa Mon Sep 17 00:00:00 2001 From: James Chen Date: Thu, 28 Nov 2019 12:22:17 +0900 Subject: [PATCH 30/43] feat: Polish updater i18n translations and UI --- .../neuron-ui/src/components/GeneralSetting/index.tsx | 2 +- packages/neuron-ui/src/locales/en.json | 8 ++++---- packages/neuron-ui/src/locales/zh.json | 10 +++++----- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/neuron-ui/src/components/GeneralSetting/index.tsx b/packages/neuron-ui/src/components/GeneralSetting/index.tsx index e2accd625b..98c710ecff 100644 --- a/packages/neuron-ui/src/components/GeneralSetting/index.tsx +++ b/packages/neuron-ui/src/components/GeneralSetting/index.tsx @@ -109,7 +109,7 @@ const GeneralSetting = ({ dispatch }: React.PropsWithoutRef) }, [dispatch]) return ( - + {updater.version !== '' || updater.downloadProgress >= 0 ? ( diff --git a/packages/neuron-ui/src/locales/en.json b/packages/neuron-ui/src/locales/en.json index 2aababc0e4..b2dfe7c53d 100644 --- a/packages/neuron-ui/src/locales/en.json +++ b/packages/neuron-ui/src/locales/en.json @@ -349,10 +349,10 @@ "downloading-update": "Downloading update...", "update-not-available": "There are currently no updates available.", "release-notes": "Release Notes:", - "updates-found-do-you-want-to-update": "An update ({{version}}) is available, do you want to download and update now?", - "download-update": "Download Update", - "updates-downloaded-about-to-quit-and-install": "Update downloaded. Please quit to install the update.", - "quit-and-install": "Quit and Install" + "updates-found-do-you-want-to-update": "An update ({{version}}) is available, do you want to download and install now?", + "download-update": "Install Update", + "updates-downloaded-about-to-quit-and-install": "Update downloaded. Ready to install and relaunch.", + "quit-and-install": "Install and relaunch" } } } diff --git a/packages/neuron-ui/src/locales/zh.json b/packages/neuron-ui/src/locales/zh.json index 7a20666739..ad859f0de5 100644 --- a/packages/neuron-ui/src/locales/zh.json +++ b/packages/neuron-ui/src/locales/zh.json @@ -347,12 +347,12 @@ "updates": { "check-updates": "检查更新", "downloading-update": "正在下载更新...", - "update-not-available": "没有可供升级的新版本。", + "update-not-available": "已经在使用最新版本", "release-notes": "Release Notes:", - "updates-found-do-you-want-to-update": "有可供升级的新版本({{version}})。现在进行下载和升级吗?", - "download-update": "下载更新以升级", - "updates-downloaded-about-to-quit-and-install": "下载完成。请退出并安装新版本。", - "quit-and-install": "退出并安装" + "updates-found-do-you-want-to-update": "新版本 {{version}} 可供下载。要下载和安装吗?", + "download-update": "下载安装", + "updates-downloaded-about-to-quit-and-install": "下载完成。请安装新版本。", + "quit-and-install": "安装并重启应用" } } } From 6b68ab6024fcde69feda0bd373bf23e781cfafe0 Mon Sep 17 00:00:00 2001 From: Keith Date: Thu, 28 Nov 2019 12:47:40 +0800 Subject: [PATCH 31/43] feat(neuron-ui): update the url to nervos dao rfc --- packages/neuron-ui/src/utils/const.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/neuron-ui/src/utils/const.ts b/packages/neuron-ui/src/utils/const.ts index 8c41f126af..a2fba54805 100644 --- a/packages/neuron-ui/src/utils/const.ts +++ b/packages/neuron-ui/src/utils/const.ts @@ -19,9 +19,10 @@ export const SHANNON_CKB_RATIO = 1e8 export const MEDIUM_FEE_RATE = 6000 export const WITHDRAW_EPOCHS = 180 -export const RUN_NODE_GUIDE_URL = 'https://docs.nervos.org/references/neuron-wallet-guide.html#1-run-a-ckb-mainnet-node' +export const RUN_NODE_GUIDE_URL = + 'https://www.docs.nervos.org/references/neuron-wallet-guide.html#1-run-a-ckb-mainnet-node' export const NERVOS_DAO_RFC_URL = - 'https://github.com/nervosnetwork/rfcs/tree/master/rfcs/0000-dao-deposit-withdraw/0000-dao-deposit-withdraw.md' + 'https://www.github.com/nervosnetwork/rfcs/blob/master/rfcs/0023-dao-deposit-withdraw/0023-dao-deposit-withdraw.md' export enum ConnectionStatus { Online = 'online', From 3fc81544b3ac959290dbcc14da7e905d242e918e Mon Sep 17 00:00:00 2001 From: Keith Date: Thu, 28 Nov 2019 13:46:25 +0800 Subject: [PATCH 32/43] fix(neuron-ui): remove www from docs.nervos.org --- packages/neuron-ui/src/utils/const.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/neuron-ui/src/utils/const.ts b/packages/neuron-ui/src/utils/const.ts index a2fba54805..3c94a590f6 100644 --- a/packages/neuron-ui/src/utils/const.ts +++ b/packages/neuron-ui/src/utils/const.ts @@ -19,8 +19,7 @@ export const SHANNON_CKB_RATIO = 1e8 export const MEDIUM_FEE_RATE = 6000 export const WITHDRAW_EPOCHS = 180 -export const RUN_NODE_GUIDE_URL = - 'https://www.docs.nervos.org/references/neuron-wallet-guide.html#1-run-a-ckb-mainnet-node' +export const RUN_NODE_GUIDE_URL = 'https://docs.nervos.org/references/neuron-wallet-guide.html#1-run-a-ckb-mainnet-node' export const NERVOS_DAO_RFC_URL = 'https://www.github.com/nervosnetwork/rfcs/blob/master/rfcs/0023-dao-deposit-withdraw/0023-dao-deposit-withdraw.md' From ed557b6c4c0209823da334e3d5e97aa9acd69bd5 Mon Sep 17 00:00:00 2001 From: classicalliu Date: Thu, 28 Nov 2019 15:34:11 +0800 Subject: [PATCH 33/43] fix: the missing txs --- .../src/models/subjects/address-created-subject.ts | 4 ++++ packages/neuron-wallet/src/startup/sync-block-task/task.ts | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/neuron-wallet/src/models/subjects/address-created-subject.ts b/packages/neuron-wallet/src/models/subjects/address-created-subject.ts index 63ff7968cd..1601899534 100644 --- a/packages/neuron-wallet/src/models/subjects/address-created-subject.ts +++ b/packages/neuron-wallet/src/models/subjects/address-created-subject.ts @@ -7,4 +7,8 @@ export default class AddressCreatedSubject { static getSubject() { return this.subject } + + static setSubject(subject: ReplaySubject) { + this.subject = subject + } } diff --git a/packages/neuron-wallet/src/startup/sync-block-task/task.ts b/packages/neuron-wallet/src/startup/sync-block-task/task.ts index 31c0226e0f..0638917d53 100644 --- a/packages/neuron-wallet/src/startup/sync-block-task/task.ts +++ b/packages/neuron-wallet/src/startup/sync-block-task/task.ts @@ -8,11 +8,14 @@ import Utils from 'services/sync/utils' import { switchNetwork as syncSwitchNetwork } from './sync' import { switchNetwork as indexerSwitchNetwork } from './indexer' import { DatabaseInitParams } from './create' +import AddressCreatedSubject from 'models/subjects/address-created-subject' // register to listen address updates registerAddressListener() -const { addressesUsedSubject, databaseInitSubject } = remote.require('./startup/sync-block-task/params') +const { addressesUsedSubject, databaseInitSubject, addressCreatedSubject } = remote.require('./startup/sync-block-task/params') + +AddressCreatedSubject.setSubject(addressCreatedSubject) // pass to task a main process subject AddressesUsedSubject.setSubject(addressesUsedSubject) From 43edefe399062b42383a97a47c81ffb2bb132123 Mon Sep 17 00:00:00 2001 From: classicalliu Date: Thu, 28 Nov 2019 15:52:03 +0800 Subject: [PATCH 34/43] chore: set lock hashes unique --- packages/neuron-wallet/src/services/sync/block-listener.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/neuron-wallet/src/services/sync/block-listener.ts b/packages/neuron-wallet/src/services/sync/block-listener.ts index 5aed6e8d2b..b592ff7088 100644 --- a/packages/neuron-wallet/src/services/sync/block-listener.ts +++ b/packages/neuron-wallet/src/services/sync/block-listener.ts @@ -31,11 +31,12 @@ export default class BlockListener { } public setLockHashes = (lockHashes: string[]) => { - this.lockHashes = lockHashes + const hashes = [...new Set(lockHashes)] + this.lockHashes = hashes if (!this.queue) { return } - this.queue.setLockHashes(lockHashes) + this.queue.setLockHashes(hashes) } public appendLockHashes = (lockHashes: string[]) => { From 9b0a07760bde325f3b82c5d56d999b9f2c8c3dc8 Mon Sep 17 00:00:00 2001 From: classicalliu Date: Thu, 28 Nov 2019 16:29:29 +0800 Subject: [PATCH 35/43] fix: remove bufferTime for address created event The bufferTime will cause the problem that addresses created after tx fetched, so can't check tx correctly, and tx will not save to local db --- .../neuron-wallet/src/listeners/address.ts | 22 +++++-------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/packages/neuron-wallet/src/listeners/address.ts b/packages/neuron-wallet/src/listeners/address.ts index 845105fd7f..a69592d6f9 100644 --- a/packages/neuron-wallet/src/listeners/address.ts +++ b/packages/neuron-wallet/src/listeners/address.ts @@ -1,6 +1,4 @@ import { remote } from 'electron' -import { ReplaySubject } from 'rxjs' -import { bufferTime } from 'rxjs/operators' import AddressesUsedSubject, { AddressesWithURL } from 'models/subjects/addresses-used-subject' import AddressService from 'services/addresses' import { Address } from 'database/address/address-dao' @@ -12,23 +10,13 @@ const addressesUsedSubject = isRenderer ? remote.require('./models/subjects/addresses-used-subject').default.getSubject() : AddressesUsedSubject.getSubject() -// pipe not working directly -const bridge = new ReplaySubject(1000) -addressesUsedSubject.subscribe((params: AddressesWithURL) => { - bridge.next(params) -}) - // update txCount when addresses used export const register = () => { - bridge.pipe(bufferTime(1000)).subscribe(async (addressesList: AddressesWithURL[]) => { - if (addressesList.length === 0) { - return - } - const addresses = addressesList.map(list => list.addresses).reduce((acc, val) => acc.concat(val), []) - const url: string = addressesList[addressesList.length - 1].url - const uniqueAddresses = [...new Set(addresses)] - const addrs = await AddressService.updateTxCountAndBalances(uniqueAddresses, url) - const walletIds: string[] = addrs.map(addr => (addr as Address).walletId).filter((value, idx, a) => a.indexOf(value) === idx) + addressesUsedSubject.subscribe(async (address: AddressesWithURL) => { + const addrs = await AddressService.updateTxCountAndBalances(address.addresses, address.url) + const walletIds: string[] = addrs + .map(addr => (addr as Address).walletId) + .filter((value, idx, a) => a.indexOf(value) === idx) for (const id of walletIds) { const wallet = WalletService.getInstance().get(id) const accountExtendedPublicKey: AccountExtendedPublicKey = wallet.accountExtendedPublicKey() From ee4a842a12330a352b79f2b254cad02d6afc10c3 Mon Sep 17 00:00:00 2001 From: James Chen Date: Thu, 28 Nov 2019 17:52:01 +0900 Subject: [PATCH 36/43] docs: Update changelog for v0.25.2 --- CHANGELOG.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 944a2d5f33..9687d27a0b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,37 @@ +## [0.25.2](https://github.com/nervosnetwork/neuron/compare/v0.25.1...v0.25.2) (2019-11-29) + + +### Bug Fixes + +* remove bufferTime for address created event ([9b0a077](https://github.com/nervosnetwork/neuron/commit/9b0a077)) +* the missing txs ([ed557b6](https://github.com/nervosnetwork/neuron/commit/ed557b6)) +* **neuron-ui:** remove www from docs.nervos.org ([3fc8154](https://github.com/nervosnetwork/neuron/commit/3fc8154)) +* balance not update after sent tx ([65e51dd](https://github.com/nervosnetwork/neuron/commit/65e51dd)) +* **neuron-ui:** show 0 if withdraw rpc returns errors ([b714376](https://github.com/nervosnetwork/neuron/commit/b714376)) +* also clean lock/dao info in renderer process ([a0b2470](https://github.com/nervosnetwork/neuron/commit/a0b2470)) +* clean lock utils info and dao utils info when switch network ([60ec486](https://github.com/nervosnetwork/neuron/commit/60ec486)) +* initialize NetworksService in renderer process ([73f1bf0](https://github.com/nervosnetwork/neuron/commit/73f1bf0)) +* network switch event broadcast twice ([f1b0f72](https://github.com/nervosnetwork/neuron/commit/f1b0f72)) +* pending in windows when network off ([67dcb79](https://github.com/nervosnetwork/neuron/commit/67dcb79)) +* sign witnesses test ([5000edd](https://github.com/nervosnetwork/neuron/commit/5000edd)) + + +### Features + +* **neuron-ui:** update the url to nervos dao rfc ([6b68ab6](https://github.com/nervosnetwork/neuron/commit/6b68ab6)) +* Add API for downloading and installing updates ([b8d24ca](https://github.com/nervosnetwork/neuron/commit/b8d24ca)) +* Add app updater subject and state ([423109d](https://github.com/nervosnetwork/neuron/commit/423109d)) +* Adding check update to settings view ([98fe06c](https://github.com/nervosnetwork/neuron/commit/98fe06c)) +* Connect updater events to UI ([b267321](https://github.com/nervosnetwork/neuron/commit/b267321)) +* Delete unused updater translations ([bcafce8](https://github.com/nervosnetwork/neuron/commit/bcafce8)) +* Different stage status of checking updates ([cd82ca4](https://github.com/nervosnetwork/neuron/commit/cd82ca4)) +* Polish updater i18n translations and UI ([af45f0c](https://github.com/nervosnetwork/neuron/commit/af45f0c)) +* Show release notes when there's update available ([8cf9581](https://github.com/nervosnetwork/neuron/commit/8cf9581)) +* Trigger check updates menu item enabling/disabling ([cd8e5d5](https://github.com/nervosnetwork/neuron/commit/cd8e5d5)) +* **neuron-ui:** add copy address and copy tx hash context menus on the tx detail view. ([7d86454](https://github.com/nervosnetwork/neuron/commit/7d86454)) + + + ## [0.25.1](https://github.com/nervosnetwork/neuron/compare/v0.25.0...v0.25.1) (2019-11-18) From 0f763a574098ca27c992368a592f8a85536160bf Mon Sep 17 00:00:00 2001 From: classicalliu Date: Fri, 29 Nov 2019 02:17:33 +0800 Subject: [PATCH 37/43] fix: Fix the problem that balance not right if switch network from default network Change WalletCreatedSubject from ReplaySubject to Subject, when switch network from default network, WalletCreatedSubject will start subscribe and replay the old created event which happend in default network, so two queue will started and balance will be incorrect --- .../models/subjects/wallet-created-subject.ts | 6 +++--- .../src/startup/sync-block-task/create.ts | 18 ++++++++++++------ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/packages/neuron-wallet/src/models/subjects/wallet-created-subject.ts b/packages/neuron-wallet/src/models/subjects/wallet-created-subject.ts index f7afa4f591..653a951c38 100644 --- a/packages/neuron-wallet/src/models/subjects/wallet-created-subject.ts +++ b/packages/neuron-wallet/src/models/subjects/wallet-created-subject.ts @@ -1,13 +1,13 @@ -import { ReplaySubject } from 'rxjs' +import { Subject } from 'rxjs' export class WalletCreatedSubject { - static subject = new ReplaySubject(1) + static subject = new Subject() static getSubject() { return this.subject } - static setSubject(subject: ReplaySubject) { + static setSubject(subject: Subject) { this.subject = subject } } diff --git a/packages/neuron-wallet/src/startup/sync-block-task/create.ts b/packages/neuron-wallet/src/startup/sync-block-task/create.ts index b9c1935d48..a23072413d 100644 --- a/packages/neuron-wallet/src/startup/sync-block-task/create.ts +++ b/packages/neuron-wallet/src/startup/sync-block-task/create.ts @@ -10,7 +10,7 @@ import DataUpdateSubject from 'models/subjects/data-update' import logger from 'utils/logger' import NodeService from 'services/node' import NetworksService from 'services/networks' -import { distinctUntilChanged } from 'rxjs/operators' +import { distinctUntilChanged, pairwise, startWith } from 'rxjs/operators' import LockUtils from 'models/lock-utils' import DaoUtils from 'models/dao-utils' import NetworkSwitchSubject from 'models/subjects/network-switch-subject' @@ -59,11 +59,17 @@ const networkChange = async (network: NetworkWithID) => { export const databaseInitSubject = new ReplaySubject(1) -NetworkSwitchSubject.getSubject().subscribe(async (network: NetworkWithID | undefined) => { - if (network) { - await networkChange(network) - } -}) +NetworkSwitchSubject + .getSubject() + .pipe( + startWith(undefined), + pairwise() + ) + .subscribe(async ([previousNetwork, network]: (NetworkWithID | undefined)[]) => { + if ((!previousNetwork && network) || (previousNetwork && network && network.id !== previousNetwork.id)) { + await networkChange(network) + } + }) NodeService .getInstance() From 3397239d4db3f090b238c18606cafaf67fc1bd77 Mon Sep 17 00:00:00 2001 From: James Chen Date: Fri, 29 Nov 2019 08:31:31 +0900 Subject: [PATCH 38/43] docs: Update changelog --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9687d27a0b..69eb28eeb7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,12 +3,13 @@ ### Bug Fixes +* also clean lock/dao info in renderer process ([a0b2470](https://github.com/nervosnetwork/neuron/commit/a0b2470)) +* Fix the problem that balance not right if switch network from default network ([0f763a5](https://github.com/nervosnetwork/neuron/commit/0f763a5)) * remove bufferTime for address created event ([9b0a077](https://github.com/nervosnetwork/neuron/commit/9b0a077)) * the missing txs ([ed557b6](https://github.com/nervosnetwork/neuron/commit/ed557b6)) * **neuron-ui:** remove www from docs.nervos.org ([3fc8154](https://github.com/nervosnetwork/neuron/commit/3fc8154)) * balance not update after sent tx ([65e51dd](https://github.com/nervosnetwork/neuron/commit/65e51dd)) * **neuron-ui:** show 0 if withdraw rpc returns errors ([b714376](https://github.com/nervosnetwork/neuron/commit/b714376)) -* also clean lock/dao info in renderer process ([a0b2470](https://github.com/nervosnetwork/neuron/commit/a0b2470)) * clean lock utils info and dao utils info when switch network ([60ec486](https://github.com/nervosnetwork/neuron/commit/60ec486)) * initialize NetworksService in renderer process ([73f1bf0](https://github.com/nervosnetwork/neuron/commit/73f1bf0)) * network switch event broadcast twice ([f1b0f72](https://github.com/nervosnetwork/neuron/commit/f1b0f72)) From 77b31f176d2b6f735a060b33bacc6e956847a1ec Mon Sep 17 00:00:00 2001 From: James Chen Date: Fri, 29 Nov 2019 08:49:02 +0900 Subject: [PATCH 39/43] chore: Build each binary for three platforms with its single job --- azure-pipelines.yml | 55 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 48 insertions(+), 7 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 6f62d0933a..9fd8458d72 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -99,7 +99,8 @@ jobs: - script: yarn test:e2e name: Test - - job: Release + - job: release_mac + displayName: Release macOS condition: eq(variables['build.sourceBranch'], 'refs/heads/master') pool: vmImage: 'macos-10.14' @@ -117,19 +118,59 @@ jobs: displayName: 'Download macOS Signing Certificate' inputs: secureFile: Neuron_mac.p12 + - script: yarn release mac + name: Release + displayName: 'Sign and Release' + env: + CSC_LINK: $(macSiginingCertificate.secureFilePath) + CSC_KEY_PASSWORD: $(macSiginingCertificatePassword) + APPLE_ID: $(appleId) + APPLE_ID_PASSWORD: $(appleIdPassword) + GH_TOKEN: $(ghToken) + + - job: release_linux + displayName: Release Linux + condition: eq(variables['build.sourceBranch'], 'refs/heads/master') + pool: + vmImage: 'ubuntu-16.04' + steps: + - task: NodeTool@0 + inputs: + versionSpec: 12.x + displayName: 'Install Node.js' + - script: | + yarn global add lerna + yarn bootstrap + name: Bootstrap + - script: yarn release linux + name: Release + displayName: 'Sign and Release' + env: + GH_TOKEN: $(ghToken) + + - job: release_win + displayName: Release Windows + condition: eq(variables['build.sourceBranch'], 'refs/heads/master') + pool: + vmImage: 'macos-10.14' + steps: + - task: NodeTool@0 + inputs: + versionSpec: 12.x + displayName: 'Install Node.js' + - script: | + yarn global add lerna + yarn bootstrap + name: Bootstrap - task: DownloadSecureFile@1 name: winSiginingCertificate displayName: 'Download Windows Signing Certificate' inputs: secureFile: Neuron_win.p12 - - script: yarn release + - script: yarn release win name: Release displayName: 'Sign and Release' env: - CSC_LINK: $(macSiginingCertificate.secureFilePath) - CSC_KEY_PASSWORD: $(macSiginingCertificatePassword) WIN_CSC_LINK: $(winSiginingCertificate.secureFilePath) WIN_CSC_KEY_PASSWORD: $(winSiginingCertificatePassword) - APPLE_ID: $(appleId) - APPLE_ID_PASSWORD: $(appleIdPassword) - GH_TOKEN: $(ghToken) + GH_TOKEN: $(ghToken) \ No newline at end of file From 3ad348607471d9a08d913d3891dd3f9805c764af Mon Sep 17 00:00:00 2001 From: James Chen Date: Fri, 29 Nov 2019 09:09:12 +0900 Subject: [PATCH 40/43] chore: Upgrade azure pipelines linux agent to ubuntu 18.04 --- azure-pipelines.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 9fd8458d72..d4ce7e4bd2 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -39,7 +39,7 @@ jobs: - job: Linux pool: - vmImage: 'ubuntu-16.04' + vmImage: 'ubuntu-18.04' strategy: matrix: node_12_x: @@ -132,7 +132,7 @@ jobs: displayName: Release Linux condition: eq(variables['build.sourceBranch'], 'refs/heads/master') pool: - vmImage: 'ubuntu-16.04' + vmImage: 'ubuntu-18.04' steps: - task: NodeTool@0 inputs: From a6e873b9a70baf320251a6b566eb4c81d6f8a801 Mon Sep 17 00:00:00 2001 From: James Chen Date: Fri, 29 Nov 2019 09:46:52 +0900 Subject: [PATCH 41/43] chore: Add stages to azure pipelines --- azure-pipelines.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index d4ce7e4bd2..527f86eb73 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -16,7 +16,10 @@ pr: include: - '*' -jobs: +stages: +- stage: unit_tests + displayName: Unit Tests + jobs: - job: macOS pool: vmImage: 'macos-10.14' @@ -84,6 +87,9 @@ jobs: yarn test name: Test +- stage: e2e_tests + displayName: Integration Tests + dependsOn: [] - job: Integration pool: vmImage: 'macos-10.14' @@ -99,6 +105,9 @@ jobs: - script: yarn test:e2e name: Test +- stage: release + displayName: Release Binaries + jobs: - job: release_mac displayName: Release macOS condition: eq(variables['build.sourceBranch'], 'refs/heads/master') From 9993d79f8ea0923b336e9b99049da8a81ee5986b Mon Sep 17 00:00:00 2001 From: James Chen Date: Fri, 29 Nov 2019 09:49:57 +0900 Subject: [PATCH 42/43] chore: Add missing jobs key for e2e tests stage --- azure-pipelines.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 527f86eb73..91d294d0f5 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -90,6 +90,7 @@ stages: - stage: e2e_tests displayName: Integration Tests dependsOn: [] + jobs: - job: Integration pool: vmImage: 'macos-10.14' From 9ed690813a40f81b3471cca7c825d2a06ae19d15 Mon Sep 17 00:00:00 2001 From: James Chen Date: Fri, 29 Nov 2019 10:04:35 +0900 Subject: [PATCH 43/43] chore: Move build condition of release jobs up to their stage --- azure-pipelines.yml | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 91d294d0f5..e720ce4279 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -20,7 +20,8 @@ stages: - stage: unit_tests displayName: Unit Tests jobs: - - job: macOS + - job: mac + displayName: macOS pool: vmImage: 'macos-10.14' strategy: @@ -40,7 +41,8 @@ stages: - script: CI=true yarn test name: Test - - job: Linux + - job: linux + displayName: Linux pool: vmImage: 'ubuntu-18.04' strategy: @@ -63,7 +65,8 @@ stages: CI=true yarn test name: Test - - job: Windows + - job: win + displayName: Windows pool: vmImage: 'windows-2019' strategy: @@ -92,6 +95,7 @@ stages: dependsOn: [] jobs: - job: Integration + displayName: Integration Tests pool: vmImage: 'macos-10.14' steps: @@ -108,10 +112,10 @@ stages: - stage: release displayName: Release Binaries + condition: eq(variables['build.sourceBranch'], 'refs/heads/master') jobs: - job: release_mac displayName: Release macOS - condition: eq(variables['build.sourceBranch'], 'refs/heads/master') pool: vmImage: 'macos-10.14' steps: @@ -140,7 +144,6 @@ stages: - job: release_linux displayName: Release Linux - condition: eq(variables['build.sourceBranch'], 'refs/heads/master') pool: vmImage: 'ubuntu-18.04' steps: @@ -160,7 +163,6 @@ stages: - job: release_win displayName: Release Windows - condition: eq(variables['build.sourceBranch'], 'refs/heads/master') pool: vmImage: 'macos-10.14' steps: