diff --git a/packages/neuron-wallet/src/controllers/api.ts b/packages/neuron-wallet/src/controllers/api.ts index 189dc30381..e36054e311 100644 --- a/packages/neuron-wallet/src/controllers/api.ts +++ b/packages/neuron-wallet/src/controllers/api.ts @@ -246,8 +246,8 @@ export default class ApiController { } @MapApiResponse - public static async createNetwork({ name, remote, type = NetworkType.Normal, chain = 'ckb' }: Network) { - return NetworksController.create({ name, remote, type, chain }) + public static async createNetwork({ name, remote, type = NetworkType.Normal, genesisHash = '0x', chain = 'ckb' }: Network) { + return NetworksController.create({ name, remote, type, genesisHash, chain }) } @MapApiResponse diff --git a/packages/neuron-wallet/src/env.ts b/packages/neuron-wallet/src/env.ts index f4a3e0ba2f..e18ef7a3a5 100644 --- a/packages/neuron-wallet/src/env.ts +++ b/packages/neuron-wallet/src/env.ts @@ -1,7 +1,6 @@ import { app as electronApp, remote } from 'electron' import os from 'os' import * as path from 'path' -import { NetworkWithID } from 'types/network' const app = electronApp || (remote && remote.app) || { getPath(aPath: string): string { @@ -35,10 +34,6 @@ interface ENV { fileBasePath: string mainURL: string remote: string - presetNetworks: { - current: 'testnet' - list: NetworkWithID[] - } isTestMode: boolean } const env: ENV = { @@ -46,25 +41,6 @@ const env: ENV = { fileBasePath: path.resolve(app.getPath('userData'), fileBase), mainURL: isDevMode ? 'http://localhost:3000' : `file://${path.join(__dirname, '../dist/neuron-ui/index.html')}`, remote: 'http://localhost:8114', - presetNetworks: { - current: 'testnet', - list: [ - { - id: 'testnet', - name: 'Testnet', - remote: 'http://localhost:8114', - type: 0, - chain: '', - }, - { - id: 'local', - name: 'Local', - remote: 'http://localhost:8114', - type: 1, - chain: '', - }, - ], - }, isTestMode, } diff --git a/packages/neuron-wallet/src/services/networks.ts b/packages/neuron-wallet/src/services/networks.ts index 45a82e58bc..c36d800a90 100644 --- a/packages/neuron-wallet/src/services/networks.ts +++ b/packages/neuron-wallet/src/services/networks.ts @@ -4,16 +4,29 @@ import { BehaviorSubject } from 'rxjs' import { LackOfDefaultNetwork, DefaultNetworkUnremovable } from 'exceptions/network' import Store from 'models/store' -import env from 'env' import { Validate, Required } from 'decorators' import { UsedName, NetworkNotFound, InvalidFormat } from 'exceptions' import { NetworkListSubject, CurrentNetworkIDSubject } from 'models/subjects/networks' -import { NetworkID, NetworkName, NetworkRemote, NetworksKey, NetworkType, Network, NetworkWithID } from 'types/network' +import { MAINNET_GENESIS_HASH, NetworkID, NetworkName, NetworkRemote, NetworksKey, NetworkType, Network, NetworkWithID } from 'types/network' import logger from 'utils/logger' export const networkSwitchSubject = new BehaviorSubject(undefined) +const presetNetworks: { selected: string, networks: NetworkWithID[] } = { + selected: 'mainnet', + networks: [ + { + id: 'mainnet', + name: 'Mainnet', + remote: 'http://localhost:8114', + genesisHash: MAINNET_GENESIS_HASH, + type: NetworkType.Default, + chain: 'ckb', + } + ] +} + export default class NetworksService extends Store { private static instance: NetworksService @@ -25,7 +38,7 @@ export default class NetworksService extends Store { } constructor() { - super('networks', 'index.json', JSON.stringify(env.presetNetworks)) + super('networks', 'index.json', JSON.stringify(presetNetworks)) this.getAll().then(currentNetworkList => { if (currentNetworkList) { @@ -88,7 +101,7 @@ export default class NetworksService extends Store { public getAll = async () => { const list = await this.read(NetworksKey.List) - return list || [] + return list || presetNetworks.networks } @Validate @@ -102,15 +115,11 @@ export default class NetworksService extends Store { if (!Array.isArray(networks)) { throw new InvalidFormat('Networks') } - await this.writeSync(NetworksKey.List, networks) + this.writeSync(NetworksKey.List, networks) } @Validate - public async create( - @Required name: NetworkName, - @Required remote: NetworkRemote, - type: NetworkType = NetworkType.Normal, - ) { + public async create(@Required name: NetworkName, @Required remote: NetworkRemote, type: NetworkType = NetworkType.Normal) { const list = await this.getAll() if (list.some(item => item.name === name)) { throw new UsedName('Network') @@ -122,11 +131,15 @@ export default class NetworksService extends Store { .getBlockchainInfo() .then(info => info.chain) .catch(() => '') + const genesisHash = await core.rpc + .getBlockHash('0x0') + .catch(() => '0x') const newOne = { id: uuid(), name, remote, + genesisHash, type, chain, } @@ -146,11 +159,17 @@ export default class NetworksService extends Store { Object.assign(network, options) if (!options.chain) { const core = new Core(network.remote) + const chain = await core.rpc .getBlockchainInfo() .then(info => info.chain) .catch(() => '') network.chain = chain + + const genesisHash = await core.rpc + .getBlockHash('0x0') + .catch(() => '0x') + network.genesisHash = genesisHash } this.updateAll(list) @@ -183,6 +202,11 @@ export default class NetworksService extends Store { } this.writeSync(NetworksKey.Current, id) + // No need to update the default mainnet + if (network.type === NetworkType.Default) { + return + } + const core = new Core(network.remote) const chain = await core.rpc @@ -190,8 +214,12 @@ export default class NetworksService extends Store { .then(info => info.chain) .catch(() => '') - if (chain && chain !== network.chain) { - this.update(id, { chain }) + const genesisHash = await core.rpc + .getBlockHash('0x0') + .catch(() => '0x') + + if (chain && chain !== network.chain && genesisHash && genesisHash !== network.genesisHash) { + this.update(id, { chain, genesisHash }) } } diff --git a/packages/neuron-wallet/src/types/network.ts b/packages/neuron-wallet/src/types/network.ts index b035d485b6..687a80ebdb 100644 --- a/packages/neuron-wallet/src/types/network.ts +++ b/packages/neuron-wallet/src/types/network.ts @@ -1,22 +1,28 @@ export type NetworkID = string export type NetworkName = string export type NetworkRemote = string +export type NetworkGenesisHash = string + export enum NetworksKey { - List = 'list', - Current = 'current', + List = 'networks', + Current = 'selected', } export enum NetworkType { - Default, + Default, // Preset mainnet node Normal, } +export const MAINNET_GENESIS_HASH = "0x" // TODO: set this when mainnet launches! + export interface Network { name: NetworkName remote: NetworkRemote type: NetworkType + genesisHash: NetworkGenesisHash chain: 'ckb' | 'ckb_testnet' | 'ckb_dev' | string // returned by rpc.getBlockchainInfo } + export interface NetworkWithID extends Network { id: NetworkID } diff --git a/packages/neuron-wallet/tests/services/networks.test.ts b/packages/neuron-wallet/tests/services/networks.test.ts index 91edf45b04..aebaa2a560 100644 --- a/packages/neuron-wallet/tests/services/networks.test.ts +++ b/packages/neuron-wallet/tests/services/networks.test.ts @@ -1,6 +1,5 @@ import NetworksService from '../../src/services/networks' import { NetworkWithID } from '../../src/types/network' -import env from '../../src/env' import i18n from '../../src/utils/i18n' const ERROR_MESSAGE = { @@ -9,23 +8,19 @@ const ERROR_MESSAGE = { NETWORK_ID_NOT_FOUND: `messages.network-not-found`, } -const { - presetNetworks: { current, list }, -} = env -const [testnetNetwork, localNetwork] = list - describe(`Unit tests of networks service`, () => { const newNetwork: NetworkWithID = { name: `new network`, - remote: `http://new-network.localhost.com`, + remote: `http://localhost:8114`, type: 0, + genesisHash: '', id: '', chain: '', } const newNetworkWithDefaultTypeOf1 = { name: `new network with the default type of 1`, - remote: `http://test.localhost.com`, + remote: `http://localhost:8114`, id: '', } @@ -52,7 +47,8 @@ describe(`Unit tests of networks service`, () => { it(`has preset networks`, async () => { const networks = await service.getAll() - expect(networks).toEqual(list) + expect(networks.length).toBe(1) + expect(networks[0].id).toEqual('mainnet') }) it(`get the default network`, async () => { @@ -60,20 +56,9 @@ describe(`Unit tests of networks service`, () => { expect(network && network.type).toBe(0) }) - it(`testnet should be type of default network`, async () => { - const defaultNetwork = await service.defaultOne() - expect(defaultNetwork).toEqual(testnetNetwork) - }) - - it(`testnet should be the current one by default`, async () => { + it(`mainnet should be the current one by default`, async () => { const currentNetworkID = await service.getCurrentID() - expect(currentNetworkID).toBe(current) - expect(currentNetworkID).toBe(testnetNetwork.id) - }) - - it(`get network by id ${current}`, async () => { - const currentNetwork = await service.get(current) - expect(currentNetwork).toEqual(list.find(network => network.id === current)) + expect(currentNetworkID).toBe('mainnet') }) it(`getting a non-exsiting network should return null`, async () => { @@ -94,35 +79,31 @@ describe(`Unit tests of networks service`, () => { expect(res.type).toBe(1) }) - it(`update the local networks's name`, async () => { - const name = `new local network name` - await service.update(localNetwork.id, { name }) - const network = await service.get(localNetwork.id) - expect(network && network.name).toBe(name) - }) - - it(`update the local network address`, async () => { - const addr = `http://updated-address.com` - await service.update(localNetwork.id, { remote: addr }) - const network = await service.get(localNetwork.id) - expect(network && network.remote).toBe(addr) + it(`update the networks's name`, async () => { + const network = await service.create(newNetworkWithDefaultTypeOf1.name, newNetworkWithDefaultTypeOf1.remote) + const name = `new network name` + await service.update(network.id, { name }) + const updated = await service.get(network.id) + expect(updated && updated.name).toBe(name) }) - it(`update the local network type to 1`, async () => { - const type = 1 - await service.update(localNetwork.id, { type }) - const network = await service.get(localNetwork.id) - expect(network && network.type).toBe(type) + it(`update the network' address`, async () => { + const network = await service.create(newNetworkWithDefaultTypeOf1.name, newNetworkWithDefaultTypeOf1.remote) + const address = `http://localhost:8115` + await service.update(network.id, { remote: address }) + const updated = await service.get(network.id) + expect(updated && updated.remote).toBe(address) }) - it(`set the local network to be the current one`, async () => { - await service.activate(localNetwork.id) + it(`set the network to be the current one`, async () => { + const network = await service.create(newNetworkWithDefaultTypeOf1.name, newNetworkWithDefaultTypeOf1.remote) + await service.activate(network.id) const currentNetworkID = await service.getCurrentID() - expect(currentNetworkID).toBe(localNetwork.id) + expect(currentNetworkID).toBe(network.id) }) it(`delete an inactive network`, async () => { - const inactiveNetwork = localNetwork + const inactiveNetwork = await service.create(newNetworkWithDefaultTypeOf1.name, newNetworkWithDefaultTypeOf1.remote) const prevCurrentID = (await service.getCurrentID()) || '' const prevNetworks = await service.getAll() await service.delete(inactiveNetwork.id) @@ -134,12 +115,13 @@ describe(`Unit tests of networks service`, () => { expect(currentID).toBe(prevCurrentID) }) - it(`activate the local network and delete it, the current networks should switch to the testnet network`, async () => { - await service.activate(localNetwork.id) + it(`activate a network and delete it, the current networks should switch to the default network`, async () => { + const network = await service.create(newNetworkWithDefaultTypeOf1.name, newNetworkWithDefaultTypeOf1.remote) + await service.activate(network.id) const prevCurrentID = await service.getCurrentID() const prevNetworks = await service.getAll() - expect(prevCurrentID).toBe(localNetwork.id) - expect(prevNetworks.map(n => n.id)).toEqual(list.map(n => n.id)) + expect(prevCurrentID).toBe(network.id) + expect(prevNetworks.map(n => n.id)).toEqual(['Mainnet', network.id]) await service.delete(prevCurrentID || '') const currentNetworks = await service.getAll() expect(currentNetworks.map(n => n.id)).toEqual(prevNetworks.filter(n => n.id !== prevCurrentID).map(n => n.id)) @@ -148,16 +130,16 @@ describe(`Unit tests of networks service`, () => { service.getCurrentID().then(cID => resolve(cID)) }, 500) }) - expect(currentID).toBe(testnetNetwork.id) + expect(currentID).toBe('mainnet') }) it(`reset the netowrks`, async () => { await service.create(newNetwork.name, newNetwork.remote) const newNetworkList = await service.getAll() - expect(newNetworkList.length).toBe(list.length + 1) + expect(newNetworkList.length).toBe(2) service.clear() const networks = await service.getAll() - expect(networks.length).toBe(list.length) + expect(networks.length).toBe(1) }) }) @@ -192,8 +174,8 @@ describe(`Unit tests of networks service`, () => { }) describe(`validation on network existence`, () => { - it(`create network with existing name of ${list[0].name}`, () => { - expect(service.create(list[0].name, list[0].remote)).rejects.toThrowError(i18n.t(ERROR_MESSAGE.NAME_USED)) + it(`create network with existing name of Mainnet`, () => { + expect(service.create('Mainnet', 'http://localhost:8114')).rejects.toThrowError(i18n.t(ERROR_MESSAGE.NAME_USED)) }) it(`update network which is not existing`, () => {