Merge branch 'release/0.5.15'

This commit is contained in:
obscuren 2014-06-26 19:54:09 +02:00
commit 3777ead25e
26 changed files with 798 additions and 594 deletions

3
.gitignore vendored

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

@ -5,7 +5,7 @@ Ethereum
Ethereum Go Client © 2014 Jeffrey Wilcke. Ethereum Go Client © 2014 Jeffrey Wilcke.
Current state: Proof of Concept 5.0 RC14. Current state: Proof of Concept 0.5.15.
For the development package please see the [eth-go package](https://github.com/ethereum/eth-go). For the development package please see the [eth-go package](https://github.com/ethereum/eth-go).

@ -10,9 +10,9 @@ ApplicationWindow {
visible: false visible: false
title: "IceCREAM" title: "IceCREAM"
minimumWidth: 1280 minimumWidth: 1280
minimumHeight: 900 minimumHeight: 700
width: 1290 width: 1290
height: 900 height: 700
property alias codeText: codeEditor.text property alias codeText: codeEditor.text
property alias dataText: rawDataField.text property alias dataText: rawDataField.text
@ -42,7 +42,7 @@ ApplicationWindow {
TableView { TableView {
id: asmTableView id: asmTableView
width: 200 width: 200
TableViewColumn{ role: "value" ; title: "" ; width: 100 } TableViewColumn{ role: "value" ; title: "" ; width: 200 }
model: asmModel model: asmModel
} }
@ -56,7 +56,7 @@ ApplicationWindow {
Rectangle { Rectangle {
color: "#00000000" color: "#00000000"
height: 500 height: 330
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
@ -208,6 +208,12 @@ ApplicationWindow {
} }
text: "Next" text: "Next"
} }
CheckBox {
id: breakEachLine
objectName: "breakEachLine"
text: "Break each instruction"
checked: true
}
} }
} }

