|
|
@ -13,285 +13,319 @@ import ( |
|
|
|
|
|
|
|
cfg "github.com/tendermint/tendermint/config" |
|
|
|
"github.com/tendermint/tendermint/libs/bytes" |
|
|
|
"github.com/tendermint/tendermint/libs/log" |
|
|
|
tmrand "github.com/tendermint/tendermint/libs/rand" |
|
|
|
tmtime "github.com/tendermint/tendermint/libs/time" |
|
|
|
"github.com/tendermint/tendermint/privval" |
|
|
|
"github.com/tendermint/tendermint/types" |
|
|
|
) |
|
|
|
|
|
|
|
var ( |
|
|
|
nValidators int |
|
|
|
nNonValidators int |
|
|
|
initialHeight int64 |
|
|
|
configFile string |
|
|
|
outputDir string |
|
|
|
nodeDirPrefix string |
|
|
|
|
|
|
|
populatePersistentPeers bool |
|
|
|
hostnamePrefix string |
|
|
|
hostnameSuffix string |
|
|
|
startingIPAddress string |
|
|
|
hostnames []string |
|
|
|
p2pPort int |
|
|
|
randomMonikers bool |
|
|
|
) |
|
|
|
|
|
|
|
const ( |
|
|
|
nodeDirPerm = 0755 |
|
|
|
) |
|
|
|
|
|
|
|
func init() { |
|
|
|
TestnetFilesCmd.Flags().IntVar(&nValidators, "v", 4, |
|
|
|
// MakeTestnetFilesCommand constructs a command to generate testnet config files.
|
|
|
|
func MakeTestnetFilesCommand(conf *cfg.Config, logger log.Logger) *cobra.Command { |
|
|
|
cmd := &cobra.Command{ |
|
|
|
Use: "testnet", |
|
|
|
Short: "Initialize files for a Tendermint testnet", |
|
|
|
Long: `testnet will create "v" + "n" number of directories and populate each with |
|
|
|
necessary files (private validator, genesis, config, etc.). |
|
|
|
|
|
|
|
Note, strict routability for addresses is turned off in the config file. |
|
|
|
|
|
|
|
Optionally, it will fill in persistent-peers list in config file using either hostnames or IPs. |
|
|
|
|
|
|
|
Example: |
|
|
|
|
|
|
|
tendermint testnet --v 4 --o ./output --populate-persistent-peers --starting-ip-address 192.168.10.2 |
|
|
|
`, |
|
|
|
} |
|
|
|
var ( |
|
|
|
nValidators int |
|
|
|
nNonValidators int |
|
|
|
initialHeight int64 |
|
|
|
configFile string |
|
|
|
outputDir string |
|
|
|
nodeDirPrefix string |
|
|
|
|
|
|
|
populatePersistentPeers bool |
|
|
|
hostnamePrefix string |
|
|
|
hostnameSuffix string |
|
|
|
startingIPAddress string |
|
|
|
hostnames []string |
|
|
|
p2pPort int |
|
|
|
randomMonikers bool |
|
|
|
keyType string |
|
|
|
) |
|
|
|
|
|
|
|
cmd.Flags().IntVar(&nValidators, "v", 4, |
|
|
|
"number of validators to initialize the testnet with") |
|
|
|
TestnetFilesCmd.Flags().StringVar(&configFile, "config", "", |
|
|
|
cmd.Flags().StringVar(&configFile, "config", "", |
|
|
|
"config file to use (note some options may be overwritten)") |
|
|
|
TestnetFilesCmd.Flags().IntVar(&nNonValidators, "n", 0, |
|
|
|
cmd.Flags().IntVar(&nNonValidators, "n", 0, |
|
|
|
"number of non-validators to initialize the testnet with") |
|
|
|
TestnetFilesCmd.Flags().StringVar(&outputDir, "o", "./mytestnet", |
|
|
|
cmd.Flags().StringVar(&outputDir, "o", "./mytestnet", |
|
|
|
"directory to store initialization data for the testnet") |
|
|
|
TestnetFilesCmd.Flags().StringVar(&nodeDirPrefix, "node-dir-prefix", "node", |
|
|
|
cmd.Flags().StringVar(&nodeDirPrefix, "node-dir-prefix", "node", |
|
|
|
"prefix the directory name for each node with (node results in node0, node1, ...)") |
|
|
|
TestnetFilesCmd.Flags().Int64Var(&initialHeight, "initial-height", 0, |
|
|
|
cmd.Flags().Int64Var(&initialHeight, "initial-height", 0, |
|
|
|
"initial height of the first block") |
|
|
|
|
|
|
|
TestnetFilesCmd.Flags().BoolVar(&populatePersistentPeers, "populate-persistent-peers", true, |
|
|
|
cmd.Flags().BoolVar(&populatePersistentPeers, "populate-persistent-peers", true, |
|
|
|
"update config of each node with the list of persistent peers build using either"+ |
|
|
|
" hostname-prefix or"+ |
|
|
|
" starting-ip-address") |
|
|
|
TestnetFilesCmd.Flags().StringVar(&hostnamePrefix, "hostname-prefix", "node", |
|
|
|
cmd.Flags().StringVar(&hostnamePrefix, "hostname-prefix", "node", |
|
|
|
"hostname prefix (\"node\" results in persistent peers list ID0@node0:26656, ID1@node1:26656, ...)") |
|
|
|
TestnetFilesCmd.Flags().StringVar(&hostnameSuffix, "hostname-suffix", "", |
|
|
|
cmd.Flags().StringVar(&hostnameSuffix, "hostname-suffix", "", |
|
|
|
"hostname suffix ("+ |
|
|
|
"\".xyz.com\""+ |
|
|
|
" results in persistent peers list ID0@node0.xyz.com:26656, ID1@node1.xyz.com:26656, ...)") |
|
|
|
TestnetFilesCmd.Flags().StringVar(&startingIPAddress, "starting-ip-address", "", |
|
|
|
cmd.Flags().StringVar(&startingIPAddress, "starting-ip-address", "", |
|
|
|
"starting IP address ("+ |
|
|
|
"\"192.168.0.1\""+ |
|
|
|
" results in persistent peers list ID0@192.168.0.1:26656, ID1@192.168.0.2:26656, ...)") |
|
|
|
TestnetFilesCmd.Flags().StringArrayVar(&hostnames, "hostname", []string{}, |
|
|
|
cmd.Flags().StringArrayVar(&hostnames, "hostname", []string{}, |
|
|
|
"manually override all hostnames of validators and non-validators (use --hostname multiple times for multiple hosts)") |
|
|
|
TestnetFilesCmd.Flags().IntVar(&p2pPort, "p2p-port", 26656, |
|
|
|
cmd.Flags().IntVar(&p2pPort, "p2p-port", 26656, |
|
|
|
"P2P Port") |
|
|
|
TestnetFilesCmd.Flags().BoolVar(&randomMonikers, "random-monikers", false, |
|
|
|
cmd.Flags().BoolVar(&randomMonikers, "random-monikers", false, |
|
|
|
"randomize the moniker for each generated node") |
|
|
|
TestnetFilesCmd.Flags().StringVar(&keyType, "key", types.ABCIPubKeyTypeEd25519, |
|
|
|
cmd.Flags().StringVar(&keyType, "key", types.ABCIPubKeyTypeEd25519, |
|
|
|
"Key type to generate privval file with. Options: ed25519, secp256k1") |
|
|
|
} |
|
|
|
|
|
|
|
// TestnetFilesCmd allows initialisation of files for a Tendermint testnet.
|
|
|
|
var TestnetFilesCmd = &cobra.Command{ |
|
|
|
Use: "testnet", |
|
|
|
Short: "Initialize files for a Tendermint testnet", |
|
|
|
Long: `testnet will create "v" + "n" number of directories and populate each with |
|
|
|
necessary files (private validator, genesis, config, etc.). |
|
|
|
|
|
|
|
Note, strict routability for addresses is turned off in the config file. |
|
|
|
|
|
|
|
Optionally, it will fill in persistent-peers list in config file using either hostnames or IPs. |
|
|
|
cmd.RunE = func(cmd *cobra.Command, args []string) error { |
|
|
|
if len(hostnames) > 0 && len(hostnames) != (nValidators+nNonValidators) { |
|
|
|
return fmt.Errorf( |
|
|
|
"testnet needs precisely %d hostnames (number of validators plus non-validators) if --hostname parameter is used", |
|
|
|
nValidators+nNonValidators, |
|
|
|
) |
|
|
|
} |
|
|
|
|
|
|
|
Example: |
|
|
|
// set mode to validator for testnet
|
|
|
|
config := cfg.DefaultValidatorConfig() |
|
|
|
|
|
|
|
tendermint testnet --v 4 --o ./output --populate-persistent-peers --starting-ip-address 192.168.10.2 |
|
|
|
`, |
|
|
|
RunE: testnetFiles, |
|
|
|
} |
|
|
|
// overwrite default config if set and valid
|
|
|
|
if configFile != "" { |
|
|
|
viper.SetConfigFile(configFile) |
|
|
|
if err := viper.ReadInConfig(); err != nil { |
|
|
|
return err |
|
|
|
} |
|
|
|
if err := viper.Unmarshal(config); err != nil { |
|
|
|
return err |
|
|
|
} |
|
|
|
if err := config.ValidateBasic(); err != nil { |
|
|
|
return err |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func testnetFiles(cmd *cobra.Command, args []string) error { |
|
|
|
if len(hostnames) > 0 && len(hostnames) != (nValidators+nNonValidators) { |
|
|
|
return fmt.Errorf( |
|
|
|
"testnet needs precisely %d hostnames (number of validators plus non-validators) if --hostname parameter is used", |
|
|
|
nValidators+nNonValidators, |
|
|
|
) |
|
|
|
} |
|
|
|
genVals := make([]types.GenesisValidator, nValidators) |
|
|
|
ctx := cmd.Context() |
|
|
|
for i := 0; i < nValidators; i++ { |
|
|
|
nodeDirName := fmt.Sprintf("%s%d", nodeDirPrefix, i) |
|
|
|
nodeDir := filepath.Join(outputDir, nodeDirName) |
|
|
|
config.SetRoot(nodeDir) |
|
|
|
|
|
|
|
err := os.MkdirAll(filepath.Join(nodeDir, "config"), nodeDirPerm) |
|
|
|
if err != nil { |
|
|
|
_ = os.RemoveAll(outputDir) |
|
|
|
return err |
|
|
|
} |
|
|
|
err = os.MkdirAll(filepath.Join(nodeDir, "data"), nodeDirPerm) |
|
|
|
if err != nil { |
|
|
|
_ = os.RemoveAll(outputDir) |
|
|
|
return err |
|
|
|
} |
|
|
|
|
|
|
|
// set mode to validator for testnet
|
|
|
|
config := cfg.DefaultValidatorConfig() |
|
|
|
if err := initFilesWithConfig(ctx, config, logger); err != nil { |
|
|
|
return err |
|
|
|
} |
|
|
|
|
|
|
|
// overwrite default config if set and valid
|
|
|
|
if configFile != "" { |
|
|
|
viper.SetConfigFile(configFile) |
|
|
|
if err := viper.ReadInConfig(); err != nil { |
|
|
|
return err |
|
|
|
} |
|
|
|
if err := viper.Unmarshal(config); err != nil { |
|
|
|
return err |
|
|
|
} |
|
|
|
if err := config.ValidateBasic(); err != nil { |
|
|
|
return err |
|
|
|
} |
|
|
|
} |
|
|
|
pvKeyFile := filepath.Join(nodeDir, config.PrivValidator.Key) |
|
|
|
pvStateFile := filepath.Join(nodeDir, config.PrivValidator.State) |
|
|
|
pv, err := privval.LoadFilePV(pvKeyFile, pvStateFile) |
|
|
|
if err != nil { |
|
|
|
return err |
|
|
|
} |
|
|
|
|
|
|
|
genVals := make([]types.GenesisValidator, nValidators) |
|
|
|
ctx := cmd.Context() |
|
|
|
for i := 0; i < nValidators; i++ { |
|
|
|
nodeDirName := fmt.Sprintf("%s%d", nodeDirPrefix, i) |
|
|
|
nodeDir := filepath.Join(outputDir, nodeDirName) |
|
|
|
config.SetRoot(nodeDir) |
|
|
|
ctx, cancel := context.WithTimeout(ctx, ctxTimeout) |
|
|
|
defer cancel() |
|
|
|
|
|
|
|
err := os.MkdirAll(filepath.Join(nodeDir, "config"), nodeDirPerm) |
|
|
|
if err != nil { |
|
|
|
_ = os.RemoveAll(outputDir) |
|
|
|
return err |
|
|
|
} |
|
|
|
err = os.MkdirAll(filepath.Join(nodeDir, "data"), nodeDirPerm) |
|
|
|
if err != nil { |
|
|
|
_ = os.RemoveAll(outputDir) |
|
|
|
return err |
|
|
|
pubKey, err := pv.GetPubKey(ctx) |
|
|
|
if err != nil { |
|
|
|
return fmt.Errorf("can't get pubkey: %w", err) |
|
|
|
} |
|
|
|
genVals[i] = types.GenesisValidator{ |
|
|
|
Address: pubKey.Address(), |
|
|
|
PubKey: pubKey, |
|
|
|
Power: 1, |
|
|
|
Name: nodeDirName, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if err := initFilesWithConfig(ctx, config); err != nil { |
|
|
|
return err |
|
|
|
} |
|
|
|
for i := 0; i < nNonValidators; i++ { |
|
|
|
nodeDir := filepath.Join(outputDir, fmt.Sprintf("%s%d", nodeDirPrefix, i+nValidators)) |
|
|
|
config.SetRoot(nodeDir) |
|
|
|
|
|
|
|
pvKeyFile := filepath.Join(nodeDir, config.PrivValidator.Key) |
|
|
|
pvStateFile := filepath.Join(nodeDir, config.PrivValidator.State) |
|
|
|
pv, err := privval.LoadFilePV(pvKeyFile, pvStateFile) |
|
|
|
if err != nil { |
|
|
|
return err |
|
|
|
} |
|
|
|
err := os.MkdirAll(filepath.Join(nodeDir, "config"), nodeDirPerm) |
|
|
|
if err != nil { |
|
|
|
_ = os.RemoveAll(outputDir) |
|
|
|
return err |
|
|
|
} |
|
|
|
|
|
|
|
ctx, cancel := context.WithTimeout(ctx, ctxTimeout) |
|
|
|
defer cancel() |
|
|
|
err = os.MkdirAll(filepath.Join(nodeDir, "data"), nodeDirPerm) |
|
|
|
if err != nil { |
|
|
|
_ = os.RemoveAll(outputDir) |
|
|
|
return err |
|
|
|
} |
|
|
|
|
|
|
|
pubKey, err := pv.GetPubKey(ctx) |
|
|
|
if err != nil { |
|
|
|
return fmt.Errorf("can't get pubkey: %w", err) |
|
|
|
} |
|
|
|
genVals[i] = types.GenesisValidator{ |
|
|
|
Address: pubKey.Address(), |
|
|
|
PubKey: pubKey, |
|
|
|
Power: 1, |
|
|
|
Name: nodeDirName, |
|
|
|
if err := initFilesWithConfig(ctx, conf, logger); err != nil { |
|
|
|
return err |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
for i := 0; i < nNonValidators; i++ { |
|
|
|
nodeDir := filepath.Join(outputDir, fmt.Sprintf("%s%d", nodeDirPrefix, i+nValidators)) |
|
|
|
config.SetRoot(nodeDir) |
|
|
|
|
|
|
|
err := os.MkdirAll(filepath.Join(nodeDir, "config"), nodeDirPerm) |
|
|
|
if err != nil { |
|
|
|
_ = os.RemoveAll(outputDir) |
|
|
|
return err |
|
|
|
// Generate genesis doc from generated validators
|
|
|
|
genDoc := &types.GenesisDoc{ |
|
|
|
ChainID: "chain-" + tmrand.Str(6), |
|
|
|
GenesisTime: tmtime.Now(), |
|
|
|
InitialHeight: initialHeight, |
|
|
|
Validators: genVals, |
|
|
|
ConsensusParams: types.DefaultConsensusParams(), |
|
|
|
} |
|
|
|
|
|
|
|
err = os.MkdirAll(filepath.Join(nodeDir, "data"), nodeDirPerm) |
|
|
|
if err != nil { |
|
|
|
_ = os.RemoveAll(outputDir) |
|
|
|
return err |
|
|
|
if keyType == "secp256k1" { |
|
|
|
genDoc.ConsensusParams.Validator = types.ValidatorParams{ |
|
|
|
PubKeyTypes: []string{types.ABCIPubKeyTypeSecp256k1}, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if err := initFilesWithConfig(ctx, config); err != nil { |
|
|
|
return err |
|
|
|
// Write genesis file.
|
|
|
|
for i := 0; i < nValidators+nNonValidators; i++ { |
|
|
|
nodeDir := filepath.Join(outputDir, fmt.Sprintf("%s%d", nodeDirPrefix, i)) |
|
|
|
if err := genDoc.SaveAs(filepath.Join(nodeDir, config.BaseConfig.Genesis)); err != nil { |
|
|
|
_ = os.RemoveAll(outputDir) |
|
|
|
return err |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Generate genesis doc from generated validators
|
|
|
|
genDoc := &types.GenesisDoc{ |
|
|
|
ChainID: "chain-" + tmrand.Str(6), |
|
|
|
GenesisTime: tmtime.Now(), |
|
|
|
InitialHeight: initialHeight, |
|
|
|
Validators: genVals, |
|
|
|
ConsensusParams: types.DefaultConsensusParams(), |
|
|
|
} |
|
|
|
if keyType == "secp256k1" { |
|
|
|
genDoc.ConsensusParams.Validator = types.ValidatorParams{ |
|
|
|
PubKeyTypes: []string{types.ABCIPubKeyTypeSecp256k1}, |
|
|
|
// Gather persistent peer addresses.
|
|
|
|
var ( |
|
|
|
persistentPeers = make([]string, 0) |
|
|
|
err error |
|
|
|
) |
|
|
|
tpargs := testnetPeerArgs{ |
|
|
|
numValidators: nValidators, |
|
|
|
numNonValidators: nNonValidators, |
|
|
|
peerToPeerPort: p2pPort, |
|
|
|
nodeDirPrefix: nodeDirPrefix, |
|
|
|
outputDir: outputDir, |
|
|
|
hostnames: hostnames, |
|
|
|
startingIPAddr: startingIPAddress, |
|
|
|
hostnamePrefix: hostnamePrefix, |
|
|
|
hostnameSuffix: hostnameSuffix, |
|
|
|
randomMonikers: randomMonikers, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Write genesis file.
|
|
|
|
for i := 0; i < nValidators+nNonValidators; i++ { |
|
|
|
nodeDir := filepath.Join(outputDir, fmt.Sprintf("%s%d", nodeDirPrefix, i)) |
|
|
|
if err := genDoc.SaveAs(filepath.Join(nodeDir, config.BaseConfig.Genesis)); err != nil { |
|
|
|
_ = os.RemoveAll(outputDir) |
|
|
|
return err |
|
|
|
} |
|
|
|
} |
|
|
|
if populatePersistentPeers { |
|
|
|
|
|
|
|
// Gather persistent peer addresses.
|
|
|
|
var ( |
|
|
|
persistentPeers = make([]string, 0) |
|
|
|
err error |
|
|
|
) |
|
|
|
if populatePersistentPeers { |
|
|
|
persistentPeers, err = persistentPeersArray(config) |
|
|
|
if err != nil { |
|
|
|
_ = os.RemoveAll(outputDir) |
|
|
|
return err |
|
|
|
persistentPeers, err = persistentPeersArray(config, tpargs) |
|
|
|
if err != nil { |
|
|
|
_ = os.RemoveAll(outputDir) |
|
|
|
return err |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Overwrite default config.
|
|
|
|
for i := 0; i < nValidators+nNonValidators; i++ { |
|
|
|
nodeDir := filepath.Join(outputDir, fmt.Sprintf("%s%d", nodeDirPrefix, i)) |
|
|
|
config.SetRoot(nodeDir) |
|
|
|
config.P2P.AllowDuplicateIP = true |
|
|
|
if populatePersistentPeers { |
|
|
|
persistentPeersWithoutSelf := make([]string, 0) |
|
|
|
for j := 0; j < len(persistentPeers); j++ { |
|
|
|
if j == i { |
|
|
|
continue |
|
|
|
// Overwrite default config.
|
|
|
|
for i := 0; i < nValidators+nNonValidators; i++ { |
|
|
|
nodeDir := filepath.Join(outputDir, fmt.Sprintf("%s%d", nodeDirPrefix, i)) |
|
|
|
config.SetRoot(nodeDir) |
|
|
|
config.P2P.AllowDuplicateIP = true |
|
|
|
if populatePersistentPeers { |
|
|
|
persistentPeersWithoutSelf := make([]string, 0) |
|
|
|
for j := 0; j < len(persistentPeers); j++ { |
|
|
|
if j == i { |
|
|
|
continue |
|
|
|
} |
|
|
|
persistentPeersWithoutSelf = append(persistentPeersWithoutSelf, persistentPeers[j]) |
|
|
|
} |
|
|
|
persistentPeersWithoutSelf = append(persistentPeersWithoutSelf, persistentPeers[j]) |
|
|
|
config.P2P.PersistentPeers = strings.Join(persistentPeersWithoutSelf, ",") |
|
|
|
} |
|
|
|
config.P2P.PersistentPeers = strings.Join(persistentPeersWithoutSelf, ",") |
|
|
|
} |
|
|
|
config.Moniker = moniker(i) |
|
|
|
config.Moniker = tpargs.moniker(i) |
|
|
|
|
|
|
|
if err := cfg.WriteConfigFile(nodeDir, config); err != nil { |
|
|
|
return err |
|
|
|
if err := cfg.WriteConfigFile(nodeDir, config); err != nil { |
|
|
|
return err |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
fmt.Printf("Successfully initialized %v node directories\n", nValidators+nNonValidators) |
|
|
|
return nil |
|
|
|
} |
|
|
|
|
|
|
|
fmt.Printf("Successfully initialized %v node directories\n", nValidators+nNonValidators) |
|
|
|
return nil |
|
|
|
return cmd |
|
|
|
} |
|
|
|
|
|
|
|
type testnetPeerArgs struct { |
|
|
|
numValidators int |
|
|
|
numNonValidators int |
|
|
|
peerToPeerPort int |
|
|
|
nodeDirPrefix string |
|
|
|
outputDir string |
|
|
|
hostnames []string |
|
|
|
startingIPAddr string |
|
|
|
hostnamePrefix string |
|
|
|
hostnameSuffix string |
|
|
|
randomMonikers bool |
|
|
|
} |
|
|
|
|
|
|
|
func hostnameOrIP(i int) string { |
|
|
|
if len(hostnames) > 0 && i < len(hostnames) { |
|
|
|
return hostnames[i] |
|
|
|
func (args *testnetPeerArgs) hostnameOrIP(i int) (string, error) { |
|
|
|
if len(args.hostnames) > 0 && i < len(args.hostnames) { |
|
|
|
return args.hostnames[i], nil |
|
|
|
} |
|
|
|
if startingIPAddress == "" { |
|
|
|
return fmt.Sprintf("%s%d%s", hostnamePrefix, i, hostnameSuffix) |
|
|
|
if args.startingIPAddr == "" { |
|
|
|
return fmt.Sprintf("%s%d%s", args.hostnamePrefix, i, args.hostnameSuffix), nil |
|
|
|
} |
|
|
|
ip := net.ParseIP(startingIPAddress) |
|
|
|
ip := net.ParseIP(args.startingIPAddr) |
|
|
|
ip = ip.To4() |
|
|
|
if ip == nil { |
|
|
|
fmt.Printf("%v: non ipv4 address\n", startingIPAddress) |
|
|
|
os.Exit(1) |
|
|
|
return "", fmt.Errorf("%v is non-ipv4 address", args.startingIPAddr) |
|
|
|
} |
|
|
|
|
|
|
|
for j := 0; j < i; j++ { |
|
|
|
ip[3]++ |
|
|
|
} |
|
|
|
return ip.String() |
|
|
|
return ip.String(), nil |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// get an array of persistent peers
|
|
|
|
func persistentPeersArray(config *cfg.Config) ([]string, error) { |
|
|
|
peers := make([]string, nValidators+nNonValidators) |
|
|
|
for i := 0; i < nValidators+nNonValidators; i++ { |
|
|
|
nodeDir := filepath.Join(outputDir, fmt.Sprintf("%s%d", nodeDirPrefix, i)) |
|
|
|
func persistentPeersArray(config *cfg.Config, args testnetPeerArgs) ([]string, error) { |
|
|
|
peers := make([]string, args.numValidators+args.numNonValidators) |
|
|
|
for i := 0; i < len(peers); i++ { |
|
|
|
nodeDir := filepath.Join(args.outputDir, fmt.Sprintf("%s%d", args.nodeDirPrefix, i)) |
|
|
|
config.SetRoot(nodeDir) |
|
|
|
nodeKey, err := config.LoadNodeKeyID() |
|
|
|
if err != nil { |
|
|
|
return []string{}, err |
|
|
|
return nil, err |
|
|
|
} |
|
|
|
peers[i] = nodeKey.AddressString(fmt.Sprintf("%s:%d", hostnameOrIP(i), p2pPort)) |
|
|
|
addr, err := args.hostnameOrIP(i) |
|
|
|
if err != nil { |
|
|
|
return nil, err |
|
|
|
} |
|
|
|
|
|
|
|
peers[i] = nodeKey.AddressString(fmt.Sprintf("%s:%d", addr, args.peerToPeerPort)) |
|
|
|
} |
|
|
|
return peers, nil |
|
|
|
} |
|
|
|
|
|
|
|
func moniker(i int) string { |
|
|
|
if randomMonikers { |
|
|
|
func (args *testnetPeerArgs) moniker(i int) string { |
|
|
|
if args.randomMonikers { |
|
|
|
return randomMoniker() |
|
|
|
} |
|
|
|
if len(hostnames) > 0 && i < len(hostnames) { |
|
|
|
return hostnames[i] |
|
|
|
if len(args.hostnames) > 0 && i < len(args.hostnames) { |
|
|
|
return args.hostnames[i] |
|
|
|
} |
|
|
|
if startingIPAddress == "" { |
|
|
|
return fmt.Sprintf("%s%d%s", hostnamePrefix, i, hostnameSuffix) |
|
|
|
if args.startingIPAddr == "" { |
|
|
|
return fmt.Sprintf("%s%d%s", args.hostnamePrefix, i, args.hostnameSuffix) |
|
|
|
} |
|
|
|
return randomMoniker() |
|
|
|
} |
|
|
|