From 55b300b6c2256fae3752ce97ff225ac2680ec36e Mon Sep 17 00:00:00 2001
From: David Hill <dhill@mindcry.org>
Date: Thu, 10 Oct 2013 14:05:54 -0400
Subject: [PATCH] improve addblock

---
 util/addblock/addblock.go | 128 +++++++++++++++++++-------------------
 1 file changed, 65 insertions(+), 63 deletions(-)

diff --git a/util/addblock/addblock.go b/util/addblock/addblock.go
index ca12626a..68713674 100644
--- a/util/addblock/addblock.go
+++ b/util/addblock/addblock.go
@@ -6,13 +6,13 @@ package main
 
 import (
 	"encoding/binary"
-	"flag"
 	"fmt"
 	"github.com/conformal/btcdb"
 	_ "github.com/conformal/btcdb/ldb"
 	_ "github.com/conformal/btcdb/sqlite3"
 	"github.com/conformal/btcutil"
 	"github.com/conformal/btcwire"
+	"github.com/conformal/go-flags"
 	"github.com/conformal/seelog"
 	"io"
 	"os"
@@ -23,6 +23,14 @@ import (
 
 type ShaHash btcwire.ShaHash
 
+type config struct {
+	DataDir  string `short:"b" long:"datadir" description:"Directory to store data"`
+	DbType   string `long:"dbtype" description:"Database backend"`
+	TestNet3 bool   `long:"testnet" description:"Use the test network"`
+	Progress bool   `short:"p" description:"show progress"`
+	InFile   string `short:"i" long:"infile" description:"File containing the block(s)" required:"true"`
+}
+
 var log seelog.LoggerInterface
 
 const (
@@ -42,25 +50,21 @@ type blkQueue struct {
 }
 
 func main() {
-	var err error
-	var dbType string
-	var datadir string
-	var infile string
-	var progress int
-	flag.StringVar(&dbType, "dbtype", "", "Database backend to use for the Block Chain")
-	flag.StringVar(&datadir, "datadir", "", "Directory to store data")
-	flag.StringVar(&infile, "i", "", "infile")
-	flag.IntVar(&progress, "p", 0, "show progress")
-
-	flag.Parse()
-
-	runtime.GOMAXPROCS(runtime.NumCPU())
-
-	if len (infile) == 0 {
-		fmt.Printf("Must specify inputfile")
+	cfg := config{
+		DbType:  "leveldb",
+		DataDir: filepath.Join(btcdHomeDir(), "data"),
+	}
+	parser := flags.NewParser(&cfg, flags.Default)
+	_, err := parser.Parse()
+	if err != nil {
+		if e, ok := err.(*flags.Error); !ok || e.Type != flags.ErrHelp {
+			parser.WriteHelp(os.Stderr)
+		}
 		return
 	}
 
+	runtime.GOMAXPROCS(runtime.NumCPU())
+
 	log, err = seelog.LoggerFromWriterWithMinLevel(os.Stdout,
 		seelog.InfoLvl)
 	if err != nil {
@@ -70,30 +74,29 @@ func main() {
 	defer log.Flush()
 	btcdb.UseLogger(log)
 
-	if len(dbType) == 0 {
-		dbType = "sqlite"
+	var testnet string
+	if cfg.TestNet3 {
+		testnet = "testnet"
+	} else {
+		testnet = "mainnet"
 	}
 
-	if len(datadir) == 0 {
-		datadir = filepath.Join(btcdHomeDir(), "data")
-	}
-	datadir = filepath.Join(datadir, "mainnet")
+	cfg.DataDir = filepath.Join(cfg.DataDir, testnet)
 
-	err = os.MkdirAll(datadir, 0700)
+	err = os.MkdirAll(cfg.DataDir, 0700)
 	if err != nil {
-		fmt.Printf("unable to create db repo area %v, %v", datadir, err)
+		fmt.Printf("unable to create db repo area %v, %v", cfg.DataDir, err)
 	}
 
-
 	blockDbNamePrefix := "blocks"
-        dbName := blockDbNamePrefix + "_" + dbType
-	if dbType == "sqlite" {
+	dbName := blockDbNamePrefix + "_" + cfg.DbType
+	if cfg.DbType == "sqlite" {
 		dbName = dbName + ".db"
 	}
-	dbPath := filepath.Join(datadir, dbName)
+	dbPath := filepath.Join(cfg.DataDir, dbName)
 
 	log.Infof("loading db")
-	db, err := btcdb.CreateDB(dbType, dbPath)
+	db, err := btcdb.CreateDB(cfg.DbType, dbPath)
 	if err != nil {
 		log.Warnf("db open failed: %v", err)
 		return
@@ -101,16 +104,15 @@ func main() {
 	defer db.Close()
 	log.Infof("db created")
 
-
 	var fi io.ReadCloser
 
-	fi, err = os.Open(infile)
+	fi, err = os.Open(cfg.InFile)
 	if err != nil {
-		log.Warnf("failed to open file %v, err %v", infile, err)
+		log.Warnf("failed to open file %v, err %v", cfg.InFile, err)
 	}
 	defer func() {
 		if err := fi.Close(); err != nil {
-			log.Warn("failed to close file %v %v", infile, err)
+			log.Warn("failed to close file %v %v", cfg.InFile, err)
 		}
 	}()
 
@@ -125,11 +127,11 @@ func main() {
 	go readBlocks(fi, bufqueue)
 
 	var eheight int64
-	doneMap := map [int64] *blkQueue {}
+	doneMap := map[int64]*blkQueue{}
 	for {
 
 		select {
-		case blkM := <- blkqueue:
+		case blkM := <-blkqueue:
 			doneMap[blkM.height] = blkM
 
 			for {
@@ -138,12 +140,12 @@ func main() {
 					blkP.complete <- true
 					db.InsertBlock(blkP.blk)
 
-					if progress != 0 && eheight%int64(progress) == 0 {
+					if cfg.Progress && eheight%int64(1) == 0 {
 						log.Infof("Processing block %v", eheight)
 					}
 					eheight++
 
-					if eheight % 2000 == 0 {
+					if eheight%2000 == 0 {
 						f, err := os.Create(fmt.Sprintf("profile.%d", eheight))
 						if err == nil {
 							pprof.WriteHeapProfile(f)
@@ -161,10 +163,10 @@ func main() {
 }
 
 func processBuf(idx int, bufqueue chan *bufQueue, blkqueue chan *blkQueue) {
-	complete := make (chan bool)
+	complete := make(chan bool)
 	for {
 		select {
-		case bq := <- bufqueue:
+		case bq := <-bufqueue:
 			var blkmsg blkQueue
 
 			blkmsg.height = bq.height
@@ -174,7 +176,7 @@ func processBuf(idx int, bufqueue chan *bufQueue, blkqueue chan *blkQueue) {
 				blkqueue <- &blkmsg
 			}
 
-			blk, err :=  btcutil.NewBlockFromBytes(bq.blkbuf)
+			blk, err := btcutil.NewBlockFromBytes(bq.blkbuf)
 			if err != nil {
 				fmt.Printf("failed to parse block %v", bq.height)
 				return
@@ -183,7 +185,7 @@ func processBuf(idx int, bufqueue chan *bufQueue, blkqueue chan *blkQueue) {
 			blkmsg.complete = complete
 			blkqueue <- &blkmsg
 			select {
-			case <- complete:
+			case <-complete:
 			}
 		}
 	}
@@ -204,7 +206,7 @@ func readBlocks(fi io.Reader, bufqueue chan *bufQueue) {
 			bufqueue <- &bufM
 		}
 		if net != uint32(btcwire.MainNet) {
-			fmt.Printf("network mismatch %v %v", 
+			fmt.Printf("network mismatch %v %v",
 				net, uint32(btcwire.MainNet))
 
 			bufqueue <- &bufM
@@ -224,7 +226,7 @@ func readBlocks(fi io.Reader, bufqueue chan *bufQueue) {
 // newLogger creates a new seelog logger using the provided logging level and
 // log message prefix.
 func newLogger(level string, prefix string) seelog.LoggerInterface {
-        fmtstring := `
+	fmtstring := `
         <seelog type="adaptive" mininterval="2000000" maxinterval="100000000"
                 critmsgcount="500" minlevel="%s">
                 <outputs formatid="all">
@@ -234,31 +236,31 @@ func newLogger(level string, prefix string) seelog.LoggerInterface {
                         <format id="all" format="[%%Time %%Date] [%%LEV] [%s] %%Msg%%n" />
                 </formats>
         </seelog>`
-        config := fmt.Sprintf(fmtstring, level, prefix)
+	config := fmt.Sprintf(fmtstring, level, prefix)
 
-        logger, err := seelog.LoggerFromConfigAsString(config)
-        if err != nil {
-                fmt.Fprintf(os.Stderr, "failed to create logger: %v", err)
-                os.Exit(1)
-        }
+	logger, err := seelog.LoggerFromConfigAsString(config)
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "failed to create logger: %v", err)
+		os.Exit(1)
+	}
 
-        return logger
+	return logger
 }
 
 // btcdHomeDir returns an OS appropriate home directory for btcd.
 func btcdHomeDir() string {
-        // Search for Windows APPDATA first.  This won't exist on POSIX OSes.
-        appData := os.Getenv("APPDATA")
-        if appData != "" {
-                return filepath.Join(appData, "btcd")
-        }
+	// Search for Windows APPDATA first.  This won't exist on POSIX OSes.
+	appData := os.Getenv("APPDATA")
+	if appData != "" {
+		return filepath.Join(appData, "btcd")
+	}
 
-        // Fall back to standard HOME directory that works for most POSIX OSes.
-        home := os.Getenv("HOME")
-        if home != "" {
-                return filepath.Join(home, ".btcd")
-        }
+	// Fall back to standard HOME directory that works for most POSIX OSes.
+	home := os.Getenv("HOME")
+	if home != "" {
+		return filepath.Join(home, ".btcd")
+	}
 
-        // In the worst case, use the current directory.
-        return "."
+	// In the worst case, use the current directory.
+	return "."
 }