Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify local boot and enable multi node #1751

Merged
merged 8 commits into from
Dec 18, 2018
87 changes: 6 additions & 81 deletions tasks/build/local/build.js
Original file line number Diff line number Diff line change
@@ -1,90 +1,15 @@
"use strict"

const fs = require(`fs-extra`)
const buildLocalNode = require(`./helper`).buildLocalNode
const { cli } = require(`@nodeguy/cli`)
const path = require(`path`)
const homeDir = require(`os`).homedir()
const appDir = path.resolve(__dirname + `/../../../`)

let {
initNode,
createKey,
initGenesis,
makeExec,
nodeBinary
} = require(`../../gaia.js`)
const appDir = path.resolve(`${__dirname}/../../`)
const buildTestnetPath = `${appDir}builds/testnets`

const optionsSpecification = {
overwrite: [`overwrite ~/.gaiad-testnet/`, false],
password: [`custom password, default is 1234567890`, 1234567890]
password: [`custom password, default is 1234567890`, 1234567890],
nodes: [`number of validators in the network`, 1]
}

cli(optionsSpecification, async options => {
try {
// remove existing config
if (options.overwrite) {
if (fs.existsSync(appDir + `/builds/testnets/local-testnet`)) {
await makeExec(`rm -r builds/testnets/local-testnet`)
}
if (fs.existsSync(homeDir + `/.gaiad-testnet`)) {
await makeExec(`rm -r ~/.gaiad-testnet`)
}
if (fs.existsSync(homeDir + `/.cosmos-voyager-dev/local-testnet`)) {
await makeExec(`rm -r ~/.cosmos-voyager-dev/local-testnet`)
}
}

const chainId = `local-testnet`
const moniker = `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,
`${homeDir}/.gaiad-testnet`,
options.password,
options.overwrite
)
const { address } = await createKey(defaultAccountInfo)
await initGenesis(defaultAccountInfo, address, nodeHome)
await moveFiles()
console.log(`\n 🎉 SUCCESS 🎉\n`)
console.log(
`To start Voyager with a local node please run:
yarn start local-testnet

Default account:
username: '${defaultAccountInfo.keyName}'
password: '${defaultAccountInfo.password}'
`
)
} catch (error) {
console.log(`Encountered an Error:`)
console.error(error.msg ? error : error.toString())
}
})

async function moveFiles() {
fs.ensureDirSync(`builds/testnets/local-testnet`)

await makeExec(
`cp ~/.gaiad-testnet/config/{genesis.json,config.toml} builds/testnets/local-testnet/`
)

await makeExec(
`sed -i.bak 's/seeds = ""/seeds = "localhost"/g' ./builds/testnets/local-testnet/config.toml`
)

await makeExec(
`sed -i.bak 's/index_all_tags = false/index_all_tags = true/g' ${homeDir}/.gaiad-testnet/config/config.toml`
)

await makeExec(
`${nodeBinary} version > ./builds/testnets/local-testnet/gaiaversion.txt`
)
}
cli(optionsSpecification, buildLocalNode(buildTestnetPath))
192 changes: 192 additions & 0 deletions tasks/build/local/helper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
"use strict"

const fs = require(`fs-extra`)
const path = require(`path`)
const startLocalNode = require(`../../gaia`).startLocalNode
const getNodeId = require(`../../gaia`).getNodeId
const makeValidator = require(`../../gaia`).makeValidator

let {
initNode,
createKey,
initGenesis,
makeExec,
nodeBinary
} = require(`../../gaia.js`)

const buildLocalNode = buildTestnetPath => async options => {
try {
const chainId = `local-testnet`
const moniker = `local`
const localTestnetPath = `${buildTestnetPath}/${chainId}`
// remove existing config
if (options.overwrite) {
fs.removeSync(localTestnetPath)
}

const clientHome = `./${localTestnetPath}/main-node-cli/lcd`
const nodeHome = `${localTestnetPath}/main-node-home`
const defaultAccountInfo = {
keyName: `local`,
password: options.password,
clientHomeDir: clientHome
}
await initNode(
chainId,
moniker,
nodeHome,
options.password,
options.overwrite
)
const { address } = await createKey(defaultAccountInfo)
await initGenesis(defaultAccountInfo, address, nodeHome)
await makeExec(
`sed -i.bak 's/seeds = ""/seeds = "localhost"/g' ${nodeHome}/config.toml`
)
saveVersion(nodeHome)
console.log(`\n 🎉 SUCCESS 🎉\n`)
console.log(
`To start Voyager with a local node please run:
yarn start local-testnet

Default account:
username: '${defaultAccountInfo.keyName}'
password: '${defaultAccountInfo.password}'
`
)
} catch (error) {
console.log(`Encountered an Error:`)
console.error(error.msg ? error : error.toString())
}
}

// save the version of the currently used gaia into the newly created network config folder
const saveVersion = nodeHome => {
const versionPath = path.join(nodeHome, `config`)
let versionFilePath = path.join(versionPath, `gaiaversion.txt`) // nodeHome/config is used to copy created config files from
return makeExec(
`mkdir -p ${versionPath} && ${nodeBinary} version > ${versionFilePath}`
)
}

// nodes[0] is a placeholder just to be aligned with the enumeration used in gaia
// TODO: next PR refactor also gaia to simplify numeration
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

const startNodes = async (nodes, mainAccountSignInfo) => {
for (let i = 1; i < nodes.length; i++) {
// start secondary nodes and connect to node one
// wait until all nodes are showing blocks, so we know they are running
await startLocalNode(nodes[i].home, i, i > 1 ? nodes[1].id : ``)
// make our secondary nodes also to validators
i > 1 &&
(await makeValidator(
mainAccountSignInfo,
nodes[i].home,
nodes[i].cliHome,
`local_${i}`
))
}
}

const buildNodes = async (targetDir, chainId, numberNodes = 1) => {
const cliHomePrefix = path.join(targetDir, `cli_home`)
const nodeHomePrefix = path.join(targetDir, `node_home`)

fs.removeSync(targetDir)

// create address to delegate staking tokens to 2nd and 3rd validator
let mainAccountSignInfo = undefined
let genesis = undefined

const nodes = [{ id: `dummy` }]
for (let i = 1; i < numberNodes; i++) {
// setup additional nodes
const home = `${nodeHomePrefix}_${i}`
nodes.push({
home,
cliHome: `${cliHomePrefix}_${i}`,
id: await setupLocalNode(home, i, chainId, true, genesis)
})
if (i === 1) {
await saveVersion(home)
mainAccountSignInfo = {
keyName: `testkey`,
password: `1234567890`,
clientHomeDir: home
}
let { address } = await createKey(mainAccountSignInfo)
genesis = await initGenesis(mainAccountSignInfo, address, home)
}
}

return { nodes, mainAccountSignInfo, genesis, cliHomePrefix }
}

// init a node and define it as a validator
async function setupLocalNode(
nodeHome,
number = 1,
chainId = `local-testnet`,
isTest = false,
mainGenesis = undefined
) {
await initNode(chainId, `local_${number}`, nodeHome, `1234567890`, true)
mainGenesis &&
(await fs.writeJSON(
path.join(nodeHome, `config`, `genesis.json`),
mainGenesis
))
isTest && (await reduceTimeouts(nodeHome))

return await getNodeId(nodeHome)
}

// declare candidacy for node

function reduceTimeouts(nodeHome, strictAddressbook = false) {
const configPath = path.join(nodeHome, `config`, `config.toml`)
let configToml = fs.readFileSync(configPath, `utf8`)

const timeouts = [
`timeout_propose`,
`timeout_propose_delta`,
`timeout_prevote`,
`timeout_prevote_delta`,
`timeout_precommit`,
`timeout_precommit_delta`,
`timeout_commit`,
`flush_throttle_timeout`
]
const updatedConfigToml = configToml
.split(`\n`)
.map(line => {
let [key, value] = line.split(` = `)

if (key === `addr_book_strict`) {
return `${key} = ${strictAddressbook ? `true` : `false`}`
}

if (!timeouts.includes(key)) {
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`)

fs.writeFileSync(configPath, updatedConfigToml, `utf8`)
}

module.exports = {
buildLocalNode,
buildNodes,
saveVersion,
startNodes
}
8 changes: 4 additions & 4 deletions tasks/gaia.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ let nodeBinary =
process.env.NODE_BINARY_PATH ||
path.join(__dirname, `../builds/Gaia/`, osFolderName, `gaiad`)
const defaultStartPort = 26656
const getStartPort = nodeNumber => defaultStartPort - (nodeNumber - 1) * 3

// initialise the node config folder and genesis
async function initNode(
Expand Down Expand Up @@ -188,11 +189,10 @@ function startLocalNode(
return new Promise((resolve, reject) => {
let command = `${nodeBinary} start --home ${nodeHome}` // TODO add --minimum_fees 1STAKE here
if (number > 1) {
const port = getStartPort(number)
// 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}`
command += ` --p2p.laddr=tcp://0.0.0.0:${port} --address=tcp://0.0.0.0:${port +
1} --rpc.laddr=tcp://0.0.0.0:${port + 2}`
// set the first node as a persistent peer
command += ` --p2p.persistent_peers="${nodeOneId}@localhost:${defaultStartPort}"`
}
Expand Down
9 changes: 9 additions & 0 deletions tasks/testnet.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"use strict"

import { buildLocalNode } from "./build/local/build"

let runDev = require(`./runner.js`)
let config = require(`../app/src/config.js`)
const path = require(`path`)
Expand All @@ -18,6 +20,13 @@ async function main() {
}
const TESTNET_NODE_FOLDER = path.join(userHome, `.gaiad-testnet`)
startLocalNode(TESTNET_NODE_FOLDER)
if (process.env[`VALIDATORS`] && process.env[`VALIDATORS`] > 1) {
// let's re-t
sabau marked this conversation as resolved.
Show resolved Hide resolved
await buildLocalNode({
overwrite: true,
nodes: parseInt(process.env[`VALIDATORS`], 10)
})
}
}

// run Voyager in a development environment
Expand Down
Loading