From 3b9808f23ca4eb1621a92aad80de5c89269f17fe Mon Sep 17 00:00:00 2001
From: Felix Lange <fjl@twurst.com>
Date: Wed, 27 May 2015 13:29:34 +0200
Subject: [PATCH] cmd/geth, cmd/utils: don't use Ethereum for import, export
 and upgradedb

The blockchain commands don't need the full stack. With this change,
p2p, miner, downloader, etc are no longer started for blockchain
operations.
---
 cmd/geth/main.go   | 113 +++++++++++++--------------------------------
 cmd/utils/cmd.go   |  49 +++++++++-----------
 cmd/utils/flags.go |  44 ++++++++----------
 3 files changed, 72 insertions(+), 134 deletions(-)

diff --git a/cmd/geth/main.go b/cmd/geth/main.go
index 0cbf8e41a..f849063fa 100644
--- a/cmd/geth/main.go
+++ b/cmd/geth/main.go
@@ -41,6 +41,7 @@ import (
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/eth"
 	"github.com/ethereum/go-ethereum/logger"
+	"github.com/ethereum/go-ethereum/logger/glog"
 	"github.com/mattn/go-colorable"
 	"github.com/mattn/go-isatty"
 )
@@ -282,17 +283,12 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Conso
 		utils.SolcPathFlag,
 	}
 	app.Before = func(ctx *cli.Context) error {
+		utils.SetupLogger(ctx)
 		if ctx.GlobalBool(utils.PProfEanbledFlag.Name) {
 			utils.StartPProf(ctx)
 		}
 		return nil
 	}
