From b0b0939879b9fb8453ec1c8fa2ceb522e56df3bc Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 26 Mar 2015 21:27:52 +0100 Subject: renamed ethereum => geth --- cmd/ethereum/admin.go | 256 ----------------------- cmd/ethereum/blocktest.go | 80 ------- cmd/ethereum/js.go | 246 ---------------------- cmd/ethereum/js_test.go | 262 ----------------------- cmd/ethereum/main.go | 516 ---------------------------------------------- cmd/geth/admin.go | 256 +++++++++++++++++++++++ cmd/geth/blocktest.go | 80 +++++++ cmd/geth/js.go | 246 ++++++++++++++++++++++ cmd/geth/js_test.go | 262 +++++++++++++++++++++++ cmd/geth/main.go | 516 ++++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 1360 insertions(+), 1360 deletions(-) delete mode 100644 cmd/ethereum/admin.go delete mode 100644 cmd/ethereum/blocktest.go delete mode 100644 cmd/ethereum/js.go delete mode 100644 cmd/ethereum/js_test.go delete mode 100644 cmd/ethereum/main.go create mode 100644 cmd/geth/admin.go create mode 100644 cmd/geth/blocktest.go create mode 100644 cmd/geth/js.go create mode 100644 cmd/geth/js_test.go create mode 100644 cmd/geth/main.go (limited to 'cmd') diff --git a/cmd/ethereum/admin.go b/cmd/ethereum/admin.go deleted file mode 100644 index 139395dad..000000000 --- a/cmd/ethereum/admin.go +++ /dev/null @@ -1,256 +0,0 @@ -package main - -import ( - "fmt" - "net" - "net/http" - "os" - "time" - - "github.com/ethereum/go-ethereum/cmd/utils" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/rlp" - "github.com/ethereum/go-ethereum/rpc" - "github.com/ethereum/go-ethereum/core/state" - "github.com/ethereum/go-ethereum/xeth" - "github.com/robertkrimen/otto" -) - -/* -node admin bindings -*/ - -func (js *jsre) adminBindings() { - js.re.Set("admin", struct{}{}) - t, _ := js.re.Get("admin") - admin := t.Object() - admin.Set("suggestPeer", js.suggestPeer) - admin.Set("startRPC", js.startRPC) - admin.Set("startMining", js.startMining) - admin.Set("stopMining", js.stopMining) - admin.Set("nodeInfo", js.nodeInfo) - admin.Set("peers", js.peers) - admin.Set("newAccount", js.newAccount) - admin.Set("unlock", js.unlock) - admin.Set("import", js.importChain) - admin.Set("export", js.exportChain) - admin.Set("dumpBlock", js.dumpBlock) -} - -func (js *jsre) startMining(call otto.FunctionCall) otto.Value { - _, err := call.Argument(0).ToInteger() - if err != nil { - fmt.Println(err) - return otto.FalseValue() - } - // threads now ignored - err = js.ethereum.StartMining() - if err != nil { - fmt.Println(err) - return otto.FalseValue() - } - return otto.TrueValue() -} - -func (js *jsre) stopMining(call otto.FunctionCall) otto.Value { - js.ethereum.StopMining() - return otto.TrueValue() -} - -func (js *jsre) startRPC(call otto.FunctionCall) otto.Value { - addr, err := call.Argument(0).ToString() - if err != nil { - fmt.Println(err) - return otto.FalseValue() - } - port, err := call.Argument(1).ToInteger() - if err != nil { - fmt.Println(err) - return otto.FalseValue() - } - dataDir := js.ethereum.DataDir - - l, err := net.Listen("tcp", fmt.Sprintf("%s:%d", addr, port)) - if err != nil { - fmt.Printf("Can't listen on %s:%d: %v", addr, port, err) - return otto.FalseValue() - } - go http.Serve(l, rpc.JSONRPC(xeth.New(js.ethereum, nil), dataDir)) - return otto.TrueValue() -} - -func (js *jsre) suggestPeer(call otto.FunctionCall) otto.Value { - nodeURL, err := call.Argument(0).ToString() - if err != nil { - fmt.Println(err) - return otto.FalseValue() - } - err = js.ethereum.SuggestPeer(nodeURL) - if err != nil { - fmt.Println(err) - return otto.FalseValue() - } - return otto.TrueValue() -} - -func (js *jsre) unlock(call otto.FunctionCall) otto.Value { - addr, err := call.Argument(0).ToString() - if err != nil { - fmt.Println(err) - return otto.FalseValue() - } - seconds, err := call.Argument(2).ToInteger() - if err != nil { - fmt.Println(err) - return otto.FalseValue() - } - arg := call.Argument(1) - var passphrase string - if arg.IsUndefined() { - fmt.Println("Please enter a passphrase now.") - passphrase, err = readPassword("Passphrase: ", true) - if err != nil { - utils.Fatalf("%v", err) - } - } else { - passphrase, err = arg.ToString() - if err != nil { - fmt.Println(err) - return otto.FalseValue() - } - } - 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) - return otto.FalseValue() - } - return otto.TrueValue() -} - -func (js *jsre) newAccount(call otto.FunctionCall) otto.Value { - arg := call.Argument(0) - var passphrase string - if arg.IsUndefined() { - fmt.Println("The new account will be encrypted with a passphrase.") - fmt.Println("Please enter a passphrase now.") - auth, err := readPassword("Passphrase: ", true) - if err != nil { - utils.Fatalf("%v", err) - } - confirm, err := readPassword("Repeat Passphrase: ", false) - if err != nil { - utils.Fatalf("%v", err) - } - if auth != confirm { - utils.Fatalf("Passphrases did not match.") - } - passphrase = auth - } else { - var err error - passphrase, err = arg.ToString() - if err != nil { - fmt.Println(err) - return otto.FalseValue() - } - } - acct, err := js.ethereum.AccountManager().NewAccount(passphrase) - if err != nil { - fmt.Printf("Could not create the account: %v", err) - return otto.UndefinedValue() - } - return js.re.ToVal(common.Bytes2Hex(acct.Address)) -} - -func (js *jsre) nodeInfo(call otto.FunctionCall) otto.Value { - return js.re.ToVal(js.ethereum.NodeInfo()) -} - -func (js *jsre) peers(call otto.FunctionCall) otto.Value { - return js.re.ToVal(js.ethereum.PeersInfo()) -} - -func (js *jsre) importChain(call otto.FunctionCall) otto.Value { - if len(call.ArgumentList) == 0 { - 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) - return otto.FalseValue() - } - - return otto.TrueValue() -} - -func (js *jsre) exportChain(call otto.FunctionCall) otto.Value { - if len(call.ArgumentList) == 0 { - fmt.Println("err: require file name") - return otto.FalseValue() - } - - fn, err := call.Argument(0).ToString() - if err != nil { - fmt.Println(err) - return otto.FalseValue() - } - if err := utils.ExportChain(js.ethereum.ChainManager(), fn); err != nil { - fmt.Println(err) - return otto.FalseValue() - } - return otto.TrueValue() -} - -func (js *jsre) dumpBlock(call otto.FunctionCall) otto.Value { - var block *types.Block - if len(call.ArgumentList) > 0 { - if call.Argument(0).IsNumber() { - num, _ := call.Argument(0).ToInteger() - block = js.ethereum.ChainManager().GetBlockByNumber(uint64(num)) - } else if call.Argument(0).IsString() { - hash, _ := call.Argument(0).ToString() - block = js.ethereum.ChainManager().GetBlock(common.HexToHash(hash)) - } else { - fmt.Println("invalid argument for dump. Either hex string or number") - } - - } else { - block = js.ethereum.ChainManager().CurrentBlock() - } - if block == nil { - fmt.Println("block not found") - return otto.UndefinedValue() - } - - statedb := state.New(block.Root(), js.ethereum.StateDb()) - dump := statedb.RawDump() - return js.re.ToVal(dump) - -} diff --git a/cmd/ethereum/blocktest.go b/cmd/ethereum/blocktest.go deleted file mode 100644 index d9cdfa83f..000000000 --- a/cmd/ethereum/blocktest.go +++ /dev/null @@ -1,80 +0,0 @@ -package main - -import ( - "fmt" - - "github.com/codegangsta/cli" - "github.com/ethereum/go-ethereum/cmd/utils" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/eth" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/tests" -) - -var blocktestCmd = cli.Command{ - Action: runblocktest, - Name: "blocktest", - Usage: `loads a block test file`, - Description: ` -The first argument should be a block test file. -The second argument is the name of a block test from the file. - -The block test will be loaded into an in-memory database. -If loading succeeds, the RPC server is started. Clients will -be able to interact with the chain defined by the test. -`, -} - -func runblocktest(ctx *cli.Context) { - if len(ctx.Args()) != 3 { - utils.Fatalf("Usage: ethereum blocktest {rpc, norpc}") - } - file, testname, startrpc := ctx.Args()[0], ctx.Args()[1], ctx.Args()[2] - - bt, err := tests.LoadBlockTests(file) - if err != nil { - utils.Fatalf("%v", err) - } - test, ok := bt[testname] - if !ok { - utils.Fatalf("Test file does not contain test named %q", testname) - } - - cfg := utils.MakeEthConfig(ClientIdentifier, Version, ctx) - cfg.NewDB = func(path string) (common.Database, error) { return ethdb.NewMemDatabase() } - cfg.MaxPeers = 0 // disable network - ethereum, err := eth.New(cfg) - if err != nil { - utils.Fatalf("%v", err) - } - - // import the genesis block - ethereum.ResetWithGenesisBlock(test.Genesis) - - // import pre accounts - statedb, err := test.InsertPreState(ethereum.StateDb()) - if err != nil { - utils.Fatalf("could not insert genesis accounts: %v", err) - } - - // insert the test blocks, which will execute all transactions - chain := ethereum.ChainManager() - if err := chain.InsertChain(test.Blocks); err != nil { - utils.Fatalf("Block Test load error: %v", err) - } else { - fmt.Println("Block Test chain loaded") - } - - if err := test.ValidatePostState(statedb); err != nil { - utils.Fatalf("post state validation failed: %v", err) - } - fmt.Println("Block Test post state validated, starting ethereum.") - - if startrpc == "rpc" { - startEth(ctx, ethereum) - utils.StartRPC(ethereum, ctx) - ethereum.WaitForShutdown() - } else { - startEth(ctx, ethereum) - } -} diff --git a/cmd/ethereum/js.go b/cmd/ethereum/js.go deleted file mode 100644 index 8e88a1c54..000000000 --- a/cmd/ethereum/js.go +++ /dev/null @@ -1,246 +0,0 @@ -// Copyright (c) 2013-2014, Jeffrey Wilcke. All rights reserved. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -// MA 02110-1301 USA - -package main - -import ( - "bufio" - "fmt" - "os" - "path" - "strings" - - "github.com/ethereum/go-ethereum/cmd/utils" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/eth" - re "github.com/ethereum/go-ethereum/jsre" - "github.com/ethereum/go-ethereum/rpc" - "github.com/ethereum/go-ethereum/xeth" - "github.com/peterh/liner" - "github.com/robertkrimen/otto" -) - -type prompter interface { - AppendHistory(string) - Prompt(p string) (string, error) - PasswordPrompt(p string) (string, error) -} - -type dumbterm struct{ r *bufio.Reader } - -func (r dumbterm) Prompt(p string) (string, error) { - fmt.Print(p) - return r.r.ReadString('\n') -} - -func (r dumbterm) PasswordPrompt(p string) (string, error) { - fmt.Println("!! Unsupported terminal, password will echo.") - fmt.Print(p) - input, err := bufio.NewReader(os.Stdin).ReadString('\n') - fmt.Println() - return input, err -} - -func (r dumbterm) AppendHistory(string) {} - -type jsre struct { - re *re.JSRE - ethereum *eth.Ethereum - xeth *xeth.XEth - ps1 string - atexit func() - - prompter -} - -func newJSRE(ethereum *eth.Ethereum, libPath string, interactive bool) *jsre { - js := &jsre{ethereum: ethereum, ps1: "> "} - js.xeth = xeth.New(ethereum, js) - js.re = re.New(libPath) - js.apiBindings() - js.adminBindings() - - if !liner.TerminalSupported() || !interactive { - js.prompter = dumbterm{bufio.NewReader(os.Stdin)} - } else { - lr := liner.NewLiner() - js.withHistory(func(hist *os.File) { lr.ReadHistory(hist) }) - lr.SetCtrlCAborts(true) - js.prompter = lr - js.atexit = func() { - js.withHistory(func(hist *os.File) { hist.Truncate(0); lr.WriteHistory(hist) }) - lr.Close() - } - } - return js -} - -func (js *jsre) apiBindings() { - - ethApi := rpc.NewEthereumApi(js.xeth, js.ethereum.DataDir) - ethApi.Close() - //js.re.Bind("jeth", rpc.NewJeth(ethApi, js.re.ToVal)) - - jeth := rpc.NewJeth(ethApi, js.re.ToVal, js.re) - //js.re.Bind("jeth", jeth) - js.re.Set("jeth", struct{}{}) - t, _ := js.re.Get("jeth") - jethObj := t.Object() - jethObj.Set("send", jeth.Send) - - err := js.re.Compile("bignumber.js", re.BigNumber_JS) - if err != nil { - utils.Fatalf("Error loading bignumber.js: %v", err) - } - - // we need to declare a dummy setTimeout. Otto does not support it - _, err = js.re.Eval("setTimeout = function(cb, delay) {};") - if err != nil { - utils.Fatalf("Error defining setTimeout: %v", err) - } - - err = js.re.Compile("ethereum.js", re.Ethereum_JS) - if err != nil { - utils.Fatalf("Error loading ethereum.js: %v", err) - } - - _, err = js.re.Eval("var web3 = require('ethereum.js');") - if err != nil { - utils.Fatalf("Error requiring web3: %v", err) - } - - _, err = js.re.Eval("web3.setProvider(jeth)") - if err != nil { - utils.Fatalf("Error setting web3 provider: %v", err) - } - _, err = js.re.Eval(` -var eth = web3.eth; -var shh = web3.shh; -var db = web3.db; -var net = web3.net; - `) - if err != nil { - utils.Fatalf("Error setting namespaces: %v", err) - } - -} - -func (self *jsre) ConfirmTransaction(tx *types.Transaction) bool { - p := fmt.Sprintf("Confirm Transaction %v\n[y/n] ", tx) - answer, _ := self.Prompt(p) - return strings.HasPrefix(strings.Trim(answer, " "), "y") -} - -func (self *jsre) UnlockAccount(addr []byte) bool { - fmt.Printf("Please unlock account %x.\n", addr) - pass, err := self.PasswordPrompt("Passphrase: ") - if err != nil { - return false - } - // TODO: allow retry - if err := self.ethereum.AccountManager().Unlock(addr, pass); err != nil { - return false - } else { - fmt.Println("Account is now unlocked for this session.") - return true - } -} - -func (self *jsre) exec(filename string) error { - if err := self.re.Exec(filename); err != nil { - return fmt.Errorf("Javascript Error: %v", err) - } - return nil -} - -func (self *jsre) interactive() { - for { - input, err := self.Prompt(self.ps1) - if err != nil { - break - } - if input == "" { - continue - } - str += input + "\n" - self.setIndent() - if indentCount <= 0 { - if input == "exit" { - break - } - hist := str[:len(str)-1] - self.AppendHistory(hist) - self.parseInput(str) - str = "" - } - } - if self.atexit != nil { - self.atexit() - } -} - -func (self *jsre) withHistory(op func(*os.File)) { - hist, err := os.OpenFile(path.Join(self.ethereum.DataDir, "history"), os.O_RDWR|os.O_CREATE, os.ModePerm) - if err != nil { - fmt.Printf("unable to open history file: %v\n", err) - return - } - op(hist) - hist.Close() -} - -func (self *jsre) parseInput(code string) { - defer func() { - if r := recover(); r != nil { - fmt.Println("[native] error", r) - } - }() - value, err := self.re.Run(code) - if err != nil { - if ottoErr, ok := err.(*otto.Error); ok { - fmt.Println(ottoErr.String()) - } else { - fmt.Println(err) - } - return - } - self.printValue(value) -} - -var indentCount = 0 -var str = "" - -func (self *jsre) setIndent() { - open := strings.Count(str, "{") - open += strings.Count(str, "(") - closed := strings.Count(str, "}") - closed += strings.Count(str, ")") - indentCount = open - closed - if indentCount <= 0 { - self.ps1 = "> " - } else { - self.ps1 = strings.Join(make([]string, indentCount*2), "..") - self.ps1 += " " - } -} - -func (self *jsre) printValue(v interface{}) { - val, err := self.re.PrettyPrint(v) - if err == nil { - fmt.Printf("%v", val) - } -} diff --git a/cmd/ethereum/js_test.go b/cmd/ethereum/js_test.go deleted file mode 100644 index 5b962f621..000000000 --- a/cmd/ethereum/js_test.go +++ /dev/null @@ -1,262 +0,0 @@ -package main - -import ( - "fmt" - "io/ioutil" - "os" - "path" - "testing" - - "github.com/robertkrimen/otto" - - "github.com/ethereum/go-ethereum/accounts" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/eth" -) - -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) - if err != nil { - t.Errorf("%v", err) - return - } - // 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) - - port++ - ethereum, err = eth.New(ð.Config{ - DataDir: "/tmp/eth", - AccountManager: accounts.NewManager(ks), - Port: fmt.Sprintf("%d", port), - MaxPeers: 10, - Name: "test", - }) - - if err != nil { - t.Errorf("%v", err) - return - } - assetPath := path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "cmd", "mist", "assets", "ext") - repl = newJSRE(ethereum, assetPath, false) - return -} - -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 - } - 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) - } -} - -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 - } - 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) - } - - 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 == [, ], got %v (%v)", addrs, 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 - } - defer ethereum.Stop() - - // should get current block - val0, err := repl.re.Run("admin.dumpBlock()") - if err != nil { - t.Errorf("expected no error, got %v", err) - } - - fn := "/tmp/eth/data/blockchain.0" - _, err = repl.re.Run("admin.export(\"" + fn + "\")") - 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) - } - - _, err = repl.re.Run("admin.import(\"" + fn + "\")") - if err != nil { - t.Errorf("expected no error, got %v", err) - } - - var val1 otto.Value - - // should get current block - val1, err = repl.re.Run("admin.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) - } -} - -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 - } - 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") - } - -} - -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 { - 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) - } - success, _ := val.ToBoolean() - if !success { - t.Errorf("expected true (started), got false") - } -} diff --git a/cmd/ethereum/main.go b/cmd/ethereum/main.go deleted file mode 100644 index 42321e8bc..000000000 --- a/cmd/ethereum/main.go +++ /dev/null @@ -1,516 +0,0 @@ -/* - This file is part of go-ethereum - - go-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - go-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with go-ethereum. If not, see . -*/ -/** - * @authors - * Jeffrey Wilcke - */ -package main - -import ( - "bufio" - "fmt" - "io/ioutil" - "os" - "runtime" - "strconv" - "time" - - "github.com/codegangsta/cli" - "github.com/ethereum/ethash" - "github.com/ethereum/go-ethereum/accounts" - "github.com/ethereum/go-ethereum/cmd/utils" - "github.com/ethereum/go-ethereum/common" - "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/logger" - "github.com/peterh/liner" -) - -const ( - ClientIdentifier = "Ethereum(G)" - Version = "0.9.4" -) - -var ( - clilogger = logger.NewLogger("CLI") - app = utils.NewApp(Version, "the go-ethereum command line interface") -) - -func init() { - app.Action = run - app.HideVersion = true // we have a command to print the version - app.Commands = []cli.Command{ - blocktestCmd, - { - Action: makedag, - Name: "makedag", - Usage: "generate ethash dag (for testing)", - Description: ` -The makedag command generates an ethash DAG in /tmp/dag. - -This command exists to support the system testing project. -Regular users do not need to execute it. -`, - }, - { - Action: version, - Name: "version", - Usage: "print ethereum version numbers", - Description: ` -The output of this command is supposed to be machine-readable. -`, - }, - - { - Name: "wallet", - Usage: "ethereum presale wallet", - Subcommands: []cli.Command{ - { - Action: importWallet, - Name: "import", - Usage: "import ethereum presale wallet", - }, - }, - }, - { - Action: accountList, - Name: "account", - Usage: "manage accounts", - Description: ` - -Manage accounts lets you create new accounts, list all existing accounts, -import a private key into a new account. - -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 -safe environments. - -Make sure you remember the password you gave when creating a new account (with -either new or import). Without it you are not able to unlock your account. - -Note that exporting your key in unencrypted format is NOT supported. - -Keys are stored under /keys. -It is safe to transfer the entire directory or the individual keys therein -between ethereum nodes. -Make sure you backup your keys regularly. - -And finally. DO NOT FORGET YOUR PASSWORD. -`, - Subcommands: []cli.Command{ - { - Action: accountList, - Name: "list", - Usage: "print account addresses", - }, - { - Action: accountCreate, - Name: "new", - Usage: "create a new account", - Description: ` - - ethereum account new - -Creates a new account. Prints the address. - -The account is saved in encrypted format, you are prompted for a passphrase. - -You must remember this passphrase to unlock your account in the future. - -For non-interactive use the passphrase can be specified with the --password flag: - - ethereum --password account new - -Note, this is meant to be used for testing only, it is a bad idea to save your -password to file or expose in any other way. - `, - }, - { - Action: accountImport, - Name: "import", - Usage: "import a private key into a new account", - Description: ` - - ethereum account import - -Imports an unencrypted private key from and creates a new account. -Prints the address. - -The keyfile is assumed to contain an unencrypted private key in canonical EC -raw bytes format. - -The account is saved in encrypted format, you are prompted for a passphrase. - -You must remember this passphrase to unlock your account in the future. - -For non-interactive use the passphrase can be specified with the -password flag: - - ethereum --password account import - -Note: -As you can directly copy your encrypted accounts to another ethereum instance, -this import mechanism is not needed when you transfer an account between -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, - Name: "console", - Usage: `Ethereum Console: interactive JavaScript environment`, - Description: ` -Console is an interactive shell for the Ethereum 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 -`, - }, - { - Action: execJSFiles, - Name: "js", - Usage: `executes the given JavaScript files in the Ethereum JavaScript VM`, - Description: ` -The Ethereum JavaScript VM exposes a node admin interface as well as the DAPP -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`, - }, - } - app.Flags = []cli.Flag{ - utils.UnlockedAccountFlag, - utils.PasswordFileFlag, - utils.BootnodesFlag, - utils.DataDirFlag, - utils.JSpathFlag, - utils.ListenPortFlag, - utils.LogFileFlag, - utils.LogJSONFlag, - utils.LogLevelFlag, - utils.MaxPeersFlag, - utils.MinerThreadsFlag, - utils.MiningEnabledFlag, - utils.NATFlag, - utils.NodeKeyFileFlag, - utils.NodeKeyHexFlag, - utils.RPCEnabledFlag, - utils.RPCListenAddrFlag, - utils.RPCPortFlag, - utils.VMDebugFlag, - utils.ProtocolVersionFlag, - utils.NetworkIdFlag, - } - - // 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") - - // 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() { - runtime.GOMAXPROCS(runtime.NumCPU()) - defer logger.Flush() - if err := app.Run(os.Args); err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) - } -} - -func run(ctx *cli.Context) { - fmt.Printf("Welcome to the FRONTIER\n") - utils.HandleInterrupt() - cfg := utils.MakeEthConfig(ClientIdentifier, Version, ctx) - ethereum, err := eth.New(cfg) - if err != nil { - utils.Fatalf("%v", err) - } - - startEth(ctx, ethereum) - // this blocks the thread - ethereum.WaitForShutdown() -} - -func console(ctx *cli.Context) { - cfg := utils.MakeEthConfig(ClientIdentifier, Version, ctx) - ethereum, err := eth.New(cfg) - if err != nil { - utils.Fatalf("%v", err) - } - - startEth(ctx, ethereum) - repl := newJSRE(ethereum, ctx.String(utils.JSpathFlag.Name), true) - repl.interactive() - - ethereum.Stop() - ethereum.WaitForShutdown() -} - -func execJSFiles(ctx *cli.Context) { - cfg := utils.MakeEthConfig(ClientIdentifier, Version, ctx) - ethereum, err := eth.New(cfg) - if err != nil { - utils.Fatalf("%v", err) - } - - startEth(ctx, ethereum) - repl := newJSRE(ethereum, ctx.String(utils.JSpathFlag.Name), false) - for _, file := range ctx.Args() { - repl.exec(file) - } - - ethereum.Stop() - ethereum.WaitForShutdown() -} - -func unlockAccount(ctx *cli.Context, am *accounts.Manager, account string) (passphrase string) { - var err error - // Load startup keys. XXX we are going to need a different format - // Attempt to unlock the account - passphrase = getPassPhrase(ctx, "", false) - accbytes := common.FromHex(account) - if len(accbytes) == 0 { - utils.Fatalf("Invalid account address '%s'", account) - } - err = am.Unlock(accbytes, passphrase) - if err != nil { - utils.Fatalf("Unlock account failed '%v'", err) - } - return -} - -func startEth(ctx *cli.Context, eth *eth.Ethereum) { - utils.StartEthereum(eth) - am := eth.AccountManager() - - account := ctx.GlobalString(utils.UnlockedAccountFlag.Name) - if len(account) > 0 { - if account == "coinbase" { - accbytes, err := am.Coinbase() - if err != nil { - utils.Fatalf("no coinbase account: %v", err) - } - account = common.ToHex(accbytes) - } - unlockAccount(ctx, am, account) - } - // Start auxiliary services if enabled. - if ctx.GlobalBool(utils.RPCEnabledFlag.Name) { - utils.StartRPC(eth, ctx) - } - if ctx.GlobalBool(utils.MiningEnabledFlag.Name) { - eth.StartMining() - } -} - -func accountList(ctx *cli.Context) { - am := utils.GetAccountManager(ctx) - accts, err := am.Accounts() - if err != nil { - utils.Fatalf("Could not list accounts: %v", err) - } - for _, acct := range accts { - fmt.Printf("Address: %x\n", acct) - } -} - -func getPassPhrase(ctx *cli.Context, desc string, confirmation bool) (passphrase string) { - passfile := ctx.GlobalString(utils.PasswordFileFlag.Name) - if len(passfile) == 0 { - fmt.Println(desc) - auth, err := readPassword("Passphrase: ", true) - if err != nil { - utils.Fatalf("%v", err) - } - if confirmation { - confirm, err := readPassword("Repeat Passphrase: ", false) - if err != nil { - utils.Fatalf("%v", err) - } - if auth != confirm { - utils.Fatalf("Passphrases did not match.") - } - } - passphrase = auth - - } else { - passbytes, err := ioutil.ReadFile(passfile) - if err != nil { - utils.Fatalf("Unable to read password file '%s': %v", passfile, err) - } - passphrase = string(passbytes) - } - return -} - -func accountCreate(ctx *cli.Context) { - am := utils.GetAccountManager(ctx) - 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) - if err != nil { - utils.Fatalf("Could not create the account: %v", err) - } - fmt.Printf("Address: %x\n", acct) -} - -func importWallet(ctx *cli.Context) { - keyfile := ctx.Args().First() - if len(keyfile) == 0 { - utils.Fatalf("keyfile must be given as argument") - } - keyJson, err := ioutil.ReadFile(keyfile) - if err != nil { - utils.Fatalf("Could not read wallet file: %v", err) - } - - am := utils.GetAccountManager(ctx) - passphrase := getPassPhrase(ctx, "", false) - - acct, err := am.ImportPreSaleKey(keyJson, passphrase) - if err != nil { - utils.Fatalf("Could not create the account: %v", err) - } - fmt.Printf("Address: %x\n", acct) -} - -func accountImport(ctx *cli.Context) { - keyfile := ctx.Args().First() - if len(keyfile) == 0 { - utils.Fatalf("keyfile must be given as argument") - } - am := utils.GetAccountManager(ctx) - 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) - if err != nil { - utils.Fatalf("Could not create the account: %v", err) - } - fmt.Printf("Address: %x\n", acct) -} - -func importchain(ctx *cli.Context) { - if len(ctx.Args()) != 1 { - utils.Fatalf("This command requires an argument.") - } - chainmgr, _, _ := utils.GetChain(ctx) - start := time.Now() - err := utils.ImportChain(chainmgr, ctx.Args().First()) - if err != nil { - utils.Fatalf("Import error: %v\n", err) - } - 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.") - } - chainmgr, _, _ := utils.GetChain(ctx) - 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 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()) - // fmt.Println(block) - } - } -} - -func makedag(ctx *cli.Context) { - chain, _, _ := utils.GetChain(ctx) - pow := ethash.New(chain) - fmt.Println("making cache") - pow.UpdateCache(true) - fmt.Println("making DAG") - pow.UpdateDAG() -} - -func version(c *cli.Context) { - fmt.Printf(`%v -Version: %v -Protocol Version: %d -Network Id: %d -GO: %s -OS: %s -GOPATH=%s -GOROOT=%s -`, ClientIdentifier, Version, c.GlobalInt(utils.ProtocolVersionFlag.Name), c.GlobalInt(utils.NetworkIdFlag.Name), runtime.Version(), runtime.GOOS, os.Getenv("GOPATH"), runtime.GOROOT()) -} - -// hashish returns true for strings that look like hashes. -func hashish(x string) bool { - _, err := strconv.Atoi(x) - return err != nil -} - -func readPassword(prompt string, warnTerm bool) (string, error) { - if liner.TerminalSupported() { - lr := liner.NewLiner() - defer lr.Close() - return lr.PasswordPrompt(prompt) - } - if warnTerm { - fmt.Println("!! Unsupported terminal, password will be echoed.") - } - fmt.Print(prompt) - input, err := bufio.NewReader(os.Stdin).ReadString('\n') - fmt.Println() - return input, err -} diff --git a/cmd/geth/admin.go b/cmd/geth/admin.go new file mode 100644 index 000000000..139395dad --- /dev/null +++ b/cmd/geth/admin.go @@ -0,0 +1,256 @@ +package main + +import ( + "fmt" + "net" + "net/http" + "os" + "time" + + "github.com/ethereum/go-ethereum/cmd/utils" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/rpc" + "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/xeth" + "github.com/robertkrimen/otto" +) + +/* +node admin bindings +*/ + +func (js *jsre) adminBindings() { + js.re.Set("admin", struct{}{}) + t, _ := js.re.Get("admin") + admin := t.Object() + admin.Set("suggestPeer", js.suggestPeer) + admin.Set("startRPC", js.startRPC) + admin.Set("startMining", js.startMining) + admin.Set("stopMining", js.stopMining) + admin.Set("nodeInfo", js.nodeInfo) + admin.Set("peers", js.peers) + admin.Set("newAccount", js.newAccount) + admin.Set("unlock", js.unlock) + admin.Set("import", js.importChain) + admin.Set("export", js.exportChain) + admin.Set("dumpBlock", js.dumpBlock) +} + +func (js *jsre) startMining(call otto.FunctionCall) otto.Value { + _, err := call.Argument(0).ToInteger() + if err != nil { + fmt.Println(err) + return otto.FalseValue() + } + // threads now ignored + err = js.ethereum.StartMining() + if err != nil { + fmt.Println(err) + return otto.FalseValue() + } + return otto.TrueValue() +} + +func (js *jsre) stopMining(call otto.FunctionCall) otto.Value { + js.ethereum.StopMining() + return otto.TrueValue() +} + +func (js *jsre) startRPC(call otto.FunctionCall) otto.Value { + addr, err := call.Argument(0).ToString() + if err != nil { + fmt.Println(err) + return otto.FalseValue() + } + port, err := call.Argument(1).ToInteger() + if err != nil { + fmt.Println(err) + return otto.FalseValue() + } + dataDir := js.ethereum.DataDir + + l, err := net.Listen("tcp", fmt.Sprintf("%s:%d", addr, port)) + if err != nil { + fmt.Printf("Can't listen on %s:%d: %v", addr, port, err) + return otto.FalseValue() + } + go http.Serve(l, rpc.JSONRPC(xeth.New(js.ethereum, nil), dataDir)) + return otto.TrueValue() +} + +func (js *jsre) suggestPeer(call otto.FunctionCall) otto.Value { + nodeURL, err := call.Argument(0).ToString() + if err != nil { + fmt.Println(err) + return otto.FalseValue() + } + err = js.ethereum.SuggestPeer(nodeURL) + if err != nil { + fmt.Println(err) + return otto.FalseValue() + } + return otto.TrueValue() +} + +func (js *jsre) unlock(call otto.FunctionCall) otto.Value { + addr, err := call.Argument(0).ToString() + if err != nil { + fmt.Println(err) + return otto.FalseValue() + } + seconds, err := call.Argument(2).ToInteger() + if err != nil { + fmt.Println(err) + return otto.FalseValue() + } + arg := call.Argument(1) + var passphrase string + if arg.IsUndefined() { + fmt.Println("Please enter a passphrase now.") + passphrase, err = readPassword("Passphrase: ", true) + if err != nil { + utils.Fatalf("%v", err) + } + } else { + passphrase, err = arg.ToString() + if err != nil { + fmt.Println(err) + return otto.FalseValue() + } + } + 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) + return otto.FalseValue() + } + return otto.TrueValue() +} + +func (js *jsre) newAccount(call otto.FunctionCall) otto.Value { + arg := call.Argument(0) + var passphrase string + if arg.IsUndefined() { + fmt.Println("The new account will be encrypted with a passphrase.") + fmt.Println("Please enter a passphrase now.") + auth, err := readPassword("Passphrase: ", true) + if err != nil { + utils.Fatalf("%v", err) + } + confirm, err := readPassword("Repeat Passphrase: ", false) + if err != nil { + utils.Fatalf("%v", err) + } + if auth != confirm { + utils.Fatalf("Passphrases did not match.") + } + passphrase = auth + } else { + var err error + passphrase, err = arg.ToString() + if err != nil { + fmt.Println(err) + return otto.FalseValue() + } + } + acct, err := js.ethereum.AccountManager().NewAccount(passphrase) + if err != nil { + fmt.Printf("Could not create the account: %v", err) + return otto.UndefinedValue() + } + return js.re.ToVal(common.Bytes2Hex(acct.Address)) +} + +func (js *jsre) nodeInfo(call otto.FunctionCall) otto.Value { + return js.re.ToVal(js.ethereum.NodeInfo()) +} + +func (js *jsre) peers(call otto.FunctionCall) otto.Value { + return js.re.ToVal(js.ethereum.PeersInfo()) +} + +func (js *jsre) importChain(call otto.FunctionCall) otto.Value { + if len(call.ArgumentList) == 0 { + 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) + return otto.FalseValue() + } + + return otto.TrueValue() +} + +func (js *jsre) exportChain(call otto.FunctionCall) otto.Value { + if len(call.ArgumentList) == 0 { + fmt.Println("err: require file name") + return otto.FalseValue() + } + + fn, err := call.Argument(0).ToString() + if err != nil { + fmt.Println(err) + return otto.FalseValue() + } + if err := utils.ExportChain(js.ethereum.ChainManager(), fn); err != nil { + fmt.Println(err) + return otto.FalseValue() + } + return otto.TrueValue() +} + +func (js *jsre) dumpBlock(call otto.FunctionCall) otto.Value { + var block *types.Block + if len(call.ArgumentList) > 0 { + if call.Argument(0).IsNumber() { + num, _ := call.Argument(0).ToInteger() + block = js.ethereum.ChainManager().GetBlockByNumber(uint64(num)) + } else if call.Argument(0).IsString() { + hash, _ := call.Argument(0).ToString() + block = js.ethereum.ChainManager().GetBlock(common.HexToHash(hash)) + } else { + fmt.Println("invalid argument for dump. Either hex string or number") + } + + } else { + block = js.ethereum.ChainManager().CurrentBlock() + } + if block == nil { + fmt.Println("block not found") + return otto.UndefinedValue() + } + + statedb := state.New(block.Root(), js.ethereum.StateDb()) + dump := statedb.RawDump() + return js.re.ToVal(dump) + +} diff --git a/cmd/geth/blocktest.go b/cmd/geth/blocktest.go new file mode 100644 index 000000000..d9cdfa83f --- /dev/null +++ b/cmd/geth/blocktest.go @@ -0,0 +1,80 @@ +package main + +import ( + "fmt" + + "github.com/codegangsta/cli" + "github.com/ethereum/go-ethereum/cmd/utils" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/eth" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/tests" +) + +var blocktestCmd = cli.Command{ + Action: runblocktest, + Name: "blocktest", + Usage: `loads a block test file`, + Description: ` +The first argument should be a block test file. +The second argument is the name of a block test from the file. + +The block test will be loaded into an in-memory database. +If loading succeeds, the RPC server is started. Clients will +be able to interact with the chain defined by the test. +`, +} + +func runblocktest(ctx *cli.Context) { + if len(ctx.Args()) != 3 { + utils.Fatalf("Usage: ethereum blocktest {rpc, norpc}") + } + file, testname, startrpc := ctx.Args()[0], ctx.Args()[1], ctx.Args()[2] + + bt, err := tests.LoadBlockTests(file) + if err != nil { + utils.Fatalf("%v", err) + } + test, ok := bt[testname] + if !ok { + utils.Fatalf("Test file does not contain test named %q", testname) + } + + cfg := utils.MakeEthConfig(ClientIdentifier, Version, ctx) + cfg.NewDB = func(path string) (common.Database, error) { return ethdb.NewMemDatabase() } + cfg.MaxPeers = 0 // disable network + ethereum, err := eth.New(cfg) + if err != nil { + utils.Fatalf("%v", err) + } + + // import the genesis block + ethereum.ResetWithGenesisBlock(test.Genesis) + + // import pre accounts + statedb, err := test.InsertPreState(ethereum.StateDb()) + if err != nil { + utils.Fatalf("could not insert genesis accounts: %v", err) + } + + // insert the test blocks, which will execute all transactions + chain := ethereum.ChainManager() + if err := chain.InsertChain(test.Blocks); err != nil { + utils.Fatalf("Block Test load error: %v", err) + } else { + fmt.Println("Block Test chain loaded") + } + + if err := test.ValidatePostState(statedb); err != nil { + utils.Fatalf("post state validation failed: %v", err) + } + fmt.Println("Block Test post state validated, starting ethereum.") + + if startrpc == "rpc" { + startEth(ctx, ethereum) + utils.StartRPC(ethereum, ctx) + ethereum.WaitForShutdown() + } else { + startEth(ctx, ethereum) + } +} diff --git a/cmd/geth/js.go b/cmd/geth/js.go new file mode 100644 index 000000000..8e88a1c54 --- /dev/null +++ b/cmd/geth/js.go @@ -0,0 +1,246 @@ +// Copyright (c) 2013-2014, Jeffrey Wilcke. All rights reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301 USA + +package main + +import ( + "bufio" + "fmt" + "os" + "path" + "strings" + + "github.com/ethereum/go-ethereum/cmd/utils" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/eth" + re "github.com/ethereum/go-ethereum/jsre" + "github.com/ethereum/go-ethereum/rpc" + "github.com/ethereum/go-ethereum/xeth" + "github.com/peterh/liner" + "github.com/robertkrimen/otto" +) + +type prompter interface { + AppendHistory(string) + Prompt(p string) (string, error) + PasswordPrompt(p string) (string, error) +} + +type dumbterm struct{ r *bufio.Reader } + +func (r dumbterm) Prompt(p string) (string, error) { + fmt.Print(p) + return r.r.ReadString('\n') +} + +func (r dumbterm) PasswordPrompt(p string) (string, error) { + fmt.Println("!! Unsupported terminal, password will echo.") + fmt.Print(p) + input, err := bufio.NewReader(os.Stdin).ReadString('\n') + fmt.Println() + return input, err +} + +func (r dumbterm) AppendHistory(string) {} + +type jsre struct { + re *re.JSRE + ethereum *eth.Ethereum + xeth *xeth.XEth + ps1 string + atexit func() + + prompter +} + +func newJSRE(ethereum *eth.Ethereum, libPath string, interactive bool) *jsre { + js := &jsre{ethereum: ethereum, ps1: "> "} + js.xeth = xeth.New(ethereum, js) + js.re = re.New(libPath) + js.apiBindings() + js.adminBindings() + + if !liner.TerminalSupported() || !interactive { + js.prompter = dumbterm{bufio.NewReader(os.Stdin)} + } else { + lr := liner.NewLiner() + js.withHistory(func(hist *os.File) { lr.ReadHistory(hist) }) + lr.SetCtrlCAborts(true) + js.prompter = lr + js.atexit = func() { + js.withHistory(func(hist *os.File) { hist.Truncate(0); lr.WriteHistory(hist) }) + lr.Close() + } + } + return js +} + +func (js *jsre) apiBindings() { + + ethApi := rpc.NewEthereumApi(js.xeth, js.ethereum.DataDir) + ethApi.Close() + //js.re.Bind("jeth", rpc.NewJeth(ethApi, js.re.ToVal)) + + jeth := rpc.NewJeth(ethApi, js.re.ToVal, js.re) + //js.re.Bind("jeth", jeth) + js.re.Set("jeth", struct{}{}) + t, _ := js.re.Get("jeth") + jethObj := t.Object() + jethObj.Set("send", jeth.Send) + + err := js.re.Compile("bignumber.js", re.BigNumber_JS) + if err != nil { + utils.Fatalf("Error loading bignumber.js: %v", err) + } + + // we need to declare a dummy setTimeout. Otto does not support it + _, err = js.re.Eval("setTimeout = function(cb, delay) {};") + if err != nil { + utils.Fatalf("Error defining setTimeout: %v", err) + } + + err = js.re.Compile("ethereum.js", re.Ethereum_JS) + if err != nil { + utils.Fatalf("Error loading ethereum.js: %v", err) + } + + _, err = js.re.Eval("var web3 = require('ethereum.js');") + if err != nil { + utils.Fatalf("Error requiring web3: %v", err) + } + + _, err = js.re.Eval("web3.setProvider(jeth)") + if err != nil { + utils.Fatalf("Error setting web3 provider: %v", err) + } + _, err = js.re.Eval(` +var eth = web3.eth; +var shh = web3.shh; +var db = web3.db; +var net = web3.net; + `) + if err != nil { + utils.Fatalf("Error setting namespaces: %v", err) + } + +} + +func (self *jsre) ConfirmTransaction(tx *types.Transaction) bool { + p := fmt.Sprintf("Confirm Transaction %v\n[y/n] ", tx) + answer, _ := self.Prompt(p) + return strings.HasPrefix(strings.Trim(answer, " "), "y") +} + +func (self *jsre) UnlockAccount(addr []byte) bool { + fmt.Printf("Please unlock account %x.\n", addr) + pass, err := self.PasswordPrompt("Passphrase: ") + if err != nil { + return false + } + // TODO: allow retry + if err := self.ethereum.AccountManager().Unlock(addr, pass); err != nil { + return false + } else { + fmt.Println("Account is now unlocked for this session.") + return true + } +} + +func (self *jsre) exec(filename string) error { + if err := self.re.Exec(filename); err != nil { + return fmt.Errorf("Javascript Error: %v", err) + } + return nil +} + +func (self *jsre) interactive() { + for { + input, err := self.Prompt(self.ps1) + if err != nil { + break + } + if input == "" { + continue + } + str += input + "\n" + self.setIndent() + if indentCount <= 0 { + if input == "exit" { + break + } + hist := str[:len(str)-1] + self.AppendHistory(hist) + self.parseInput(str) + str = "" + } + } + if self.atexit != nil { + self.atexit() + } +} + +func (self *jsre) withHistory(op func(*os.File)) { + hist, err := os.OpenFile(path.Join(self.ethereum.DataDir, "history"), os.O_RDWR|os.O_CREATE, os.ModePerm) + if err != nil { + fmt.Printf("unable to open history file: %v\n", err) + return + } + op(hist) + hist.Close() +} + +func (self *jsre) parseInput(code string) { + defer func() { + if r := recover(); r != nil { + fmt.Println("[native] error", r) + } + }() + value, err := self.re.Run(code) + if err != nil { + if ottoErr, ok := err.(*otto.Error); ok { + fmt.Println(ottoErr.String()) + } else { + fmt.Println(err) + } + return + } + self.printValue(value) +} + +var indentCount = 0 +var str = "" + +func (self *jsre) setIndent() { + open := strings.Count(str, "{") + open += strings.Count(str, "(") + closed := strings.Count(str, "}") + closed += strings.Count(str, ")") + indentCount = open - closed + if indentCount <= 0 { + self.ps1 = "> " + } else { + self.ps1 = strings.Join(make([]string, indentCount*2), "..") + self.ps1 += " " + } +} + +func (self *jsre) printValue(v interface{}) { + val, err := self.re.PrettyPrint(v) + if err == nil { + fmt.Printf("%v", val) + } +} diff --git a/cmd/geth/js_test.go b/cmd/geth/js_test.go new file mode 100644 index 000000000..5b962f621 --- /dev/null +++ b/cmd/geth/js_test.go @@ -0,0 +1,262 @@ +package main + +import ( + "fmt" + "io/ioutil" + "os" + "path" + "testing" + + "github.com/robertkrimen/otto" + + "github.com/ethereum/go-ethereum/accounts" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth" +) + +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) + if err != nil { + t.Errorf("%v", err) + return + } + // 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) + + port++ + ethereum, err = eth.New(ð.Config{ + DataDir: "/tmp/eth", + AccountManager: accounts.NewManager(ks), + Port: fmt.Sprintf("%d", port), + MaxPeers: 10, + Name: "test", + }) + + if err != nil { + t.Errorf("%v", err) + return + } + assetPath := path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "cmd", "mist", "assets", "ext") + repl = newJSRE(ethereum, assetPath, false) + return +} + +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 + } + 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) + } +} + +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 + } + 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) + } + + 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 == [, ], got %v (%v)", addrs, 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 + } + defer ethereum.Stop() + + // should get current block + val0, err := repl.re.Run("admin.dumpBlock()") + if err != nil { + t.Errorf("expected no error, got %v", err) + } + + fn := "/tmp/eth/data/blockchain.0" + _, err = repl.re.Run("admin.export(\"" + fn + "\")") + 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) + } + + _, err = repl.re.Run("admin.import(\"" + fn + "\")") + if err != nil { + t.Errorf("expected no error, got %v", err) + } + + var val1 otto.Value + + // should get current block + val1, err = repl.re.Run("admin.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) + } +} + +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 + } + 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") + } + +} + +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 { + 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) + } + success, _ := val.ToBoolean() + if !success { + t.Errorf("expected true (started), got false") + } +} diff --git a/cmd/geth/main.go b/cmd/geth/main.go new file mode 100644 index 000000000..da505218b --- /dev/null +++ b/cmd/geth/main.go @@ -0,0 +1,516 @@ +/* + This file is part of go-ethereum + + go-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + go-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with go-ethereum. If not, see . +*/ +/** + * @authors + * Jeffrey Wilcke + */ +package main + +import ( + "bufio" + "fmt" + "io/ioutil" + "os" + "runtime" + "strconv" + "time" + + "github.com/codegangsta/cli" + "github.com/ethereum/ethash" + "github.com/ethereum/go-ethereum/accounts" + "github.com/ethereum/go-ethereum/cmd/utils" + "github.com/ethereum/go-ethereum/common" + "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/logger" + "github.com/peterh/liner" +) + +const ( + ClientIdentifier = "Geth" + Version = "0.9.4" +) + +var ( + clilogger = logger.NewLogger("CLI") + app = utils.NewApp(Version, "the go-ethereum command line interface") +) + +func init() { + app.Action = run + app.HideVersion = true // we have a command to print the version + app.Commands = []cli.Command{ + blocktestCmd, + { + Action: makedag, + Name: "makedag", + Usage: "generate ethash dag (for testing)", + Description: ` +The makedag command generates an ethash DAG in /tmp/dag. + +This command exists to support the system testing project. +Regular users do not need to execute it. +`, + }, + { + Action: version, + Name: "version", + Usage: "print ethereum version numbers", + Description: ` +The output of this command is supposed to be machine-readable. +`, + }, + + { + Name: "wallet", + Usage: "ethereum presale wallet", + Subcommands: []cli.Command{ + { + Action: importWallet, + Name: "import", + Usage: "import ethereum presale wallet", + }, + }, + }, + { + Action: accountList, + Name: "account", + Usage: "manage accounts", + Description: ` + +Manage accounts lets you create new accounts, list all existing accounts, +import a private key into a new account. + +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 +safe environments. + +Make sure you remember the password you gave when creating a new account (with +either new or import). Without it you are not able to unlock your account. + +Note that exporting your key in unencrypted format is NOT supported. + +Keys are stored under /keys. +It is safe to transfer the entire directory or the individual keys therein +between ethereum nodes. +Make sure you backup your keys regularly. + +And finally. DO NOT FORGET YOUR PASSWORD. +`, + Subcommands: []cli.Command{ + { + Action: accountList, + Name: "list", + Usage: "print account addresses", + }, + { + Action: accountCreate, + Name: "new", + Usage: "create a new account", + Description: ` + + ethereum account new + +Creates a new account. Prints the address. + +The account is saved in encrypted format, you are prompted for a passphrase. + +You must remember this passphrase to unlock your account in the future. + +For non-interactive use the passphrase can be specified with the --password flag: + + ethereum --password account new + +Note, this is meant to be used for testing only, it is a bad idea to save your +password to file or expose in any other way. + `, + }, + { + Action: accountImport, + Name: "import", + Usage: "import a private key into a new account", + Description: ` + + ethereum account import + +Imports an unencrypted private key from and creates a new account. +Prints the address. + +The keyfile is assumed to contain an unencrypted private key in canonical EC +raw bytes format. + +The account is saved in encrypted format, you are prompted for a passphrase. + +You must remember this passphrase to unlock your account in the future. + +For non-interactive use the passphrase can be specified with the -password flag: + + ethereum --password account import + +Note: +As you can directly copy your encrypted accounts to another ethereum instance, +this import mechanism is not needed when you transfer an account between +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, + Name: "console", + 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 +`, + }, + { + Action: execJSFiles, + 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 +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`, + }, + } + app.Flags = []cli.Flag{ + utils.UnlockedAccountFlag, + utils.PasswordFileFlag, + utils.BootnodesFlag, + utils.DataDirFlag, + utils.JSpathFlag, + utils.ListenPortFlag, + utils.LogFileFlag, + utils.LogJSONFlag, + utils.LogLevelFlag, + utils.MaxPeersFlag, + utils.MinerThreadsFlag, + utils.MiningEnabledFlag, + utils.NATFlag, + utils.NodeKeyFileFlag, + utils.NodeKeyHexFlag, + utils.RPCEnabledFlag, + utils.RPCListenAddrFlag, + utils.RPCPortFlag, + utils.VMDebugFlag, + utils.ProtocolVersionFlag, + utils.NetworkIdFlag, + } + + // 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") + + // 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() { + runtime.GOMAXPROCS(runtime.NumCPU()) + defer logger.Flush() + if err := app.Run(os.Args); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} + +func run(ctx *cli.Context) { + fmt.Printf("Welcome to the FRONTIER\n") + utils.HandleInterrupt() + cfg := utils.MakeEthConfig(ClientIdentifier, Version, ctx) + ethereum, err := eth.New(cfg) + if err != nil { + utils.Fatalf("%v", err) + } + + startEth(ctx, ethereum) + // this blocks the thread + ethereum.WaitForShutdown() +} + +func console(ctx *cli.Context) { + cfg := utils.MakeEthConfig(ClientIdentifier, Version, ctx) + ethereum, err := eth.New(cfg) + if err != nil { + utils.Fatalf("%v", err) + } + + startEth(ctx, ethereum) + repl := newJSRE(ethereum, ctx.String(utils.JSpathFlag.Name), true) + repl.interactive() + + ethereum.Stop() + ethereum.WaitForShutdown() +} + +func execJSFiles(ctx *cli.Context) { + cfg := utils.MakeEthConfig(ClientIdentifier, Version, ctx) + ethereum, err := eth.New(cfg) + if err != nil { + utils.Fatalf("%v", err) + } + + startEth(ctx, ethereum) + repl := newJSRE(ethereum, ctx.String(utils.JSpathFlag.Name), false) + for _, file := range ctx.Args() { + repl.exec(file) + } + + ethereum.Stop() + ethereum.WaitForShutdown() +} + +func unlockAccount(ctx *cli.Context, am *accounts.Manager, account string) (passphrase string) { + var err error + // Load startup keys. XXX we are going to need a different format + // Attempt to unlock the account + passphrase = getPassPhrase(ctx, "", false) + accbytes := common.FromHex(account) + if len(accbytes) == 0 { + utils.Fatalf("Invalid account address '%s'", account) + } + err = am.Unlock(accbytes, passphrase) + if err != nil { + utils.Fatalf("Unlock account failed '%v'", err) + } + return +} + +func startEth(ctx *cli.Context, eth *eth.Ethereum) { + utils.StartEthereum(eth) + am := eth.AccountManager() + + account := ctx.GlobalString(utils.UnlockedAccountFlag.Name) + if len(account) > 0 { + if account == "coinbase" { + accbytes, err := am.Coinbase() + if err != nil { + utils.Fatalf("no coinbase account: %v", err) + } + account = common.ToHex(accbytes) + } + unlockAccount(ctx, am, account) + } + // Start auxiliary services if enabled. + if ctx.GlobalBool(utils.RPCEnabledFlag.Name) { + utils.StartRPC(eth, ctx) + } + if ctx.GlobalBool(utils.MiningEnabledFlag.Name) { + eth.StartMining() + } +} + +func accountList(ctx *cli.Context) { + am := utils.GetAccountManager(ctx) + accts, err := am.Accounts() + if err != nil { + utils.Fatalf("Could not list accounts: %v", err) + } + for _, acct := range accts { + fmt.Printf("Address: %x\n", acct) + } +} + +func getPassPhrase(ctx *cli.Context, desc string, confirmation bool) (passphrase string) { + passfile := ctx.GlobalString(utils.PasswordFileFlag.Name) + if len(passfile) == 0 { + fmt.Println(desc) + auth, err := readPassword("Passphrase: ", true) + if err != nil { + utils.Fatalf("%v", err) + } + if confirmation { + confirm, err := readPassword("Repeat Passphrase: ", false) + if err != nil { + utils.Fatalf("%v", err) + } + if auth != confirm { + utils.Fatalf("Passphrases did not match.") + } + } + passphrase = auth + + } else { + passbytes, err := ioutil.ReadFile(passfile) + if err != nil { + utils.Fatalf("Unable to read password file '%s': %v", passfile, err) + } + passphrase = string(passbytes) + } + return +} + +func accountCreate(ctx *cli.Context) { + am := utils.GetAccountManager(ctx) + 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) + if err != nil { + utils.Fatalf("Could not create the account: %v", err) + } + fmt.Printf("Address: %x\n", acct) +} + +func importWallet(ctx *cli.Context) { + keyfile := ctx.Args().First() + if len(keyfile) == 0 { + utils.Fatalf("keyfile must be given as argument") + } + keyJson, err := ioutil.ReadFile(keyfile) + if err != nil { + utils.Fatalf("Could not read wallet file: %v", err) + } + + am := utils.GetAccountManager(ctx) + passphrase := getPassPhrase(ctx, "", false) + + acct, err := am.ImportPreSaleKey(keyJson, passphrase) + if err != nil { + utils.Fatalf("Could not create the account: %v", err) + } + fmt.Printf("Address: %x\n", acct) +} + +func accountImport(ctx *cli.Context) { + keyfile := ctx.Args().First() + if len(keyfile) == 0 { + utils.Fatalf("keyfile must be given as argument") + } + am := utils.GetAccountManager(ctx) + 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) + if err != nil { + utils.Fatalf("Could not create the account: %v", err) + } + fmt.Printf("Address: %x\n", acct) +} + +func importchain(ctx *cli.Context) { + if len(ctx.Args()) != 1 { + utils.Fatalf("This command requires an argument.") + } + chainmgr, _, _ := utils.GetChain(ctx) + start := time.Now() + err := utils.ImportChain(chainmgr, ctx.Args().First()) + if err != nil { + utils.Fatalf("Import error: %v\n", err) + } + 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.") + } + chainmgr, _, _ := utils.GetChain(ctx) + 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 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()) + // fmt.Println(block) + } + } +} + +func makedag(ctx *cli.Context) { + chain, _, _ := utils.GetChain(ctx) + pow := ethash.New(chain) + fmt.Println("making cache") + pow.UpdateCache(true) + fmt.Println("making DAG") + pow.UpdateDAG() +} + +func version(c *cli.Context) { + fmt.Printf(`%v +Version: %v +Protocol Version: %d +Network Id: %d +GO: %s +OS: %s +GOPATH=%s +GOROOT=%s +`, ClientIdentifier, Version, c.GlobalInt(utils.ProtocolVersionFlag.Name), c.GlobalInt(utils.NetworkIdFlag.Name), runtime.Version(), runtime.GOOS, os.Getenv("GOPATH"), runtime.GOROOT()) +} + +// hashish returns true for strings that look like hashes. +func hashish(x string) bool { + _, err := strconv.Atoi(x) + return err != nil +} + +func readPassword(prompt string, warnTerm bool) (string, error) { + if liner.TerminalSupported() { + lr := liner.NewLiner() + defer lr.Close() + return lr.PasswordPrompt(prompt) + } + if warnTerm { + fmt.Println("!! Unsupported terminal, password will be echoed.") + } + fmt.Print(prompt) + input, err := bufio.NewReader(os.Stdin).ReadString('\n') + fmt.Println() + return input, err +} -- cgit