From ab7d0003d3120ce5470799c57ee41799afbac8e4 Mon Sep 17 00:00:00 2001 From: Voyager Bot Date: Thu, 1 Nov 2018 15:05:33 +0100 Subject: [PATCH 01/42] change init local testnet to latest SDK --- tasks/build/local/build.js | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/tasks/build/local/build.js b/tasks/build/local/build.js index 378ab0ef3b..c0ee3a5a77 100644 --- a/tasks/build/local/build.js +++ b/tasks/build/local/build.js @@ -87,20 +87,15 @@ async function moveFiles(options, environment) { function init(options, environment) { return new Promise(async (resolve, reject) => { - if (options.overwrite && fs.existsSync(homeDir + `/.gaiad-testnet`)) { - let out = await makeExec(`rm -r ${homeDir}/.gaiad-testnet`) - out && console.log(out) - } - let command = `builds/Gaia/${environment}/gaiad init --home ${homeDir}/.gaiad-testnet --home-client builds/testnets/local-testnet/lcd --name local` if (options.overwrite) { - command += ` -o --owk` + command += ` -o --overwrite-key` } console.log(`$ ` + command) const localnodeProcess = spawn(command, { shell: true }) - localnodeProcess.stdout.on(`data`, resolve) localnodeProcess.stdin.write(`${options.password}\n`) - localnodeProcess.stderr.on(`data`, reject) - localnodeProcess.once(`exit`, reject) + localnodeProcess.once(`exit`, code => { + code === 0 ? resolve() : reject() + }) }) } From 4ed2629062f5e90fc767946268a60c2db8bd8dd7 Mon Sep 17 00:00:00 2001 From: Voyager Bot Date: Thu, 1 Nov 2018 15:30:27 +0100 Subject: [PATCH 02/42] working initialising --- app/src/main/index.js | 62 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/app/src/main/index.js b/app/src/main/index.js index 671d30e9c8..7999fbb101 100644 --- a/app/src/main/index.js +++ b/app/src/main/index.js @@ -8,6 +8,7 @@ let childProcess = require(`child_process`) let semver = require(`semver`) let Raven = require(`raven`) let axios = require(`axios`) +const userHome = require(`user-home`) let pkg = require(`../../../package.json`) let addMenu = require(`./menu.js`) @@ -582,6 +583,63 @@ const checkGaiaCompatibility = async gaiacliVersionPath => { } } +const initLCD = async lcdHome => { + log(`initialising the LCD config dir`) + await new Promise((resolve, reject) => { + const NODE_BINARY_NAME = WIN ? `gaiad.exe` : `gaiad` + const tempNodeDir = join(lcdHome, `.temp_node_home`) + + const child = startProcess(NODE_BINARY_NAME, [ + `init`, + `--home`, + tempNodeDir, + `--home-client`, + lcdHome, + `--name`, + `default` + ]) + + child.stdin.write(`1234567890\n`) + + child.on(`exit`, code => { + if (code === 0) { + resolve() + } else { + reject() + } + + fs.remove(tempNodeDir) + }) + }) + + log(`deleting forced default account`) + // initLCD always needs to create one key, we don't want to confuse + // the user with this key, so we throw it away + await deleteKey(`default`, `1234567890`, lcdHome) +} + +const deleteKey = (name, password, lcdHome) => { + return new Promise((resolve, reject) => { + const child = startProcess(LCD_BINARY_NAME, [ + `keys`, + `delete`, + name, + `--home`, + lcdHome + ]) + + child.stdin.write(`${password}\n`) + + child.on(`exit`, code => { + if (code === 0) { + resolve() + } else { + reject() + } + }) + }) +} + async function main() { // we only enable error collection after users opted in Raven.config(``, { captureUnhandledRejections: false }).install() @@ -642,6 +700,10 @@ async function main() { fs.writeFileSync(appVersionPath, pkg.version) } + if (!fs.existsSync(lcdHome)) { + await initLCD(lcdHome) + } + await checkGaiaCompatibility(gaiacliVersionPath) // read chainId from genesis.json From a5110ee677123bd373f013a6b3d34d9fa7853d7a Mon Sep 17 00:00:00 2001 From: David Braun Date: Thu, 1 Nov 2018 23:21:51 -0400 Subject: [PATCH 03/42] WIP: Implement HTTPS support for Gaia Lite. Blocked by https://github.com/cosmos/cosmos-sdk/issues/2664 --- app/src/main/index.js | 109 ++++++++++++++--------- app/src/renderer/connectors/lcdClient.js | 9 +- app/src/renderer/connectors/node.js | 33 ++++++- 3 files changed, 104 insertions(+), 47 deletions(-) diff --git a/app/src/main/index.js b/app/src/main/index.js index 671d30e9c8..ca00c2604f 100644 --- a/app/src/main/index.js +++ b/app/src/main/index.js @@ -3,10 +3,12 @@ const assert = require(`assert`) let { app, BrowserWindow, ipcMain } = require(`electron`) let fs = require(`fs-extra`) +const https = require(`https`) let { join, relative } = require(`path`) let childProcess = require(`child_process`) let semver = require(`semver`) let Raven = require(`raven`) +const readline = require(`readline`) let axios = require(`axios`) let pkg = require(`../../../package.json`) @@ -203,6 +205,17 @@ function startProcess(name, args, env) { } child.stdout.on(`data`, data => !shuttingDown && log(`${name}: ${data}`)) child.stderr.on(`data`, data => !shuttingDown && log(`${name}: ${data}`)) + + // Make stdout more useful by emitting a line at a time. + readline.createInterface({ input: child.stdout }).on(`line`, line => { + child.stdout.emit(`line`, line) + }) + + // Make stderr more useful by emitting a line at a time. + readline.createInterface({ input: child.stderr }).on(`line`, line => { + child.stderr.emit(`line`, line) + }) + child.on( `exit`, code => !shuttingDown && log(`${name} exited with code ${code}`) @@ -256,7 +269,6 @@ async function startLCD(home, nodeURL) { log(`startLCD`, home) let child = startProcess(LCD_BINARY_NAME, [ `rest-server`, - `--insecure`, `--laddr`, `tcp://localhost:${LCD_PORT}`, `--home`, @@ -270,7 +282,12 @@ async function startLCD(home, nodeURL) { ]) logProcess(child, join(home, `lcd.log`)) - child.stderr.on(`data`, error => { + child.stdout.once(`line`, async line => { + const certPath = /\(cert: "(.+?)"/.exec(line)[1] + resolve({ ca: fs.readFileSync(certPath, `utf8`), process: child }) + }) + + child.stderr.on(`line`, error => { let errorMessage = `The gaiacli rest-server (LCD) experienced an error:\n${error.toString( `utf8` )}`.substr(0, 1000) @@ -278,19 +295,6 @@ async function startLCD(home, nodeURL) { ? handleCrash(errorMessage) // if fails later : reject(errorMessage) // if fails immediatly }) - - // poll until LCD is started - let client = LcdClient(axios, `http://localhost:${LCD_PORT}`) - while (true) { - try { - await client.keys.values() - break // request succeeded - } catch (err) { - await sleep(1000) - } - } - lcdStarted = true - resolve(child) }) } @@ -434,20 +438,9 @@ Object.entries(eventHandlers).forEach(([event, handler]) => { ipcMain.on(event, handler) }) -// query version of the used SDK via LCD -async function getNodeVersion(nodeURL) { - let versionURL = `${nodeURL}/node_version` - let nodeVersion = await axios - .get(versionURL, { timeout: 3000 }) - .then(res => res.data) - .then(fullversion => fullversion.split(`-`)[0]) - - return nodeVersion -} - // test an actual node version against the expected one and flag the node if incompatible -async function testNodeVersion(nodeURL, expectedGaiaVersion) { - let nodeVersion = await getNodeVersion(nodeURL) +async function testNodeVersion(client, expectedGaiaVersion) { + let nodeVersion = (await client.nodeVersion()).split(`-`)[0] let semverDiff = semver.diff(nodeVersion, expectedGaiaVersion) if (semverDiff === `patch` || semverDiff === null) { return { compatible: true, nodeVersion } @@ -456,20 +449,48 @@ async function testNodeVersion(nodeURL, expectedGaiaVersion) { return { compatible: false, nodeVersion } } +// Proxy requests to Axios through the main process because we need +// Node.js in order to support self-signed TLS certificates. +const AxiosListener = axios => { + return async (event, id, options) => { + let response + + try { + response = { + value: await axios(options) + } + } catch (exception) { + response = { exception } + } + + event.sender.send(`Axios/${id}`, response) + } +} + // check if our node is reachable and the SDK version is compatible with the local one async function pickAndConnect() { let nodeURL = config.node_lcd connecting = true + let gaiaLite + try { - await connect(nodeURL) + gaiaLite = await connect(nodeURL) } catch (err) { handleCrash(err) return } + const axiosInstance = axios.create({ + httpsAgent: new https.Agent({ ca: gaiaLite.ca }) + }) + let compatible, nodeVersion try { - const out = await testNodeVersion(config.node_lcd, expectedGaiaCliVersion) + const out = await testNodeVersion( + LcdClient(axiosInstance, config.node_lcd), + expectedGaiaCliVersion + ) + compatible = out.compatible nodeVersion = out.nodeVersion } catch (err) { @@ -491,27 +512,27 @@ async function pickAndConnect() { return } - return nodeURL + ipcMain.removeAllListeners(`Axios`) + ipcMain.on(`Axios`, AxiosListener(axiosInstance)) } async function connect() { log(`starting gaia rest server with nodeURL ${config.node_lcd}`) - try { - lcdProcess = await startLCD(lcdHome, config.node_rpc) - log(`gaia rest server ready`) - - afterBooted(() => { - log(`Signaling connected node`) - mainWindow.webContents.send(`connected`, { - lcdURL: config.node_lcd, - rpcURL: config.node_rpc - }) + + const gaiaLite = await startLCD(lcdHome, config.node_rpc) + lcdProcess = gaiaLite.process + log(`gaia rest server ready`) + + afterBooted(() => { + log(`Signaling connected node`) + mainWindow.webContents.send(`connected`, { + lcdURL: config.node_lcd, + rpcURL: config.node_rpc }) - } catch (err) { - throw err - } + }) connecting = false + return gaiaLite } async function reconnect() { diff --git a/app/src/renderer/connectors/lcdClient.js b/app/src/renderer/connectors/lcdClient.js index 4da1ff3556..f1016c0a56 100644 --- a/app/src/renderer/connectors/lcdClient.js +++ b/app/src/renderer/connectors/lcdClient.js @@ -3,7 +3,12 @@ const Client = (axios, localLcdURL, remoteLcdURL) => { async function request(method, path, data, useRemote) { const url = useRemote ? remoteLcdURL : localLcdURL - return (await axios[method.toLowerCase()](url + path, data)).data + + return (await axios({ + method: method.toLowerCase(), + url: url + path, + data + })).data } // returns an async function which makes a request for the given @@ -64,6 +69,8 @@ const Client = (axios, localLcdURL, remoteLcdURL) => { return keys.values().then(() => true, () => false) }, + nodeVersion: req(`GET`, `/node_version`), + // tx postTx: req(`POST`, `/tx`), diff --git a/app/src/renderer/connectors/node.js b/app/src/renderer/connectors/node.js index 6c6a05a2a3..a523f704ed 100644 --- a/app/src/renderer/connectors/node.js +++ b/app/src/renderer/connectors/node.js @@ -1,11 +1,40 @@ "use strict" -const axios = require(`axios`) +const { ipcRenderer } = require(`electron`) const RestClient = require(`./lcdClient.js`) const mockedRestClient = require(`./lcdClientMock.js`) const RpcWrapper = require(`./rpcWrapper.js`) const MockedRpcWrapper = require(`./rpcWrapperMock.js`) +// Proxy requests to Axios through the main process because we need +// Node.js in order to support self-signed TLS certificates. +const AxiosProxy = () => { + let requestCounter = 0 + + return options => + new Promise((resolve, reject) => { + requestCounter++ + + if (requestCounter === Number.MAX_SAFE_INTEGER) { + requestCounter = 0 + } + + const channel = `Axios/${requestCounter}` + + ipcRenderer.once(channel, (event, { exception, value }) => { + ipcRenderer.removeAllListeners(channel) + + if (exception) { + reject(exception) + } else { + resolve(value) + } + }) + + ipcRenderer.send(`Axios`, requestCounter, options) + }) +} + module.exports = function(localLcdURL, remoteLcdURL, mocked = false) { let connector = { mocked, @@ -16,7 +45,7 @@ module.exports = function(localLcdURL, remoteLcdURL, mocked = false) { console.log(`Setting connector to state:` + (mocked ? `mocked` : `live`)) let newRestClient = mocked ? mockedRestClient - : new RestClient(axios, localLcdURL, remoteLcdURL) + : new RestClient(AxiosProxy(), localLcdURL, remoteLcdURL) let newRpcClient = mocked ? MockedRpcWrapper(connector) : RpcWrapper(connector) From ccf25dd9c632b6fb072ca06616c33984427e9a67 Mon Sep 17 00:00:00 2001 From: Voyager Bot Date: Mon, 5 Nov 2018 11:57:38 +0100 Subject: [PATCH 04/42] using working commit --- tasks/build/Gaia/COMMIT.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasks/build/Gaia/COMMIT.sh b/tasks/build/Gaia/COMMIT.sh index a81aa05502..dc309588ee 100755 --- a/tasks/build/Gaia/COMMIT.sh +++ b/tasks/build/Gaia/COMMIT.sh @@ -2,5 +2,5 @@ # This is the commit of the SDK version to use for building Gaia. We use an # explicit hash instead of a tag so we don't have to trust GitHub. -export COMMIT=ce23ad41ce7bc53494c80a2d73fdc1c9e39f7ec7 +export COMMIT=9559d171198e1fd36093ce8565b152697290783c From 07b457c955e03ec13aa9202f77c0ed74b2bb2a93 Mon Sep 17 00:00:00 2001 From: Voyager Bot Date: Mon, 5 Nov 2018 12:49:03 +0100 Subject: [PATCH 05/42] updated to latest --- tasks/build/Gaia/COMMIT.sh | 2 +- tasks/build/local/build.js | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/tasks/build/Gaia/COMMIT.sh b/tasks/build/Gaia/COMMIT.sh index dc309588ee..8721d0b6c0 100755 --- a/tasks/build/Gaia/COMMIT.sh +++ b/tasks/build/Gaia/COMMIT.sh @@ -2,5 +2,5 @@ # This is the commit of the SDK version to use for building Gaia. We use an # explicit hash instead of a tag so we don't have to trust GitHub. -export COMMIT=9559d171198e1fd36093ce8565b152697290783c +export COMMIT=10e8e0312eeed9a450e7c49f4337427b9268b459 diff --git a/tasks/build/local/build.js b/tasks/build/local/build.js index c0ee3a5a77..7e8c804a14 100644 --- a/tasks/build/local/build.js +++ b/tasks/build/local/build.js @@ -87,13 +87,14 @@ async function moveFiles(options, environment) { function init(options, environment) { return new Promise(async (resolve, reject) => { - let command = `builds/Gaia/${environment}/gaiad init --home ${homeDir}/.gaiad-testnet --home-client builds/testnets/local-testnet/lcd --name local` + let command = `builds/Gaia/${environment}/gaiad init --home ${homeDir}/.gaiad-testnet --moniker local` if (options.overwrite) { - command += ` -o --overwrite-key` + command += ` -o` } console.log(`$ ` + command) const localnodeProcess = spawn(command, { shell: true }) localnodeProcess.stdin.write(`${options.password}\n`) + localnodeProcess.stderr.pipe(process.stderr) localnodeProcess.once(`exit`, code => { code === 0 ? resolve() : reject() }) From 4a3d5c9a34ec1737a4e647b00810b00a5d011a98 Mon Sep 17 00:00:00 2001 From: Voyager Bot Date: Mon, 5 Nov 2018 15:30:07 +0100 Subject: [PATCH 06/42] working node start --- tasks/build/local/build.js | 74 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 2 deletions(-) diff --git a/tasks/build/local/build.js b/tasks/build/local/build.js index 7e8c804a14..333ec56495 100644 --- a/tasks/build/local/build.js +++ b/tasks/build/local/build.js @@ -33,6 +33,8 @@ cli(optionsSpecification, async options => { } await init(options, environment) + const { address } = await createKey(options, environment) + await initGenesis(options, environment, address) await moveFiles(options, environment) console.log(`\n 🎉 SUCCESS 🎉\n`) console.log( @@ -87,16 +89,84 @@ async function moveFiles(options, environment) { function init(options, environment) { return new Promise(async (resolve, reject) => { - let command = `builds/Gaia/${environment}/gaiad init --home ${homeDir}/.gaiad-testnet --moniker local` + let command = `builds/Gaia/${environment}/gaiad init --home ${homeDir}/.gaiad-testnet --moniker local --chain-id local-testnet` if (options.overwrite) { command += ` -o` } console.log(`$ ` + command) const localnodeProcess = spawn(command, { shell: true }) localnodeProcess.stdin.write(`${options.password}\n`) - localnodeProcess.stderr.pipe(process.stderr) + // localnodeProcess.stderr.pipe(process.stderr) localnodeProcess.once(`exit`, code => { code === 0 ? resolve() : reject() }) }) } + +function createKey(options, environment) { + return new Promise(async (resolve, reject) => { + let command = `builds/Gaia/${environment}/gaiacli keys add local --home ./builds/testnets/local-testnet/lcd -o json` + console.log(`$ ` + command) + const child = spawn(command, { shell: true }) + + child.stdin.write(`${options.password}\n`) + child.stdin.write(`${options.password}\n`) + + child.stdout.once(`data`, data => { + resolve(JSON.parse(data)) + }) + + child.once(`exit`, code => { + code !== 0 && reject() + }) + }) +} + +async function initGenesis(options, environment, address) { + const genesisLocation = path.join( + homeDir, + `.gaiad-testnet/config`, + `genesis.json` + ) + let genesis = fs.readJSONSync(genesisLocation) + genesis.app_state.accounts = [ + { + address, + coins: [ + { + denom: `steak`, + amount: `150` + }, + { + denom: `localcoin`, + amount: `1000` + } + ] + } + ] + fs.writeJSONSync(genesisLocation, genesis) + + await new Promise((resolve, reject) => { + const child = spawn(`builds/Gaia/${environment}/gaiad`, [ + `gentx`, + `--name`, + `local`, + `--home`, + path.join(homeDir, `.gaiad-testnet`), + `--home-client`, + `./builds/testnets/local-testnet/lcd` + ]) + child.stderr.pipe(process.stderr) + child.stdin.write(`${options.password}\n`) + child.once(`exit`, code => { + code === 0 ? resolve() : reject() + }) + }) + + exec( + `builds/Gaia/${environment}/gaiad collect-gentxs --home ${path.join( + homeDir, + `.gaiad-testnet` + )}` + ) +} From c44752b6ccb59f2b356ee8704131ab3da3f5fe76 Mon Sep 17 00:00:00 2001 From: Voyager Bot Date: Mon, 5 Nov 2018 16:20:11 +0100 Subject: [PATCH 07/42] working https --- app/src/renderer/connectors/lcdClient.js | 16 +++++++++++++--- app/src/renderer/connectors/node.js | 9 +++++++++ app/src/renderer/main.js | 3 ++- app/src/renderer/vuex/modules/delegation.js | 9 ++++++++- tasks/testnet.js | 2 +- 5 files changed, 33 insertions(+), 6 deletions(-) diff --git a/app/src/renderer/connectors/lcdClient.js b/app/src/renderer/connectors/lcdClient.js index f1016c0a56..b2485a43de 100644 --- a/app/src/renderer/connectors/lcdClient.js +++ b/app/src/renderer/connectors/lcdClient.js @@ -102,8 +102,18 @@ const Client = (axios, localLcdURL, remoteLcdURL) => { /* ============ STAKE ============ */ // Get all delegations information from a delegator - getDelegator: function(addr) { - return req(`GET`, `/stake/delegators/${addr}`, true)() + getDelegations: function(addr) { + return req(`GET`, `/stake/delegators/${addr}/delegations`, true)() + }, + getUndelegations: function(addr) { + return req( + `GET`, + `/stake/delegators/${addr}/unbonding_delegations`, + true + )() + }, + getRedelegations: function(addr) { + return req(`GET`, `/stake/delegators/${addr}/redelegations`, true)() }, // Get all txs from a delegator getDelegatorTxs: function(addr, types) { @@ -161,7 +171,7 @@ const Client = (axios, localLcdURL, remoteLcdURL) => { /* ============ Slashing ============ */ queryValidatorSigningInfo: function(pubKey) { - return req(`GET`, `/slashing/signing_info/${pubKey}`, true)() + return req(`GET`, `/slashing/validators/${pubKey}/signing_info`, true)() }, /* ============ Governance ============ */ diff --git a/app/src/renderer/connectors/node.js b/app/src/renderer/connectors/node.js index a523f704ed..e5f322ad50 100644 --- a/app/src/renderer/connectors/node.js +++ b/app/src/renderer/connectors/node.js @@ -21,12 +21,21 @@ const AxiosProxy = () => { const channel = `Axios/${requestCounter}` + console.log(`Request ${options.method.toUpperCase()} ${options.url}`) ipcRenderer.once(channel, (event, { exception, value }) => { ipcRenderer.removeAllListeners(channel) if (exception) { + console.error( + `Request ${options.method.toUpperCase()} ${options.url} failed`, + exception + ) reject(exception) } else { + console.log( + `Request ${options.method.toUpperCase()} ${options.url} successful`, + value.data + ) resolve(value) } }) diff --git a/app/src/renderer/main.js b/app/src/renderer/main.js index ab2247311d..bedf3d5893 100644 --- a/app/src/renderer/main.js +++ b/app/src/renderer/main.js @@ -67,7 +67,8 @@ Vue.directive(`focus`, { async function main() { let lcdPort = getQueryParameter(`lcd_port`) - let localLcdURL = `http://localhost:${lcdPort}` + // TODO get from process.env + let localLcdURL = `https://localhost:${lcdPort}` console.log(`Expecting lcd-server on port: ` + lcdPort) node = Node(localLcdURL, config.node_lcd, config.mocked) diff --git a/app/src/renderer/vuex/modules/delegation.js b/app/src/renderer/vuex/modules/delegation.js index b921101107..826c98a196 100644 --- a/app/src/renderer/vuex/modules/delegation.js +++ b/app/src/renderer/vuex/modules/delegation.js @@ -69,7 +69,14 @@ export default ({ node }) => { let address = rootState.user.address candidates = candidates || (await dispatch(`getDelegates`)) - let delegator = await node.getDelegator(address) + let delegations = await node.getDelegations(address) + let unbonding_delegations = await node.getUndelegations(address) + let redelegations = await node.getRedelegations(address) + let delegator = { + delegations, + unbonding_delegations, + redelegations + } // the request runs that long, that the user might sign out and back in again // the result is, that the new users state gets updated by the old users request // here we check if the user is still the same diff --git a/tasks/testnet.js b/tasks/testnet.js index d18d8f01aa..34b0a293b9 100644 --- a/tasks/testnet.js +++ b/tasks/testnet.js @@ -12,7 +12,7 @@ async function main() { if (network === `local-testnet`) { Object.assign(process.env, { - LCD_URL: `http://localhost:9070`, + LCD_URL: `https://localhost:9070`, RPC_URL: `http://localhost:26657` }) startLocalNode() From 8d1e8c7e236160eec05bffc1a0f5372b8b6138fe Mon Sep 17 00:00:00 2001 From: Voyager Bot Date: Mon, 5 Nov 2018 16:35:51 +0100 Subject: [PATCH 08/42] remove decimals fix --- app/src/renderer/connectors/lcdClientMock.js | 6 ------ app/src/renderer/vuex/modules/delegates.js | 10 ++++------ app/src/renderer/vuex/modules/delegation.js | 2 +- .../specs/__snapshots__/lcdClientMock.spec.js.snap | 2 +- test/unit/specs/lcdClientMock.spec.js | 6 +++--- 5 files changed, 9 insertions(+), 17 deletions(-) diff --git a/app/src/renderer/connectors/lcdClientMock.js b/app/src/renderer/connectors/lcdClientMock.js index 50ec0cf2a1..ba09312cce 100644 --- a/app/src/renderer/connectors/lcdClientMock.js +++ b/app/src/renderer/connectors/lcdClientMock.js @@ -492,9 +492,6 @@ module.exports = { delegator.delegations.push(delegation) } - // TODO remove after sdk.Dec parsing is fixed - amount = amount * 10000000000 - let shares = parseInt(delegation.shares) delegation.shares = (shares + amount).toString() let candidate = state.candidates.find( @@ -544,9 +541,6 @@ module.exports = { return results } - // TODO remove after sdk.Dec parsing is fixed - amount = amount * 10000000000 - let shares = parseInt(delegation.shares) delegation.shares = (+shares - amount).toString() diff --git a/app/src/renderer/vuex/modules/delegates.js b/app/src/renderer/vuex/modules/delegates.js index a1596d43b3..328e78ddc6 100644 --- a/app/src/renderer/vuex/modules/delegates.js +++ b/app/src/renderer/vuex/modules/delegates.js @@ -77,12 +77,10 @@ export default ({ node }) => { // the tokens and shares are currently served in a weird format that is a amino representation of a float value validators = validators.map(validator => { return Object.assign(JSON.parse(JSON.stringify(validator)), { - tokens: ratToBigNumber(validator.tokens) - .div(10000000000) - .toString(), - delegator_shares: ratToBigNumber(validator.delegator_shares) - .div(10000000000) - .toString() + tokens: ratToBigNumber(validator.tokens).toString(), + delegator_shares: ratToBigNumber( + validator.delegator_shares + ).toString() }) }) diff --git a/app/src/renderer/vuex/modules/delegation.js b/app/src/renderer/vuex/modules/delegation.js index 826c98a196..b7793a9d12 100644 --- a/app/src/renderer/vuex/modules/delegation.js +++ b/app/src/renderer/vuex/modules/delegation.js @@ -86,7 +86,7 @@ export default ({ node }) => { delegator.delegations.forEach(({ validator_addr, shares }) => { commit(`setCommittedDelegation`, { candidateId: validator_addr, - value: parseFloat(shares) / 10000000000 + value: parseFloat(shares) }) if (shares > 0) { const delegate = candidates.find( diff --git a/test/unit/specs/__snapshots__/lcdClientMock.spec.js.snap b/test/unit/specs/__snapshots__/lcdClientMock.spec.js.snap index a0dac5f032..260d6b252d 100644 --- a/test/unit/specs/__snapshots__/lcdClientMock.spec.js.snap +++ b/test/unit/specs/__snapshots__/lcdClientMock.spec.js.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`LCD Client Mock delegates to multiple validators at once 1`] = `"100000000000"`; +exports[`LCD Client Mock delegates to multiple validators at once 1`] = `"10"`; exports[`LCD Client Mock delegates to multiple validators at once 2`] = `"240000000000"`; diff --git a/test/unit/specs/lcdClientMock.spec.js b/test/unit/specs/lcdClientMock.spec.js index 6a6a3d8ef2..81c8f6b4f6 100644 --- a/test/unit/specs/lcdClientMock.spec.js +++ b/test/unit/specs/lcdClientMock.spec.js @@ -326,7 +326,7 @@ describe(`LCD Client Mock`, () => { lcdClientMock.addresses[0], lcdClientMock.validators[1] ) - expect(updatedStake.shares).toBe(`100000000000`) + expect(updatedStake.shares).toBe(`10`) }) it(`executes an unbond tx`, async () => { @@ -352,7 +352,7 @@ describe(`LCD Client Mock`, () => { lcdClientMock.addresses[0], lcdClientMock.validators[1] ) - expect(initialStake.shares).toBe(`100000000000`) + expect(initialStake.shares).toBe(`10`) res = await client.updateDelegations(lcdClientMock.addresses[0], { base_req: { @@ -389,7 +389,7 @@ describe(`LCD Client Mock`, () => { { delegator_addr: lcdClientMock.addresses[0], validator_addr: lcdClientMock.validators[1], - delegation: { denom: `mycoin`, amount: String(100000 * 10000000000) } + delegation: { denom: `mycoin`, amount: String(100000) } } ], begin_unbondings: [] From d78a7e99fd187cecdaa7b318acfe81f6b90a7d58 Mon Sep 17 00:00:00 2001 From: Voyager Bot Date: Mon, 5 Nov 2018 16:49:40 +0100 Subject: [PATCH 09/42] fixed some tests related to updating --- app/src/renderer/connectors/lcdClientMock.js | 22 +++++++++++++------ test/unit/specs/App.spec.js | 2 +- .../__snapshots__/lcdClientMock.spec.js.snap | 4 ++-- test/unit/specs/lcdClientMock.spec.js | 21 ++++++++++++------ test/unit/specs/store/delegation.spec.js | 2 +- 5 files changed, 33 insertions(+), 18 deletions(-) diff --git a/app/src/renderer/connectors/lcdClientMock.js b/app/src/renderer/connectors/lcdClientMock.js index ba09312cce..fb2ae3e016 100644 --- a/app/src/renderer/connectors/lcdClientMock.js +++ b/app/src/renderer/connectors/lcdClientMock.js @@ -124,7 +124,7 @@ let state = { { delegator_addr: addresses[0], validator_addr: validators[0], - shares: `140000000000`, + shares: `14`, height: 123 } ], @@ -136,8 +136,8 @@ let state = { operator_address: validators[0], pub_key: `cosmosvalpub1234`, revoked: false, - tokens: `140000000000`, - delegator_shares: `140000000000`, + tokens: `14`, + delegator_shares: `14`, description: { website: `www.monty.ca`, details: `Mr Mounty`, @@ -183,8 +183,8 @@ let state = { { operator_address: validators[2], pub_key: `cosmosvalpub8910`, - tokens: `190000000000`, - delegator_shares: `190000000000`, + tokens: `19`, + delegator_shares: `19`, description: { details: `Herr Schmidt`, website: `www.schmidt.de`, @@ -609,9 +609,17 @@ module.exports = { ) }, // Get all delegations information from a delegator - getDelegator(delegatorAddress) { + getDelegations(delegatorAddress) { let delegator = state.stake[delegatorAddress] || {} - return delegator + return delegator.delegations || [] + }, + getUndelegations(delegatorAddress) { + let delegator = state.stake[delegatorAddress] || {} + return delegator.unbonding_delegations || [] + }, + getRedelegations(delegatorAddress) { + let delegator = state.stake[delegatorAddress] || {} + return delegator.redelegations || [] }, getDelegatorTxs(addr, types = []) { if (types.length === 0) types = [`bonding`, `unbonding`] diff --git a/test/unit/specs/App.spec.js b/test/unit/specs/App.spec.js index de4b219d9b..af9372ec26 100644 --- a/test/unit/specs/App.spec.js +++ b/test/unit/specs/App.spec.js @@ -60,7 +60,7 @@ describe(`App without analytics`, () => { let Node = require(`renderer/connectors/node.js`) require(`renderer/main.js`) expect(Node).toHaveBeenCalledWith( - `http://localhost:8080`, + `https://localhost:8080`, `https://awesomenode.de:12345`, true ) diff --git a/test/unit/specs/__snapshots__/lcdClientMock.spec.js.snap b/test/unit/specs/__snapshots__/lcdClientMock.spec.js.snap index 260d6b252d..3028ce00dc 100644 --- a/test/unit/specs/__snapshots__/lcdClientMock.spec.js.snap +++ b/test/unit/specs/__snapshots__/lcdClientMock.spec.js.snap @@ -2,10 +2,10 @@ exports[`LCD Client Mock delegates to multiple validators at once 1`] = `"10"`; -exports[`LCD Client Mock delegates to multiple validators at once 2`] = `"240000000000"`; +exports[`LCD Client Mock delegates to multiple validators at once 2`] = `"24"`; exports[`LCD Client Mock deletes keys 1`] = `[Error: Passwords do not match]`; -exports[`LCD Client Mock queries bondings per delegator 1`] = `"140000000000"`; +exports[`LCD Client Mock queries bondings per delegator 1`] = `"14"`; exports[`LCD Client Mock updates keys 1`] = `[Error: Passwords do not match]`; diff --git a/test/unit/specs/lcdClientMock.spec.js b/test/unit/specs/lcdClientMock.spec.js index 81c8f6b4f6..52423bcd57 100644 --- a/test/unit/specs/lcdClientMock.spec.js +++ b/test/unit/specs/lcdClientMock.spec.js @@ -376,7 +376,7 @@ describe(`LCD Client Mock`, () => { lcdClientMock.addresses[0], lcdClientMock.validators[1] ) - expect(updatedStake.shares).toBe(`50000000000`) + expect(updatedStake.shares).toBe(`5`) }) it(`can not stake fermions you dont have`, async () => { @@ -614,12 +614,19 @@ describe(`LCD Client Mock`, () => { expect(res[0].check_tx.code).toBe(2) }) - it(`queries for summary of delegation information for a delegator`, async () => { - let delegation = await client.getDelegator(lcdClientMock.addresses[0]) - expect(Object.keys(delegation)).toEqual([ - `delegations`, - `unbonding_delegations` - ]) + it(`queries for delegation information for a delegator`, async () => { + let delegations = await client.getDelegations(lcdClientMock.addresses[0]) + expect(Array.isArray(delegations)).toBe(true) + }) + + it(`queries for undelegation information for a delegator`, async () => { + let delegations = await client.getUndelegations(lcdClientMock.addresses[0]) + expect(Array.isArray(delegations)).toBe(true) + }) + + it(`queries for redelegation information for a delegator`, async () => { + let delegations = await client.getRedelegations(lcdClientMock.addresses[0]) + expect(Array.isArray(delegations)).toBe(true) }) it(`queries for an unbonding delegation between a validator and a delegator`, async () => { diff --git a/test/unit/specs/store/delegation.spec.js b/test/unit/specs/store/delegation.spec.js index c91d482b26..188e333ef0 100644 --- a/test/unit/specs/store/delegation.spec.js +++ b/test/unit/specs/store/delegation.spec.js @@ -159,7 +159,7 @@ describe(`Module: Delegations`, () => { let resolveDelegationRequest // mock returning some delegations - node.getDelegator = () => + node.getDelegations = () => new Promise(resolve => { resolveDelegationRequest = () => resolve({ From 6b8e959c17e7139019331eb3a20e40ed39ddac01 Mon Sep 17 00:00:00 2001 From: Voyager Bot Date: Mon, 5 Nov 2018 17:17:13 +0100 Subject: [PATCH 10/42] correctly map unbonding delegations and txs --- .../components/wallet/PageTransactions.vue | 6 ++--- app/src/renderer/vuex/modules/delegation.js | 23 ++++++++++--------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/app/src/renderer/components/wallet/PageTransactions.vue b/app/src/renderer/components/wallet/PageTransactions.vue index 602c07f0b2..42d448c9b0 100644 --- a/app/src/renderer/components/wallet/PageTransactions.vue +++ b/app/src/renderer/components/wallet/PageTransactions.vue @@ -111,12 +111,10 @@ export default { let unbondingDelegation = this.delegation.unbondingDelegations[ tx.validator_addr ] - // TODO hack, use creation_height when https://github.com/cosmos/cosmos-sdk/issues/2314 is resolved if ( unbondingDelegation && - new Date(unbondingDelegation.min_time).getTime() - - new Date(copiedTransaction.time).getTime() === - 0 + unbondingDelegation.creation_height === + String(copiedTransaction.height) ) copiedTransaction.unbondingDelegation = unbondingDelegation } diff --git a/app/src/renderer/vuex/modules/delegation.js b/app/src/renderer/vuex/modules/delegation.js index b7793a9d12..16c3de480e 100644 --- a/app/src/renderer/vuex/modules/delegation.js +++ b/app/src/renderer/vuex/modules/delegation.js @@ -40,12 +40,19 @@ export default ({ node }) => { } state.committedDelegates = committedDelegates }, - setUnbondingDelegations(state, { validator_addr, min_time, balance }) { + setUnbondingDelegations( + state, + { validator_addr, min_time, balance, creation_height } + ) { let unbondingDelegations = Object.assign({}, state.unbondingDelegations) if (balance.amount === 0) { delete unbondingDelegations[validator_addr] } else { - unbondingDelegations[validator_addr] = { min_time, balance } + unbondingDelegations[validator_addr] = { + min_time, + balance, + creation_height + } } state.unbondingDelegations = unbondingDelegations } @@ -111,15 +118,9 @@ export default ({ node }) => { }) if (delegator.unbonding_delegations) { - delegator.unbonding_delegations.forEach( - ({ validator_addr, balance, min_time }) => { - commit(`setUnbondingDelegations`, { - validator_addr, - balance, - min_time - }) - } - ) + delegator.unbonding_delegations.forEach(ubd => { + commit(`setUnbondingDelegations`, ubd) + }) } // delete undelegations not present anymore Object.keys(state.unbondingDelegations).forEach(validatorAddr => { From 9fdcefd2ee2e48b9098b1c354ad39d819204d132 Mon Sep 17 00:00:00 2001 From: Voyager Bot Date: Mon, 5 Nov 2018 17:25:58 +0100 Subject: [PATCH 11/42] pipe init --- tasks/build/local/build.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasks/build/local/build.js b/tasks/build/local/build.js index 333ec56495..031637fc67 100644 --- a/tasks/build/local/build.js +++ b/tasks/build/local/build.js @@ -96,7 +96,7 @@ function init(options, environment) { console.log(`$ ` + command) const localnodeProcess = spawn(command, { shell: true }) localnodeProcess.stdin.write(`${options.password}\n`) - // localnodeProcess.stderr.pipe(process.stderr) + localnodeProcess.stderr.pipe(process.stderr) localnodeProcess.once(`exit`, code => { code === 0 ? resolve() : reject() }) From db0c47d64145bcb5d4b1ee7b884ba276e9e8928a Mon Sep 17 00:00:00 2001 From: Voyager Bot Date: Mon, 5 Nov 2018 17:55:53 +0100 Subject: [PATCH 12/42] clear all data on overwrite --- tasks/build/local/build.js | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/tasks/build/local/build.js b/tasks/build/local/build.js index 031637fc67..139e685120 100644 --- a/tasks/build/local/build.js +++ b/tasks/build/local/build.js @@ -24,12 +24,19 @@ cli(optionsSpecification, async options => { : `linux_amd64` try { // remove existing config - if ( - options.overwrite && - fs.existsSync(appDir + `/builds/testnets/local-testnet`) - ) { - let out = await makeExec(`rm -r builds/testnets/local-testnet`) - out && console.log(out) + if (options.overwrite) { + if (fs.existsSync(appDir + `/builds/testnets/local-testnet`)) { + let out = await makeExec(`rm -r builds/testnets/local-testnet`) + out && console.log(out) + } + if (fs.existsSync(homeDir + `/.gaiad-testnet`)) { + let out = await makeExec(`rm -r ~/.gaiad-testnet`) + out && console.log(out) + } + if (fs.existsSync(homeDir + `/.cosmos-voyager-dev/local-testnet`)) { + let out = await makeExec(`rm -r ~/.cosmos-voyager-dev/local-testnet`) + out && console.log(out) + } } await init(options, environment) From 4a1322482c14d68258bf2868ee744084dbd02010 Mon Sep 17 00:00:00 2001 From: Voyager Bot Date: Thu, 8 Nov 2018 16:02:56 +0100 Subject: [PATCH 13/42] go to 0.26-rc0 --- tasks/build/Gaia/COMMIT.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasks/build/Gaia/COMMIT.sh b/tasks/build/Gaia/COMMIT.sh index 8721d0b6c0..10a4ca78c1 100755 --- a/tasks/build/Gaia/COMMIT.sh +++ b/tasks/build/Gaia/COMMIT.sh @@ -2,5 +2,5 @@ # This is the commit of the SDK version to use for building Gaia. We use an # explicit hash instead of a tag so we don't have to trust GitHub. -export COMMIT=10e8e0312eeed9a450e7c49f4337427b9268b459 +export COMMIT=c7b3efdd02be2132f19c0ad4afc58b002edc73fe From e8db09ae94644e876d79c15935d8e836cce9bd7f Mon Sep 17 00:00:00 2001 From: David Braun Date: Fri, 9 Nov 2018 12:30:36 -0500 Subject: [PATCH 14/42] Fix a bunch of tests in lcdClient.spec. --- app/src/renderer/connectors/lcdClient.js | 11 +- test/unit/specs/lcdClient.spec.js | 723 ++++++++++++++--------- 2 files changed, 433 insertions(+), 301 deletions(-) diff --git a/app/src/renderer/connectors/lcdClient.js b/app/src/renderer/connectors/lcdClient.js index b2485a43de..588d17f996 100644 --- a/app/src/renderer/connectors/lcdClient.js +++ b/app/src/renderer/connectors/lcdClient.js @@ -3,12 +3,7 @@ const Client = (axios, localLcdURL, remoteLcdURL) => { async function request(method, path, data, useRemote) { const url = useRemote ? remoteLcdURL : localLcdURL - - return (await axios({ - method: method.toLowerCase(), - url: url + path, - data - })).data + return (await axios({ data, method, url: url + path })).data } // returns an async function which makes a request for the given @@ -28,9 +23,7 @@ const Client = (axios, localLcdURL, remoteLcdURL) => { if (Array.isArray(args)) { args = args.join(`/`) } - if (method === `DELETE`) { - data = { data } - } + return request(method, `${prefix}/${args}${suffix}`, data, useRemote) } } diff --git a/test/unit/specs/lcdClient.spec.js b/test/unit/specs/lcdClient.spec.js index 0ecc4de69d..cd1a73a858 100644 --- a/test/unit/specs/lcdClient.spec.js +++ b/test/unit/specs/lcdClient.spec.js @@ -23,165 +23,71 @@ const { MemoryDataStore, Resource } = createMiddleware const { promisify } = require(`util`) describe(`LCD Client`, () => { - describe(`helper functions`, () => { - let axios + describe(`Gaia-Lite`, () => { let client + const dataStore = new MemoryDataStore() + let mockServer - beforeEach(() => { - axios = {} - client = LcdClient(axios, `http://localhost`, `http://remotehost`) - }) - - it(`makes a GET request with no args`, async () => { - axios.get = jest - .fn() - .mockReturnValueOnce(Promise.resolve({ data: { foo: `bar` } })) + beforeAll(async () => { + const application = Express() - let res = await client.keys.values() - expect(res).toEqual({ foo: `bar` }) - expect(axios.get.mock.calls[0]).toEqual([ - `http://localhost/keys`, - undefined - ]) - }) - - it(`makes a GET request with one arg`, async () => { - axios.get = jest - .fn() - .mockReturnValueOnce(Promise.resolve({ data: { foo: `bar` } })) + const middleware = await promisify(createMiddleware)( + path.join(__dirname, `../helpers/Gaia-Lite.yaml`), + application + ) - let res = await client.keys.get(`myKey`) - expect(res).toEqual({ foo: `bar` }) - expect(axios.get.mock.calls[0]).toEqual([ - `http://localhost/keys/myKey`, - undefined - ]) - }) + application.use(middleware.metadata()) - it(`makes a POST request`, async () => { - axios.post = jest - .fn() - .mockReturnValueOnce(Promise.resolve({ data: { foo: `bar` } })) + // The fact that /keys is a collection but /keys/seed is not a resource in + // that collection confuses the Swagger middleware so we have to mock it + // separately. - let res = await client.keys.add() - expect(res).toEqual({ foo: `bar` }) - expect(axios.post.mock.calls[0]).toEqual([ - `http://localhost/keys`, - undefined - ]) - }) + application.get(`/keys/seed`, (request, response) => { + response.send(request.swagger.path.get.responses[`200`].example) + }) - it(`makes a POST request with args and data`, async () => { - axios.put = jest - .fn() - .mockReturnValueOnce(Promise.resolve({ data: { foo: `bar` } })) + // Don't return passwords. This is a workaround to + // https://github.com/APIDevTools/swagger-express-middleware/issues/18 + application.get( + `/keys`, + mung.json(body => { + body.forEach(key => { + delete key.password + }) - let res = await client.keys.set(`myKey`, { abc: 123 }) - expect(res).toEqual({ foo: `bar` }) - expect(axios.put.mock.calls[0]).toEqual([ - `http://localhost/keys/myKey`, - { abc: 123 } - ]) - }) + return body + }) + ) - it(`makes a GET request with an error`, async () => { - axios.get = jest.fn().mockReturnValueOnce( - Promise.reject({ - response: { - data: `foo` - } + // Don't return passwords. This is a workaround to + // https://github.com/APIDevTools/swagger-express-middleware/issues/18 + application.get( + `/keys/:name`, + mung.json(body => { + delete body.password + return body }) ) - try { - await await client.keys.values() - } catch (err) { - expect(err.response.data).toBe(`foo`) - } - expect(axios.get.mock.calls[0]).toEqual([ - `http://localhost/keys`, - undefined - ]) - }) + application.use( + // Why is this necessary? + middleware.CORS(), - it(`delete requests have the correct format for data`, async () => { - axios.delete = (path, config) => { - expect(config).toEqual({ data: { password: `abc` } }) - return Promise.resolve({ data: { foo: `bar` } }) - } + middleware.parseRequest(), + middleware.validateRequest(), + middleware.mock(dataStore) + ) - // doesn't throw - await client.keys.delete(`test`, { password: `abc` }) + mockServer = http.createServer(application) + await promisify(mockServer.listen.bind(mockServer))(0, `localhost`) + const localLcdURL = `http://localhost:${mockServer.address().port}` + client = LcdClient(axios, localLcdURL, `http://remotehost`) }) - }) - - let client - const dataStore = new MemoryDataStore() - let mockServer - let remoteLcdURL - - beforeAll(async () => { - const application = Express() - - const middleware = await promisify(createMiddleware)( - path.join(__dirname, `../helpers/Gaia-Lite.yaml`), - application - ) - - application.use(middleware.metadata()) - // The fact that /keys is a collection but /keys/seed is not a resource in - // that collection confuses the Swagger middleware so we have to mock it - // separately. - - application.get(`/keys/seed`, (request, response) => { - response.send(request.swagger.path.get.responses[`200`].example) + afterAll(done => { + mockServer.close(done) }) - // Don't return passwords. This is a workaround to - // https://github.com/APIDevTools/swagger-express-middleware/issues/18 - application.get( - `/keys`, - mung.json(body => { - body.forEach(key => { - delete key.password - }) - - return body - }) - ) - - // Don't return passwords. This is a workaround to - // https://github.com/APIDevTools/swagger-express-middleware/issues/18 - application.get( - `/keys/:name`, - mung.json(body => { - delete body.password - return body - }) - ) - - application.use( - // Why is this necessary? - middleware.CORS(), - - middleware.parseRequest(), - middleware.validateRequest(), - middleware.mock(dataStore) - ) - - mockServer = http.createServer(application) - await promisify(mockServer.listen.bind(mockServer))(0, `localhost`) - const localLcdURL = `http://localhost:${mockServer.address().port}` - remoteLcdURL = `http://awesomenode.de:12345` - client = LcdClient(axios, localLcdURL, remoteLcdURL) - }) - - afterAll(done => { - mockServer.close(done) - }) - - describe(`Gaia-Lite`, () => { beforeEach(done => { const initialState = [ { @@ -239,9 +145,6 @@ describe(`LCD Client`, () => { }) }) - // In the future we'll use the SDK's Swagger file instead of our own copy - // and this test will dependend on - // https://github.com/cosmos/cosmos-sdk/pull/2496 being merged. it(`seed`, async () => { expect(await client.keys.seed()).toEqual( `blossom pool issue kidney elevator blame furnace winter account merry vessel security depend exact travel bargain problem jelly rural net again mask roast chest` @@ -272,10 +175,93 @@ describe(`LCD Client`, () => { ]) }) }) + }) + + describe(`unit tests`, () => { + let axios + let client + + beforeEach(() => { + axios = jest.fn() + client = LcdClient(axios, `http://localhost`, `http://remotehost`) + }) + + describe(`helper functions`, () => { + it(`makes a GET request with no args`, async () => { + axios.mockReturnValueOnce(Promise.resolve({ data: { foo: `bar` } })) + let res = await client.keys.values() + expect(res).toEqual({ foo: `bar` }) + + expect(axios.mock.calls).toEqual([ + [{ data: undefined, method: `GET`, url: `http://localhost/keys` }] + ]) + }) + + it(`makes a GET request with one arg`, async () => { + axios.mockReturnValueOnce(Promise.resolve({ data: { foo: `bar` } })) + let res = await client.keys.get(`myKey`) + expect(res).toEqual({ foo: `bar` }) + + expect(axios.mock.calls).toEqual([ + [ + { + data: undefined, + method: `GET`, + url: `http://localhost/keys/myKey` + } + ] + ]) + }) + + it(`makes a POST request`, async () => { + axios.mockReturnValueOnce(Promise.resolve({ data: { foo: `bar` } })) + let res = await client.keys.add() + expect(res).toEqual({ foo: `bar` }) + + expect(axios.mock.calls).toEqual([ + [{ data: undefined, method: `POST`, url: `http://localhost/keys` }] + ]) + }) + + it(`makes a PUT request with args and data`, async () => { + axios.mockReturnValueOnce(Promise.resolve({ data: { foo: `bar` } })) + let res = await client.keys.set(`myKey`, { abc: 123 }) + expect(res).toEqual({ foo: `bar` }) + + expect(axios.mock.calls).toEqual([ + [ + { + data: { abc: 123 }, + method: `PUT`, + url: `http://localhost/keys/myKey` + } + ] + ]) + }) + + it(`makes a GET request with an error`, async () => { + axios.mockReturnValueOnce( + Promise.reject({ + response: { + data: `foo` + } + }) + ) + + try { + await await client.keys.values() + } catch (err) { + expect(err.response.data).toBe(`foo`) + } + expect(axios.mock.calls).toEqual([ + [{ data: undefined, method: `GET`, url: `http://localhost/keys` }] + ]) + }) + }) describe(`stake`, () => { it(`queries for shares for a validator and delegate`, async () => { - axios.get = jest.fn().mockReturnValueOnce( + axios.mockReturnValueOnce( Promise.resolve({ response: { data: { @@ -285,103 +271,335 @@ describe(`LCD Client`, () => { }) ) await client.queryDelegation(`abc`, `efg`) - expect(axios.get.mock.calls[0]).toEqual([ - `${remoteLcdURL}/stake/delegators/abc/delegations/efg`, - undefined + + expect(axios.mock.calls).toEqual([ + [ + { + data: undefined, + method: `GET`, + url: `http://remotehost/stake/delegators/abc/delegations/efg` + } + ] ]) }) it(`queries for a delegation summary for a delegator`, async () => { - axios.get = jest.fn().mockReturnValue({}) + axios.mockReturnValue({}) await client.getDelegator(`abc`) - expect(axios.get.mock.calls[0]).toEqual([ - `${remoteLcdURL}/stake/delegators/abc`, - undefined + + expect(axios.mock.calls).toEqual([ + [ + { + data: undefined, + method: `GET`, + url: `http://remotehost/stake/delegators/abc` + } + ] ]) }) it(`queries for a delegation txs`, async () => { - axios.get = jest - .fn() - .mockReturnValue(Promise.resolve({ data: lcdClientMock.txs })) + axios.mockReturnValue(Promise.resolve({ data: lcdClientMock.txs })) await client.getDelegatorTxs(`abc`) await client.getDelegatorTxs(`abc`, [`bonding`]) await client.getDelegatorTxs(`abc`, [`unbonding`]) await client.getDelegatorTxs(`abc`, [`redelegate`]) - expect(axios.get.mock.calls).toEqual([ - [`${remoteLcdURL}/stake/delegators/abc/txs`, undefined], - [`${remoteLcdURL}/stake/delegators/abc/txs?type=bonding`, undefined], + + expect(axios.mock.calls).toEqual([ + [ + { + data: undefined, + method: `GET`, + url: `http://remotehost/stake/delegators/abc/txs` + } + ], + [ + { + data: undefined, + method: `GET`, + url: `http://remotehost/stake/delegators/abc/txs?type=bonding` + } + ], [ - `${remoteLcdURL}/stake/delegators/abc/txs?type=unbonding`, - undefined + { + data: undefined, + method: `GET`, + url: `http://remotehost/stake/delegators/abc/txs?type=unbonding` + } ], [ - `${remoteLcdURL}/stake/delegators/abc/txs?type=redelegate`, - undefined + { + data: undefined, + method: `GET`, + url: `http://remotehost/stake/delegators/abc/txs?type=redelegate` + } ] ]) }) it(`queries all validators that a delegator is bonded to`, async () => { - axios.get = jest.fn().mockReturnValue({}) + axios.mockReturnValue({}) await client.getDelegatorValidators(`abc`) - expect(axios.get.mock.calls[0]).toEqual([ - `${remoteLcdURL}/stake/delegators/abc/validators`, - undefined + + expect(axios.mock.calls).toEqual([ + [ + { + data: undefined, + method: `GET`, + url: `http://remotehost/stake/delegators/abc/validators` + } + ] ]) }) it(`queries for undelegations between a delegator and a validator`, async () => { - axios.get = jest.fn().mockReturnValue({}) + axios.mockReturnValue({}) await client.queryUnbonding(`abc`, `def`) - expect(axios.get.mock.calls[0]).toEqual([ - `${remoteLcdURL}/stake/delegators/abc/unbonding_delegations/def`, - undefined + + expect(axios.mock.calls).toEqual([ + [ + { + data: undefined, + method: `GET`, + url: `http://remotehost/stake/delegators/abc/unbonding_delegations/def` + } + ] ]) }) it(`queries for a validator`, async () => { - axios.get = jest.fn().mockReturnValue({}) + axios.mockReturnValue({}) await client.getCandidate(`abc`) - expect(axios.get.mock.calls[0]).toEqual([ - `${remoteLcdURL}/stake/validators/abc`, - undefined + + expect(axios.mock.calls).toEqual([ + [ + { + data: undefined, + method: `GET`, + url: `http://remotehost/stake/validators/abc` + } + ] ]) }) it(`updateDelegations`, async () => { - axios.post = jest.fn().mockReturnValue({}) + axios.mockReturnValue({}) await client.updateDelegations(`abc`) - expect(axios.post.mock.calls[0]).toEqual([ - `http://localhost:${ - mockServer.address().port - }/stake/delegators/abc/delegations`, - undefined + + expect(axios.mock.calls).toEqual([ + [ + { + data: undefined, + method: `POST`, + url: `http://localhost/stake/delegators/abc/delegations` + } + ] ]) }) it(`queries for staking parameters`, async () => { - axios.get = jest.fn().mockReturnValue({}) + axios.mockReturnValue({}) await client.getParameters() - expect(axios.get.mock.calls[0]).toEqual([ - `${remoteLcdURL}/stake/parameters`, - undefined + + expect(axios.mock.calls).toEqual([ + [ + { + data: undefined, + method: `GET`, + url: `http://remotehost/stake/parameters` + } + ] ]) }) it(`queries for staking pool`, async () => { - axios.get = jest.fn().mockReturnValue({}) + axios.mockReturnValue({}) await client.getPool() - expect(axios.get.mock.calls[0]).toEqual([ - `${remoteLcdURL}/stake/pool`, - undefined + + expect(axios.mock.calls).toEqual([ + [ + { + data: undefined, + method: `GET`, + url: `http://remotehost/stake/pool` + } + ] + ]) + }) + }) + + describe(`governance`, () => { + it(`fetches all governance proposals`, async () => { + axios.mockReturnValue({}) + await client.queryProposals() + + expect(axios.mock.calls).toEqual([ + [ + { + data: undefined, + method: `GET`, + url: `http://remotehost/gov/proposals` + } + ] + ]) + }) + + it(`queries a single proposal`, async () => { + axios.mockReturnValue({}) + await client.queryProposal(1) + + expect(axios.mock.calls).toEqual([ + [ + { + data: undefined, + method: `GET`, + url: `http://remotehost/gov/proposals/1` + } + ] + ]) + }) + + it(`queries a proposal votes`, async () => { + axios.mockReturnValue({}) + await client.queryProposalVotes(1) + + expect(axios.mock.calls).toEqual([ + [ + { + data: undefined, + method: `GET`, + url: `http://remotehost/gov/proposals/1/votes` + } + ] + ]) + }) + + it(`queries a proposal vote from an address`, async () => { + axios.mockReturnValue({}) + await client.queryProposalVote( + 1, + `cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5ctpesxxn9` + ) + + expect(axios.mock.calls).toEqual([ + [ + { + data: undefined, + method: `GET`, + url: `http://remotehost/gov/proposals/1/votes/cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5ctpesxxn9` + } + ] + ]) + }) + + it(`queries a proposal deposits`, async () => { + axios.mockReturnValue({}) + await client.queryProposalDeposits(1) + + expect(axios.mock.calls).toEqual([ + [ + { + data: undefined, + method: `GET`, + url: `http://remotehost/gov/proposals/1/deposits` + } + ] + ]) + }) + + it(`queries a proposal deposit from an address`, async () => { + axios.mockReturnValue({}) + await client.queryProposalDeposit( + 1, + `cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5ctpesxxn9` + ) + + expect(axios.mock.calls).toEqual([ + [ + { + data: undefined, + method: `GET`, + url: `http://remotehost/gov/proposals/1/deposits/cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5ctpesxxn9` + } + ] + ]) + }) + + it(`submits a new proposal`, async () => { + axios.mockReturnValue({}) + await client.submitProposal(proposals[0]) + + expect(axios.mock.calls).toEqual([ + [ + { + data: proposals[0], + method: `POST`, + url: `http://remotehost/gov/proposals` + } + ] + ]) + }) + + it(`submits a new vote to a proposal`, async () => { + axios.mockReturnValue({}) + await client.submitVote(proposals[0].proposal_id, votes[0]) + + expect(axios.mock.calls).toEqual([ + [ + { + data: undefined, + method: `POST`, + url: `http://remotehost/gov/proposals/1/votes` + } + ] + ]) + }) + + it(`submits a new deposit to a proposal`, async () => { + axios.mockReturnValue({}) + await client.submitDeposit(proposals[0].proposal_id, deposits[0]) + + expect(axios.mock.calls).toEqual([ + [ + { + data: undefined, + method: `POST`, + url: `http://remotehost/gov/proposals/1/deposits` + } + ] + ]) + }) + + it(`queries for governance txs`, async () => { + axios.mockReturnValue({}) + await client.getGovernanceTxs(lcdClientMock.addresses[0]) + + expect(axios.mock.calls).toEqual([ + [ + { + data: undefined, + method: `GET`, + url: `http://remotehost/txs?tag=action=submit-proposal&proposer='${ + lcdClientMock.addresses[0] + }'` + } + ], + [ + { + data: undefined, + method: `GET`, + url: `http://remotehost/txs?tag=action=deposit&depositer='${ + lcdClientMock.addresses[0] + }'` + } + ] ]) }) }) describe(`queryAccount`, () => { it(`returns an account`, async () => { - axios.get = jest.fn().mockReturnValueOnce( + axios.mockReturnValueOnce( Promise.resolve({ data: { value: { @@ -411,7 +629,7 @@ describe(`LCD Client`, () => { }) it(`does not throw error for empty results`, async () => { - axios.get = jest.fn().mockReturnValueOnce( + axios.mockReturnValueOnce( Promise.reject({ response: { data: `account bytes are empty` @@ -423,7 +641,7 @@ describe(`LCD Client`, () => { }) it(`throws error for error other than empty account`, async () => { - axios.get = jest.fn().mockReturnValueOnce( + axios.mockReturnValueOnce( Promise.reject({ response: { data: `something failed` @@ -447,123 +665,44 @@ describe(`LCD Client`, () => { }) it(`queries for indexed transactions`, async () => { - let axios = require(`axios`) - axios.get = jest - .fn() + axios .mockReturnValueOnce(Promise.resolve({ data: [] })) .mockReturnValueOnce(Promise.resolve({ data: [`abc`] })) let result = await client.txs(`abc`) - expect(axios.get).toHaveBeenCalledTimes(2) + expect(axios).toHaveBeenCalledTimes(2) client.keys.values = () => Promise.resolve() expect(result).toEqual([`abc`]) }) it(`gets the list of the validators in the latest validator set`, async () => { - axios.get = jest.fn().mockReturnValue({}) + axios.mockReturnValue({}) await client.getValidatorSet() - expect(axios.get.mock.calls[0]).toEqual([ - `${remoteLcdURL}/validatorsets/latest`, - undefined + + expect(axios.mock.calls).toEqual([ + [ + { + data: undefined, + method: `GET`, + url: `http://remotehost/validatorsets/latest` + } + ] ]) }) it(`queries a validator signing information`, async () => { - axios.get = jest.fn().mockReturnValue({}) + axios.mockReturnValue({}) await client.queryValidatorSigningInfo(`pubKey`) - expect(axios.get.mock.calls[0]).toEqual([ - `${remoteLcdURL}/slashing/signing_info/pubKey`, - undefined + + expect(axios.mock.calls).toEqual([ + [ + { + data: undefined, + method: `GET`, + url: `http://remotehost/slashing/signing_info/pubKey` + } + ] ]) }) }) - - /* ============ Governance ============ */ - - it(`fetches all governance proposals`, async () => { - axios.get = jest.fn().mockReturnValue({}) - await client.queryProposals() - expect(axios.get.mock.calls[0]).toEqual([ - `${remoteLcdURL}/gov/proposals`, - undefined - ]) - }) - - it(`queries a single proposal`, async () => { - axios.get = jest.fn().mockReturnValue({}) - await client.queryProposal(1) - expect(axios.get.mock.calls[0]).toEqual([ - `${remoteLcdURL}/gov/proposals/1`, - undefined - ]) - }) - - it(`queries a proposal votes`, async () => { - axios.get = jest.fn().mockReturnValue({}) - await client.queryProposalVotes(1) - expect(axios.get.mock.calls[0]).toEqual([ - `${remoteLcdURL}/gov/proposals/1/votes`, - undefined - ]) - }) - - it(`queries a proposal vote from an address`, async () => { - axios.get = jest.fn().mockReturnValue({}) - await client.queryProposalVote( - 1, - `cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5ctpesxxn9` - ) - expect(axios.get.mock.calls[0]).toEqual([ - `${remoteLcdURL}/gov/proposals/1/votes/cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5ctpesxxn9`, - undefined - ]) - }) - - it(`queries a proposal deposits`, async () => { - axios.get = jest.fn().mockReturnValue({}) - await client.queryProposalDeposits(1) - expect(axios.get.mock.calls[0]).toEqual([ - `${remoteLcdURL}/gov/proposals/1/deposits`, - undefined - ]) - }) - - it(`queries a proposal deposit from an address`, async () => { - axios.get = jest.fn().mockReturnValue({}) - await client.queryProposalDeposit( - 1, - `cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5ctpesxxn9` - ) - expect(axios.get.mock.calls[0]).toEqual([ - `${remoteLcdURL}/gov/proposals/1/deposits/cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5ctpesxxn9`, - undefined - ]) - }) - - it(`submits a new proposal`, async () => { - axios.post = jest.fn().mockReturnValue({}) - await client.submitProposal(proposals[0]) - expect(axios.post.mock.calls[0]).toEqual([ - `${remoteLcdURL}/gov/proposals`, - proposals[0] - ]) - }) - - it(`submits a new vote to a proposal`, async () => { - axios.post = jest.fn().mockReturnValue({}) - await client.submitVote(proposals[0].proposal_id, votes[0]) - expect(axios.post.mock.calls[0]).toEqual([ - `${remoteLcdURL}/gov/proposals/${proposals[0].proposal_id}/votes`, - votes[0] - ]) - }) - - it(`submits a new deposit to a proposal`, async () => { - axios.post = jest.fn().mockReturnValue({}) - await client.submitDeposit(proposals[0].proposal_id, deposits[0]) - expect(axios.post.mock.calls[0]).toEqual([ - `${remoteLcdURL}/gov/proposals/${proposals[0].proposal_id}/deposits`, - deposits[0] - ]) - }) }) From 5235cd821598a588e2db87512f5196fe774f965d Mon Sep 17 00:00:00 2001 From: Voyager Bot Date: Mon, 12 Nov 2018 19:09:14 +0100 Subject: [PATCH 15/42] most tests fixed --- app/src/main/index.js | 28 ++-- test/unit/specs/main.spec.js | 265 +++++++++++++++++++---------------- 2 files changed, 160 insertions(+), 133 deletions(-) diff --git a/app/src/main/index.js b/app/src/main/index.js index 1dca5f53b3..fbc7e22502 100644 --- a/app/src/main/index.js +++ b/app/src/main/index.js @@ -81,10 +81,6 @@ function logProcess(process, logPath) { } } -function sleep(ms) { - return new Promise(resolve => setTimeout(resolve, ms)) -} - function handleCrash(error) { afterBooted(() => { if (mainWindow) { @@ -309,12 +305,10 @@ function stopLCD() { try { // prevent the exit to signal bad termination warnings lcdProcess.removeAllListeners(`exit`) - lcdProcess.on(`exit`, () => { lcdProcess = null resolve() }) - lcdProcess.kill(`SIGKILL`) } catch (err) { handleCrash(err) @@ -425,9 +419,7 @@ const eventHandlers = { reconnect: () => reconnect(), - "stop-lcd": () => { - stopLCD() - }, + "stop-lcd": () => stopLCD(), "successful-launch": () => { console.log(`[START SUCCESS] Vue app successfuly started`) @@ -441,7 +433,14 @@ Object.entries(eventHandlers).forEach(([event, handler]) => { // test an actual node version against the expected one and flag the node if incompatible async function testNodeVersion(client, expectedGaiaVersion) { - let nodeVersion = (await client.nodeVersion()).split(`-`)[0] + let result + try { + result = await client.nodeVersion() + } catch (err) { + debugger + return { compatible: false, nodeVersion: null } + } + let nodeVersion = result.split(`-`)[0] let semverDiff = semver.diff(nodeVersion, expectedGaiaVersion) if (semverDiff === `patch` || semverDiff === null) { return { compatible: true, nodeVersion } @@ -487,10 +486,8 @@ async function pickAndConnect() { let compatible, nodeVersion try { - const out = await testNodeVersion( - LcdClient(axiosInstance, config.node_lcd), - expectedGaiaCliVersion - ) + const client = LcdClient(axiosInstance, config.node_lcd) + const out = await testNodeVersion(client, expectedGaiaCliVersion) compatible = out.compatible nodeVersion = out.nodeVersion @@ -743,5 +740,6 @@ module.exports = main() .then(() => ({ shutdown, processes: { lcdProcess }, - eventHandlers + eventHandlers, + getLCDProcess: () => lcdProcess })) diff --git a/test/unit/specs/main.spec.js b/test/unit/specs/main.spec.js index ec30295bc3..5f6c936a02 100644 --- a/test/unit/specs/main.spec.js +++ b/test/unit/specs/main.spec.js @@ -1,6 +1,17 @@ -const EventEmitter = require(`events`) +// const EventEmitter = require(`events`) const { join } = require(`path`) const mockFsExtra = require(`../helpers/fs-mock`).default +jest.mock(`readline`, () => ({ + createInterface: () => ({ + on: () => {} + }) +})) + +jest.mock(`raven`, () => ({ + config: () => ({ install: () => {} }), + uninstall: () => ({ config: () => ({ install: () => {} }) }), + captureException: () => {} +})) // prevents warnings from repeated event handling process.setMaxListeners(1000) @@ -26,16 +37,11 @@ jest.mock(`fs-extra`, () => { `utf8` ) ) + mockFs.writeFile(`./cert/cert.txt`, `super-cert`) return mockFs }) let fs = require(`fs-extra`) -jest.mock(`../../../app/src/renderer/connectors/lcdClient.js`, () => { - return () => ({ - keys: { values: jest.fn().mockReturnValueOnce(Promise.reject()) } - }) -}) - jest.mock(`electron`, () => { let electron = { app: { @@ -77,22 +83,25 @@ jest.mock(`electron`, () => { }) const mockSpawnReturnValue = () => { - const emitter = new EventEmitter() - - return Object.assign(emitter, { - kill: () => { - emitter.emit(`exit`, 0) - }, - mocked: true, - stdout: { + return Object.assign( + {}, + { on: () => {}, - pipe: () => {} - }, - stderr: { - on: () => {}, - pipe: () => {} + kill: () => {}, + removeAllListeners: () => {}, + mocked: true, + stdout: { + on: () => {}, + once: () => {}, + pipe: () => {} + }, + stderr: { + on: () => {}, + once: () => {}, + pipe: () => {} + } } - }) + ) } let stdoutMocks = (path, args) => ({ @@ -100,24 +109,13 @@ let stdoutMocks = (path, args) => ({ if (args[0] === `version` && type === `data`) { cb({ toString: () => `0.13.0` }) } - // mock gaiacli init approval request - if ( - type === `data` && - path.includes(`gaiacli`) && - args.includes(`init`) && - args.length > 4 - ) { - cb(`No hash yet`) - setImmediate(() => { - cb(`1234567890123456789012345678901234567890`) - }) + }, + once: (type, cb) => { + if (type === `line`) { + cb(`(cert: "cert/cert.txt"...`) } } }) -childProcessMock((path, args) => ({ - stdin: { write: () => {} }, - stdout: stdoutMocks(path, args) -})) mockConfig() let main @@ -175,9 +173,8 @@ describe(`Startup Process`, () => { it(`should error if it can't connect to the node`, async () => { await main.shutdown() prepareMain() - // mock the version check request - jest.doMock(`axios`, () => ({ - get: jest.fn(() => Promise.reject()) + jest.doMock(`renderer/connectors/lcdClient.js`, () => () => ({ + nodeVersion: async () => Promise.reject(`X`) })) let { send } = require(`electron`) send.mockClear() @@ -194,12 +191,9 @@ describe(`Startup Process`, () => { it(`should check if our node has a compatible SDK version`, async () => { await main.shutdown() prepareMain() - const mockAxiosGet = jest - .fn() - .mockReturnValueOnce(Promise.resolve({ data: `0.1.0` })) // should fail as expected version is 0.13.0 - // mock the version check request - jest.doMock(`axios`, () => ({ - get: mockAxiosGet + const nodeVersionSpy = jest.fn(() => `0.1.0`) + jest.doMock(`renderer/connectors/lcdClient.js`, () => () => ({ + nodeVersion: nodeVersionSpy })) let { send } = require(`electron`) send.mockClear() @@ -207,7 +201,7 @@ describe(`Startup Process`, () => { // run main main = await require(appRoot + `src/main/index.js`) - expect(mockAxiosGet).toHaveBeenCalledTimes(1) + expect(nodeVersionSpy).toHaveBeenCalledTimes(1) expect(send).toHaveBeenCalledWith(`error`, { code: `NO_NODES_AVAILABLE`, message: `No nodes available to connect to.` @@ -374,10 +368,15 @@ describe(`Startup Process`, () => { }) it(`should stop the LCD on IPC call`, async () => { - let killSpy = jest.spyOn(main.processes.lcdProcess, `kill`) + let process + while (!process) { + await new Promise(resolve => setTimeout(resolve, 100)) + process = main.getLCDProcess() + } + process.kill = jest.fn() await registeredIPCListeners[`stop-lcd`]() - expect(killSpy).toHaveBeenCalled() + expect(process.kill).toHaveBeenCalled() }) it(`should not start reconnecting again if already trying to reconnect`, async done => { @@ -443,11 +442,18 @@ describe(`Startup Process`, () => { childProcess.spawn = () => Object.assign(mockSpawnReturnValue(), { + on: (type, cb) => { + if (type === `exit`) { + cb(0) + } + }, stderr: { on: (type, cb) => { - // type is always 'data' - cb(Buffer.from(`Some error`)) + if (type === `line`) { + cb(Buffer.from(`Some error`)) + } }, + once: () => {}, pipe: () => {} } }) @@ -459,24 +465,43 @@ describe(`Startup Process`, () => { }) it(`should error on gaiacli crashing async instead of breaking`, async () => { - await initMain() - let { send } = require(`electron`) let errorCB - childProcess.spawn = () => - Object.assign(mockSpawnReturnValue(), { - stderr: { - on: (type, cb) => { - // type is always 'data' + jest.resetModules() + childProcessMock((path, args) => ({ + stdin: { write: () => {} }, + stdout: stdoutMocks(path, args), + stderr: { + on: (type, cb) => { + if (args[0] === `rest-server` && type === `line`) { errorCB = cb - }, - pipe: () => {} + } + }, + once: () => {} + }, + on: (type, cb) => { + if (args[0] === `init` && type === `exit`) { + cb(0) } - }) + if (args[0] === `rest-server` && type === `exit`) { + setImmediate(() => { + cb(0) + }) + } + if (args[0] === `keys` && args[1] === `delete` && type === `exit`) { + cb(0) + } + } + })) + + await initMain() + let { send } = require(`electron`) - await main.eventHandlers.reconnect() expect(send.mock.calls.find(([type]) => type === `error`)).toBeUndefined() + while (!errorCB) { + await new Promise(resolve => setTimeout(resolve, 500)) + } errorCB(Buffer.from(`Gaiacli errord asynchronous`)) expect( @@ -525,8 +550,41 @@ describe(`Startup Process`, () => { }) describe(`Error handling on init`, () => { - // testFailingChildProcess("gaiacli", "init") - testFailingChildProcess(`gaiacli`, `rest-server`) + it(`should fail if there is a not handled error in the rest-server process`, async function() { + // TODO refactor standout on responses + jest.resetModules() + childProcessMock((path, args) => ({ + stdin: { write: () => {} }, + stdout: Object.assign({}, stdoutMocks(path, args), { once: () => {} }), + stderr: { + on: (type, cb) => { + if (args[0] === `rest-server` && type === `line`) { + cb(Buffer.from(`Some error`)) + } + }, + once: () => {} + }, + on: (type, cb) => { + if (args[0] === `init` && type === `exit`) { + cb(0) + } + if (args[0] === `rest-server` && type === `exit`) { + setImmediate(() => { + cb(1) + }) + } + if (args[0] === `keys` && args[1] === `delete` && type === `exit`) { + cb(0) + } + } + })) + let { send } = require(`electron`) + await require(appRoot + `src/main/index.js`) + + expect(send).toHaveBeenCalledWith(`error`, { + message: `The gaiacli rest-server (LCD) experienced an error:\nSome error` + }) + }) }) }) @@ -536,7 +594,7 @@ function mainSetup() { }) afterAll(async function() { - await main.shutdown() + // await main.shutdown() }) } @@ -544,33 +602,35 @@ function mainSetup() { function prepareMain() { // restart main with a now initialized state jest.resetModules() - childProcess = require(`child_process`) - // have the same mocked fs as main uses - // this is reset with jest.resetModules - fs = require(`fs-extra`) - const Raven = require(`raven`) - Raven.disableConsoleAlerts() - - jest.mock( - `app/src/main/addressbook.js`, - () => - class MockAddressbook { - async pickNode() { - return `127.0.0.1:46657` - } - flagNodeIncompatible() {} + childProcessMock((path, args) => ({ + stdin: { write: () => {} }, + stdout: stdoutMocks(path, args), + on: (type, cb) => { + if (args[0] === `init` && type === `exit`) { + cb(0) } - ) - - // mock the version check request - jest.mock(`axios`, () => ({ - get: async url => { - if (url.indexOf(`node_version`) !== -1) { - return { data: `0.13.0` } + if (args[0] === `rest-server` && type === `exit`) { + // needs to be deferred because the callback overrides a variable + setImmediate(() => { + cb(0) + }) + } + if (args[0] === `keys` && args[1] === `delete` && type === `exit`) { + cb(0) } } })) + childProcess = require(`child_process`) + jest.doMock(`renderer/connectors/lcdClient.js`, () => { + return () => ({ + nodeVersion: async () => `0.13.0` + }) + }) + + // have the same mocked fs as main uses + // this is reset with jest.resetModules + fs = require(`fs-extra`) } async function initMain() { @@ -584,8 +644,8 @@ async function initMain() { function testFailingChildProcess(name, cmd) { return it(`should fail if there is a not handled error in the ${name} ${cmd || ``} process`, async function() { - failingChildProcess(name, cmd) prepareMain() + failingChildProcess(name, cmd) let { send } = require(`electron`) await require(appRoot + `src/main/index.js`) @@ -606,33 +666,6 @@ function childProcessMock(mockExtend = () => ({})) { })) } -function failingChildProcess(mockName, mockCmd) { - childProcessMock((path, args) => ({ - on: (type, cb) => { - if (type === `exit`) { - if ( - path.includes(mockName) && - (mockCmd === undefined || args.find(x => x === mockCmd)) - ) { - cb(-1) - // init processes always should return with 0 - } else if (args.find(x => x === `init`)) { - cb(0) - } - } - }, - stdin: { write: () => {} }, - stdout: stdoutMocks(path, args), - stderr: { - on: (type, cb) => { - // type is always 'data' - cb(Buffer.from(`${mockName} produced an unexpected error`)) - }, - pipe: () => {} - } - })) -} - // sometime we want to simulate a sequential run of the UI // usualy we want to clean up all the modules after each run but in this case, we want to persist the mocked filesystem function resetModulesKeepingFS() { @@ -640,10 +673,6 @@ function resetModulesKeepingFS() { jest.resetModules() fs = require(`fs-extra`) fs.fs = fileSystem - - // we want to keep Raven quiet - const Raven = require(`raven`) - Raven.disableConsoleAlerts() } function mockConfig() { From f79de8b8e4b61bd62710e7570e9faf86af4a4692 Mon Sep 17 00:00:00 2001 From: Voyager Bot Date: Tue, 13 Nov 2018 10:00:36 +0100 Subject: [PATCH 16/42] fixed last test in main --- app/src/main/index.js | 1 + test/unit/specs/main.spec.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/index.js b/app/src/main/index.js index fbc7e22502..75b394c302 100644 --- a/app/src/main/index.js +++ b/app/src/main/index.js @@ -282,6 +282,7 @@ async function startLCD(home, nodeURL) { child.stdout.once(`line`, async line => { const certPath = /\(cert: "(.+?)"/.exec(line)[1] resolve({ ca: fs.readFileSync(certPath, `utf8`), process: child }) + lcdStarted = true }) child.stderr.on(`line`, error => { diff --git a/test/unit/specs/main.spec.js b/test/unit/specs/main.spec.js index 5f6c936a02..5bfd937a90 100644 --- a/test/unit/specs/main.spec.js +++ b/test/unit/specs/main.spec.js @@ -494,7 +494,7 @@ describe(`Startup Process`, () => { } })) - await initMain() + main = await require(appRoot + `src/main/index.js`) let { send } = require(`electron`) expect(send.mock.calls.find(([type]) => type === `error`)).toBeUndefined() From 059e7692c00f349b88ee3c8c8d829be1f90ac646 Mon Sep 17 00:00:00 2001 From: Voyager Bot Date: Tue, 13 Nov 2018 10:15:06 +0100 Subject: [PATCH 17/42] tests all passing --- app/src/renderer/connectors/lcdClient.js | 12 ++++++ test/unit/specs/lcdClient.spec.js | 38 +++++++++++++++++-- .../__snapshots__/delegation.spec.js.snap | 2 + 3 files changed, 48 insertions(+), 4 deletions(-) diff --git a/app/src/renderer/connectors/lcdClient.js b/app/src/renderer/connectors/lcdClient.js index 588d17f996..cf29e32201 100644 --- a/app/src/renderer/connectors/lcdClient.js +++ b/app/src/renderer/connectors/lcdClient.js @@ -197,6 +197,18 @@ const Client = (axios, localLcdURL, remoteLcdURL) => { }, submitDeposit: function(proposalId, data) { return req(`POST`, `/gov/proposals/${proposalId}/deposits`, true)(data) + }, + getGovernanceTxs: function(address) { + return Promise.all([ + req( + `GET`, + `/txs?tag=action=submit-proposal&proposer='${address}'`, + true + )(), + req(`GET`, `/txs?tag=action=deposit&depositer='${address}'`, true)() + ]).then(([depositerTxs, proposerTxs]) => + [].concat(depositerTxs, proposerTxs) + ) } } } diff --git a/test/unit/specs/lcdClient.spec.js b/test/unit/specs/lcdClient.spec.js index cd1a73a858..70f028bff7 100644 --- a/test/unit/specs/lcdClient.spec.js +++ b/test/unit/specs/lcdClient.spec.js @@ -283,16 +283,46 @@ describe(`LCD Client`, () => { ]) }) - it(`queries for a delegation summary for a delegator`, async () => { + it(`queries for a delegations of a delegator`, async () => { axios.mockReturnValue({}) - await client.getDelegator(`abc`) + await client.getDelegations(`abc`) expect(axios.mock.calls).toEqual([ [ { data: undefined, method: `GET`, - url: `http://remotehost/stake/delegators/abc` + url: `http://remotehost/stake/delegators/abc/delegations` + } + ] + ]) + }) + + it(`queries for a undelegations of a delegator`, async () => { + axios.mockReturnValue({}) + await client.getUndelegations(`abc`) + + expect(axios.mock.calls).toEqual([ + [ + { + data: undefined, + method: `GET`, + url: `http://remotehost/stake/delegators/abc/unbonding_delegations` + } + ] + ]) + }) + + it(`queries for a redelegations of a delegator`, async () => { + axios.mockReturnValue({}) + await client.getRedelegations(`abc`) + + expect(axios.mock.calls).toEqual([ + [ + { + data: undefined, + method: `GET`, + url: `http://remotehost/stake/delegators/abc/redelegations` } ] ]) @@ -699,7 +729,7 @@ describe(`LCD Client`, () => { { data: undefined, method: `GET`, - url: `http://remotehost/slashing/signing_info/pubKey` + url: `http://remotehost/slashing/validators/pubKey/signing_info` } ] ]) diff --git a/test/unit/specs/store/__snapshots__/delegation.spec.js.snap b/test/unit/specs/store/__snapshots__/delegation.spec.js.snap index 45922d4b64..5f73b0b729 100644 --- a/test/unit/specs/store/__snapshots__/delegation.spec.js.snap +++ b/test/unit/specs/store/__snapshots__/delegation.spec.js.snap @@ -12,12 +12,14 @@ Object { "balance": Object { "amount": "356.0000000000", }, + "creation_height": undefined, "min_time": undefined, }, "cosmosvaladdr15ky9du8a2wlstz6fpx3p4mqpjyrm5ctqzh8yqw": Object { "balance": Object { "amount": "113.0000000000", }, + "creation_height": undefined, "min_time": undefined, }, } From 8aed8dca7bf9ca6b19cc59a117cf9afb4070e70c Mon Sep 17 00:00:00 2001 From: Voyager Bot Date: Wed, 14 Nov 2018 12:50:07 +0100 Subject: [PATCH 18/42] working e2e test start --- app/src/main/index.js | 12 +- tasks/build/Gaia/COMMIT.sh | 2 +- tasks/build/local/build.js | 111 +++----------- tasks/gaiacli.js | 291 +++++++++++++++++++++++++++++++++++ test/e2e/launch.js | 305 ++++++++----------------------------- 5 files changed, 381 insertions(+), 340 deletions(-) create mode 100644 tasks/gaiacli.js diff --git a/app/src/main/index.js b/app/src/main/index.js index 75b394c302..13f7aa748b 100644 --- a/app/src/main/index.js +++ b/app/src/main/index.js @@ -611,11 +611,7 @@ const initLCD = async lcdHome => { const child = startProcess(NODE_BINARY_NAME, [ `init`, `--home`, - tempNodeDir, - `--home-client`, - lcdHome, - `--name`, - `default` + tempNodeDir ]) child.stdin.write(`1234567890\n`) @@ -719,9 +715,9 @@ async function main() { fs.writeFileSync(appVersionPath, pkg.version) } - if (!fs.existsSync(lcdHome)) { - await initLCD(lcdHome) - } + // if (!fs.existsSync(lcdHome)) { + // await initLCD(lcdHome) + // } await checkGaiaCompatibility(gaiacliVersionPath) diff --git a/tasks/build/Gaia/COMMIT.sh b/tasks/build/Gaia/COMMIT.sh index 10a4ca78c1..d3880e959e 100755 --- a/tasks/build/Gaia/COMMIT.sh +++ b/tasks/build/Gaia/COMMIT.sh @@ -2,5 +2,5 @@ # This is the commit of the SDK version to use for building Gaia. We use an # explicit hash instead of a tag so we don't have to trust GitHub. -export COMMIT=c7b3efdd02be2132f19c0ad4afc58b002edc73fe +export COMMIT=bb54a0de127e45713f272217f578c0abe53a5b21 diff --git a/tasks/build/local/build.js b/tasks/build/local/build.js index 139e685120..921eb390a2 100644 --- a/tasks/build/local/build.js +++ b/tasks/build/local/build.js @@ -7,7 +7,9 @@ const path = require(`path`) const homeDir = require(`os`).homedir() const appDir = path.resolve(__dirname + `/../../../`) -let { spawn, exec } = require(`child_process`) +let { exec } = require(`child_process`) + +let { initNode, createKey, initGenesis } = require(`../../gaia-wrapper.js`) const optionsSpecification = { overwrite: [`overwrite ~/.gaiad-testnet/`, false], @@ -39,9 +41,26 @@ cli(optionsSpecification, async options => { } } - await init(options, environment) - const { address } = await createKey(options, environment) - await initGenesis(options, environment, address) + const chainId = `local-testnet` + const moniker = `local` + const operatorKeyName = `local` + const clientHome = `./builds/testnets/local-testnet/lcd` + const nodeHome = `${homeDir}/.gaiad-testnet` + await initNode( + chainId, + moniker, + `${homeDir}/.gaiad-testnet`, + options.password, + options.overwrite + ) + const { address } = await createKey(`local`, options.password, clientHome) + await initGenesis( + options.password, + address, + nodeHome, + clientHome, + operatorKeyName + ) await moveFiles(options, environment) console.log(`\n 🎉 SUCCESS 🎉\n`) console.log( @@ -93,87 +112,3 @@ async function moveFiles(options, environment) { ) out && console.log(out) } - -function init(options, environment) { - return new Promise(async (resolve, reject) => { - let command = `builds/Gaia/${environment}/gaiad init --home ${homeDir}/.gaiad-testnet --moniker local --chain-id local-testnet` - if (options.overwrite) { - command += ` -o` - } - console.log(`$ ` + command) - const localnodeProcess = spawn(command, { shell: true }) - localnodeProcess.stdin.write(`${options.password}\n`) - localnodeProcess.stderr.pipe(process.stderr) - localnodeProcess.once(`exit`, code => { - code === 0 ? resolve() : reject() - }) - }) -} - -function createKey(options, environment) { - return new Promise(async (resolve, reject) => { - let command = `builds/Gaia/${environment}/gaiacli keys add local --home ./builds/testnets/local-testnet/lcd -o json` - console.log(`$ ` + command) - const child = spawn(command, { shell: true }) - - child.stdin.write(`${options.password}\n`) - child.stdin.write(`${options.password}\n`) - - child.stdout.once(`data`, data => { - resolve(JSON.parse(data)) - }) - - child.once(`exit`, code => { - code !== 0 && reject() - }) - }) -} - -async function initGenesis(options, environment, address) { - const genesisLocation = path.join( - homeDir, - `.gaiad-testnet/config`, - `genesis.json` - ) - let genesis = fs.readJSONSync(genesisLocation) - genesis.app_state.accounts = [ - { - address, - coins: [ - { - denom: `steak`, - amount: `150` - }, - { - denom: `localcoin`, - amount: `1000` - } - ] - } - ] - fs.writeJSONSync(genesisLocation, genesis) - - await new Promise((resolve, reject) => { - const child = spawn(`builds/Gaia/${environment}/gaiad`, [ - `gentx`, - `--name`, - `local`, - `--home`, - path.join(homeDir, `.gaiad-testnet`), - `--home-client`, - `./builds/testnets/local-testnet/lcd` - ]) - child.stderr.pipe(process.stderr) - child.stdin.write(`${options.password}\n`) - child.once(`exit`, code => { - code === 0 ? resolve() : reject() - }) - }) - - exec( - `builds/Gaia/${environment}/gaiad collect-gentxs --home ${path.join( - homeDir, - `.gaiad-testnet` - )}` - ) -} diff --git a/tasks/gaiacli.js b/tasks/gaiacli.js new file mode 100644 index 0000000000..f035a97fb5 --- /dev/null +++ b/tasks/gaiacli.js @@ -0,0 +1,291 @@ +const path = require(`path`) +const fs = require(`fs-extra`) +const { spawn, exec } = require(`child_process`) +let { sleep } = require(`../test/e2e/common.js`) + +const osFolderName = (function() { + switch (process.platform) { + case `win32`: + return `windows_amd64` + case `darwin`: + return `darwin_amd64` + case `linux`: + return `linux_amd64` + } +})() +let cliBinary = + process.env.BINARY_PATH || + path.join(__dirname, `../builds/Gaia/`, osFolderName, `gaiacli`) + +let nodeBinary = + process.env.NODE_BINARY_PATH || + path.join(__dirname, `../builds/Gaia/`, osFolderName, `gaiad`) +const defaultStartPort = 26656 + +module.exports.initNode = async function initNode( + chainId, + moniker, + homeDir, + password = `1234567890`, + overwrite = false +) { + let command = `${nodeBinary} init --home ${homeDir} --moniker ${moniker} --chain-id ${chainId}` + if (overwrite) { + command += ` -o` + } + await makeExecWithInputs(command, [password]) +} + +module.exports.createKey = async function createKey( + name, + password, + clientHomeDir +) { + let command = `${cliBinary} keys add ${name} --home ${clientHomeDir} -o json` + return makeExecWithInputs(command, [password, password]) +} + +module.exports.getKeys = async function getKeys(clientHomeDir) { + let command = `${cliBinary} keys list --home ${clientHomeDir} -o json` + return makeExec(command) +} + +module.exports.initGenesis = async function initGenesis( + password, + address, + homeDir, + clientHomeDir, + operatorKeyName +) { + const genesisLocation = path.join(homeDir, `config/genesis.json`) + let genesis = fs.readJSONSync(genesisLocation) + console.log( + `Adding tokens to genesis at ${genesisLocation} for address ${address}` + ) + genesis.app_state.accounts = genesis.app_state.accounts || [] + genesis.app_state.accounts.push({ + address, + coins: [ + { + denom: `steak`, + amount: `150` + }, + { + denom: `localcoin`, + amount: `1000` + } + ] + }) + fs.writeJSONSync(genesisLocation, genesis) + + await makeExecWithInputs( + `${nodeBinary} gentx --name ${operatorKeyName} --home ${homeDir} --home-client ${clientHomeDir}`, + [password] + ) + + await makeExec(`${nodeBinary} collect-gentxs --home ${homeDir}`) + + genesis = fs.readJSONSync(genesisLocation) + console.log(`X`, genesis) + return genesis +} + +module.exports.getGenesis = function getGenesis(homeDir) { + const genesisLocation = path.join(homeDir, `config/genesis.json`) + let genesis = fs.readJSONSync(genesisLocation) + return genesis +} + +module.exports.makeValidator = async function makeValidator( + nodeHome, + cliHome, + number, + accountName, // account name to sign delegation + address // address of that account with coins to delegate +) { + let newNodeHome = nodeHome + `_` + number + let newCliHome = cliHome + `_` + number + + let valPubKey = await module.exports.getValPubKey(newNodeHome) + await module.exports.sendTokens(newCliHome, `10steak`, accountName, address) + while (true) { + console.log(`Waiting for funds to delegate`) + try { + await sleep(1000) // TODO identify why this timeout is needed + await module.exports.getBalance(newCliHome, address) + } catch (err) { + console.error(err) + continue + } + break + } + await module.exports.declareValidator( + newCliHome, + `local_${number}`, + valPubKey, + address, + `local_${number}` + ) +} + +module.exports.getValPubKey = async function getValPubKey(node_home) { + let command = `${nodeBinary} tendermint show-validator --home ${node_home}` + const stdout = await makeExec(command) + return stdout.trim() +} +module.exports.getNodeId = async function getNodeId(node_home) { + let command = `${nodeBinary} tendermint show-node-id --home ${node_home}` + const stdout = await makeExec(command) + return stdout.trim() +} +module.exports.getBalance = async function getBalance(cliHome, address) { + let command = `${cliBinary} query account ${address} --home ${cliHome} --output "json" --trust-node` + const stdout = await makeExec(command) + return JSON.parse(stdout.trim()) +} +module.exports.declareValidator = async function declareValidator( + mainCliHome, + moniker, + valPubKey, + operatorAddress, + coinHolderAccountName +) { + let command = + `${cliBinary} tx create-validator` + + ` --home ${mainCliHome}` + + ` --from ${coinHolderAccountName}` + + ` --amount=10steak` + + ` --pubkey=${valPubKey}` + + ` --address-delegator=${operatorAddress}` + + ` --moniker="${moniker}"` + + ` --chain-id=test_chain` + + ` --commission-max-change-rate=0` + + ` --commission-max-rate=0` + + ` --commission-rate=0` + console.log(command) + const child = await spawn(command, { shell: true }) + child.stderr.pipe(process.stderr) + child.stdin.write(`1234567890\n`) // unlock signing key + return new Promise((resolve, reject) => { + child.stdout.once(`data`, resolve) + child.stderr.once(`data`, reject) + }) +} + +module.exports.sendTokens = async function sendTokens( + mainCliHome, + tokenString, + fromAccountName, + toAddress +) { + let command = + `${cliBinary} tx send` + + ` --home ${mainCliHome}` + + ` --from ${fromAccountName}` + + ` --amount=${tokenString}` + + ` --to=${toAddress}` + + ` --chain-id=test_chain` + console.log(command) + const child = await spawn(command, { shell: true }) + child.stderr.pipe(process.stderr) + child.stdin.write(`1234567890\n`) // unlock signing key + return new Promise((resolve, reject) => { + child.stdout.once(`data`, resolve) + child.stderr.once(`data`, reject) + }) +} + +// start a node and connect it to nodeOne +// nodeOne is used as a persistent peer for all the other nodes +// wait for blocks to show as a proof, the node is running correctly +module.exports.startLocalNode = function startLocalNode( + nodeHome, //prefix + number, + nodeOneId = `` +) { + return new Promise((resolve, reject) => { + const thisNodeHome = `${nodeHome}_${number}` + let command = `${nodeBinary} start --home ${thisNodeHome}` + if (number > 1) { + // setup different ports + command += ` --p2p.laddr=tcp://0.0.0.0:${defaultStartPort - + (number - 1) * 3} --address=tcp://0.0.0.0:${defaultStartPort - + (number - 1) * 3 + + 1} --rpc.laddr=tcp://0.0.0.0:${defaultStartPort - (number - 1) * 3 + 2}` + // set the first node as a persistent peer + command += ` --p2p.persistent_peers="${nodeOneId}@localhost:${defaultStartPort}"` + } + console.log(command) + const localnodeProcess = spawn(command, { shell: true }) + + // log output for debugging + const logPath = path.join(thisNodeHome, `process.log`) + console.log(`Redirecting node ` + number + ` output to ` + logPath) + fs.createFileSync(logPath) + let logStream = fs.createWriteStream(logPath, { flags: `a` }) + localnodeProcess.stdout.pipe(logStream) + + localnodeProcess.stderr.pipe(process.stderr) + + // wait 20s for the first block or assume the node has failed + const timeout = setTimeout(() => { + reject(`Timed out waiting for block for node ${number}`) + }, 20000) + + // wait for a message about a block being produced + function listener(data) { + let msg = data.toString() + + if (msg.includes(`Block{`)) { + localnodeProcess.stdout.removeListener(`data`, listener) + console.log(`Node ` + number + ` is running`) + clearTimeout(timeout) + resolve() + } + } + + console.log(`Waiting for first block on node ` + number) + localnodeProcess.stdout.on(`data`, listener) + + localnodeProcess.once(`exit`, reject) + }) +} + +function makeExec(command) { + console.log(`$ ` + command) + return new Promise((resolve, reject) => { + exec(command, (err, stdout, stderr) => { + if (err) return reject(err) + // if (stderr) return reject(stderr) + resolve(stdout) + }) + }) +} + +function makeExecWithInputs(command, inputs = []) { + console.log(`$ ` + command) + + let binary = command.split(` `)[0] + let args = command.split(` `).slice(1) + return new Promise((resolve, reject) => { + const child = spawn(binary, args) + child.stderr.pipe(process.stderr) + child.stdout.pipe(process.stdout) + inputs.forEach(input => { + child.stdin.write(`${input}\n`) + }) + + let resolved = false + child.stdout.once(`data`, data => { + if (resolved) return + resolved = true + resolve(JSON.parse(data)) + }) + + child.once(`exit`, code => { + if (resolved) return + resolved = true + code === 0 ? resolve() : reject(`Process exited with code ${code}`) + }) + }) +} diff --git a/test/e2e/launch.js b/test/e2e/launch.js index 692e4b6acd..5c7286d228 100644 --- a/test/e2e/launch.js +++ b/test/e2e/launch.js @@ -1,17 +1,23 @@ "use strict" -const { shell } = require(`@nodeguy/cli`) let { Application } = require(`spectron`) let test = require(`tape-promise/tape`) let electron = require(`electron`) let { join } = require(`path`) let { spawn } = require(`child_process`) -const util = require(`util`) -const exec = util.promisify(require(`child_process`).exec) let fs = require(`fs-extra`) -let { sleep } = require(`../e2e/common.js`) const testDir = join(__dirname, `../../testArtifacts`) +let { + initNode, + createKey, + getKeys, + initGenesis, + getGenesis, + startLocalNode, + makeValidator, + getNodeId +} = require(`../../tasks/gaiacli.js`) let app, cliHome, nodeHome, started, crashed @@ -55,36 +61,49 @@ function launch(t) { fs.removeSync(`testArtifacts`) // setup first node - const initValues = await initLocalNode(1) + await initLocalNode(nodeHome, 1) const nodeOneHome = nodeHome + `_1` const nodeOneCliHome = cliHome + `_1` - console.error(`ui home: ${cliHome}`) + const operatorKeyName = `testkey` + console.error(`ui home: ${nodeOneCliHome}`) console.error(`node home: ${nodeOneHome}`) - let genesis = fs.readJSONSync(join(nodeOneHome, `config/genesis.json`)) - fs.writeJSONSync(join(nodeOneCliHome, `genesis.json`), genesis) + + // let genesis = fs.readJSONSync(join(nodeOneHome, `config/genesis.json`)) + // fs.writeJSONSync(join(nodeOneCliHome, `genesis.json`), genesis) const nodeOneId = await getNodeId(nodeOneHome) reduceTimeouts(nodeOneHome) disableStrictAddressbook(nodeOneHome) await saveVersion(nodeHome + `_1`) - // get address to delegate staking tokens to 2nd and 3rd validator - let { address } = await getDefaultKey(nodeOneCliHome) + // create address to delegate staking tokens to 2nd and 3rd validator + let { address } = await createKey( + operatorKeyName, + `1234567890`, + nodeOneCliHome + ) + const genesis = await initGenesis( + `1234567890`, + address, + nodeOneHome, + nodeOneCliHome, + operatorKeyName + ) + // wait till the first node produces blocks - await startLocalNode(1) + await startLocalNode(nodeHome, 1) // setup additional nodes - await initSecondaryLocalNode(2, genesis, address) - await initSecondaryLocalNode(3, genesis, address) + await initSecondaryLocalNode(nodeHome, 2, genesis, address) + await initSecondaryLocalNode(nodeHome, 3, genesis, address) // wait until all nodes are showing blocks, so we know they are running - await startLocalNode(2, nodeOneId) - await startLocalNode(3, nodeOneId) + await startLocalNode(nodeHome, 2, nodeOneId) + await startLocalNode(nodeHome, 3, nodeOneId) console.log(`Started local nodes.`) // make our secondary nodes also to validators - // await sleep(2000) // TODO identify why this timeout is needed - await makeValidator(2) - await makeValidator(3) + await makeValidator(nodeHome, cliHome, 2, operatorKeyName, address) + await makeValidator(nodeHome, cliHome, 3, operatorKeyName, address) console.log(`Declared secondary nodes to be a validator.`) app = new Application({ @@ -105,7 +124,7 @@ function launch(t) { COSMOS_NETWORK: join(nodeOneHome, `config`), COSMOS_MOCKED: false, // the e2e tests expect mocking to be switched off BINARY_PATH: cliBinary, - LCD_URL: `http://localhost:9071`, + LCD_URL: `https://localhost:9071`, RPC_URL: `http://localhost:${defaultStartPort + 1}` } }) @@ -113,7 +132,7 @@ function launch(t) { await startApp(app) await stop(app) - let accounts = await setupAccounts(initValues) + let accounts = await setupAccounts(nodeOneCliHome, join(cliHome, `lcd`)) await startApp(app, `.tm-session-title=Sign In`) t.ok(app.isRunning(), `app is running`) @@ -142,11 +161,11 @@ test.onFinish(async () => { process.exit(0) }) -async function setupAccounts(initValues) { - let accounts = [] - // testkey account needs to match genesis to own tokens for testing - accounts.push(await createAccount(`testkey`, initValues.app_message.secret)) - accounts.push(await createAccount(`testreceiver`)) +async function setupAccounts(nodeOneClientDir, voyagerCLIDir) { + fs.copySync(nodeOneClientDir, voyagerCLIDir) + await createKey(`testreceiver`, `1234567890`, voyagerCLIDir) + + let accounts = await getKeys(voyagerCLIDir) console.log(`setup test accounts`, accounts) return accounts @@ -249,202 +268,25 @@ async function handleCrash(app, error) { } } -// start a node and connect it to nodeOne -// nodeOne is used as a persistent peer for all the other nodes -// wait for blocks to show as a proof, the node is running correctly -function startLocalNode(number, nodeOneId = ``) { - return new Promise((resolve, reject) => { - const thisNodeHome = `${nodeHome}_${number}` - let command = `${nodeBinary} start --home ${thisNodeHome}` - if (number > 1) { - // setup different ports - command += ` --p2p.laddr=tcp://0.0.0.0:${defaultStartPort - - (number - 1) * 3} --address=tcp://0.0.0.0:${defaultStartPort - - (number - 1) * 3 + - 1} --rpc.laddr=tcp://0.0.0.0:${defaultStartPort - (number - 1) * 3 + 2}` - // set the first node as a persistent peer - command += ` --p2p.persistent_peers="${nodeOneId}@localhost:${defaultStartPort}"` - } - console.log(command) - const localnodeProcess = spawn(command, { shell: true }) - - // log output for debugging - const logPath = join(thisNodeHome, `process.log`) - console.log(`Redirecting node ` + number + ` output to ` + logPath) - fs.createFileSync(logPath) - let logStream = fs.createWriteStream(logPath, { flags: `a` }) - localnodeProcess.stdout.pipe(logStream) - - localnodeProcess.stderr.pipe(process.stderr) - - // wait 20s for the first block or assume the node has failed - const timeout = setTimeout(() => { - reject(`Timed out waiting for block for node ${number}`) - }, 20000) - - // wait for a message about a block being produced - function listener(data) { - let msg = data.toString() - - if (msg.includes(`Block{`)) { - localnodeProcess.stdout.removeListener(`data`, listener) - console.log(`Node ` + number + ` is running`) - clearTimeout(timeout) - resolve() - } - } - - console.log(`Waiting for first block on node ` + number) - localnodeProcess.stdout.on(`data`, listener) - - localnodeProcess.once(`exit`, reject) - }) -} - -async function initLocalNode(number = 1) { +async function initLocalNode(nodeHome, number = 1) { const home = `${nodeHome}_${number}` - // this command stores the keys and address of the default account in a - // predictable ways - const command = `echo 1234567890 | ${nodeBinary} init \ - --home ${home} \ - --name local_${number} \ - --owk \ - --overwrite \ - --chain-id=test_chain \ - --home-client ${cliHome}_${number}` - - console.log(command) - const parsed = JSON.parse(await shell(command)) - - // Tendermint won't talk to nodes with the same IP address by default. We're - // running multiple nodes on localhost so we have to allow duplicate IP - // addresses. - const configPath = join(home, `config/config.toml`) - const config = fs.readFileSync(configPath, `utf8`) - - const newConfig = config.replace( - `[p2p]`, - `[p2p] -allow_duplicate_ip = true` - ) + await initNode(`test_chain`, `local_${number}`, home, `1234567890`, true) - fs.writeFileSync(configPath, newConfig) - return parsed + return getGenesis(home) } // init a node and define it as a validator -async function initSecondaryLocalNode(number, mainGenesis) { +async function initSecondaryLocalNode(nodeHome, number, mainGenesis) { let newNodeHome = nodeHome + `_` + number - await initLocalNode(number) + await initLocalNode(nodeHome, number) fs.writeJSONSync(join(newNodeHome, `config/genesis.json`), mainGenesis) reduceTimeouts(newNodeHome) disableStrictAddressbook(newNodeHome) } // declare candidacy for node -async function makeValidator(number) { - let newNodeHome = nodeHome + `_` + number - let newCliHome = cliHome + `_` + number - - let valPubKey = await getValPubKey(newNodeHome) - let { address } = await getDefaultKey(newCliHome) - await sendTokens(cliHome + `_1`, `10steak`, `local_1`, address) - while (true) { - console.log(`Waiting for funds to delegate`) - try { - await sleep(1000) // TODO identify why this timeout is needed - await getBalance(cliHome + `_1`, address) - } catch (err) { - continue - } - break - } - await declareValidator( - cliHome + `_` + number, - `local_${number}`, - valPubKey, - address, - `local_${number}` - ) -} - -async function getValPubKey(node_home) { - let command = `${nodeBinary} tendermint show-validator --home ${node_home}` - console.log(command) - const { stdout } = await exec(command) - return stdout.trim() -} -async function getNodeId(node_home) { - let command = `${nodeBinary} tendermint show-node-id --home ${node_home}` - console.log(command) - const { stdout } = await exec(command) - return stdout.trim() -} -async function getDefaultKey(cliHome) { - let command = `${cliBinary} keys list --home ${cliHome} --output "json"` - console.log(command) - const { stdout } = await exec(command) - return JSON.parse(stdout.trim())[0] -} -async function getBalance(cliHome, address) { - let command = `${cliBinary} query account ${address} --home ${cliHome} --output "json" --trust-node` - console.log(command) - const { stdout } = await exec(command) - return JSON.parse(stdout.trim()) -} -async function declareValidator( - mainCliHome, - moniker, - valPubKey, - operatorAddress, - coinHolderAccountName -) { - let command = - `${cliBinary} tx create-validator` + - ` --home ${mainCliHome}` + - ` --from ${coinHolderAccountName}` + - ` --amount=10steak` + - ` --pubkey=${valPubKey}` + - ` --address-delegator=${operatorAddress}` + - ` --moniker="${moniker}"` + - ` --chain-id=test_chain` + - ` --commission-max-change-rate=0` + - ` --commission-max-rate=0` + - ` --commission-rate=0` - console.log(command) - const child = await spawn(command, { shell: true }) - child.stderr.pipe(process.stderr) - child.stdin.write(`1234567890\n`) // unlock signing key - return new Promise((resolve, reject) => { - child.stdout.once(`data`, resolve) - child.stderr.once(`data`, reject) - }) -} - -async function sendTokens( - mainCliHome, - tokenString, - fromAccountName, - toAddress -) { - let command = - `${cliBinary} tx send` + - ` --home ${mainCliHome}` + - ` --from ${fromAccountName}` + - ` --amount=${tokenString}` + - ` --to=${toAddress}` + - ` --chain-id=test_chain` - console.log(command) - const child = await spawn(command, { shell: true }) - child.stderr.pipe(process.stderr) - child.stdin.write(`1234567890\n`) // unlock signing key - return new Promise((resolve, reject) => { - child.stdout.once(`data`, resolve) - child.stderr.once(`data`, reject) - }) -} function reduceTimeouts(nodeHome) { const configPath = join(nodeHome, `config`, `config.toml`) @@ -464,10 +306,20 @@ function reduceTimeouts(nodeHome) { .split(`\n`) .map(line => { let [key, value] = line.split(` = `) - if (timeouts.indexOf(key) !== -1) { - return `${key} = ${parseInt(value) / 10}` + + if (timeouts.indexOf(key) === -1) { + return line } - return line + + // timeouts are in the format "100ms" or "5s" + value = value.replace(/"/g, ``) + if (value.trim().endsWith(`ms`)) { + value = parseInt(value.trim().substr(0, value.length - 2)) + } else if (value.trim().endsWith(`s`)) { + value = parseInt(value.trim().substr(0, value.length - 1)) * 1000 + } + + return `${key} = "${value / 10}ms"` }) .join(`\n`) @@ -511,39 +363,6 @@ function saveVersion(nodeHome) { }) } -function createAccount(name, seed) { - return new Promise((resolve, reject) => { - let child = spawn( - cliBinary, - [ - `keys`, - `add`, - name, - seed ? `--recover` : null, - `--home`, - join(cliHome, `lcd`), - `--output`, - `json` - ].filter(x => x !== null) - ) - - child.stdout.once(`data`, data => { - let msg = data.toString() - - if (msg.startsWith(`{`)) { - resolve(JSON.parse(msg)) - } - }) - - child.stdin.write(`1234567890\n`) - seed && child.stdin.write(seed + `\n`) - child.stderr.pipe(process.stdout) - child.once(`exit`, code => { - if (code !== 0) reject() - }) - }) -} - module.exports = { getApp: launch, restart: async function(app, awaitingSelector = `.tm-session-title=Sign In`) { From 37e215ba5e59788921380a9d0994a5bb748d4e2c Mon Sep 17 00:00:00 2001 From: Voyager Bot Date: Wed, 14 Nov 2018 15:40:45 +0100 Subject: [PATCH 19/42] declaring validators works --- tasks/gaiacli.js | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/tasks/gaiacli.js b/tasks/gaiacli.js index f035a97fb5..b9c0cebe0d 100644 --- a/tasks/gaiacli.js +++ b/tasks/gaiacli.js @@ -100,19 +100,28 @@ module.exports.makeValidator = async function makeValidator( nodeHome, cliHome, number, - accountName, // account name to sign delegation - address // address of that account with coins to delegate + accountName // account name that has funds ) { let newNodeHome = nodeHome + `_` + number let newCliHome = cliHome + `_` + number let valPubKey = await module.exports.getValPubKey(newNodeHome) - await module.exports.sendTokens(newCliHome, `10steak`, accountName, address) + let { address: operatorAddress } = await module.exports.createKey( + `local`, + `1234567890`, + newCliHome + ) + await module.exports.sendTokens( + cliHome + `_1`, // main validator home with the key with funds + `10steak`, + accountName, + operatorAddress + ) while (true) { console.log(`Waiting for funds to delegate`) try { await sleep(1000) // TODO identify why this timeout is needed - await module.exports.getBalance(newCliHome, address) + await module.exports.getBalance(newCliHome, operatorAddress) } catch (err) { console.error(err) continue @@ -123,8 +132,8 @@ module.exports.makeValidator = async function makeValidator( newCliHome, `local_${number}`, valPubKey, - address, - `local_${number}` + operatorAddress, + `local` // key name that holds funds and is the same address as the operator address ) } @@ -148,28 +157,23 @@ module.exports.declareValidator = async function declareValidator( moniker, valPubKey, operatorAddress, - coinHolderAccountName + operatorAccountName // key name that holds funds and is the same address as the operator address ) { let command = `${cliBinary} tx create-validator` + ` --home ${mainCliHome}` + - ` --from ${coinHolderAccountName}` + + ` --from ${operatorAccountName}` + ` --amount=10steak` + ` --pubkey=${valPubKey}` + ` --address-delegator=${operatorAddress}` + - ` --moniker="${moniker}"` + + ` --moniker=${moniker}` + ` --chain-id=test_chain` + ` --commission-max-change-rate=0` + ` --commission-max-rate=0` + - ` --commission-rate=0` - console.log(command) - const child = await spawn(command, { shell: true }) - child.stderr.pipe(process.stderr) - child.stdin.write(`1234567890\n`) // unlock signing key - return new Promise((resolve, reject) => { - child.stdout.once(`data`, resolve) - child.stderr.once(`data`, reject) - }) + ` --commission-rate=0` + + ` --json` + + return makeExecWithInputs(command, [`1234567890`]) } module.exports.sendTokens = async function sendTokens( From 4b2db72e03492f99f60eb1792327d30e48503a9c Mon Sep 17 00:00:00 2001 From: Voyager Bot Date: Wed, 14 Nov 2018 15:59:24 +0100 Subject: [PATCH 20/42] all e2e tests passed --- tasks/gaiacli.js | 3 ++- test/e2e/wallet.js | 16 ++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/tasks/gaiacli.js b/tasks/gaiacli.js index b9c0cebe0d..f50e7b2a62 100644 --- a/tasks/gaiacli.js +++ b/tasks/gaiacli.js @@ -47,7 +47,8 @@ module.exports.createKey = async function createKey( module.exports.getKeys = async function getKeys(clientHomeDir) { let command = `${cliBinary} keys list --home ${clientHomeDir} -o json` - return makeExec(command) + let accounts = await makeExec(command) + return JSON.parse(accounts) } module.exports.initGenesis = async function initGenesis( diff --git a/test/e2e/wallet.js b/test/e2e/wallet.js index 2bad81ae45..e115e4fd54 100644 --- a/test/e2e/wallet.js +++ b/test/e2e/wallet.js @@ -43,7 +43,7 @@ test(`wallet`, async function(t) { await navigate(app, `Wallet`) await $(`#part-available-balances`) - .$(`.tm-li-dt=LOCAL_1TOKEN`) + .$(`.tm-li-dt=LOCALCOIN`) .$(`..`) .$(`..`) .click() @@ -55,14 +55,14 @@ test(`wallet`, async function(t) { let addressInput = () => $(`#send-address`) let amountInput = () => $(`#send-amount`) let defaultBalance = 1000.0 - t.test(`LOCAL_1TOKEN balance before sending`, async function(t) { + t.test(`LOCALCOIN balance before sending`, async function(t) { await app.client.waitForExist( `//span[contains(text(), "Send")]`, 15 * defaultBalance ) - let LOCAL_1TOKENEl = balanceEl(`LOCAL_1TOKEN`) - await waitForText(() => LOCAL_1TOKENEl, `1,000.0000000000`) + let LOCALCOINEl = balanceEl(`LOCALCOIN`) + await waitForText(() => LOCALCOINEl, `1,000.0000000000`) t.end() }) @@ -157,7 +157,7 @@ test(`wallet`, async function(t) { t.test(`own balance updated`, async function(t) { await navigate(app, `Wallet`) - let mycoinEl = () => balanceEl(`LOCAL_1TOKEN`) + let mycoinEl = () => balanceEl(`LOCALCOIN`) await waitForText(mycoinEl, `900.0000000000`, 10000) t.pass(`balance is reduced by 100`) t.end() @@ -167,18 +167,18 @@ test(`wallet`, async function(t) { }) t.test(`receive`, async function(t) { - t.test(`LOCAL_1TOKEN balance after receiving`, async function(t) { + t.test(`LOCALCOIN balance after receiving`, async function(t) { await restart(app) await login(app, `testreceiver`) await navigate(app, `Wallet`) - let LOCAL_1TOKENEl = () => balanceEl(`LOCAL_1TOKEN`) + let LOCALCOINEl = () => balanceEl(`LOCALCOIN`) await app.client.waitForExist( `//span[contains(text(), "Send")]`, 15 * 1000 ) - await waitForText(LOCAL_1TOKENEl, `100.0000000000`, 5000) + await waitForText(LOCALCOINEl, `100.0000000000`, 5000) t.pass(`received mycoin transaction`) t.end() }) From c057b927ce28810bfc7459bb98f7770c5bea5355 Mon Sep 17 00:00:00 2001 From: Voyager Bot Date: Wed, 14 Nov 2018 17:31:26 +0100 Subject: [PATCH 21/42] comments --- tasks/gaiacli.js | 4 ++++ test/e2e/launch.js | 3 +++ 2 files changed, 7 insertions(+) diff --git a/tasks/gaiacli.js b/tasks/gaiacli.js index f50e7b2a62..cfecc2095b 100644 --- a/tasks/gaiacli.js +++ b/tasks/gaiacli.js @@ -51,6 +51,7 @@ module.exports.getKeys = async function getKeys(clientHomeDir) { return JSON.parse(accounts) } +// init a genesis file with an account that has funds module.exports.initGenesis = async function initGenesis( password, address, @@ -97,6 +98,7 @@ module.exports.getGenesis = function getGenesis(homeDir) { return genesis } +// make it so that one initialized node will become a validator module.exports.makeValidator = async function makeValidator( nodeHome, cliHome, @@ -153,6 +155,8 @@ module.exports.getBalance = async function getBalance(cliHome, address) { const stdout = await makeExec(command) return JSON.parse(stdout.trim()) } + +// sends a create-validator tx module.exports.declareValidator = async function declareValidator( mainCliHome, moniker, diff --git a/test/e2e/launch.js b/test/e2e/launch.js index 5c7286d228..a6b667f922 100644 --- a/test/e2e/launch.js +++ b/test/e2e/launch.js @@ -162,7 +162,10 @@ test.onFinish(async () => { }) async function setupAccounts(nodeOneClientDir, voyagerCLIDir) { + // use the master account that holds funds from node 1 fs.copySync(nodeOneClientDir, voyagerCLIDir) + + // this account is later used to send funds to, to test token sending await createKey(`testreceiver`, `1234567890`, voyagerCLIDir) let accounts = await getKeys(voyagerCLIDir) From ced3b46601d2db5ee6abf654fa5237308ac10988 Mon Sep 17 00:00:00 2001 From: Voyager Bot Date: Wed, 14 Nov 2018 17:52:12 +0100 Subject: [PATCH 22/42] linted --- app/src/main/index.js | 54 ------------------------------------ tasks/gaiacli.js | 3 +- test/unit/specs/main.spec.js | 17 ------------ 3 files changed, 1 insertion(+), 73 deletions(-) diff --git a/app/src/main/index.js b/app/src/main/index.js index 13f7aa748b..db762a667b 100644 --- a/app/src/main/index.js +++ b/app/src/main/index.js @@ -10,7 +10,6 @@ let semver = require(`semver`) let Raven = require(`raven`) const readline = require(`readline`) let axios = require(`axios`) -const userHome = require(`user-home`) let pkg = require(`../../../package.json`) let addMenu = require(`./menu.js`) @@ -602,59 +601,6 @@ const checkGaiaCompatibility = async gaiacliVersionPath => { } } -const initLCD = async lcdHome => { - log(`initialising the LCD config dir`) - await new Promise((resolve, reject) => { - const NODE_BINARY_NAME = WIN ? `gaiad.exe` : `gaiad` - const tempNodeDir = join(lcdHome, `.temp_node_home`) - - const child = startProcess(NODE_BINARY_NAME, [ - `init`, - `--home`, - tempNodeDir - ]) - - child.stdin.write(`1234567890\n`) - - child.on(`exit`, code => { - if (code === 0) { - resolve() - } else { - reject() - } - - fs.remove(tempNodeDir) - }) - }) - - log(`deleting forced default account`) - // initLCD always needs to create one key, we don't want to confuse - // the user with this key, so we throw it away - await deleteKey(`default`, `1234567890`, lcdHome) -} - -const deleteKey = (name, password, lcdHome) => { - return new Promise((resolve, reject) => { - const child = startProcess(LCD_BINARY_NAME, [ - `keys`, - `delete`, - name, - `--home`, - lcdHome - ]) - - child.stdin.write(`${password}\n`) - - child.on(`exit`, code => { - if (code === 0) { - resolve() - } else { - reject() - } - }) - }) -} - async function main() { // we only enable error collection after users opted in Raven.config(``, { captureUnhandledRejections: false }).install() diff --git a/tasks/gaiacli.js b/tasks/gaiacli.js index cfecc2095b..26f1ab8819 100644 --- a/tasks/gaiacli.js +++ b/tasks/gaiacli.js @@ -263,9 +263,8 @@ module.exports.startLocalNode = function startLocalNode( function makeExec(command) { console.log(`$ ` + command) return new Promise((resolve, reject) => { - exec(command, (err, stdout, stderr) => { + exec(command, (err, stdout) => { if (err) return reject(err) - // if (stderr) return reject(stderr) resolve(stdout) }) }) diff --git a/test/unit/specs/main.spec.js b/test/unit/specs/main.spec.js index 5bfd937a90..91368fcf15 100644 --- a/test/unit/specs/main.spec.js +++ b/test/unit/specs/main.spec.js @@ -641,23 +641,6 @@ async function initMain() { return main } -function testFailingChildProcess(name, cmd) { - return it(`should fail if there is a not handled error in the ${name} ${cmd || - ``} process`, async function() { - prepareMain() - failingChildProcess(name, cmd) - let { send } = require(`electron`) - await require(appRoot + `src/main/index.js`) - - expect(send.mock.calls.find(([type]) => type === `error`)).toBeTruthy() - expect( - send.mock.calls - .find(([type]) => type === `error`)[1] - .message.toLowerCase() - ).toContain(name) - }) -} - function childProcessMock(mockExtend = () => ({})) { jest.doMock(`child_process`, () => ({ spawn: jest.fn((path, args) => From c4642fbd09418587c00675ff2f9561e16cfb3461 Mon Sep 17 00:00:00 2001 From: Voyager Bot Date: Fri, 16 Nov 2018 12:25:45 +0100 Subject: [PATCH 23/42] refactor --- app/src/renderer/connectors/lcdClient.js | 8 +- app/src/renderer/connectors/lcdClientMock.js | 4 +- tasks/build/local/build.js | 2 +- tasks/{gaiacli.js => gaia.js} | 151 +++++++++---------- test/e2e/launch.js | 118 +++++++-------- test/unit/specs/App.spec.js | 2 +- test/unit/specs/lcdClient.spec.js | 11 +- test/unit/specs/lcdClientMock.spec.js | 6 +- 8 files changed, 153 insertions(+), 149 deletions(-) rename tasks/{gaiacli.js => gaia.js} (66%) diff --git a/app/src/renderer/connectors/lcdClient.js b/app/src/renderer/connectors/lcdClient.js index 383e7dff3d..ef31fd6a61 100644 --- a/app/src/renderer/connectors/lcdClient.js +++ b/app/src/renderer/connectors/lcdClient.js @@ -213,10 +213,14 @@ const Client = (axios, localLcdURL, remoteLcdURL) => { return Promise.all([ req( `GET`, - `/txs?tag=action=submit-proposal&proposer='${address}'`, + `/txs?tag=action='submit-proposal'&tag=proposer='${address}'`, true )(), - req(`GET`, `/txs?tag=action=deposit&depositer='${address}'`, true)() + req( + `GET`, + `/txs?tag=action='deposit'&tag=depositer='${address}'`, + true + )() ]).then(([depositerTxs, proposerTxs]) => [].concat(depositerTxs, proposerTxs) ) diff --git a/app/src/renderer/connectors/lcdClientMock.js b/app/src/renderer/connectors/lcdClientMock.js index cc2f8ea1f9..ac81027fc8 100644 --- a/app/src/renderer/connectors/lcdClientMock.js +++ b/app/src/renderer/connectors/lcdClientMock.js @@ -771,8 +771,8 @@ module.exports = { } // check if there's an existing redelegation - let summary = this.getDelegator(tx.delegator_addr) - let red = summary.redelegations.find( + let redelegations = this.getRedelegations(tx.delegator_addr) + let red = redelegations.find( red => red.validator_src_addr === tx.validator_src_addr && red.validator_dst_addr === tx.validator_dst_addr diff --git a/tasks/build/local/build.js b/tasks/build/local/build.js index 921eb390a2..0c6522c3f1 100644 --- a/tasks/build/local/build.js +++ b/tasks/build/local/build.js @@ -9,7 +9,7 @@ const appDir = path.resolve(__dirname + `/../../../`) let { exec } = require(`child_process`) -let { initNode, createKey, initGenesis } = require(`../../gaia-wrapper.js`) +let { initNode, createKey, initGenesis } = require(`../../gaia.js`) const optionsSpecification = { overwrite: [`overwrite ~/.gaiad-testnet/`, false], diff --git a/tasks/gaiacli.js b/tasks/gaia.js similarity index 66% rename from tasks/gaiacli.js rename to tasks/gaia.js index 26f1ab8819..2ae9586a2b 100644 --- a/tasks/gaiacli.js +++ b/tasks/gaia.js @@ -22,7 +22,8 @@ let nodeBinary = path.join(__dirname, `../builds/Gaia/`, osFolderName, `gaiad`) const defaultStartPort = 26656 -module.exports.initNode = async function initNode( +// initialise the node config folder and genesis +async function initNode( chainId, moniker, homeDir, @@ -36,30 +37,25 @@ module.exports.initNode = async function initNode( await makeExecWithInputs(command, [password]) } -module.exports.createKey = async function createKey( - name, - password, - clientHomeDir -) { - let command = `${cliBinary} keys add ${name} --home ${clientHomeDir} -o json` +async function createKey({ keyName, password, clientHomeDir }) { + let command = `${cliBinary} keys add ${keyName} --home ${clientHomeDir} -o json` return makeExecWithInputs(command, [password, password]) } -module.exports.getKeys = async function getKeys(clientHomeDir) { +async function getKeys(clientHomeDir) { let command = `${cliBinary} keys list --home ${clientHomeDir} -o json` let accounts = await makeExec(command) return JSON.parse(accounts) } // init a genesis file with an account that has funds -module.exports.initGenesis = async function initGenesis( - password, - address, - homeDir, - clientHomeDir, - operatorKeyName +// creates a key to access this address in the clientHomeDir +async function initGenesis( + { keyName, password, clientHomeDir }, // operator sign info + address, // this address will have funds after initialization + nodeHomeDir ) { - const genesisLocation = path.join(homeDir, `config/genesis.json`) + const genesisLocation = path.join(nodeHomeDir, `config/genesis.json`) let genesis = fs.readJSONSync(genesisLocation) console.log( `Adding tokens to genesis at ${genesisLocation} for address ${address}` @@ -81,93 +77,86 @@ module.exports.initGenesis = async function initGenesis( fs.writeJSONSync(genesisLocation, genesis) await makeExecWithInputs( - `${nodeBinary} gentx --name ${operatorKeyName} --home ${homeDir} --home-client ${clientHomeDir}`, + `${nodeBinary} gentx --name ${keyName} --home ${nodeHomeDir} --home-client ${clientHomeDir}`, [password] ) - await makeExec(`${nodeBinary} collect-gentxs --home ${homeDir}`) + await makeExec(`${nodeBinary} collect-gentxs --home ${nodeHomeDir}`) genesis = fs.readJSONSync(genesisLocation) - console.log(`X`, genesis) return genesis } -module.exports.getGenesis = function getGenesis(homeDir) { +function getGenesis(homeDir) { const genesisLocation = path.join(homeDir, `config/genesis.json`) let genesis = fs.readJSONSync(genesisLocation) return genesis } // make it so that one initialized node will become a validator -module.exports.makeValidator = async function makeValidator( +// the operator of that validator needs to declare the validator +// therefor the operator needs funds to do initial staking +// therefor we need to send some tokens from another account to the operator account +async function makeValidator( + mainSignInfo, // main account that holds funds nodeHome, cliHome, - number, - accountName // account name that has funds + moniker, + operatorSignInfo = { + keyName: `local`, + password: `1234567890`, + clientHomeDir: cliHome + } ) { - let newNodeHome = nodeHome + `_` + number - let newCliHome = cliHome + `_` + number - - let valPubKey = await module.exports.getValPubKey(newNodeHome) - let { address: operatorAddress } = await module.exports.createKey( - `local`, - `1234567890`, - newCliHome - ) - await module.exports.sendTokens( - cliHome + `_1`, // main validator home with the key with funds - `10steak`, - accountName, - operatorAddress - ) + let valPubKey = await getValPubKey(nodeHome) + let { address: operatorAddress } = await createKey(operatorSignInfo) + await sendTokens(mainSignInfo, `10steak`, operatorAddress) while (true) { console.log(`Waiting for funds to delegate`) try { - await sleep(1000) // TODO identify why this timeout is needed - await module.exports.getBalance(newCliHome, operatorAddress) + await sleep(1000) + await getBalance(cliHome, operatorAddress) } catch (err) { - console.error(err) + console.error(err) // kept in here to see if something unexpected fails continue } break } - await module.exports.declareValidator( - newCliHome, - `local_${number}`, + await declareValidator( + operatorSignInfo, // key name that holds funds and is the same address as the operator address + moniker, valPubKey, - operatorAddress, - `local` // key name that holds funds and is the same address as the operator address + operatorAddress ) } -module.exports.getValPubKey = async function getValPubKey(node_home) { +async function getValPubKey(node_home) { let command = `${nodeBinary} tendermint show-validator --home ${node_home}` const stdout = await makeExec(command) return stdout.trim() } -module.exports.getNodeId = async function getNodeId(node_home) { +async function getNodeId(node_home) { let command = `${nodeBinary} tendermint show-node-id --home ${node_home}` const stdout = await makeExec(command) return stdout.trim() } -module.exports.getBalance = async function getBalance(cliHome, address) { +async function getBalance(cliHome, address) { let command = `${cliBinary} query account ${address} --home ${cliHome} --output "json" --trust-node` const stdout = await makeExec(command) return JSON.parse(stdout.trim()) } // sends a create-validator tx -module.exports.declareValidator = async function declareValidator( - mainCliHome, +async function declareValidator( + { keyName, password, clientHomeDir }, // operatorSignInfo moniker, valPubKey, - operatorAddress, - operatorAccountName // key name that holds funds and is the same address as the operator address + operatorAddress ) { let command = `${cliBinary} tx create-validator` + - ` --home ${mainCliHome}` + - ` --from ${operatorAccountName}` + + ` --home ${clientHomeDir}` + + ` --from ${keyName}` + ` --amount=10steak` + ` --pubkey=${valPubKey}` + ` --address-delegator=${operatorAddress}` + @@ -178,43 +167,34 @@ module.exports.declareValidator = async function declareValidator( ` --commission-rate=0` + ` --json` - return makeExecWithInputs(command, [`1234567890`]) + return makeExecWithInputs(command, [password]) } -module.exports.sendTokens = async function sendTokens( - mainCliHome, - tokenString, - fromAccountName, +async function sendTokens( + { keyName, password, clientHomeDir }, // senderSignInfo + tokenString, // like "10stake" <- amount followed by denomination toAddress ) { let command = `${cliBinary} tx send` + - ` --home ${mainCliHome}` + - ` --from ${fromAccountName}` + + ` --home ${clientHomeDir}` + + ` --from ${keyName}` + ` --amount=${tokenString}` + ` --to=${toAddress}` + ` --chain-id=test_chain` - console.log(command) - const child = await spawn(command, { shell: true }) - child.stderr.pipe(process.stderr) - child.stdin.write(`1234567890\n`) // unlock signing key - return new Promise((resolve, reject) => { - child.stdout.once(`data`, resolve) - child.stderr.once(`data`, reject) - }) + return makeExecWithInputs(command, [password], false) } // start a node and connect it to nodeOne // nodeOne is used as a persistent peer for all the other nodes // wait for blocks to show as a proof, the node is running correctly -module.exports.startLocalNode = function startLocalNode( - nodeHome, //prefix - number, +function startLocalNode( + nodeHome, + number, // number is used to prevent conflicting ports when running multiple nodes nodeOneId = `` ) { return new Promise((resolve, reject) => { - const thisNodeHome = `${nodeHome}_${number}` - let command = `${nodeBinary} start --home ${thisNodeHome}` + let command = `${nodeBinary} start --home ${nodeHome}` if (number > 1) { // setup different ports command += ` --p2p.laddr=tcp://0.0.0.0:${defaultStartPort - @@ -228,7 +208,7 @@ module.exports.startLocalNode = function startLocalNode( const localnodeProcess = spawn(command, { shell: true }) // log output for debugging - const logPath = path.join(thisNodeHome, `process.log`) + const logPath = path.join(nodeHome, `process.log`) console.log(`Redirecting node ` + number + ` output to ` + logPath) fs.createFileSync(logPath) let logStream = fs.createWriteStream(logPath, { flags: `a` }) @@ -260,6 +240,7 @@ module.exports.startLocalNode = function startLocalNode( }) } +// execute command and return stdout function makeExec(command) { console.log(`$ ` + command) return new Promise((resolve, reject) => { @@ -270,7 +251,8 @@ function makeExec(command) { }) } -function makeExecWithInputs(command, inputs = []) { +// execute command, write all inputs followed by enter to stdin and return stdout +function makeExecWithInputs(command, inputs = [], json = true) { console.log(`$ ` + command) let binary = command.split(` `)[0] @@ -287,7 +269,7 @@ function makeExecWithInputs(command, inputs = []) { child.stdout.once(`data`, data => { if (resolved) return resolved = true - resolve(JSON.parse(data)) + resolve(json ? JSON.parse(data) : data) }) child.once(`exit`, code => { @@ -297,3 +279,18 @@ function makeExecWithInputs(command, inputs = []) { }) }) } + +module.exports = { + initNode, + createKey, + getKeys, + initGenesis, + getGenesis, + startLocalNode, + makeValidator, + getNodeId, + + cliBinary, + nodeBinary, + defaultStartPort +} diff --git a/test/e2e/launch.js b/test/e2e/launch.js index a6b667f922..b599bd70a9 100644 --- a/test/e2e/launch.js +++ b/test/e2e/launch.js @@ -16,29 +16,14 @@ let { getGenesis, startLocalNode, makeValidator, - getNodeId -} = require(`../../tasks/gaiacli.js`) - -let app, cliHome, nodeHome, started, crashed - -const osFolderName = (function() { - switch (process.platform) { - case `win32`: - return `windows_amd64` - case `darwin`: - return `darwin_amd64` - case `linux`: - return `linux_amd64` - } -})() -let cliBinary = - process.env.BINARY_PATH || - join(__dirname, `../../builds/Gaia/`, osFolderName, `gaiacli`) + getNodeId, + + cliBinary, + nodeBinary, + defaultStartPort +} = require(`../../tasks/gaia.js`) -let nodeBinary = - process.env.NODE_BINARY_PATH || - join(__dirname, `../../builds/Gaia/`, osFolderName, `gaiad`) -const defaultStartPort = 26656 +let app, started, crashed /* * NOTE: don't use a global `let client = app.client` as the client object changes when restarting the app @@ -55,56 +40,64 @@ function launch(t) { console.log(`using cli binary`, cliBinary) console.log(`using node binary`, nodeBinary) - cliHome = join(testDir, `cli_home`) - nodeHome = join(testDir, `node_home`) + const cliHomePrefix = join(testDir, `cli_home`) + const nodeHomePrefix = join(testDir, `node_home`) fs.removeSync(`testArtifacts`) // setup first node - await initLocalNode(nodeHome, 1) - const nodeOneHome = nodeHome + `_1` - const nodeOneCliHome = cliHome + `_1` + const nodeOneHome = nodeHomePrefix + `_1` + const nodeOneCliHome = cliHomePrefix + `_1` const operatorKeyName = `testkey` console.error(`ui home: ${nodeOneCliHome}`) console.error(`node home: ${nodeOneHome}`) - // let genesis = fs.readJSONSync(join(nodeOneHome, `config/genesis.json`)) - // fs.writeJSONSync(join(nodeOneCliHome, `genesis.json`), genesis) + await initLocalNode(nodeOneHome, 1) const nodeOneId = await getNodeId(nodeOneHome) reduceTimeouts(nodeOneHome) disableStrictAddressbook(nodeOneHome) - await saveVersion(nodeHome + `_1`) + await saveVersion(nodeHomePrefix + `_1`) // create address to delegate staking tokens to 2nd and 3rd validator - let { address } = await createKey( - operatorKeyName, - `1234567890`, - nodeOneCliHome - ) + let mainAccountSignInfo = { + keyName: operatorKeyName, + password: `1234567890`, + clientHomeDir: nodeOneCliHome + } + let { address } = await createKey(mainAccountSignInfo) const genesis = await initGenesis( - `1234567890`, + mainAccountSignInfo, address, - nodeOneHome, - nodeOneCliHome, - operatorKeyName + nodeOneHome ) // wait till the first node produces blocks - await startLocalNode(nodeHome, 1) + await startLocalNode(nodeOneHome, 1) // setup additional nodes - await initSecondaryLocalNode(nodeHome, 2, genesis, address) - await initSecondaryLocalNode(nodeHome, 3, genesis, address) + await initSecondaryLocalNode(`${nodeHomePrefix}_2`, 2, genesis, address) + await initSecondaryLocalNode(`${nodeHomePrefix}_3`, 3, genesis, address) + // start secondary nodes and connect to node one // wait until all nodes are showing blocks, so we know they are running - await startLocalNode(nodeHome, 2, nodeOneId) - await startLocalNode(nodeHome, 3, nodeOneId) + await startLocalNode(`${nodeHomePrefix}_2`, 2, nodeOneId) + await startLocalNode(`${nodeHomePrefix}_3`, 3, nodeOneId) console.log(`Started local nodes.`) // make our secondary nodes also to validators - await makeValidator(nodeHome, cliHome, 2, operatorKeyName, address) - await makeValidator(nodeHome, cliHome, 3, operatorKeyName, address) - console.log(`Declared secondary nodes to be a validator.`) + await makeValidator( + mainAccountSignInfo, + `${nodeHomePrefix}_2`, + `${cliHomePrefix}_2`, + `local_2` + ) + await makeValidator( + mainAccountSignInfo, + `${nodeHomePrefix}_3`, + `${cliHomePrefix}_3`, + `local_3` + ) + console.log(`Declared secondary nodes to be validators.`) app = new Application({ path: electron, @@ -120,7 +113,7 @@ function launch(t) { NODE_ENV: `production`, PREVIEW: `true`, COSMOS_DEVTOOLS: 0, // open devtools will cause issues with spectron, you can open them later manually - COSMOS_HOME: cliHome, + COSMOS_HOME: cliHomePrefix, COSMOS_NETWORK: join(nodeOneHome, `config`), COSMOS_MOCKED: false, // the e2e tests expect mocking to be switched off BINARY_PATH: cliBinary, @@ -132,7 +125,11 @@ function launch(t) { await startApp(app) await stop(app) - let accounts = await setupAccounts(nodeOneCliHome, join(cliHome, `lcd`)) + // setup additional accounts for testing + let accounts = await setupAccounts( + nodeOneCliHome, + join(cliHomePrefix, `lcd`) + ) await startApp(app, `.tm-session-title=Sign In`) t.ok(app.isRunning(), `app is running`) @@ -145,7 +142,7 @@ function launch(t) { resolve({ app, - cliHome, + cliHomePrefix, accounts }) }) @@ -163,10 +160,15 @@ test.onFinish(async () => { async function setupAccounts(nodeOneClientDir, voyagerCLIDir) { // use the master account that holds funds from node 1 + // to use it, we copy the key database from node one to our Voyager cli config folde fs.copySync(nodeOneClientDir, voyagerCLIDir) // this account is later used to send funds to, to test token sending - await createKey(`testreceiver`, `1234567890`, voyagerCLIDir) + await createKey({ + keyName: `testreceiver`, + password: `1234567890`, + clientHomeDir: voyagerCLIDir + }) let accounts = await getKeys(voyagerCLIDir) console.log(`setup test accounts`, accounts) @@ -272,21 +274,17 @@ async function handleCrash(app, error) { } async function initLocalNode(nodeHome, number = 1) { - const home = `${nodeHome}_${number}` - - await initNode(`test_chain`, `local_${number}`, home, `1234567890`, true) + await initNode(`test_chain`, `local_${number}`, nodeHome, `1234567890`, true) - return getGenesis(home) + return getGenesis(nodeHome) } // init a node and define it as a validator async function initSecondaryLocalNode(nodeHome, number, mainGenesis) { - let newNodeHome = nodeHome + `_` + number - await initLocalNode(nodeHome, number) - fs.writeJSONSync(join(newNodeHome, `config/genesis.json`), mainGenesis) - reduceTimeouts(newNodeHome) - disableStrictAddressbook(newNodeHome) + fs.writeJSONSync(join(nodeHome, `config/genesis.json`), mainGenesis) + reduceTimeouts(nodeHome) + disableStrictAddressbook(nodeHome) } // declare candidacy for node diff --git a/test/unit/specs/App.spec.js b/test/unit/specs/App.spec.js index 5e45570cd6..52b7f56e85 100644 --- a/test/unit/specs/App.spec.js +++ b/test/unit/specs/App.spec.js @@ -57,7 +57,7 @@ describe(`App without analytics`, () => { }) let Node = require(`renderer/connectors/node.js`) require(`renderer/main.js`) - expect(Node).toHaveBeenCalledWith( + expect(Node.mock.calls[0].slice(1)).toEqual([ `https://localhost:8080`, `https://awesomenode.de:12345`, true diff --git a/test/unit/specs/lcdClient.spec.js b/test/unit/specs/lcdClient.spec.js index 35b08432e9..8476dadf81 100644 --- a/test/unit/specs/lcdClient.spec.js +++ b/test/unit/specs/lcdClient.spec.js @@ -575,7 +575,7 @@ describe(`LCD Client`, () => { it(`submits a new vote to a proposal`, async () => { axios.mockReturnValue({}) - await client.submitVote(proposals[0].proposal_id, votes[0]) + await client.submitProposalVote(proposals[0].proposal_id, votes[0]) expect(axios.mock.calls).toEqual([ [ @@ -590,7 +590,10 @@ describe(`LCD Client`, () => { it(`submits a new deposit to a proposal`, async () => { axios.mockReturnValue({}) - await client.submitDeposit(proposals[0].proposal_id, deposits[0]) + await client.submitProposalDeposit( + proposals[0].proposal_id, + deposits[0] + ) expect(axios.mock.calls).toEqual([ [ @@ -612,7 +615,7 @@ describe(`LCD Client`, () => { { data: undefined, method: `GET`, - url: `http://remotehost/txs?tag=action=submit-proposal&proposer='${ + url: `http://remotehost/txs?tag=action='submit-proposal'&tag=proposer='${ lcdClientMock.addresses[0] }'` } @@ -621,7 +624,7 @@ describe(`LCD Client`, () => { { data: undefined, method: `GET`, - url: `http://remotehost/txs?tag=action=deposit&depositer='${ + url: `http://remotehost/txs?tag=action='deposit'&tag=depositer='${ lcdClientMock.addresses[0] }'` } diff --git a/test/unit/specs/lcdClientMock.spec.js b/test/unit/specs/lcdClientMock.spec.js index cb3bdc8899..66ed7a4835 100644 --- a/test/unit/specs/lcdClientMock.spec.js +++ b/test/unit/specs/lcdClientMock.spec.js @@ -801,8 +801,10 @@ describe(`LCD Client Mock`, () => { ] }) - let summary = await client.getDelegator(lcdClientMock.addresses[0]) - expect(summary.redelegations[0].balance.amount).toBe(`10`) + let redelegations = await client.getRedelegations( + lcdClientMock.addresses[0] + ) + expect(redelegations[0].balance.amount).toBe(`10`) }) it(`queries for staking txs`, async () => { From 2c29168bd192cb9c0f5b08ebb3e0879a435245cb Mon Sep 17 00:00:00 2001 From: Voyager Bot Date: Fri, 16 Nov 2018 12:55:39 +0100 Subject: [PATCH 24/42] refactors --- app/src/main/index.js | 2 ++ app/src/renderer/main.js | 7 ++++++- package.json | 1 - tasks/gaia.js | 2 +- tasks/testnet.js | 37 +++---------------------------------- 5 files changed, 12 insertions(+), 37 deletions(-) diff --git a/app/src/main/index.js b/app/src/main/index.js index 336e168eba..c02b145a63 100644 --- a/app/src/main/index.js +++ b/app/src/main/index.js @@ -482,6 +482,8 @@ async function pickAndConnect() { return } + // make the ca available to the view + global.config.ca = gaiaLite.ca const axiosInstance = axios.create({ httpsAgent: new https.Agent({ ca: gaiaLite.ca }) }) diff --git a/app/src/renderer/main.js b/app/src/renderer/main.js index 30d6f558bb..ad844407c5 100644 --- a/app/src/renderer/main.js +++ b/app/src/renderer/main.js @@ -13,6 +13,7 @@ import App from "./App" import routes from "./routes" import Node from "./connectors/node" import Store from "./vuex/store" +const https = require(`https`) const config = remote.getGlobal(`config`) @@ -71,7 +72,11 @@ async function main() { // TODO get from process.env let localLcdURL = `https://localhost:${lcdPort}` console.log(`Expecting lcd-server on port: ` + lcdPort) - node = Node(axios, localLcdURL, config.node_lcd, config.mocked) + + const axiosInstance = axios.create({ + httpsAgent: new https.Agent({ ca: config.ca }) + }) + node = Node(axiosInstance, localLcdURL, config.node_lcd, config.mocked) store = Store({ node }) store.dispatch(`loadTheme`) diff --git a/package.json b/package.json index 8dcd0d626f..9b44dfc228 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,6 @@ "build:testnets": "cd tasks/build/testnets && ./localBuild.sh", "build:gaia": "cd tasks/build/Gaia && ./localBuild.sh", "build:local": "node tasks/build/local/build", - "local": "yarn run testnet local", "start": "node tasks/testnet.js", "testnet": "echo \"'yarn testnet' has been deprecated. Please use 'yarn start'\"", "lint": "yarn lint:eslint && yarn lint:format", diff --git a/tasks/gaia.js b/tasks/gaia.js index 2ae9586a2b..4954584ab8 100644 --- a/tasks/gaia.js +++ b/tasks/gaia.js @@ -190,7 +190,7 @@ async function sendTokens( // wait for blocks to show as a proof, the node is running correctly function startLocalNode( nodeHome, - number, // number is used to prevent conflicting ports when running multiple nodes + number = 1, // number is used to prevent conflicting ports when running multiple nodes nodeOneId = `` ) { return new Promise((resolve, reject) => { diff --git a/tasks/testnet.js b/tasks/testnet.js index a5d41f476f..fc92ccaa47 100644 --- a/tasks/testnet.js +++ b/tasks/testnet.js @@ -3,9 +3,8 @@ let runDev = require(`./runner.js`) let config = require(`../app/src/config.js`) const path = require(`path`) -const childProcess = require(`child_process`) const userHome = require(`user-home`) -const fs = require(`fs-extra`) +const { startLocalNode } = require(`./gaia.js`) async function main() { const network = process.argv[2] || config.default_network @@ -17,7 +16,8 @@ async function main() { LCD_URL: `https://localhost:9070`, RPC_URL: `http://localhost:26657` } - startLocalNode() + const TESTNET_NODE_FOLDER = path.join(userHome, `.gaiad-testnet`) + startLocalNode(TESTNET_NODE_FOLDER) } // run Voyager in a development environment @@ -33,34 +33,3 @@ async function main() { main().catch(function(err) { console.error(`Starting the application failed`, err) }) - -async function startLocalNode() { - const TESTNET_NODE_FOLDER = path.join(userHome, `.gaiad-testnet`) - const osFolderName = { - win32: `windows_amd64`, - darwin: `darwin_amd64`, - linux: `linux_amd64` - }[process.platform] - const gaiadFileName = process.platform === `win32` ? `gaiad.exe` : `gaiad` - const gaiadPath = path.join(`./builds/Gaia`, osFolderName, gaiadFileName) - - console.log(`Starting local node`) - let child = childProcess.spawn(gaiadPath, [ - `start`, - `--home`, - TESTNET_NODE_FOLDER - ]) - - // log output - const PROCESS_LOG = path.join(TESTNET_NODE_FOLDER, `process.log`) - const log = fs.createWriteStream(PROCESS_LOG, { flags: `a` }) - console.log(`Find the node process logs at: ${PROCESS_LOG}`) - child.stdout.pipe(log) - child.stderr.pipe(process.stderr) - - // handle node crashed - child.on(`exit`, () => { - console.error(`Local node crashed`) - process.exit() - }) -} From 72fabaa9def6da833530c4347710c0462c56f282 Mon Sep 17 00:00:00 2001 From: Voyager Bot Date: Fri, 16 Nov 2018 13:04:06 +0100 Subject: [PATCH 25/42] reverted to axios proxy --- app/src/renderer/connectors/node.js | 43 +++++++++++++++++++++++++++-- app/src/renderer/main.js | 7 +---- 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/app/src/renderer/connectors/node.js b/app/src/renderer/connectors/node.js index 88579ed521..e5f322ad50 100644 --- a/app/src/renderer/connectors/node.js +++ b/app/src/renderer/connectors/node.js @@ -1,11 +1,50 @@ "use strict" +const { ipcRenderer } = require(`electron`) const RestClient = require(`./lcdClient.js`) const mockedRestClient = require(`./lcdClientMock.js`) const RpcWrapper = require(`./rpcWrapper.js`) const MockedRpcWrapper = require(`./rpcWrapperMock.js`) -module.exports = function(axios, localLcdURL, remoteLcdURL, mocked = false) { +// Proxy requests to Axios through the main process because we need +// Node.js in order to support self-signed TLS certificates. +const AxiosProxy = () => { + let requestCounter = 0 + + return options => + new Promise((resolve, reject) => { + requestCounter++ + + if (requestCounter === Number.MAX_SAFE_INTEGER) { + requestCounter = 0 + } + + const channel = `Axios/${requestCounter}` + + console.log(`Request ${options.method.toUpperCase()} ${options.url}`) + ipcRenderer.once(channel, (event, { exception, value }) => { + ipcRenderer.removeAllListeners(channel) + + if (exception) { + console.error( + `Request ${options.method.toUpperCase()} ${options.url} failed`, + exception + ) + reject(exception) + } else { + console.log( + `Request ${options.method.toUpperCase()} ${options.url} successful`, + value.data + ) + resolve(value) + } + }) + + ipcRenderer.send(`Axios`, requestCounter, options) + }) +} + +module.exports = function(localLcdURL, remoteLcdURL, mocked = false) { let connector = { mocked, localLcdURL, @@ -15,7 +54,7 @@ module.exports = function(axios, localLcdURL, remoteLcdURL, mocked = false) { console.log(`Setting connector to state:` + (mocked ? `mocked` : `live`)) let newRestClient = mocked ? mockedRestClient - : new RestClient(axios, localLcdURL, remoteLcdURL) + : new RestClient(AxiosProxy(), localLcdURL, remoteLcdURL) let newRpcClient = mocked ? MockedRpcWrapper(connector) : RpcWrapper(connector) diff --git a/app/src/renderer/main.js b/app/src/renderer/main.js index ad844407c5..6819c8493a 100644 --- a/app/src/renderer/main.js +++ b/app/src/renderer/main.js @@ -1,6 +1,5 @@ "use strict" -import axios from "axios" import Vue from "vue" import Electron from "vue-electron" import Router from "vue-router" @@ -13,7 +12,6 @@ import App from "./App" import routes from "./routes" import Node from "./connectors/node" import Store from "./vuex/store" -const https = require(`https`) const config = remote.getGlobal(`config`) @@ -73,10 +71,7 @@ async function main() { let localLcdURL = `https://localhost:${lcdPort}` console.log(`Expecting lcd-server on port: ` + lcdPort) - const axiosInstance = axios.create({ - httpsAgent: new https.Agent({ ca: config.ca }) - }) - node = Node(axiosInstance, localLcdURL, config.node_lcd, config.mocked) + node = Node(localLcdURL, config.node_lcd, config.mocked) store = Store({ node }) store.dispatch(`loadTheme`) From e198f286bc60208372488c04fadfc31ec85ff19c Mon Sep 17 00:00:00 2001 From: Voyager Bot Date: Fri, 16 Nov 2018 13:05:47 +0100 Subject: [PATCH 26/42] fixed refactor issues --- tasks/build/local/build.js | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/tasks/build/local/build.js b/tasks/build/local/build.js index 0c6522c3f1..7518ff2cf7 100644 --- a/tasks/build/local/build.js +++ b/tasks/build/local/build.js @@ -43,9 +43,13 @@ cli(optionsSpecification, async options => { const chainId = `local-testnet` const moniker = `local` - const operatorKeyName = `local` const clientHome = `./builds/testnets/local-testnet/lcd` const nodeHome = `${homeDir}/.gaiad-testnet` + const defaultAccountInfo = { + keyName: `local`, + password: options.password, + clientHomeDir: clientHome + } await initNode( chainId, moniker, @@ -53,14 +57,8 @@ cli(optionsSpecification, async options => { options.password, options.overwrite ) - const { address } = await createKey(`local`, options.password, clientHome) - await initGenesis( - options.password, - address, - nodeHome, - clientHome, - operatorKeyName - ) + const { address } = await createKey(defaultAccountInfo) + await initGenesis(defaultAccountInfo, address, nodeHome) await moveFiles(options, environment) console.log(`\n 🎉 SUCCESS 🎉\n`) console.log( @@ -68,8 +66,8 @@ cli(optionsSpecification, async options => { yarn start local-testnet Default account: - username: 'local' - password: '1234567890' + username: '${defaultAccountInfo.keyName}' + password: '${defaultAccountInfo.password}' ` ) } catch (error) { From f81da319865e1e958d21226d255d7fe231956a1d Mon Sep 17 00:00:00 2001 From: Voyager Bot Date: Fri, 16 Nov 2018 13:05:47 +0100 Subject: [PATCH 27/42] fixed refactor issues --- tasks/build/local/build.js | 20 +++++++++----------- test/unit/specs/App.spec.js | 4 ++-- test/unit/specs/node.spec.js | 6 +++--- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/tasks/build/local/build.js b/tasks/build/local/build.js index 0c6522c3f1..7518ff2cf7 100644 --- a/tasks/build/local/build.js +++ b/tasks/build/local/build.js @@ -43,9 +43,13 @@ cli(optionsSpecification, async options => { const chainId = `local-testnet` const moniker = `local` - const operatorKeyName = `local` const clientHome = `./builds/testnets/local-testnet/lcd` const nodeHome = `${homeDir}/.gaiad-testnet` + const defaultAccountInfo = { + keyName: `local`, + password: options.password, + clientHomeDir: clientHome + } await initNode( chainId, moniker, @@ -53,14 +57,8 @@ cli(optionsSpecification, async options => { options.password, options.overwrite ) - const { address } = await createKey(`local`, options.password, clientHome) - await initGenesis( - options.password, - address, - nodeHome, - clientHome, - operatorKeyName - ) + const { address } = await createKey(defaultAccountInfo) + await initGenesis(defaultAccountInfo, address, nodeHome) await moveFiles(options, environment) console.log(`\n 🎉 SUCCESS 🎉\n`) console.log( @@ -68,8 +66,8 @@ cli(optionsSpecification, async options => { yarn start local-testnet Default account: - username: 'local' - password: '1234567890' + username: '${defaultAccountInfo.keyName}' + password: '${defaultAccountInfo.password}' ` ) } catch (error) { diff --git a/test/unit/specs/App.spec.js b/test/unit/specs/App.spec.js index 52b7f56e85..3c744b7800 100644 --- a/test/unit/specs/App.spec.js +++ b/test/unit/specs/App.spec.js @@ -57,11 +57,11 @@ describe(`App without analytics`, () => { }) let Node = require(`renderer/connectors/node.js`) require(`renderer/main.js`) - expect(Node.mock.calls[0].slice(1)).toEqual([ + expect(Node).toHaveBeenCalledWith( `https://localhost:8080`, `https://awesomenode.de:12345`, true - ]) + ) jest.resetModules() }) diff --git a/test/unit/specs/node.spec.js b/test/unit/specs/node.spec.js index 4b928ddffa..5b0aeea90f 100644 --- a/test/unit/specs/node.spec.js +++ b/test/unit/specs/node.spec.js @@ -33,19 +33,19 @@ describe(`Connector`, () => { }) it(`should hold the lcdPort`, () => { - let node = Node(axios, localLcdURL, remoteLcdURL) + let node = Node(localLcdURL, remoteLcdURL) expect(node.remoteLcdURL).toBe(remoteLcdURL) expect(node.localLcdURL).toBe(localLcdURL) }) it(`should setup the connectors`, () => { - let node = Node(axios, localLcdURL, remoteLcdURL) + let node = Node(localLcdURL, remoteLcdURL) expect(node.fooRpc).toBe(`rpcBar`) expect(node.fooLcd()).toBe(`lcdBar`) }) it(`should setup the mock connectors`, () => { - let node = Node(axios, localLcdURL, remoteLcdURL, true) + let node = Node(localLcdURL, remoteLcdURL, true) expect(node.fooRpc).toBe(`rpcBarMock`) expect(node.fooLcd()).toBe(`lcdBarMock`) }) From 402c1377fa7c837f3278cd8b7dd544f47d4f194d Mon Sep 17 00:00:00 2001 From: Voyager Bot Date: Fri, 16 Nov 2018 14:47:49 +0100 Subject: [PATCH 28/42] linted --- test/unit/specs/node.spec.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/unit/specs/node.spec.js b/test/unit/specs/node.spec.js index 5b0aeea90f..f8baca9f6c 100644 --- a/test/unit/specs/node.spec.js +++ b/test/unit/specs/node.spec.js @@ -1,13 +1,10 @@ let Node describe(`Connector`, () => { - let axios const remoteLcdURL = `http://awesomenode.de:12345` const localLcdURL = `https://localhost:9876` beforeAll(() => { - axios = jest.fn() - jest.mock( `renderer/connectors/lcdClient`, () => From 16992b4f33ed976ca4f4d2ddefbc51beeb2f5d75 Mon Sep 17 00:00:00 2001 From: Voyager Bot Date: Fri, 16 Nov 2018 15:03:46 +0100 Subject: [PATCH 29/42] skip using url for communicating lcdPort --- app/src/main/index.js | 6 +----- app/src/renderer/main.js | 15 +-------------- test/unit/specs/App.spec.js | 4 +++- 3 files changed, 5 insertions(+), 20 deletions(-) diff --git a/app/src/main/index.js b/app/src/main/index.js index c02b145a63..846ca19b9e 100644 --- a/app/src/main/index.js +++ b/app/src/main/index.js @@ -149,7 +149,7 @@ function createWindow() { }) // start vue app - mainWindow.loadURL(winURL + `?lcd_port=` + LCD_PORT) + mainWindow.loadURL(winURL) mainWindow.on(`closed`, shutdown) @@ -665,10 +665,6 @@ async function main() { fs.writeFileSync(appVersionPath, pkg.version) } - // if (!fs.existsSync(lcdHome)) { - // await initLCD(lcdHome) - // } - await checkGaiaCompatibility(gaiacliVersionPath) // read chainId from genesis.json diff --git a/app/src/renderer/main.js b/app/src/renderer/main.js index 6819c8493a..a558b32837 100644 --- a/app/src/renderer/main.js +++ b/app/src/renderer/main.js @@ -66,8 +66,7 @@ Vue.directive(`focus`, { }) async function main() { - let lcdPort = getQueryParameter(`lcd_port`) - // TODO get from process.env + let lcdPort = config.development ? config.lcd_port : config.lcd_port_prod let localLcdURL = `https://localhost:${lcdPort}` console.log(`Expecting lcd-server on port: ` + lcdPort) @@ -139,15 +138,3 @@ main() module.exports.store = store module.exports.node = node module.exports.router = router - -function getQueryParameter(name) { - let queryString = window.location.search.substring(1) - let pairs = queryString - .split(`&`) - .map(pair => pair.split(`=`)) - .filter(pair => pair[0] === name) - if (pairs.length > 0) { - return pairs[0][1] - } - return null -} diff --git a/test/unit/specs/App.spec.js b/test/unit/specs/App.spec.js index 3c744b7800..43be08d3da 100644 --- a/test/unit/specs/App.spec.js +++ b/test/unit/specs/App.spec.js @@ -53,7 +53,9 @@ describe(`App without analytics`, () => { electron.remote.getGlobal = () => ({ env: { NODE_ENV: `test` }, mocked: true, - node_lcd: `https://awesomenode.de:12345` + node_lcd: `https://awesomenode.de:12345`, + development: false, + lcd_port_prod: `8080` }) let Node = require(`renderer/connectors/node.js`) require(`renderer/main.js`) From 2e4af2b48d6d6453aa2edefac79caf2b78d675b1 Mon Sep 17 00:00:00 2001 From: Voyager Bot Date: Fri, 16 Nov 2018 15:04:40 +0100 Subject: [PATCH 30/42] removed ratTo when not needed --- app/src/renderer/vuex/modules/delegates.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/src/renderer/vuex/modules/delegates.js b/app/src/renderer/vuex/modules/delegates.js index 15338760c6..460f98ef30 100644 --- a/app/src/renderer/vuex/modules/delegates.js +++ b/app/src/renderer/vuex/modules/delegates.js @@ -80,10 +80,8 @@ export default ({ node }) => { // the tokens and shares are currently served in a weird format that is a amino representation of a float value validators = validators.map(validator => { return Object.assign(JSON.parse(JSON.stringify(validator)), { - tokens: ratToBigNumber(validator.tokens).toString(), - delegator_shares: ratToBigNumber( - validator.delegator_shares - ).toString() + tokens: validator.tokens, + delegator_shares: validator.delegator_shares }) }) From 668514343f11ace9a553f3ef8a7abe41fe91ae98 Mon Sep 17 00:00:00 2001 From: Voyager Bot Date: Fri, 16 Nov 2018 15:40:12 +0100 Subject: [PATCH 31/42] added catching --- tasks/gaia.js | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/tasks/gaia.js b/tasks/gaia.js index 4954584ab8..584c4d6969 100644 --- a/tasks/gaia.js +++ b/tasks/gaia.js @@ -258,25 +258,29 @@ function makeExecWithInputs(command, inputs = [], json = true) { let binary = command.split(` `)[0] let args = command.split(` `).slice(1) return new Promise((resolve, reject) => { - const child = spawn(binary, args) - child.stderr.pipe(process.stderr) - child.stdout.pipe(process.stdout) - inputs.forEach(input => { - child.stdin.write(`${input}\n`) - }) + try { + const child = spawn(binary, args) + child.stderr.pipe(process.stderr) + child.stdout.pipe(process.stdout) + inputs.forEach(input => { + child.stdin.write(`${input}\n`) + }) - let resolved = false - child.stdout.once(`data`, data => { - if (resolved) return - resolved = true - resolve(json ? JSON.parse(data) : data) - }) + let resolved = false + child.stdout.once(`data`, data => { + if (resolved) return + resolved = true + resolve(json ? JSON.parse(data) : data) + }) - child.once(`exit`, code => { - if (resolved) return - resolved = true - code === 0 ? resolve() : reject(`Process exited with code ${code}`) - }) + child.once(`exit`, code => { + if (resolved) return + resolved = true + code === 0 ? resolve() : reject(`Process exited with code ${code}`) + }) + } catch (err) { + reject(err) + } }) } From ed72c2a078ae1cdd3c75e01d9fb26f572df61c2b Mon Sep 17 00:00:00 2001 From: Voyager Bot Date: Fri, 16 Nov 2018 15:47:00 +0100 Subject: [PATCH 32/42] added logging --- tasks/gaia.js | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/tasks/gaia.js b/tasks/gaia.js index 584c4d6969..c1cd38ef9d 100644 --- a/tasks/gaia.js +++ b/tasks/gaia.js @@ -258,29 +258,29 @@ function makeExecWithInputs(command, inputs = [], json = true) { let binary = command.split(` `)[0] let args = command.split(` `).slice(1) return new Promise((resolve, reject) => { - try { - const child = spawn(binary, args) - child.stderr.pipe(process.stderr) - child.stdout.pipe(process.stdout) - inputs.forEach(input => { - child.stdin.write(`${input}\n`) - }) + const child = spawn(binary, args) + child.stderr.on(`error`, console.error) + child.stdout.on(`error`, console.error) + child.stdin.on(`error`, console.error) - let resolved = false - child.stdout.once(`data`, data => { - if (resolved) return - resolved = true - resolve(json ? JSON.parse(data) : data) - }) + child.stderr.pipe(process.stderr) + child.stdout.pipe(process.stdout) + inputs.forEach(input => { + child.stdin.write(`${input}\n`) + }) - child.once(`exit`, code => { - if (resolved) return - resolved = true - code === 0 ? resolve() : reject(`Process exited with code ${code}`) - }) - } catch (err) { - reject(err) - } + let resolved = false + child.stdout.once(`data`, data => { + if (resolved) return + resolved = true + resolve(json ? JSON.parse(data) : data) + }) + + child.once(`exit`, code => { + if (resolved) return + resolved = true + code === 0 ? resolve() : reject(`Process exited with code ${code}`) + }) }) } From 1e703fc34a4887cddc5a8b63f59250dd11d6dd68 Mon Sep 17 00:00:00 2001 From: Voyager Bot Date: Fri, 16 Nov 2018 15:50:32 +0100 Subject: [PATCH 33/42] fix ubuntu running --- tasks/gaia.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tasks/gaia.js b/tasks/gaia.js index c1cd38ef9d..5c5f9b2909 100644 --- a/tasks/gaia.js +++ b/tasks/gaia.js @@ -259,6 +259,8 @@ function makeExecWithInputs(command, inputs = [], json = true) { let args = command.split(` `).slice(1) return new Promise((resolve, reject) => { const child = spawn(binary, args) + + // needed so commands don't fail on Ubuntu child.stderr.on(`error`, console.error) child.stdout.on(`error`, console.error) child.stdin.on(`error`, console.error) From 8a2b98116176453b50d461a261f671c0a44c2e21 Mon Sep 17 00:00:00 2001 From: Voyager Bot Date: Fri, 16 Nov 2018 15:57:04 +0100 Subject: [PATCH 34/42] fixed e2e test (passing wrong dir to tests) --- test/e2e/launch.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/launch.js b/test/e2e/launch.js index b599bd70a9..00687d69aa 100644 --- a/test/e2e/launch.js +++ b/test/e2e/launch.js @@ -142,7 +142,7 @@ function launch(t) { resolve({ app, - cliHomePrefix, + cliHome: cliHomePrefix, // the Voyager instance will have another folder outside of the nodes config folders accounts }) }) From e0bb0a2e64541fd9b86f6760b685f2f5a40c3300 Mon Sep 17 00:00:00 2001 From: Voyager Bot Date: Fri, 16 Nov 2018 16:11:22 +0100 Subject: [PATCH 35/42] fixed coverage issues in lcdclient --- app/src/renderer/connectors/lcdClient.js | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/app/src/renderer/connectors/lcdClient.js b/app/src/renderer/connectors/lcdClient.js index ef31fd6a61..620b457283 100644 --- a/app/src/renderer/connectors/lcdClient.js +++ b/app/src/renderer/connectors/lcdClient.js @@ -19,11 +19,6 @@ const Client = (axios, localLcdURL, remoteLcdURL) => { // to the path (/foo/{arg}/...) function argReq(method, prefix, suffix = ``, useRemote) { return function(args, data) { - // `args` can either be a single value or an array - if (Array.isArray(args)) { - args = args.join(`/`) - } - return request(method, `${prefix}/${args}${suffix}`, data, useRemote) } } @@ -187,16 +182,6 @@ const Client = (axios, localLcdURL, remoteLcdURL) => { true )() }, - getGovernanceTxs: function(addr) { - return Promise.all([ - req( - `GET`, - `/txs?tag=action='submit-proposal'&tag=proposer='${addr}'`, - true - )(), - req(`GET`, `/txs?tag=action='deposit'&tag=depositer='${addr}'`, true)() - ]).then(([proposalTxs, depositTxs]) => [].concat(proposalTxs, depositTxs)) - }, getGovDepositParameters: req(`GET`, `/gov/parameters/deposit`, true), getGovTallyingParameters: req(`GET`, `/gov/parameters/tallying`, true), getGovVotingParameters: req(`GET`, `/gov/parameters/voting`, true), From 9123e21c174fe1e500a6fa84589285744aab0d6f Mon Sep 17 00:00:00 2001 From: Voyager Bot Date: Fri, 16 Nov 2018 17:37:39 +0100 Subject: [PATCH 36/42] added test for axios proxy --- app/src/renderer/connectors/node.js | 43 +------- app/src/renderer/main.js | 3 +- app/src/renderer/scripts/axiosProxy.js | 37 +++++++ test/unit/helpers/electron_mock.js | 7 +- test/unit/specs/App.spec.js | 3 +- test/unit/specs/node.spec.js | 9 +- test/unit/specs/scripts/axiosProxy.spec.js | 121 +++++++++++++++++++++ 7 files changed, 176 insertions(+), 47 deletions(-) create mode 100644 app/src/renderer/scripts/axiosProxy.js create mode 100644 test/unit/specs/scripts/axiosProxy.spec.js diff --git a/app/src/renderer/connectors/node.js b/app/src/renderer/connectors/node.js index e5f322ad50..88579ed521 100644 --- a/app/src/renderer/connectors/node.js +++ b/app/src/renderer/connectors/node.js @@ -1,50 +1,11 @@ "use strict" -const { ipcRenderer } = require(`electron`) const RestClient = require(`./lcdClient.js`) const mockedRestClient = require(`./lcdClientMock.js`) const RpcWrapper = require(`./rpcWrapper.js`) const MockedRpcWrapper = require(`./rpcWrapperMock.js`) -// Proxy requests to Axios through the main process because we need -// Node.js in order to support self-signed TLS certificates. -const AxiosProxy = () => { - let requestCounter = 0 - - return options => - new Promise((resolve, reject) => { - requestCounter++ - - if (requestCounter === Number.MAX_SAFE_INTEGER) { - requestCounter = 0 - } - - const channel = `Axios/${requestCounter}` - - console.log(`Request ${options.method.toUpperCase()} ${options.url}`) - ipcRenderer.once(channel, (event, { exception, value }) => { - ipcRenderer.removeAllListeners(channel) - - if (exception) { - console.error( - `Request ${options.method.toUpperCase()} ${options.url} failed`, - exception - ) - reject(exception) - } else { - console.log( - `Request ${options.method.toUpperCase()} ${options.url} successful`, - value.data - ) - resolve(value) - } - }) - - ipcRenderer.send(`Axios`, requestCounter, options) - }) -} - -module.exports = function(localLcdURL, remoteLcdURL, mocked = false) { +module.exports = function(axios, localLcdURL, remoteLcdURL, mocked = false) { let connector = { mocked, localLcdURL, @@ -54,7 +15,7 @@ module.exports = function(localLcdURL, remoteLcdURL, mocked = false) { console.log(`Setting connector to state:` + (mocked ? `mocked` : `live`)) let newRestClient = mocked ? mockedRestClient - : new RestClient(AxiosProxy(), localLcdURL, remoteLcdURL) + : new RestClient(axios, localLcdURL, remoteLcdURL) let newRpcClient = mocked ? MockedRpcWrapper(connector) : RpcWrapper(connector) diff --git a/app/src/renderer/main.js b/app/src/renderer/main.js index a558b32837..e0639c8a41 100644 --- a/app/src/renderer/main.js +++ b/app/src/renderer/main.js @@ -12,6 +12,7 @@ import App from "./App" import routes from "./routes" import Node from "./connectors/node" import Store from "./vuex/store" +import AxiosProxy from "./scripts/axiosProxy" const config = remote.getGlobal(`config`) @@ -70,7 +71,7 @@ async function main() { let localLcdURL = `https://localhost:${lcdPort}` console.log(`Expecting lcd-server on port: ` + lcdPort) - node = Node(localLcdURL, config.node_lcd, config.mocked) + node = Node(AxiosProxy(), localLcdURL, config.node_lcd, config.mocked) store = Store({ node }) store.dispatch(`loadTheme`) diff --git a/app/src/renderer/scripts/axiosProxy.js b/app/src/renderer/scripts/axiosProxy.js new file mode 100644 index 0000000000..baed1ce80b --- /dev/null +++ b/app/src/renderer/scripts/axiosProxy.js @@ -0,0 +1,37 @@ +const { ipcRenderer } = require(`electron`) + +// Proxy requests to Axios through the main process because we need +// Node.js in order to support self-signed TLS certificates. +module.exports = (requestCounter = 0) => { + return options => + new Promise((resolve, reject) => { + requestCounter++ + + if (requestCounter === Number.MAX_SAFE_INTEGER) { + requestCounter = 0 + } + + const channel = `Axios/${requestCounter}` + + console.log(`Request ${options.method.toUpperCase()} ${options.url}`) + ipcRenderer.once(channel, (event, { exception, value }) => { + ipcRenderer.removeAllListeners(channel) + + if (exception) { + console.error( + `Request ${options.method.toUpperCase()} ${options.url} failed`, + exception + ) + reject(exception) + } else { + console.log( + `Request ${options.method.toUpperCase()} ${options.url} successful`, + value.data + ) + resolve(value) + } + }) + + ipcRenderer.send(`Axios`, requestCounter, options) + }) +} diff --git a/test/unit/helpers/electron_mock.js b/test/unit/helpers/electron_mock.js index 89d24cd893..860309290c 100644 --- a/test/unit/helpers/electron_mock.js +++ b/test/unit/helpers/electron_mock.js @@ -3,7 +3,12 @@ // this mocks the IPC layer and isolates the mainthread from the renderer thread in tests jest.mock(`electron`, () => ({ clipboard: { writeText: jest.fn() }, - ipcRenderer: { send: jest.fn(), once: jest.fn(), on: jest.fn() }, + ipcRenderer: { + send: jest.fn(), + once: jest.fn(), + on: jest.fn(), + removeAllListeners: jest.fn() + }, ipcMain: { on: jest.fn() }, remote: { getGlobal(name) { diff --git a/test/unit/specs/App.spec.js b/test/unit/specs/App.spec.js index 43be08d3da..19c06da200 100644 --- a/test/unit/specs/App.spec.js +++ b/test/unit/specs/App.spec.js @@ -60,7 +60,8 @@ describe(`App without analytics`, () => { let Node = require(`renderer/connectors/node.js`) require(`renderer/main.js`) expect(Node).toHaveBeenCalledWith( - `https://localhost:8080`, + expect.any(Function), + `https://localhost:8080`, // axios or axios proxy `https://awesomenode.de:12345`, true ) diff --git a/test/unit/specs/node.spec.js b/test/unit/specs/node.spec.js index f8baca9f6c..4b928ddffa 100644 --- a/test/unit/specs/node.spec.js +++ b/test/unit/specs/node.spec.js @@ -1,10 +1,13 @@ let Node describe(`Connector`, () => { + let axios const remoteLcdURL = `http://awesomenode.de:12345` const localLcdURL = `https://localhost:9876` beforeAll(() => { + axios = jest.fn() + jest.mock( `renderer/connectors/lcdClient`, () => @@ -30,19 +33,19 @@ describe(`Connector`, () => { }) it(`should hold the lcdPort`, () => { - let node = Node(localLcdURL, remoteLcdURL) + let node = Node(axios, localLcdURL, remoteLcdURL) expect(node.remoteLcdURL).toBe(remoteLcdURL) expect(node.localLcdURL).toBe(localLcdURL) }) it(`should setup the connectors`, () => { - let node = Node(localLcdURL, remoteLcdURL) + let node = Node(axios, localLcdURL, remoteLcdURL) expect(node.fooRpc).toBe(`rpcBar`) expect(node.fooLcd()).toBe(`lcdBar`) }) it(`should setup the mock connectors`, () => { - let node = Node(localLcdURL, remoteLcdURL, true) + let node = Node(axios, localLcdURL, remoteLcdURL, true) expect(node.fooRpc).toBe(`rpcBarMock`) expect(node.fooLcd()).toBe(`lcdBarMock`) }) diff --git a/test/unit/specs/scripts/axiosProxy.spec.js b/test/unit/specs/scripts/axiosProxy.spec.js new file mode 100644 index 0000000000..0cb6f57b84 --- /dev/null +++ b/test/unit/specs/scripts/axiosProxy.spec.js @@ -0,0 +1,121 @@ +describe(`AxiosProxy`, () => { + let ipcRenderer + let AxiosProxy + beforeEach(() => { + jest.resetModules() + ipcRenderer = require(`electron`).ipcRenderer + AxiosProxy = require(`renderer/scripts/axiosProxy.js`) + }) + + beforeAll(() => { + jest.spyOn(console, `log`).mockImplementation(() => {}) + }) + + afterAll(() => { + console.log.mockReset() + }) + + it(`should send requests via ipc`, () => { + let axios = AxiosProxy() + axios({ method: `POST`, url: `/keys/add`, data: { name: `fabo` } }) + + const requestCounter = 1 + expect(ipcRenderer.send).toHaveBeenCalledWith(`Axios`, requestCounter, { + method: `POST`, + url: `/keys/add`, + data: { name: `fabo` } + }) + expect(ipcRenderer.once).toHaveBeenCalledWith( + `Axios/1`, + expect.any(Function) + ) + }) + + it(`should send requests with increasing request counters`, () => { + let axios = AxiosProxy() + axios({ method: `POST`, url: `/keys/add`, data: { name: `fabo` } }) + axios({ method: `POST`, url: `/keys/add`, data: { name: `fede` } }) + + const requestCounter = 2 + expect(ipcRenderer.send).toHaveBeenCalledWith(`Axios`, requestCounter, { + method: `POST`, + url: `/keys/add`, + data: { name: `fede` } + }) + expect(ipcRenderer.once).toHaveBeenCalledWith( + `Axios/2`, + expect.any(Function) + ) + }) + + it(`should respond to answers from the main thread to requests`, async () => { + ipcRenderer.once = (channel, cb) => { + cb(`xxx`, { exception: null, value: `HALLO WORLD` }) + } + + let axios = AxiosProxy() + let result = await axios({ + method: `POST`, + url: `/keys/add`, + data: { name: `fabo` } + }) + + expect(result).toBe(`HALLO WORLD`) + }) + + it(`should remove the channel listener after receiving a response`, async () => { + ipcRenderer.once = (channel, cb) => { + cb(`xxx`, { exception: null, value: `HALLO WORLD` }) + } + + let axios = AxiosProxy() + await axios({ + method: `POST`, + url: `/keys/add`, + data: { name: `fabo` } + }) + + expect(ipcRenderer.removeAllListeners).toHaveBeenCalledWith(`Axios/1`) + }) + + it(`should pass through exceptions`, async done => { + ipcRenderer.once = (channel, cb) => { + cb(`xxx`, { exception: `Error`, value: null }) + } + + jest.spyOn(console, `error`).mockImplementation(() => {}) + + let axios = AxiosProxy() + await axios({ + method: `POST`, + url: `/keys/add`, + data: { name: `fabo` } + }) + .then(() => done.fail()) + .catch(err => { + expect(err).toBe(`Error`) + done() + }) + + console.error.mockReset() + }) + + it(`should reset the requestCounter after max number is reached`, () => { + let axios = AxiosProxy(Number.MAX_SAFE_INTEGER - 1) + axios({ + method: `POST`, + url: `/keys/add`, + data: { name: `fabo` } + }) + + expect(ipcRenderer.send).toHaveBeenCalledWith(`Axios`, 0, { + method: `POST`, + url: `/keys/add`, + data: { name: `fabo` } + }) + expect(ipcRenderer.once).toHaveBeenCalledWith( + `Axios/0`, + expect.any(Function) + ) + }) +}) From ca6cb6e21eed96b0d5444e9cadf6d498ca6c4682 Mon Sep 17 00:00:00 2001 From: David Braun Date: Fri, 16 Nov 2018 18:24:23 +0100 Subject: [PATCH 37/42] Update app/src/renderer/connectors/lcdClient.js Co-Authored-By: faboweb --- app/src/renderer/connectors/lcdClient.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/renderer/connectors/lcdClient.js b/app/src/renderer/connectors/lcdClient.js index 620b457283..2979d04642 100644 --- a/app/src/renderer/connectors/lcdClient.js +++ b/app/src/renderer/connectors/lcdClient.js @@ -207,7 +207,7 @@ const Client = (axios, localLcdURL, remoteLcdURL) => { true )() ]).then(([depositerTxs, proposerTxs]) => - [].concat(depositerTxs, proposerTxs) + depositerTxs.concat(proposerTxs) ) } } From b5db553f857bc61dbb45d2d56a83a8e1846167ea Mon Sep 17 00:00:00 2001 From: David Braun Date: Fri, 16 Nov 2018 19:03:18 +0100 Subject: [PATCH 38/42] Update tasks/gaia.js Co-Authored-By: faboweb --- tasks/gaia.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasks/gaia.js b/tasks/gaia.js index 5c5f9b2909..560dedbd46 100644 --- a/tasks/gaia.js +++ b/tasks/gaia.js @@ -56,7 +56,7 @@ async function initGenesis( nodeHomeDir ) { const genesisLocation = path.join(nodeHomeDir, `config/genesis.json`) - let genesis = fs.readJSONSync(genesisLocation) + let genesis = require(genesisLocation) console.log( `Adding tokens to genesis at ${genesisLocation} for address ${address}` ) From a7aae148af46e0e4c590d0cb33b488c93f28d455 Mon Sep 17 00:00:00 2001 From: David Braun Date: Sat, 17 Nov 2018 11:27:13 +0100 Subject: [PATCH 39/42] Update test/e2e/launch.js Co-Authored-By: faboweb --- test/e2e/launch.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/launch.js b/test/e2e/launch.js index 00687d69aa..ad20665438 100644 --- a/test/e2e/launch.js +++ b/test/e2e/launch.js @@ -308,7 +308,7 @@ function reduceTimeouts(nodeHome) { .map(line => { let [key, value] = line.split(` = `) - if (timeouts.indexOf(key) === -1) { + if (!timeouts.includes(key)) { return line } From 0bdf122586aebf4191f5fdb9261d3b5abcf33f1f Mon Sep 17 00:00:00 2001 From: Voyager Bot Date: Sat, 17 Nov 2018 12:09:04 +0100 Subject: [PATCH 40/42] implemented comments --- app/src/main/index.js | 3 +- app/src/renderer/connectors/lcdClient.js | 4 +- tasks/build/local/build.js | 56 +++++++----------------- tasks/gaia.js | 43 +++++++----------- test/e2e/launch.js | 4 +- test/unit/specs/main.spec.js | 5 --- 6 files changed, 39 insertions(+), 76 deletions(-) diff --git a/app/src/main/index.js b/app/src/main/index.js index 846ca19b9e..377bfadeaf 100644 --- a/app/src/main/index.js +++ b/app/src/main/index.js @@ -482,7 +482,8 @@ async function pickAndConnect() { return } - // make the ca available to the view + // make the tls certificate available to the view process + // https://en.wikipedia.org/wiki/Certificate_authority global.config.ca = gaiaLite.ca const axiosInstance = axios.create({ httpsAgent: new https.Agent({ ca: gaiaLite.ca }) diff --git a/app/src/renderer/connectors/lcdClient.js b/app/src/renderer/connectors/lcdClient.js index 2979d04642..f752f65ace 100644 --- a/app/src/renderer/connectors/lcdClient.js +++ b/app/src/renderer/connectors/lcdClient.js @@ -206,9 +206,7 @@ const Client = (axios, localLcdURL, remoteLcdURL) => { `/txs?tag=action='deposit'&tag=depositer='${address}'`, true )() - ]).then(([depositerTxs, proposerTxs]) => - depositerTxs.concat(proposerTxs) - ) + ]).then(([depositerTxs, proposerTxs]) => depositerTxs.concat(proposerTxs)) } } } diff --git a/tasks/build/local/build.js b/tasks/build/local/build.js index 7518ff2cf7..fff5dd992c 100644 --- a/tasks/build/local/build.js +++ b/tasks/build/local/build.js @@ -1,15 +1,18 @@ "use strict" -const os = require(`os`) const fs = require(`fs-extra`) const { cli } = require(`@nodeguy/cli`) const path = require(`path`) const homeDir = require(`os`).homedir() const appDir = path.resolve(__dirname + `/../../../`) -let { exec } = require(`child_process`) - -let { initNode, createKey, initGenesis } = require(`../../gaia.js`) +let { + initNode, + createKey, + initGenesis, + makeExec, + nodeBinary +} = require(`../../gaia.js`) const optionsSpecification = { overwrite: [`overwrite ~/.gaiad-testnet/`, false], @@ -17,27 +20,17 @@ const optionsSpecification = { } cli(optionsSpecification, async options => { - const platform = os.platform() - const environment = - platform === `darwin` - ? `darwin_amd64` - : platform === `win32` - ? `windows_amd64` - : `linux_amd64` try { // remove existing config if (options.overwrite) { if (fs.existsSync(appDir + `/builds/testnets/local-testnet`)) { - let out = await makeExec(`rm -r builds/testnets/local-testnet`) - out && console.log(out) + await makeExec(`rm -r builds/testnets/local-testnet`) } if (fs.existsSync(homeDir + `/.gaiad-testnet`)) { - let out = await makeExec(`rm -r ~/.gaiad-testnet`) - out && console.log(out) + await makeExec(`rm -r ~/.gaiad-testnet`) } if (fs.existsSync(homeDir + `/.cosmos-voyager-dev/local-testnet`)) { - let out = await makeExec(`rm -r ~/.cosmos-voyager-dev/local-testnet`) - out && console.log(out) + await makeExec(`rm -r ~/.cosmos-voyager-dev/local-testnet`) } } @@ -59,7 +52,7 @@ cli(optionsSpecification, async options => { ) const { address } = await createKey(defaultAccountInfo) await initGenesis(defaultAccountInfo, address, nodeHome) - await moveFiles(options, environment) + await moveFiles() console.log(`\n 🎉 SUCCESS 🎉\n`) console.log( `To start Voyager with a local node please run: @@ -76,37 +69,22 @@ Default account: } }) -function makeExec(command) { - console.log(`$ ` + command) - return new Promise((resolve, reject) => { - exec(command, (err, stdout, stderr) => { - if (err) return reject(err) - if (stderr) return reject(stderr) - resolve(stdout) - }) - }) -} -async function moveFiles(options, environment) { - let out +async function moveFiles() { fs.ensureDirSync(`builds/testnets/local-testnet`) - out = await makeExec( + await makeExec( `cp ~/.gaiad-testnet/config/{genesis.json,config.toml} builds/testnets/local-testnet/` ) - out && console.log(out) - out = await makeExec( + await makeExec( `sed -i.bak 's/seeds = ""/seeds = "localhost"/g' ./builds/testnets/local-testnet/config.toml` ) - out && console.log(out) - out = await makeExec( + await makeExec( `sed -i.bak 's/index_all_tags = false/index_all_tags = true/g' ${homeDir}/.gaiad-testnet/config/config.toml` ) - out && console.log(out) - out = await makeExec( - `./builds/Gaia/${environment}/gaiad version > ./builds/testnets/local-testnet/gaiaversion.txt` + await makeExec( + `${nodeBinary} version > ./builds/testnets/local-testnet/gaiaversion.txt` ) - out && console.log(out) } diff --git a/tasks/gaia.js b/tasks/gaia.js index 560dedbd46..3de8a19a19 100644 --- a/tasks/gaia.js +++ b/tasks/gaia.js @@ -1,18 +1,14 @@ const path = require(`path`) const fs = require(`fs-extra`) +const util = require(`util`) const { spawn, exec } = require(`child_process`) let { sleep } = require(`../test/e2e/common.js`) -const osFolderName = (function() { - switch (process.platform) { - case `win32`: - return `windows_amd64` - case `darwin`: - return `darwin_amd64` - case `linux`: - return `linux_amd64` - } -})() +const osFolderName = { + win32: `windows_amd64`, + darwin: `darwin_amd64`, + linux: `linux_amd64` +}[process.platform] let cliBinary = process.env.BINARY_PATH || path.join(__dirname, `../builds/Gaia/`, osFolderName, `gaiacli`) @@ -88,9 +84,7 @@ async function initGenesis( } function getGenesis(homeDir) { - const genesisLocation = path.join(homeDir, `config/genesis.json`) - let genesis = fs.readJSONSync(genesisLocation) - return genesis + return require(path.join(homeDir, `config/genesis.json`)) } // make it so that one initialized node will become a validator @@ -132,18 +126,15 @@ async function makeValidator( async function getValPubKey(node_home) { let command = `${nodeBinary} tendermint show-validator --home ${node_home}` - const stdout = await makeExec(command) - return stdout.trim() + return await makeExec(command) } async function getNodeId(node_home) { let command = `${nodeBinary} tendermint show-node-id --home ${node_home}` - const stdout = await makeExec(command) - return stdout.trim() + return await makeExec(command) } async function getBalance(cliHome, address) { let command = `${cliBinary} query account ${address} --home ${cliHome} --output "json" --trust-node` - const stdout = await makeExec(command) - return JSON.parse(stdout.trim()) + return JSON.parse(await makeExec(command)) } // sends a create-validator tx @@ -243,12 +234,9 @@ function startLocalNode( // execute command and return stdout function makeExec(command) { console.log(`$ ` + command) - return new Promise((resolve, reject) => { - exec(command, (err, stdout) => { - if (err) return reject(err) - resolve(stdout) - }) - }) + return util + .promisify(exec)(command) + .then(({ stdout }) => stdout.trim()) } // execute command, write all inputs followed by enter to stdin and return stdout @@ -298,5 +286,8 @@ module.exports = { cliBinary, nodeBinary, - defaultStartPort + defaultStartPort, + + makeExec, + makeExecWithInputs } diff --git a/test/e2e/launch.js b/test/e2e/launch.js index ad20665438..81130efd8e 100644 --- a/test/e2e/launch.js +++ b/test/e2e/launch.js @@ -49,8 +49,8 @@ function launch(t) { const nodeOneHome = nodeHomePrefix + `_1` const nodeOneCliHome = cliHomePrefix + `_1` const operatorKeyName = `testkey` - console.error(`ui home: ${nodeOneCliHome}`) - console.error(`node home: ${nodeOneHome}`) + console.log(`ui home: ${nodeOneCliHome}`) + console.log(`node home: ${nodeOneHome}`) await initLocalNode(nodeOneHome, 1) const nodeOneId = await getNodeId(nodeOneHome) diff --git a/test/unit/specs/main.spec.js b/test/unit/specs/main.spec.js index 91368fcf15..d8e38684d2 100644 --- a/test/unit/specs/main.spec.js +++ b/test/unit/specs/main.spec.js @@ -1,4 +1,3 @@ -// const EventEmitter = require(`events`) const { join } = require(`path`) const mockFsExtra = require(`../helpers/fs-mock`).default jest.mock(`readline`, () => ({ @@ -592,10 +591,6 @@ function mainSetup() { beforeAll(async function() { main = await initMain() }) - - afterAll(async function() { - // await main.shutdown() - }) } // prepare mocks before we start the main process From 117c7883eba1bcdf19c76f01d3385112b8711353 Mon Sep 17 00:00:00 2001 From: Voyager Bot Date: Sat, 17 Nov 2018 12:18:51 +0100 Subject: [PATCH 41/42] fixed test --- app/src/renderer/connectors/lcdClient.js | 11 +- test/unit/specs/lcdClient.spec.js | 174 +---------------------- 2 files changed, 8 insertions(+), 177 deletions(-) diff --git a/app/src/renderer/connectors/lcdClient.js b/app/src/renderer/connectors/lcdClient.js index f752f65ace..130b50879f 100644 --- a/app/src/renderer/connectors/lcdClient.js +++ b/app/src/renderer/connectors/lcdClient.js @@ -3,7 +3,9 @@ const Client = (axios, localLcdURL, remoteLcdURL) => { async function request(method, path, data, useRemote) { const url = useRemote ? remoteLcdURL : localLcdURL - return (await axios({ data, method, url: url + path })).data + const result = await axios({ data, method, url: url + path }) + console.log(method, path, data, result.data) + return result.data } // returns an async function which makes a request for the given @@ -194,8 +196,8 @@ const Client = (axios, localLcdURL, remoteLcdURL) => { submitProposalDeposit: function(proposalId, data) { return req(`POST`, `/gov/proposals/${proposalId}/deposits`, true)(data) }, - getGovernanceTxs: function(address) { - return Promise.all([ + getGovernanceTxs: async function(address) { + let [depositerTxs, proposerTxs] = await Promise.all([ req( `GET`, `/txs?tag=action='submit-proposal'&tag=proposer='${address}'`, @@ -206,7 +208,8 @@ const Client = (axios, localLcdURL, remoteLcdURL) => { `/txs?tag=action='deposit'&tag=depositer='${address}'`, true )() - ]).then(([depositerTxs, proposerTxs]) => depositerTxs.concat(proposerTxs)) + ]) + return depositerTxs.concat(proposerTxs) } } } diff --git a/test/unit/specs/lcdClient.spec.js b/test/unit/specs/lcdClient.spec.js index 8476dadf81..b354ba40a1 100644 --- a/test/unit/specs/lcdClient.spec.js +++ b/test/unit/specs/lcdClient.spec.js @@ -607,179 +607,7 @@ describe(`LCD Client`, () => { }) it(`queries for governance txs`, async () => { - axios.mockReturnValue({}) - await client.getGovernanceTxs(lcdClientMock.addresses[0]) - - expect(axios.mock.calls).toEqual([ - [ - { - data: undefined, - method: `GET`, - url: `http://remotehost/txs?tag=action='submit-proposal'&tag=proposer='${ - lcdClientMock.addresses[0] - }'` - } - ], - [ - { - data: undefined, - method: `GET`, - url: `http://remotehost/txs?tag=action='deposit'&tag=depositer='${ - lcdClientMock.addresses[0] - }'` - } - ] - ]) - }) - }) - - describe(`governance`, () => { - it(`fetches all governance proposals`, async () => { - axios.mockReturnValue({}) - await client.queryProposals() - - expect(axios.mock.calls).toEqual([ - [ - { - data: undefined, - method: `GET`, - url: `http://remotehost/gov/proposals` - } - ] - ]) - }) - - it(`queries a single proposal`, async () => { - axios.mockReturnValue({}) - await client.queryProposal(1) - - expect(axios.mock.calls).toEqual([ - [ - { - data: undefined, - method: `GET`, - url: `http://remotehost/gov/proposals/1` - } - ] - ]) - }) - - it(`queries a proposal votes`, async () => { - axios.mockReturnValue({}) - await client.queryProposalVotes(1) - - expect(axios.mock.calls).toEqual([ - [ - { - data: undefined, - method: `GET`, - url: `http://remotehost/gov/proposals/1/votes` - } - ] - ]) - }) - - it(`queries a proposal vote from an address`, async () => { - axios.mockReturnValue({}) - await client.queryProposalVote( - 1, - `cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5ctpesxxn9` - ) - - expect(axios.mock.calls).toEqual([ - [ - { - data: undefined, - method: `GET`, - url: `http://remotehost/gov/proposals/1/votes/cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5ctpesxxn9` - } - ] - ]) - }) - - it(`queries a proposal deposits`, async () => { - axios.mockReturnValue({}) - await client.queryProposalDeposits(1) - - expect(axios.mock.calls).toEqual([ - [ - { - data: undefined, - method: `GET`, - url: `http://remotehost/gov/proposals/1/deposits` - } - ] - ]) - }) - - it(`queries a proposal deposit from an address`, async () => { - axios.mockReturnValue({}) - await client.queryProposalDeposit( - 1, - `cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5ctpesxxn9` - ) - - expect(axios.mock.calls).toEqual([ - [ - { - data: undefined, - method: `GET`, - url: `http://remotehost/gov/proposals/1/deposits/cosmos15ky9du8a2wlstz6fpx3p4mqpjyrm5ctpesxxn9` - } - ] - ]) - }) - - it(`submits a new proposal`, async () => { - axios.mockReturnValue({}) - await client.submitProposal(proposals[0]) - - expect(axios.mock.calls).toEqual([ - [ - { - data: proposals[0], - method: `POST`, - url: `http://remotehost/gov/proposals` - } - ] - ]) - }) - - it(`submits a new vote to a proposal`, async () => { - axios.mockReturnValue({}) - await client.submitProposalVote(proposals[0].proposal_id, votes[0]) - - expect(axios.mock.calls).toEqual([ - [ - { - data: undefined, - method: `POST`, - url: `http://remotehost/gov/proposals/1/votes` - } - ] - ]) - }) - - it(`submits a new deposit to a proposal`, async () => { - axios.mockReturnValue({}) - await client.submitProposalDeposit( - proposals[0].proposal_id, - deposits[0] - ) - - expect(axios.mock.calls).toEqual([ - [ - { - data: undefined, - method: `POST`, - url: `http://remotehost/gov/proposals/1/deposits` - } - ] - ]) - }) - - it(`queries for governance txs`, async () => { - axios.mockReturnValue({}) + axios.mockReturnValue({ data: [] }) await client.getGovernanceTxs(lcdClientMock.addresses[0]) expect(axios.mock.calls).toEqual([ From da99f945d5484709113c45bb32ab295f9a8e6a5c Mon Sep 17 00:00:00 2001 From: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Date: Sat, 17 Nov 2018 23:03:56 +0100 Subject: [PATCH 42/42] Update lcdClient.js --- app/src/renderer/connectors/lcdClient.js | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/renderer/connectors/lcdClient.js b/app/src/renderer/connectors/lcdClient.js index 130b50879f..1fd9e38bb5 100644 --- a/app/src/renderer/connectors/lcdClient.js +++ b/app/src/renderer/connectors/lcdClient.js @@ -4,7 +4,6 @@ const Client = (axios, localLcdURL, remoteLcdURL) => { async function request(method, path, data, useRemote) { const url = useRemote ? remoteLcdURL : localLcdURL const result = await axios({ data, method, url: url + path }) - console.log(method, path, data, result.data) return result.data }