This commit is contained in:
BuildFuture 2014-08-11 10:55:36 +00:00
commit e3953837dc
16 changed files with 642 additions and 245 deletions

View file

@ -1,7 +1,9 @@
Ethereum Ethereum
======== ========
[![Build Status](https://travis-ci.org/ethereum/go-ethereum.png?branch=master)](https://travis-ci.org/ethereum/go-ethereum) Master [![Build
Status](http://cpt-obvious.ethercasts.com:8010/buildstatusimage?builder=go-ethereum-master-docker)](http://cpt-obvious.ethercasts.com:8010/builders/go-ethereum-master-docker/builds/-1) Develop [![Build
Status](http://cpt-obvious.ethercasts.com:8010/buildstatusimage?builder=go-ethereum-develop-docker)](http://cpt-obvious.ethercasts.com:8010/builders/go-ethereum-develop-docker/builds/-1)
Ethereum Go Client © 2014 Jeffrey Wilcke. Ethereum Go Client © 2014 Jeffrey Wilcke.

View file

@ -0,0 +1,21 @@
<!doctype>
<html>
<head>
<title>Ethereum</title>
<style type="text/css">
h1 {
text-align: center;
font-family: Courier;
font-size: 50pt;
margin-top: 25%
}
</style>
</head>
<body>
<h1>... Ethereum ...</h1>
<!-- ĐΞV --!>
</body>
</html>

View file

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

View file

@ -26,6 +26,27 @@ ApplicationWindow {
shortcut: "Ctrl+o" shortcut: "Ctrl+o"
onTriggered: openAppDialog.open() 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 { Menu {
@ -35,6 +56,13 @@ ApplicationWindow {
shortcut: "Ctrl+d" shortcut: "Ctrl+d"
onTriggered: ui.startDebugger() onTriggered: ui.startDebugger()
} }
MenuItem {
text: "Import Tx"
onTriggered: {
txImportDialog.visible = true
}
}
} }
Menu { Menu {
@ -77,6 +105,7 @@ ApplicationWindow {
historyView.visible = false historyView.visible = false
newTxView.visible = false newTxView.visible = false
infoView.visible = false infoView.visible = false
pendingTxView.visible = false
view.visible = true view.visible = true
//root.title = "Ethereal - " = view.title //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) signal addPlugin(string name)
Component { Component {
@ -375,9 +437,7 @@ ApplicationWindow {
//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")))
var path = openAppDialog.fileUrl.toString() var path = openAppDialog.fileUrl.toString()
console.log(path)
var ext = path.split('.').pop() var ext = path.split('.').pop()
console.log(ext)
if(ext == "html" || ext == "htm") { if(ext == "html" || ext == "htm") {
ui.openHtml(path) ui.openHtml(path)
}else if(ext == "qml"){ }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 { statusBar: StatusBar {
height: 30 height: 30
RowLayout { 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 { Window {
id: popup id: popup
visible: false visible: false
@ -660,7 +766,7 @@ ApplicationWindow {
anchors.left: aboutIcon.right anchors.left: aboutIcon.right
anchors.leftMargin: 10 anchors.leftMargin: 10
font.pointSize: 12 font.pointSize: 12
text: "<h2>Ethereal</h2><br><h3>Development</h3>Jeffrey Wilcke<br>Maran Hidskes<br>Viktor Trón<br>" text: "<h2>Ethereal - Adrastea</h2><br><h3>Development</h3>Jeffrey Wilcke<br>Maran Hidskes<br>Viktor Trón<br>"
} }
} }
@ -684,7 +790,7 @@ ApplicationWindow {
walletValueLabel.text = value walletValueLabel.text = value
} }
function addTx(tx, inout) { function addTx(type, tx, inout) {
var isContract var isContract
if (tx.contract == true){ if (tx.contract == true){
isContract = "Yes" isContract = "Yes"
@ -692,13 +798,19 @@ ApplicationWindow {
isContract = "No" isContract = "No"
} }
var address;
if(inout == "recv") { if(type == "post") {
address = tx.sender; var address;
} else { if(inout == "recv") {
address = tx.address; 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) { function addBlock(block, initial) {
@ -714,7 +826,7 @@ ApplicationWindow {
if(initial){ 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)}) 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)}) 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 { Window {
id: peerWindow id: peerWindow
//flags: Qt.CustomizeWindowHint | Qt.Tool | Qt.WindowCloseButtonHint //flags: Qt.CustomizeWindowHint | Qt.Tool | Qt.WindowCloseButtonHint
height: 200 height: 200
width: 700 width: 700
Rectangle { Rectangle {
@ -897,10 +1009,10 @@ ApplicationWindow {
placeholderText: "Gas" placeholderText: "Gas"
text: "500" text: "500"
/* /*
onTextChanged: { onTextChanged: {
contractFormReady() contractFormReady()
} }
*/ */
} }
Label { Label {
id: atLabel id: atLabel
@ -914,10 +1026,10 @@ ApplicationWindow {
text: "10" text: "10"
validator: RegExpValidator { regExp: /\d*/ } validator: RegExpValidator { regExp: /\d*/ }
/* /*
onTextChanged: { onTextChanged: {
contractFormReady() contractFormReady()
} }
*/ */
} }
ComboBox { ComboBox {
@ -962,7 +1074,7 @@ ApplicationWindow {
var gasPrice = txGasPrice.text + denomModel.get(gasDenom.currentIndex).zeros; var gasPrice = txGasPrice.text + denomModel.get(gasDenom.currentIndex).zeros;
var res = eth.create(txFuelRecipient.text, value, txGas.text, gasPrice, codeView.text) var res = eth.create(txFuelRecipient.text, value, txGas.text, gasPrice, codeView.text)
if(res[1]) { if(res[1]) {
txResult.text = "Your contract <b>could not</b> be send over the network:\n<b>" txResult.text = "Your contract <b>could not</b> be sent over the network:\n<b>"
txResult.text += res[1].error() txResult.text += res[1].error()
txResult.text += "</b>" txResult.text += "</b>"
mainContractColumn.state = "ERROR" mainContractColumn.state = "ERROR"

View file

@ -21,19 +21,54 @@ ApplicationWindow {
id: root id: root
anchors.fill: parent anchors.fill: parent
state: "inspectorShown" 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 { WebView {
objectName: "webView" objectName: "webView"
id: webview id: webview
anchors.fill: parent anchors {
/* left: parent.left
anchors { right: parent.right
left: parent.left bottom: parent.bottom
right: parent.right top: uriNav.bottom
bottom: sizeGrip.top }
top: parent.top
}
*/
onTitleChanged: { window.title = title } onTitleChanged: { window.title = title }
experimental.preferences.javascriptEnabled: true experimental.preferences.javascriptEnabled: true
experimental.preferences.navigatorQtObjectEnabled: true experimental.preferences.navigatorQtObjectEnabled: true
@ -46,50 +81,50 @@ ApplicationWindow {
try { try {
switch(data.call) { switch(data.call) {
case "getCoinBase": case "getCoinBase":
postData(data._seed, eth.getCoinBase()) postData(data._seed, eth.getCoinBase())
break break
case "getIsListening": case "getIsListening":
postData(data._seed, eth.getIsListening()) postData(data._seed, eth.getIsListening())
break break
case "getIsMining": case "getIsMining":
postData(data._seed, eth.getIsMining()) postData(data._seed, eth.getIsMining())
break break
case "getPeerCount": case "getPeerCount":
postData(data._seed, eth.getPeerCount()) postData(data._seed, eth.getPeerCount())
break break
case "getTxCountAt": case "getTxCountAt":
require(1) require(1)
postData(data._seed, eth.getTxCountAt(data.args[0])) postData(data._seed, eth.getTxCountAt(data.args[0]))
break break
case "getBlockByNumber": case "getBlockByNumber":
var block = eth.getBlock(data.args[0]) var block = eth.getBlock(data.args[0])
postData(data._seed, block) postData(data._seed, block)
break break
case "getBlockByHash": case "getBlockByHash":
var block = eth.getBlock(data.args[0]) var block = eth.getBlock(data.args[0])
postData(data._seed, block) postData(data._seed, block)
break break
case "transact": case "transact":
require(5) require(5)
var tx = eth.transact(data.args[0], data.args[1], data.args[2],data.args[3],data.args[4],data.args[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) postData(data._seed, tx)
break break
case "create": case "create":
postData(data._seed, null) postData(data._seed, null)
break break
case "getStorage": case "getStorage":
require(2); require(2);
var stateObject = eth.getStateObject(data.args[0]) var stateObject = eth.getStateObject(data.args[0])
@ -97,52 +132,52 @@ ApplicationWindow {
postData(data._seed, storage) postData(data._seed, storage)
break break
case "getStateKeyVals": case "getStateKeyVals":
require(1); require(1);
var stateObject = eth.getStateObject(data.args[0]).stateKeyVal(true) var stateObject = eth.getStateObject(data.args[0]).stateKeyVal(true)
postData(data._seed,stateObject) postData(data._seed,stateObject)
break break
case "getTransactionsFor": case "getTransactionsFor":
require(1); require(1);
var txs = eth.getTransactionsFor(data.args[0], true) var txs = eth.getTransactionsFor(data.args[0], true)
postData(data._seed, txs) postData(data._seed, txs)
break break
case "getBalance": case "getBalance":
require(1); require(1);
postData(data._seed, eth.getStateObject(data.args[0]).value()); postData(data._seed, eth.getStateObject(data.args[0]).value());
break break
case "getKey": case "getKey":
var key = eth.getKey().privateKey; var key = eth.getKey().privateKey;
postData(data._seed, key) postData(data._seed, key)
break break
case "watch": case "watch":
require(1) require(1)
eth.watch(data.args[0], data.args[1]); eth.watch(data.args[0], data.args[1]);
break break
case "disconnect": case "disconnect":
require(1) require(1)
postData(data._seed, null) postData(data._seed, null)
break; break;
case "set": case "set":
console.log("'Set' has been depcrecated") console.log("'Set' has been depcrecated")
/* /*
for(var key in data.args) { for(var key in data.args) {
if(webview.hasOwnProperty(key)) { if(webview.hasOwnProperty(key)) {
window[key] = data.args[key]; window[key] = data.args[key];
} }
} }
*/ */
break; break;
case "getSecretToAddress": case "getSecretToAddress":
require(1) require(1)
postData(data._seed, eth.secretToAddress(data.args[0])) postData(data._seed, eth.secretToAddress(data.args[0]))
break; break;
case "debug": case "debug":
console.log(data.args[0]); console.log(data.args[0]);
break; break;
} }
@ -191,12 +226,12 @@ ApplicationWindow {
inspector.visible = false inspector.visible = false
}else{ }else{
inspector.visible = true inspector.visible = true
inspector.url = webview.experimental.remoteInspectorUrl inspector.url = webview.experimental.remoteInspectorUrl
} }
} }
onDoubleClicked: { onDoubleClicked: {
console.log('refreshing') console.log('refreshing')
webView.reload() webView.reload()
} }
anchors.fill: parent anchors.fill: parent
} }

View file

@ -2,15 +2,16 @@ package main
import ( import (
"fmt" "fmt"
"math/big"
"strconv"
"strings"
"github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethstate" "github.com/ethereum/eth-go/ethstate"
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/eth-go/ethvm" "github.com/ethereum/eth-go/ethvm"
"github.com/ethereum/go-ethereum/utils" "github.com/ethereum/go-ethereum/utils"
"github.com/go-qml/qml" "github.com/go-qml/qml"
"math/big"
"strconv"
"strings"
) )
type DebuggerWindow struct { type DebuggerWindow struct {
@ -134,26 +135,13 @@ func (self *DebuggerWindow) Debug(valueStr, gasStr, gasPriceStr, scriptStr, data
state := self.lib.eth.StateManager().TransState() state := self.lib.eth.StateManager().TransState()
account := self.lib.eth.StateManager().TransState().GetAccount(keyPair.Address()) account := self.lib.eth.StateManager().TransState().GetAccount(keyPair.Address())
contract := ethstate.NewStateObject([]byte{0}) contract := ethstate.NewStateObject([]byte{0})
contract.Amount = value contract.Balance = value
self.SetAsm(script) self.SetAsm(script)
callerClosure := ethvm.NewClosure(account, contract, script, gas, gasPrice)
block := self.lib.eth.BlockChain().CurrentBlock block := self.lib.eth.BlockChain().CurrentBlock
/* callerClosure := ethvm.NewClosure(account, contract, script, gas, gasPrice)
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),
})
*/
env := utils.NewEnv(state, block, account.Address(), value) env := utils.NewEnv(state, block, account.Address(), value)
vm := ethvm.New(env) vm := ethvm.New(env)
vm.Verbose = true vm.Verbose = true

View file

@ -1,9 +1,9 @@
package main package main
import ( import (
"fmt"
"github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethpub" "github.com/ethereum/eth-go/ethpub"
"github.com/ethereum/eth-go/ethreact"
"github.com/ethereum/eth-go/ethstate" "github.com/ethereum/eth-go/ethstate"
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethutil"
"github.com/go-qml/qml" "github.com/go-qml/qml"
@ -25,8 +25,8 @@ type AppContainer interface {
type ExtApplication struct { type ExtApplication struct {
*ethpub.PEthereum *ethpub.PEthereum
blockChan chan ethutil.React blockChan chan ethreact.Event
changeChan chan ethutil.React changeChan chan ethreact.Event
quitChan chan bool quitChan chan bool
watcherQuitChan chan bool watcherQuitChan chan bool
@ -38,8 +38,8 @@ type ExtApplication struct {
func NewExtApplication(container AppContainer, lib *UiLib) *ExtApplication { func NewExtApplication(container AppContainer, lib *UiLib) *ExtApplication {
app := &ExtApplication{ app := &ExtApplication{
ethpub.NewPEthereum(lib.eth), ethpub.NewPEthereum(lib.eth),
make(chan ethutil.React, 1), make(chan ethreact.Event, 100),
make(chan ethutil.React, 1), make(chan ethreact.Event, 100),
make(chan bool), make(chan bool),
make(chan bool), make(chan bool),
container, container,
@ -58,8 +58,7 @@ func (app *ExtApplication) run() {
err := app.container.Create() err := app.container.Create()
if err != nil { if err != nil {
fmt.Println(err) logger.Errorln(err)
return return
} }

View file

@ -3,20 +3,23 @@ package main
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"math/big"
"strconv"
"strings"
"time"
"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/ethlog"
"github.com/ethereum/eth-go/ethminer" "github.com/ethereum/eth-go/ethminer"
"github.com/ethereum/eth-go/ethpipe"
"github.com/ethereum/eth-go/ethpub" "github.com/ethereum/eth-go/ethpub"
"github.com/ethereum/eth-go/ethreact"
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/eth-go/ethwire" "github.com/ethereum/eth-go/ethwire"
"github.com/ethereum/go-ethereum/utils" "github.com/ethereum/go-ethereum/utils"
"github.com/go-qml/qml" "github.com/go-qml/qml"
"math/big"
"strconv"
"strings"
"time"
) )
var logger = ethlog.NewLogger("GUI") var logger = ethlog.NewLogger("GUI")
@ -144,17 +147,20 @@ func (gui *Gui) showWallet(context *qml.Context) (*qml.Window, error) {
win := gui.createWindow(component) win := gui.createWindow(component)
go func() { go func() {
gui.setInitialBlockChain() go gui.setInitialBlockChain()
gui.loadAddressBook() gui.loadAddressBook()
gui.readPreviousTransactions()
gui.setPeerInfo() gui.setPeerInfo()
gui.readPreviousTransactions()
}() }()
go gui.update() gui.update()
return win, nil return win, nil
} }
func (gui *Gui) ImportKey(filePath string) {
}
func (gui *Gui) showKeyImport(context *qml.Context) (*qml.Window, error) { func (gui *Gui) showKeyImport(context *qml.Context) (*qml.Window, error) {
context.SetVar("lib", gui) context.SetVar("lib", gui)
component, err := gui.engine.LoadFile(gui.uiLib.AssetPath("qml/first_run.qml")) 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() { func (gui *Gui) readPreviousTransactions() {
it := gui.txDb.Db().NewIterator(nil, nil) it := gui.txDb.Db().NewIterator(nil, nil)
addr := gui.address()
for it.Next() { for it.Next() {
tx := ethchain.NewTransactionFromBytes(it.Value()) tx := ethchain.NewTransactionFromBytes(it.Value())
var inout string gui.insertTransaction("post", tx)
if bytes.Compare(tx.Sender(), addr) == 0 {
inout = "send"
} else {
inout = "recv"
}
gui.win.Root().Call("addTx", ethpub.NewPTx(tx), inout)
} }
it.Release() 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 // Simple go routine function that updates the list of peers in the GUI
func (gui *Gui) update() { func (gui *Gui) update() {
reactor := gui.eth.Reactor()
var ( var (
blockChan = make(chan ethutil.React, 1) blockChan = make(chan ethreact.Event, 100)
txChan = make(chan ethutil.React, 1) txChan = make(chan ethreact.Event, 100)
objectChan = make(chan ethutil.React, 1) objectChan = make(chan ethreact.Event, 100)
peerChan = make(chan ethutil.React, 1) peerChan = make(chan ethreact.Event, 100)
chainSyncChan = make(chan ethutil.React, 1) chainSyncChan = make(chan ethreact.Event, 100)
miningChan = make(chan ethutil.React, 1) 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("newBlock", blockChan)
reactor.Subscribe("newTx:pre", txChan) reactor.Subscribe("newTx:pre", txChan)
reactor.Subscribe("newTx:post", txChan) reactor.Subscribe("newTx:post", txChan)
@ -303,86 +426,6 @@ func (gui *Gui) update() {
reactor.Subscribe("object:"+string(nameReg.Address()), objectChan) reactor.Subscribe("object:"+string(nameReg.Address()), objectChan)
} }
reactor.Subscribe("peerList", peerChan) 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() { 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) 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) { func (gui *Gui) SetCustomIdentifier(customIdentifier string) {
gui.clientIdentity.SetCustomIdentifier(customIdentifier) gui.clientIdentity.SetCustomIdentifier(customIdentifier)
gui.config.Save("id", customIdentifier) gui.config.Save("id", customIdentifier)

View file

@ -2,17 +2,18 @@ package main
import ( import (
"errors" "errors"
"io/ioutil"
"net/url"
"os"
"path"
"path/filepath"
"github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethpub" "github.com/ethereum/eth-go/ethpub"
"github.com/ethereum/eth-go/ethstate" "github.com/ethereum/eth-go/ethstate"
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethutil"
"github.com/go-qml/qml" "github.com/go-qml/qml"
"github.com/howeyc/fsnotify" "github.com/howeyc/fsnotify"
"io/ioutil"
"net/url"
"os"
"path"
"path/filepath"
) )
type HtmlApplication struct { type HtmlApplication struct {
@ -41,7 +42,7 @@ func (app *HtmlApplication) Create() error {
return errors.New("Ethereum package not yet supported") return errors.New("Ethereum package not yet supported")
// TODO // TODO
ethutil.OpenPackage(app.path) //ethutil.OpenPackage(app.path)
} }
win := component.CreateWindow(nil) win := component.CreateWindow(nil)

View file

@ -1,16 +1,17 @@
package main package main
import ( import (
"os"
"runtime"
"github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethlog"
"github.com/ethereum/go-ethereum/utils" "github.com/ethereum/go-ethereum/utils"
"github.com/go-qml/qml" "github.com/go-qml/qml"
"os"
"runtime"
) )
const ( const (
ClientIdentifier = "Ethereal" ClientIdentifier = "Ethereal"
Version = "0.6.0" Version = "0.6.1"
) )
func main() { func main() {

View file

@ -25,7 +25,7 @@ func (app *QmlApplication) Create() error {
path := string(app.path) 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 // 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:] path = app.path[1:]
} }

View file

@ -1,10 +1,11 @@
package main package main
import ( import (
"path"
"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"
"path"
) )
type memAddr struct { type memAddr struct {
@ -42,6 +43,10 @@ func (ui *UiLib) OpenHtml(path string) {
go app.run() go app.run()
} }
func (ui *UiLib) OpenBrowser() {
ui.OpenHtml("file://" + ui.AssetPath("ext/home.html"))
}
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 {

View file

@ -3,10 +3,11 @@ package main
import ( import (
"flag" "flag"
"fmt" "fmt"
"github.com/ethereum/eth-go/ethlog"
"os" "os"
"os/user" "os/user"
"path" "path"
"github.com/ethereum/eth-go/ethlog"
) )
var Identifier string var Identifier string
@ -31,6 +32,9 @@ var LogFile string
var ConfigFile string var ConfigFile string
var DebugFile string var DebugFile string
var LogLevel int var LogLevel int
var Dump bool
var DumpHash string
var DumpNumber int
// flags specific to cli client // flags specific to cli client
var StartMining bool var StartMining bool
@ -71,6 +75,10 @@ func Init() {
flag.BoolVar(&DiffTool, "difftool", false, "creates output for diff'ing. Sets LogLevel=0") 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.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(&StartMining, "mine", false, "start dagger mining")
flag.BoolVar(&StartJsConsole, "js", false, "launches javascript console") flag.BoolVar(&StartJsConsole, "js", false, "launches javascript console")

View file

@ -1,15 +1,19 @@
package main package main
import ( import (
"fmt"
"os"
"runtime"
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethlog"
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/go-ethereum/utils" "github.com/ethereum/go-ethereum/utils"
"runtime"
) )
const ( const (
ClientIdentifier = "Ethereum(G)" ClientIdentifier = "Ethereum(G)"
Version = "0.6.0" Version = "0.6.1"
) )
var logger = ethlog.NewLogger("CLI") var logger = ethlog.NewLogger("CLI")
@ -23,7 +27,7 @@ func main() {
Init() // parsing command line Init() // parsing command line
// If the difftool option is selected ignore all other log output // If the difftool option is selected ignore all other log output
if DiffTool { if DiffTool || Dump {
LogLevel = 0 LogLevel = 0
} }
@ -46,6 +50,32 @@ func main() {
ethereum := utils.NewEthereum(db, clientIdentity, keyManager, UseUPnP, OutboundPort, MaxPeer) 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 { if ShowGenesis {
utils.ShowGenesis(ethereum) utils.ShowGenesis(ethereum)
} }

View file

@ -2,18 +2,20 @@ package ethrepl
import ( import (
"fmt" "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" "io/ioutil"
"os" "os"
"path" "path"
"path/filepath" "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") var jsrelogger = ethlog.NewLogger("JSRE")
@ -23,8 +25,8 @@ type JSRE struct {
vm *otto.Otto vm *otto.Otto
lib *ethpub.PEthereum lib *ethpub.PEthereum
blockChan chan ethutil.React blockChan chan ethreact.Event
changeChan chan ethutil.React changeChan chan ethreact.Event
quitChan chan bool quitChan chan bool
objectCb map[string][]otto.Value objectCb map[string][]otto.Value
@ -49,8 +51,8 @@ func NewJSRE(ethereum *eth.Ethereum) *JSRE {
ethereum, ethereum,
otto.New(), otto.New(),
ethpub.NewPEthereum(ethereum), ethpub.NewPEthereum(ethereum),
make(chan ethutil.React, 1), make(chan ethreact.Event, 10),
make(chan ethutil.React, 1), make(chan ethreact.Event, 10),
make(chan bool), make(chan bool),
make(map[string][]otto.Value), 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" // We have to make sure that, whoever calls this, calls "Stop"
go re.mainLoop() go re.mainLoop()
// Subscribe to events
reactor := ethereum.Reactor()
reactor.Subscribe("newBlock", re.blockChan)
re.Bind("eth", &JSEthereum{re.lib, re.vm}) re.Bind("eth", &JSEthereum{re.lib, re.vm})
re.initStdFuncs() re.initStdFuncs()
@ -109,10 +115,6 @@ func (self *JSRE) Stop() {
} }
func (self *JSRE) mainLoop() { func (self *JSRE) mainLoop() {
// Subscribe to events
reactor := self.ethereum.Reactor()
reactor.Subscribe("newBlock", self.blockChan)
out: out:
for { for {
select { select {
@ -146,12 +148,44 @@ func (self *JSRE) initStdFuncs() {
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) eth.Set("execBlock", self.execBlock)
eth.Set("dump", self.dump)
} }
/* /*
* The following methods are natively implemented javascript functions * 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 { func (self *JSRE) stopMining(call otto.FunctionCall) otto.Value {
v, _ := self.vm.ToValue(utils.StopMining(self.ethereum)) v, _ := self.vm.ToValue(utils.StopMining(self.ethereum))
return v return v

View file

@ -127,6 +127,7 @@ func NewDatabase() ethutil.Database {
} }
func NewClientIdentity(clientIdentifier, version, customIdentifier string) *ethwire.SimpleClientIdentity { func NewClientIdentity(clientIdentifier, version, customIdentifier string) *ethwire.SimpleClientIdentity {
logger.Infoln("identity created")
return ethwire.NewSimpleClientIdentity(clientIdentifier, version, customIdentifier) return ethwire.NewSimpleClientIdentity(clientIdentifier, version, customIdentifier)
} }
@ -243,21 +244,18 @@ func GetMiner() *ethminer.Miner {
func StartMining(ethereum *eth.Ethereum) bool { func StartMining(ethereum *eth.Ethereum) bool {
if !ethereum.Mining { if !ethereum.Mining {
ethereum.Mining = true ethereum.Mining = true
addr := ethereum.KeyManager().Address() addr := ethereum.KeyManager().Address()
go func() { go func() {
logger.Infoln("Start mining")
if miner == nil { if miner == nil {
miner = ethminer.NewDefaultMiner(addr, ethereum) miner = ethminer.NewDefaultMiner(addr, ethereum)
} }
// Give it some time to connect with peers // Give it some time to connect with peers
time.Sleep(3 * time.Second) time.Sleep(3 * time.Second)
for !ethereum.IsUpToDate() { for !ethereum.IsUpToDate() {
time.Sleep(5 * time.Second) time.Sleep(5 * time.Second)
} }
logger.Infoln("Miner started")
miner.Start() miner.Start()
}() }()
RegisterInterrupt(func(os.Signal) { RegisterInterrupt(func(os.Signal) {
@ -271,9 +269,7 @@ func StartMining(ethereum *eth.Ethereum) bool {
func StopMining(ethereum *eth.Ethereum) bool { func StopMining(ethereum *eth.Ethereum) bool {
if ethereum.Mining && miner != nil { if ethereum.Mining && miner != nil {
miner.Stop() miner.Stop()
logger.Infoln("Stopped mining")
logger.Infoln("Miner stopped")
ethereum.Mining = false ethereum.Mining = false
return true return true