@ -58,6 +58,9 @@ window.eth = {
getBalanceAt: function(address, cb) { getBalanceAt: function(address, cb) {
postData({call: "getBalance", args: [address]}, cb); postData({call: "getBalance", args: [address]}, cb);
}, },
getTransactionsFor: function(address, cb) {
postData({call: "getTransactionsFor", args: [address]}, cb);
},
getSecretToAddress: function(sec, cb) { getSecretToAddress: function(sec, cb) {
postData({call: "getSecretToAddress", args: [sec]}, cb); postData({call: "getSecretToAddress", args: [sec]}, cb);

@ -0,0 +1,22 @@
import QtQuick 2.0
import QtQuick.Controls 1.0;
import QtQuick.Layouts 1.0;
import Ethereum 1.0
ApplicationWindow {
minimumWidth: 500
maximumWidth: 500
maximumHeight: 400
minimumHeight: 400
function onNewBlockCb(block) {
console.log("Please overwrite onNewBlock(block):", block)
}
function onObjectChangeCb(stateObject) {
console.log("Please overwrite onObjectChangeCb(object)", stateObject)
}
function onStorageChangeCb(storageObject) {
var ev = ["storage", storageObject.stateAddress, storageObject.address].join(":");
console.log("Please overwrite onStorageChangeCb(object)", ev)
}
}

@ -3,33 +3,68 @@ import QtQuick.Controls 1.0;
import QtQuick.Layouts 1.0; import QtQuick.Layouts 1.0;
import Ethereum 1.0 import Ethereum 1.0
ApplicationWindow { QmlApp {
minimumWidth: 500 minimumWidth: 350
maximumWidth: 500 maximumWidth: 350
maximumHeight: 100 maximumHeight: 80
minimumHeight: 100 minimumHeight: 80
title: "Ethereum Dice" title: "Generic Coin"
TextField { property string contractAddr: "f299f6c74515620e4c4cd8fe3d205b5c4f2e25c8"
id: textField property string addr: "2ef47100e0787b915105fd5e3f4ff6752079d5cb"
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter Component.onCompleted: {
placeholderText: "Amount" eth.watch(contractAddr, addr)
eth.watch(addr, contractAddr)
setAmount()
} }
Label {
id: txHash function onStorageChangeCb(storageObject) {
anchors.bottom: textField.top setAmount()
anchors.bottomMargin: 5
anchors.horizontalCenter: parent.horizontalCenter
} }
Button {
anchors.top: textField.bottom function setAmount(){
anchors.horizontalCenter: parent.horizontalCenter var state = eth.getStateObject(contractAddr)
anchors.topMargin: 5 var storage = state.getStorage(addr)
text: "Place bet" amountLabel.text = storage
onClicked: { }
txHash.text = eth.createTx("e6716f9544a56c530d868e4bfbacb172315bdead", textField.text) Column {
spacing: 5
Row {
spacing: 20
Label {
id: genLabel
text: "Generic coin balance:"
}
Label {
id: amountLabel
}
}
Row {
spacing: 20
TextField {
id: address
placeholderText: "Address"
}
TextField {
id: amount
placeholderText: "Amount"
}
}
Button {
text: "Send coins"
onClicked: {
var privKey = eth.getKey().privateKey
if(privKey){
var result = eth.transact(privKey, contractAddr, 0,"100000","250", "0x" + address.text + "\n" + amount.text)
resultTx.text = result.hash
}
}
}
Label {
id: resultTx
} }
} }
} }

@ -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: {
@ -372,7 +372,15 @@ ApplicationWindow {
onAccepted: { onAccepted: {
//ui.open(openAppDialog.fileUrl.toString()) //ui.open(openAppDialog.fileUrl.toString())
//ui.openHtml(Qt.resolvedUrl(ui.assetPath("test.html"))) //ui.openHtml(Qt.resolvedUrl(ui.assetPath("test.html")))
ui.openHtml(openAppDialog.fileUrl.toString()) var path = openAppDialog.fileUrl.toString()
console.log(path)
var ext = path.split('.').pop()
console.log(ext)
if(ext == "html" || ext == "htm") {
ui.openHtml(path)
}else if(ext == "qml"){
ui.openQml(path)
}
} }
} }

@ -103,6 +103,12 @@ ApplicationWindow {
postData(data._seed,stateObject) postData(data._seed,stateObject)
break break
case "getTransactionsFor":
require(1);
var txs = eth.getTransactionsFor(data.args[0], true)
postData(data._seed, txs)
break
case "getBalance": case "getBalance":
require(1); require(1);

@ -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()
}

@ -26,7 +26,7 @@ func NewDebuggerWindow(lib *UiLib) *DebuggerWindow {
} }
win := component.CreateWindow(nil) win := component.CreateWindow(nil)
db := &Debugger{win, make(chan bool), make(chan bool), true, false} db := &Debugger{win, make(chan bool), make(chan bool), true, false, true}
return &DebuggerWindow{engine: engine, win: win, lib: lib, Db: db} return &DebuggerWindow{engine: engine, win: win, lib: lib, Db: db}
} }
@ -59,6 +59,7 @@ func (self *DebuggerWindow) Debug(valueStr, gasStr, gasPriceStr, scriptStr, data
if !self.Db.done { if !self.Db.done {
self.Db.Q <- true self.Db.Q <- true
} }
self.Db.breakOnInstr = self.win.Root().ObjectByName("breakEachLine").Bool("checked")
defer func() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
@ -95,16 +96,20 @@ func (self *DebuggerWindow) Debug(valueStr, gasStr, gasPriceStr, scriptStr, data
self.win.Root().Call("setAsm", str) self.win.Root().Call("setAsm", str)
} }
gas := ethutil.Big(gasStr) var (
gasPrice := ethutil.Big(gasPriceStr) gas = ethutil.Big(gasStr)
// Contract addr as test address gasPrice = ethutil.Big(gasPriceStr)
keyPair := ethutil.GetKeyRing().Get(0) value = ethutil.Big(valueStr)
callerTx := ethchain.NewContractCreationTx(ethutil.Big(valueStr), gas, gasPrice, script) // Contract addr as test address
keyPair = ethutil.GetKeyRing().Get(0)
callerTx = ethchain.NewContractCreationTx(ethutil.Big(valueStr), gas, gasPrice, script)
)
callerTx.Sign(keyPair.PrivateKey) callerTx.Sign(keyPair.PrivateKey)
state := self.lib.eth.BlockChain().CurrentBlock.State() state := self.lib.eth.BlockChain().CurrentBlock.State()
account := self.lib.eth.StateManager().TransState().GetAccount(keyPair.Address()) account := self.lib.eth.StateManager().TransState().GetAccount(keyPair.Address())
contract := ethchain.MakeContract(callerTx, state) contract := ethchain.MakeContract(callerTx, state)
contract.Amount = value
callerClosure := ethchain.NewClosure(account, contract, script, state, gas, gasPrice) callerClosure := ethchain.NewClosure(account, contract, script, state, gas, gasPrice)
block := self.lib.eth.BlockChain().CurrentBlock block := self.lib.eth.BlockChain().CurrentBlock
@ -164,6 +169,7 @@ type Debugger struct {
N chan bool N chan bool
Q chan bool Q chan bool
done, interrupt bool done, interrupt bool
breakOnInstr bool
} }
type storeVal struct { type storeVal struct {
@ -190,16 +196,18 @@ func (d *Debugger) halting(pc int, op ethchain.OpCode, mem *ethchain.Memory, sta
d.win.Root().Call("setStorage", storeVal{fmt.Sprintf("% x", key), fmt.Sprintf("% x", node.Str())}) d.win.Root().Call("setStorage", storeVal{fmt.Sprintf("% x", key), fmt.Sprintf("% x", node.Str())})
}) })
out: if d.breakOnInstr {
for { out:
select { for {
case <-d.N: select {
break out case <-d.N:
case <-d.Q: break out
d.interrupt = true case <-d.Q:
d.clearBuffers() d.interrupt = true
d.clearBuffers()
return false return false
}
} }
} }

