diff --git a/beacon-chain/node/BUILD.bazel b/beacon-chain/node/BUILD.bazel index 0d0f562d7b00..470f7919ac8f 100644 --- a/beacon-chain/node/BUILD.bazel +++ b/beacon-chain/node/BUILD.bazel @@ -40,6 +40,7 @@ go_library( "@com_github_pkg_errors//:go_default_library", "@com_github_sirupsen_logrus//:go_default_library", "@com_github_urfave_cli_v2//:go_default_library", + "@in_gopkg_yaml_v2//:go_default_library", ], ) diff --git a/beacon-chain/node/node.go b/beacon-chain/node/node.go index 9fa5602ba2e3..12bbf72dfcc7 100644 --- a/beacon-chain/node/node.go +++ b/beacon-chain/node/node.go @@ -48,6 +48,7 @@ import ( "github.com/prysmaticlabs/prysm/shared/version" "github.com/sirupsen/logrus" "github.com/urfave/cli/v2" + "gopkg.in/yaml.v2" ) var log = logrus.WithField("prefix", "node") @@ -114,7 +115,7 @@ func NewBeaconNode(cliCtx *cli.Context) (*BeaconNode, error) { } if cliCtx.IsSet(cmd.BootstrapNode.Name) { c := params.BeaconNetworkConfig() - c.BootstrapNodes = strings.Split(cliCtx.String(cmd.BootstrapNode.Name), ",") + c.BootstrapNodes = cliCtx.StringSlice(cmd.BootstrapNode.Name) params.OverrideBeaconNetworkConfig(c) } if cliCtx.IsSet(flags.ContractDeploymentBlock.Name) { @@ -315,16 +316,32 @@ func (b *BeaconNode) startStateGen() { b.stateGen = stategen.New(b.db, b.stateSummaryCache) } +func readbootNodes(fileName string) ([]string, error) { + fileContent, err := ioutil.ReadFile(fileName) + if err != nil { + return nil, err + } + listNodes := make([]string, 0) + err = yaml.Unmarshal(fileContent, &listNodes) + if err != nil { + return nil, err + } + return listNodes, nil +} + func (b *BeaconNode) registerP2P(cliCtx *cli.Context) error { - // Bootnode ENR may be a filepath to an ENR file. - bootnodeAddrs := params.BeaconNetworkConfig().BootstrapNodes - for i, addr := range bootnodeAddrs { - if filepath.Ext(addr) == ".enr" { - b, err := ioutil.ReadFile(addr) + // Bootnode ENR may be a filepath to a YAML file + bootnodesTemp := params.BeaconNetworkConfig().BootstrapNodes //actual CLI values + bootnodeAddrs := make([]string, 0) //dest of final list of nodes + for _, addr := range bootnodesTemp { + if filepath.Ext(addr) == ".yaml" { + fileNodes, err := readbootNodes(addr) if err != nil { return err } - bootnodeAddrs[i] = string(b) + bootnodeAddrs = append(bootnodeAddrs, fileNodes...) + } else { + bootnodeAddrs = append(bootnodeAddrs, addr) } } diff --git a/beacon-chain/node/node_test.go b/beacon-chain/node/node_test.go index 3569bcd6094b..98456da1e259 100644 --- a/beacon-chain/node/node_test.go +++ b/beacon-chain/node/node_test.go @@ -3,6 +3,7 @@ package node import ( "flag" "fmt" + "io/ioutil" "os" "testing" @@ -47,3 +48,34 @@ func TestNodeClose_OK(t *testing.T) { t.Log(err) } } + +func TestBootStrapNodeFile(t *testing.T) { + file, err := ioutil.TempFile(testutil.TempDir(), "bootstrapFile") + if err != nil { + t.Fatalf("Error in TempFile call: %v", err) + } + defer func() { + if err := os.Remove(file.Name()); err != nil { + t.Log(err) + } + }() + + sampleNode0 := "- enr:-Ku4QMKVC_MowDsmEa20d5uGjrChI0h8_KsKXDmgVQbIbngZV0i" + + "dV6_RL7fEtZGo-kTNZ5o7_EJI_vCPJ6scrhwX0Z4Bh2F0dG5ldHOIAAAAAAAAAACEZXRoMpD" + + "1pf1CAAAAAP__________gmlkgnY0gmlwhBLf22SJc2VjcDI1NmsxoQJxCnE6v_x2ekgY_uo" + + "E1rtwzvGy40mq9eD66XfHPBWgIIN1ZHCCD6A" + sampleNode1 := "- enr:-TESTNODE2" + sampleNode2 := "- enr:-TESTNODE3" + err = ioutil.WriteFile(file.Name(), []byte(sampleNode0+"\n"+sampleNode1+"\n"+sampleNode2), 0644) + if err != nil { + t.Fatalf("Error in WriteFile call: %v", err) + } + nodeList, err := readbootNodes(file.Name()) + if err != nil { + t.Fatalf("Error in readbootNodes call: %v", err) + } + if nodeList[0] != sampleNode0[2:] || nodeList[1] != sampleNode1[2:] || nodeList[2] != sampleNode2[2:] { + // nodeList's YAML parsing will have removed the leading "- " + t.Fatalf("TestBootStrapNodeFile failed. Nodes do not match") + } +} diff --git a/shared/cmd/flags.go b/shared/cmd/flags.go index 462f58be24ad..4a113b2ab339 100644 --- a/shared/cmd/flags.go +++ b/shared/cmd/flags.go @@ -80,10 +80,10 @@ var ( Usage: "Connect with this peer. This flag may be used multiple times.", } // BootstrapNode tells the beacon node which bootstrap node to connect to - BootstrapNode = &cli.StringFlag{ + BootstrapNode = &cli.StringSliceFlag{ Name: "bootstrap-node", - Usage: "The address of bootstrap node. Beacon node will connect for peer discovery via DHT. Multiple nodes can be separated with a comma", - Value: "enr:-Ku4QMKVC_MowDsmEa20d5uGjrChI0h8_KsKXDmgVQbIbngZV0idV6_RL7fEtZGo-kTNZ5o7_EJI_vCPJ6scrhwX0Z4Bh2F0dG5ldHOIAAAAAAAAAACEZXRoMpD1pf1CAAAAAP__________gmlkgnY0gmlwhBLf22SJc2VjcDI1NmsxoQJxCnE6v_x2ekgY_uoE1rtwzvGy40mq9eD66XfHPBWgIIN1ZHCCD6A", + Usage: "The address of bootstrap node. Beacon node will connect for peer discovery via DHT. Multiple nodes can be passed by using the flag multiple times but not comma-separated. You can also pass YAML files containing multiple nodes.", + Value: cli.NewStringSlice("enr:-Ku4QMKVC_MowDsmEa20d5uGjrChI0h8_KsKXDmgVQbIbngZV0idV6_RL7fEtZGo-kTNZ5o7_EJI_vCPJ6scrhwX0Z4Bh2F0dG5ldHOIAAAAAAAAAACEZXRoMpD1pf1CAAAAAP__________gmlkgnY0gmlwhBLf22SJc2VjcDI1NmsxoQJxCnE6v_x2ekgY_uoE1rtwzvGy40mq9eD66XfHPBWgIIN1ZHCCD6A"), } // RelayNode tells the beacon node which relay node to connect to. RelayNode = &cli.StringFlag{