diff options
Diffstat (limited to 'cmd/ethereum')
-rw-r--r-- | cmd/ethereum/cmd.go | 35 | ||||
-rw-r--r-- | cmd/ethereum/flags.go | 103 | ||||
-rw-r--r-- | cmd/ethereum/main.go | 115 | ||||
-rw-r--r-- | cmd/ethereum/repl/console_colors_windows.go | 80 | ||||
-rw-r--r-- | cmd/ethereum/repl/repl.go | 85 | ||||
-rw-r--r-- | cmd/ethereum/repl/repl_darwin.go | 127 | ||||
l--------- | cmd/ethereum/repl/repl_linux.go | 1 | ||||
-rw-r--r-- | cmd/ethereum/repl/repl_windows.go | 75 |
8 files changed, 621 insertions, 0 deletions
diff --git a/cmd/ethereum/cmd.go b/cmd/ethereum/cmd.go new file mode 100644 index 000000000..e99e2931a --- /dev/null +++ b/cmd/ethereum/cmd.go @@ -0,0 +1,35 @@ +package main + +import ( + "io/ioutil" + "os" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/cmd/ethereum/repl" + "github.com/ethereum/go-ethereum/javascript" + "github.com/ethereum/go-ethereum/utils" +) + +func InitJsConsole(ethereum *eth.Ethereum) { + repl := ethrepl.NewJSRepl(ethereum) + go repl.Start() + utils.RegisterInterrupt(func(os.Signal) { + repl.Stop() + }) +} + +func ExecJsFile(ethereum *eth.Ethereum, InputFile string) { + file, err := os.Open(InputFile) + if err != nil { + logger.Fatalln(err) + } + content, err := ioutil.ReadAll(file) + if err != nil { + logger.Fatalln(err) + } + re := javascript.NewJSRE(ethereum) + utils.RegisterInterrupt(func(os.Signal) { + re.Stop() + }) + re.Run(string(content)) +} diff --git a/cmd/ethereum/flags.go b/cmd/ethereum/flags.go new file mode 100644 index 000000000..92cf97537 --- /dev/null +++ b/cmd/ethereum/flags.go @@ -0,0 +1,103 @@ +package main + +import ( + "flag" + "fmt" + "log" + "os" + "os/user" + "path" + + "github.com/ethereum/go-ethereum/ethlog" + "github.com/ethereum/go-ethereum/vm" +) + +var ( + Identifier string + KeyRing string + DiffTool bool + DiffType string + KeyStore string + StartRpc bool + StartWebSockets bool + RpcPort int + UseUPnP bool + OutboundPort string + ShowGenesis bool + AddPeer string + MaxPeer int + GenAddr bool + UseSeed bool + SecretFile string + ExportDir string + NonInteractive bool + Datadir string + LogFile string + ConfigFile string + DebugFile string + LogLevel int + Dump bool + DumpHash string + DumpNumber int + VmType int +) + +// flags specific to cli client +var ( + StartMining bool + StartJsConsole bool + InputFile string +) + +func defaultDataDir() string { + usr, _ := user.Current() + return path.Join(usr.HomeDir, ".ethereum") +} + +var defaultConfigFile = path.Join(defaultDataDir(), "conf.ini") + +func Init() { + flag.Usage = func() { + fmt.Fprintf(os.Stderr, "%s [options] [filename]:\noptions precedence: default < config file < environment variables < command line\n", os.Args[0]) + flag.PrintDefaults() + } + + flag.IntVar(&VmType, "vm", 0, "Virtual Machine type: 0-1: standard, debug") + flag.StringVar(&Identifier, "id", "", "Custom client identifier") + flag.StringVar(&KeyRing, "keyring", "", "identifier for keyring to use") + flag.StringVar(&KeyStore, "keystore", "db", "system to store keyrings: db|file (db)") + flag.StringVar(&OutboundPort, "port", "30303", "listening port") + flag.BoolVar(&UseUPnP, "upnp", false, "enable UPnP support") + flag.IntVar(&MaxPeer, "maxpeer", 10, "maximum desired peers") + flag.IntVar(&RpcPort, "rpcport", 8080, "port to start json-rpc server on") + flag.BoolVar(&StartRpc, "rpc", false, "start rpc server") + flag.BoolVar(&StartWebSockets, "ws", false, "start websocket server") + flag.BoolVar(&NonInteractive, "y", false, "non-interactive mode (say yes to confirmations)") + flag.BoolVar(&UseSeed, "seed", true, "seed peers") + flag.BoolVar(&GenAddr, "genaddr", false, "create a new priv/pub key") + 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.StringVar(&LogFile, "logfile", "", "log file (defaults to standard output)") + flag.StringVar(&Datadir, "datadir", defaultDataDir(), "specifies the datadir to use") + flag.StringVar(&ConfigFile, "conf", defaultConfigFile, "config file") + flag.StringVar(&DebugFile, "debug", "", "debug file (no debugging if not set)") + flag.IntVar(&LogLevel, "loglevel", int(ethlog.InfoLevel), "loglevel: 0-5: silent,error,warn,info,debug,debug detail)") + 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.BoolVar(&ShowGenesis, "genesis", false, "Dump the genesis block") + + flag.BoolVar(&Dump, "dump", false, "output the ethereum state in JSON format. Sub args [number, hash]") + flag.StringVar(&DumpHash, "hash", "", "specify arg in hex") + flag.IntVar(&DumpNumber, "number", -1, "specify arg in number") + + flag.BoolVar(&StartMining, "mine", false, "start dagger mining") + flag.BoolVar(&StartJsConsole, "js", false, "launches javascript console") + + flag.Parse() + + if VmType >= int(vm.MaxVmTy) { + log.Fatal("Invalid VM type ", VmType) + } + + InputFile = flag.Arg(0) +} diff --git a/cmd/ethereum/main.go b/cmd/ethereum/main.go new file mode 100644 index 000000000..f7d7761e8 --- /dev/null +++ b/cmd/ethereum/main.go @@ -0,0 +1,115 @@ +package main + +import ( + "fmt" + "os" + "runtime" + + "github.com/ethereum/go-ethereum/ethchain" + "github.com/ethereum/go-ethereum/ethlog" + "github.com/ethereum/go-ethereum/ethutil" + "github.com/ethereum/go-ethereum/utils" +) + +const ( + ClientIdentifier = "Ethereum(G)" + Version = "0.7.0" +) + +var logger = ethlog.NewLogger("CLI") + +func main() { + runtime.GOMAXPROCS(runtime.NumCPU()) + + utils.HandleInterrupt() + + // precedence: code-internal flag default < config file < environment variables < command line + Init() // parsing command line + + // If the difftool option is selected ignore all other log output + if DiffTool || Dump { + LogLevel = 0 + } + + utils.InitConfig(VmType, ConfigFile, Datadir, "ETH") + ethutil.Config.Diff = DiffTool + ethutil.Config.DiffType = DiffType + + utils.InitDataDir(Datadir) + + utils.InitLogging(Datadir, LogFile, LogLevel, DebugFile) + + db := utils.NewDatabase() + err := utils.DBSanityCheck(db) + if err != nil { + fmt.Println(err) + + os.Exit(1) + } + + keyManager := utils.NewKeyManager(KeyStore, Datadir, db) + + // create, import, export keys + utils.KeyTasks(keyManager, KeyRing, GenAddr, SecretFile, ExportDir, NonInteractive) + + clientIdentity := utils.NewClientIdentity(ClientIdentifier, Version, Identifier) + + ethereum := utils.NewEthereum(db, clientIdentity, keyManager, UseUPnP, OutboundPort, MaxPeer) + + if Dump { + var block *ethchain.Block + + if len(DumpHash) == 0 && DumpNumber == -1 { + block = ethereum.ChainManager().CurrentBlock + } else if len(DumpHash) > 0 { + block = ethereum.ChainManager().GetBlock(ethutil.Hex2Bytes(DumpHash)) + } else { + block = ethereum.ChainManager().GetBlockByNumber(uint64(DumpNumber)) + } + + if block == nil { + fmt.Fprintln(os.Stderr, "block not found") + + // We want to output valid JSON + fmt.Println("{}") + + os.Exit(1) + } + + fmt.Printf("RLP: %x\nstate: %x\nhash: %x\n", ethutil.Rlp(block), block.GetRoot(), block.Hash()) + + // Leave the Println. This needs clean output for piping + fmt.Printf("%s\n", block.State().Dump()) + + os.Exit(0) + } + + if ShowGenesis { + utils.ShowGenesis(ethereum) + } + + if StartMining { + utils.StartMining(ethereum) + } + + // better reworked as cases + if StartJsConsole { + InitJsConsole(ethereum) + } else if len(InputFile) > 0 { + ExecJsFile(ethereum, InputFile) + } + + if StartRpc { + utils.StartRpc(ethereum, RpcPort) + } + + if StartWebSockets { + utils.StartWebSockets(ethereum) + } + + utils.StartEthereum(ethereum, UseSeed) + + // this blocks the thread + ethereum.WaitForShutdown() + ethlog.Flush() +} diff --git a/cmd/ethereum/repl/console_colors_windows.go b/cmd/ethereum/repl/console_colors_windows.go new file mode 100644 index 000000000..1f517bd8c --- /dev/null +++ b/cmd/ethereum/repl/console_colors_windows.go @@ -0,0 +1,80 @@ +/* Inspired by https://github.com/xuyu/logging/blob/master/colorful_win.go */ + +package ethrepl + +import ( + "syscall" + "unsafe" +) + +type color uint16 + +const ( + green = color(0x0002) + red = color(0x0004) + yellow = color(0x000E) +) + +const ( + mask = uint16(yellow | green | red) +) + +var ( + kernel32 = syscall.NewLazyDLL("kernel32.dll") + procGetStdHandle = kernel32.NewProc("GetStdHandle") + procSetConsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute") + procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo") + hStdout uintptr + initScreenInfo *consoleScreenBufferInfo +) + +func setConsoleTextAttribute(hConsoleOutput uintptr, wAttributes uint16) bool { + ret, _, _ := procSetConsoleTextAttribute.Call(hConsoleOutput, uintptr(wAttributes)) + return ret != 0 +} + +type coord struct { + X, Y int16 +} + +type smallRect struct { + Left, Top, Right, Bottom int16 +} + +type consoleScreenBufferInfo struct { + DwSize coord + DwCursorPosition coord + WAttributes uint16 + SrWindow smallRect + DwMaximumWindowSize coord +} + +func getConsoleScreenBufferInfo(hConsoleOutput uintptr) *consoleScreenBufferInfo { + var csbi consoleScreenBufferInfo + ret, _, _ := procGetConsoleScreenBufferInfo.Call(hConsoleOutput, uintptr(unsafe.Pointer(&csbi))) + if ret == 0 { + return nil + } + return &csbi +} + +const ( + stdOutputHandle = uint32(-11 & 0xFFFFFFFF) +) + +func init() { + hStdout, _, _ = procGetStdHandle.Call(uintptr(stdOutputHandle)) + initScreenInfo = getConsoleScreenBufferInfo(hStdout) +} + +func resetColorful() { + if initScreenInfo == nil { + return + } + setConsoleTextAttribute(hStdout, initScreenInfo.WAttributes) +} + +func changeColor(c color) { + attr := uint16(0) & ^mask | uint16(c) + setConsoleTextAttribute(hStdout, attr) +} diff --git a/cmd/ethereum/repl/repl.go b/cmd/ethereum/repl/repl.go new file mode 100644 index 000000000..a40a8874e --- /dev/null +++ b/cmd/ethereum/repl/repl.go @@ -0,0 +1,85 @@ +package ethrepl + +import ( + "bufio" + "fmt" + "io" + "os" + "path" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/ethlog" + "github.com/ethereum/go-ethereum/ethutil" + "github.com/ethereum/go-ethereum/javascript" +) + +var logger = ethlog.NewLogger("REPL") + +type Repl interface { + Start() + Stop() +} + +type JSRepl struct { + re *javascript.JSRE + + prompt string + + history *os.File + + running bool +} + +func NewJSRepl(ethereum *eth.Ethereum) *JSRepl { + hist, err := os.OpenFile(path.Join(ethutil.Config.ExecPath, "history"), os.O_RDWR|os.O_CREATE, os.ModePerm) + if err != nil { + panic(err) + } + + return &JSRepl{re: javascript.NewJSRE(ethereum), prompt: "> ", history: hist} +} + +func (self *JSRepl) Start() { + if !self.running { + self.running = true + logger.Infoln("init JS Console") + reader := bufio.NewReader(self.history) + for { + line, err := reader.ReadString('\n') + if err != nil && err == io.EOF { + break + } else if err != nil { + fmt.Println("error reading history", err) + break + } + + addHistory(line[:len(line)-1]) + } + self.read() + } +} + +func (self *JSRepl) Stop() { + if self.running { + self.running = false + self.re.Stop() + logger.Infoln("exit JS Console") + self.history.Close() + } +} + +func (self *JSRepl) parseInput(code string) { + defer func() { + if r := recover(); r != nil { + fmt.Println("[native] error", r) + } + }() + + value, err := self.re.Run(code) + if err != nil { + fmt.Println(err) + return + } + + self.PrintValue(value) +} diff --git a/cmd/ethereum/repl/repl_darwin.go b/cmd/ethereum/repl/repl_darwin.go new file mode 100644 index 000000000..ba7dae996 --- /dev/null +++ b/cmd/ethereum/repl/repl_darwin.go @@ -0,0 +1,127 @@ +package ethrepl + +// #cgo darwin CFLAGS: -I/usr/local/opt/readline/include +// #cgo darwin LDFLAGS: -L/usr/local/opt/readline/lib +// #cgo LDFLAGS: -lreadline +// #include <stdio.h> +// #include <stdlib.h> +// #include <readline/readline.h> +// #include <readline/history.h> +import "C" +import ( + "fmt" + "os" + "os/signal" + "strings" + "syscall" + "unsafe" +) + +func initReadLine() { + C.rl_catch_sigwinch = 0 + C.rl_catch_signals = 0 + c := make(chan os.Signal, 1) + signal.Notify(c, syscall.SIGWINCH) + signal.Notify(c, os.Interrupt) + go func() { + for sig := range c { + switch sig { + case syscall.SIGWINCH: + C.rl_resize_terminal() + + case os.Interrupt: + C.rl_cleanup_after_signal() + default: + + } + } + }() +} + +func readLine(prompt *string) *string { + var p *C.char + + //readline allows an empty prompt(NULL) + if prompt != nil { + p = C.CString(*prompt) + } + + ret := C.readline(p) + + if p != nil { + C.free(unsafe.Pointer(p)) + } + + if ret == nil { + return nil + } //EOF + + s := C.GoString(ret) + C.free(unsafe.Pointer(ret)) + return &s +} + +func addHistory(s string) { + p := C.CString(s) + C.add_history(p) + C.free(unsafe.Pointer(p)) +} + +var indentCount = 0 +var str = "" + +func (self *JSRepl) setIndent() { + open := strings.Count(str, "{") + open += strings.Count(str, "(") + closed := strings.Count(str, "}") + closed += strings.Count(str, ")") + indentCount = open - closed + if indentCount <= 0 { + self.prompt = "> " + } else { + self.prompt = strings.Join(make([]string, indentCount*2), "..") + self.prompt += " " + } +} + +func (self *JSRepl) read() { + initReadLine() +L: + for { + switch result := readLine(&self.prompt); true { + case result == nil: + break L + + case *result != "": + str += *result + "\n" + + self.setIndent() + + if indentCount <= 0 { + if *result == "exit" { + self.Stop() + break L + } + + hist := str[:len(str)-1] + addHistory(hist) //allow user to recall this line + self.history.WriteString(str) + + self.parseInput(str) + + str = "" + } + } + } +} + +func (self *JSRepl) PrintValue(v interface{}) { + method, _ := self.re.Vm.Get("prettyPrint") + v, err := self.re.Vm.ToValue(v) + if err == nil { + val, err := method.Call(method, v) + if err == nil { + fmt.Printf("%v", val) + } + } +} diff --git a/cmd/ethereum/repl/repl_linux.go b/cmd/ethereum/repl/repl_linux.go new file mode 120000 index 000000000..276f135d7 --- /dev/null +++ b/cmd/ethereum/repl/repl_linux.go @@ -0,0 +1 @@ +repl_darwin.go
\ No newline at end of file diff --git a/cmd/ethereum/repl/repl_windows.go b/cmd/ethereum/repl/repl_windows.go new file mode 100644 index 000000000..bfae57088 --- /dev/null +++ b/cmd/ethereum/repl/repl_windows.go @@ -0,0 +1,75 @@ +package ethrepl + +import ( + "bufio" + "fmt" + "os" + "strings" +) + +func (self *JSRepl) read() { + reader := bufio.NewReader(os.Stdin) + for { + fmt.Printf(self.prompt) + str, _, err := reader.ReadLine() + if err != nil { + fmt.Println("Error reading input", err) + } else { + if (string(str) == "exit") { + self.Stop() + break + } else { + self.parseInput(string(str)) + } + } + } +} + +func addHistory(s string) { +} + +func printColored(outputVal string) { + for ; outputVal != "" ; { + codePart := "" + if (strings.HasPrefix(outputVal, "\033[32m")) { + codePart = "\033[32m" + changeColor(2) + } + if (strings.HasPrefix(outputVal, "\033[1m\033[30m")) { + codePart = "\033[1m\033[30m" + changeColor(8) + } + if (strings.HasPrefix(outputVal, "\033[31m")) { + codePart = "\033[31m" + changeColor(red) + } + if (strings.HasPrefix(outputVal, "\033[35m")) { + codePart = "\033[35m" + changeColor(5) + } + if (strings.HasPrefix(outputVal, "\033[0m")) { + codePart = "\033[0m" + resetColorful() + } + textPart := outputVal[len(codePart):len(outputVal)] + index := strings.Index(textPart, "\033") + if index == -1 { + outputVal = "" + } else { + outputVal = textPart[index:len(textPart)] + textPart = textPart[0:index] + } + fmt.Printf("%v", textPart) + } +} + +func (self *JSRepl) PrintValue(v interface{}) { + method, _ := self.re.Vm.Get("prettyPrint") + v, err := self.re.Vm.ToValue(v) + if err == nil { + val, err := method.Call(method, v) + if err == nil { + printColored(fmt.Sprintf("%v", val)) + } + } +} |