From 6b727c0440f79d12ba38f6c21f50d33b84aeaa83 Mon Sep 17 00:00:00 2001
From: Felix Lange <fjl@twurst.com>
Date: Mon, 5 Sep 2016 13:08:41 +0200
Subject: [PATCH] cmd/evm, cmd/geth, cmd/utils: move version handling to
 cmd/utils

---
 cmd/evm/main.go             |  6 ++-
 cmd/geth/accountcmd.go      | 10 ++---
 cmd/geth/consolecmd_test.go |  5 ++-
 cmd/geth/main.go            | 88 ++++++++++++++-----------------------
 cmd/utils/flags.go          | 24 +++++-----
 cmd/utils/version.go        | 64 +++++++++++++++++++++++++++
 6 files changed, 121 insertions(+), 76 deletions(-)
 create mode 100644 cmd/utils/version.go

diff --git a/cmd/evm/main.go b/cmd/evm/main.go
index 09cc9ee1f6..3f44e0f3c0 100644
--- a/cmd/evm/main.go
+++ b/cmd/evm/main.go
@@ -35,8 +35,11 @@ import (
 	"gopkg.in/urfave/cli.v1"
 )
 
+var gitCommit = "" // Git SHA1 commit hash of the release (set via linker flags)
+
 var (
-	app       *cli.App
+	app = utils.NewApp(gitCommit, "the evm command line interface")
+
 	DebugFlag = cli.BoolFlag{
 		Name:  "debug",
 		Usage: "output full trace logs",
@@ -91,7 +94,6 @@ var (
 )
 
 func init() {
-	app = utils.NewApp("0.2", "the evm command line interface")
 	app.Flags = []cli.Flag{
 		CreateFlag,
 		DebugFlag,
diff --git a/cmd/geth/accountcmd.go b/cmd/geth/accountcmd.go
index 2069df6cd9..2d70dcc2c9 100644
--- a/cmd/geth/accountcmd.go
+++ b/cmd/geth/accountcmd.go
@@ -168,7 +168,7 @@ nodes.
 )
 
 func accountList(ctx *cli.Context) error {
-	stack := utils.MakeNode(ctx, clientIdentifier, verString)
+	stack := utils.MakeNode(ctx, clientIdentifier, gitCommit)
 	for i, acct := range stack.AccountManager().Accounts() {
 		fmt.Printf("Account #%d: {%x} %s\n", i, acct.Address, acct.File)
 	}
@@ -261,7 +261,7 @@ func ambiguousAddrRecovery(am *accounts.Manager, err *accounts.AmbiguousAddrErro
 
 // accountCreate creates a new account into the keystore defined by the CLI flags.
 func accountCreate(ctx *cli.Context) error {
-	stack := utils.MakeNode(ctx, clientIdentifier, verString)
+	stack := utils.MakeNode(ctx, clientIdentifier, gitCommit)
 	password := getPassPhrase("Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0, utils.MakePasswordList(ctx))
 
 	account, err := stack.AccountManager().NewAccount(password)
@@ -278,7 +278,7 @@ func accountUpdate(ctx *cli.Context) error {
 	if len(ctx.Args()) == 0 {
 		utils.Fatalf("No accounts specified to update")
 	}
-	stack := utils.MakeNode(ctx, clientIdentifier, verString)
+	stack := utils.MakeNode(ctx, clientIdentifier, gitCommit)
 	account, oldPassword := unlockAccount(ctx, stack.AccountManager(), ctx.Args().First(), 0, nil)
 	newPassword := getPassPhrase("Please give a new password. Do not forget this password.", true, 0, nil)
 	if err := stack.AccountManager().Update(account, oldPassword, newPassword); err != nil {
@@ -297,7 +297,7 @@ func importWallet(ctx *cli.Context) error {
 		utils.Fatalf("Could not read wallet file: %v", err)
 	}
 
-	stack := utils.MakeNode(ctx, clientIdentifier, verString)
+	stack := utils.MakeNode(ctx, clientIdentifier, gitCommit)
 	passphrase := getPassPhrase("", false, 0, utils.MakePasswordList(ctx))
 	acct, err := stack.AccountManager().ImportPreSaleKey(keyJson, passphrase)
 	if err != nil {
@@ -316,7 +316,7 @@ func accountImport(ctx *cli.Context) error {
 	if err != nil {
 		utils.Fatalf("Failed to load the private key: %v", err)
 	}
-	stack := utils.MakeNode(ctx, clientIdentifier, verString)
+	stack := utils.MakeNode(ctx, clientIdentifier, gitCommit)
 	passphrase := getPassPhrase("Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0, utils.MakePasswordList(ctx))
 	acct, err := stack.AccountManager().ImportECDSA(key, passphrase)
 	if err != nil {
diff --git a/cmd/geth/consolecmd_test.go b/cmd/geth/consolecmd_test.go
index e0e549e124..3f09c0414e 100644
--- a/cmd/geth/consolecmd_test.go
+++ b/cmd/geth/consolecmd_test.go
@@ -28,6 +28,7 @@ import (
 	"testing"
 	"time"
 
+	"github.com/ethereum/go-ethereum/cmd/utils"
 	"github.com/ethereum/go-ethereum/rpc"
 )
 
@@ -45,7 +46,7 @@ func TestConsoleWelcome(t *testing.T) {
 	// Gather all the infos the welcome message needs to contain
 	geth.setTemplateFunc("goos", func() string { return runtime.GOOS })
 	geth.setTemplateFunc("gover", runtime.Version)
-	geth.setTemplateFunc("gethver", func() string { return verString })
+	geth.setTemplateFunc("gethver", func() string { return utils.Version })
 	geth.setTemplateFunc("niltime", func() string { return time.Unix(0, 0).Format(time.RFC1123) })
 	geth.setTemplateFunc("apis", func() []string {
 		apis := append(strings.Split(rpc.DefaultIPCApis, ","), rpc.MetadataApi)
@@ -131,7 +132,7 @@ func testAttachWelcome(t *testing.T, geth *testgeth, endpoint string) {
 	// Gather all the infos the welcome message needs to contain
 	attach.setTemplateFunc("goos", func() string { return runtime.GOOS })
 	attach.setTemplateFunc("gover", runtime.Version)
-	attach.setTemplateFunc("gethver", func() string { return verString })
+	attach.setTemplateFunc("gethver", func() string { return utils.Version })
 	attach.setTemplateFunc("etherbase", func() string { return geth.Etherbase })
 	attach.setTemplateFunc("niltime", func() string { return time.Unix(0, 0).Format(time.RFC1123) })
 	attach.setTemplateFunc("ipc", func() bool { return strings.HasPrefix(endpoint, "ipc") })
diff --git a/cmd/geth/main.go b/cmd/geth/main.go
index 82eae244d3..b5e454d872 100644
--- a/cmd/geth/main.go
+++ b/cmd/geth/main.go
@@ -42,49 +42,24 @@ import (
 	"github.com/ethereum/go-ethereum/logger/glog"
 	"github.com/ethereum/go-ethereum/metrics"
 	"github.com/ethereum/go-ethereum/node"
-	"github.com/ethereum/go-ethereum/params"
-	"github.com/ethereum/go-ethereum/rlp"
 	"gopkg.in/urfave/cli.v1"
 )
 
 const (
-	clientIdentifier = "Geth"     // Client identifier to advertise over the network
-	versionMajor     = 1          // Major version component of the current release
-	versionMinor     = 5          // Minor version component of the current release
-	versionPatch     = 0          // Patch version component of the current release
-	versionMeta      = "unstable" // Version metadata to append to the version string
-
-	versionOracle = "0xfa7b9770ca4cb04296cac84f37736d4041251cdf" // Ethereum address of the Geth release oracle
+	clientIdentifier = "Geth" // Client identifier to advertise over the network
 )
 
 var (
-	gitCommit string         // Git SHA1 commit hash of the release (set via linker flags)
-	verString string         // Combined textual representation of all the version components
-	relConfig release.Config // Structured version information and release oracle config
-	app       *cli.App
+	// Git SHA1 commit hash of the release (set via linker flags)
+	gitCommit = ""
+	// Ethereum address of the Geth release oracle.
+	relOracle = common.HexToAddress("0xfa7b9770ca4cb04296cac84f37736d4041251cdf")
+	// The app that holds all commands and flags.
+	app = utils.NewApp(gitCommit, "the go-ethereum command line interface")
 )
 
 func init() {
-	// Construct the textual version string from the individual components
-	verString = fmt.Sprintf("%d.%d.%d", versionMajor, versionMinor, versionPatch)
-	if versionMeta != "" {
-		verString += "-" + versionMeta
-	}
-	if gitCommit != "" {
-		verString += "-" + gitCommit[:8]
-	}
-	// Construct the version release oracle configuration
-	relConfig.Oracle = common.HexToAddress(versionOracle)
-
-	relConfig.Major = uint32(versionMajor)
-	relConfig.Minor = uint32(versionMinor)
-	relConfig.Patch = uint32(versionPatch)
-
-	commit, _ := hex.DecodeString(gitCommit)
-	copy(relConfig.Commit[:], commit)
-
 	// Initialize the CLI app and start Geth
-	app = utils.NewApp(verString, "the go-ethereum command line interface")
 	app.Action = geth
 	app.HideVersion = true // we have a command to print the version
 	app.Commands = []cli.Command{
@@ -290,35 +265,32 @@ func initGenesis(ctx *cli.Context) error {
 }
 
 func makeFullNode(ctx *cli.Context) *node.Node {
-	node := utils.MakeNode(ctx, clientIdentifier, verString)
-	utils.RegisterEthService(ctx, node, relConfig, makeDefaultExtra())
+	stack := utils.MakeNode(ctx, clientIdentifier, gitCommit)
+	utils.RegisterEthService(ctx, stack, utils.MakeDefaultExtraData(clientIdentifier))
+
 	// Whisper must be explicitly enabled, but is auto-enabled in --dev mode.
 	shhEnabled := ctx.GlobalBool(utils.WhisperEnabledFlag.Name)
 	shhAutoEnabled := !ctx.GlobalIsSet(utils.WhisperEnabledFlag.Name) && ctx.GlobalIsSet(utils.DevModeFlag.Name)
 	if shhEnabled || shhAutoEnabled {
-		utils.RegisterShhService(node)
-	}
-	return node
-}
-
-func makeDefaultExtra() []byte {
-	var clientInfo = struct {
-		Version   uint
-		Name      string
-		GoVersion string
-		Os        string
-	}{uint(versionMajor<<16 | versionMinor<<8 | versionPatch), clientIdentifier, runtime.Version(), runtime.GOOS}
-	extra, err := rlp.EncodeToBytes(clientInfo)
-	if err != nil {
-		glog.V(logger.Warn).Infoln("error setting canonical miner information:", err)
+		utils.RegisterShhService(stack)
 	}
 
-	if uint64(len(extra)) > params.MaximumExtraDataSize.Uint64() {
-		glog.V(logger.Warn).Infoln("error setting canonical miner information: extra exceeds", params.MaximumExtraDataSize)
-		glog.V(logger.Debug).Infof("extra: %x\n", extra)
-		return nil
+	// Add the release oracle service so it boots along with node.
+	if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
+		config := release.Config{
+			Oracle: relOracle,
+			Major:  uint32(utils.VersionMajor),
+			Minor:  uint32(utils.VersionMinor),
+			Patch:  uint32(utils.VersionPatch),
+		}
+		commit, _ := hex.DecodeString(gitCommit)
+		copy(config.Commit[:], commit)
+		return release.NewReleaseService(ctx, config)
+	}); err != nil {
+		utils.Fatalf("Failed to register the Geth release oracle service: %v", err)
 	}
-	return extra
+
+	return stack
 }
 
 // startNode boots up the system node and all registered protocols, after which
@@ -326,7 +298,8 @@ func makeDefaultExtra() []byte {
 // miner.
 func startNode(ctx *cli.Context, stack *node.Node) {
 	// Report geth version
-	glog.V(logger.Info).Infof("instance: Geth/%s/%s/%s\n", verString, runtime.Version(), runtime.GOOS)
+	glog.V(logger.Info).Infof("instance: Geth/%s/%s/%s\n", utils.Version, runtime.Version(), runtime.GOOS)
+
 	// Start up the node itself
 	utils.StartNode(stack)
 
@@ -408,7 +381,10 @@ func gpubench(ctx *cli.Context) error {
 
 func version(c *cli.Context) error {
 	fmt.Println(clientIdentifier)
-	fmt.Println("Version:", verString)
+	fmt.Println("Version:", utils.Version)
+	if gitCommit != "" {
+		fmt.Println("Git Commit:", gitCommit)
+	}
 	fmt.Println("Protocol Versions:", eth.ProtocolVersions)
 	fmt.Println("Network Id:", c.GlobalInt(utils.NetworkIdFlag.Name))
 	fmt.Println("Go Version:", runtime.Version())
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index 488e7fea21..a1f098f299 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -33,7 +33,6 @@ import (
 	"github.com/ethereum/ethash"
 	"github.com/ethereum/go-ethereum/accounts"
 	"github.com/ethereum/go-ethereum/common"
-	"github.com/ethereum/go-ethereum/contracts/release"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/crypto"
@@ -80,13 +79,16 @@ OPTIONS:
 }
 
 // NewApp creates an app with sane defaults.
-func NewApp(version, usage string) *cli.App {
+func NewApp(gitCommit, usage string) *cli.App {
 	app := cli.NewApp()
 	app.Name = filepath.Base(os.Args[0])
 	app.Author = ""
 	//app.Authors = nil
 	app.Email = ""
-	app.Version = version
+	app.Version = Version
+	if gitCommit != "" {
+		app.Version += "-" + gitCommit[:8]
+	}
 	app.Usage = usage
 	return app
 }
@@ -608,13 +610,18 @@ func MakePasswordList(ctx *cli.Context) []string {
 }
 
 // MakeNode configures a node with no services from command line flags.
-func MakeNode(ctx *cli.Context, name, version string) *node.Node {
+func MakeNode(ctx *cli.Context, name, gitCommit string) *node.Node {
+	vsn := Version
+	if gitCommit != "" {
+		vsn += "-" + gitCommit[:8]
+	}
+
 	config := &node.Config{
 		DataDir:           MustMakeDataDir(ctx),
 		KeyStoreDir:       ctx.GlobalString(KeyStoreDirFlag.Name),
 		UseLightweightKDF: ctx.GlobalBool(LightKDFFlag.Name),
 		PrivateKey:        MakeNodeKey(ctx),
-		Name:              MakeNodeName(name, version, ctx),
+		Name:              MakeNodeName(name, vsn, ctx),
 		NoDiscovery:       ctx.GlobalBool(NoDiscoverFlag.Name),
 		BootstrapNodes:    MakeBootstrapNodes(ctx),
 		ListenAddr:        MakeListenAddress(ctx),
@@ -648,7 +655,7 @@ func MakeNode(ctx *cli.Context, name, version string) *node.Node {
 
 // RegisterEthService configures eth.Ethereum from command line flags and adds it to the
 // given node.
-func RegisterEthService(ctx *cli.Context, stack *node.Node, relconf release.Config, extra []byte) {
+func RegisterEthService(ctx *cli.Context, stack *node.Node, extra []byte) {
 	// Avoid conflicting network flags
 	networks, netFlags := 0, []cli.BoolFlag{DevModeFlag, TestNetFlag, OlympicFlag}
 	for _, flag := range netFlags {
@@ -723,11 +730,6 @@ func RegisterEthService(ctx *cli.Context, stack *node.Node, relconf release.Conf
 	}); err != nil {
 		Fatalf("Failed to register the Ethereum service: %v", err)
 	}
-	if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
-		return release.NewReleaseService(ctx, relconf)
-	}); err != nil {
-		Fatalf("Failed to register the Geth release oracle service: %v", err)
-	}
 }
 
 // RegisterShhService configures whisper and adds it to the given node.
diff --git a/cmd/utils/version.go b/cmd/utils/version.go
new file mode 100644
index 0000000000..03633d694a
--- /dev/null
+++ b/cmd/utils/version.go
@@ -0,0 +1,64 @@
+// Copyright 2014 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 <http://www.gnu.org/licenses/>.
+
+// Package utils contains internal helper functions for go-ethereum commands.
+package utils
+
+import (
+	"fmt"
+	"runtime"
+
+	"github.com/ethereum/go-ethereum/logger"
+	"github.com/ethereum/go-ethereum/logger/glog"
+	"github.com/ethereum/go-ethereum/params"
+	"github.com/ethereum/go-ethereum/rlp"
+)
+
+const (
+	VersionMajor = 1          // Major version component of the current release
+	VersionMinor = 5          // Minor version component of the current release
+	VersionPatch = 0          // Patch version component of the current release
+	VersionMeta  = "unstable" // Version metadata to append to the version string
+)
+
+// Version holds the textual version string.
+var Version = func() string {
+	v := fmt.Sprintf("%d.%d.%d", VersionMajor, VersionMinor, VersionPatch)
+	if VersionMeta != "" {
+		v += "-" + VersionMeta
+	}
+	return v
+}()
+
+// MakeDefaultExtraData returns the default Ethereum block extra data blob.
+func MakeDefaultExtraData(clientIdentifier string) []byte {
+	var clientInfo = struct {
+		Version   uint
+		Name      string
+		GoVersion string
+		Os        string
+	}{uint(VersionMajor<<16 | VersionMinor<<8 | VersionPatch), clientIdentifier, runtime.Version(), runtime.GOOS}
+	extra, err := rlp.EncodeToBytes(clientInfo)
+	if err != nil {
+		glog.V(logger.Warn).Infoln("error setting canonical miner information:", err)
+	}
+	if uint64(len(extra)) > params.MaximumExtraDataSize.Uint64() {
+		glog.V(logger.Warn).Infoln("error setting canonical miner information: extra exceeds", params.MaximumExtraDataSize)
+		glog.V(logger.Debug).Infof("extra: %x\n", extra)
+		return nil
+	}
+	return extra
+}