diff --git a/README.md b/README.md
index 790ee541e1..186c979bc9 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,9 @@
Ethereum
========
-[](https://travis-ci.org/ethereum/go-ethereum)
+Master [](http://cpt-obvious.ethercasts.com:8010/builders/go-ethereum-master-docker/builds/-1) Develop [](http://cpt-obvious.ethercasts.com:8010/builders/go-ethereum-develop-docker/builds/-1)
Ethereum Go Client © 2014 Jeffrey Wilcke.
diff --git a/ethereal/assets/ext/home.html b/ethereal/assets/ext/home.html
new file mode 100644
index 0000000000..86a659d65f
--- /dev/null
+++ b/ethereal/assets/ext/home.html
@@ -0,0 +1,21 @@
+
+
+
+Ethereum
+
+
+
+
+
+... Ethereum ...
+
+
+
+
diff --git a/ethereal/assets/ext/messaging.js b/ethereal/assets/ext/messaging.js
new file mode 100644
index 0000000000..e7bc630202
--- /dev/null
+++ b/ethereal/assets/ext/messaging.js
@@ -0,0 +1,117 @@
+function handleMessage(message) {
+ console.log("[onMessageReceived]: ", message.data)
+ // TODO move to messaging.js
+ var data = JSON.parse(message.data)
+
+ 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(data.args[0])
+ postData(data._seed, block)
+
+ break
+ case "getBlockByHash":
+ var block = eth.getBlock(data.args[0])
+ postData(data._seed, block)
+
+ break
+ case "transact":
+ require(5)
+
+ var tx = eth.transact(data.args[0], data.args[1], data.args[2],data.args[3],data.args[4],data.args[5])
+ postData(data._seed, tx)
+
+ break
+ case "create":
+ postData(data._seed, null)
+
+ break
+ case "getStorage":
+ require(2);
+
+ var stateObject = eth.getStateObject(data.args[0])
+ var storage = stateObject.getStorage(data.args[1])
+ postData(data._seed, storage)
+
+ break
+ case "getStateKeyVals":
+ require(1);
+ var stateObject = eth.getStateObject(data.args[0]).stateKeyVal(true)
+ postData(data._seed,stateObject)
+
+ break
+ case "getTransactionsFor":
+ require(1);
+ var txs = eth.getTransactionsFor(data.args[0], true)
+ postData(data._seed, txs)
+
+ break
+ case "getBalance":
+ require(1);
+
+ postData(data._seed, eth.getStateObject(data.args[0]).value());
+
+ break
+ case "getKey":
+ var key = eth.getKey().privateKey;
+
+ postData(data._seed, key)
+ break
+ case "watch":
+ require(1)
+ eth.watch(data.args[0], data.args[1]);
+ break
+ case "disconnect":
+ require(1)
+ 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)
+ postData(data._seed, eth.secretToAddress(data.args[0]))
+ break;
+ case "debug":
+ console.log(data.args[0]);
+ break;
+ }
+ } catch(e) {
+ console.log(data.call + ": " + e)
+
+ postData(data._seed, null);
+ }
+}
+
+function postData(seed, data) {
+ webview.experimental.postMessage(JSON.stringify({data: data, _seed: seed}))
+}
diff --git a/ethereal/assets/qml/wallet.qml b/ethereal/assets/qml/wallet.qml
index eef49824f1..e3ef148b0b 100644
--- a/ethereal/assets/qml/wallet.qml
+++ b/ethereal/assets/qml/wallet.qml
@@ -26,6 +26,27 @@ ApplicationWindow {
shortcut: "Ctrl+o"
onTriggered: openAppDialog.open()
}
+
+ MenuItem {
+ text: "Browser"
+ onTriggered: ui.openBrowser()
+ }
+
+ MenuSeparator {}
+
+ MenuItem {
+ text: "Import key"
+ shortcut: "Ctrl+i"
+ onTriggered: importDialog.open()
+ }
+
+ MenuItem {
+ text: "Export keys"
+ shortcut: "Ctrl+e"
+ onTriggered: exportDialog.open()
+ }
+
+ //MenuSeparator {}
}
Menu {
@@ -35,6 +56,13 @@ ApplicationWindow {
shortcut: "Ctrl+d"
onTriggered: ui.startDebugger()
}
+
+ MenuItem {
+ text: "Import Tx"
+ onTriggered: {
+ txImportDialog.visible = true
+ }
+ }
}
Menu {
@@ -77,6 +105,7 @@ ApplicationWindow {
historyView.visible = false
newTxView.visible = false
infoView.visible = false
+ pendingTxView.visible = false
view.visible = true
//root.title = "Ethereal - " = view.title
}
@@ -140,6 +169,17 @@ ApplicationWindow {
}
}
}
+
+ Image {
+ source: "../tx.png"
+ anchors.horizontalCenter: parent.horizontalCenter
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ setView(pendingTxView)
+ }
+ }
+ }
}
}
@@ -344,6 +384,28 @@ ApplicationWindow {
}
}
+ Rectangle {
+ anchors.fill: parent
+ visible: false
+ id: pendingTxView
+ property var title: "Pending Transactions"
+
+ property var pendingTxModel: ListModel {
+ id: pendingTxModel
+ }
+
+ TableView {
+ id: pendingTxTableView
+ anchors.fill: parent
+ TableViewColumn{ role: "value" ; title: "Value" ; width: 100 }
+ TableViewColumn{ role: "from" ; title: "sender" ; width: 230 }
+ TableViewColumn{ role: "to" ; title: "Reciever" ; width: 230 }
+ TableViewColumn{ role: "contract" ; title: "Contract" ; width: 100 }
+
+ model: pendingTxModel
+ }
+ }
+
/*
signal addPlugin(string name)
Component {
@@ -375,9 +437,7 @@ ApplicationWindow {
//ui.open(openAppDialog.fileUrl.toString())
//ui.openHtml(Qt.resolvedUrl(ui.assetPath("test.html")))
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"){
@@ -386,6 +446,22 @@ ApplicationWindow {
}
}
+ FileDialog {
+ id: exportDialog
+ title: "Export keys"
+ onAccepted: {
+ }
+ }
+
+ FileDialog {
+ id: importDialog
+ title: "Import key"
+ onAccepted: {
+ var path = this.fileUrl.toString()
+ ui.importKey(path)
+ }
+ }
+
statusBar: StatusBar {
height: 30
RowLayout {
@@ -465,6 +541,36 @@ ApplicationWindow {
}
}
+ Window {
+ id: txImportDialog
+ minimumWidth: 270
+ maximumWidth: 270
+ maximumHeight: 50
+ minimumHeight: 50
+ TextField {
+ id: txImportField
+ width: 170
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.left: parent.left
+ anchors.leftMargin: 10
+ onAccepted: {
+ }
+ }
+ Button {
+ anchors.left: txImportField.right
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.leftMargin: 5
+ text: "Import"
+ onClicked: {
+ eth.importTx(txImportField.text)
+ txImportField.visible = false
+ }
+ }
+ Component.onCompleted: {
+ addrField.focus = true
+ }
+ }
+
Window {
id: popup
visible: false
@@ -660,7 +766,7 @@ ApplicationWindow {
anchors.left: aboutIcon.right
anchors.leftMargin: 10
font.pointSize: 12
- text: "Ethereal
Development
Jeffrey Wilcke
Maran Hidskes
Viktor Trón
"
+ text: "Ethereal - Adrastea
Development
Jeffrey Wilcke
Maran Hidskes
Viktor Trón
"
}
}
@@ -684,7 +790,7 @@ ApplicationWindow {
walletValueLabel.text = value
}
- function addTx(tx, inout) {
+ function addTx(type, tx, inout) {
var isContract
if (tx.contract == true){
isContract = "Yes"
@@ -692,13 +798,19 @@ ApplicationWindow {
isContract = "No"
}
- var address;
- if(inout == "recv") {
- address = tx.sender;
- } else {
- address = tx.address;
+
+ if(type == "post") {
+ var address;
+ if(inout == "recv") {
+ address = tx.sender;
+ } else {
+ address = tx.address;
+ }
+
+ txModel.insert(0, {inout: inout, hash: tx.hash, address: address, value: tx.value, contract: isContract})
+ } else if(type == "pre") {
+ pendingTxModel.insert(0, {hash: tx.hash, to: tx.address, from: tx.sender, value: tx.value, contract: isContract})
}
- txModel.insert(0, {inout: inout, hash: tx.hash, address: address, value: tx.value, contract: isContract})
}
function addBlock(block, initial) {
@@ -714,7 +826,7 @@ ApplicationWindow {
if(initial){
blockModel.append({number: block.number, name: block.name, gasLimit: block.gasLimit, gasUsed: block.gasUsed, coinbase: block.coinbase, hash: block.hash, txs: txs, txAmount: amount, time: block.time, prettyTime: convertToPretty(block.time)})
- }else{
+ } else {
blockModel.insert(0, {number: block.number, name: block.name, gasLimit: block.gasLimit, gasUsed: block.gasUsed, coinbase: block.coinbase, hash: block.hash, txs: txs, txAmount: amount, time: block.time, prettyTime: convertToPretty(block.time)})
}
}
@@ -770,7 +882,7 @@ ApplicationWindow {
// ******************************************
Window {
id: peerWindow
- //flags: Qt.CustomizeWindowHint | Qt.Tool | Qt.WindowCloseButtonHint
+ //flags: Qt.CustomizeWindowHint | Qt.Tool | Qt.WindowCloseButtonHint
height: 200
width: 700
Rectangle {
@@ -897,10 +1009,10 @@ ApplicationWindow {
placeholderText: "Gas"
text: "500"
/*
- onTextChanged: {
- contractFormReady()
- }
- */
+ onTextChanged: {
+ contractFormReady()
+ }
+ */
}
Label {
id: atLabel
@@ -914,10 +1026,10 @@ ApplicationWindow {
text: "10"
validator: RegExpValidator { regExp: /\d*/ }
/*
- onTextChanged: {
- contractFormReady()
- }
- */
+ onTextChanged: {
+ contractFormReady()
+ }
+ */
}
ComboBox {
@@ -962,7 +1074,7 @@ ApplicationWindow {
var gasPrice = txGasPrice.text + denomModel.get(gasDenom.currentIndex).zeros;
var res = eth.create(txFuelRecipient.text, value, txGas.text, gasPrice, codeView.text)
if(res[1]) {
- txResult.text = "Your contract could not be send over the network:\n"
+ txResult.text = "Your contract could not be sent over the network:\n"
txResult.text += res[1].error()
txResult.text += ""
mainContractColumn.state = "ERROR"
diff --git a/ethereal/assets/qml/webapp.qml b/ethereal/assets/qml/webapp.qml
index 5e4c035d8d..15177e3fd0 100644
--- a/ethereal/assets/qml/webapp.qml
+++ b/ethereal/assets/qml/webapp.qml
@@ -21,19 +21,54 @@ ApplicationWindow {
id: root
anchors.fill: parent
state: "inspectorShown"
+ TextField {
+ anchors {
+ top: parent.top
+ left: parent.left
+ right: parent.right
+ }
+ id: uriNav
+ //text: webview.url
+
+ Keys.onReturnPressed: {
+ var reg = /(^https?\:\/\/(?:www\.)?)([a-zA-Z0-9_\-]*\.eth)(.*)/
+
+ var uri = this.text;
+ if(reg.test(uri)) {
+ this.text.replace(reg, function(match, pre, domain, path) {
+ uri = pre;
+
+ var lookup = eth.lookupDomain(domain.substring(0, domain.length - 4));
+ var ip = [];
+ for(var i = 0, l = lookup.length; i < l; i++) {
+ ip.push(lookup.charCodeAt(i))
+ }
+
+ if(ip.length != 0) {
+ uri += ip.join(".");
+ } else {
+ uri += domain;
+ }
+
+ uri += path;
+ });
+ }
+
+ console.log("connecting to ...", uri)
+
+ webview.url = uri;
+ }
+ }
WebView {
objectName: "webView"
id: webview
- anchors.fill: parent
- /*
- anchors {
- left: parent.left
- right: parent.right
- bottom: sizeGrip.top
- top: parent.top
- }
- */
+ anchors {
+ left: parent.left
+ right: parent.right
+ bottom: parent.bottom
+ top: uriNav.bottom
+ }
onTitleChanged: { window.title = title }
experimental.preferences.javascriptEnabled: true
experimental.preferences.navigatorQtObjectEnabled: true
@@ -46,50 +81,50 @@ ApplicationWindow {
try {
switch(data.call) {
- case "getCoinBase":
- postData(data._seed, eth.getCoinBase())
+ case "getCoinBase":
+ postData(data._seed, eth.getCoinBase())
- break
- case "getIsListening":
- postData(data._seed, eth.getIsListening())
+ break
+ case "getIsListening":
+ postData(data._seed, eth.getIsListening())
- break
- case "getIsMining":
- postData(data._seed, eth.getIsMining())
+ break
+ case "getIsMining":
+ postData(data._seed, eth.getIsMining())
- break
- case "getPeerCount":
- postData(data._seed, eth.getPeerCount())
+ break
+ case "getPeerCount":
+ postData(data._seed, eth.getPeerCount())
- break
+ break
- case "getTxCountAt":
- require(1)
- postData(data._seed, eth.getTxCountAt(data.args[0]))
+ case "getTxCountAt":
+ require(1)
+ postData(data._seed, eth.getTxCountAt(data.args[0]))
- break
- case "getBlockByNumber":
+ break
+ case "getBlockByNumber":
var block = eth.getBlock(data.args[0])
postData(data._seed, block)
break
- case "getBlockByHash":
+ case "getBlockByHash":
var block = eth.getBlock(data.args[0])
postData(data._seed, block)
break
- case "transact":
+ case "transact":
require(5)
var tx = eth.transact(data.args[0], data.args[1], data.args[2],data.args[3],data.args[4],data.args[5])
postData(data._seed, tx)
break
- case "create":
+ case "create":
postData(data._seed, null)
break
- case "getStorage":
+ case "getStorage":
require(2);
var stateObject = eth.getStateObject(data.args[0])
@@ -97,52 +132,52 @@ ApplicationWindow {
postData(data._seed, storage)
break
- case "getStateKeyVals":
- require(1);
- var stateObject = eth.getStateObject(data.args[0]).stateKeyVal(true)
- postData(data._seed,stateObject)
+ case "getStateKeyVals":
+ require(1);
+ var stateObject = eth.getStateObject(data.args[0]).stateKeyVal(true)
+ postData(data._seed,stateObject)
break
- case "getTransactionsFor":
- require(1);
- var txs = eth.getTransactionsFor(data.args[0], true)
- postData(data._seed, txs)
+ case "getTransactionsFor":
+ require(1);
+ var txs = eth.getTransactionsFor(data.args[0], true)
+ postData(data._seed, txs)
- break
- case "getBalance":
+ break
+ case "getBalance":
require(1);
postData(data._seed, eth.getStateObject(data.args[0]).value());
break
- case "getKey":
+ case "getKey":
var key = eth.getKey().privateKey;
postData(data._seed, key)
break
- case "watch":
+ case "watch":
require(1)
eth.watch(data.args[0], data.args[1]);
break
- case "disconnect":
+ case "disconnect":
require(1)
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];
- }
- }
- */
+ 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":
+ case "getSecretToAddress":
require(1)
postData(data._seed, eth.secretToAddress(data.args[0]))
break;
- case "debug":
+ case "debug":
console.log(data.args[0]);
break;
}
@@ -191,12 +226,12 @@ ApplicationWindow {
inspector.visible = false
}else{
inspector.visible = true
- inspector.url = webview.experimental.remoteInspectorUrl
+ inspector.url = webview.experimental.remoteInspectorUrl
}
}
onDoubleClicked: {
- console.log('refreshing')
- webView.reload()
+ console.log('refreshing')
+ webView.reload()
}
anchors.fill: parent
}
diff --git a/ethereal/debugger.go b/ethereal/debugger.go
index 0963874057..1cf5e0b664 100644
--- a/ethereal/debugger.go
+++ b/ethereal/debugger.go
@@ -2,15 +2,16 @@ package main
import (
"fmt"
+ "math/big"
+ "strconv"
+ "strings"
+
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethstate"
"github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/eth-go/ethvm"
"github.com/ethereum/go-ethereum/utils"
"github.com/go-qml/qml"
- "math/big"
- "strconv"
- "strings"
)
type DebuggerWindow struct {
@@ -134,26 +135,13 @@ func (self *DebuggerWindow) Debug(valueStr, gasStr, gasPriceStr, scriptStr, data
state := self.lib.eth.StateManager().TransState()
account := self.lib.eth.StateManager().TransState().GetAccount(keyPair.Address())
contract := ethstate.NewStateObject([]byte{0})
- contract.Amount = value
+ contract.Balance = value
self.SetAsm(script)
- callerClosure := ethvm.NewClosure(account, contract, script, gas, gasPrice)
-
block := self.lib.eth.BlockChain().CurrentBlock
- /*
- vm := ethchain.NewVm(state, self.lib.eth.StateManager(), ethchain.RuntimeVars{
- Block: block,
- Origin: account.Address(),
- BlockNumber: block.Number,
- PrevHash: block.PrevHash,
- Coinbase: block.Coinbase,
- Time: block.Time,
- Diff: block.Difficulty,
- Value: ethutil.Big(valueStr),
- })
- */
+ callerClosure := ethvm.NewClosure(account, contract, script, gas, gasPrice)
env := utils.NewEnv(state, block, account.Address(), value)
vm := ethvm.New(env)
vm.Verbose = true
diff --git a/ethereal/ext_app.go b/ethereal/ext_app.go
index ac3e090f90..697630504f 100644
--- a/ethereal/ext_app.go
+++ b/ethereal/ext_app.go
@@ -1,9 +1,9 @@
package main
import (
- "fmt"
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethpub"
+ "github.com/ethereum/eth-go/ethreact"
"github.com/ethereum/eth-go/ethstate"
"github.com/ethereum/eth-go/ethutil"
"github.com/go-qml/qml"
@@ -25,8 +25,8 @@ type AppContainer interface {
type ExtApplication struct {
*ethpub.PEthereum
- blockChan chan ethutil.React
- changeChan chan ethutil.React
+ blockChan chan ethreact.Event
+ changeChan chan ethreact.Event
quitChan chan bool
watcherQuitChan chan bool
@@ -38,8 +38,8 @@ type ExtApplication struct {
func NewExtApplication(container AppContainer, lib *UiLib) *ExtApplication {
app := &ExtApplication{
ethpub.NewPEthereum(lib.eth),
- make(chan ethutil.React, 1),
- make(chan ethutil.React, 1),
+ make(chan ethreact.Event, 100),
+ make(chan ethreact.Event, 100),
make(chan bool),
make(chan bool),
container,
@@ -58,8 +58,7 @@ func (app *ExtApplication) run() {
err := app.container.Create()
if err != nil {
- fmt.Println(err)
-
+ logger.Errorln(err)
return
}
diff --git a/ethereal/gui.go b/ethereal/gui.go
index df01cddda0..36e147ba97 100644
--- a/ethereal/gui.go
+++ b/ethereal/gui.go
@@ -3,20 +3,23 @@ package main
import (
"bytes"
"fmt"
+ "math/big"
+ "strconv"
+ "strings"
+ "time"
+
"github.com/ethereum/eth-go"
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethdb"
"github.com/ethereum/eth-go/ethlog"
"github.com/ethereum/eth-go/ethminer"
+ "github.com/ethereum/eth-go/ethpipe"
"github.com/ethereum/eth-go/ethpub"
+ "github.com/ethereum/eth-go/ethreact"
"github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/eth-go/ethwire"
"github.com/ethereum/go-ethereum/utils"
"github.com/go-qml/qml"
- "math/big"
- "strconv"
- "strings"
- "time"
)
var logger = ethlog.NewLogger("GUI")
@@ -144,17 +147,20 @@ func (gui *Gui) showWallet(context *qml.Context) (*qml.Window, error) {
win := gui.createWindow(component)
go func() {
- gui.setInitialBlockChain()
+ go gui.setInitialBlockChain()
gui.loadAddressBook()
- gui.readPreviousTransactions()
gui.setPeerInfo()
+ gui.readPreviousTransactions()
}()
- go gui.update()
+ gui.update()
return win, nil
}
+func (gui *Gui) ImportKey(filePath string) {
+}
+
func (gui *Gui) showKeyImport(context *qml.Context) (*qml.Window, error) {
context.SetVar("lib", gui)
component, err := gui.engine.LoadFile(gui.uiLib.AssetPath("qml/first_run.qml"))
@@ -231,20 +237,54 @@ func (gui *Gui) loadAddressBook() {
}
}
+func (gui *Gui) insertTransaction(window string, tx *ethchain.Transaction) {
+ nameReg := ethpipe.New(gui.eth).World().Config().Get("NameReg")
+ addr := gui.address()
+
+ var inout string
+ if bytes.Compare(tx.Sender(), addr) == 0 {
+ inout = "send"
+ } else {
+ inout = "recv"
+ }
+
+ var (
+ ptx = ethpub.NewPTx(tx)
+ send = nameReg.Storage(tx.Sender())
+ rec = nameReg.Storage(tx.Recipient)
+ s, r string
+ )
+
+ if tx.CreatesContract() {
+ rec = nameReg.Storage(tx.CreationAddress())
+ }
+
+ if send.Len() != 0 {
+ s = strings.Trim(send.Str(), "\x00")
+ } else {
+ s = ethutil.Bytes2Hex(tx.Sender())
+ }
+ if rec.Len() != 0 {
+ r = strings.Trim(rec.Str(), "\x00")
+ } else {
+ if tx.CreatesContract() {
+ r = ethutil.Bytes2Hex(tx.CreationAddress())
+ } else {
+ r = ethutil.Bytes2Hex(tx.Recipient)
+ }
+ }
+ ptx.Sender = s
+ ptx.Address = r
+
+ gui.win.Root().Call("addTx", window, ptx, inout)
+}
+
func (gui *Gui) readPreviousTransactions() {
it := gui.txDb.Db().NewIterator(nil, nil)
- addr := gui.address()
for it.Next() {
tx := ethchain.NewTransactionFromBytes(it.Value())
- var inout string
- if bytes.Compare(tx.Sender(), addr) == 0 {
- inout = "send"
- } else {
- inout = "recv"
- }
-
- gui.win.Root().Call("addTx", ethpub.NewPTx(tx), inout)
+ gui.insertTransaction("post", tx)
}
it.Release()
@@ -280,17 +320,100 @@ func (self *Gui) getObjectByName(objectName string) qml.Object {
// Simple go routine function that updates the list of peers in the GUI
func (gui *Gui) update() {
- reactor := gui.eth.Reactor()
var (
- blockChan = make(chan ethutil.React, 1)
- txChan = make(chan ethutil.React, 1)
- objectChan = make(chan ethutil.React, 1)
- peerChan = make(chan ethutil.React, 1)
- chainSyncChan = make(chan ethutil.React, 1)
- miningChan = make(chan ethutil.React, 1)
+ blockChan = make(chan ethreact.Event, 100)
+ txChan = make(chan ethreact.Event, 100)
+ objectChan = make(chan ethreact.Event, 100)
+ peerChan = make(chan ethreact.Event, 100)
+ chainSyncChan = make(chan ethreact.Event, 100)
+ miningChan = make(chan ethreact.Event, 100)
)
+ peerUpdateTicker := time.NewTicker(5 * time.Second)
+ generalUpdateTicker := time.NewTicker(1 * time.Second)
+
+ state := gui.eth.StateManager().TransState()
+
+ unconfirmedFunds := new(big.Int)
+ gui.win.Root().Call("setWalletValue", fmt.Sprintf("%v", ethutil.CurrencyToString(state.GetAccount(gui.address()).Balance)))
+ gui.getObjectByName("syncProgressIndicator").Set("visible", !gui.eth.IsUpToDate())
+
+ lastBlockLabel := gui.getObjectByName("lastBlockLabel")
+
+ go func() {
+ for {
+ select {
+ case b := <-blockChan:
+ block := b.Resource.(*ethchain.Block)
+ gui.processBlock(block, false)
+ if bytes.Compare(block.Coinbase, gui.address()) == 0 {
+ gui.setWalletValue(gui.eth.StateManager().CurrentState().GetAccount(gui.address()).Balance, nil)
+ }
+ case txMsg := <-txChan:
+ tx := txMsg.Resource.(*ethchain.Transaction)
+
+ if txMsg.Name == "newTx:pre" {
+ object := state.GetAccount(gui.address())
+
+ if bytes.Compare(tx.Sender(), gui.address()) == 0 {
+ unconfirmedFunds.Sub(unconfirmedFunds, tx.Value)
+ } else if bytes.Compare(tx.Recipient, gui.address()) == 0 {
+ unconfirmedFunds.Add(unconfirmedFunds, tx.Value)
+ }
+
+ gui.setWalletValue(object.Balance, unconfirmedFunds)
+
+ gui.insertTransaction("pre", tx)
+ } else {
+ object := state.GetAccount(gui.address())
+ if bytes.Compare(tx.Sender(), gui.address()) == 0 {
+ object.SubAmount(tx.Value)
+
+ gui.win.Root().Call("addTx", "post", ethpub.NewPTx(tx), "send")
+ gui.txDb.Put(tx.Hash(), tx.RlpEncode())
+ } else if bytes.Compare(tx.Recipient, gui.address()) == 0 {
+ object.AddAmount(tx.Value)
+
+ gui.win.Root().Call("addTx", "post", ethpub.NewPTx(tx), "recv")
+ gui.txDb.Put(tx.Hash(), tx.RlpEncode())
+ }
+
+ gui.setWalletValue(object.Balance, nil)
+
+ state.UpdateStateObject(object)
+ }
+ case msg := <-chainSyncChan:
+ sync := msg.Resource.(bool)
+ gui.win.Root().ObjectByName("syncProgressIndicator").Set("visible", sync)
+
+ case <-objectChan:
+ gui.loadAddressBook()
+ case <-peerChan:
+ gui.setPeerInfo()
+ case <-peerUpdateTicker.C:
+ gui.setPeerInfo()
+ case msg := <-miningChan:
+ if msg.Name == "miner:start" {
+ gui.miner = msg.Resource.(*ethminer.Miner)
+ } else {
+ gui.miner = nil
+ }
+ case <-generalUpdateTicker.C:
+ statusText := "#" + gui.eth.BlockChain().CurrentBlock.Number.String()
+ if gui.miner != nil {
+ pow := gui.miner.GetPow()
+ if pow.GetHashrate() != 0 {
+ statusText = "Mining @ " + strconv.FormatInt(pow.GetHashrate(), 10) + "Khash - " + statusText
+ }
+ }
+ lastBlockLabel.Set("text", statusText)
+ }
+ }
+ }()
+
+ reactor := gui.eth.Reactor()
+
reactor.Subscribe("newBlock", blockChan)
reactor.Subscribe("newTx:pre", txChan)
reactor.Subscribe("newTx:post", txChan)
@@ -303,86 +426,6 @@ func (gui *Gui) update() {
reactor.Subscribe("object:"+string(nameReg.Address()), objectChan)
}
reactor.Subscribe("peerList", peerChan)
-
- peerUpdateTicker := time.NewTicker(5 * time.Second)
- generalUpdateTicker := time.NewTicker(1 * time.Second)
-
- state := gui.eth.StateManager().TransState()
-
- unconfirmedFunds := new(big.Int)
- gui.win.Root().Call("setWalletValue", fmt.Sprintf("%v", ethutil.CurrencyToString(state.GetAccount(gui.address()).Amount)))
- gui.getObjectByName("syncProgressIndicator").Set("visible", !gui.eth.IsUpToDate())
-
- lastBlockLabel := gui.getObjectByName("lastBlockLabel")
-
- for {
- select {
- case b := <-blockChan:
- block := b.Resource.(*ethchain.Block)
- gui.processBlock(block, false)
- if bytes.Compare(block.Coinbase, gui.address()) == 0 {
- gui.setWalletValue(gui.eth.StateManager().CurrentState().GetAccount(gui.address()).Amount, nil)
- }
-
- case txMsg := <-txChan:
- tx := txMsg.Resource.(*ethchain.Transaction)
-
- if txMsg.Event == "newTx:pre" {
- object := state.GetAccount(gui.address())
-
- if bytes.Compare(tx.Sender(), gui.address()) == 0 {
- gui.win.Root().Call("addTx", ethpub.NewPTx(tx), "send")
- gui.txDb.Put(tx.Hash(), tx.RlpEncode())
-
- unconfirmedFunds.Sub(unconfirmedFunds, tx.Value)
- } else if bytes.Compare(tx.Recipient, gui.address()) == 0 {
- gui.win.Root().Call("addTx", ethpub.NewPTx(tx), "recv")
- gui.txDb.Put(tx.Hash(), tx.RlpEncode())
-
- unconfirmedFunds.Add(unconfirmedFunds, tx.Value)
- }
-
- gui.setWalletValue(object.Amount, unconfirmedFunds)
- } else {
- object := state.GetAccount(gui.address())
- if bytes.Compare(tx.Sender(), gui.address()) == 0 {
- object.SubAmount(tx.Value)
- } else if bytes.Compare(tx.Recipient, gui.address()) == 0 {
- object.AddAmount(tx.Value)
- }
-
- gui.setWalletValue(object.Amount, nil)
-
- state.UpdateStateObject(object)
- }
- case msg := <-chainSyncChan:
- sync := msg.Resource.(bool)
- gui.win.Root().ObjectByName("syncProgressIndicator").Set("visible", sync)
-
- case <-objectChan:
- gui.loadAddressBook()
- case <-peerChan:
- gui.setPeerInfo()
- case <-peerUpdateTicker.C:
- gui.setPeerInfo()
- case msg := <-miningChan:
- if msg.Event == "miner:start" {
- gui.miner = msg.Resource.(*ethminer.Miner)
- } else {
- gui.miner = nil
- }
-
- case <-generalUpdateTicker.C:
- statusText := "#" + gui.eth.BlockChain().CurrentBlock.Number.String()
- if gui.miner != nil {
- pow := gui.miner.GetPow()
- if pow.GetHashrate() != 0 {
- statusText = "Mining @ " + strconv.FormatInt(pow.GetHashrate(), 10) + "Khash - " + statusText
- }
- }
- lastBlockLabel.Set("text", statusText)
- }
- }
}
func (gui *Gui) setPeerInfo() {
@@ -416,6 +459,11 @@ func (gui *Gui) Create(recipient, value, gas, gasPrice, data string) (*ethpub.PR
return gui.pub.Transact(gui.privateKey(), recipient, value, gas, gasPrice, data)
}
+func (self *Gui) ImportTx(rlpTx string) {
+ tx := ethchain.NewTransactionFromBytes(ethutil.Hex2Bytes(rlpTx))
+ self.eth.TxPool().QueueTransaction(tx)
+}
+
func (gui *Gui) SetCustomIdentifier(customIdentifier string) {
gui.clientIdentity.SetCustomIdentifier(customIdentifier)
gui.config.Save("id", customIdentifier)
diff --git a/ethereal/html_container.go b/ethereal/html_container.go
index b00d3f78e0..40a9f55842 100644
--- a/ethereal/html_container.go
+++ b/ethereal/html_container.go
@@ -2,17 +2,18 @@ package main
import (
"errors"
+ "io/ioutil"
+ "net/url"
+ "os"
+ "path"
+ "path/filepath"
+
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethpub"
"github.com/ethereum/eth-go/ethstate"
"github.com/ethereum/eth-go/ethutil"
"github.com/go-qml/qml"
"github.com/howeyc/fsnotify"
- "io/ioutil"
- "net/url"
- "os"
- "path"
- "path/filepath"
)
type HtmlApplication struct {
@@ -41,7 +42,7 @@ func (app *HtmlApplication) Create() error {
return errors.New("Ethereum package not yet supported")
// TODO
- ethutil.OpenPackage(app.path)
+ //ethutil.OpenPackage(app.path)
}
win := component.CreateWindow(nil)
diff --git a/ethereal/main.go b/ethereal/main.go
index 0f99be8865..04a04536d2 100644
--- a/ethereal/main.go
+++ b/ethereal/main.go
@@ -1,16 +1,17 @@
package main
import (
+ "os"
+ "runtime"
+
"github.com/ethereum/eth-go/ethlog"
"github.com/ethereum/go-ethereum/utils"
"github.com/go-qml/qml"
- "os"
- "runtime"
)
const (
ClientIdentifier = "Ethereal"
- Version = "0.6.0"
+ Version = "0.6.1"
)
func main() {
diff --git a/ethereal/qml_container.go b/ethereal/qml_container.go
index 1b420ee219..53ff13c2f3 100644
--- a/ethereal/qml_container.go
+++ b/ethereal/qml_container.go
@@ -25,7 +25,7 @@ func (app *QmlApplication) Create() error {
path := string(app.path)
// For some reason for windows we get /c:/path/to/something, windows doesn't like the first slash but is fine with the others so we are removing it
- if string(app.path[0]) == "/" && runtime.GOOS == "windows" {
+ if app.path[0] == '/' && runtime.GOOS == "windows" {
path = app.path[1:]
}
diff --git a/ethereal/ui_lib.go b/ethereal/ui_lib.go
index 6a62fa1df2..42c5c9ad2d 100644
--- a/ethereal/ui_lib.go
+++ b/ethereal/ui_lib.go
@@ -1,10 +1,11 @@
package main
import (
+ "path"
+
"github.com/ethereum/eth-go"
"github.com/ethereum/eth-go/ethutil"
"github.com/go-qml/qml"
- "path"
)
type memAddr struct {
@@ -42,6 +43,10 @@ func (ui *UiLib) OpenHtml(path string) {
go app.run()
}
+func (ui *UiLib) OpenBrowser() {
+ ui.OpenHtml("file://" + ui.AssetPath("ext/home.html"))
+}
+
func (ui *UiLib) Muted(content string) {
component, err := ui.engine.LoadFile(ui.AssetPath("qml/muted.qml"))
if err != nil {
diff --git a/ethereum/flags.go b/ethereum/flags.go
index 4f59ddf060..5ed208411b 100644
--- a/ethereum/flags.go
+++ b/ethereum/flags.go
@@ -3,10 +3,11 @@ package main
import (
"flag"
"fmt"
- "github.com/ethereum/eth-go/ethlog"
"os"
"os/user"
"path"
+
+ "github.com/ethereum/eth-go/ethlog"
)
var Identifier string
@@ -31,6 +32,9 @@ var LogFile string
var ConfigFile string
var DebugFile string
var LogLevel int
+var Dump bool
+var DumpHash string
+var DumpNumber int
// flags specific to cli client
var StartMining bool
@@ -71,6 +75,10 @@ func Init() {
flag.BoolVar(&DiffTool, "difftool", false, "creates output for diff'ing. Sets LogLevel=0")
flag.StringVar(&DiffType, "diff", "all", "sets the level of diff output [vm, all]. Has no effect if difftool=false")
+ flag.BoolVar(&Dump, "dump", false, "output the ethereum state in JSON format. Sub args [number, hash]")
+ flag.StringVar(&DumpHash, "hash", "", "specify arg in hex")
+ flag.IntVar(&DumpNumber, "number", -1, "specify arg in number")
+
flag.BoolVar(&StartMining, "mine", false, "start dagger mining")
flag.BoolVar(&StartJsConsole, "js", false, "launches javascript console")
diff --git a/ethereum/main.go b/ethereum/main.go
index 2179910748..17838997c4 100644
--- a/ethereum/main.go
+++ b/ethereum/main.go
@@ -1,15 +1,19 @@
package main
import (
+ "fmt"
+ "os"
+ "runtime"
+
+ "github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethlog"
"github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/go-ethereum/utils"
- "runtime"
)
const (
ClientIdentifier = "Ethereum(G)"
- Version = "0.6.0"
+ Version = "0.6.1"
)
var logger = ethlog.NewLogger("CLI")
@@ -23,7 +27,7 @@ func main() {
Init() // parsing command line
// If the difftool option is selected ignore all other log output
- if DiffTool {
+ if DiffTool || Dump {
LogLevel = 0
}
@@ -46,6 +50,32 @@ func main() {
ethereum := utils.NewEthereum(db, clientIdentity, keyManager, UseUPnP, OutboundPort, MaxPeer)
+ if Dump {
+ var block *ethchain.Block
+
+ if len(DumpHash) == 0 && DumpNumber == -1 {
+ block = ethereum.BlockChain().CurrentBlock
+ } else if len(DumpHash) > 0 {
+ block = ethereum.BlockChain().GetBlock(ethutil.Hex2Bytes(DumpHash))
+ } else {
+ block = ethereum.BlockChain().GetBlockByNumber(uint64(DumpNumber))
+ }
+
+ if block == nil {
+ fmt.Fprintln(os.Stderr, "block not found")
+
+ // We want to output valid JSON
+ fmt.Println("{}")
+
+ os.Exit(1)
+ }
+
+ // Leave the Println. This needs clean output for piping
+ fmt.Println(block.State().Dump())
+
+ os.Exit(0)
+ }
+
if ShowGenesis {
utils.ShowGenesis(ethereum)
}
diff --git a/ethereum/repl/javascript_runtime.go b/ethereum/repl/javascript_runtime.go
index 41b6216d49..026e6f374c 100644
--- a/ethereum/repl/javascript_runtime.go
+++ b/ethereum/repl/javascript_runtime.go
@@ -2,18 +2,20 @@ package ethrepl
import (
"fmt"
- "github.com/ethereum/eth-go"
- "github.com/ethereum/eth-go/ethchain"
- "github.com/ethereum/eth-go/ethlog"
- "github.com/ethereum/eth-go/ethpub"
- "github.com/ethereum/eth-go/ethstate"
- "github.com/ethereum/eth-go/ethutil"
- "github.com/ethereum/go-ethereum/utils"
- "github.com/obscuren/otto"
"io/ioutil"
"os"
"path"
"path/filepath"
+
+ "github.com/ethereum/eth-go"
+ "github.com/ethereum/eth-go/ethchain"
+ "github.com/ethereum/eth-go/ethlog"
+ "github.com/ethereum/eth-go/ethpub"
+ "github.com/ethereum/eth-go/ethreact"
+ "github.com/ethereum/eth-go/ethstate"
+ "github.com/ethereum/eth-go/ethutil"
+ "github.com/ethereum/go-ethereum/utils"
+ "github.com/obscuren/otto"
)
var jsrelogger = ethlog.NewLogger("JSRE")
@@ -23,8 +25,8 @@ type JSRE struct {
vm *otto.Otto
lib *ethpub.PEthereum
- blockChan chan ethutil.React
- changeChan chan ethutil.React
+ blockChan chan ethreact.Event
+ changeChan chan ethreact.Event
quitChan chan bool
objectCb map[string][]otto.Value
@@ -49,8 +51,8 @@ func NewJSRE(ethereum *eth.Ethereum) *JSRE {
ethereum,
otto.New(),
ethpub.NewPEthereum(ethereum),
- make(chan ethutil.React, 1),
- make(chan ethutil.React, 1),
+ make(chan ethreact.Event, 10),
+ make(chan ethreact.Event, 10),
make(chan bool),
make(map[string][]otto.Value),
}
@@ -65,6 +67,10 @@ func NewJSRE(ethereum *eth.Ethereum) *JSRE {
// We have to make sure that, whoever calls this, calls "Stop"
go re.mainLoop()
+ // Subscribe to events
+ reactor := ethereum.Reactor()
+ reactor.Subscribe("newBlock", re.blockChan)
+
re.Bind("eth", &JSEthereum{re.lib, re.vm})
re.initStdFuncs()
@@ -109,10 +115,6 @@ func (self *JSRE) Stop() {
}
func (self *JSRE) mainLoop() {
- // Subscribe to events
- reactor := self.ethereum.Reactor()
- reactor.Subscribe("newBlock", self.blockChan)
-
out:
for {
select {
@@ -146,12 +148,44 @@ func (self *JSRE) initStdFuncs() {
eth.Set("stopMining", self.stopMining)
eth.Set("startMining", self.startMining)
eth.Set("execBlock", self.execBlock)
+ eth.Set("dump", self.dump)
}
/*
* The following methods are natively implemented javascript functions
*/
+func (self *JSRE) dump(call otto.FunctionCall) otto.Value {
+ var state *ethstate.State
+
+ if len(call.ArgumentList) > 0 {
+ var block *ethchain.Block
+ if call.Argument(0).IsNumber() {
+ num, _ := call.Argument(0).ToInteger()
+ block = self.ethereum.BlockChain().GetBlockByNumber(uint64(num))
+ } else if call.Argument(0).IsString() {
+ hash, _ := call.Argument(0).ToString()
+ block = self.ethereum.BlockChain().GetBlock(ethutil.Hex2Bytes(hash))
+ } else {
+ fmt.Println("invalid argument for dump. Either hex string or number")
+ }
+
+ if block == nil {
+ fmt.Println("block not found")
+
+ return otto.UndefinedValue()
+ }
+
+ state = block.State()
+ } else {
+ state = self.ethereum.StateManager().CurrentState()
+ }
+
+ v, _ := self.vm.ToValue(state.Dump())
+
+ return v
+}
+
func (self *JSRE) stopMining(call otto.FunctionCall) otto.Value {
v, _ := self.vm.ToValue(utils.StopMining(self.ethereum))
return v
diff --git a/utils/cmd.go b/utils/cmd.go
index 5d0b3463c5..0eeb1049e1 100644
--- a/utils/cmd.go
+++ b/utils/cmd.go
@@ -127,6 +127,7 @@ func NewDatabase() ethutil.Database {
}
func NewClientIdentity(clientIdentifier, version, customIdentifier string) *ethwire.SimpleClientIdentity {
+ logger.Infoln("identity created")
return ethwire.NewSimpleClientIdentity(clientIdentifier, version, customIdentifier)
}
@@ -243,21 +244,18 @@ func GetMiner() *ethminer.Miner {
func StartMining(ethereum *eth.Ethereum) bool {
if !ethereum.Mining {
ethereum.Mining = true
-
addr := ethereum.KeyManager().Address()
go func() {
+ logger.Infoln("Start mining")
if miner == nil {
miner = ethminer.NewDefaultMiner(addr, ethereum)
}
-
// Give it some time to connect with peers
time.Sleep(3 * time.Second)
for !ethereum.IsUpToDate() {
time.Sleep(5 * time.Second)
}
-
- logger.Infoln("Miner started")
miner.Start()
}()
RegisterInterrupt(func(os.Signal) {
@@ -271,9 +269,7 @@ func StartMining(ethereum *eth.Ethereum) bool {
func StopMining(ethereum *eth.Ethereum) bool {
if ethereum.Mining && miner != nil {
miner.Stop()
-
- logger.Infoln("Miner stopped")
-
+ logger.Infoln("Stopped mining")
ethereum.Mining = false
return true