2014-01-12 19:05:05 +01:00
// Copyright (c) 2013-2014 Conformal Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package main
import (
"fmt"
2014-07-02 15:50:08 +02:00
"os"
"path/filepath"
2014-01-12 19:05:05 +01:00
"github.com/conformal/btcdb"
_ "github.com/conformal/btcdb/ldb"
2014-05-27 06:55:10 +02:00
"github.com/conformal/btcnet"
2014-01-12 19:05:05 +01:00
"github.com/conformal/btcutil"
"github.com/conformal/btcwire"
2014-07-02 15:50:08 +02:00
flags "github.com/conformal/go-flags"
2014-01-12 19:05:05 +01:00
)
const (
defaultDbType = "leveldb"
defaultDataFile = "bootstrap.dat"
2014-03-19 02:23:27 +01:00
defaultProgress = 10
2014-01-12 19:05:05 +01:00
)
var (
2014-07-21 07:42:41 +02:00
btcdHomeDir = btcutil . AppDataDir ( "btcd" , false )
defaultDataDir = filepath . Join ( btcdHomeDir , "data" )
knownDbTypes = btcdb . SupportedDBs ( )
activeNetParams = & btcnet . MainNetParams
2014-01-12 19:05:05 +01:00
)
// config defines the configuration options for findcheckpoint.
//
// See loadConfig for details on the configuration load process.
type config struct {
2014-07-21 07:42:41 +02:00
DataDir string ` short:"b" long:"datadir" description:"Location of the btcd data directory" `
DbType string ` long:"dbtype" description:"Database backend to use for the Block Chain" `
TestNet3 bool ` long:"testnet" description:"Use the test network" `
RegressionTest bool ` long:"regtest" description:"Use the regression test network" `
SimNet bool ` long:"simnet" description:"Use the simulation test network" `
InFile string ` short:"i" long:"infile" description:"File containing the block(s)" `
Progress int ` short:"p" long:"progress" description:"Show a progress message each time this number of seconds have passed -- Use 0 to disable progress announcements" `
2014-01-12 19:05:05 +01:00
}
// filesExists reports whether the named file or directory exists.
func fileExists ( name string ) bool {
if _ , err := os . Stat ( name ) ; err != nil {
if os . IsNotExist ( err ) {
return false
}
}
return true
}
// validDbType returns whether or not dbType is a supported database type.
func validDbType ( dbType string ) bool {
for _ , knownType := range knownDbTypes {
if dbType == knownType {
return true
}
}
return false
}
2014-05-27 06:55:10 +02:00
// netName returns the name used when referring to a bitcoin network. At the
// time of writing, btcd currently places blocks for testnet version 3 in the
// data and log directory "testnet", which does not match the Name field of the
// btcnet parameters. This function can be used to override this directory name
// as "testnet" when the passed active network matches btcwire.TestNet3.
//
// A proper upgrade to move the data and log directories for this network to
// "testnet3" is planned for the future, at which point this function can be
// removed and the network parameter's name used instead.
func netName ( netParams * btcnet . Params ) string {
switch netParams . Net {
case btcwire . TestNet3 :
return "testnet"
default :
return netParams . Name
2014-01-12 19:05:05 +01:00
}
}
// loadConfig initializes and parses the config using command line options.
func loadConfig ( ) ( * config , [ ] string , error ) {
// Default config.
cfg := config {
DataDir : defaultDataDir ,
DbType : defaultDbType ,
InFile : defaultDataFile ,
Progress : defaultProgress ,
}
// Parse command line options.
parser := flags . NewParser ( & cfg , flags . Default )
remainingArgs , err := parser . Parse ( )
if err != nil {
if e , ok := err . ( * flags . Error ) ; ! ok || e . Type != flags . ErrHelp {
parser . WriteHelp ( os . Stderr )
}
return nil , nil , err
}
2014-07-21 07:42:41 +02:00
// Multiple networks can't be selected simultaneously.
funcName := "loadConfig"
numNets := 0
// Count number of network flags passed; assign active network params
// while we're at it
2014-01-12 19:05:05 +01:00
if cfg . TestNet3 {
2014-07-21 07:42:41 +02:00
numNets ++
activeNetParams = & btcnet . TestNet3Params
}
if cfg . RegressionTest {
numNets ++
activeNetParams = & btcnet . RegressionNetParams
}
if cfg . SimNet {
numNets ++
activeNetParams = & btcnet . SimNetParams
}
if numNets > 1 {
str := "%s: The testnet, regtest, and simnet params can't be " +
"used together -- choose one of the three"
err := fmt . Errorf ( str , funcName )
fmt . Fprintln ( os . Stderr , err )
parser . WriteHelp ( os . Stderr )
return nil , nil , err
2014-01-12 19:05:05 +01:00
}
// Validate database type.
if ! validDbType ( cfg . DbType ) {
str := "%s: The specified database type [%v] is invalid -- " +
"supported types %v"
err := fmt . Errorf ( str , "loadConfig" , cfg . DbType , knownDbTypes )
fmt . Fprintln ( os . Stderr , err )
parser . WriteHelp ( os . Stderr )
return nil , nil , err
}
// Append the network type to the data directory so it is "namespaced"
// per network. In addition to the block database, there are other
// pieces of data that are saved to disk such as address manager state.
// All data is specific to a network, so namespacing the data directory
// means each individual piece of serialized data does not have to
// worry about changing names per network and such.
2014-07-21 07:42:41 +02:00
cfg . DataDir = filepath . Join ( cfg . DataDir , netName ( activeNetParams ) )
2014-01-12 19:05:05 +01:00
// Ensure the specified block file exists.
if ! fileExists ( cfg . InFile ) {
str := "%s: The specified block file [%v] does not exist"
err := fmt . Errorf ( str , "loadConfig" , cfg . InFile )
fmt . Fprintln ( os . Stderr , err )
parser . WriteHelp ( os . Stderr )
return nil , nil , err
}
return & cfg , remainingArgs , nil
}