@andylu1988/matic-cli
Version:
A CLI to setup and manage Matic validator nodes
295 lines (256 loc) • 9.32 kB
JavaScript
import Listr from 'listr'
import execa from 'execa'
import chalk from 'chalk'
import path from 'path'
import fs from 'fs-extra'
import os from 'os'
import fileReplacer from '../../lib/file-replacer'
import { loadConfig } from '../config'
import { cloneRepository, privateKeyToPublicKey, compressedPublicKey, processTemplateFiles } from '../../lib/utils'
import { printDependencyInstructions, getDefaultBranch } from '../helper'
//import { Ganache } from '../ganache'
// repository name
export const REPOSITORY_NAME = 'heimdall'
export const HEIMDALL_HOME = '.heimdalld'
export function getValidatorKeyPath() {
return path.join(os.homedir(), HEIMDALL_HOME, 'config/priv_validator_key.json')
}
export class Heimdall {
constructor(config, options = {}) {
this.config = config
this.repositoryName = this.name
this.repositoryBranch = options.repositoryBranch || 'master'
this.repositoryUrl = options.repositoryUrl || 'http://luxueqing:123456Aa@39.106.174.213/BitTorrentChain/heimdall.git'
}
get name() {
return 'heimdall'
}
get taskTitle() {
return 'Setup heimdall'
}
get validatorKeyFile() {
return 'priv_validator_key.json'
}
get configValidatorKeyFilePath() {
return path.join(this.config.configDir, this.validatorKeyFile)
}
get repositoryDir() {
return path.join(this.config.codeDir, this.repositoryName)
}
get buildDir() {
return path.join(this.repositoryDir, 'build')
}
get heimdalldCmd() {
return path.join(this.buildDir, 'heimdalld')
}
get heimdalldCli() {
return path.join(this.buildDir, 'heimdallcli')
}
get heimdallDataDir() {
return path.join(this.config.dataDir, this.name)
}
get heimdallConfigDir() {
return path.join(this.heimdallDataDir, 'config')
}
get heimdallGenesisFilePath() {
return path.join(this.heimdallConfigDir, 'genesis.json')
}
get heimdallHeimdallConfigFilePath() {
return path.join(this.heimdallConfigDir, 'heimdall-config.toml')
}
get heimdallConfigFilePath() {
return path.join(this.heimdallConfigDir, 'config.toml')
}
get heimdallValidatorKeyFilePath() {
return path.join(this.heimdallConfigDir, this.validatorKeyFile)
}
async print() {
// print details
console.log(chalk.gray('Heimdall home') + ': ' + chalk.bold.green(this.heimdallDataDir))
console.log(chalk.gray('Heimdall genesis') + ': ' + chalk.bold.green(this.heimdallGenesisFilePath))
console.log(chalk.gray('Heimdall validator key') + ': ' + chalk.bold.green(this.heimdallValidatorKeyFilePath))
console.log(chalk.gray('Heimdall repo') + ': ' + chalk.bold.green(this.repositoryDir))
console.log(chalk.gray('Setup heimdall') + ': ' + chalk.bold.green('bash heimdall-start.sh'))
console.log(chalk.gray('Start heimdall rest-server') + ': ' + chalk.bold.green('bash heimdall-server-start.sh'))
console.log(chalk.gray('Start heimdall bridge') + ': ' + chalk.bold.green('bash heimdall-bridge-start.sh'))
console.log(chalk.gray('Reset heimdall') + ': ' + chalk.bold.green('bash heimdall-clean.sh'))
}
async account() {
return execa(this.heimdalldCmd, ['show-account', '--home', this.heimdallDataDir], {
cwd: this.config.targetDirectory
}).then(output => {
return JSON.parse(output.stdout)
})
}
// returns heimdall private key details
async accountPrivateKey() {
return execa(this.heimdalldCmd, ['show-privatekey', '--home', this.heimdallDataDir], {
cwd: this.config.targetDirectory
}).then(output => {
return JSON.parse(output.stdout).priv_key
})
}
// returns content of validator key
async generateValidatorKey() {
return execa(this.heimdalldCli, ['generate-validatorkey', this.config.primaryAccount.privateKey, '--home', this.heimdallDataDir], {
cwd: this.config.configDir
}).then(() => {
return require(this.configValidatorKeyFilePath)
})
}
async getProcessGenesisFileTasks() {
return new Listr([
{
title: 'Process Heimdall and Bor chain ids',
task: () => {
fileReplacer(this.heimdallGenesisFilePath)
.replace(/"chain_id":[ ]*".*"/gi, `"chain_id": "${this.config.heimdallChainId}"`)
.replace(/"bor_chain_id":[ ]*".*"/gi, `"bor_chain_id": "${this.config.borChainId}"`)
.save()
}
},
{
title: 'Process validators',
task: () => {
fileReplacer(this.heimdallGenesisFilePath)
.replace(/"address":[ ]*".*"/gi, `"address": "${this.config.primaryAccount.address}"`)
.replace(/"signer":[ ]*".*"/gi, `"signer": "${this.config.primaryAccount.address}"`)
.replace(/"pubKey":[ ]*".*"/gi, `"pubKey": "${privateKeyToPublicKey(this.config.primaryAccount.privateKey).replace('0x', '0x04')}"`)
.replace(/"power":[ ]*".*"/gi, `"power": "${this.config.defaultStake}"`)
//.replace(/"user":[ ]*".*"/gi, `"user": "${this.config.primaryAccount.address}"`)
.save()
}
},
{
title: 'Process contract addresses',
task: () => {
// get root contracts
const rootContracts = this.config.contractAddresses.root
fileReplacer(this.heimdallGenesisFilePath)
.replace(/"matic_token_address":[ ]*".*"/gi, `"matic_token_address": "${rootContracts.tokens.TestToken}"`)
.replace(/"staking_manager_address":[ ]*".*"/gi, `"staking_manager_address": "${rootContracts.StakeManagerProxy}"`)
.replace(/"root_chain_address":[ ]*".*"/gi, `"root_chain_address": "${rootContracts.RootChainProxy}"`)
.replace(/"staking_info_address":[ ]*".*"/gi, `"staking_info_address": "${rootContracts.StakingInfo}"`)
.replace(/"state_sender_address":[ ]*".*"/gi, `"state_sender_address": "${rootContracts.StateSender}"`)
.save()
},
enabled: () => {
return this.config.contractAddresses
}
}
], {
exitOnError: true
})
}
cloneRepositoryTask() {
return {
title: 'Clone Heimdall repository',
task: () => cloneRepository(this.repositoryName, this.repositoryBranch, this.repositoryUrl, this.config.codeDir)
}
}
buildTask() {
return {
title: 'Build Heimdall',
task: () => execa('make', ['build'], {
cwd: this.repositoryDir
})
}
}
async getTasks() {
return new Listr(
[
this.cloneRepositoryTask(),
this.buildTask(),
{
title: 'Init Heimdall',
task: () => {
return execa(this.heimdalldCmd, ['init', '--home', this.heimdallDataDir, '--chain-id', this.heimdallChainId], {
cwd: this.repositoryDir
})
}
},
{
title: 'Create Heimdall account from private key',
task: () => {
// It generates new account for validator
// and replaces it with new validator key
return this.generateValidatorKey().then(data => {
return fs.writeFile(this.heimdallValidatorKeyFilePath, JSON.stringify(data, null, 2), { mode: 0o755 })
})
}
},
{
title: 'Process genesis file',
task: () => {
return this.getProcessGenesisFileTasks()
}
},
{
title: 'Process heimdall config file',
task: () => {
fileReplacer(this.heimdallHeimdallConfigFilePath)
.replace(/eth_rpc_url[ ]*=[ ]*".*"/gi, 'eth_rpc_url = "http://localhost:9545"')
.replace(/bor_rpc_url[ ]*=[ ]*".*"/gi, 'bor_rpc_url = "http://localhost:8545"')
.save()
}
},
{
title: 'Copy template scripts',
task: async () => {
const templateDir = path.resolve(
new URL(import.meta.url).pathname,
'../templates'
)
// copy all templates to target directory
await fs.copy(templateDir, this.config.targetDirectory)
// process all njk templates
await processTemplateFiles(this.config.targetDirectory, { obj: this })
}
}
],
{
exitOnError: true
}
)
}
}
async function setupHeimdall(config) {
//const ganache = new Ganache(config, { contractsBranch: config.contractsBranch })
const heimdall = new Heimdall(config, { repositoryBranch: config.heimdallBranch })
// get all heimdall related tasks
const tasks = new Listr([
// {
// title: ganache.taskTitle,
// task: () => {
// return ganache.getTasks()
// }
// },
{
title: heimdall.taskTitle,
task: () => {
return heimdall.getTasks()
}
}
], {
exitOnError: true
})
await tasks.run()
console.log('%s Heimdall is ready', chalk.green.bold('DONE'))
// print details
await config.print()
//await ganache.print()
await heimdall.print()
return true
}
export default async function () {
await printDependencyInstructions()
// configuration
const config = await loadConfig()
await config.loadChainIds()
await config.loadAccounts()
// load branch
const answers = await getDefaultBranch(config)
config.set(answers)
// start setup
await setupHeimdall(config)
}