2013-10-04 17:12:24 +02:00
// Copyright (c) 2013 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"
2013-10-08 03:53:25 +02:00
"github.com/conformal/btcdb"
_ "github.com/conformal/btcdb/ldb"
2014-05-27 06:39:30 +02:00
"github.com/conformal/btcnet"
2013-11-11 18:52:59 +01:00
"github.com/conformal/btcutil"
2013-10-08 03:53:25 +02:00
"github.com/conformal/btcwire"
2014-07-02 15:50:08 +02:00
flags "github.com/conformal/go-flags"
2013-10-04 17:12:24 +02:00
)
const (
minCandidates = 1
maxCandidates = 20
defaultNumCandidates = 5
2013-10-09 03:50:15 +02:00
defaultDbType = "leveldb"
2013-10-04 17:12:24 +02: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
2013-10-04 17:12:24 +02: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" `
NumCandidates int ` short:"n" long:"numcandidates" description:"Max num of checkpoint candidates to show { 1-20}" `
UseGoOutput bool ` short:"g" long:"gooutput" description:"Display the candidates using Go syntax that is ready to insert into the btcchain checkpoint list" `
2013-10-04 17:12:24 +02:00
}
2013-10-08 03:53:25 +02:00
// 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:39:30 +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
2013-10-08 03:53:25 +02:00
}
}
2013-10-04 17:12:24 +02:00
// loadConfig initializes and parses the config using command line options.
func loadConfig ( ) ( * config , [ ] string , error ) {
// Default config.
cfg := config {
DataDir : defaultDataDir ,
2013-10-08 03:53:25 +02:00
DbType : defaultDbType ,
2013-10-04 17:12:24 +02:00
NumCandidates : defaultNumCandidates ,
}
// 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
2013-10-08 03:53:25 +02: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
2013-10-08 03:53:25 +02: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 )
2013-10-04 17:12:24 +02:00
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 ) )
2013-10-08 03:53:25 +02:00
// Validate the number of candidates.
if cfg . NumCandidates < minCandidates || cfg . NumCandidates > maxCandidates {
str := "%s: The specified number of candidates is out of " +
"range -- parsed [%v]"
err = fmt . Errorf ( str , "loadConfig" , cfg . NumCandidates )
fmt . Fprintln ( os . Stderr , err )
parser . WriteHelp ( os . Stderr )
return nil , nil , err
}
2013-10-04 17:12:24 +02:00
return & cfg , remainingArgs , nil
}