Merge branch 'release/poc5-rc4'

pull/84/head poc5-rc4
obscuren 11 years ago
commit 1adfc272a8
  1. 17
      ethereal/assets/ext/ethereum.js
  2. 262
      ethereal/assets/qml/first_run.qml
  3. 31
      ethereal/assets/qml/webapp.qml
  4. 43
      ethereal/assets/util/test.html
  5. 2
      ethereal/config.go
  6. 14
      ethereal/ethereum.go
  7. 2
      ethereal/ui/ext_app.go
  8. 117
      ethereal/ui/gui.go
  9. 2
      ethereum/config.go
  10. 2
      ethereum/dev_console.go
  11. 48
      ethereum/ethereum.go

@ -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 = {}

@ -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"
id: wizardRoot
width: 500
height: 400
title: "Ethereal first run setup"
Column {
spacing: 5
anchors.leftMargin: 10
anchors.left: parent.left
Column {
spacing: 5
anchors.leftMargin: 10
anchors.left: parent.left
Text {
visible: true
text: "<h2>Ethereal setup</h2>"
}
Text {
visible: true
text: "<h2>Ethereal setup</h2>"
}
Column {
id: restoreColumn
spacing: 5
Text {
visible: true
font.pointSize: 14
text: "Restore your Ethereum account"
id: restoreLabel
}
Column {
id: restoreColumn
spacing: 5
Text {
visible: true
font.pointSize: 14
text: "Restore your Ethereum account"
id: restoreLabel
}
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
}
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
}
}
}
}
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
}
}
Column {
id: importedDetails
visible: false
Text {
text: "<b>Your account has been imported. Please close the application and restart it again to let the changes take effect.</b>"
wrapMode: Text.WordWrap
width: 460
}
}
Text {
id: detailLabel
font.pointSize: 12
anchors.topMargin: 10
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: "<b>A new account has been created. Please take the time to write down the <i>24 words</i>. You can use those to restore your account at a later date.</b>"
wrapMode: Text.WordWrap
width: 480
}
Label {
text: "Please restart the application once you have completed the steps above."
wrapMode: Text.WordWrap
width: 480
}
}
}
}
Column {
id: importedDetails
visible: false
Text {
text: "<b>Your account has been imported. Please close the application and restart it again to let the changes take effect.</b>"
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: "<b>A new account has been created. Please take the time to write down the <i>24 words</i>. You can use those to restore your account at a later date.</b>"
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]
}
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
// Hide restore
restoreColumn.visible = false
// Show new details
newDetailsColumn.visible = true
newKey.visible = false
// Show new details
newDetailsColumn.visible = true
newKey.visible = false
}
}
}
}

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

@ -0,0 +1,43 @@
<html>
<head>
<title>Utils</title>
</head>
<body onload="init();">
<label>Nonce for 2ef47100e0787b915105fd5e3f4ff6752079d5cb</label>
<p id="nonce"></p>
<label>Connected peers</label>
<p id="peers"></p>
<label>Is mining</label>
<p id="isMining"></p>
<label>Is listening</label>
<p id="isListen"></p>
<label>Coinbase</label>
<p id="coinbase"></p>
<script type="text/javascript">
function init() {
eth.getTxCountAt("2ef47100e0787b915105fd5e3f4ff6752079d5cb", function(nonce){
document.querySelector("#nonce").innerHTML = nonce;
})
eth.getPeerCount(function(peerLength){
document.querySelector("#peers").innerHTML = peerLength;
})
eth.getIsMining(function(mining){
document.querySelector("#isMining").innerHTML = mining;
})
eth.getIsListening(function(listen){
document.querySelector("#isListen").innerHTML = listen;
})
eth.getCoinBase(function(address){
document.querySelector("#coinbase").innerHTML = address;
})
}
</script>
</body>
</html>

@ -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)")

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

@ -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),

@ -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"))
} 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()
}
if firstRun {
component, err = gui.engine.LoadFile(uiLib.AssetPath("qml/first_run.qml"))
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,26 +132,48 @@ 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
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
}
// Add the ui as a log system so we can log directly to the UGI
ethutil.Config.Log.AddLogSystem(gui)
win := gui.createWindow(component)
// Loads previous blocks
if firstRun == false {
go gui.setInitialBlockChain()
go gui.readPreviousTransactions()
go gui.update()
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
}
gui.win.Show()
gui.win.Wait()
return gui.createWindow(component), nil
}
gui.eth.Stop()
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() {
@ -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 {

@ -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")

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

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

Loading…
Cancel
Save