Merge pull request #773 from ethersphere/frontier/cli

CLI and JS admin changes
This commit is contained in:
Jeffrey Wilcke 2015-04-24 06:58:31 -07:00
commit 168ff36676
6 changed files with 66 additions and 55 deletions

View File

@ -35,7 +35,6 @@ func (js *jsre) adminBindings() {
admin.Set("import", js.importChain) admin.Set("import", js.importChain)
admin.Set("export", js.exportChain) admin.Set("export", js.exportChain)
admin.Set("verbosity", js.verbosity) admin.Set("verbosity", js.verbosity)
admin.Set("backtrace", js.backtrace)
admin.Set("progress", js.downloadProgress) admin.Set("progress", js.downloadProgress)
admin.Set("miner", struct{}{}) admin.Set("miner", struct{}{})
@ -49,11 +48,12 @@ func (js *jsre) adminBindings() {
admin.Set("debug", struct{}{}) admin.Set("debug", struct{}{})
t, _ = admin.Get("debug") t, _ = admin.Get("debug")
debug := t.Object() debug := t.Object()
debug.Set("backtrace", js.backtrace)
debug.Set("printBlock", js.printBlock) debug.Set("printBlock", js.printBlock)
debug.Set("dumpBlock", js.dumpBlock) debug.Set("dumpBlock", js.dumpBlock)
debug.Set("getBlockRlp", js.getBlockRlp) debug.Set("getBlockRlp", js.getBlockRlp)
debug.Set("setHead", js.setHead) 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) { func (js *jsre) getBlock(call otto.FunctionCall) (*types.Block, error) {
@ -203,16 +203,26 @@ func (js *jsre) startRPC(call otto.FunctionCall) otto.Value {
fmt.Println(err) fmt.Println(err)
return otto.FalseValue() return otto.FalseValue()
} }
port, err := call.Argument(1).ToInteger() port, err := call.Argument(1).ToInteger()
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
return otto.FalseValue() 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{ config := rpc.RpcConfig{
ListenAddress: addr, ListenAddress: addr,
ListenPort: uint(port), ListenPort: uint(port),
// CorsDomain: ctx.GlobalString(RPCCORSDomainFlag.Name), CorsDomain: corsDomain,
} }
xeth := xeth.New(js.ethereum, nil) xeth := xeth.New(js.ethereum, nil)
@ -274,10 +284,6 @@ func (js *jsre) unlock(call otto.FunctionCall) otto.Value {
} }
} }
am := js.ethereum.AccountManager() 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) err = am.TimedUnlock(common.FromHex(addr), passphrase, time.Duration(seconds)*time.Second)
if err != nil { if err != nil {
fmt.Printf("Unlock account failed '%v'\n", err) fmt.Printf("Unlock account failed '%v'\n", err)

View File

@ -59,17 +59,19 @@ func (r dumbterm) PasswordPrompt(p string) (string, error) {
func (r dumbterm) AppendHistory(string) {} func (r dumbterm) AppendHistory(string) {}
type jsre struct { type jsre struct {
re *re.JSRE re *re.JSRE
ethereum *eth.Ethereum ethereum *eth.Ethereum
xeth *xeth.XEth xeth *xeth.XEth
ps1 string ps1 string
atexit func() atexit func()
corsDomain string
prompter 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: "> "} 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.xeth = xeth.New(ethereum, js)
js.re = re.New(libPath) js.re = re.New(libPath)
js.apiBindings() js.apiBindings()

View File

@ -3,16 +3,16 @@ package main
import ( import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"path/filepath"
"os" "os"
"path" "path"
"path/filepath"
"testing" "testing"
"github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth"
"runtime"
"regexp" "regexp"
"runtime"
"strconv" "strconv"
) )
@ -36,7 +36,7 @@ func testJEthRE(t *testing.T) (*jsre, *eth.Ethereum) {
t.Fatal("%v", err) t.Fatal("%v", err)
} }
assetPath := path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "cmd", "mist", "assets", "ext") assetPath := path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "cmd", "mist", "assets", "ext")
repl := newJSRE(ethereum, assetPath, false) repl := newJSRE(ethereum, assetPath, false, "")
return repl, ethereum return repl, ethereum
} }
@ -70,8 +70,8 @@ func TestAccounts(t *testing.T) {
t.Errorf("address not hex: %q", addr) t.Errorf("address not hex: %q", addr)
} }
checkEvalJSON(t, repl, `eth.accounts`, `["` + addr + `"]`) checkEvalJSON(t, repl, `eth.accounts`, `["`+addr+`"]`)
checkEvalJSON(t, repl, `eth.coinbase`, `"` + addr + `"`) checkEvalJSON(t, repl, `eth.coinbase`, `"`+addr+`"`)
} }
func TestBlockChain(t *testing.T) { func TestBlockChain(t *testing.T) {
@ -97,13 +97,13 @@ func TestBlockChain(t *testing.T) {
tmpfile := filepath.Join(tmp, "export.chain") tmpfile := filepath.Join(tmp, "export.chain")
tmpfileq := strconv.Quote(tmpfile) tmpfileq := strconv.Quote(tmpfile)
checkEvalJSON(t, repl, `admin.export(` + tmpfileq + `)`, `true`) checkEvalJSON(t, repl, `admin.export(`+tmpfileq+`)`, `true`)
if _, err := os.Stat(tmpfile); err != nil { if _, err := os.Stat(tmpfile); err != nil {
t.Fatal(err) t.Fatal(err)
} }
// check import, verify that dumpBlock gives the same result. // check import, verify that dumpBlock gives the same result.
checkEvalJSON(t, repl, `admin.import(` + tmpfileq + `)`, `true`) checkEvalJSON(t, repl, `admin.import(`+tmpfileq+`)`, `true`)
checkEvalJSON(t, repl, `admin.debug.dumpBlock()`, beforeExport) checkEvalJSON(t, repl, `admin.debug.dumpBlock()`, beforeExport)
} }
@ -129,7 +129,7 @@ func TestRPC(t *testing.T) {
} }
func checkEvalJSON(t *testing.T, re *jsre, expr, want string) error { func checkEvalJSON(t *testing.T, re *jsre, expr, want string) error {
val, err := re.re.Run("JSON.stringify("+ expr + ")") val, err := re.re.Run("JSON.stringify(" + expr + ")")
if err == nil && val.String() != want { if err == nil && val.String() != want {
err = fmt.Errorf("Output mismatch for `%s`:\ngot: %s\nwant: %s", expr, val.String(), want) err = fmt.Errorf("Output mismatch for `%s`:\ngot: %s\nwant: %s", expr, val.String(), want)
} }

View File

@ -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, Manage accounts lets you create new accounts, list all existing accounts,
import a private key into a new account. 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 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 where passwords are supplied via a given password file.
Non-interactive mode is only meant for scripted use on test networks or known 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`, Usage: `Geth Console: interactive JavaScript environment`,
Description: ` Description: `
The Geth console is an interactive shell for the JavaScript runtime environment 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. which exposes a node admin interface as well as the Ðapp JavaScript API.
See https://github.com/ethereum/go-ethereum/wiki/Frontier-Console 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", Name: "js",
Usage: `executes the given JavaScript files in the Geth JavaScript VM`, Usage: `executes the given JavaScript files in the Geth JavaScript VM`,
Description: ` 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 JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Console
`, `,
}, },
@ -261,10 +263,6 @@ 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.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") // 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() { func main() {
@ -298,7 +296,7 @@ func console(ctx *cli.Context) {
} }
startEth(ctx, ethereum) 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() repl.interactive()
ethereum.Stop() ethereum.Stop()
@ -313,7 +311,7 @@ func execJSFiles(ctx *cli.Context) {
} }
startEth(ctx, ethereum) 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() { for _, file := range ctx.Args() {
repl.exec(file) repl.exec(file)
} }
@ -356,10 +354,14 @@ func startEth(ctx *cli.Context, eth *eth.Ethereum) {
} }
// Start auxiliary services if enabled. // Start auxiliary services if enabled.
if ctx.GlobalBool(utils.RPCEnabledFlag.Name) { 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) { if ctx.GlobalBool(utils.MiningEnabledFlag.Name) {
eth.StartMining() if err := eth.StartMining(); err != nil {
utils.Fatalf("%v", err)
}
} }
} }
@ -369,8 +371,10 @@ func accountList(ctx *cli.Context) {
if err != nil { if err != nil {
utils.Fatalf("Could not list accounts: %v", err) utils.Fatalf("Could not list accounts: %v", err)
} }
for _, acct := range accts { name := "Primary"
fmt.Printf("Address: %x\n", acct) for i, acct := range accts {
fmt.Printf("%s #%d: %x\n", name, i, acct)
name = "Account"
} }
} }

