diff options
Diffstat (limited to 'cmd/geth')
-rw-r--r-- | cmd/geth/admin.go | 45 | ||||
-rw-r--r-- | cmd/geth/block_go_test.go | 80 | ||||
-rw-r--r-- | cmd/geth/blocktest.go | 8 | ||||
-rw-r--r-- | cmd/geth/js.go | 18 | ||||
-rw-r--r-- | cmd/geth/js_test.go | 255 | ||||
-rw-r--r-- | cmd/geth/main.go | 35 |
6 files changed, 118 insertions, 323 deletions
diff --git a/cmd/geth/admin.go b/cmd/geth/admin.go index bd09291bf..31f8d4400 100644 --- a/cmd/geth/admin.go +++ b/cmd/geth/admin.go @@ -3,7 +3,6 @@ package main import ( "errors" "fmt" - "os" "time" "github.com/ethereum/go-ethereum/cmd/utils" @@ -36,7 +35,6 @@ func (js *jsre) adminBindings() { admin.Set("import", js.importChain) admin.Set("export", js.exportChain) admin.Set("verbosity", js.verbosity) - admin.Set("backtrace", js.backtrace) admin.Set("progress", js.downloadProgress) admin.Set("miner", struct{}{}) @@ -50,11 +48,12 @@ func (js *jsre) adminBindings() { admin.Set("debug", struct{}{}) t, _ = admin.Get("debug") debug := t.Object() + debug.Set("backtrace", js.backtrace) debug.Set("printBlock", js.printBlock) debug.Set("dumpBlock", js.dumpBlock) debug.Set("getBlockRlp", js.getBlockRlp) debug.Set("setHead", js.setHead) - debug.Set("block", js.debugBlock) + debug.Set("processBlock", js.debugBlock) } func (js *jsre) getBlock(call otto.FunctionCall) (*types.Block, error) { @@ -204,16 +203,26 @@ func (js *jsre) startRPC(call otto.FunctionCall) otto.Value { fmt.Println(err) return otto.FalseValue() } + port, err := call.Argument(1).ToInteger() if err != nil { fmt.Println(err) return otto.FalseValue() } + corsDomain := js.corsDomain + if len(call.ArgumentList) > 2 { + corsDomain, err = call.Argument(2).ToString() + if err != nil { + fmt.Println(err) + return otto.FalseValue() + } + } + config := rpc.RpcConfig{ ListenAddress: addr, ListenPort: uint(port), - // CorsDomain: ctx.GlobalString(RPCCORSDomainFlag.Name), + CorsDomain: corsDomain, } xeth := xeth.New(js.ethereum, nil) @@ -275,10 +284,6 @@ func (js *jsre) unlock(call otto.FunctionCall) otto.Value { } } am := js.ethereum.AccountManager() - // err := am.Unlock(common.FromHex(split[0]), split[1]) - // if err != nil { - // utils.Fatalf("Unlock account failed '%v'", err) - // } err = am.TimedUnlock(common.FromHex(addr), passphrase, time.Duration(seconds)*time.Second) if err != nil { fmt.Printf("Unlock account failed '%v'\n", err) @@ -318,7 +323,7 @@ func (js *jsre) newAccount(call otto.FunctionCall) otto.Value { fmt.Printf("Could not create the account: %v", err) return otto.UndefinedValue() } - return js.re.ToVal(common.Bytes2Hex(acct.Address)) + return js.re.ToVal("0x" + common.Bytes2Hex(acct.Address)) } func (js *jsre) nodeInfo(call otto.FunctionCall) otto.Value { @@ -334,33 +339,15 @@ func (js *jsre) importChain(call otto.FunctionCall) otto.Value { fmt.Println("err: require file name") return otto.FalseValue() } - fn, err := call.Argument(0).ToString() if err != nil { fmt.Println(err) return otto.FalseValue() } - - var fh *os.File - fh, err = os.OpenFile(fn, os.O_RDONLY, os.ModePerm) - if err != nil { - fmt.Println(err) - return otto.FalseValue() - } - defer fh.Close() - - var blocks types.Blocks - if err = rlp.Decode(fh, &blocks); err != nil { - fmt.Println(err) - return otto.FalseValue() - } - - js.ethereum.ChainManager().Reset() - if err = js.ethereum.ChainManager().InsertChain(blocks); err != nil { - fmt.Println(err) + if err := utils.ImportChain(js.ethereum.ChainManager(), fn); err != nil { + fmt.Println("Import error: ", err) return otto.FalseValue() } - return otto.TrueValue() } diff --git a/cmd/geth/block_go_test.go b/cmd/geth/block_go_test.go deleted file mode 100644 index 1980e4798..000000000 --- a/cmd/geth/block_go_test.go +++ /dev/null @@ -1,80 +0,0 @@ -package main - -import ( - "path" - "testing" - - "github.com/ethereum/go-ethereum/accounts" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/eth" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/tests" -) - -// TODO: refactor test setup & execution to better align with vm and tx tests -// TODO: refactor to avoid duplication with cmd/geth/blocktest.go -func TestBcValidBlockTests(t *testing.T) { - runBlockTestsInFile("../../tests/files/BlockTests/bcValidBlockTest.json", t) -} - -/* -func TestBcUncleTests(t *testing.T) { - runBlockTestsInFile("../../tests/files/BlockTests/bcUncleTest.json", t) -} -*/ - -func runBlockTestsInFile(filepath string, t *testing.T) { - bt, err := tests.LoadBlockTests(filepath) - if err != nil { - t.Fatal(err) - } - for name, test := range bt { - runTest(name, test, t) - } -} - -func runTest(name string, test *tests.BlockTest, t *testing.T) { - t.Log("Running test: ", name) - cfg := testEthConfig() - ethereum, err := eth.New(cfg) - if err != nil { - t.Fatalf("%v", err) - } - - err = ethereum.Start() - if err != nil { - t.Fatalf("%v", err) - } - - // import the genesis block - ethereum.ResetWithGenesisBlock(test.Genesis) - - // import pre accounts - statedb, err := test.InsertPreState(ethereum.StateDb()) - if err != nil { - t.Fatalf("InsertPreState: %v", err) - } - - // insert the test blocks, which will execute all transactions - if err := test.InsertBlocks(ethereum.ChainManager()); err != nil { - t.Fatalf("Block Test load error: %v %T", err, err) - } - - if err := test.ValidatePostState(statedb); err != nil { - t.Fatal("post state validation failed: %v", err) - } - t.Log("Test passed: ", name) -} - -func testEthConfig() *eth.Config { - ks := crypto.NewKeyStorePassphrase(path.Join(common.DefaultDataDir(), "keys")) - - return ð.Config{ - DataDir: common.DefaultDataDir(), - LogLevel: 5, - Etherbase: "primary", - AccountManager: accounts.NewManager(ks), - NewDB: func(path string) (common.Database, error) { return ethdb.NewMemDatabase() }, - } -} diff --git a/cmd/geth/blocktest.go b/cmd/geth/blocktest.go index 792981ec0..5c80ad07e 100644 --- a/cmd/geth/blocktest.go +++ b/cmd/geth/blocktest.go @@ -104,15 +104,15 @@ func runOneBlockTest(ctx *cli.Context, test *tests.BlockTest) (*eth.Ethereum, er ethereum.ResetWithGenesisBlock(test.Genesis) // import pre accounts - statedb, err := test.InsertPreState(ethereum.StateDb()) + statedb, err := test.InsertPreState(ethereum) if err != nil { return ethereum, fmt.Errorf("InsertPreState: %v", err) } - // insert the test blocks, which will execute all transactions - if err := test.InsertBlocks(ethereum.ChainManager()); err != nil { - return ethereum, fmt.Errorf("Block Test load error: %v %T", err, err) + if err := test.TryBlocksInsert(ethereum.ChainManager()); err != nil { + return ethereum, fmt.Errorf("Block Test load error: %v", err) } + fmt.Println("chain loaded") if err := test.ValidatePostState(statedb); err != nil { return ethereum, fmt.Errorf("post state validation failed: %v", err) diff --git a/cmd/geth/js.go b/cmd/geth/js.go index 6e5a6f1c7..a545de1d0 100644 --- a/cmd/geth/js.go +++ b/cmd/geth/js.go @@ -59,17 +59,19 @@ func (r dumbterm) PasswordPrompt(p string) (string, error) { func (r dumbterm) AppendHistory(string) {} type jsre struct { - re *re.JSRE - ethereum *eth.Ethereum - xeth *xeth.XEth - ps1 string - atexit func() - + re *re.JSRE + ethereum *eth.Ethereum + xeth *xeth.XEth + ps1 string + atexit func() + corsDomain string prompter } -func newJSRE(ethereum *eth.Ethereum, libPath string, interactive bool) *jsre { +func newJSRE(ethereum *eth.Ethereum, libPath string, interactive bool, corsDomain string) *jsre { js := &jsre{ethereum: ethereum, ps1: "> "} + // set default cors domain used by startRpc from CLI flag + js.corsDomain = corsDomain js.xeth = xeth.New(ethereum, js) js.re = re.New(libPath) js.apiBindings() @@ -118,7 +120,7 @@ func (js *jsre) apiBindings() { utils.Fatalf("Error loading ethereum.js: %v", err) } - _, err = js.re.Eval("var web3 = require('ethereum.js');") + _, err = js.re.Eval("var web3 = require('web3');") if err != nil { utils.Fatalf("Error requiring web3: %v", err) } diff --git a/cmd/geth/js_test.go b/cmd/geth/js_test.go index 4421b1d68..50528b80a 100644 --- a/cmd/geth/js_test.go +++ b/cmd/geth/js_test.go @@ -5,258 +5,139 @@ import ( "io/ioutil" "os" "path" + "path/filepath" "testing" - "github.com/robertkrimen/otto" - "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth" + "regexp" + "runtime" + "strconv" ) var port = 30300 -func testJEthRE(t *testing.T) (repl *jsre, ethereum *eth.Ethereum, err error) { - os.RemoveAll("/tmp/eth/") - err = os.MkdirAll("/tmp/eth/keys/e273f01c99144c438695e10f24926dc1f9fbf62d/", os.ModePerm) - if err != nil { - t.Errorf("%v", err) - return - } - err = os.MkdirAll("/tmp/eth/data", os.ModePerm) +func testJEthRE(t *testing.T) (*jsre, *eth.Ethereum) { + tmp, err := ioutil.TempDir("", "geth-test") if err != nil { - t.Errorf("%v", err) - return + t.Fatal(err) } - // FIXME: this does not work ATM - ks := crypto.NewKeyStorePlain("/tmp/eth/keys") - ioutil.WriteFile("/tmp/eth/keys/e273f01c99144c438695e10f24926dc1f9fbf62d/e273f01c99144c438695e10f24926dc1f9fbf62d", - []byte(`{"Id":"RhRXD+fNRKS4jx+7ZfEsNA==","Address":"4nPwHJkUTEOGleEPJJJtwfn79i0=","PrivateKey":"h4ACVpe74uIvi5Cg/2tX/Yrm2xdr3J7QoMbMtNX2CNc="}`), os.ModePerm) + defer os.RemoveAll(tmp) - port++ - ethereum, err = eth.New(ð.Config{ - DataDir: "/tmp/eth", + ks := crypto.NewKeyStorePlain(filepath.Join(tmp, "keys")) + ethereum, err := eth.New(ð.Config{ + DataDir: tmp, AccountManager: accounts.NewManager(ks), - Port: fmt.Sprintf("%d", port), - MaxPeers: 10, + MaxPeers: 0, Name: "test", }) - if err != nil { - t.Errorf("%v", err) - return + t.Fatal("%v", err) } assetPath := path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "cmd", "mist", "assets", "ext") - repl = newJSRE(ethereum, assetPath, false) - return + repl := newJSRE(ethereum, assetPath, false, "") + return repl, ethereum } func TestNodeInfo(t *testing.T) { - repl, ethereum, err := testJEthRE(t) - if err != nil { - t.Errorf("error creating jsre, got %v", err) - return - } - err = ethereum.Start() - if err != nil { - t.Errorf("error starting ethereum: %v", err) - return + repl, ethereum := testJEthRE(t) + if err := ethereum.Start(); err != nil { + t.Fatalf("error starting ethereum: %v", err) } defer ethereum.Stop() - val, err := repl.re.Run("admin.nodeInfo()") - if err != nil { - t.Errorf("expected no error, got %v", err) - } - exp, err := val.Export() - if err != nil { - t.Errorf("expected no error, got %v", err) - } - nodeInfo, ok := exp.(*eth.NodeInfo) - if !ok { - t.Errorf("expected nodeInfo, got %v", err) - } - exp = "test" - got := nodeInfo.Name - if exp != got { - t.Errorf("expected %v, got %v", exp, got) - } - exp = 30301 - port := nodeInfo.DiscPort - if exp != port { - t.Errorf("expected %v, got %v", exp, port) - } - exp = 30301 - port = nodeInfo.TCPPort - if exp != port { - t.Errorf("expected %v, got %v", exp, port) - } + want := `{"DiscPort":0,"IP":"0.0.0.0","ListenAddr":"","Name":"test","NodeID":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","NodeUrl":"enode://00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000@0.0.0.0:0","TCPPort":0,"Td":"0"}` + checkEvalJSON(t, repl, `admin.nodeInfo()`, want) } func TestAccounts(t *testing.T) { - repl, ethereum, err := testJEthRE(t) - if err != nil { - t.Errorf("error creating jsre, got %v", err) - return - } - err = ethereum.Start() - if err != nil { - t.Errorf("error starting ethereum: %v", err) - return + repl, ethereum := testJEthRE(t) + if err := ethereum.Start(); err != nil { + t.Fatalf("error starting ethereum: %v", err) } defer ethereum.Stop() - val, err := repl.re.Run("eth.coinbase") - if err != nil { - t.Errorf("expected no error, got %v", err) - } - - pp, err := repl.re.PrettyPrint(val) - if err != nil { - t.Errorf("%v", err) - } - - if !val.IsString() { - t.Errorf("incorrect type, expected string, got %v: %v", val, pp) - } - strVal, _ := val.ToString() - expected := "0xe273f01c99144c438695e10f24926dc1f9fbf62d" - if strVal != expected { - t.Errorf("incorrect result, expected %s, got %v", expected, strVal) - } + checkEvalJSON(t, repl, `eth.accounts`, `[]`) + checkEvalJSON(t, repl, `eth.coinbase`, `"0x"`) - val, err = repl.re.Run(`admin.newAccount("password")`) + val, err := repl.re.Run(`admin.newAccount("password")`) if err != nil { t.Errorf("expected no error, got %v", err) } - addr, err := val.ToString() - if err != nil { - t.Errorf("expected string, got %v", err) - } - - val, err = repl.re.Run("eth.accounts") - if err != nil { - t.Errorf("expected no error, got %v", err) - } - exp, err := val.Export() - if err != nil { - t.Errorf("expected no error, got %v", err) - } - interfaceAddr, ok := exp.([]interface{}) - if !ok { - t.Errorf("expected []string, got %T", exp) - } - - addrs := make([]string, len(interfaceAddr)) - for i, addr := range interfaceAddr { - var ok bool - if addrs[i], ok = addr.(string); !ok { - t.Errorf("expected addrs[%d] to be string. Got %T instead", i, addr) - } - } - - if len(addrs) != 2 || (addr != addrs[0][2:] && addr != addrs[1][2:]) { - t.Errorf("expected addrs == [<default>, <new>], got %v (%v)", addrs, addr) + addr := val.String() + if !regexp.MustCompile(`0x[0-9a-f]{40}`).MatchString(addr) { + t.Errorf("address not hex: %q", addr) } + checkEvalJSON(t, repl, `eth.accounts`, `["`+addr+`"]`) + checkEvalJSON(t, repl, `eth.coinbase`, `"`+addr+`"`) } func TestBlockChain(t *testing.T) { - repl, ethereum, err := testJEthRE(t) - if err != nil { - t.Errorf("error creating jsre, got %v", err) - return - } - err = ethereum.Start() - if err != nil { - t.Errorf("error starting ethereum: %v", err) - return + repl, ethereum := testJEthRE(t) + if err := ethereum.Start(); err != nil { + t.Fatalf("error starting ethereum: %v", err) } defer ethereum.Stop() - // should get current block - val0, err := repl.re.Run("admin.debug.dumpBlock()") + // get current block dump before export/import. + val, err := repl.re.Run("JSON.stringify(admin.debug.dumpBlock())") if err != nil { t.Errorf("expected no error, got %v", err) } + beforeExport := val.String() - fn := "/tmp/eth/data/blockchain.0" - _, err = repl.re.Run("admin.export(\"" + fn + "\")") + // do the export + tmp, err := ioutil.TempDir("", "geth-test-export") if err != nil { - t.Errorf("expected no error, got %v", err) - } - if _, err = os.Stat(fn); err != nil { - t.Errorf("expected no error on file, got %v", err) + t.Fatal(err) } + defer os.RemoveAll(tmp) + tmpfile := filepath.Join(tmp, "export.chain") + tmpfileq := strconv.Quote(tmpfile) - _, err = repl.re.Run("admin.import(\"" + fn + "\")") - if err != nil { - t.Errorf("expected no error, got %v", err) + checkEvalJSON(t, repl, `admin.export(`+tmpfileq+`)`, `true`) + if _, err := os.Stat(tmpfile); err != nil { + t.Fatal(err) } - var val1 otto.Value - - // should get current block - val1, err = repl.re.Run("admin.debug.dumpBlock()") - if err != nil { - t.Errorf("expected no error, got %v", err) - } - - // FIXME: neither != , nor reflect.DeepEqual works, doing string comparison - v0 := fmt.Sprintf("%v", val0) - v1 := fmt.Sprintf("%v", val1) - if v0 != v1 { - t.Errorf("expected same head after export-import, got %v (!=%v)", v1, v0) - } + // check import, verify that dumpBlock gives the same result. + checkEvalJSON(t, repl, `admin.import(`+tmpfileq+`)`, `true`) + checkEvalJSON(t, repl, `admin.debug.dumpBlock()`, beforeExport) } func TestMining(t *testing.T) { - repl, ethereum, err := testJEthRE(t) - if err != nil { - t.Errorf("error creating jsre, got %v", err) - return - } - err = ethereum.Start() - if err != nil { - t.Errorf("error starting ethereum: %v", err) - return + repl, ethereum := testJEthRE(t) + if err := ethereum.Start(); err != nil { + t.Fatalf("error starting ethereum: %v", err) } defer ethereum.Stop() - val, err := repl.re.Run("eth.mining") - if err != nil { - t.Errorf("expected no error, got %v", err) - } - var mining bool - mining, err = val.ToBoolean() - if err != nil { - t.Errorf("expected boolean, got %v", err) - } - if mining { - t.Errorf("expected false (not mining), got true") - } - + checkEvalJSON(t, repl, `eth.mining`, `false`) } func TestRPC(t *testing.T) { - repl, ethereum, err := testJEthRE(t) - if err != nil { - t.Errorf("error creating jsre, got %v", err) - return - } - err = ethereum.Start() - if err != nil { + repl, ethereum := testJEthRE(t) + if err := ethereum.Start(); err != nil { t.Errorf("error starting ethereum: %v", err) return } defer ethereum.Stop() - val, err := repl.re.Run(`admin.startRPC("127.0.0.1", 5004)`) - if err != nil { - t.Errorf("expected no error, got %v", err) + checkEvalJSON(t, repl, `admin.startRPC("127.0.0.1", 5004)`, `true`) +} + +func checkEvalJSON(t *testing.T, re *jsre, expr, want string) error { + val, err := re.re.Run("JSON.stringify(" + expr + ")") + if err == nil && val.String() != want { + err = fmt.Errorf("Output mismatch for `%s`:\ngot: %s\nwant: %s", expr, val.String(), want) } - success, _ := val.ToBoolean() - if !success { - t.Errorf("expected true (started), got false") + if err != nil { + _, file, line, _ := runtime.Caller(1) + file = path.Base(file) + fmt.Printf("\t%s:%d: %v\n", file, line, err) + t.Fail() } + return err } diff --git a/cmd/geth/main.go b/cmd/geth/main.go index ddbd1f129..6ffc3c4a0 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -47,7 +47,7 @@ import _ "net/http/pprof" const ( ClientIdentifier = "Geth" - Version = "0.9.11" + Version = "0.9.12" ) var app = utils.NewApp(Version, "the go-ethereum command line interface") @@ -97,6 +97,8 @@ The output of this command is supposed to be machine-readable. Manage accounts lets you create new accounts, list all existing accounts, import a private key into a new account. +'account help' shows a list of subcommands or help for one subcommand. + It supports interactive mode, when you are prompted for password as well as non-interactive mode where passwords are supplied via a given password file. Non-interactive mode is only meant for scripted use on test networks or known @@ -186,8 +188,8 @@ Use "ethereum dump 0" to dump the genesis block. Usage: `Geth Console: interactive JavaScript environment`, Description: ` The Geth console is an interactive shell for the JavaScript runtime environment -which exposes a node admin interface as well as the DAPP JavaScript API. -See https://github.com/ethereum/go-ethereum/wiki/Frontier-Console +which exposes a node admin interface as well as the Γapp JavaScript API. +See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Console `, }, { @@ -195,7 +197,7 @@ See https://github.com/ethereum/go-ethereum/wiki/Frontier-Console Name: "js", Usage: `executes the given JavaScript files in the Geth JavaScript VM`, Description: ` -The JavaScript VM exposes a node admin interface as well as the DAPP +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 `, }, @@ -261,14 +263,11 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Conso // 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") - // potential subcommands: - // flag.StringVar(&SecretFile, "import", "", "imports the file given (hex or mnemonic formats)") - // flag.StringVar(&ExportDir, "export", "", "exports the session keyring to files in the directory given") - // flag.BoolVar(&GenAddr, "genaddr", false, "create a new priv/pub key") } func main() { - fmt.Printf("Welcome to the FRONTIER\n") + //fmt.Printf("\n π\n\n α΄‘α΄Κα΄α΄α΄α΄ α΄α΄ α΄Κα΄\n π
π π π π π π π\n\nπΎ π΅πΎπΎ π πΎ π΅ πΎ\n\n") + fmt.Println("\n Welcome to the\n FRONTIER\n") runtime.GOMAXPROCS(runtime.NumCPU()) defer logger.Flush() if err := app.Run(os.Args); err != nil { @@ -298,7 +297,7 @@ func console(ctx *cli.Context) { } startEth(ctx, ethereum) - repl := newJSRE(ethereum, ctx.String(utils.JSpathFlag.Name), true) + repl := newJSRE(ethereum, ctx.String(utils.JSpathFlag.Name), true, ctx.GlobalString(utils.RPCCORSDomainFlag.Name)) repl.interactive() ethereum.Stop() @@ -313,7 +312,7 @@ func execJSFiles(ctx *cli.Context) { } startEth(ctx, ethereum) - repl := newJSRE(ethereum, ctx.String(utils.JSpathFlag.Name), false) + repl := newJSRE(ethereum, ctx.String(utils.JSpathFlag.Name), false, ctx.GlobalString(utils.RPCCORSDomainFlag.Name)) for _, file := range ctx.Args() { repl.exec(file) } @@ -356,10 +355,14 @@ func startEth(ctx *cli.Context, eth *eth.Ethereum) { } // Start auxiliary services if enabled. if ctx.GlobalBool(utils.RPCEnabledFlag.Name) { - utils.StartRPC(eth, ctx) + if err := utils.StartRPC(eth, ctx); err != nil { + utils.Fatalf("Error starting RPC: %v", err) + } } if ctx.GlobalBool(utils.MiningEnabledFlag.Name) { - eth.StartMining() + if err := eth.StartMining(); err != nil { + utils.Fatalf("%v", err) + } } } @@ -369,8 +372,10 @@ func accountList(ctx *cli.Context) { if err != nil { utils.Fatalf("Could not list accounts: %v", err) } - for _, acct := range accts { - fmt.Printf("Address: %x\n", acct) + name := "Primary" + for i, acct := range accts { + fmt.Printf("%s #%d: %x\n", name, i, acct) + name = "Account" } } |