Merge pull request #1123 from fjl/lean-blockchain-commands

cmd/geth: leaner blockchain commands
This commit is contained in:
Jeffrey Wilcke 2015-05-28 04:17:47 -07:00
commit 9f467c387a
7 changed files with 287 additions and 269 deletions

View File

@ -12,7 +12,7 @@ import (
"github.com/ethereum/go-ethereum/tests" "github.com/ethereum/go-ethereum/tests"
) )
var blocktestCmd = cli.Command{ var blocktestCommand = cli.Command{
Action: runBlockTest, Action: runBlockTest,
Name: "blocktest", Name: "blocktest",
Usage: `loads a block test file`, Usage: `loads a block test file`,

159
cmd/geth/chaincmd.go Normal file
View File

@ -0,0 +1,159 @@
package main
import (
"fmt"
"os"
"path/filepath"
"strconv"
"time"
"github.com/codegangsta/cli"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/logger/glog"
)
var (
importCommand = cli.Command{
Action: importChain,
Name: "import",
Usage: `import a blockchain file`,
}
exportCommand = cli.Command{
Action: exportChain,
Name: "export",
Usage: `export blockchain into file`,
}
upgradedbCommand = cli.Command{
Action: upgradeDB,
Name: "upgradedb",
Usage: "upgrade chainblock database",
}
removedbCommand = cli.Command{
Action: removeDB,
Name: "removedb",
Usage: "Remove blockchain and state databases",
}
dumpCommand = cli.Command{
Action: dump,
Name: "dump",
Usage: `dump a specific block from storage`,
Description: `
The arguments are interpreted as block numbers or hashes.
Use "ethereum dump 0" to dump the genesis block.
`,
}
)
func importChain(ctx *cli.Context) {
if len(ctx.Args()) != 1 {
utils.Fatalf("This command requires an argument.")
}
chain, blockDB, stateDB, extraDB := utils.MakeChain(ctx)
start := time.Now()
err := utils.ImportChain(chain, ctx.Args().First())
closeAll(blockDB, stateDB, extraDB)
if err != nil {
utils.Fatalf("Import error: %v", err)
}
fmt.Printf("Import done in %v", time.Since(start))
}
func exportChain(ctx *cli.Context) {
if len(ctx.Args()) != 1 {
utils.Fatalf("This command requires an argument.")
}
chain, _, _, _ := utils.MakeChain(ctx)
start := time.Now()
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))
}
func removeDB(ctx *cli.Context) {
confirm, err := utils.PromptConfirm("Remove local databases?")
if err != nil {
utils.Fatalf("%v", err)
}
if confirm {
fmt.Println("Removing chain and state databases...")
start := time.Now()
os.RemoveAll(filepath.Join(ctx.GlobalString(utils.DataDirFlag.Name), "blockchain"))
os.RemoveAll(filepath.Join(ctx.GlobalString(utils.DataDirFlag.Name), "state"))
fmt.Printf("Removed in %v\n", time.Since(start))
} else {
fmt.Println("Operation aborted")
}
}
func upgradeDB(ctx *cli.Context) {
glog.Infoln("Upgrading blockchain database")
chain, blockDB, stateDB, extraDB := utils.MakeChain(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)
if err := utils.ExportChain(chain, exportFile); err != nil {
utils.Fatalf("Unable to export chain for reimport %s", err)
}
closeAll(blockDB, stateDB, extraDB)
os.RemoveAll(filepath.Join(ctx.GlobalString(utils.DataDirFlag.Name), "blockchain"))
os.RemoveAll(filepath.Join(ctx.GlobalString(utils.DataDirFlag.Name), "state"))
// Import the chain file.
chain, blockDB, stateDB, extraDB = utils.MakeChain(ctx)
blockDB.Put([]byte("BlockchainVersion"), common.NewValue(core.BlockChainVersion).Bytes())
err := utils.ImportChain(chain, exportFile)
closeAll(blockDB, stateDB, extraDB)
if err != nil {
utils.Fatalf("Import error %v (a backup is made in %s, use the import command to import it)", err, exportFile)
} else {
os.Remove(exportFile)
glog.Infoln("Import finished")
}
}
func dump(ctx *cli.Context) {
chain, _, stateDB, _ := utils.MakeChain(ctx)
for _, arg := range ctx.Args() {
var block *types.Block
if hashish(arg) {
block = chain.GetBlock(common.HexToHash(arg))
} else {
num, _ := strconv.Atoi(arg)
block = chain.GetBlockByNumber(uint64(num))
}
if block == nil {
fmt.Println("{}")
utils.Fatalf("block not found")
} else {
state := state.New(block.Root(), stateDB)
fmt.Printf("%s\n", state.Dump())
}
}
}
// hashish returns true for strings that look like hashes.
func hashish(x string) bool {
_, err := strconv.Atoi(x)
return err != nil
}
func closeAll(dbs ...common.Database) {
for _, db := range dbs {
db.Close()
}
}

