2016-02-03 18:42:04 +01:00
|
|
|
// Copyright (c) 2015-2016 The btcsuite developers
|
|
|
|
// Use of this source code is governed by an ISC
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
"strings"
|
|
|
|
|
2015-08-26 11:54:55 +02:00
|
|
|
"github.com/btcsuite/btcd/database"
|
2016-02-03 18:42:04 +01:00
|
|
|
"github.com/btcsuite/btclog"
|
2016-12-09 18:54:33 +01:00
|
|
|
flags "github.com/jessevdk/go-flags"
|
2016-02-03 18:42:04 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
// blockDbNamePrefix is the prefix for the btcd block database.
|
|
|
|
blockDbNamePrefix = "blocks"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
log btclog.Logger
|
|
|
|
shutdownChannel = make(chan error)
|
|
|
|
)
|
|
|
|
|
|
|
|
// loadBlockDB opens the block database and returns a handle to it.
|
|
|
|
func loadBlockDB() (database.DB, error) {
|
|
|
|
// The database name is based on the database type.
|
|
|
|
dbName := blockDbNamePrefix + "_" + cfg.DbType
|
|
|
|
dbPath := filepath.Join(cfg.DataDir, dbName)
|
|
|
|
|
|
|
|
log.Infof("Loading block database from '%s'", dbPath)
|
|
|
|
db, err := database.Open(cfg.DbType, dbPath, activeNetParams.Net)
|
|
|
|
if err != nil {
|
|
|
|
// Return the error if it's not because the database doesn't
|
|
|
|
// exist.
|
|
|
|
if dbErr, ok := err.(database.Error); !ok || dbErr.ErrorCode !=
|
|
|
|
database.ErrDbDoesNotExist {
|
|
|
|
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create the db if it does not exist.
|
|
|
|
err = os.MkdirAll(cfg.DataDir, 0700)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
db, err = database.Create(cfg.DbType, dbPath, activeNetParams.Net)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Info("Block database loaded")
|
|
|
|
return db, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// realMain is the real main function for the utility. It is necessary to work
|
|
|
|
// around the fact that deferred functions do not run when os.Exit() is called.
|
|
|
|
func realMain() error {
|
|
|
|
// Setup logging.
|
2017-05-24 23:24:06 +02:00
|
|
|
backendLogger := btclog.NewBackend(os.Stdout)
|
|
|
|
defer os.Stdout.Sync()
|
|
|
|
log = backendLogger.Logger("MAIN")
|
|
|
|
dbLog := backendLogger.Logger("BCDB")
|
|
|
|
dbLog.SetLevel(btclog.LevelDebug)
|
2016-02-03 18:42:04 +01:00
|
|
|
database.UseLogger(dbLog)
|
|
|
|
|
|
|
|
// Setup the parser options and commands.
|
|
|
|
appName := filepath.Base(os.Args[0])
|
|
|
|
appName = strings.TrimSuffix(appName, filepath.Ext(appName))
|
|
|
|
parserFlags := flags.Options(flags.HelpFlag | flags.PassDoubleDash)
|
|
|
|
parser := flags.NewNamedParser(appName, parserFlags)
|
|
|
|
parser.AddGroup("Global Options", "", cfg)
|
|
|
|
parser.AddCommand("insecureimport",
|
|
|
|
"Insecurely import bulk block data from bootstrap.dat",
|
|
|
|
"Insecurely import bulk block data from bootstrap.dat. "+
|
|
|
|
"WARNING: This is NOT secure because it does NOT "+
|
|
|
|
"verify chain rules. It is only provided for testing "+
|
|
|
|
"purposes.", &importCfg)
|
|
|
|
parser.AddCommand("loadheaders",
|
|
|
|
"Time how long to load headers for all blocks in the database",
|
|
|
|
"", &headersCfg)
|
|
|
|
parser.AddCommand("fetchblock",
|
|
|
|
"Fetch the specific block hash from the database", "",
|
|
|
|
&fetchBlockCfg)
|
|
|
|
parser.AddCommand("fetchblockregion",
|
|
|
|
"Fetch the specified block region from the database", "",
|
|
|
|
&blockRegionCfg)
|
|
|
|
|
|
|
|
// Parse command line and invoke the Execute function for the specified
|
|
|
|
// command.
|
|
|
|
if _, err := parser.Parse(); err != nil {
|
|
|
|
if e, ok := err.(*flags.Error); ok && e.Type == flags.ErrHelp {
|
|
|
|
parser.WriteHelp(os.Stderr)
|
|
|
|
} else {
|
|
|
|
log.Error(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
// Work around defer not working after os.Exit()
|
|
|
|
if err := realMain(); err != nil {
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
}
|