From 706a1e552c96bf75c60844c1dc28fc83778795fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 11 Apr 2017 02:25:53 +0300 Subject: cmd/puppeth: your Ethereum private network manager (#13854) --- cmd/puppeth/wizard_node.go | 153 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 cmd/puppeth/wizard_node.go (limited to 'cmd/puppeth/wizard_node.go') diff --git a/cmd/puppeth/wizard_node.go b/cmd/puppeth/wizard_node.go new file mode 100644 index 000000000..d70d8f3c9 --- /dev/null +++ b/cmd/puppeth/wizard_node.go @@ -0,0 +1,153 @@ +// Copyright 2017 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package main + +import ( + "encoding/json" + "fmt" + "time" + + "github.com/ethereum/go-ethereum/accounts/keystore" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/log" +) + +// deployNode creates a new node configuration based on some user input. +func (w *wizard) deployNode(boot bool) { + // Do some sanity check before the user wastes time on input + if w.conf.genesis == nil { + log.Error("No genesis block configured") + return + } + if w.conf.ethstats == "" { + log.Error("No ethstats server configured") + return + } + // Select the server to interact with + server := w.selectServer() + if server == "" { + return + } + client := w.servers[server] + + // Retrieve any active ethstats configurations from the server + infos, err := checkNode(client, w.network, boot) + if err != nil { + if boot { + infos = &nodeInfos{portFull: 30303, peersTotal: 512, peersLight: 256} + } else { + infos = &nodeInfos{portFull: 30303, peersTotal: 50, peersLight: 0} + } + } + infos.genesis, _ = json.MarshalIndent(w.conf.genesis, "", " ") + infos.network = w.conf.genesis.Config.ChainId.Int64() + + // Figure out where the user wants to store the persistent data + fmt.Println() + if infos.datadir == "" { + fmt.Printf("Where should data be stored on the remote machine?\n") + infos.datadir = w.readString() + } else { + fmt.Printf("Where should data be stored on the remote machine? (default = %s)\n", infos.datadir) + infos.datadir = w.readDefaultString(infos.datadir) + } + // Figure out which port to listen on + fmt.Println() + fmt.Printf("Which TCP/UDP port to listen on? (default = %d)\n", infos.portFull) + infos.portFull = w.readDefaultInt(infos.portFull) + + // Figure out how many peers to allow (different based on node type) + fmt.Println() + fmt.Printf("How many peers to allow connecting? (default = %d)\n", infos.peersTotal) + infos.peersTotal = w.readDefaultInt(infos.peersTotal) + + // Figure out how many light peers to allow (different based on node type) + fmt.Println() + fmt.Printf("How many light peers to allow connecting? (default = %d)\n", infos.peersLight) + infos.peersLight = w.readDefaultInt(infos.peersLight) + + // Set a proper name to report on the stats page + fmt.Println() + if infos.ethstats == "" { + fmt.Printf("What should the node be called on the stats page?\n") + infos.ethstats = w.readString() + ":" + w.conf.ethstats + } else { + fmt.Printf("What should the node be called on the stats page? (default = %s)\n", infos.ethstats) + infos.ethstats = w.readDefaultString(infos.ethstats) + ":" + w.conf.ethstats + } + // If the node is a miner/signer, load up needed credentials + if !boot { + if w.conf.genesis.Config.Ethash != nil { + // Ethash based miners only need an etherbase to mine against + fmt.Println() + if infos.etherbase == "" { + fmt.Printf("What address should the miner user?\n") + for { + if address := w.readAddress(); address != nil { + infos.etherbase = address.Hex() + break + } + } + } else { + fmt.Printf("What address should the miner user? (default = %s)\n", infos.etherbase) + infos.etherbase = w.readDefaultAddress(common.HexToAddress(infos.etherbase)).Hex() + } + } else if w.conf.genesis.Config.Clique != nil { + // If a previous signer was already set, offer to reuse it + if infos.keyJSON != "" { + var key keystore.Key + if err := json.Unmarshal([]byte(infos.keyJSON), &key); err != nil { + infos.keyJSON, infos.keyPass = "", "" + } else { + fmt.Println() + fmt.Printf("Reuse previous (%s) signing account (y/n)? (default = yes)\n", key.Address.Hex()) + if w.readDefaultString("y") != "y" { + infos.keyJSON, infos.keyPass = "", "" + } + } + } + // Clique based signers need a keyfile and unlock password, ask if unavailable + if infos.keyJSON == "" { + fmt.Println() + fmt.Println("Please paste the signer's key JSON:") + infos.keyJSON = w.readJSON() + + fmt.Println() + fmt.Println("What's the unlock password for the account? (won't be echoed)") + infos.keyPass = w.readPassword() + + if _, err := keystore.DecryptKey([]byte(infos.keyJSON), infos.keyPass); err != nil { + log.Error("Failed to decrypt key with given passphrase") + return + } + } + } + } + // Try to deploy the full node on the host + if out, err := deployNode(client, w.network, w.conf.bootFull, infos); err != nil { + log.Error("Failed to deploy Ethereum node container", "err", err) + if len(out) > 0 { + fmt.Printf("%s\n", out) + } + return + } + // All ok, run a network scan to pick any changes up + log.Info("Waiting for node to finish booting") + time.Sleep(3 * time.Second) + + w.networkStats(false) +} -- cgit v1.2.3