@ -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
@ -32,11 +35,13 @@ 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,11 +57,11 @@ 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) {
const version = "0.5.0 RC14" const version = "0.5.0 RC15"
defer gui.txDb.Close() defer gui.txDb.Close()
@ -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() {
@ -154,10 +173,6 @@ func (gui *Gui) createWindow(comp qml.Object) *qml.Window {
gui.win = win gui.win = win
gui.uiLib.win = win gui.uiLib.win = win
db := &Debugger{gui.win, make(chan bool), make(chan bool), true, false}
gui.lib.Db = db
gui.uiLib.Db = db
return gui.win return gui.win
} }
func (gui *Gui) setInitialBlockChain() { func (gui *Gui) setInitialBlockChain() {
@ -315,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)
@ -357,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)
} }
} }
}() }()

59
ethereal/ui/qml_app.go Normal file

@ -0,0 +1,59 @@
package ethui
import (
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethpub"
"github.com/ethereum/eth-go/ethutil"
"github.com/go-qml/qml"
)
type QmlApplication struct {
win *qml.Window
engine *qml.Engine
lib *UiLib
path string
}
func NewQmlApplication(path string, lib *UiLib) *QmlApplication {
engine := qml.NewEngine()
return &QmlApplication{engine: engine, path: path, lib: lib}
}
func (app *QmlApplication) Create() error {
component, err := app.engine.LoadFile(app.path)
if err != nil {
logger.Warnln(err)
}
app.win = component.CreateWindow(nil)
return nil
}
func (app *QmlApplication) Destroy() {
app.engine.Destroy()
}
func (app *QmlApplication) NewWatcher(quitChan chan bool) {
}
// Events
func (app *QmlApplication) NewBlock(block *ethchain.Block) {
pblock := &ethpub.PBlock{Number: int(block.BlockInfo().Number), Hash: ethutil.Hex(block.Hash())}
app.win.Call("onNewBlockCb", pblock)
}
func (app *QmlApplication) ObjectChanged(stateObject *ethchain.StateObject) {
app.win.Call("onObjectChangeCb", ethpub.NewPStateObject(stateObject))
}
func (app *QmlApplication) StorageChanged(storageObject *ethchain.StorageState) {
app.win.Call("onStorageChangeCb", ethpub.NewPStorageState(storageObject))
}
// Getters
func (app *QmlApplication) Engine() *qml.Engine {
return app.engine
}
func (app *QmlApplication) Window() *qml.Window {
return app.win
}

