Merge branch 'ethersphere-feature/logging' into develop

This commit is contained in:
obscuren 2014-06-26 19:52:23 +02:00
commit 91bdf9e801
17 changed files with 555 additions and 510 deletions

3
.gitignore vendored

@ -9,5 +9,6 @@
*un~ *un~
.DS_Store .DS_Store
*/**/.DS_Store */**/.DS_Store
./ethereum/ethereum ethereum/ethereum
ethereal/ethereal

@ -319,7 +319,7 @@ ApplicationWindow {
Slider { Slider {
id: logLevelSlider id: logLevelSlider
value: 1 value: eth.getLogLevelInt()
anchors { anchors {
right: parent.right right: parent.right
top: parent.top top: parent.top
@ -332,7 +332,7 @@ ApplicationWindow {
} }
orientation: Qt.Vertical orientation: Qt.Vertical
maximumValue: 3 maximumValue: 5
stepSize: 1 stepSize: 1
onValueChanged: { onValueChanged: {

@ -1,43 +0,0 @@
package main
import (
"flag"
)
var Identifier string
//var StartMining bool
var StartRpc bool
var RpcPort int
var UseUPnP bool
var OutboundPort string
var ShowGenesis bool
var AddPeer string
var MaxPeer int
var GenAddr bool
var UseSeed bool
var ImportKey string
var ExportKey bool
var AssetPath string
var Datadir string
func Init() {
flag.StringVar(&Identifier, "id", "", "Custom client identifier")
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.StringVar(&AssetPath, "asset_path", "", "absolute path to GUI assets directory")
flag.BoolVar(&ShowGenesis, "genesis", false, "prints genesis header and exits")
flag.BoolVar(&UseSeed, "seed", true, "seed peers")
flag.BoolVar(&GenAddr, "genaddr", false, "create a new priv/pub key")
flag.BoolVar(&ExportKey, "export", false, "export private key")
flag.StringVar(&ImportKey, "import", "", "imports the given private key (hex)")
flag.StringVar(&Datadir, "datadir", ".ethereal", "specifies the datadir to use. Takes precedence over config file.")
flag.Parse()
}

@ -1,142 +0,0 @@
package main
import (
"fmt"
"github.com/ethereum/eth-go"
"github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/go-ethereum/ethereal/ui"
"github.com/ethereum/go-ethereum/utils"
"github.com/go-qml/qml"
"github.com/rakyll/globalconf"
"log"
"os"
"os/signal"
"path"
"runtime"
)
const Debug = true
// Register interrupt handlers so we can stop the ethereum
func RegisterInterupts(s *eth.Ethereum) {
// Buffered chan of one is enough
c := make(chan os.Signal, 1)
// Notify about interrupts for now
signal.Notify(c, os.Interrupt)
go func() {
for sig := range c {
fmt.Printf("Shutting down (%v) ... \n", sig)
s.Stop()
}
}()
}
func main() {
Init()
qml.Init(nil)
runtime.GOMAXPROCS(runtime.NumCPU())
g, err := globalconf.NewWithOptions(&globalconf.Options{
Filename: path.Join(ethutil.ApplicationFolder(Datadir), "conf.ini"),
})
if err != nil {
fmt.Println(err)
} else {
g.ParseAll()
}
ethutil.ReadConfig(Datadir, ethutil.LogFile|ethutil.LogStd, g, Identifier)
// Instantiated a eth stack
ethereum, err := eth.New(eth.CapDefault, UseUPnP)
if err != nil {
log.Println("eth start err:", err)
return
}
ethereum.Port = OutboundPort
if GenAddr {
fmt.Println("This action overwrites your old private key. Are you sure? (y/n)")
var r string
fmt.Scanln(&r)
for ; ; fmt.Scanln(&r) {
if r == "n" || r == "y" {
break
} else {
fmt.Printf("Yes or no?", r)
}
}
if r == "y" {
utils.CreateKeyPair(true)
}
os.Exit(0)
} else {
if len(ImportKey) > 0 {
fmt.Println("This action overwrites your old private key. Are you sure? (y/n)")
var r string
fmt.Scanln(&r)
for ; ; fmt.Scanln(&r) {
if r == "n" || r == "y" {
break
} else {
fmt.Printf("Yes or no?", r)
}
}
if r == "y" {
utils.ImportPrivateKey(ImportKey)
os.Exit(0)
}
}
}
if ExportKey {
keyPair := ethutil.GetKeyRing().Get(0)
fmt.Printf(`
Generating new address and keypair.
Please keep your keys somewhere save.
++++++++++++++++ KeyRing +++++++++++++++++++
addr: %x
prvk: %x
pubk: %x
++++++++++++++++++++++++++++++++++++++++++++
save these words so you can restore your account later: %s
`, keyPair.Address(), keyPair.PrivateKey, keyPair.PublicKey)
os.Exit(0)
}
if ShowGenesis {
fmt.Println(ethereum.BlockChain().Genesis())
os.Exit(0)
}
/*
if StartMining {
utils.DoMining(ethereum)
}
*/
if StartRpc {
utils.DoRpc(ethereum, RpcPort)
}
log.Printf("Starting Ethereum GUI v%s\n", ethutil.Config.Ver)
// Set the max peers
ethereum.MaxPeers = MaxPeer
gui := ethui.New(ethereum)
ethereum.Start(UseSeed)
gui.Start(AssetPath)
// Wait for shutdown
ethereum.WaitForShutdown()
}

95
ethereal/flags.go Normal file

@ -0,0 +1,95 @@
package main
import (
"bitbucket.org/kardianos/osext"
"flag"
"fmt"
"github.com/ethereum/eth-go/ethlog"
"os"
"os/user"
"path"
"path/filepath"
"runtime"
)
var Identifier string
var StartRpc bool
var RpcPort int
var UseUPnP bool
var OutboundPort string
var ShowGenesis bool
var AddPeer string
var MaxPeer int
var GenAddr bool
var UseSeed bool
var ImportKey string
var ExportKey bool
var NonInteractive bool
var Datadir string
var LogFile string
var ConfigFile string
var DebugFile string
var LogLevel int
// flags specific to gui client
var AssetPath string
func defaultAssetPath() string {
var assetPath string
// If the current working directory is the go-ethereum dir
// assume a debug build and use the source directory as
// asset directory.
pwd, _ := os.Getwd()
if pwd == path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "ethereal") {
assetPath = path.Join(pwd, "assets")
} else {
switch runtime.GOOS {
case "darwin":
// Get Binary Directory
exedir, _ := osext.ExecutableFolder()
assetPath = filepath.Join(exedir, "../Resources")
case "linux":
assetPath = "/usr/share/ethereal"
case "window":
fallthrough
default:
assetPath = "."
}
}
return assetPath
}
func defaultDataDir() string {
usr, _ := user.Current()
return path.Join(usr.HomeDir, ".ethereal")
}
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.StringVar(&Identifier, "id", "", "Custom client identifier")
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(&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.BoolVar(&ExportKey, "export", false, "export private key")
flag.StringVar(&LogFile, "logfile", "", "log file (defaults to standard output)")
flag.StringVar(&ImportKey, "import", "", "imports the given private key (hex)")
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.StringVar(&AssetPath, "asset_path", defaultAssetPath(), "absolute path to GUI assets directory")
flag.Parse()
}

61
ethereal/main.go Normal file

@ -0,0 +1,61 @@
package main
import (
"github.com/ethereum/eth-go/ethlog"
"github.com/ethereum/go-ethereum/ethereal/ui"
"github.com/ethereum/go-ethereum/utils"
"github.com/go-qml/qml"
"os"
"runtime"
)
func main() {
runtime.GOMAXPROCS(runtime.NumCPU())
qml.Init(nil)
var interrupted = false
utils.RegisterInterrupt(func(os.Signal) {
interrupted = true
})
utils.HandleInterrupt()
// precedence: code-internal flag default < config file < environment variables < command line
Init() // parsing command line
utils.InitConfig(ConfigFile, Datadir, Identifier, "ETH")
utils.InitDataDir(Datadir)
utils.InitLogging(Datadir, LogFile, LogLevel, DebugFile)
ethereum := utils.NewEthereum(UseUPnP, OutboundPort, MaxPeer)
// create, import, export keys
utils.KeyTasks(GenAddr, ImportKey, ExportKey, NonInteractive)
if ShowGenesis {
utils.ShowGenesis(ethereum)
}
if StartRpc {
utils.StartRpc(ethereum, RpcPort)
}
gui := ethui.New(ethereum, LogLevel)
utils.RegisterInterrupt(func(os.Signal) {
gui.Stop()
})
utils.StartEthereum(ethereum, UseSeed)
// gui blocks the main thread
gui.Start(AssetPath)
// we need to run the interrupt callbacks in case gui is closed
// this skips if we got here by actual interrupt stopping the GUI
if !interrupted {
utils.RunInterruptCallbacks(os.Interrupt)
}
// this blocks the thread
ethereum.WaitForShutdown()
ethlog.Flush()
}

@ -6,6 +6,7 @@ import (
"github.com/ethereum/eth-go" "github.com/ethereum/eth-go"
"github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethdb" "github.com/ethereum/eth-go/ethdb"
"github.com/ethereum/eth-go/ethlog"
"github.com/ethereum/eth-go/ethpub" "github.com/ethereum/eth-go/ethpub"
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/go-ethereum/utils" "github.com/ethereum/go-ethereum/utils"
@ -15,6 +16,8 @@ import (
"time" "time"
) )
var logger = ethlog.NewLogger("GUI")
type Gui struct { type Gui struct {
// The main application window // The main application window
win *qml.Window win *qml.Window
@ -33,10 +36,12 @@ type Gui struct {
addr []byte addr []byte
pub *ethpub.PEthereum pub *ethpub.PEthereum
logLevel ethlog.LogLevel
open bool
} }
// Create GUI, but doesn't start it // Create GUI, but doesn't start it
func New(ethereum *eth.Ethereum) *Gui { func New(ethereum *eth.Ethereum, logLevel int) *Gui {
lib := &EthLib{stateManager: ethereum.StateManager(), blockChain: ethereum.BlockChain(), txPool: ethereum.TxPool()} lib := &EthLib{stateManager: ethereum.StateManager(), blockChain: ethereum.BlockChain(), txPool: ethereum.TxPool()}
db, err := ethdb.NewLDBDatabase("tx_database") db, err := ethdb.NewLDBDatabase("tx_database")
if err != nil { if err != nil {
@ -52,7 +57,7 @@ func New(ethereum *eth.Ethereum) *Gui {
pub := ethpub.NewPEthereum(ethereum) pub := ethpub.NewPEthereum(ethereum)
return &Gui{eth: ethereum, lib: lib, txDb: db, addr: addr, pub: pub} return &Gui{eth: ethereum, lib: lib, txDb: db, addr: addr, pub: pub, logLevel: ethlog.LogLevel(logLevel), open: false}
} }
func (gui *Gui) Start(assetPath string) { func (gui *Gui) Start(assetPath string) {
@ -86,25 +91,39 @@ func (gui *Gui) Start(assetPath string) {
var win *qml.Window var win *qml.Window
var err error var err error
var addlog = false
if len(data) == 0 { if len(data) == 0 {
win, err = gui.showKeyImport(context) win, err = gui.showKeyImport(context)
} else { } else {
win, err = gui.showWallet(context) win, err = gui.showWallet(context)
addlog = true
ethutil.Config.Log.AddLogSystem(gui)
} }
if err != nil { if err != nil {
ethutil.Config.Log.Infoln("FATAL: asset not found: you can set an alternative asset path on on the command line using option 'asset_path'", err) logger.Errorln("asset not found: you can set an alternative asset path on the command line using option 'asset_path'", err)
panic(err) panic(err)
} }
ethutil.Config.Log.Infoln("[GUI] Starting GUI") logger.Infoln("Starting GUI")
gui.open = true
win.Show() win.Show()
// only add the gui logger after window is shown otherwise slider wont be shown
if addlog {
ethlog.AddLogSystem(gui)
}
win.Wait() win.Wait()
// need to silence gui logger after window closed otherwise logsystem hangs
gui.SetLogLevel(ethlog.Silence)
gui.open = false
}
gui.eth.Stop() func (gui *Gui) Stop() {
if gui.open {
gui.SetLogLevel(ethlog.Silence)
gui.open = false
gui.win.Hide()
}
logger.Infoln("Stopped")
} }
func (gui *Gui) ToggleMining() { func (gui *Gui) ToggleMining() {
@ -311,22 +330,6 @@ func (gui *Gui) setPeerInfo() {
} }
} }
// Logging functions that log directly to the GUI interface
func (gui *Gui) Println(v ...interface{}) {
str := strings.TrimRight(fmt.Sprintln(v...), "\n")
lines := strings.Split(str, "\n")
for _, line := range lines {
gui.win.Root().Call("addLog", line)
}
}
func (gui *Gui) Printf(format string, v ...interface{}) {
str := strings.TrimRight(fmt.Sprintf(format, v...), "\n")
lines := strings.Split(str, "\n")
for _, line := range lines {
gui.win.Root().Call("addLog", line)
}
}
func (gui *Gui) RegisterName(name string) { func (gui *Gui) RegisterName(name string) {
keyPair := ethutil.GetKeyRing().Get(0) keyPair := ethutil.GetKeyRing().Get(0)
name = fmt.Sprintf("\"%s\"\n1", name) name = fmt.Sprintf("\"%s\"\n1", name)
@ -353,6 +356,34 @@ func (gui *Gui) ClientId() string {
return ethutil.Config.Identifier return ethutil.Config.Identifier
} }
func (gui *Gui) SetLogLevel(level int) { // functions that allow Gui to implement interface ethlog.LogSystem
ethutil.Config.Log.SetLevel(level) func (gui *Gui) SetLogLevel(level ethlog.LogLevel) {
gui.logLevel = level
}
func (gui *Gui) GetLogLevel() ethlog.LogLevel {
return gui.logLevel
}
// this extra function needed to give int typecast value to gui widget
// that sets initial loglevel to default
func (gui *Gui) GetLogLevelInt() int {
return int(gui.logLevel)
}
func (gui *Gui) Println(v ...interface{}) {
gui.printLog(fmt.Sprintln(v...))
}
func (gui *Gui) Printf(format string, v ...interface{}) {
gui.printLog(fmt.Sprintf(format, v...))
}
// Print function that logs directly to the GUI
func (gui *Gui) printLog(s string) {
str := strings.TrimRight(s, "\n")
lines := strings.Split(str, "\n")
for _, line := range lines {
gui.win.Root().Call("addLog", line)
}
} }

@ -96,11 +96,11 @@ func (app *HtmlApplication) NewWatcher(quitChan chan bool) {
app.watcher.Close() app.watcher.Close()
break out break out
case <-app.watcher.Event: case <-app.watcher.Event:
//ethutil.Config.Log.Debugln("Got event:", ev) //logger.Debugln("Got event:", ev)
app.webView.Call("reload") app.webView.Call("reload")
case err := <-app.watcher.Error: case err := <-app.watcher.Error:
// TODO: Do something here // TODO: Do something here
ethutil.Config.Log.Infoln("Watcher error:", err) logger.Infoln("Watcher error:", err)
} }
} }
}() }()

@ -22,7 +22,7 @@ func NewQmlApplication(path string, lib *UiLib) *QmlApplication {
func (app *QmlApplication) Create() error { func (app *QmlApplication) Create() error {
component, err := app.engine.LoadFile(app.path) component, err := app.engine.LoadFile(app.path)
if err != nil { if err != nil {
ethutil.Config.Log.Debugln(err) logger.Warnln(err)
} }
app.win = component.CreateWindow(nil) app.win = component.CreateWindow(nil)

@ -1,14 +1,10 @@
package ethui package ethui
import ( import (
"bitbucket.org/kardianos/osext"
"github.com/ethereum/eth-go" "github.com/ethereum/eth-go"
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethutil"
"github.com/go-qml/qml" "github.com/go-qml/qml"
"os"
"path" "path"
"path/filepath"
"runtime"
) )
type memAddr struct { type memAddr struct {
@ -29,9 +25,6 @@ type UiLib struct {
} }
func NewUiLib(engine *qml.Engine, eth *eth.Ethereum, assetPath string) *UiLib { func NewUiLib(engine *qml.Engine, eth *eth.Ethereum, assetPath string) *UiLib {
if assetPath == "" {
assetPath = DefaultAssetPath()
}
return &UiLib{engine: engine, eth: eth, assetPath: assetPath} return &UiLib{engine: engine, eth: eth, assetPath: assetPath}
} }
@ -52,7 +45,7 @@ func (ui *UiLib) OpenHtml(path string) {
func (ui *UiLib) Muted(content string) { func (ui *UiLib) Muted(content string) {
component, err := ui.engine.LoadFile(ui.AssetPath("qml/muted.qml")) component, err := ui.engine.LoadFile(ui.AssetPath("qml/muted.qml"))
if err != nil { if err != nil {
ethutil.Config.Log.Debugln(err) logger.Debugln(err)
return return
} }
@ -81,6 +74,7 @@ func (ui *UiLib) ConnectToPeer(addr string) {
func (ui *UiLib) AssetPath(p string) string { func (ui *UiLib) AssetPath(p string) string {
return path.Join(ui.assetPath, p) return path.Join(ui.assetPath, p)
} }
func (self *UiLib) StartDbWithContractAndData(contractHash, data string) { func (self *UiLib) StartDbWithContractAndData(contractHash, data string) {
dbWindow := NewDebuggerWindow(self) dbWindow := NewDebuggerWindow(self)
object := self.eth.StateManager().CurrentState().GetStateObject(ethutil.FromHex(contractHash)) object := self.eth.StateManager().CurrentState().GetStateObject(ethutil.FromHex(contractHash))
@ -104,29 +98,3 @@ func (self *UiLib) StartDebugger() {
dbWindow.Show() dbWindow.Show()
} }
func DefaultAssetPath() string {
var base string
// If the current working directory is the go-ethereum dir
// assume a debug build and use the source directory as
// asset directory.
pwd, _ := os.Getwd()
if pwd == path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "ethereal") {
base = path.Join(pwd, "assets")
} else {
switch runtime.GOOS {
case "darwin":
// Get Binary Directory
exedir, _ := osext.ExecutableFolder()
base = filepath.Join(exedir, "../Resources")
case "linux":
base = "/usr/share/ethereal"
case "window":
fallthrough
default:
base = "."
}
}
return base
}

32
ethereum/cmd.go Normal file

@ -0,0 +1,32 @@
package main
import (
"github.com/ethereum/eth-go"
"github.com/ethereum/go-ethereum/utils"
"io/ioutil"
"os"
)
func InitJsConsole(ethereum *eth.Ethereum) {
repl := 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 := NewJSRE(ethereum)
utils.RegisterInterrupt(func(os.Signal) {
re.Stop()
})
re.Run(string(content))
}

@ -1,193 +0,0 @@
package main
import (
"fmt"
"github.com/ethereum/eth-go"
"github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/go-ethereum/utils"
"github.com/rakyll/globalconf"
"io/ioutil"
"log"
"os"
"os/signal"
"path"
"runtime"
"strings"
)
const Debug = true
func RegisterInterrupt(cb func(os.Signal)) {
go func() {
// Buffered chan of one is enough
c := make(chan os.Signal, 1)
// Notify about interrupts for now
signal.Notify(c, os.Interrupt)
for sig := range c {
cb(sig)
}
}()
}
func confirm(message string) bool {
fmt.Println(message, "Are you sure? (y/n)")
var r string
fmt.Scanln(&r)
for ; ; fmt.Scanln(&r) {
if r == "n" || r == "y" {
break
} else {
fmt.Printf("Yes or no?", r)
}
}
return r == "y"
}
func main() {
Init()
runtime.GOMAXPROCS(runtime.NumCPU())
// set logger
var logSys *log.Logger
flags := log.LstdFlags
var lt ethutil.LoggerType
if StartJsConsole || len(InputFile) > 0 {
lt = ethutil.LogFile
} else {
lt = ethutil.LogFile | ethutil.LogStd
}
g, err := globalconf.NewWithOptions(&globalconf.Options{
Filename: path.Join(ethutil.ApplicationFolder(Datadir), "conf.ini"),
})
if err != nil {
fmt.Println(err)
} else {
g.ParseAll()
}
ethutil.ReadConfig(Datadir, lt, g, Identifier)
logger := ethutil.Config.Log
if LogFile != "" {
logfile, err := os.OpenFile(LogFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
panic(fmt.Sprintf("error opening log file '%s': %v", LogFile, err))
}
defer logfile.Close()
log.SetOutput(logfile)
logSys = log.New(logfile, "", flags)
logger.AddLogSystem(logSys)
} else {
logSys = log.New(os.Stdout, "", flags)
}
// Instantiated a eth stack
ethereum, err := eth.New(eth.CapDefault, UseUPnP)
if err != nil {
log.Println("eth start err:", err)
return
}
ethereum.Port = OutboundPort
// bookkeeping tasks
switch {
case GenAddr:
if NonInteractive || confirm("This action overwrites your old private key.") {
utils.CreateKeyPair(true)
}
os.Exit(0)
case len(ImportKey) > 0:
if NonInteractive || confirm("This action overwrites your old private key.") {
mnemonic := strings.Split(ImportKey, " ")
if len(mnemonic) == 24 {
logSys.Println("Got mnemonic key, importing.")
key := ethutil.MnemonicDecode(mnemonic)
utils.ImportPrivateKey(key)
} else if len(mnemonic) == 1 {
logSys.Println("Got hex key, importing.")
utils.ImportPrivateKey(ImportKey)
} else {
logSys.Println("Did not recognise format, exiting.")
}
}
os.Exit(0)
case ExportKey:
keyPair := ethutil.GetKeyRing().Get(0)
fmt.Printf(`
Generating new address and keypair.
Please keep your keys somewhere save.
++++++++++++++++ KeyRing +++++++++++++++++++
addr: %x
prvk: %x
pubk: %x
++++++++++++++++++++++++++++++++++++++++++++
save these words so you can restore your account later: %s
`, keyPair.Address(), keyPair.PrivateKey, keyPair.PublicKey)
os.Exit(0)
case ShowGenesis:
logSys.Println(ethereum.BlockChain().Genesis())
os.Exit(0)
default:
// Creates a keypair if non exists
utils.CreateKeyPair(false)
}
// client
logger.Infoln(fmt.Sprintf("Starting Ethereum v%s", ethutil.Config.Ver))
// Set the max peers
ethereum.MaxPeers = MaxPeer
// Set Mining status
ethereum.Mining = StartMining
if StartMining {
utils.DoMining(ethereum)
}
if StartJsConsole {
repl := NewJSRepl(ethereum)
go repl.Start()
RegisterInterrupt(func(os.Signal) {
repl.Stop()
})
} else if len(InputFile) > 0 {
file, err := os.Open(InputFile)
if err != nil {
ethutil.Config.Log.Fatal(err)
}
content, err := ioutil.ReadAll(file)
if err != nil {
ethutil.Config.Log.Fatal(err)
}
re := NewJSRE(ethereum)
RegisterInterrupt(func(os.Signal) {
re.Stop()
})
re.Run(string(content))
}
if StartRpc {
utils.DoRpc(ethereum, RpcPort)
}
RegisterInterrupt(func(sig os.Signal) {
fmt.Printf("Shutting down (%v) ... \n", sig)
ethereum.Stop()
})
ethereum.Start(UseSeed)
// Wait for shutdown
ethereum.WaitForShutdown()
}

@ -3,11 +3,13 @@ package main
import ( import (
"flag" "flag"
"fmt" "fmt"
"github.com/ethereum/eth-go/ethlog"
"os" "os"
"os/user"
"path"
) )
var Identifier string var Identifier string
var StartMining bool
var StartRpc bool var StartRpc bool
var RpcPort int var RpcPort int
var UseUPnP bool var UseUPnP bool
@ -19,16 +21,28 @@ var GenAddr bool
var UseSeed bool var UseSeed bool
var ImportKey string var ImportKey string
var ExportKey bool var ExportKey bool
var LogFile string
var NonInteractive bool var NonInteractive bool
var Datadir string
var LogFile string
var ConfigFile string
var DebugFile string
var LogLevel int
// flags specific to cli client
var StartMining bool
var StartJsConsole bool var StartJsConsole bool
var InputFile string var InputFile string
var Datadir string func defaultDataDir() string {
usr, _ := user.Current()
return path.Join(usr.HomeDir, ".ethereum")
}
var defaultConfigFile = path.Join(defaultDataDir(), "conf.ini")
func Init() { func Init() {
flag.Usage = func() { flag.Usage = func() {
fmt.Fprintf(os.Stderr, "%s [options] [filename]:\n", os.Args[0]) fmt.Fprintf(os.Stderr, "%s [options] [filename]:\noptions precedence: default < config file < environment variables < command line\n", os.Args[0])
flag.PrintDefaults() flag.PrintDefaults()
} }
@ -38,17 +52,19 @@ func Init() {
flag.IntVar(&MaxPeer, "maxpeer", 10, "maximum desired peers") flag.IntVar(&MaxPeer, "maxpeer", 10, "maximum desired peers")
flag.IntVar(&RpcPort, "rpcport", 8080, "port to start json-rpc server on") flag.IntVar(&RpcPort, "rpcport", 8080, "port to start json-rpc server on")
flag.BoolVar(&StartRpc, "rpc", false, "start rpc server") flag.BoolVar(&StartRpc, "rpc", false, "start rpc server")
flag.BoolVar(&StartJsConsole, "js", false, "exp")
flag.BoolVar(&StartMining, "mine", false, "start dagger mining")
flag.BoolVar(&NonInteractive, "y", false, "non-interactive mode (say yes to confirmations)") flag.BoolVar(&NonInteractive, "y", false, "non-interactive mode (say yes to confirmations)")
flag.BoolVar(&UseSeed, "seed", true, "seed peers") flag.BoolVar(&UseSeed, "seed", true, "seed peers")
flag.BoolVar(&GenAddr, "genaddr", false, "create a new priv/pub key") flag.BoolVar(&GenAddr, "genaddr", false, "create a new priv/pub key")
flag.BoolVar(&ExportKey, "export", false, "export private key") flag.BoolVar(&ExportKey, "export", false, "export private key")
flag.StringVar(&LogFile, "logfile", "", "log file (defaults to standard output)") flag.StringVar(&LogFile, "logfile", "", "log file (defaults to standard output)")
flag.StringVar(&ImportKey, "import", "", "imports the given private key (hex)") flag.StringVar(&ImportKey, "import", "", "imports the given private key (hex)")
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.StringVar(&Datadir, "datadir", ".ethereum", "specifies the datadir to use. Takes precedence over config file.") flag.BoolVar(&StartMining, "mine", false, "start dagger mining")
flag.BoolVar(&StartJsConsole, "js", false, "launches javascript console")
flag.Parse() flag.Parse()

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"github.com/ethereum/eth-go" "github.com/ethereum/eth-go"
"github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethlog"
"github.com/ethereum/eth-go/ethpub" "github.com/ethereum/eth-go/ethpub"
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/go-ethereum/utils" "github.com/ethereum/go-ethereum/utils"
@ -14,6 +15,8 @@ import (
"path/filepath" "path/filepath"
) )
var jsrelogger = ethlog.NewLogger("JSRE")
type JSRE struct { type JSRE struct {
ethereum *eth.Ethereum ethereum *eth.Ethereum
vm *otto.Otto vm *otto.Otto
@ -31,7 +34,7 @@ func (jsre *JSRE) LoadExtFile(path string) {
if err == nil { if err == nil {
jsre.vm.Run(result) jsre.vm.Run(result)
} else { } else {
ethutil.Config.Log.Debugln("Could not load file:", path) jsrelogger.Debugln("Could not load file:", path)
} }
} }
@ -65,6 +68,8 @@ func NewJSRE(ethereum *eth.Ethereum) *JSRE {
re.initStdFuncs() re.initStdFuncs()
jsrelogger.Infoln("started")
return re return re
} }
@ -99,6 +104,7 @@ func (self *JSRE) Stop() {
close(self.blockChan) close(self.blockChan)
close(self.quitChan) close(self.quitChan)
close(self.changeChan) close(self.changeChan)
jsrelogger.Infoln("stopped")
} }
func (self *JSRE) mainLoop() { func (self *JSRE) mainLoop() {

53
ethereum/main.go Normal file

@ -0,0 +1,53 @@
package main
import (
"github.com/ethereum/eth-go/ethlog"
"github.com/ethereum/go-ethereum/utils"
"runtime"
)
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
utils.InitConfig(ConfigFile, Datadir, Identifier, "ETH")
utils.InitDataDir(Datadir)
utils.InitLogging(Datadir, LogFile, LogLevel, DebugFile)
ethereum := utils.NewEthereum(UseUPnP, OutboundPort, MaxPeer)
// create, import, export keys
utils.KeyTasks(GenAddr, ImportKey, ExportKey, NonInteractive)
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)
}
utils.StartEthereum(ethereum, UseSeed)
// this blocks the thread
ethereum.WaitForShutdown()
ethlog.Flush()
}

@ -23,6 +23,8 @@ type JSRepl struct {
prompt string prompt string
history *os.File history *os.File
running bool
} }
func NewJSRepl(ethereum *eth.Ethereum) *JSRepl { func NewJSRepl(ethereum *eth.Ethereum) *JSRepl {
@ -35,6 +37,9 @@ func NewJSRepl(ethereum *eth.Ethereum) *JSRepl {
} }
func (self *JSRepl) Start() { func (self *JSRepl) Start() {
if !self.running {
self.running = true
logger.Infoln("init JS Console")
reader := bufio.NewReader(self.history) reader := bufio.NewReader(self.history)
for { for {
line, err := reader.ReadString('\n') line, err := reader.ReadString('\n')
@ -49,11 +54,16 @@ func (self *JSRepl) Start() {
} }
self.read() self.read()
} }
}
func (self *JSRepl) Stop() { func (self *JSRepl) Stop() {
if self.running {
self.running = false
self.re.Stop() self.re.Stop()
logger.Infoln("exit JS Console")
self.history.Close() self.history.Close()
} }
}
func (self *JSRepl) parseInput(code string) { func (self *JSRepl) parseInput(code string) {
defer func() { defer func() {

@ -3,18 +3,184 @@ package utils
import ( import (
"fmt" "fmt"
"github.com/ethereum/eth-go" "github.com/ethereum/eth-go"
"github.com/ethereum/eth-go/ethlog"
"github.com/ethereum/eth-go/ethminer" "github.com/ethereum/eth-go/ethminer"
"github.com/ethereum/eth-go/ethpub" "github.com/ethereum/eth-go/ethpub"
"github.com/ethereum/eth-go/ethrpc" "github.com/ethereum/eth-go/ethrpc"
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethutil"
"io"
"log"
"os"
"os/signal"
"path"
"strings"
"time" "time"
) )
func DoRpc(ethereum *eth.Ethereum, RpcPort int) { var logger = ethlog.NewLogger("CLI")
var interruptCallbacks = []func(os.Signal){}
// Register interrupt handlers callbacks
func RegisterInterrupt(cb func(os.Signal)) {
interruptCallbacks = append(interruptCallbacks, cb)
}
// go routine that call interrupt handlers in order of registering
func HandleInterrupt() {
c := make(chan os.Signal, 1)
go func() {
signal.Notify(c, os.Interrupt)
for sig := range c {
logger.Errorf("Shutting down (%v) ... \n", sig)
RunInterruptCallbacks(sig)
}
}()
}
func RunInterruptCallbacks(sig os.Signal) {
for _, cb := range interruptCallbacks {
cb(sig)
}
}
func AbsolutePath(Datadir string, filename string) string {
if path.IsAbs(filename) {
return filename
}
return path.Join(Datadir, filename)
}
func openLogFile(Datadir string, filename string) *os.File {
path := AbsolutePath(Datadir, filename)
file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
panic(fmt.Sprintf("error opening log file '%s': %v", filename, err))
}
return file
}
func confirm(message string) bool {
fmt.Println(message, "Are you sure? (y/n)")
var r string
fmt.Scanln(&r)
for ; ; fmt.Scanln(&r) {
if r == "n" || r == "y" {
break
} else {
fmt.Printf("Yes or no?", r)
}
}
return r == "y"
}
func InitDataDir(Datadir string) {
_, err := os.Stat(Datadir)
if err != nil {
if os.IsNotExist(err) {
fmt.Printf("Debug logging directory '%s' doesn't exist, creating it\n", Datadir)
os.Mkdir(Datadir, 0777)
}
}
}
func InitLogging(Datadir string, LogFile string, LogLevel int, DebugFile string) {
var writer io.Writer
if LogFile == "" {
writer = os.Stdout
} else {
writer = openLogFile(Datadir, LogFile)
}
ethlog.AddLogSystem(ethlog.NewStdLogSystem(writer, log.LstdFlags, ethlog.LogLevel(LogLevel)))
if DebugFile != "" {
writer = openLogFile(Datadir, DebugFile)
ethlog.AddLogSystem(ethlog.NewStdLogSystem(writer, log.LstdFlags, ethlog.DebugLevel))
}
}
func InitConfig(ConfigFile string, Datadir string, Identifier string, EnvPrefix string) {
InitDataDir(Datadir)
ethutil.ReadConfig(ConfigFile, Datadir, Identifier, EnvPrefix)
ethutil.Config.Set("rpcport", "700")
}
func exit(status int) {
ethlog.Flush()
os.Exit(status)
}
func NewEthereum(UseUPnP bool, OutboundPort string, MaxPeer int) *eth.Ethereum {
ethereum, err := eth.New(eth.CapDefault, UseUPnP)
if err != nil {
logger.Fatalln("eth start err:", err)
}
ethereum.Port = OutboundPort
ethereum.MaxPeers = MaxPeer
return ethereum
}
func StartEthereum(ethereum *eth.Ethereum, UseSeed bool) {
logger.Infof("Starting Ethereum v%s", ethutil.Config.Ver)
ethereum.Start(UseSeed)
RegisterInterrupt(func(sig os.Signal) {
ethereum.Stop()
ethlog.Flush()
})
}
func ShowGenesis(ethereum *eth.Ethereum) {
logger.Infoln(ethereum.BlockChain().Genesis())
exit(0)
}
func KeyTasks(GenAddr bool, ImportKey string, ExportKey bool, NonInteractive bool) {
switch {
case GenAddr:
if NonInteractive || confirm("This action overwrites your old private key.") {
CreateKeyPair(true)
}
exit(0)
case len(ImportKey) > 0:
if NonInteractive || confirm("This action overwrites your old private key.") {
// import should be from file
mnemonic := strings.Split(ImportKey, " ")
if len(mnemonic) == 24 {
logger.Infoln("Got mnemonic key, importing.")
key := ethutil.MnemonicDecode(mnemonic)
ImportPrivateKey(key)
} else if len(mnemonic) == 1 {
logger.Infoln("Got hex key, importing.")
ImportPrivateKey(ImportKey)
} else {
logger.Errorln("Did not recognise format, exiting.")
}
}
exit(0)
case ExportKey: // this should be exporting to a filename
keyPair := ethutil.GetKeyRing().Get(0)
fmt.Printf(`
Generating new address and keypair.
Please keep your keys somewhere save.
++++++++++++++++ KeyRing +++++++++++++++++++
addr: %x
prvk: %x
pubk: %x
++++++++++++++++++++++++++++++++++++++++++++
save these words so you can restore your account later: %s
`, keyPair.Address(), keyPair.PrivateKey, keyPair.PublicKey)
exit(0)
default:
// Creates a keypair if none exists
CreateKeyPair(false)
}
}
func StartRpc(ethereum *eth.Ethereum, RpcPort int) {
var err error var err error
ethereum.RpcServer, err = ethrpc.NewJsonRpcServer(ethpub.NewPEthereum(ethereum), RpcPort) ethereum.RpcServer, err = ethrpc.NewJsonRpcServer(ethpub.NewPEthereum(ethereum), RpcPort)
if err != nil { if err != nil {
ethutil.Config.Log.Infoln("Could not start RPC interface:", err) logger.Errorf("Could not start RPC interface (port %v): %v", RpcPort, err)
} else { } else {
go ethereum.RpcServer.Start() go ethereum.RpcServer.Start()
} }
@ -22,57 +188,41 @@ func DoRpc(ethereum *eth.Ethereum, RpcPort int) {
var miner ethminer.Miner var miner ethminer.Miner
func DoMining(ethereum *eth.Ethereum) { func StartMining(ethereum *eth.Ethereum) bool {
// Set Mining status if !ethereum.Mining {
ethereum.Mining = true ethereum.Mining = true
if ethutil.GetKeyRing().Len() == 0 { if ethutil.GetKeyRing().Len() == 0 {
ethutil.Config.Log.Infoln("No address found, can't start mining") logger.Errorln("No address found, can't start mining")
return ethereum.Mining = false
return true //????
} }
keyPair := ethutil.GetKeyRing().Get(0) keyPair := ethutil.GetKeyRing().Get(0)
addr := keyPair.Address() addr := keyPair.Address()
go func() { go func() {
miner = ethminer.NewDefaultMiner(addr, ethereum) miner = ethminer.NewDefaultMiner(addr, ethereum)
// Give it some time to connect with peers // Give it some time to connect with peers
time.Sleep(3 * time.Second) time.Sleep(3 * time.Second)
logger.Infoln("Miner started")
/*
for ethereum.IsUpToDate() == false {
time.Sleep(5 * time.Second)
}
*/
ethutil.Config.Log.Infoln("Miner started")
miner := ethminer.NewDefaultMiner(addr, ethereum) miner := ethminer.NewDefaultMiner(addr, ethereum)
miner.Start() miner.Start()
}() }()
RegisterInterrupt(func(os.Signal) {
StopMining(ethereum)
})
return true
}
return false
} }
func StopMining(ethereum *eth.Ethereum) bool { func StopMining(ethereum *eth.Ethereum) bool {
if ethereum.Mining { if ethereum.Mining {
miner.Stop() miner.Stop()
logger.Infoln("Miner stopped")
ethutil.Config.Log.Infoln("Miner stopped")
ethereum.Mining = false ethereum.Mining = false
return true return true
} }
return false
}
func StartMining(ethereum *eth.Ethereum) bool {
if !ethereum.Mining {
DoMining(ethereum)
return true
}
return false return false
} }