View File

@ -24,27 +24,23 @@ import (
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
_ "net/http/pprof"
"os" "os"
"path/filepath" "path/filepath"
"runtime" "runtime"
"strconv" "strconv"
"strings" "strings"
"time"
"github.com/codegangsta/cli" "github.com/codegangsta/cli"
"github.com/ethereum/ethash" "github.com/ethereum/ethash"
"github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger"
"github.com/mattn/go-colorable" "github.com/mattn/go-colorable"
"github.com/mattn/go-isatty" "github.com/mattn/go-isatty"
) )
import _ "net/http/pprof"
const ( const (
ClientIdentifier = "Geth" ClientIdentifier = "Geth"
@ -68,7 +64,12 @@ func init() {
app.Action = run app.Action = run
app.HideVersion = true // we have a command to print the version app.HideVersion = true // we have a command to print the version
app.Commands = []cli.Command{ app.Commands = []cli.Command{
blocktestCmd, blocktestCommand,
importCommand,
exportCommand,
upgradedbCommand,
removedbCommand,
dumpCommand,
{ {
Action: makedag, Action: makedag,
Name: "makedag", Name: "makedag",
@ -193,15 +194,6 @@ nodes.
}, },
}, },
}, },
{
Action: dump,
Name: "dump",
Usage: `dump a specific block from storage`,
Description: `
The arguments are interpreted as block numbers or hashes.
Use "ethereum dump 0" to dump the genesis block.
`,
},
{ {
Action: console, Action: console,
Name: "console", Name: "console",
@ -221,26 +213,6 @@ The JavaScript VM exposes a node admin interface as well as the Ðapp
JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Console JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Console
`, `,
}, },
{
Action: importchain,
Name: "import",
Usage: `import a blockchain file`,
},
{
Action: exportchain,
Name: "export",
Usage: `export blockchain into file`,
},
{
Action: upgradeDb,
Name: "upgradedb",
Usage: "upgrade chainblock database",
},
{
Action: removeDb,
Name: "removedb",
Usage: "Remove blockchain and state databases",
},
} }
app.Flags = []cli.Flag{ app.Flags = []cli.Flag{
utils.IdentityFlag, utils.IdentityFlag,
@ -282,17 +254,12 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Conso
utils.SolcPathFlag, utils.SolcPathFlag,
} }
app.Before = func(ctx *cli.Context) error { app.Before = func(ctx *cli.Context) error {
utils.SetupLogger(ctx)
if ctx.GlobalBool(utils.PProfEanbledFlag.Name) { if ctx.GlobalBool(utils.PProfEanbledFlag.Name) {
utils.StartPProf(ctx) utils.StartPProf(ctx)
} }
return nil 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() { func main() {
@ -427,7 +394,7 @@ func startEth(ctx *cli.Context, eth *eth.Ethereum) {
} }
func accountList(ctx *cli.Context) { func accountList(ctx *cli.Context) {
am := utils.GetAccountManager(ctx) am := utils.MakeAccountManager(ctx)
accts, err := am.Accounts() accts, err := am.Accounts()
if err != nil { if err != nil {
utils.Fatalf("Could not list accounts: %v", err) utils.Fatalf("Could not list accounts: %v", err)
@ -469,7 +436,7 @@ func getPassPhrase(ctx *cli.Context, desc string, confirmation bool) (passphrase
} }
func accountCreate(ctx *cli.Context) { func accountCreate(ctx *cli.Context) {
am := utils.GetAccountManager(ctx) am := utils.MakeAccountManager(ctx)
passphrase := getPassPhrase(ctx, "Your new account is locked with a password. Please give a password. Do not forget this password.", true) passphrase := getPassPhrase(ctx, "Your new account is locked with a password. Please give a password. Do not forget this password.", true)
acct, err := am.NewAccount(passphrase) acct, err := am.NewAccount(passphrase)
if err != nil { if err != nil {
@ -488,7 +455,7 @@ func importWallet(ctx *cli.Context) {
utils.Fatalf("Could not read wallet file: %v", err) utils.Fatalf("Could not read wallet file: %v", err)
} }
am := utils.GetAccountManager(ctx) am := utils.MakeAccountManager(ctx)
passphrase := getPassPhrase(ctx, "", false) passphrase := getPassPhrase(ctx, "", false)
acct, err := am.ImportPreSaleKey(keyJson, passphrase) acct, err := am.ImportPreSaleKey(keyJson, passphrase)
@ -503,7 +470,7 @@ func accountImport(ctx *cli.Context) {
if len(keyfile) == 0 { if len(keyfile) == 0 {
utils.Fatalf("keyfile must be given as argument") utils.Fatalf("keyfile must be given as argument")
} }
am := utils.GetAccountManager(ctx) am := utils.MakeAccountManager(ctx)
passphrase := getPassPhrase(ctx, "Your new account is locked with a password. Please give a password. Do not forget this password.", true) passphrase := getPassPhrase(ctx, "Your new account is locked with a password. Please give a password. Do not forget this password.", true)
acct, err := am.Import(keyfile, passphrase) acct, err := am.Import(keyfile, passphrase)
if err != nil { if err != nil {
@ -512,153 +479,6 @@ func accountImport(ctx *cli.Context) {
fmt.Printf("Address: %x\n", acct) fmt.Printf("Address: %x\n", acct)
} }
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()
start := time.Now()
err = utils.ImportChain(chainmgr, ctx.Args().First())
if err != nil {
utils.Fatalf("Import error: %v\n", err)
}
// force database flush
ethereum.BlockDb().Flush()
ethereum.StateDb().Flush()
ethereum.ExtraDb().Flush()
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()
start := time.Now()
err = utils.ExportChain(chainmgr, ctx.Args().First())
if err != nil {
utils.Fatalf("Export error: %v\n", err)
}
fmt.Printf("Export done in %v", time.Since(start))
return
}
func removeDb(ctx *cli.Context) {
confirm, err := utils.PromptConfirm("Remove local databases?")
if err != nil {
utils.Fatalf("%v", err)
}
if confirm {
fmt.Println("Removing chain and state databases...")
start := time.Now()
os.RemoveAll(filepath.Join(ctx.GlobalString(utils.DataDirFlag.Name), "blockchain"))
os.RemoveAll(filepath.Join(ctx.GlobalString(utils.DataDirFlag.Name), "state"))
fmt.Printf("Removed in %v\n", time.Since(start))
} else {
fmt.Println("Operation aborted")
}
}
func upgradeDb(ctx *cli.Context) {
fmt.Println("Upgrade blockchain DB")
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"))
bcVersion := int(common.NewValue(v).Uint())
if bcVersion == 0 {
bcVersion = core.BlockChainVersion
}
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 {
utils.Fatalf("Unable to export chain for reimport %s\n", err)
}
ethereum.BlockDb().Close()
ethereum.StateDb().Close()
ethereum.ExtraDb().Close()
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)
if err != nil {
utils.Fatalf("Import error %v (a backup is made in %s, use the import command to import it)\n", err, exportFile)
}
// 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)
for _, arg := range ctx.Args() {
var block *types.Block
if hashish(arg) {
block = chainmgr.GetBlock(common.HexToHash(arg))
} else {
num, _ := strconv.Atoi(arg)
block = chainmgr.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())
}
}
}
func makedag(ctx *cli.Context) { func makedag(ctx *cli.Context) {
args := ctx.Args() args := ctx.Args()
wrongArgs := func() { wrongArgs := func() {
@ -701,9 +521,3 @@ func version(c *cli.Context) {
fmt.Printf("GOPATH=%s\n", os.Getenv("GOPATH")) fmt.Printf("GOPATH=%s\n", os.Getenv("GOPATH"))
fmt.Printf("GOROOT=%s\n", runtime.GOROOT()) fmt.Printf("GOROOT=%s\n", runtime.GOROOT())
} }
// hashish returns true for strings that look like hashes.
func hashish(x string) bool {
_, err := strconv.Atoi(x)
return err != nil
}

View File

@ -86,6 +86,10 @@ func init() {
utils.BlockchainVersionFlag, utils.BlockchainVersionFlag,
utils.NetworkIdFlag, utils.NetworkIdFlag,
} }
app.Before = func(ctx *cli.Context) error {
utils.SetupLogger(ctx)
return nil
}
} }
func main() { func main() {

View File

@ -40,6 +40,10 @@ import (
"github.com/peterh/liner" "github.com/peterh/liner"
) )
const (
importBatchSize = 2500
)
var interruptCallbacks = []func(os.Signal){} var interruptCallbacks = []func(os.Signal){}
// Register interrupt handlers callbacks // Register interrupt handlers callbacks
@ -125,10 +129,17 @@ func initDataDir(Datadir string) {
} }
} }
// Fatalf formats a message to standard output and exits the program. // Fatalf formats a message to standard error and exits the program.
// The message is also printed to standard output if standard error
// is redirected to a different file.
func Fatalf(format string, args ...interface{}) { func Fatalf(format string, args ...interface{}) {
fmt.Fprintf(os.Stderr, "Fatal: "+format+"\n", args...) w := io.MultiWriter(os.Stdout, os.Stderr)
fmt.Fprintf(os.Stdout, "Fatal: "+format+"\n", args...) outf, _ := os.Stdout.Stat()
errf, _ := os.Stderr.Stat()
if outf != nil && errf != nil && os.SameFile(outf, errf) {
w = os.Stderr
}
fmt.Fprintf(w, "Fatal: "+format+"\n", args...)
logger.Flush() logger.Flush()
os.Exit(1) os.Exit(1)
} }
@ -166,53 +177,86 @@ func FormatTransactionData(data string) []byte {
return d return d
} }
func ImportChain(chainmgr *core.ChainManager, fn string) error { func ImportChain(chain *core.ChainManager, fn string) error {
fmt.Printf("importing blockchain '%s'\n", fn) // Watch for Ctrl-C while the import is running.
fh, err := os.OpenFile(fn, os.O_RDONLY, os.ModePerm) // If a signal is received, the import will stop at the next batch.
interrupt := make(chan os.Signal, 1)
stop := make(chan struct{})
signal.Notify(interrupt, os.Interrupt)
defer signal.Stop(interrupt)
defer close(interrupt)
go func() {
if _, ok := <-interrupt; ok {
glog.Info("caught interrupt during import, will stop at next batch")
}
close(stop)
}()
checkInterrupt := func() bool {
select {
case <-stop:
return true
default:
return false
}
}
glog.Infoln("Importing blockchain", fn)
fh, err := os.Open(fn)
if err != nil { if err != nil {
return err return err
} }
defer fh.Close() defer fh.Close()
chainmgr.Reset()
stream := rlp.NewStream(fh, 0) stream := rlp.NewStream(fh, 0)
var i, n int
batchSize := 2500 // Run actual the import.
blocks := make(types.Blocks, batchSize) blocks := make(types.Blocks, importBatchSize)
n := 0
for ; ; i++ { for batch := 0; ; batch++ {
// Load a batch of RLP blocks.
if checkInterrupt() {
return fmt.Errorf("interrupted")
}
i := 0
for ; i < importBatchSize; i++ {
var b types.Block var b types.Block
if err := stream.Decode(&b); err == io.EOF { if err := stream.Decode(&b); err == io.EOF {
break break
} else if err != nil { } else if err != nil {
return fmt.Errorf("at block %d: %v", i, err) return fmt.Errorf("at block %d: %v", n, err)
} }
blocks[i] = &b
blocks[n] = &b
n++ n++
if n == batchSize {
if _, err := chainmgr.InsertChain(blocks); err != nil {
return fmt.Errorf("invalid block %v", err)
} }
n = 0 if i == 0 {
blocks = make(types.Blocks, batchSize) break
}
// Import the batch.
if checkInterrupt() {
return fmt.Errorf("interrupted")
}
if hasAllBlocks(chain, blocks[:i]) {
glog.Infof("skipping batch %d, all blocks present [%x / %x]",
batch, blocks[0].Hash().Bytes()[:4], blocks[i-1].Hash().Bytes()[:4])
continue
}
if _, err := chain.InsertChain(blocks[:i]); err != nil {
return fmt.Errorf("invalid block %d: %v", n, err)
} }
} }
if n > 0 {
if _, err := chainmgr.InsertChain(blocks[:n]); err != nil {
return fmt.Errorf("invalid block %v", err)
}
}
fmt.Printf("imported %d blocks\n", i)
return nil return nil
} }
func hasAllBlocks(chain *core.ChainManager, bs []*types.Block) bool {
for _, b := range bs {
if !chain.HasBlock(b.Hash()) {
return false
}
}
return true
}
func ExportChain(chainmgr *core.ChainManager, fn string) error { 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) fh, err := os.OpenFile(fn, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
if err != nil { if err != nil {
return err return err
@ -221,6 +265,6 @@ func ExportChain(chainmgr *core.ChainManager, fn string) error {
if err := chainmgr.Export(fh); err != nil { if err := chainmgr.Export(fh); err != nil {
return err return err
} }
fmt.Printf("exported blockchain\n") glog.Infoln("Exported blockchain to", fn)
return nil return nil
} }

View File

@ -256,7 +256,8 @@ var (
} }
) )
func GetNAT(ctx *cli.Context) nat.Interface { // MakeNAT creates a port mapper from set command line flags.
func MakeNAT(ctx *cli.Context) nat.Interface {
natif, err := nat.Parse(ctx.GlobalString(NATFlag.Name)) natif, err := nat.Parse(ctx.GlobalString(NATFlag.Name))
if err != nil { if err != nil {
Fatalf("Option %s: %v", NATFlag.Name, err) Fatalf("Option %s: %v", NATFlag.Name, err)
@ -264,7 +265,8 @@ func GetNAT(ctx *cli.Context) nat.Interface {
return natif return natif
} }
func GetNodeKey(ctx *cli.Context) (key *ecdsa.PrivateKey) { // MakeNodeKey creates a node key from set command line flags.
func MakeNodeKey(ctx *cli.Context) (key *ecdsa.PrivateKey) {
hex, file := ctx.GlobalString(NodeKeyHexFlag.Name), ctx.GlobalString(NodeKeyFileFlag.Name) hex, file := ctx.GlobalString(NodeKeyHexFlag.Name), ctx.GlobalString(NodeKeyFileFlag.Name)
var err error var err error
switch { switch {
@ -282,21 +284,12 @@ func GetNodeKey(ctx *cli.Context) (key *ecdsa.PrivateKey) {
return key return key
} }
// MakeEthConfig creates ethereum options from set command line flags.
func MakeEthConfig(clientID, version string, ctx *cli.Context) *eth.Config { 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) customName := ctx.GlobalString(IdentityFlag.Name)
if len(customName) > 0 { if len(customName) > 0 {
clientID += "/" + customName clientID += "/" + customName
} }
return &eth.Config{ return &eth.Config{
Name: common.MakeName(clientID, version), Name: common.MakeName(clientID, version),
DataDir: ctx.GlobalString(DataDirFlag.Name), DataDir: ctx.GlobalString(DataDirFlag.Name),
@ -309,15 +302,15 @@ func MakeEthConfig(clientID, version string, ctx *cli.Context) *eth.Config {
LogJSON: ctx.GlobalString(LogJSONFlag.Name), LogJSON: ctx.GlobalString(LogJSONFlag.Name),
Etherbase: ctx.GlobalString(EtherbaseFlag.Name), Etherbase: ctx.GlobalString(EtherbaseFlag.Name),
MinerThreads: ctx.GlobalInt(MinerThreadsFlag.Name), MinerThreads: ctx.GlobalInt(MinerThreadsFlag.Name),
AccountManager: GetAccountManager(ctx), AccountManager: MakeAccountManager(ctx),
VmDebug: ctx.GlobalBool(VMDebugFlag.Name), VmDebug: ctx.GlobalBool(VMDebugFlag.Name),
MaxPeers: ctx.GlobalInt(MaxPeersFlag.Name), MaxPeers: ctx.GlobalInt(MaxPeersFlag.Name),
MaxPendingPeers: ctx.GlobalInt(MaxPendingPeersFlag.Name), MaxPendingPeers: ctx.GlobalInt(MaxPendingPeersFlag.Name),
Port: ctx.GlobalString(ListenPortFlag.Name), Port: ctx.GlobalString(ListenPortFlag.Name),
NAT: GetNAT(ctx), NAT: MakeNAT(ctx),
NatSpec: ctx.GlobalBool(NatspecEnabledFlag.Name), NatSpec: ctx.GlobalBool(NatspecEnabledFlag.Name),
Discovery: !ctx.GlobalBool(NoDiscoverFlag.Name), Discovery: !ctx.GlobalBool(NoDiscoverFlag.Name),
NodeKey: GetNodeKey(ctx), NodeKey: MakeNodeKey(ctx),
Shh: ctx.GlobalBool(WhisperEnabledFlag.Name), Shh: ctx.GlobalBool(WhisperEnabledFlag.Name),
Dial: true, Dial: true,
BootNodes: ctx.GlobalString(BootnodesFlag.Name), BootNodes: ctx.GlobalString(BootnodesFlag.Name),
@ -327,35 +320,39 @@ func MakeEthConfig(clientID, version string, ctx *cli.Context) *eth.Config {
} }
} }
func GetChain(ctx *cli.Context) (*core.ChainManager, common.Database, common.Database) { // SetupLogger configures glog from the logging-related command line flags.
dataDir := ctx.GlobalString(DataDirFlag.Name) func SetupLogger(ctx *cli.Context) {
glog.SetV(ctx.GlobalInt(VerbosityFlag.Name))
blockDb, err := ethdb.NewLDBDatabase(filepath.Join(dataDir, "blockchain")) glog.CopyStandardLogTo("INFO")
if err != nil { glog.SetToStderr(true)
Fatalf("Could not open database: %v", err) glog.SetLogDir(ctx.GlobalString(LogFileFlag.Name))
} }
stateDb, err := ethdb.NewLDBDatabase(filepath.Join(dataDir, "state")) // MakeChain creates a chain manager from set command line flags.
if err != nil { func MakeChain(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) Fatalf("Could not open database: %v", err)
} }
if stateDB, err = ethdb.NewLDBDatabase(filepath.Join(dd, "state")); err != nil {
extraDb, err := ethdb.NewLDBDatabase(filepath.Join(dataDir, "extra")) Fatalf("Could not open database: %v", err)
if err != nil { }
if extraDB, err = ethdb.NewLDBDatabase(filepath.Join(dd, "extra")); err != nil {
Fatalf("Could not open database: %v", err) Fatalf("Could not open database: %v", err)
} }
eventMux := new(event.TypeMux) eventMux := new(event.TypeMux)
pow := ethash.New() pow := ethash.New()
chainManager := core.NewChainManager(blockDb, stateDb, pow, eventMux) chain = core.NewChainManager(blockDB, stateDB, pow, eventMux)
txPool := core.NewTxPool(eventMux, chainManager.State, chainManager.GasLimit) txpool := core.NewTxPool(eventMux, chain.State, chain.GasLimit)
blockProcessor := core.NewBlockProcessor(stateDb, extraDb, pow, txPool, chainManager, eventMux) proc := core.NewBlockProcessor(stateDB, extraDB, pow, txpool, chain, eventMux)
chainManager.SetProcessor(blockProcessor) chain.SetProcessor(proc)
return chain, blockDB, stateDB, extraDB
return chainManager, blockDb, stateDb
} }
func GetAccountManager(ctx *cli.Context) *accounts.Manager { // MakeChain creates an account manager from set command line flags.
func MakeAccountManager(ctx *cli.Context) *accounts.Manager {
dataDir := ctx.GlobalString(DataDirFlag.Name) dataDir := ctx.GlobalString(DataDirFlag.Name)
ks := crypto.NewKeyStorePassphrase(filepath.Join(dataDir, "keystore")) ks := crypto.NewKeyStorePassphrase(filepath.Join(dataDir, "keystore"))
return accounts.NewManager(ks) return accounts.NewManager(ks)

View File

@ -30,7 +30,7 @@ func TestAutoDiscRace(t *testing.T) {
} }
// Check that they all return the correct result within the deadline. // Check that they all return the correct result within the deadline.
deadline := time.After(550 * time.Millisecond) deadline := time.After(2 * time.Second)
for i := 0; i < cap(results); i++ { for i := 0; i < cap(results); i++ {
select { select {
case <-deadline: case <-deadline: