From 2788a8f38016e39ff2790013d021ae892c571b59 Mon Sep 17 00:00:00 2001 From: Keith Date: Sat, 11 May 2019 16:13:36 +0800 Subject: [PATCH] refactor(neuron-wallet): refactor node service 1. move ckb core into node service; 2. add network switching on active network updating; 3. check active network on initApp; 4. add basic check on the network url, protocol required; --- .../MainContent/actionCreators/networks.ts | 6 ++++ packages/neuron-ui/src/locales/en.json | 3 +- packages/neuron-ui/src/locales/zh.json | 3 +- packages/neuron-ui/src/utils/const.ts | 1 + packages/neuron-wallet/src/core.ts | 13 ------- .../neuron-wallet/src/services/addresses.ts | 4 +-- .../neuron-wallet/src/services/networks.ts | 5 +++ packages/neuron-wallet/src/services/node.ts | 29 +++++++++++----- .../neuron-wallet/src/services/syncBlocks.ts | 12 ++++--- .../src/services/transactions.ts | 34 ++++++++++--------- .../neuron-wallet/src/services/wallets.ts | 10 +++--- packages/neuron-wallet/src/startup/initApp.ts | 14 ++++++-- .../neuron-wallet/src/startup/nodeService.ts | 3 ++ packages/neuron-wallet/tests/address.test.ts | 5 +-- 14 files changed, 88 insertions(+), 54 deletions(-) delete mode 100644 packages/neuron-wallet/src/core.ts create mode 100644 packages/neuron-wallet/src/startup/nodeService.ts diff --git a/packages/neuron-ui/src/containers/MainContent/actionCreators/networks.ts b/packages/neuron-ui/src/containers/MainContent/actionCreators/networks.ts index 531d1a97df..d3cda52dd0 100644 --- a/packages/neuron-ui/src/containers/MainContent/actionCreators/networks.ts +++ b/packages/neuron-ui/src/containers/MainContent/actionCreators/networks.ts @@ -36,6 +36,12 @@ export default { payload: { networks: i18n.t(`messages.${Message.URLIsRequired}`) }, } } + if (!remote.startsWith('http')) { + return { + type: MainActions.ErrorMessage, + payload: { networks: i18n.t(`messages.${Message.ProtocolIsRequired}`) }, + } + } // verification, for now, only name is unique if (id === 'new') { if (networks.some(network => network.name === name)) { diff --git a/packages/neuron-ui/src/locales/en.json b/packages/neuron-ui/src/locales/en.json index a465fcd943..4d0b772a24 100644 --- a/packages/neuron-ui/src/locales/en.json +++ b/packages/neuron-ui/src/locales/en.json @@ -128,7 +128,8 @@ "no-wallet": "No Wallet", "wallet-imported-successfully": "{{name}} imported successfully", "wallet-created-successfully": "{{name}} created successfully", - "wallet-updated-successfully": "{{name}} updated successfully" + "wallet-updated-successfully": "{{name}} updated successfully", + "protocol-is-required": "Protocol is required" } } } diff --git a/packages/neuron-ui/src/locales/zh.json b/packages/neuron-ui/src/locales/zh.json index e13eb05ce9..62c24fa5f8 100644 --- a/packages/neuron-ui/src/locales/zh.json +++ b/packages/neuron-ui/src/locales/zh.json @@ -123,7 +123,8 @@ "no-wallet": "没有钱包", "wallet-imported-successfully": "{{name}} 导入成功", "wallet-created-successfully": "{{name}} 创建成功", - "wallet-updated-successfully": "{{name}} 更新成功" + "wallet-updated-successfully": "{{name}} 更新成功", + "protocol-is-required": "请指定 URL 协议" } } } diff --git a/packages/neuron-ui/src/utils/const.ts b/packages/neuron-ui/src/utils/const.ts index 1210981f5e..3813446dd8 100644 --- a/packages/neuron-ui/src/utils/const.ts +++ b/packages/neuron-ui/src/utils/const.ts @@ -86,6 +86,7 @@ export enum Message { InvalidCapacity = 'invalid-capacity', CapacityNotEnough = 'capacity-is-not-enough', IsUnremovable = 'is-unremovable', + ProtocolIsRequired = 'protocol-is-required', } export enum TransactionType { diff --git a/packages/neuron-wallet/src/core.ts b/packages/neuron-wallet/src/core.ts deleted file mode 100644 index f6d7ab7a59..0000000000 --- a/packages/neuron-wallet/src/core.ts +++ /dev/null @@ -1,13 +0,0 @@ -import Core from '@nervosnetwork/ckb-sdk-core' -import env from './env' - -if (!env.remote) { - throw new Error(`REMOTE is not set in .env`) -} - -const ckbCore = new Core(env.remote) -Object.defineProperty(ckbCore.node, 'name', { - value: 'Default Remote', -}) - -export default ckbCore diff --git a/packages/neuron-wallet/src/services/addresses.ts b/packages/neuron-wallet/src/services/addresses.ts index 5c1ee44bab..4b0968b986 100644 --- a/packages/neuron-wallet/src/services/addresses.ts +++ b/packages/neuron-wallet/src/services/addresses.ts @@ -1,13 +1,13 @@ import TransactionsService from './transactions' -import ckbCore from '../core' import HD from '../keys/hd' import { KeysData } from '../keys/keystore' // TODO: Should use service import WalletStore from '../store/walletStore' +import nodeService from '../startup/nodeService' const { utils: { AddressPrefix, AddressType: Type, AddressBinIdx, pubkeyToAddress }, -} = ckbCore +} = nodeService.core export const MAX_ADDRESS_COUNT = 30 export const SEARCH_RANGE = 20 diff --git a/packages/neuron-wallet/src/services/networks.ts b/packages/neuron-wallet/src/services/networks.ts index b62d4c0e8d..bad302f9de 100644 --- a/packages/neuron-wallet/src/services/networks.ts +++ b/packages/neuron-wallet/src/services/networks.ts @@ -6,6 +6,7 @@ import windowManage from '../utils/windowManage' import { ResponseCode } from '../controllers' import { NetworksMethod } from '../controllers/networks' import { Channel } from '../utils/const' +import nodeService from '../startup/nodeService' export type NetworkID = string export type NetworkName = string @@ -50,6 +51,10 @@ export default class NetworksService extends Store { }) this.on(NetworksKey.Active, async (_, newActiveId) => { + const network = await this.get(newActiveId) + if (network) { + nodeService.setNetwork(network.remote) + } windowManage.broadcast(Channel.Networks, NetworksMethod.ActiveId, { status: ResponseCode.Success, result: newActiveId, diff --git a/packages/neuron-wallet/src/services/node.ts b/packages/neuron-wallet/src/services/node.ts index 1341915244..6427e732ae 100644 --- a/packages/neuron-wallet/src/services/node.ts +++ b/packages/neuron-wallet/src/services/node.ts @@ -1,12 +1,25 @@ +import Core from '@nervosnetwork/ckb-sdk-core' import { interval, Subject } from 'rxjs' import { distinctUntilChanged, flatMap, retry, filter } from 'rxjs/operators' -import ckbCore from '../core' class NodeService { tick = interval(1000) tipNumberSubject = new Subject() + core: Core = new Core('') + + setNetwork = (url: string) => { + if (typeof url !== 'string') { + throw new Error('url should be type of string') + } + if (!url.startsWith('http')) { + throw new Error('Protocol of url should be specified') + } + this.core = new Core(url) + return this.core + } + start = () => { const { unsubscribe } = this.tipNumber() return unsubscribe @@ -15,7 +28,9 @@ class NodeService { tipNumber = () => this.tick .pipe( - flatMap(() => ckbCore.rpc.getTipBlockNumber()), + flatMap(() => { + return this.core.rpc.getTipBlockNumber() + }), // TODO: to determine retry or not retry(3), distinctUntilChanged(), @@ -33,18 +48,16 @@ class NodeService { tipHeader = () => this.tipNumberSubject.pipe( filter(tipNumber => typeof tipNumber !== 'undefined'), - flatMap(ckbCore.rpc.getTipHeader), + flatMap(this.core.rpc.getTipHeader), ) tipBlock = () => this.tipNumberSubject .pipe( filter(tipNumber => typeof tipNumber !== 'undefined'), - flatMap(ckbCore.rpc.getBlockHash), + flatMap(this.core.rpc.getBlockHash), ) - .pipe(flatMap(ckbCore.rpc.getBlock)) + .pipe(flatMap(this.core.rpc.getBlock)) } -const nodeService = new NodeService() - -export default nodeService +export default NodeService diff --git a/packages/neuron-wallet/src/services/syncBlocks.ts b/packages/neuron-wallet/src/services/syncBlocks.ts index 45463d7d10..cf64c90e40 100644 --- a/packages/neuron-wallet/src/services/syncBlocks.ts +++ b/packages/neuron-wallet/src/services/syncBlocks.ts @@ -3,8 +3,10 @@ import { Subject } from 'rxjs' import { Script, OutPoint, Cell } from './cells' import TransactionsService, { Input, Transaction } from './transactions' import OutputEntity from '../entities/Output' -import ckbCore from '../core' import SyncInfoEntity from '../entities/SyncInfo' +import nodeService from '../startup/nodeService' + +const { core } = nodeService export interface BlockHeader { version: number @@ -91,7 +93,7 @@ export default class SyncBlocksService { async tryGetTipBlockNumber(): Promise { try { - const tipBlockNumber = await ckbCore.rpc.getTipBlockNumber() + const tipBlockNumber = await core.rpc.getTipBlockNumber() return parseInt(tipBlockNumber, 10) } catch { return this.tryGetTipBlockNumber() @@ -150,7 +152,7 @@ export default class SyncBlocksService { const blockNumbers = Array.from({ length: size }).map((_a, i) => i + startBlockNumber) const blockHashes: string[] = await Promise.all( blockNumbers.map(async num => { - const hash: string = await ckbCore.rpc.getBlockHash(num.toString()) + const hash: string = await core.rpc.getBlockHash(num.toString()) return hash }), ) @@ -160,7 +162,7 @@ export default class SyncBlocksService { static async getBlocks(blockHashes: string[]): Promise { const blocks = await Promise.all( blockHashes.map(async hash => { - const block = await ckbCore.rpc.getBlock(hash) + const block = await core.rpc.getBlock(hash) return SyncBlocksService.convertBlock(block) }), ) @@ -337,7 +339,7 @@ export default class SyncBlocksService { static convertInput(input: any): Input { return { previousOutput: input.previous_output, - args: input.args.map((arg: Uint8Array) => ckbCore.utils.bytesToHex(arg)), + args: input.args.map((arg: Uint8Array) => core.utils.bytesToHex(arg)), } } diff --git a/packages/neuron-wallet/src/services/transactions.ts b/packages/neuron-wallet/src/services/transactions.ts index 7d331bd671..45c6ac61de 100644 --- a/packages/neuron-wallet/src/services/transactions.ts +++ b/packages/neuron-wallet/src/services/transactions.ts @@ -4,7 +4,9 @@ import InputEntity from '../entities/Input' import OutputEntity from '../entities/Output' import TransactionEntity from '../entities/Transaction' import { getHistoryTransactions } from '../mock_rpc' -import ckbCore from '../core' +import nodeService from '../startup/nodeService' + +const { core } = nodeService export interface Input { previousOutput: OutPoint @@ -147,7 +149,7 @@ export default class TransactionsService { ): Promise> => { const lockHashes: string[] = await Promise.all( params.pubkeys.map(async pubkey => { - const addr = ckbCore.utils.pubkeyToAddress(pubkey) + const addr = core.utils.pubkeyToAddress(pubkey) const lockHash = await TransactionsService.addressToLockHash(addr) return lockHash }), @@ -190,7 +192,7 @@ export default class TransactionsService { // check whether the address has history transactions public static hasTransactions = async (address: string): Promise => { - const blake160 = ckbCore.utils.parseAddress(address, ckbCore.utils.AddressPrefix.Testnet, 'hex') as string + const blake160 = core.utils.parseAddress(address, core.utils.AddressPrefix.Testnet, 'hex') as string const contractInfo = await TransactionsService.contractInfo() const lock: Script = { @@ -426,14 +428,14 @@ export default class TransactionsService { // system contract info public static contractInfo = async () => { - const genesisHash: string = await ckbCore.rpc.getBlockHash('0') - const genesisBlock = await ckbCore.rpc.getBlock(genesisHash) + const genesisHash: string = await core.rpc.getBlockHash('0') + const genesisBlock = await core.rpc.getBlock(genesisHash) const systemScriptTx = genesisBlock.transactions[0] - const blake2b = ckbCore.utils.blake2b(32) + const blake2b = core.utils.blake2b(32) const systemScriptCell = systemScriptTx.outputs[0] const { data } = systemScriptCell if (typeof data === 'string') { - blake2b.update(ckbCore.utils.hexToBytes(data)) + blake2b.update(core.utils.hexToBytes(data)) } else { // if Uint8Array blake2b.update(data) @@ -462,7 +464,7 @@ export default class TransactionsService { const outputs: Cell[] = targetOutputs.map(o => { const { capacity, address } = o - const blake160: string = ckbCore.utils.parseAddress(address, ckbCore.utils.AddressPrefix.Testnet, 'hex') as string + const blake160: string = core.utils.parseAddress(address, core.utils.AddressPrefix.Testnet, 'hex') as string const output: Cell = { capacity, @@ -478,9 +480,9 @@ export default class TransactionsService { // change if (BigInt(capacities) > needCapacities) { - const changeBlake160: string = ckbCore.utils.parseAddress( + const changeBlake160: string = core.utils.parseAddress( changeAddress, - ckbCore.utils.AddressPrefix.Testnet, + core.utils.AddressPrefix.Testnet, 'hex', ) as string @@ -509,7 +511,7 @@ export default class TransactionsService { public static lockScriptToHash = (lock: Script) => { const binaryHash: string = lock!.binaryHash! const args: string[] = lock.args! - const lockHash: string = ckbCore.utils.lockScriptToHash({ + const lockHash: string = core.utils.lockScriptToHash({ binaryHash, args, }) @@ -522,7 +524,7 @@ export default class TransactionsService { } public static addressToLockScript = async (address: string): Promise