github.com/klaytn/klaytn@v1.12.1/cmd/homi/setup/cmd.go (about)

     1  // Copyright 2018 The klaytn Authors
     2  // Copyright 2017 AMIS Technologies
     3  // This file is part of the go-ethereum library.
     4  //
     5  // The go-ethereum library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Lesser General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // The go-ethereum library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  // GNU Lesser General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Lesser General Public License
    16  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package setup
    19  
    20  import (
    21  	"crypto/ecdsa"
    22  	"encoding/json"
    23  	"fmt"
    24  	"io"
    25  	"math/big"
    26  	"math/rand"
    27  	"net"
    28  	"net/http"
    29  	"os"
    30  	"path"
    31  	"strconv"
    32  	"strings"
    33  	"time"
    34  
    35  	"github.com/klaytn/klaytn/accounts"
    36  	"github.com/klaytn/klaytn/accounts/keystore"
    37  	"github.com/klaytn/klaytn/blockchain"
    38  	"github.com/klaytn/klaytn/blockchain/system"
    39  	istcommon "github.com/klaytn/klaytn/cmd/homi/common"
    40  	"github.com/klaytn/klaytn/cmd/homi/docker/compose"
    41  	"github.com/klaytn/klaytn/cmd/homi/docker/service"
    42  	"github.com/klaytn/klaytn/cmd/homi/genesis"
    43  	"github.com/klaytn/klaytn/common"
    44  	"github.com/klaytn/klaytn/crypto"
    45  	"github.com/klaytn/klaytn/log"
    46  	"github.com/klaytn/klaytn/networks/p2p/discover"
    47  	"github.com/klaytn/klaytn/params"
    48  	"github.com/urfave/cli/v2"
    49  	"github.com/urfave/cli/v2/altsrc"
    50  )
    51  
    52  type ValidatorInfo struct {
    53  	Address  common.Address
    54  	Nodekey  string
    55  	NodeInfo string
    56  }
    57  
    58  type GrafanaFile struct {
    59  	url  string
    60  	name string
    61  }
    62  
    63  var HomiFlags = []cli.Flag{
    64  	homiYamlFlag,
    65  	altsrc.NewStringFlag(genTypeFlag),
    66  	altsrc.NewBoolFlag(cypressTestFlag),
    67  	altsrc.NewBoolFlag(cypressFlag),
    68  	altsrc.NewBoolFlag(baobabTestFlag),
    69  	altsrc.NewBoolFlag(baobabFlag),
    70  	altsrc.NewBoolFlag(serviceChainFlag),
    71  	altsrc.NewBoolFlag(serviceChainTestFlag),
    72  	altsrc.NewBoolFlag(cliqueFlag),
    73  	altsrc.NewIntFlag(numOfCNsFlag),
    74  	altsrc.NewIntFlag(numOfValidatorsFlag),
    75  	altsrc.NewIntFlag(numOfPNsFlag),
    76  	altsrc.NewIntFlag(numOfENsFlag),
    77  	altsrc.NewIntFlag(numOfSCNsFlag),
    78  	altsrc.NewIntFlag(numOfSPNsFlag),
    79  	altsrc.NewIntFlag(numOfSENsFlag),
    80  	altsrc.NewIntFlag(numOfTestKeyFlag),
    81  	altsrc.NewStringFlag(mnemonic),
    82  	altsrc.NewStringFlag(mnemonicPath),
    83  	altsrc.NewUint64Flag(chainIDFlag),
    84  	altsrc.NewUint64Flag(serviceChainIDFlag),
    85  	altsrc.NewUint64Flag(unitPriceFlag),
    86  	altsrc.NewIntFlag(deriveShaImplFlag),
    87  	altsrc.NewStringFlag(fundingAddrFlag),
    88  	altsrc.NewBoolFlag(patchAddressBookFlag),
    89  	altsrc.NewStringFlag(patchAddressBookAddrFlag),
    90  	altsrc.NewStringFlag(outputPathFlag),
    91  	altsrc.NewBoolFlag(addressBookMockFlag),
    92  	altsrc.NewStringFlag(dockerImageIdFlag),
    93  	altsrc.NewBoolFlag(fasthttpFlag),
    94  	altsrc.NewIntFlag(networkIdFlag),
    95  	altsrc.NewBoolFlag(nografanaFlag),
    96  	altsrc.NewBoolFlag(useTxGenFlag),
    97  	altsrc.NewIntFlag(txGenRateFlag),
    98  	altsrc.NewIntFlag(txGenThFlag),
    99  	altsrc.NewIntFlag(txGenConnFlag),
   100  	altsrc.NewStringFlag(txGenDurFlag),
   101  	altsrc.NewIntFlag(rpcPortFlag),
   102  	altsrc.NewIntFlag(wsPortFlag),
   103  	altsrc.NewIntFlag(p2pPortFlag),
   104  	altsrc.NewStringFlag(dataDirFlag),
   105  	altsrc.NewStringFlag(logDirFlag),
   106  	altsrc.NewBoolFlag(governanceFlag),
   107  	altsrc.NewStringFlag(govModeFlag),
   108  	altsrc.NewStringFlag(governingNodeFlag),
   109  	altsrc.NewStringFlag(govParamContractFlag),
   110  	altsrc.NewStringFlag(rewardMintAmountFlag),
   111  	altsrc.NewStringFlag(rewardRatioFlag),
   112  	altsrc.NewStringFlag(rewardKip82RatioFlag),
   113  	altsrc.NewBoolFlag(rewardGiniCoeffFlag),
   114  	altsrc.NewUint64Flag(rewardStakingFlag),
   115  	altsrc.NewUint64Flag(rewardProposerFlag),
   116  	altsrc.NewStringFlag(rewardMinimumStakeFlag),
   117  	altsrc.NewBoolFlag(rewardDeferredTxFeeFlag),
   118  	altsrc.NewUint64Flag(istEpochFlag),
   119  	altsrc.NewUint64Flag(istProposerPolicyFlag),
   120  	altsrc.NewUint64Flag(istSubGroupFlag),
   121  	altsrc.NewUint64Flag(cliqueEpochFlag),
   122  	altsrc.NewUint64Flag(cliquePeriodFlag),
   123  	altsrc.NewInt64Flag(istanbulCompatibleBlockNumberFlag),
   124  	altsrc.NewInt64Flag(londonCompatibleBlockNumberFlag),
   125  	altsrc.NewInt64Flag(ethTxTypeCompatibleBlockNumberFlag),
   126  	altsrc.NewInt64Flag(magmaCompatibleBlockNumberFlag),
   127  	altsrc.NewInt64Flag(koreCompatibleBlockNumberFlag),
   128  	altsrc.NewInt64Flag(shanghaiCompatibleBlockNumberFlag),
   129  	altsrc.NewInt64Flag(cancunCompatibleBlockNumberFlag),
   130  	altsrc.NewInt64Flag(kip103CompatibleBlockNumberFlag),
   131  	altsrc.NewStringFlag(kip103ContractAddressFlag),
   132  	altsrc.NewInt64Flag(randaoCompatibleBlockNumberFlag),
   133  	altsrc.NewStringFlag(kip113ProxyAddressFlag),
   134  	altsrc.NewStringFlag(kip113LogicAddressFlag),
   135  	altsrc.NewBoolFlag(kip113MockFlag),
   136  	altsrc.NewBoolFlag(registryMockFlag),
   137  }
   138  
   139  var SetupCommand = &cli.Command{
   140  	Name:  "setup",
   141  	Usage: "Generate klaytn CN's init files",
   142  	Description: `This tool helps generate:
   143  		* Genesis Block (genesis.json)
   144  		* Static nodes for all CNs(Consensus Node)
   145  		* CN details
   146  		* Docker-compose
   147  
   148  		for Klaytn Consensus Node.
   149  
   150  Args :
   151  		type : [local | remote | deploy | docker (default)]
   152  `,
   153  	Action:    Gen,
   154  	Flags:     HomiFlags,
   155  	ArgsUsage: "type",
   156  }
   157  
   158  const (
   159  	baobabOperatorAddress = "0x79deccfacd0599d3166eb76972be7bb20f51b46f"
   160  	baobabOperatorKey     = "199fd187fdb2ce5f577797e1abaf4dd50e62275949c021f0112be40c9721e1a2"
   161  )
   162  
   163  const (
   164  	DefaultTcpPort uint16 = 32323
   165  	TypeNotDefined        = -1
   166  	TypeDocker            = 0
   167  	TypeLocal             = 1
   168  	TypeRemote            = 2
   169  	TypeDeploy            = 3
   170  	DirScript             = "scripts"
   171  	DirKeys               = "keys"
   172  	DirPnScript           = "scripts_pn"
   173  	DirPnKeys             = "keys_pn"
   174  	DirTestKeys           = "keys_test"
   175  	CNIpNetwork           = "10.11.2"
   176  	PNIpNetwork1          = "10.11.10"
   177  	PNIpNetwork2          = "10.11.11"
   178  )
   179  
   180  var Types = [4]string{"docker", "local", "remote", "deploy"}
   181  
   182  var GrafanaFiles = [...]GrafanaFile{
   183  	{
   184  		url:  "https://s3.ap-northeast-2.amazonaws.com/klaytn-tools/Klaytn.json",
   185  		name: "Klaytn.json",
   186  	},
   187  	{
   188  		url:  "https://s3.ap-northeast-2.amazonaws.com/klaytn-tools/klaytn_txpool.json",
   189  		name: "Klaytn_txpool.json",
   190  	},
   191  }
   192  
   193  var lastIssuedPortNum = DefaultTcpPort
   194  
   195  func genRewardConfig(ctx *cli.Context) *params.RewardConfig {
   196  	mintingAmount := new(big.Int)
   197  	mintingAmountString := ctx.String(rewardMintAmountFlag.Name)
   198  	if _, ok := mintingAmount.SetString(mintingAmountString, 10); !ok {
   199  		log.Fatalf("Minting amount must be a number", "value", mintingAmountString)
   200  	}
   201  	ratio := ctx.String(rewardRatioFlag.Name)
   202  	kip82Ratio := ctx.String(rewardKip82RatioFlag.Name)
   203  	giniCoeff := ctx.Bool(rewardGiniCoeffFlag.Name)
   204  	deferredTxFee := ctx.Bool(rewardDeferredTxFeeFlag.Name)
   205  	stakingInterval := ctx.Uint64(rewardStakingFlag.Name)
   206  	proposalInterval := ctx.Uint64(rewardProposerFlag.Name)
   207  	minimumStake := new(big.Int)
   208  	minimumStakeString := ctx.String(rewardMinimumStakeFlag.Name)
   209  	if _, ok := minimumStake.SetString(minimumStakeString, 10); !ok {
   210  		log.Fatalf("Minimum stake must be a number", "value", minimumStakeString)
   211  	}
   212  
   213  	return &params.RewardConfig{
   214  		MintingAmount:          mintingAmount,
   215  		Ratio:                  ratio,
   216  		Kip82Ratio:             kip82Ratio,
   217  		UseGiniCoeff:           giniCoeff,
   218  		DeferredTxFee:          deferredTxFee,
   219  		StakingUpdateInterval:  stakingInterval,
   220  		ProposerUpdateInterval: proposalInterval,
   221  		MinimumStake:           minimumStake,
   222  	}
   223  }
   224  
   225  func genKIP71Config(ctx *cli.Context) *params.KIP71Config {
   226  	lowerBoundBaseFee := ctx.Uint64(magmaLowerBoundBaseFeeFlag.Name)
   227  	upperBoundBaseFee := ctx.Uint64(magmaUpperBoundBaseFeeFlag.Name)
   228  	gasTarget := ctx.Uint64(magmaGasTarget.Name)
   229  	maxBlockGasUsedForBaseFee := ctx.Uint64(magmaMaxBlockGasUsedForBaseFee.Name)
   230  	baseFeeDenominator := ctx.Uint64(magmaBaseFeeDenominator.Name)
   231  
   232  	return &params.KIP71Config{
   233  		LowerBoundBaseFee:         lowerBoundBaseFee,         // lower bound of the base fee
   234  		UpperBoundBaseFee:         upperBoundBaseFee,         // upper bound of the base fee
   235  		GasTarget:                 gasTarget,                 // standard gas usage for whether to raise or lower the base fee
   236  		MaxBlockGasUsedForBaseFee: maxBlockGasUsedForBaseFee, // maximum gas that can be used to calculate the base fee
   237  		BaseFeeDenominator:        baseFeeDenominator,        // scaling factor to adjust the gap between used and target gas
   238  	}
   239  }
   240  
   241  func genIstanbulConfig(ctx *cli.Context) *params.IstanbulConfig {
   242  	epoch := ctx.Uint64(istEpochFlag.Name)
   243  	policy := ctx.Uint64(istProposerPolicyFlag.Name)
   244  	subGroup := ctx.Uint64(istSubGroupFlag.Name)
   245  
   246  	return &params.IstanbulConfig{
   247  		Epoch:          epoch,
   248  		ProposerPolicy: policy,
   249  		SubGroupSize:   subGroup,
   250  	}
   251  }
   252  
   253  func genGovernanceConfig(ctx *cli.Context) *params.GovernanceConfig {
   254  	govMode := ctx.String(govModeFlag.Name)
   255  	governingNode := ctx.String(governingNodeFlag.Name)
   256  	if !common.IsHexAddress(governingNode) {
   257  		log.Fatalf("Governing Node is not a valid hex address", "value", governingNode)
   258  	}
   259  	govParamContract := ctx.String(govParamContractFlag.Name)
   260  	if !common.IsHexAddress(govParamContract) {
   261  		log.Fatalf("GovParam Contract is not a valid hex address", "value", govParamContract)
   262  	}
   263  	return &params.GovernanceConfig{
   264  		GoverningNode:    common.HexToAddress(governingNode),
   265  		GovernanceMode:   govMode,
   266  		GovParamContract: common.HexToAddress(govParamContract),
   267  		Reward:           genRewardConfig(ctx),
   268  		KIP71:            genKIP71Config(ctx),
   269  	}
   270  }
   271  
   272  func genCliqueConfig(ctx *cli.Context) *params.CliqueConfig {
   273  	epoch := ctx.Uint64(cliqueEpochFlag.Name)
   274  	period := ctx.Uint64(cliquePeriodFlag.Name)
   275  
   276  	return &params.CliqueConfig{
   277  		Period: period,
   278  		Epoch:  epoch,
   279  	}
   280  }
   281  
   282  func genIstanbulGenesis(ctx *cli.Context, nodeAddrs, testAddrs []common.Address, chainId uint64) *blockchain.Genesis {
   283  	unitPrice := ctx.Uint64(unitPriceFlag.Name)
   284  	chainID := new(big.Int).SetUint64(chainId)
   285  	deriveShaImpl := ctx.Int(deriveShaImplFlag.Name)
   286  
   287  	config := genGovernanceConfig(ctx)
   288  	if len(nodeAddrs) > 0 && config.GoverningNode.String() == params.DefaultGoverningNode {
   289  		config.GoverningNode = nodeAddrs[0]
   290  	}
   291  
   292  	options := []genesis.Option{
   293  		genesis.Validators(nodeAddrs...),
   294  		genesis.Alloc(append(nodeAddrs, testAddrs...), new(big.Int).Exp(big.NewInt(10), big.NewInt(50), nil)),
   295  		genesis.DeriveShaImpl(deriveShaImpl),
   296  		genesis.UnitPrice(unitPrice),
   297  		genesis.ChainID(chainID),
   298  	}
   299  
   300  	if ok := ctx.Bool(governanceFlag.Name); ok {
   301  		options = append(options, genesis.Governance(config))
   302  	}
   303  	options = append(options, genesis.Istanbul(genIstanbulConfig(ctx)))
   304  
   305  	return genesis.New(options...)
   306  }
   307  
   308  func genCliqueGenesis(ctx *cli.Context, nodeAddrs, testAddrs []common.Address, chainId uint64) *blockchain.Genesis {
   309  	config := genCliqueConfig(ctx)
   310  	unitPrice := ctx.Uint64(unitPriceFlag.Name)
   311  	chainID := new(big.Int).SetUint64(chainId)
   312  
   313  	if ok := ctx.Bool(governanceFlag.Name); ok {
   314  		log.Fatalf("Currently, governance is not supported for clique consensus", "--governance", ok)
   315  	}
   316  
   317  	genesisJson := genesis.NewClique(
   318  		genesis.ValidatorsOfClique(nodeAddrs...),
   319  		genesis.Alloc(append(nodeAddrs, testAddrs...), new(big.Int).Exp(big.NewInt(10), big.NewInt(50), nil)),
   320  		genesis.UnitPrice(unitPrice),
   321  		genesis.ChainID(chainID),
   322  		genesis.Clique(config),
   323  	)
   324  	return genesisJson
   325  }
   326  
   327  func genValidatorKeystore(privKeys []*ecdsa.PrivateKey) {
   328  	path := path.Join(outputPath, DirKeys)
   329  	ks := keystore.NewKeyStore(path, keystore.StandardScryptN, keystore.StandardScryptP)
   330  
   331  	for i, pk := range privKeys {
   332  		pwdStr := RandStringRunes(params.PasswordLength)
   333  		account, _ := ks.ImportECDSA(pk, pwdStr)
   334  		genRewardKeystore(account, i)
   335  		WriteFile([]byte(pwdStr), DirKeys, "passwd"+strconv.Itoa(i+1))
   336  	}
   337  }
   338  
   339  func genRewardKeystore(account accounts.Account, i int) {
   340  	file, err := os.Open(account.URL.Path)
   341  	if err != nil {
   342  		log.Fatalf("Failed to open file: %s", err)
   343  	}
   344  	defer file.Close()
   345  
   346  	data, err := io.ReadAll(file)
   347  	if err != nil {
   348  		log.Fatalf("Failed to read file: %s", err)
   349  	}
   350  
   351  	v := make(map[string]interface{})
   352  	if err := json.Unmarshal(data, &v); err != nil {
   353  		log.Fatalf("Failed to unmarshal keystore file: %s", err)
   354  	}
   355  
   356  	WriteFile([]byte(v["address"].(string)), DirKeys, "reward"+strconv.Itoa(i+1))
   357  	WriteFile(data, DirKeys, "keystore"+strconv.Itoa(i+1))
   358  
   359  	// Remove UTC-XXX file created by keystore package
   360  	os.Remove(account.URL.Path)
   361  }
   362  
   363  func genCypressCommonGenesis(nodeAddrs, testAddrs []common.Address) *blockchain.Genesis {
   364  	mintingAmount, _ := new(big.Int).SetString("9600000000000000000", 10)
   365  	genesisJson := &blockchain.Genesis{
   366  		Timestamp:  uint64(time.Now().Unix()),
   367  		BlockScore: big.NewInt(genesis.InitBlockScore),
   368  		Alloc:      make(blockchain.GenesisAlloc),
   369  		Config: &params.ChainConfig{
   370  			ChainID:       big.NewInt(10000),
   371  			DeriveShaImpl: 2,
   372  			Governance: &params.GovernanceConfig{
   373  				GoverningNode:  nodeAddrs[0],
   374  				GovernanceMode: "single",
   375  				Reward: &params.RewardConfig{
   376  					MintingAmount: mintingAmount,
   377  					Ratio:         "34/54/12",
   378  					UseGiniCoeff:  true,
   379  					DeferredTxFee: true,
   380  				},
   381  			},
   382  			Istanbul: &params.IstanbulConfig{
   383  				ProposerPolicy: 2,
   384  				SubGroupSize:   22,
   385  			},
   386  			UnitPrice: 25000000000,
   387  		},
   388  	}
   389  	assignExtraData := genesis.Validators(nodeAddrs...)
   390  	assignExtraData(genesisJson)
   391  
   392  	return genesisJson
   393  }
   394  
   395  func genCypressGenesis(nodeAddrs, testAddrs []common.Address) *blockchain.Genesis {
   396  	genesisJson := genCypressCommonGenesis(nodeAddrs, testAddrs)
   397  	genesisJson.Config.Istanbul.Epoch = 604800
   398  	genesisJson.Config.Governance.Reward.StakingUpdateInterval = 86400
   399  	genesisJson.Config.Governance.Reward.ProposerUpdateInterval = 3600
   400  	genesisJson.Config.Governance.Reward.MinimumStake = new(big.Int).SetUint64(5000000)
   401  	allocationFunction := genesis.AllocWithCypressContract(append(nodeAddrs, testAddrs...), new(big.Int).Exp(big.NewInt(10), big.NewInt(50), nil))
   402  	allocationFunction(genesisJson)
   403  	return genesisJson
   404  }
   405  
   406  func genServiceChainCommonGenesis(nodeAddrs, testAddrs []common.Address) *blockchain.Genesis {
   407  	genesisJson := &blockchain.Genesis{
   408  		Timestamp:  uint64(time.Now().Unix()),
   409  		BlockScore: big.NewInt(genesis.InitBlockScore),
   410  		Alloc:      make(blockchain.GenesisAlloc),
   411  		Config: &params.ChainConfig{
   412  			ChainID:       big.NewInt(1000),
   413  			DeriveShaImpl: 2,
   414  			Istanbul: &params.IstanbulConfig{
   415  				ProposerPolicy: 0,
   416  				SubGroupSize:   22,
   417  			},
   418  			UnitPrice: 0,
   419  		},
   420  	}
   421  	assignExtraData := genesis.Validators(nodeAddrs...)
   422  	assignExtraData(genesisJson)
   423  
   424  	return genesisJson
   425  }
   426  
   427  func genServiceChainGenesis(nodeAddrs, testAddrs []common.Address) *blockchain.Genesis {
   428  	genesisJson := genServiceChainCommonGenesis(nodeAddrs, testAddrs)
   429  	genesisJson.Config.Istanbul.Epoch = 3600
   430  	allocationFunction := genesis.Alloc(append(nodeAddrs, testAddrs...), new(big.Int).Exp(big.NewInt(10), big.NewInt(50), nil))
   431  	allocationFunction(genesisJson)
   432  	return genesisJson
   433  }
   434  
   435  func genServiceChainTestGenesis(nodeAddrs, testAddrs []common.Address) *blockchain.Genesis {
   436  	genesisJson := genServiceChainCommonGenesis(nodeAddrs, testAddrs)
   437  	genesisJson.Config.Istanbul.Epoch = 30
   438  	allocationFunction := genesis.Alloc(append(nodeAddrs, testAddrs...), new(big.Int).Exp(big.NewInt(10), big.NewInt(50), nil))
   439  	allocationFunction(genesisJson)
   440  	return genesisJson
   441  }
   442  
   443  func genCypressTestGenesis(nodeAddrs, testAddrs []common.Address) *blockchain.Genesis {
   444  	testGenesis := genCypressCommonGenesis(nodeAddrs, testAddrs)
   445  	testGenesis.Config.Istanbul.Epoch = 30
   446  	testGenesis.Config.Governance.Reward.StakingUpdateInterval = 60
   447  	testGenesis.Config.Governance.Reward.ProposerUpdateInterval = 30
   448  	testGenesis.Config.Governance.Reward.MinimumStake = new(big.Int).SetUint64(5000000)
   449  	allocationFunction := genesis.AllocWithPrecypressContract(append(nodeAddrs, testAddrs...), new(big.Int).Exp(big.NewInt(10), big.NewInt(50), nil))
   450  	allocationFunction(testGenesis)
   451  	return testGenesis
   452  }
   453  
   454  func genBaobabCommonGenesis(nodeAddrs, testAddrs []common.Address) *blockchain.Genesis {
   455  	mintingAmount, _ := new(big.Int).SetString("9600000000000000000", 10)
   456  	genesisJson := &blockchain.Genesis{
   457  		Timestamp:  uint64(time.Now().Unix()),
   458  		BlockScore: big.NewInt(genesis.InitBlockScore),
   459  		Alloc:      make(blockchain.GenesisAlloc),
   460  		Config: &params.ChainConfig{
   461  			ChainID:       big.NewInt(2019),
   462  			DeriveShaImpl: 2,
   463  			Governance: &params.GovernanceConfig{
   464  				GoverningNode:  nodeAddrs[0],
   465  				GovernanceMode: "single",
   466  				Reward: &params.RewardConfig{
   467  					MintingAmount: mintingAmount,
   468  					Ratio:         "34/54/12",
   469  					UseGiniCoeff:  false,
   470  					DeferredTxFee: true,
   471  				},
   472  			},
   473  			Istanbul: &params.IstanbulConfig{
   474  				ProposerPolicy: 2,
   475  				SubGroupSize:   13,
   476  			},
   477  			UnitPrice: 25000000000,
   478  		},
   479  	}
   480  	assignExtraData := genesis.Validators(nodeAddrs...)
   481  	assignExtraData(genesisJson)
   482  
   483  	return genesisJson
   484  }
   485  
   486  func genBaobabGenesis(nodeAddrs, testAddrs []common.Address) *blockchain.Genesis {
   487  	genesisJson := genBaobabCommonGenesis(nodeAddrs, testAddrs)
   488  	genesisJson.Config.Istanbul.Epoch = 604800
   489  	genesisJson.Config.Governance.Reward.StakingUpdateInterval = 86400
   490  	genesisJson.Config.Governance.Reward.ProposerUpdateInterval = 3600
   491  	genesisJson.Config.Governance.Reward.MinimumStake = new(big.Int).SetUint64(5000000)
   492  	allocationFunction := genesis.AllocWithBaobabContract(append(nodeAddrs, testAddrs...), new(big.Int).Exp(big.NewInt(10), big.NewInt(50), nil))
   493  	allocationFunction(genesisJson)
   494  	return genesisJson
   495  }
   496  
   497  func genBaobabTestGenesis(nodeAddrs, testAddrs []common.Address) *blockchain.Genesis {
   498  	testGenesis := genBaobabCommonGenesis(nodeAddrs, testAddrs)
   499  	testGenesis.Config.Istanbul.Epoch = 30
   500  	testGenesis.Config.Governance.Reward.StakingUpdateInterval = 60
   501  	testGenesis.Config.Governance.Reward.ProposerUpdateInterval = 30
   502  	testGenesis.Config.Governance.Reward.MinimumStake = new(big.Int).SetUint64(5000000)
   503  	allocationFunction := genesis.AllocWithPrebaobabContract(append(nodeAddrs, testAddrs...), new(big.Int).Exp(big.NewInt(10), big.NewInt(50), nil))
   504  	allocationFunction(testGenesis)
   505  	WriteFile([]byte(baobabOperatorAddress), "baobab_operator", "address")
   506  	WriteFile([]byte(baobabOperatorKey), "baobab_operator", "private")
   507  	return testGenesis
   508  }
   509  
   510  func allocGenesisFund(ctx *cli.Context, genesisJson *blockchain.Genesis) {
   511  	fundingAddr := ctx.String(fundingAddrFlag.Name)
   512  	if len(fundingAddr) == 0 {
   513  		return
   514  	}
   515  
   516  	if !common.IsHexAddress(fundingAddr) {
   517  		log.Fatalf("'%s' is not a valid hex address", fundingAddr)
   518  	}
   519  	addr := common.HexToAddress(fundingAddr)
   520  	balance := new(big.Int).Exp(big.NewInt(10), big.NewInt(50), nil)
   521  	genesisJson.Alloc[addr] = blockchain.GenesisAccount{Balance: balance}
   522  }
   523  
   524  func patchGenesisAddressBook(ctx *cli.Context, genesisJson *blockchain.Genesis, nodeAddrs []common.Address) {
   525  	if patchAddressBook := ctx.Bool(patchAddressBookFlag.Name); !patchAddressBook {
   526  		return
   527  	}
   528  
   529  	var targetAddr common.Address
   530  
   531  	patchAddressBookAddr := ctx.String(patchAddressBookAddrFlag.Name)
   532  	if len(patchAddressBookAddr) == 0 {
   533  		if len(nodeAddrs) == 0 {
   534  			log.Fatalf("Need at least one consensus node (--cn-num 1) to patch AddressBook with the first CN")
   535  		}
   536  		targetAddr = nodeAddrs[0]
   537  	} else {
   538  		if !common.IsHexAddress(patchAddressBookAddr) {
   539  			log.Fatalf("'%s' is not a valid hex address", patchAddressBookAddr)
   540  		}
   541  		targetAddr = common.HexToAddress(patchAddressBookAddr)
   542  	}
   543  
   544  	allocationFunction := genesis.PatchAddressBook(targetAddr)
   545  	allocationFunction(genesisJson)
   546  }
   547  
   548  func useAddressBookMock(ctx *cli.Context, genesisJson *blockchain.Genesis) {
   549  	if useMock := ctx.Bool(addressBookMockFlag.Name); !useMock {
   550  		return
   551  	}
   552  
   553  	allocationFunction := genesis.AddressBookMock()
   554  	allocationFunction(genesisJson)
   555  }
   556  
   557  func allocateRegistry(ctx *cli.Context, genesisJson *blockchain.Genesis, owner common.Address, kip113Addr *common.Address) {
   558  	if randaoCompatibleBlock := ctx.Int64(randaoCompatibleBlockNumberFlag.Name); randaoCompatibleBlock != 0 {
   559  		return
   560  	}
   561  
   562  	registryConfig := &params.RegistryConfig{
   563  		Records: make(map[string]common.Address),
   564  		Owner:   owner,
   565  	}
   566  
   567  	if kip113Addr != nil {
   568  		registryConfig.Records[system.Kip113Name] = *kip113Addr
   569  	}
   570  
   571  	allocRegistryStorage := system.AllocRegistry(registryConfig)
   572  
   573  	allocationFunction := genesis.AllocateRegistry(allocRegistryStorage)
   574  	allocationFunction(genesisJson)
   575  }
   576  
   577  func useRegistryMock(ctx *cli.Context, genesisJson *blockchain.Genesis) {
   578  	if useMock := ctx.Bool(registryMockFlag.Name); !useMock {
   579  		return
   580  	}
   581  
   582  	allocationFunction := genesis.RegistryMock()
   583  	allocationFunction(genesisJson)
   584  }
   585  
   586  func allocateKip113(ctx *cli.Context, genesisJson *blockchain.Genesis, init system.AllocKip113Init) (*common.Address, *common.Address) {
   587  	if randaoCompatibleBlock := ctx.Int64(randaoCompatibleBlockNumberFlag.Name); randaoCompatibleBlock != 0 {
   588  		return nil, nil
   589  	}
   590  	if len(init.Infos) == 0 {
   591  		return nil, nil
   592  	}
   593  
   594  	kip113ProxyAddr := common.HexToAddress(ctx.String(kip113ProxyAddressFlag.Name))
   595  	kip113LogicAddr := common.HexToAddress(ctx.String(kip113LogicAddressFlag.Name))
   596  
   597  	if !common.IsHexAddress(ctx.String(kip113ProxyAddressFlag.Name)) {
   598  		log.Fatalf("Kip113 proxy address is not a valid hex address", "value", kip113ProxyAddr)
   599  		kip113ProxyAddr = system.Kip113ProxyAddrMock
   600  	}
   601  	if !common.IsHexAddress(ctx.String(kip113LogicAddressFlag.Name)) {
   602  		log.Fatalf("Kip113 logic address is not a valid hex address", "value", kip113LogicAddr)
   603  		kip113LogicAddr = system.Kip113LogicAddrMock
   604  	}
   605  
   606  	allocProxyStorage := system.AllocProxy(kip113LogicAddr)
   607  	allocKip113Storage := system.AllocKip113Proxy(init)
   608  	allocStorage := system.MergeStorage(allocProxyStorage, allocKip113Storage)
   609  	allocLogicStorage := system.AllocKip113Logic()
   610  
   611  	allocationFunction := genesis.AllocateKip113(kip113ProxyAddr, kip113LogicAddr, allocStorage, allocLogicStorage)
   612  	allocationFunction(genesisJson)
   613  
   614  	return &kip113ProxyAddr, &kip113LogicAddr
   615  }
   616  
   617  func useKip113Mock(ctx *cli.Context, genesisJson *blockchain.Genesis, kip113LogicAddr *common.Address) {
   618  	if useMock := ctx.Bool(kip113MockFlag.Name); !useMock {
   619  		return
   620  	}
   621  	if kip113LogicAddr == nil {
   622  		return
   623  	}
   624  
   625  	allocationFunction := genesis.Kip113Mock(*kip113LogicAddr)
   626  	allocationFunction(genesisJson)
   627  }
   628  
   629  func RandStringRunes(n int) string {
   630  	letterRunes := []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789~!@#$%^&*()_+{}|[]")
   631  
   632  	rand.Seed(time.Now().UnixNano())
   633  
   634  	b := make([]rune, n)
   635  	for i := range b {
   636  		b[i] = letterRunes[rand.Intn(len(letterRunes))]
   637  	}
   638  	return string(b)
   639  }
   640  
   641  func Gen(ctx *cli.Context) error {
   642  	genType := findGenType(ctx)
   643  
   644  	cnNum := ctx.Int(numOfCNsFlag.Name)
   645  	numValidators := ctx.Int(numOfValidatorsFlag.Name)
   646  	pnNum := ctx.Int(numOfPNsFlag.Name)
   647  	enNum := ctx.Int(numOfENsFlag.Name)
   648  	scnNum := ctx.Int(numOfSCNsFlag.Name)
   649  	spnNum := ctx.Int(numOfSPNsFlag.Name)
   650  	senNum := ctx.Int(numOfSENsFlag.Name)
   651  	numTestAccs := ctx.Int(numOfTestKeyFlag.Name)
   652  	baobab := ctx.Bool(baobabFlag.Name)
   653  	baobabTest := ctx.Bool(baobabTestFlag.Name)
   654  	cypress := ctx.Bool(cypressFlag.Name)
   655  	cypressTest := ctx.Bool(cypressTestFlag.Name)
   656  	clique := ctx.Bool(cliqueFlag.Name)
   657  	serviceChain := ctx.Bool(serviceChainFlag.Name)
   658  	serviceChainTest := ctx.Bool(serviceChainTestFlag.Name)
   659  	chainid := ctx.Uint64(chainIDFlag.Name)
   660  	serviceChainId := ctx.Uint64(serviceChainIDFlag.Name)
   661  
   662  	// Note-klaytn : the following code that seems unnecessary is for the priority to flags, not yaml
   663  	if !baobab && !baobabTest && !cypress && !cypressTest && !serviceChain && !serviceChainTest && !clique {
   664  		switch genesisType := ctx.String(genesisTypeFlag.Name); genesisType {
   665  		case "baobab":
   666  			baobab = true
   667  		case "baobab-test":
   668  			baobabTest = true
   669  		case "cypress":
   670  			cypress = true
   671  		case "cypress-test":
   672  			cypressTest = true
   673  		case "servicechain":
   674  			serviceChain = true
   675  		case "servicechain-test":
   676  			serviceChainTest = true
   677  		case "clique":
   678  			clique = true
   679  		default:
   680  			fmt.Printf("Unknown genesis type is %s.\n", genesisType)
   681  		}
   682  	}
   683  
   684  	if cnNum == 0 && scnNum == 0 {
   685  		return fmt.Errorf("needed at least one consensus node (--cn-num 1) or one service chain consensus node (--scn-num 1) ")
   686  	}
   687  
   688  	if numValidators == 0 {
   689  		numValidators = cnNum
   690  	}
   691  	if numValidators > cnNum {
   692  		return fmt.Errorf("validators-num(%d) cannot be greater than num(%d)", numValidators, cnNum)
   693  	}
   694  
   695  	var (
   696  		privKeys  []*ecdsa.PrivateKey
   697  		nodeKeys  []string
   698  		nodeAddrs []common.Address
   699  	)
   700  
   701  	if len(ctx.String(mnemonic.Name)) == 0 {
   702  		privKeys, nodeKeys, nodeAddrs = istcommon.GenerateKeys(cnNum)
   703  	} else {
   704  		mnemonic := ctx.String(mnemonic.Name)
   705  		mnemonic = strings.ReplaceAll(mnemonic, ",", " ")
   706  		// common keys used by web3 tools such as hardhat, foundry, etc.
   707  		if mnemonic == "test junk" {
   708  			mnemonic = "test test test test test test test test test test test junk"
   709  		}
   710  		path := strings.ToLower(ctx.String(mnemonicPath.Name))
   711  		if !strings.HasPrefix(path, "m") {
   712  			switch path {
   713  			case "klay":
   714  				path = "m/44'/8217'/0'/0/"
   715  			case "eth":
   716  				path = "m/44'/60'/0'/0/"
   717  			default:
   718  				return fmt.Errorf("invalid mnemonic path (format: m/44'/60'/0'/0/)")
   719  			}
   720  		}
   721  		privKeys, nodeKeys, nodeAddrs = istcommon.GenerateKeysFromMnemonic(cnNum, mnemonic, path)
   722  	}
   723  
   724  	testPrivKeys, testKeys, testAddrs := istcommon.GenerateKeys(numTestAccs)
   725  	kip113Init := istcommon.GenerateKip113Init(privKeys[:numValidators], nodeAddrs[0])
   726  
   727  	var (
   728  		genesisJson      *blockchain.Genesis
   729  		genesisJsonBytes []byte
   730  	)
   731  
   732  	validatorNodeAddrs := make([]common.Address, numValidators)
   733  	copy(validatorNodeAddrs, nodeAddrs[:numValidators])
   734  
   735  	if cypressTest {
   736  		genesisJson = genCypressTestGenesis(validatorNodeAddrs, testAddrs)
   737  	} else if cypress {
   738  		genesisJson = genCypressGenesis(validatorNodeAddrs, testAddrs)
   739  	} else if baobabTest {
   740  		genesisJson = genBaobabTestGenesis(validatorNodeAddrs, testAddrs)
   741  	} else if baobab {
   742  		genesisJson = genBaobabGenesis(validatorNodeAddrs, testAddrs)
   743  	} else if clique {
   744  		genesisJson = genCliqueGenesis(ctx, validatorNodeAddrs, testAddrs, chainid)
   745  	} else if serviceChain {
   746  		genesisJson = genServiceChainGenesis(validatorNodeAddrs, testAddrs)
   747  	} else if serviceChainTest {
   748  		genesisJson = genServiceChainTestGenesis(validatorNodeAddrs, testAddrs)
   749  	} else {
   750  		genesisJson = genIstanbulGenesis(ctx, validatorNodeAddrs, testAddrs, chainid)
   751  	}
   752  
   753  	allocGenesisFund(ctx, genesisJson)
   754  	patchGenesisAddressBook(ctx, genesisJson, validatorNodeAddrs)
   755  	useAddressBookMock(ctx, genesisJson)
   756  
   757  	// Randao hardfork related system contracts
   758  	kip113ProxyAddr, kip113LogicAddr := allocateKip113(ctx, genesisJson, kip113Init)
   759  	allocateRegistry(ctx, genesisJson, nodeAddrs[0], kip113ProxyAddr)
   760  	useKip113Mock(ctx, genesisJson, kip113LogicAddr)
   761  	useRegistryMock(ctx, genesisJson)
   762  
   763  	genesisJson.Config.IstanbulCompatibleBlock = big.NewInt(ctx.Int64(istanbulCompatibleBlockNumberFlag.Name))
   764  	genesisJson.Config.LondonCompatibleBlock = big.NewInt(ctx.Int64(londonCompatibleBlockNumberFlag.Name))
   765  	genesisJson.Config.EthTxTypeCompatibleBlock = big.NewInt(ctx.Int64(ethTxTypeCompatibleBlockNumberFlag.Name))
   766  	genesisJson.Config.MagmaCompatibleBlock = big.NewInt(ctx.Int64(magmaCompatibleBlockNumberFlag.Name))
   767  	genesisJson.Config.KoreCompatibleBlock = big.NewInt(ctx.Int64(koreCompatibleBlockNumberFlag.Name))
   768  	genesisJson.Config.ShanghaiCompatibleBlock = big.NewInt(ctx.Int64(shanghaiCompatibleBlockNumberFlag.Name))
   769  	genesisJson.Config.CancunCompatibleBlock = big.NewInt(ctx.Int64(cancunCompatibleBlockNumberFlag.Name))
   770  
   771  	// KIP103 hardfork is optional
   772  	genesisJson.Config.Kip103CompatibleBlock = big.NewInt(ctx.Int64(kip103CompatibleBlockNumberFlag.Name))
   773  	genesisJson.Config.Kip103ContractAddress = common.HexToAddress(ctx.String(kip103ContractAddressFlag.Name))
   774  
   775  	genesisJson.Config.RandaoCompatibleBlock = big.NewInt(ctx.Int64(randaoCompatibleBlockNumberFlag.Name))
   776  
   777  	genesisJsonBytes, _ = json.MarshalIndent(genesisJson, "", "    ")
   778  	genValidatorKeystore(privKeys)
   779  	lastIssuedPortNum = uint16(ctx.Int(p2pPortFlag.Name))
   780  
   781  	switch genType {
   782  	case TypeDocker:
   783  		validators := makeValidators(cnNum, false, nodeAddrs, nodeKeys, privKeys)
   784  		pnValidators, proxyNodeKeys := makeProxys(pnNum, false)
   785  		nodeInfos := filterNodeInfo(validators)
   786  		staticNodesJsonBytes, _ := json.MarshalIndent(nodeInfos, "", "\t")
   787  		address := filterAddressesString(validators)
   788  		pnInfos := filterNodeInfo(pnValidators)
   789  		enValidators, enKeys := makeEndpoints(enNum, false)
   790  		enInfos := filterNodeInfo(enValidators)
   791  
   792  		scnValidators, scnKeys := makeSCNs(scnNum, false)
   793  		scnInfos := filterNodeInfo(scnValidators)
   794  		scnAddress := filterAddresses(scnValidators)
   795  
   796  		spnValidators, spnKeys := makeSPNs(spnNum, false)
   797  		spnInfos := filterNodeInfo(spnValidators)
   798  
   799  		senValidators, senKeys := makeSENs(senNum, false)
   800  		senInfos := filterNodeInfo(senValidators)
   801  
   802  		staticPNJsonBytes, _ := json.MarshalIndent(pnInfos, "", "\t")
   803  		staticENJsonBytes, _ := json.MarshalIndent(enInfos, "", "\t")
   804  		staticSCNJsonBytes, _ := json.MarshalIndent(scnInfos, "", "\t")
   805  		staticSPNJsonBytes, _ := json.MarshalIndent(spnInfos, "", "\t")
   806  		staticSENJsonBytes, _ := json.MarshalIndent(senInfos, "", "\t")
   807  		var bridgeNodesJsonBytes []byte
   808  		if len(enInfos) != 0 {
   809  			bridgeNodesJsonBytes, _ = json.MarshalIndent(enInfos[:1], "", "\t")
   810  		}
   811  		scnGenesisJsonBytes, _ := json.MarshalIndent(genIstanbulGenesis(ctx, scnAddress, nil, serviceChainId), "", "\t")
   812  
   813  		dockerImageId := ctx.String(dockerImageIdFlag.Name)
   814  
   815  		compose := compose.New(
   816  			"172.16.239",
   817  			cnNum,
   818  			"bb98a0b6442386d0cdf8a31b267892c1",
   819  			address,
   820  			nodeKeys,
   821  			removeSpacesAndLines(genesisJsonBytes),
   822  			removeSpacesAndLines(scnGenesisJsonBytes),
   823  			removeSpacesAndLines(staticNodesJsonBytes),
   824  			removeSpacesAndLines(staticPNJsonBytes),
   825  			removeSpacesAndLines(staticENJsonBytes),
   826  			removeSpacesAndLines(staticSCNJsonBytes),
   827  			removeSpacesAndLines(staticSPNJsonBytes),
   828  			removeSpacesAndLines(staticSENJsonBytes),
   829  			removeSpacesAndLines(bridgeNodesJsonBytes),
   830  			dockerImageId,
   831  			ctx.Bool(fasthttpFlag.Name),
   832  			ctx.Int(networkIdFlag.Name),
   833  			int(chainid),
   834  			!ctx.Bool(nografanaFlag.Name),
   835  			proxyNodeKeys,
   836  			enKeys,
   837  			scnKeys,
   838  			spnKeys,
   839  			senKeys,
   840  			ctx.Bool(useTxGenFlag.Name),
   841  			service.TxGenOption{
   842  				TxGenRate:       ctx.Int(txGenRateFlag.Name),
   843  				TxGenThreadSize: ctx.Int(txGenThFlag.Name),
   844  				TxGenConnSize:   ctx.Int(txGenConnFlag.Name),
   845  				TxGenDuration:   ctx.String(txGenDurFlag.Name),
   846  			})
   847  		os.MkdirAll(outputPath, os.ModePerm)
   848  		os.WriteFile(path.Join(outputPath, "docker-compose.yml"), []byte(compose.String()), os.ModePerm)
   849  		fmt.Println("Created : ", path.Join(outputPath, "docker-compose.yml"))
   850  		os.WriteFile(path.Join(outputPath, "prometheus.yml"), []byte(compose.PrometheusService.Config.String()), os.ModePerm)
   851  		fmt.Println("Created : ", path.Join(outputPath, "prometheus.yml"))
   852  		downLoadGrafanaJson()
   853  	case TypeLocal:
   854  		writeNodeFiles(true, cnNum, pnNum, nodeAddrs, nodeKeys, privKeys, genesisJsonBytes)
   855  		writeTestKeys(DirTestKeys, testPrivKeys, testKeys)
   856  		downLoadGrafanaJson()
   857  	case TypeRemote:
   858  		writeNodeFiles(false, cnNum, pnNum, nodeAddrs, nodeKeys, privKeys, genesisJsonBytes)
   859  		writeTestKeys(DirTestKeys, testPrivKeys, testKeys)
   860  		downLoadGrafanaJson()
   861  	case TypeDeploy:
   862  		writeCNInfoKey(cnNum, nodeAddrs, nodeKeys, privKeys, genesisJsonBytes)
   863  		writeKlayConfig(ctx.Int(networkIdFlag.Name), ctx.Int(rpcPortFlag.Name), ctx.Int(wsPortFlag.Name), ctx.Int(p2pPortFlag.Name),
   864  			ctx.String(dataDirFlag.Name), ctx.String(logDirFlag.Name), "CN")
   865  		writeKlayConfig(ctx.Int(networkIdFlag.Name), ctx.Int(rpcPortFlag.Name), ctx.Int(wsPortFlag.Name), ctx.Int(p2pPortFlag.Name),
   866  			ctx.String(dataDirFlag.Name), ctx.String(logDirFlag.Name), "PN")
   867  		writePNInfoKey(ctx.Int(numOfPNsFlag.Name))
   868  		writePrometheusConfig(cnNum, ctx.Int(numOfPNsFlag.Name))
   869  	}
   870  
   871  	return nil
   872  }
   873  
   874  func downLoadGrafanaJson() {
   875  	for _, file := range GrafanaFiles {
   876  		resp, err := http.Get(file.url)
   877  		if err != nil {
   878  			fmt.Printf("Failed to download the imgs dashboard file(%s) - %v\n", file.url, err)
   879  		} else if resp.StatusCode != 200 {
   880  			fmt.Printf("Failed to download the imgs dashboard file(%s) [%s] - %v\n", file.url, resp.Status, err)
   881  		} else {
   882  			bytes, e := io.ReadAll(resp.Body)
   883  			if e != nil {
   884  				fmt.Println("Failed to read http response", e)
   885  			} else {
   886  				fileName := file.name
   887  				os.WriteFile(path.Join(outputPath, fileName), bytes, os.ModePerm)
   888  				fmt.Println("Created : ", path.Join(outputPath, fileName))
   889  			}
   890  			resp.Body.Close()
   891  		}
   892  	}
   893  }
   894  
   895  func writeCNInfoKey(num int, nodeAddrs []common.Address, nodeKeys []string, privKeys []*ecdsa.PrivateKey,
   896  	genesisJsonBytes []byte,
   897  ) {
   898  	const DirCommon = "common"
   899  	WriteFile(genesisJsonBytes, DirCommon, "genesis.json")
   900  
   901  	validators := makeValidatorsWithIp(num, false, nodeAddrs, nodeKeys, privKeys, []string{CNIpNetwork})
   902  	staticNodesJsonBytes, _ := json.MarshalIndent(filterNodeInfo(validators), "", "\t")
   903  	WriteFile(staticNodesJsonBytes, DirCommon, "static-nodes.json")
   904  
   905  	for i, v := range validators {
   906  		parentDir := fmt.Sprintf("cn%02d", i+1)
   907  		WriteFile([]byte(nodeKeys[i]), parentDir, "nodekey")
   908  		str, _ := json.MarshalIndent(v, "", "\t")
   909  		WriteFile([]byte(str), parentDir, "validator")
   910  	}
   911  }
   912  
   913  func writePNInfoKey(num int) {
   914  	privKeys, nodeKeys, nodeAddrs := istcommon.GenerateKeys(num)
   915  	validators := makeValidatorsWithIp(num, false, nodeAddrs, nodeKeys, privKeys, []string{PNIpNetwork1, PNIpNetwork2})
   916  	for i, v := range validators {
   917  		parentDir := fmt.Sprintf("pn%02d", i+1)
   918  		WriteFile([]byte(nodeKeys[i]), parentDir, "nodekey")
   919  		str, _ := json.MarshalIndent(v, "", "\t")
   920  		WriteFile([]byte(str), parentDir, "validator")
   921  	}
   922  }
   923  
   924  func writeKlayConfig(networkId int, rpcPort int, wsPort int, p2pPort int, dataDir string, logDir string, nodeType string) {
   925  	kConfig := NewKlaytnConfig(networkId, rpcPort, wsPort, p2pPort, dataDir, logDir, "/var/run/klay", nodeType)
   926  	WriteFile([]byte(kConfig.String()), strings.ToLower(nodeType), "klay.conf")
   927  }
   928  
   929  func writePrometheusConfig(cnNum int, pnNum int) {
   930  	pConf := NewPrometheusConfig(cnNum, CNIpNetwork, pnNum, PNIpNetwork1, PNIpNetwork2)
   931  	WriteFile([]byte(pConf.String()), "monitoring", "prometheus.yml")
   932  }
   933  
   934  func writeNodeFiles(isWorkOnSingleHost bool, num int, pnum int, nodeAddrs []common.Address, nodeKeys []string,
   935  	privKeys []*ecdsa.PrivateKey, genesisJsonBytes []byte,
   936  ) {
   937  	WriteFile(genesisJsonBytes, DirScript, "genesis.json")
   938  
   939  	validators := makeValidators(num, isWorkOnSingleHost, nodeAddrs, nodeKeys, privKeys)
   940  	nodeInfos := filterNodeInfo(validators)
   941  	staticNodesJsonBytes, _ := json.MarshalIndent(nodeInfos, "", "\t")
   942  	writeValidatorsAndNodesToFile(validators, DirKeys, nodeKeys)
   943  	WriteFile(staticNodesJsonBytes, DirScript, "static-nodes.json")
   944  
   945  	if pnum > 0 {
   946  		proxys, proxyNodeKeys := makeProxys(pnum, isWorkOnSingleHost)
   947  		pNodeInfos := filterNodeInfo(proxys)
   948  		staticPNodesJsonBytes, _ := json.MarshalIndent(pNodeInfos, "", "\t")
   949  		writeValidatorsAndNodesToFile(proxys, DirPnKeys, proxyNodeKeys)
   950  		WriteFile(staticPNodesJsonBytes, DirPnScript, "static-nodes.json")
   951  	}
   952  }
   953  
   954  func filterAddresses(validatorInfos []*ValidatorInfo) []common.Address {
   955  	var addresses []common.Address
   956  	for _, v := range validatorInfos {
   957  		addresses = append(addresses, v.Address)
   958  	}
   959  	return addresses
   960  }
   961  
   962  func filterAddressesString(validatorInfos []*ValidatorInfo) []string {
   963  	var address []string
   964  	for _, v := range validatorInfos {
   965  		address = append(address, v.Address.String())
   966  	}
   967  	return address
   968  }
   969  
   970  func filterNodeInfo(validatorInfos []*ValidatorInfo) []string {
   971  	var nodes []string
   972  	for _, v := range validatorInfos {
   973  		nodes = append(nodes, string(v.NodeInfo))
   974  	}
   975  	return nodes
   976  }
   977  
   978  func makeValidators(num int, isWorkOnSingleHost bool, nodeAddrs []common.Address, nodeKeys []string,
   979  	keys []*ecdsa.PrivateKey,
   980  ) []*ValidatorInfo {
   981  	var validatorPort uint16
   982  	var validators []*ValidatorInfo
   983  	for i := 0; i < num; i++ {
   984  		if isWorkOnSingleHost {
   985  			validatorPort = lastIssuedPortNum
   986  			lastIssuedPortNum++
   987  		} else {
   988  			validatorPort = DefaultTcpPort
   989  		}
   990  
   991  		v := &ValidatorInfo{
   992  			Address: nodeAddrs[i],
   993  			Nodekey: nodeKeys[i],
   994  			NodeInfo: discover.NewNode(
   995  				discover.PubkeyID(&keys[i].PublicKey),
   996  				net.ParseIP("0.0.0.0"),
   997  				0,
   998  				validatorPort,
   999  				nil,
  1000  				discover.NodeTypeCN).String(),
  1001  		}
  1002  		validators = append(validators, v)
  1003  	}
  1004  	return validators
  1005  }
  1006  
  1007  func makeValidatorsWithIp(num int, isWorkOnSingleHost bool, nodeAddrs []common.Address, nodeKeys []string,
  1008  	keys []*ecdsa.PrivateKey, networkIds []string,
  1009  ) []*ValidatorInfo {
  1010  	var validatorPort uint16
  1011  	var validators []*ValidatorInfo
  1012  	for i := 0; i < num; i++ {
  1013  		if isWorkOnSingleHost {
  1014  			validatorPort = lastIssuedPortNum
  1015  			lastIssuedPortNum++
  1016  		} else {
  1017  			validatorPort = DefaultTcpPort
  1018  		}
  1019  
  1020  		nn := len(networkIds)
  1021  		idx := (i + 1) % nn
  1022  		if nn > 1 {
  1023  			if idx == 0 {
  1024  				idx = nn - 1
  1025  			} else { // idx > 0
  1026  				idx = idx - 1
  1027  			}
  1028  		}
  1029  		v := &ValidatorInfo{
  1030  			Address: nodeAddrs[i],
  1031  			Nodekey: nodeKeys[i],
  1032  			NodeInfo: discover.NewNode(
  1033  				discover.PubkeyID(&keys[i].PublicKey),
  1034  				net.ParseIP(fmt.Sprintf("%s.%d", networkIds[idx], 100+(i/nn)+1)),
  1035  				0,
  1036  				validatorPort,
  1037  				nil,
  1038  				discover.NodeTypeCN).String(),
  1039  		}
  1040  		validators = append(validators, v)
  1041  	}
  1042  	return validators
  1043  }
  1044  
  1045  func makeProxys(num int, isWorkOnSingleHost bool) ([]*ValidatorInfo, []string) {
  1046  	privKeys, nodeKeys, nodeAddrs := istcommon.GenerateKeys(num)
  1047  
  1048  	var p2pPort uint16
  1049  	var proxies []*ValidatorInfo
  1050  	var proxyNodeKeys []string
  1051  	for i := 0; i < num; i++ {
  1052  		if isWorkOnSingleHost {
  1053  			p2pPort = lastIssuedPortNum
  1054  			lastIssuedPortNum++
  1055  		} else {
  1056  			p2pPort = DefaultTcpPort
  1057  		}
  1058  
  1059  		v := &ValidatorInfo{
  1060  			Address: nodeAddrs[i],
  1061  			Nodekey: nodeKeys[i],
  1062  			NodeInfo: discover.NewNode(
  1063  				discover.PubkeyID(&privKeys[i].PublicKey),
  1064  				net.ParseIP("0.0.0.0"),
  1065  				0,
  1066  				p2pPort,
  1067  				nil,
  1068  				discover.NodeTypePN).String(),
  1069  		}
  1070  		proxies = append(proxies, v)
  1071  		proxyNodeKeys = append(proxyNodeKeys, v.Nodekey)
  1072  	}
  1073  	return proxies, proxyNodeKeys
  1074  }
  1075  
  1076  func makeEndpoints(num int, isWorkOnSingleHost bool) ([]*ValidatorInfo, []string) {
  1077  	privKeys, nodeKeys, nodeAddrs := istcommon.GenerateKeys(num)
  1078  
  1079  	var p2pPort uint16
  1080  	var endpoints []*ValidatorInfo
  1081  	var endpointsNodeKeys []string
  1082  	for i := 0; i < num; i++ {
  1083  		if isWorkOnSingleHost {
  1084  			p2pPort = lastIssuedPortNum
  1085  			lastIssuedPortNum++
  1086  		} else {
  1087  			p2pPort = DefaultTcpPort
  1088  		}
  1089  
  1090  		v := &ValidatorInfo{
  1091  			Address: nodeAddrs[i],
  1092  			Nodekey: nodeKeys[i],
  1093  			NodeInfo: discover.NewNode(
  1094  				discover.PubkeyID(&privKeys[i].PublicKey),
  1095  				net.ParseIP("0.0.0.0"),
  1096  				0,
  1097  				p2pPort,
  1098  				nil,
  1099  				discover.NodeTypeEN).String(),
  1100  		}
  1101  		endpoints = append(endpoints, v)
  1102  		endpointsNodeKeys = append(endpointsNodeKeys, v.Nodekey)
  1103  	}
  1104  	return endpoints, endpointsNodeKeys
  1105  }
  1106  
  1107  func makeSCNs(num int, isWorkOnSingleHost bool) ([]*ValidatorInfo, []string) {
  1108  	privKeys, nodeKeys, nodeAddrs := istcommon.GenerateKeys(num)
  1109  
  1110  	var p2pPort uint16
  1111  	var scn []*ValidatorInfo
  1112  	var scnKeys []string
  1113  	for i := 0; i < num; i++ {
  1114  		if isWorkOnSingleHost {
  1115  			p2pPort = lastIssuedPortNum
  1116  			lastIssuedPortNum++
  1117  		} else {
  1118  			p2pPort = DefaultTcpPort
  1119  		}
  1120  
  1121  		v := &ValidatorInfo{
  1122  			Address: nodeAddrs[i],
  1123  			Nodekey: nodeKeys[i],
  1124  			NodeInfo: discover.NewNode(
  1125  				discover.PubkeyID(&privKeys[i].PublicKey),
  1126  				net.ParseIP("0.0.0.0"),
  1127  				0,
  1128  				p2pPort,
  1129  				nil,
  1130  				discover.NodeTypeUnknown).String(),
  1131  		}
  1132  		scn = append(scn, v)
  1133  		scnKeys = append(scnKeys, v.Nodekey)
  1134  	}
  1135  	return scn, scnKeys
  1136  }
  1137  
  1138  func makeSPNs(num int, isWorkOnSingleHost bool) ([]*ValidatorInfo, []string) {
  1139  	privKeys, nodeKeys, nodeAddrs := istcommon.GenerateKeys(num)
  1140  
  1141  	var p2pPort uint16
  1142  	var proxies []*ValidatorInfo
  1143  	var proxyNodeKeys []string
  1144  	for i := 0; i < num; i++ {
  1145  		if isWorkOnSingleHost {
  1146  			p2pPort = lastIssuedPortNum
  1147  			lastIssuedPortNum++
  1148  		} else {
  1149  			p2pPort = DefaultTcpPort
  1150  		}
  1151  
  1152  		v := &ValidatorInfo{
  1153  			Address: nodeAddrs[i],
  1154  			Nodekey: nodeKeys[i],
  1155  			NodeInfo: discover.NewNode(
  1156  				discover.PubkeyID(&privKeys[i].PublicKey),
  1157  				net.ParseIP("0.0.0.0"),
  1158  				0,
  1159  				p2pPort,
  1160  				nil,
  1161  				discover.NodeTypeUnknown).String(),
  1162  		}
  1163  		proxies = append(proxies, v)
  1164  		proxyNodeKeys = append(proxyNodeKeys, v.Nodekey)
  1165  	}
  1166  	return proxies, proxyNodeKeys
  1167  }
  1168  
  1169  func makeSENs(num int, isWorkOnSingleHost bool) ([]*ValidatorInfo, []string) {
  1170  	privKeys, nodeKeys, nodeAddrs := istcommon.GenerateKeys(num)
  1171  
  1172  	var p2pPort uint16
  1173  	var endpoints []*ValidatorInfo
  1174  	var endpointsNodeKeys []string
  1175  	for i := 0; i < num; i++ {
  1176  		if isWorkOnSingleHost {
  1177  			p2pPort = lastIssuedPortNum
  1178  			lastIssuedPortNum++
  1179  		} else {
  1180  			p2pPort = DefaultTcpPort
  1181  		}
  1182  
  1183  		v := &ValidatorInfo{
  1184  			Address: nodeAddrs[i],
  1185  			Nodekey: nodeKeys[i],
  1186  			NodeInfo: discover.NewNode(
  1187  				discover.PubkeyID(&privKeys[i].PublicKey),
  1188  				net.ParseIP("0.0.0.0"),
  1189  				0,
  1190  				p2pPort,
  1191  				nil,
  1192  				discover.NodeTypeUnknown).String(),
  1193  		}
  1194  		endpoints = append(endpoints, v)
  1195  		endpointsNodeKeys = append(endpointsNodeKeys, v.Nodekey)
  1196  	}
  1197  	return endpoints, endpointsNodeKeys
  1198  }
  1199  
  1200  func writeValidatorsAndNodesToFile(validators []*ValidatorInfo, parentDir string, nodekeys []string) {
  1201  	parentPath := path.Join(outputPath, parentDir)
  1202  	os.MkdirAll(parentPath, os.ModePerm)
  1203  
  1204  	for i, v := range validators {
  1205  		nodeKeyFilePath := path.Join(parentPath, "nodekey"+strconv.Itoa(i+1))
  1206  		os.WriteFile(nodeKeyFilePath, []byte(nodekeys[i]), os.ModePerm)
  1207  		fmt.Println("Created : ", nodeKeyFilePath)
  1208  
  1209  		str, _ := json.MarshalIndent(v, "", "\t")
  1210  		validatorInfoFilePath := path.Join(parentPath, "validator"+strconv.Itoa(i+1))
  1211  		os.WriteFile(validatorInfoFilePath, []byte(str), os.ModePerm)
  1212  		fmt.Println("Created : ", validatorInfoFilePath)
  1213  	}
  1214  }
  1215  
  1216  func writeTestKeys(parentDir string, privKeys []*ecdsa.PrivateKey, keys []string) {
  1217  	parentPath := path.Join(outputPath, parentDir)
  1218  	os.MkdirAll(parentPath, os.ModePerm)
  1219  
  1220  	for i, key := range keys {
  1221  		testKeyFilePath := path.Join(parentPath, "testkey"+strconv.Itoa(i+1))
  1222  		os.WriteFile(testKeyFilePath, []byte(key), os.ModePerm)
  1223  		fmt.Println("Created : ", testKeyFilePath)
  1224  
  1225  		pk := privKeys[i]
  1226  		ksPath := path.Join(parentPath, "keystore"+strconv.Itoa(i+1))
  1227  		ks := keystore.NewKeyStore(ksPath, keystore.StandardScryptN, keystore.StandardScryptP)
  1228  		pwdStr := RandStringRunes(params.PasswordLength)
  1229  		ks.ImportECDSA(pk, pwdStr)
  1230  		WriteFile([]byte(pwdStr), path.Join(parentDir, "keystore"+strconv.Itoa(i+1)), crypto.PubkeyToAddress(pk.PublicKey).String())
  1231  	}
  1232  }
  1233  
  1234  func WriteFile(content []byte, parentFolder string, fileName string) {
  1235  	filePath := path.Join(outputPath, parentFolder, fileName)
  1236  	os.MkdirAll(path.Dir(filePath), os.ModePerm)
  1237  	os.WriteFile(filePath, content, os.ModePerm)
  1238  	fmt.Println("Created : ", filePath)
  1239  }
  1240  
  1241  func indexGenType(genTypeFlag string, base string) int {
  1242  	// NOTE-Klaytn: genTypeFlag's default value is docker
  1243  	if base != "" && genTypeFlag == "" {
  1244  		genTypeFlag = base
  1245  	}
  1246  	for typeIndex, typeString := range Types {
  1247  		if genTypeFlag == typeString {
  1248  			return typeIndex
  1249  		}
  1250  	}
  1251  	return TypeNotDefined
  1252  }
  1253  
  1254  func findGenType(ctx *cli.Context) int {
  1255  	var (
  1256  		genTypeName string
  1257  		baseString  string
  1258  		genType     int
  1259  	)
  1260  
  1261  	if ctx.Args().Present() {
  1262  		genTypeName, baseString = ctx.Args().First(), ""
  1263  	} else {
  1264  		genTypeName, baseString = ctx.String(genTypeFlag.Name), Types[0]
  1265  	}
  1266  
  1267  	genType = indexGenType(genTypeName, baseString)
  1268  	if genType == TypeNotDefined {
  1269  		fmt.Printf("Wrong Type : %s\nSupported Types : [docker, local, remote, deploy]\n\n", genTypeName)
  1270  		cli.ShowSubcommandHelp(ctx)
  1271  		os.Exit(1)
  1272  	}
  1273  
  1274  	return genType
  1275  }
  1276  
  1277  func removeSpacesAndLines(b []byte) string {
  1278  	out := string(b)
  1279  	out = strings.Replace(out, " ", "", -1)
  1280  	out = strings.Replace(out, "\t", "", -1)
  1281  	out = strings.Replace(out, "\n", "", -1)
  1282  	return out
  1283  }
  1284  
  1285  func homiFlagsFromYaml(ctx *cli.Context) error {
  1286  	filePath := ctx.String(homiYamlFlag.Name)
  1287  	if filePath != "" {
  1288  		if err := altsrc.InitInputSourceWithContext(HomiFlags, altsrc.NewYamlSourceFromFlagFunc(homiYamlFlag.Name))(ctx); err != nil {
  1289  			return err
  1290  		}
  1291  	}
  1292  	return nil
  1293  }
  1294  
  1295  func BeforeRunHomi(ctx *cli.Context) error {
  1296  	if err := homiFlagsFromYaml(ctx); err != nil {
  1297  		return err
  1298  	}
  1299  
  1300  	return nil
  1301  }