@ -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,24 +25,14 @@ 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}
} }
// Opens a QML file (external application) func (ui *UiLib) OpenQml(path string) {
func (ui *UiLib) Open(path string) { container := NewQmlApplication(path[7:], ui)
component, err := ui.engine.LoadFile(path[7:]) app := NewExtApplication(container, ui)
if err != nil {
ethutil.Config.Log.Debugln(err)
}
win := component.CreateWindow(nil)
go func() { go app.run()
win.Show()
win.Wait()
}()
} }
func (ui *UiLib) OpenHtml(path string) { func (ui *UiLib) OpenHtml(path string) {
@ -59,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
} }
@ -88,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))
@ -111,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() {
@ -138,6 +144,7 @@ func (self *JSRE) initStdFuncs() {
eth.Set("require", self.require) eth.Set("require", self.require)
eth.Set("stopMining", self.stopMining) eth.Set("stopMining", self.stopMining)
eth.Set("startMining", self.startMining) eth.Set("startMining", self.startMining)
eth.Set("execBlock", self.execBlock)
} }
/* /*
@ -207,3 +214,18 @@ func (self *JSRE) require(call otto.FunctionCall) otto.Value {
return t return t
} }
func (self *JSRE) execBlock(call otto.FunctionCall) otto.Value {
hash, err := call.Argument(0).ToString()
if err != nil {
return otto.UndefinedValue()
}
err = utils.BlockDo(self.ethereum, ethutil.FromHex(hash))
if err != nil {
fmt.Println(err)
return otto.FalseValue()
}
return otto.TrueValue()
}

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()
}

@ -1,10 +1,15 @@
package main package main
import ( import (
"bufio"
"fmt" "fmt"
"github.com/ethereum/eth-go" "github.com/ethereum/eth-go"
"github.com/ethereum/eth-go/ethpub" "github.com/ethereum/eth-go/ethpub"
"github.com/ethereum/eth-go/ethutil"
"github.com/obscuren/otto" "github.com/obscuren/otto"
"io"
"os"
"path"
) )
type Repl interface { type Repl interface {
@ -16,18 +21,48 @@ type JSRepl struct {
re *JSRE re *JSRE
prompt string prompt string
history *os.File
running bool
} }
func NewJSRepl(ethereum *eth.Ethereum) *JSRepl { func NewJSRepl(ethereum *eth.Ethereum) *JSRepl {
return &JSRepl{re: NewJSRE(ethereum), prompt: "> "} 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: NewJSRE(ethereum), prompt: "> ", history: hist}
} }
func (self *JSRepl) Start() { func (self *JSRepl) Start() {
self.read() 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() { func (self *JSRepl) Stop() {
self.re.Stop() if self.running {
self.running = false
self.re.Stop()
logger.Infoln("exit JS Console")
self.history.Close()
}
} }
func (self *JSRepl) parseInput(code string) { func (self *JSRepl) parseInput(code string) {

@ -102,7 +102,9 @@ L:
break L break L
} }
addHistory(str[:len(str)-1]) //allow user to recall this line hist := str[:len(str)-1]
addHistory(hist) //allow user to recall this line
self.history.WriteString(str)
self.parseInput(str) self.parseInput(str)

@ -1,19 +1,186 @@
package utils package utils
import ( import (
"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()
} }
@ -21,54 +188,58 @@ 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)
addr := keyPair.Address()
go func() {
miner = ethminer.NewDefaultMiner(addr, ethereum)
// Give it some time to connect with peers
time.Sleep(3 * time.Second)
for ethereum.IsUpToDate() == false {
time.Sleep(5 * time.Second)
} }
keyPair := ethutil.GetKeyRing().Get(0)
addr := keyPair.Address()
ethutil.Config.Log.Infoln("Miner started") go func() {
miner = ethminer.NewDefaultMiner(addr, ethereum)
miner := ethminer.NewDefaultMiner(addr, ethereum) // Give it some time to connect with peers
miner.Start() time.Sleep(3 * time.Second)
}() logger.Infoln("Miner started")
miner := ethminer.NewDefaultMiner(addr, ethereum)
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 return false
} }
func StartMining(ethereum *eth.Ethereum) bool { // Replay block
if !ethereum.Mining { func BlockDo(ethereum *eth.Ethereum, hash []byte) error {
DoMining(ethereum) block := ethereum.BlockChain().GetBlock(hash)
if block == nil {
return true return fmt.Errorf("unknown block %x", hash)
} }
return false parent := ethereum.BlockChain().GetBlock(block.PrevHash)
_, err := ethereum.StateManager().ApplyDiff(parent.State(), parent, block)
if err != nil {
return err
}
return nil
} }

@ -1,41 +0,0 @@
package utils
import (
"fmt"
"github.com/obscuren/mutan"
"strings"
)
// General compile function
func Compile(script string) ([]byte, error) {
byteCode, errors := mutan.Compile(strings.NewReader(script), false)
if len(errors) > 0 {
var errs string
for _, er := range errors {
if er != nil {
errs += er.Error()
}
}
return nil, fmt.Errorf("%v", errs)
}
return byteCode, nil
}
func CompileScript(script string) ([]byte, []byte, error) {
// Preprocess
mainInput, initInput := mutan.PreParse(script)
// Compile main script
mainScript, err := Compile(mainInput)
if err != nil {
return nil, nil, err
}
// Compile init script
initScript, err := Compile(initInput)
if err != nil {
return nil, nil, err
}
return mainScript, initScript, nil
}