UNPKG

@maticnetwork/matic-cli

Version:

Testing toolkit to setup, manage and operate Polygon networks

398 lines (364 loc) 10.3 kB
// noinspection JSUnresolvedFunction,JSUnresolvedVariable import { Listr } from 'listr2' import execa from 'execa' import chalk from 'chalk' import path from 'path' import fs from 'fs-extra' import fileReplacer from '../../lib/file-replacer' import { loadConfig } from '../config' import { cloneRepository, compressedPublicKey, privateKeyToPublicKey, processTemplateFiles } from '../../lib/utils' import { getDefaultBranch } from '../helper' import { Ganache } from '../ganache' import { getRemoteStdio } from '../../express/common/remote-worker' export class Heimdall { constructor(config, options = {}) { this.config = config this.repositoryName = this.name this.repositoryBranch = options.repositoryBranch || 'develop' this.repositoryUrl = options.repositoryUrl || 'https://github.com/maticnetwork/heimdall' this.dockerContext = options.dockerContext || 'https://github.com/maticnetwork/heimdall.git#develop' } 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() { if ( this.dockerContext !== undefined && !this.dockerContext.startsWith('http') ) { return this.dockerContext } else { 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 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 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('Reset heimdall') + ': ' + chalk.bold.green('bash heimdall-clean.sh') ) } // returns content of validator key async generateValidatorKey() { return execa( this.heimdalldCmd, [ 'generate-validatorkey', this.config.primaryAccount.privateKey, '--home', this.heimdallDataDir ], { cwd: this.config.configDir, stdio: getRemoteStdio() } ).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( /"pub_key":[ ]*".*"/gi, `"pub_key": "${compressedPublicKey( 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, concurrent: 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', 'network=local'], { cwd: this.repositoryDir, stdio: getRemoteStdio() }) } } 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, 'heimdall-test' ], { cwd: this.repositoryDir, stdio: getRemoteStdio() } ) } }, { 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, { repositoryUrl: config.heimdallRepo, repositoryBranch: config.heimdallBranch, dockerContext: config.heimdallDockerBuildContext }) // 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 (command) { // configuration const config = await loadConfig({ targetDirectory: command.parent.directory, fileName: command.parent.config, interactive: command.parent.interactive }) await config.loadChainIds() await config.loadAccounts() // load branch const answers = await getDefaultBranch(config) config.set(answers) // start setup await setupHeimdall(config) }