diff --git a/ethereal/assets/ext/ethereum.js b/ethereal/assets/ext/ethereum.js
index f565e58bd..d4eaf97fd 100644
--- a/ethereal/assets/ext/ethereum.js
+++ b/ethereal/assets/ext/ethereum.js
@@ -36,6 +36,21 @@ window.eth = {
postData({call: "getKey"}, cb);
},
+ getTxCountAt: function(address, cb) {
+ postData({call: "getTxCountAt", args: [address]}, cb);
+ },
+ getIsMining: function(cb){
+ postData({call: "getIsMining"}, cb)
+ },
+ getIsListening: function(cb){
+ postData({call: "getIsListening"}, cb)
+ },
+ getCoinBase: function(cb){
+ postData({call: "getCoinBase"}, cb);
+ },
+ getPeerCount: function(cb){
+ postData({call: "getPeerCount"}, cb);
+ },
getBalanceAt: function(address, cb) {
postData({call: "getBalance", args: [address]}, cb);
},
@@ -115,6 +130,8 @@ window.eth = {
}
}
},
+
+
}
window.eth._callbacks = {}
window.eth._onCallbacks = {}
diff --git a/ethereal/assets/qml/first_run.qml b/ethereal/assets/qml/first_run.qml
index 0bd3b4ce1..0b1dac4c6 100644
--- a/ethereal/assets/qml/first_run.qml
+++ b/ethereal/assets/qml/first_run.qml
@@ -10,146 +10,146 @@ import QtQuick.Controls.Styles 1.1
import QtQuick.Dialogs 1.1
ApplicationWindow {
- id: wizardRoot
- width: 500
- height: 400
- title: "Ethereal first run setup"
-
- Column {
- spacing: 5
- anchors.leftMargin: 10
- anchors.left: parent.left
-
- Text {
- visible: true
- text: "
Ethereal setup
"
- }
+ id: wizardRoot
+ width: 500
+ height: 400
+ title: "Ethereal first run setup"
Column {
- id: restoreColumn
- spacing: 5
- Text {
- visible: true
- font.pointSize: 14
- text: "Restore your Ethereum account"
- id: restoreLabel
- }
+ spacing: 5
+ anchors.leftMargin: 10
+ anchors.left: parent.left
- TextField {
- id: txPrivKey
- width: 480
- placeholderText: "Private key or mnemonic words"
- focus: true
- onTextChanged: {
- if(this.text.length == 64){
- detailLabel.text = "Private (hex) key detected."
- actionButton.enabled = true
- }
- else if(this.text.split(" ").length == 24){
- detailLabel.text = "Mnemonic key detected."
- actionButton.enabled = true
- }else{
- detailLabel.text = ""
- actionButton.enabled = false
- }
- }
- }
- Row {
- spacing: 10
- Button {
- id: actionButton
- text: "Restore"
- enabled: false
- onClicked: {
- var success = eth.importAndSetPrivKey(txPrivKey.text)
- if(success){
- importedDetails.visible = true
- restoreColumn.visible = false
- newKey.visible = false
- wizardRoot.height = 120
- }
- }
- }
Text {
- id: detailLabel
- font.pointSize: 12
- anchors.topMargin: 10
+ visible: true
+ text: "Ethereal setup
"
}
- }
- }
- Column {
- id: importedDetails
- visible: false
- Text {
- text: "Your account has been imported. Please close the application and restart it again to let the changes take effect."
- wrapMode: Text.WordWrap
- width: 460
- }
- }
- Column {
- spacing: 5
- id: newDetailsColumn
- visible: false
- Text {
- font.pointSize: 14
- text: "Your account details"
- }
- Label {
- text: "Address"
- }
- TextField {
- id: addressInput
- readOnly:true
- width: 480
- }
- Label {
- text: "Private key"
- }
- TextField {
- id: privkeyInput
- readOnly:true
- width: 480
- }
- Label {
- text: "Mnemonic words"
- }
- TextField {
- id: mnemonicInput
- readOnly:true
- width: 480
- }
- Label {
- text: "A new account has been created. Please take the time to write down the 24 words. You can use those to restore your account at a later date."
- wrapMode: Text.WordWrap
- width: 480
- }
- Label {
- text: "Please restart the application once you have completed the steps above."
- wrapMode: Text.WordWrap
- width: 480
- }
- }
- }
- Button {
- anchors.right: parent.right
- anchors.bottom: parent.bottom
- anchors.rightMargin: 10
- anchors.bottomMargin: 10
- id: newKey
- text: "I don't have an account yet"
- onClicked: {
- var res = eth.createAndSetPrivKey()
- mnemonicInput.text = res[0]
- addressInput.text = res[1]
- privkeyInput.text = res[2]
+ Column {
+ id: restoreColumn
+ spacing: 5
+ Text {
+ visible: true
+ font.pointSize: 14
+ text: "Restore your Ethereum account"
+ id: restoreLabel
+ }
- // Hide restore
- restoreColumn.visible = false
+ TextField {
+ id: txPrivKey
+ width: 480
+ placeholderText: "Private key or mnemonic words"
+ focus: true
+ onTextChanged: {
+ if(this.text.length == 64){
+ detailLabel.text = "Private (hex) key detected."
+ actionButton.enabled = true
+ }
+ else if(this.text.split(" ").length == 24){
+ detailLabel.text = "Mnemonic key detected."
+ actionButton.enabled = true
+ }else{
+ detailLabel.text = ""
+ actionButton.enabled = false
+ }
+ }
+ }
+ Row {
+ spacing: 10
+ Button {
+ id: actionButton
+ text: "Restore"
+ enabled: false
+ onClicked: {
+ var success = lib.importAndSetPrivKey(txPrivKey.text)
+ if(success){
+ importedDetails.visible = true
+ restoreColumn.visible = false
+ newKey.visible = false
+ wizardRoot.height = 120
+ }
+ }
+ }
+ Text {
+ id: detailLabel
+ font.pointSize: 12
+ anchors.topMargin: 10
+ }
+ }
+ }
+ Column {
+ id: importedDetails
+ visible: false
+ Text {
+ text: "Your account has been imported. Please close the application and restart it again to let the changes take effect."
+ wrapMode: Text.WordWrap
+ width: 460
+ }
+ }
+ Column {
+ spacing: 5
+ id: newDetailsColumn
+ visible: false
+ Text {
+ font.pointSize: 14
+ text: "Your account details"
+ }
+ Label {
+ text: "Address"
+ }
+ TextField {
+ id: addressInput
+ readOnly:true
+ width: 480
+ }
+ Label {
+ text: "Private key"
+ }
+ TextField {
+ id: privkeyInput
+ readOnly:true
+ width: 480
+ }
+ Label {
+ text: "Mnemonic words"
+ }
+ TextField {
+ id: mnemonicInput
+ readOnly:true
+ width: 480
+ }
+ Label {
+ text: "A new account has been created. Please take the time to write down the 24 words. You can use those to restore your account at a later date."
+ wrapMode: Text.WordWrap
+ width: 480
+ }
+ Label {
+ text: "Please restart the application once you have completed the steps above."
+ wrapMode: Text.WordWrap
+ width: 480
+ }
+ }
- // Show new details
- newDetailsColumn.visible = true
- newKey.visible = false
}
- }
+ Button {
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ anchors.rightMargin: 10
+ anchors.bottomMargin: 10
+ id: newKey
+ text: "I don't have an account yet"
+ onClicked: {
+ var res = lib.createAndSetPrivKey()
+ mnemonicInput.text = res[0]
+ addressInput.text = res[1]
+ privkeyInput.text = res[2]
+
+ // Hide restore
+ restoreColumn.visible = false
+
+ // Show new details
+ newDetailsColumn.visible = true
+ newKey.visible = false
+ }
+ }
}
diff --git a/ethereal/assets/qml/webapp.qml b/ethereal/assets/qml/webapp.qml
index 1f3c3874a..7af006f77 100644
--- a/ethereal/assets/qml/webapp.qml
+++ b/ethereal/assets/qml/webapp.qml
@@ -47,13 +47,37 @@ ApplicationWindow {
try {
switch(data.call) {
+ case "getCoinBase":
+ postData(data._seed, eth.getCoinBase())
+
+ break
+ case "getIsListening":
+ postData(data._seed, eth.getIsListening())
+
+ break
+ case "getIsMining":
+ postData(data._seed, eth.getIsMining())
+
+ break
+ case "getPeerCount":
+ postData(data._seed, eth.getPeerCount())
+
+ break
+
+ case "getTxCountAt":
+ require(1)
+ postData(data._seed, eth.getTxCountAt(data.args[0]))
+
+ break
case "getBlockByNumber":
- var block = eth.getBlock("b9b56cf6f907fbee21db0cd7cbc0e6fea2fe29503a3943e275c5e467d649cb06")
+ var block = eth.getBlock("b9b56cf6f907fbee21db0cd7cbc0e6fea2fe29503a3943e275c5e467d649cb06")
postData(data._seed, block)
+
break
case "getBlockByHash":
- var block = eth.getBlock("b9b56cf6f907fbee21db0cd7cbc0e6fea2fe29503a3943e275c5e467d649cb06")
+ var block = eth.getBlock("b9b56cf6f907fbee21db0cd7cbc0e6fea2fe29503a3943e275c5e467d649cb06")
postData(data._seed, block)
+
break
case "transact":
require(5)
@@ -94,11 +118,14 @@ ApplicationWindow {
postData(data._seed, null)
break;
case "set":
+ console.log("'Set' has been depcrecated")
+ /*
for(var key in data.args) {
if(webview.hasOwnProperty(key)) {
window[key] = data.args[key];
}
}
+ */
break;
case "getSecretToAddress":
require(1)
diff --git a/ethereal/assets/util/test.html b/ethereal/assets/util/test.html
new file mode 100644
index 000000000..d458e6670
--- /dev/null
+++ b/ethereal/assets/util/test.html
@@ -0,0 +1,43 @@
+
+
+Utils
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ethereal/config.go b/ethereal/config.go
index 94f896c5f..e4bdb0a00 100644
--- a/ethereal/config.go
+++ b/ethereal/config.go
@@ -7,6 +7,7 @@ import (
var StartConsole bool
var StartMining bool
var StartRpc bool
+var RpcPort int
var UseUPnP bool
var OutboundPort string
var ShowGenesis bool
@@ -28,6 +29,7 @@ func Init() {
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.IntVar(&RpcPort, "rpcport", 8080, "port to start json-rpc server on")
flag.StringVar(&OutboundPort, "p", "30303", "listening port")
flag.StringVar(&DataDir, "dir", ".ethereal", "ethereum data directory")
flag.StringVar(&ImportKey, "import", "", "imports the given private key (hex)")
diff --git a/ethereal/ethereum.go b/ethereal/ethereum.go
index 8b8889e37..15a454bdf 100644
--- a/ethereal/ethereum.go
+++ b/ethereal/ethereum.go
@@ -100,8 +100,12 @@ func main() {
}
if StartRpc {
- ethereum.RpcServer = ethrpc.NewJsonRpcServer(ethpub.NewPEthereum(ethereum.StateManager(), ethereum.BlockChain(), ethereum.TxPool()))
- go ethereum.RpcServer.Start()
+ ethereum.RpcServer, err = ethrpc.NewJsonRpcServer(ethpub.NewPEthereum(ethereum), RpcPort)
+ if err != nil {
+ log.Println("Could not start RPC interface:", err)
+ } else {
+ go ethereum.RpcServer.Start()
+ }
}
log.Printf("Starting Ethereum GUI v%s\n", ethutil.Config.Ver)
@@ -110,5 +114,11 @@ func main() {
ethereum.MaxPeers = MaxPeer
gui := ethui.New(ethereum)
+
+ ethereum.Start(UseSeed)
+
gui.Start(AssetPath)
+
+ // Wait for shutdown
+ ethereum.WaitForShutdown()
}
diff --git a/ethereal/ui/ext_app.go b/ethereal/ui/ext_app.go
index 93db0ade1..de5f15db6 100644
--- a/ethereal/ui/ext_app.go
+++ b/ethereal/ui/ext_app.go
@@ -34,7 +34,7 @@ type ExtApplication struct {
func NewExtApplication(container AppContainer, lib *UiLib) *ExtApplication {
app := &ExtApplication{
- ethpub.NewPEthereum(lib.eth.StateManager(), lib.eth.BlockChain(), lib.eth.TxPool()),
+ ethpub.NewPEthereum(lib.eth),
make(chan ethutil.React, 1),
make(chan ethutil.React, 1),
make(chan bool),
diff --git a/ethereal/ui/gui.go b/ethereal/ui/gui.go
index 46bfa0133..7f84272d6 100644
--- a/ethereal/ui/gui.go
+++ b/ethereal/ui/gui.go
@@ -24,7 +24,8 @@ type Gui struct {
eth *eth.Ethereum
// The public Ethereum library
- lib *EthLib
+ lib *EthLib
+ uiLib *UiLib
txDb *ethdb.LDBDatabase
@@ -52,7 +53,7 @@ func New(ethereum *eth.Ethereum) *Gui {
//ethereum.StateManager().WatchAddr(addr)
}
- pub := ethpub.NewPEthereum(ethereum.StateManager(), ethereum.BlockChain(), ethereum.TxPool())
+ pub := ethpub.NewPEthereum(ethereum)
return &Gui{eth: ethereum, lib: lib, txDb: db, addr: addr, pub: pub}
}
@@ -67,7 +68,7 @@ func (gui *Gui) Start(assetPath string) {
Init: func(p *ethpub.PTx, obj qml.Object) { p.Value = ""; p.Hash = ""; p.Address = "" },
}})
- ethutil.Config.SetClientString(fmt.Sprintf("/Ethereal v%s", "0.5.0 RC3"))
+ ethutil.Config.SetClientString(fmt.Sprintf("/Ethereal v%s", "0.5.0 RC4"))
ethutil.Config.Log.Infoln("[GUI] Starting GUI")
// Create a new QML engine
gui.engine = qml.NewEngine()
@@ -75,19 +76,55 @@ func (gui *Gui) Start(assetPath string) {
// Expose the eth library and the ui library to QML
context.SetVar("eth", gui)
- uiLib := NewUiLib(gui.engine, gui.eth, assetPath)
- context.SetVar("ui", uiLib)
+ gui.uiLib = NewUiLib(gui.engine, gui.eth, assetPath)
+ context.SetVar("ui", gui.uiLib)
// Load the main QML interface
data, _ := ethutil.Config.Db.Get([]byte("KeyRing"))
- var err error
- var component qml.Object
- firstRun := len(data) == 0
+ /*
+ var err error
+ var component qml.Object
+ firstRun := len(data) == 0
- if firstRun {
- component, err = gui.engine.LoadFile(uiLib.AssetPath("qml/first_run.qml"))
+ if firstRun {
+ component, err = gui.engine.LoadFile(uiLib.AssetPath("qml/first_run.qml"))
+ } else {
+ component, err = gui.engine.LoadFile(uiLib.AssetPath("qml/wallet.qml"))
+ }
+ 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'")
+
+ panic(err)
+ }
+
+ gui.win = component.CreateWindow(nil)
+ uiLib.win = gui.win
+ db := &Debugger{gui.win, make(chan bool)}
+ gui.lib.Db = db
+ uiLib.Db = db
+
+ // Add the ui as a log system so we can log directly to the UGI
+ ethutil.Config.Log.AddLogSystem(gui)
+
+ // Loads previous blocks
+ if firstRun == false {
+ go gui.setInitialBlockChain()
+ go gui.readPreviousTransactions()
+ go gui.update()
+ }
+
+ gui.win.Show()
+ gui.win.Wait()
+
+ gui.eth.Stop()
+ */
+
+ var win *qml.Window
+ var err error
+ if len(data) == 0 {
+ win, err = gui.showKeyImport(context)
} else {
- component, err = gui.engine.LoadFile(uiLib.AssetPath("qml/wallet.qml"))
+ win, err = gui.showWallet(context)
}
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'")
@@ -95,28 +132,50 @@ func (gui *Gui) Start(assetPath string) {
panic(err)
}
- gui.win = component.CreateWindow(nil)
- uiLib.win = gui.win
- db := &Debugger{gui.win, make(chan bool)}
- gui.lib.Db = db
- uiLib.Db = db
-
- // Add the ui as a log system so we can log directly to the UGI
- ethutil.Config.Log.AddLogSystem(gui)
-
- // Loads previous blocks
- if firstRun == false {
- go gui.setInitialBlockChain()
- go gui.readPreviousTransactions()
- go gui.update()
- }
-
- gui.win.Show()
- gui.win.Wait()
+ win.Show()
+ win.Wait()
gui.eth.Stop()
}
+func (gui *Gui) showWallet(context *qml.Context) (*qml.Window, error) {
+ component, err := gui.engine.LoadFile(gui.uiLib.AssetPath("qml/wallet.qml"))
+ if err != nil {
+ return nil, err
+ }
+
+ win := gui.createWindow(component)
+
+ go gui.setInitialBlockChain()
+ go gui.readPreviousTransactions()
+ go gui.update()
+
+ return win, nil
+}
+
+func (gui *Gui) showKeyImport(context *qml.Context) (*qml.Window, error) {
+ context.SetVar("lib", gui.lib)
+ component, err := gui.engine.LoadFile(gui.uiLib.AssetPath("qml/first_run.qml"))
+ if err != nil {
+ return nil, err
+ }
+
+ return gui.createWindow(component), nil
+}
+
+func (gui *Gui) createWindow(comp qml.Object) *qml.Window {
+ win := comp.CreateWindow(nil)
+
+ gui.win = win
+ gui.uiLib.win = win
+
+ db := &Debugger{gui.win, make(chan bool)}
+ gui.lib.Db = db
+ gui.uiLib.Db = db
+
+ return gui.win
+}
+
func (gui *Gui) setInitialBlockChain() {
// Load previous 10 blocks
chain := gui.eth.BlockChain().GetChain(gui.eth.BlockChain().CurrentBlock.Hash(), 10)
@@ -148,7 +207,7 @@ func (gui *Gui) update() {
state := gui.eth.StateManager().TransState()
unconfirmedFunds := new(big.Int)
- gui.win.Root().Call("setWalletValue", fmt.Sprintf("%v", ethutil.CurrencyToString(state.GetStateObject(gui.addr).Amount)))
+ gui.win.Root().Call("setWalletValue", fmt.Sprintf("%v", ethutil.CurrencyToString(state.GetAccount(gui.addr).Amount)))
for {
select {
@@ -156,7 +215,7 @@ func (gui *Gui) update() {
tx := txMsg.Tx
if txMsg.Type == ethchain.TxPre {
- object := state.GetStateObject(gui.addr)
+ object := state.GetAccount(gui.addr)
if bytes.Compare(tx.Sender(), gui.addr) == 0 && object.Nonce <= tx.Nonce {
gui.win.Root().Call("addTx", ethpub.NewPTx(tx))
@@ -182,7 +241,7 @@ func (gui *Gui) update() {
gui.win.Root().Call("setWalletValue", str)
} else {
- object := state.GetStateObject(gui.addr)
+ object := state.GetAccount(gui.addr)
if bytes.Compare(tx.Sender(), gui.addr) == 0 {
object.SubAmount(tx.Value)
} else if bytes.Compare(tx.Recipient, gui.addr) == 0 {
diff --git a/ethereum/config.go b/ethereum/config.go
index 234e79f12..7ca1a9801 100644
--- a/ethereum/config.go
+++ b/ethereum/config.go
@@ -7,6 +7,7 @@ import (
var StartConsole bool
var StartMining bool
var StartRpc bool
+var RpcPort int
var UseUPnP bool
var OutboundPort string
var ShowGenesis bool
@@ -26,6 +27,7 @@ func Init() {
flag.BoolVar(&ShowGenesis, "g", false, "prints genesis header and exits")
//flag.BoolVar(&UseGui, "gui", true, "use the gui")
flag.BoolVar(&StartRpc, "r", false, "start rpc server")
+ flag.IntVar(&RpcPort, "rpcport", 8080, "port to start json-rpc server on")
flag.BoolVar(&NonInteractive, "y", false, "non-interactive mode (say yes to confirmations)")
flag.BoolVar(&UseUPnP, "upnp", false, "enable UPnP support")
flag.BoolVar(&UseSeed, "seed", true, "seed peers")
diff --git a/ethereum/dev_console.go b/ethereum/dev_console.go
index d2be43205..9bdd58942 100644
--- a/ethereum/dev_console.go
+++ b/ethereum/dev_console.go
@@ -191,7 +191,7 @@ func (i *Console) ParseInput(input string) bool {
case "contract":
fmt.Println("Contract editor (Ctrl-D = done)")
- mainInput, initInput := mutan.PreProcess(i.Editor())
+ mainInput, initInput := mutan.PreParse(i.Editor())
mainScript, err := utils.Compile(mainInput)
if err != nil {
fmt.Println(err)
diff --git a/ethereum/ethereum.go b/ethereum/ethereum.go
index 2f05bf2a1..babebbb48 100644
--- a/ethereum/ethereum.go
+++ b/ethereum/ethereum.go
@@ -1,6 +1,7 @@
package main
import (
+ "encoding/hex"
"fmt"
"github.com/ethereum/eth-go"
"github.com/ethereum/eth-go/ethchain"
@@ -122,24 +123,8 @@ func main() {
// Set the max peers
ethereum.MaxPeers = MaxPeer
- if StartConsole {
- err := os.Mkdir(ethutil.Config.ExecPath, os.ModePerm)
- // Error is OK if the error is ErrExist
- if err != nil && !os.IsExist(err) {
- log.Panic("Unable to create EXECPATH:", err)
- }
-
- console := NewConsole(ethereum)
- go console.Start()
- }
- if StartRpc {
- ethereum.RpcServer = ethrpc.NewJsonRpcServer(ethpub.NewPEthereum(ethereum.StateManager(), ethereum.BlockChain(), ethereum.TxPool()))
- go ethereum.RpcServer.Start()
- }
-
- RegisterInterrupts(ethereum)
-
- ethereum.Start(UseSeed)
+ // Set Mining status
+ ethereum.Mining = StartMining
if StartMining {
logger.Infoln("Miner started")
@@ -155,7 +140,9 @@ func main() {
keyRing := ethutil.NewValueFromBytes(data)
addr := keyRing.Get(1).Bytes()
- miner := ethminer.NewDefaultMiner(addr, ethereum)
+ pair, _ := ethchain.NewKeyPairFromSec(ethutil.FromHex(hex.EncodeToString(addr)))
+
+ miner := ethminer.NewDefaultMiner(pair.Address(), ethereum)
miner.Start()
}()
@@ -164,6 +151,29 @@ func main() {
}
+ if StartConsole {
+ err := os.Mkdir(ethutil.Config.ExecPath, os.ModePerm)
+ // Error is OK if the error is ErrExist
+ if err != nil && !os.IsExist(err) {
+ log.Panic("Unable to create EXECPATH:", err)
+ }
+
+ console := NewConsole(ethereum)
+ go console.Start()
+ }
+ if StartRpc {
+ ethereum.RpcServer, err = ethrpc.NewJsonRpcServer(ethpub.NewPEthereum(ethereum), RpcPort)
+ if err != nil {
+ logger.Infoln("Could not start RPC interface:", err)
+ } else {
+ go ethereum.RpcServer.Start()
+ }
+ }
+
+ RegisterInterrupts(ethereum)
+
+ ethereum.Start(UseSeed)
+
// Wait for shutdown
ethereum.WaitForShutdown()
}