View File

@ -79,22 +79,22 @@ var (
} }
ProtocolVersionFlag = cli.IntFlag{ ProtocolVersionFlag = cli.IntFlag{
Name: "protocolversion", Name: "protocolversion",
Usage: "ETH protocol version", Usage: "ETH protocol version (integer)",
Value: eth.ProtocolVersion, Value: eth.ProtocolVersion,
} }
NetworkIdFlag = cli.IntFlag{ NetworkIdFlag = cli.IntFlag{
Name: "networkid", Name: "networkid",
Usage: "Network Id", Usage: "Network Id (integer)",
Value: eth.NetworkId, Value: eth.NetworkId,
} }
BlockchainVersionFlag = cli.IntFlag{ BlockchainVersionFlag = cli.IntFlag{
Name: "blockchainversion", Name: "blockchainversion",
Usage: "Blockchain version", Usage: "Blockchain version (integer)",
Value: core.BlockChainVersion, Value: core.BlockChainVersion,
} }
IdentityFlag = cli.StringFlag{ IdentityFlag = cli.StringFlag{
Name: "identity", Name: "identity",
Usage: "node name", Usage: "Custom node name",
} }
NatspecEnabledFlag = cli.BoolFlag{ NatspecEnabledFlag = cli.BoolFlag{
Name: "natspec", Name: "natspec",
@ -113,18 +113,18 @@ var (
} }
EtherbaseFlag = cli.StringFlag{ EtherbaseFlag = cli.StringFlag{
Name: "etherbase", Name: "etherbase",
Usage: "public address for block mining rewards. By default the address of your primary account is used", Usage: "Public address for block mining rewards. By default the address of your primary account is used",
Value: "primary", Value: "primary",
} }
UnlockedAccountFlag = cli.StringFlag{ UnlockedAccountFlag = cli.StringFlag{
Name: "unlock", Name: "unlock",
Usage: "unlock the account given until this program exits (prompts for password). '--unlock primary' unlocks the primary account", Usage: "Unlock the account given until this program exits (prompts for password). '--unlock primary' unlocks the primary account",
Value: "", Value: "",
} }
PasswordFileFlag = cli.StringFlag{ PasswordFileFlag = cli.StringFlag{
Name: "password", Name: "password",
Usage: "Path to password file for (un)locking an existing account.", Usage: "Path to password file to use with options and subcommands needing a password",
Value: "", Value: "",
} }
@ -135,7 +135,7 @@ var (
} }
LogLevelFlag = cli.IntFlag{ LogLevelFlag = cli.IntFlag{
Name: "loglevel", Name: "loglevel",
Usage: "0-5 (silent, error, warn, info, debug, debug detail)", Usage: "Logging verbosity: 0-6 (0=silent, 1=error, 2=warn, 3=info, 4=core, 5=debug, 6=debug detail)",
Value: int(logger.InfoLevel), Value: int(logger.InfoLevel),
} }
LogJSONFlag = cli.StringFlag{ LogJSONFlag = cli.StringFlag{
@ -149,7 +149,7 @@ var (
} }
LogVModuleFlag = cli.GenericFlag{ LogVModuleFlag = cli.GenericFlag{
Name: "vmodule", Name: "vmodule",
Usage: "The syntax of the argument is a comma-separated list of pattern=N, where pattern is a literal file name (minus the \".go\" suffix) or \"glob\" pattern and N is a V level.", Usage: "The syntax of the argument is a comma-separated list of pattern=N, where pattern is a literal file name (minus the \".go\" suffix) or \"glob\" pattern and N is a log verbosity level.",
Value: glog.GetVModule(), Value: glog.GetVModule(),
} }
VMDebugFlag = cli.BoolFlag{ VMDebugFlag = cli.BoolFlag{
@ -158,12 +158,12 @@ var (
} }
BacktraceAtFlag = cli.GenericFlag{ BacktraceAtFlag = cli.GenericFlag{
Name: "backtrace_at", Name: "backtrace_at",
Usage: "When set to a file and line number holding a logging statement a stack trace will be written to the Info log", Usage: "If set to a file and line number (e.g., \"block.go:271\") holding a logging statement, a stack trace will be logged",
Value: glog.GetTraceLocation(), Value: glog.GetTraceLocation(),
} }
PProfEanbledFlag = cli.BoolFlag{ PProfEanbledFlag = cli.BoolFlag{
Name: "pprof", Name: "pprof",
Usage: "Whether the profiling server should be enabled", Usage: "Enable the profiling server on localhost",
} }
PProfPortFlag = cli.IntFlag{ PProfPortFlag = cli.IntFlag{
Name: "pprofport", Name: "pprofport",
@ -174,7 +174,7 @@ var (
// RPC settings // RPC settings
RPCEnabledFlag = cli.BoolFlag{ RPCEnabledFlag = cli.BoolFlag{
Name: "rpc", Name: "rpc",
Usage: "Whether RPC server is enabled", Usage: "Enable the JSON-RPC server",
} }
RPCListenAddrFlag = cli.StringFlag{ RPCListenAddrFlag = cli.StringFlag{
Name: "rpcaddr", Name: "rpcaddr",
@ -194,7 +194,7 @@ var (
// Network Settings // Network Settings
MaxPeersFlag = cli.IntFlag{ MaxPeersFlag = cli.IntFlag{
Name: "maxpeers", Name: "maxpeers",
Usage: "Maximum number of network peers", Usage: "Maximum number of network peers (network disabled if set to 0)",
Value: 16, Value: 16,
} }
ListenPortFlag = cli.IntFlag{ ListenPortFlag = cli.IntFlag{
@ -204,7 +204,7 @@ var (
} }
BootnodesFlag = cli.StringFlag{ BootnodesFlag = cli.StringFlag{
Name: "bootnodes", Name: "bootnodes",
Usage: "Space-separated enode URLs for discovery bootstrap", Usage: "Space-separated enode URLs for p2p discovery bootstrap",
Value: "", Value: "",
} }
NodeKeyFileFlag = cli.StringFlag{ NodeKeyFileFlag = cli.StringFlag{
@ -217,12 +217,12 @@ var (
} }
NATFlag = cli.StringFlag{ NATFlag = cli.StringFlag{
Name: "nat", Name: "nat",
Usage: "Port mapping mechanism (any|none|upnp|pmp|extip:<IP>)", Usage: "NAT port mapping mechanism (any|none|upnp|pmp|extip:<IP>)",
Value: "any", Value: "any",
} }
WhisperEnabledFlag = cli.BoolFlag{ WhisperEnabledFlag = cli.BoolFlag{
Name: "shh", Name: "shh",
Usage: "Whether the whisper sub-protocol is enabled", Usage: "Enable whisper",
} }
JSpathFlag = cli.StringFlag{ JSpathFlag = cli.StringFlag{
Name: "jspath", Name: "jspath",
@ -330,7 +330,7 @@ func GetAccountManager(ctx *cli.Context) *accounts.Manager {
return accounts.NewManager(ks) return accounts.NewManager(ks)
} }
func StartRPC(eth *eth.Ethereum, ctx *cli.Context) { func StartRPC(eth *eth.Ethereum, ctx *cli.Context) error {
config := rpc.RpcConfig{ config := rpc.RpcConfig{
ListenAddress: ctx.GlobalString(RPCListenAddrFlag.Name), ListenAddress: ctx.GlobalString(RPCListenAddrFlag.Name),
ListenPort: uint(ctx.GlobalInt(RPCPortFlag.Name)), ListenPort: uint(ctx.GlobalInt(RPCPortFlag.Name)),
@ -338,7 +338,7 @@ func StartRPC(eth *eth.Ethereum, ctx *cli.Context) {
} }
xeth := xeth.New(eth, nil) xeth := xeth.New(eth, nil)
_ = rpc.Start(xeth, config) return rpc.Start(xeth, config)
} }
func StartPProf(ctx *cli.Context) { func StartPProf(ctx *cli.Context) {

View File

@ -322,10 +322,9 @@ func (s *Ethereum) StartMining() error {
err = fmt.Errorf("Cannot start mining without etherbase address: %v", err) err = fmt.Errorf("Cannot start mining without etherbase address: %v", err)
glog.V(logger.Error).Infoln(err) glog.V(logger.Error).Infoln(err)
return err return err
} }
s.miner.Start(eb) go s.miner.Start(eb)
return nil return nil
} }