-
-	// missing:
-	// flag.StringVar(&ConfigFile, "conf", defaultConfigFile, "config file")
-	// flag.BoolVar(&DiffTool, "difftool", false, "creates output for diff'ing. Sets LogLevel=0")
-	// flag.StringVar(&DiffType, "diff", "all", "sets the level of diff output [vm, all]. Has no effect if difftool=false")
-
 }
 
 func main() {
@@ -516,53 +512,25 @@ func importchain(ctx *cli.Context) {
 	if len(ctx.Args()) != 1 {
 		utils.Fatalf("This command requires an argument.")
 	}
-
-	cfg := utils.MakeEthConfig(ClientIdentifier, Version, ctx)
-	cfg.SkipBcVersionCheck = true
-
-	ethereum, err := eth.New(cfg)
-	if err != nil {
-		utils.Fatalf("%v\n", err)
-	}
-
-	chainmgr := ethereum.ChainManager()
+	chain, blockDB, stateDB, extraDB := utils.GetChain(ctx)
 	start := time.Now()
-	err = utils.ImportChain(chainmgr, ctx.Args().First())
-	if err != nil {
+	if err := utils.ImportChain(chain, ctx.Args().First()); err != nil {
 		utils.Fatalf("Import error: %v\n", err)
 	}
-
-	// force database flush
-	ethereum.BlockDb().Flush()
-	ethereum.StateDb().Flush()
-	ethereum.ExtraDb().Flush()
-
+	flushAll(blockDB, stateDB, extraDB)
 	fmt.Printf("Import done in %v", time.Since(start))
-
-	return
 }
 
 func exportchain(ctx *cli.Context) {
 	if len(ctx.Args()) != 1 {
 		utils.Fatalf("This command requires an argument.")
 	}
-
-	cfg := utils.MakeEthConfig(ClientIdentifier, nodeNameVersion, ctx)
-	cfg.SkipBcVersionCheck = true
-
-	ethereum, err := eth.New(cfg)
-	if err != nil {
-		utils.Fatalf("%v\n", err)
-	}
-
-	chainmgr := ethereum.ChainManager()
+	chain, _, _, _ := utils.GetChain(ctx)
 	start := time.Now()
-	err = utils.ExportChain(chainmgr, ctx.Args().First())
-	if err != nil {
+	if err := utils.ExportChain(chain, ctx.Args().First()); err != nil {
 		utils.Fatalf("Export error: %v\n", err)
 	}
 	fmt.Printf("Export done in %v", time.Since(start))
-	return
 }
 
 func removeDb(ctx *cli.Context) {
@@ -585,76 +553,54 @@ func removeDb(ctx *cli.Context) {
 }
 
 func upgradeDb(ctx *cli.Context) {
-	fmt.Println("Upgrade blockchain DB")
+	glog.Infoln("Upgrading blockchain database")
 
-	cfg := utils.MakeEthConfig(ClientIdentifier, Version, ctx)
-	cfg.SkipBcVersionCheck = true
-
-	ethereum, err := eth.New(cfg)
-	if err != nil {
-		utils.Fatalf("%v\n", err)
-	}
-
-	v, _ := ethereum.BlockDb().Get([]byte("BlockchainVersion"))
+	chain, blockDB, stateDB, extraDB := utils.GetChain(ctx)
+	v, _ := blockDB.Get([]byte("BlockchainVersion"))
 	bcVersion := int(common.NewValue(v).Uint())
-
 	if bcVersion == 0 {
 		bcVersion = core.BlockChainVersion
 	}
 
+	// Export the current chain.
 	filename := fmt.Sprintf("blockchain_%d_%s.chain", bcVersion, time.Now().Format("20060102_150405"))
 	exportFile := filepath.Join(ctx.GlobalString(utils.DataDirFlag.Name), filename)
-
-	err = utils.ExportChain(ethereum.ChainManager(), exportFile)
-	if err != nil {
+	if err := utils.ExportChain(chain, exportFile); err != nil {
 		utils.Fatalf("Unable to export chain for reimport %s\n", err)
 	}
-
-	ethereum.BlockDb().Close()
-	ethereum.StateDb().Close()
-	ethereum.ExtraDb().Close()
-
+	flushAll(blockDB, stateDB, extraDB)
 	os.RemoveAll(filepath.Join(ctx.GlobalString(utils.DataDirFlag.Name), "blockchain"))
 	os.RemoveAll(filepath.Join(ctx.GlobalString(utils.DataDirFlag.Name), "state"))
 
-	ethereum, err = eth.New(cfg)
-	if err != nil {
-		utils.Fatalf("%v\n", err)
-	}
-
-	ethereum.BlockDb().Put([]byte("BlockchainVersion"), common.NewValue(core.BlockChainVersion).Bytes())
-
-	err = utils.ImportChain(ethereum.ChainManager(), exportFile)
+	// Import the chain file.
+	chain, blockDB, stateDB, extraDB = utils.GetChain(ctx)
+	blockDB.Put([]byte("BlockchainVersion"), common.NewValue(core.BlockChainVersion).Bytes())
+	err := utils.ImportChain(chain, exportFile)
+	flushAll(blockDB, stateDB, extraDB)
 	if err != nil {
 		utils.Fatalf("Import error %v (a backup is made in %s, use the import command to import it)\n", err, exportFile)
+	} else {
+		os.Remove(exportFile)
+		glog.Infoln("Import finished")
 	}
-
-	// force database flush
-	ethereum.BlockDb().Flush()
-	ethereum.StateDb().Flush()
-	ethereum.ExtraDb().Flush()
-
-	os.Remove(exportFile)
-
-	fmt.Println("Import finished")
 }
 
 func dump(ctx *cli.Context) {
-	chainmgr, _, stateDb := utils.GetChain(ctx)
+	chain, _, stateDB, _ := utils.GetChain(ctx)
 	for _, arg := range ctx.Args() {
 		var block *types.Block
 		if hashish(arg) {
-			block = chainmgr.GetBlock(common.HexToHash(arg))
+			block = chain.GetBlock(common.HexToHash(arg))
 		} else {
 			num, _ := strconv.Atoi(arg)
-			block = chainmgr.GetBlockByNumber(uint64(num))
+			block = chain.GetBlockByNumber(uint64(num))
 		}
 		if block == nil {
 			fmt.Println("{}")
 			utils.Fatalf("block not found")
 		} else {
-			statedb := state.New(block.Root(), stateDb)
-			fmt.Printf("%s\n", statedb.Dump())
+			state := state.New(block.Root(), stateDB)
+			fmt.Printf("%s\n", state.Dump())
 		}
 	}
 }
@@ -707,3 +653,10 @@ func hashish(x string) bool {
 	_, err := strconv.Atoi(x)
 	return err != nil
 }
+
+func flushAll(dbs ...common.Database) {
+	for _, db := range dbs {
+		db.Flush()
+		db.Close()
+	}
+}
diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go
index 39b4e46da..550ac1c51 100644
--- a/cmd/utils/cmd.go
+++ b/cmd/utils/cmd.go
@@ -167,7 +167,7 @@ func FormatTransactionData(data string) []byte {
 }
 
 func ImportChain(chainmgr *core.ChainManager, fn string) error {
-	fmt.Printf("importing blockchain '%s'\n", fn)
+	glog.Infoln("Importing blockchain", fn)
 	fh, err := os.OpenFile(fn, os.O_RDONLY, os.ModePerm)
 	if err != nil {
 		return err
@@ -176,43 +176,36 @@ func ImportChain(chainmgr *core.ChainManager, fn string) error {
 
 	chainmgr.Reset()
 	stream := rlp.NewStream(fh, 0)
-	var i, n int
 
 	batchSize := 2500
 	blocks := make(types.Blocks, batchSize)
-
-	for ; ; i++ {
-		var b types.Block
-		if err := stream.Decode(&b); err == io.EOF {
-			break
-		} else if err != nil {
-			return fmt.Errorf("at block %d: %v", i, err)
-		}
-
-		blocks[n] = &b
-		n++
-
-		if n == batchSize {
-			if _, err := chainmgr.InsertChain(blocks); err != nil {
-				return fmt.Errorf("invalid block %v", err)
+	n := 0
+	for {
+		// Load a batch of RLP blocks.
+		i := 0
+		for ; i < batchSize; i++ {
+			var b types.Block
+			if err := stream.Decode(&b); err == io.EOF {
+				break
+			} else if err != nil {
+				return fmt.Errorf("at block %d: %v", n, err)
 			}
-			n = 0
-			blocks = make(types.Blocks, batchSize)
+			blocks[i] = &b
+			n++
 		}
-	}
-
-	if n > 0 {
-		if _, err := chainmgr.InsertChain(blocks[:n]); err != nil {
-			return fmt.Errorf("invalid block %v", err)
+		if i == 0 {
+			break
+		}
+		// Import the batch.
+		if _, err := chainmgr.InsertChain(blocks[:i]); err != nil {
+			return fmt.Errorf("invalid block %d: %v", n, err)
 		}
 	}
-
-	fmt.Printf("imported %d blocks\n", i)
 	return nil
 }
 
 func ExportChain(chainmgr *core.ChainManager, fn string) error {
-	fmt.Printf("exporting blockchain '%s'\n", fn)
+	glog.Infoln("Exporting blockchain to", fn)
 	fh, err := os.OpenFile(fn, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
 	if err != nil {
 		return err
@@ -221,6 +214,6 @@ func ExportChain(chainmgr *core.ChainManager, fn string) error {
 	if err := chainmgr.Export(fh); err != nil {
 		return err
 	}
-	fmt.Printf("exported blockchain\n")
+	glog.Infoln("Exported blockchain to", fn)
 	return nil
 }
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index 155110ddc..176a546f1 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -283,20 +283,10 @@ func GetNodeKey(ctx *cli.Context) (key *ecdsa.PrivateKey) {
 }
 
 func MakeEthConfig(clientID, version string, ctx *cli.Context) *eth.Config {
-	// Set verbosity on glog
-	glog.SetV(ctx.GlobalInt(VerbosityFlag.Name))
-	glog.CopyStandardLogTo("INFO")
-	// Set the log type
-	//glog.SetToStderr(ctx.GlobalBool(LogToStdErrFlag.Name))
-	glog.SetToStderr(true)
-	// Set the log dir
-	glog.SetLogDir(ctx.GlobalString(LogFileFlag.Name))
-
 	customName := ctx.GlobalString(IdentityFlag.Name)
 	if len(customName) > 0 {
 		clientID += "/" + customName
 	}
-
 	return &eth.Config{
 		Name:               common.MakeName(clientID, version),
 		DataDir:            ctx.GlobalString(DataDirFlag.Name),
@@ -327,32 +317,34 @@ func MakeEthConfig(clientID, version string, ctx *cli.Context) *eth.Config {
 	}
 }
 
-func GetChain(ctx *cli.Context) (*core.ChainManager, common.Database, common.Database) {
-	dataDir := ctx.GlobalString(DataDirFlag.Name)
+// SetupLogger configures glog from the logging-related command line flags.
+func SetupLogger(ctx *cli.Context) {
+	glog.SetV(ctx.GlobalInt(VerbosityFlag.Name))
+	glog.CopyStandardLogTo("INFO")
+	glog.SetToStderr(true)
+	glog.SetLogDir(ctx.GlobalString(LogFileFlag.Name))
+}
 
-	blockDb, err := ethdb.NewLDBDatabase(filepath.Join(dataDir, "blockchain"))
-	if err != nil {
+func GetChain(ctx *cli.Context) (chain *core.ChainManager, blockDB, stateDB, extraDB common.Database) {
+	dd := ctx.GlobalString(DataDirFlag.Name)
+	var err error
+	if blockDB, err = ethdb.NewLDBDatabase(filepath.Join(dd, "blockchain")); err != nil {
 		Fatalf("Could not open database: %v", err)
 	}
-
-	stateDb, err := ethdb.NewLDBDatabase(filepath.Join(dataDir, "state"))
-	if err != nil {
+	if stateDB, err = ethdb.NewLDBDatabase(filepath.Join(dd, "state")); err != nil {
 		Fatalf("Could not open database: %v", err)
 	}
-
-	extraDb, err := ethdb.NewLDBDatabase(filepath.Join(dataDir, "extra"))
-	if err != nil {
+	if extraDB, err = ethdb.NewLDBDatabase(filepath.Join(dd, "extra")); err != nil {
 		Fatalf("Could not open database: %v", err)
 	}
 
 	eventMux := new(event.TypeMux)
 	pow := ethash.New()
-	chainManager := core.NewChainManager(blockDb, stateDb, pow, eventMux)
-	txPool := core.NewTxPool(eventMux, chainManager.State, chainManager.GasLimit)
-	blockProcessor := core.NewBlockProcessor(stateDb, extraDb, pow, txPool, chainManager, eventMux)
-	chainManager.SetProcessor(blockProcessor)
-
-	return chainManager, blockDb, stateDb
+	chain = core.NewChainManager(blockDB, stateDB, pow, eventMux)
+	txpool := core.NewTxPool(eventMux, chain.State, chain.GasLimit)
+	proc := core.NewBlockProcessor(stateDB, extraDB, pow, txpool, chain, eventMux)
+	chain.SetProcessor(proc)
+	return chain, blockDB, stateDB, extraDB
 }
 
 func GetAccountManager(ctx *cli.Context) *accounts.Manager {
-- 
GitLab