This commit is contained in:
BuildFuture 2014-08-13 21:40:00 +00:00
commit d386dd1d4a
27 changed files with 1723 additions and 1211 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

@ -0,0 +1,187 @@
import QtQuick 2.0
import QtQuick.Controls 1.0;
import QtQuick.Layouts 1.0;
import QtQuick.Dialogs 1.0;
import QtQuick.Window 2.1;
import QtQuick.Controls.Styles 1.1
import Ethereum 1.0
Rectangle {
property var title: "Network"
property var iconFile: "../net.png"
objectName: "chainView"
visible: false
anchors.fill: parent
TableView {
id: blockTable
width: parent.width
anchors.top: parent.top
anchors.bottom: parent.bottom
TableViewColumn{ role: "number" ; title: "#" ; width: 100 }
TableViewColumn{ role: "hash" ; title: "Hash" ; width: 560 }
TableViewColumn{ role: "txAmount" ; title: "Tx amount" ; width: 100 }
model: blockModel
onDoubleClicked: {
popup.visible = true
popup.setDetails(blockModel.get(row))
}
}
function addBlock(block, initial) {
var txs = JSON.parse(block.transactions);
var amount = 0
if(initial == undefined){
initial = false
}
if(txs != null){
amount = txs.length
}
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 {
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)})
}
}
Window {
id: popup
visible: false
//flags: Qt.CustomizeWindowHint | Qt.Tool | Qt.WindowCloseButtonHint
property var block
width: root.width
height: 300
Component{
id: blockDetailsDelegate
Rectangle {
color: "#252525"
width: popup.width
height: 150
Column {
anchors.leftMargin: 10
anchors.topMargin: 5
anchors.top: parent.top
anchors.left: parent.left
Text { text: '<h3>Block details</h3>'; color: "#F2F2F2"}
Text { text: '<b>Block number:</b> ' + number; color: "#F2F2F2"}
Text { text: '<b>Hash:</b> ' + hash; color: "#F2F2F2"}
Text { text: '<b>Coinbase:</b> &lt;' + name + '&gt; ' + coinbase; color: "#F2F2F2"}
Text { text: '<b>Block found at:</b> ' + prettyTime; color: "#F2F2F2"}
Text { text: '<b>Gas used:</b> ' + gasUsed + " / " + gasLimit; color: "#F2F2F2"}
}
}
}
ListView {
model: singleBlock
delegate: blockDetailsDelegate
anchors.top: parent.top
height: 100
anchors.leftMargin: 20
id: listViewThing
Layout.maximumHeight: 40
}
TableView {
id: txView
anchors.top: listViewThing.bottom
anchors.topMargin: 50
width: parent.width
TableViewColumn{width: 90; role: "value" ; title: "Value" }
TableViewColumn{width: 200; role: "hash" ; title: "Hash" }
TableViewColumn{width: 200; role: "sender" ; title: "Sender" }
TableViewColumn{width: 200;role: "address" ; title: "Receiver" }
TableViewColumn{width: 60; role: "gas" ; title: "Gas" }
TableViewColumn{width: 60; role: "gasPrice" ; title: "Gas Price" }
TableViewColumn{width: 60; role: "isContract" ; title: "Contract" }
model: transactionModel
onClicked: {
var tx = transactionModel.get(row)
if(tx.data) {
popup.showContractData(tx)
}else{
popup.height = 440
}
}
}
function showContractData(tx) {
txDetailsDebugButton.tx = tx
if(tx.createsContract) {
contractData.text = tx.data
contractLabel.text = "<h4> Transaction created contract " + tx.address + "</h4>"
}else{
contractLabel.text = "<h4> Transaction ran contract " + tx.address + "</h4>"
contractData.text = tx.rawData
}
popup.height = 540
}
Rectangle {
id: txDetails
width: popup.width
height: 300
anchors.left: listViewThing.left
anchors.top: txView.bottom
Label {
text: "<h4>Contract data</h4>"
anchors.top: parent.top
anchors.left: parent.left
id: contractLabel
anchors.leftMargin: 10
}
Button {
property var tx
id: txDetailsDebugButton
anchors.right: parent.right
anchors.rightMargin: 10
anchors.top: parent.top
anchors.topMargin: 10
text: "Debug contract"
onClicked: {
if(tx.createsContract){
eth.startDbWithCode(tx.rawData)
}else {
eth.startDbWithContractAndData(tx.address, tx.rawData)
}
}
}
TextArea {
id: contractData
text: "Contract"
anchors.top: contractLabel.bottom
anchors.left: parent.left
anchors.bottom: popup.bottom
wrapMode: Text.Wrap
width: parent.width - 30
height: 80
anchors.leftMargin: 10
}
}
property var transactionModel: ListModel {
id: transactionModel
}
property var singleBlock: ListModel {
id: singleBlock
}
function setDetails(block){
singleBlock.set(0,block)
popup.height = 300
transactionModel.clear()
if(block.txs != undefined){
for(var i = 0; i < block.txs.count; ++i) {
transactionModel.insert(0, block.txs.get(i))
}
if(block.txs.get(0).data){
popup.showContractData(block.txs.get(0))
}
}
txView.forceActiveFocus()
}
}
}

View file

@ -0,0 +1,50 @@
import QtQuick 2.0
import QtQuick.Controls 1.0;
import QtQuick.Layouts 1.0;
import QtQuick.Dialogs 1.0;
import QtQuick.Window 2.1;
import QtQuick.Controls.Styles 1.1
import Ethereum 1.0
Rectangle {
property var iconFile: "../tx.png"
property var title: "Transactions"
property var txModel: ListModel {
id: txModel
}
id: historyView
anchors.fill: parent
objectName: "transactionView"
TableView {
id: txTableView
anchors.fill: parent
TableViewColumn{ role: "inout" ; title: "" ; width: 40 }
TableViewColumn{ role: "value" ; title: "Value" ; width: 100 }
TableViewColumn{ role: "address" ; title: "Address" ; width: 430 }
TableViewColumn{ role: "contract" ; title: "Contract" ; width: 100 }
model: txModel
}
function addTx(type, tx, inout) {
var isContract
if (tx.contract == true){
isContract = "Yes"
}else{
isContract = "No"
}
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})
}
}

View file

@ -0,0 +1,160 @@
import QtQuick 2.0
import QtQuick.Controls 1.0;
import QtQuick.Layouts 1.0;
import QtQuick.Dialogs 1.0;
import QtQuick.Window 2.1;
import QtQuick.Controls.Styles 1.1
import Ethereum 1.0
Rectangle {
property var title: "Information"
property var iconFile: "../heart.png"
objectName: "infoView"
visible: false
anchors.fill: parent
color: "#00000000"
Column {
spacing: 3
anchors.fill: parent
anchors.topMargin: 5
anchors.leftMargin: 5
Label {
id: addressLabel
text: "Address"
}
TextField {
text: pub.getKey().address
width: 500
}
Label {
text: "Client ID"
}
TextField {
text: gui.getCustomIdentifier()
width: 500
placeholderText: "Anonymous"
onTextChanged: {
gui.setCustomIdentifier(text)
}
}
}
property var addressModel: ListModel {
id: addressModel
}
TableView {
id: addressView
width: parent.width - 200
height: 200
anchors.bottom: logLayout.top
TableViewColumn{ role: "name"; title: "name" }
TableViewColumn{ role: "address"; title: "address"; width: 300}
model: addressModel
}
Rectangle {
anchors.top: addressView.top
anchors.left: addressView.right
anchors.leftMargin: 20
TextField {
placeholderText: "Name to register"
id: nameToReg
width: 150
}
Button {
anchors.top: nameToReg.bottom
text: "Register"
MouseArea{
anchors.fill: parent
onClicked: {
gui.registerName(nameToReg.text)
nameToReg.text = ""
}
}
}
}
property var logModel: ListModel {
id: logModel
}
RowLayout {
id: logLayout
width: parent.width
height: 200
anchors.bottom: parent.bottom
TableView {
id: logView
headerVisible: false
anchors {
right: logLevelSlider.left
left: parent.left
bottom: parent.bottom
top: parent.top
}
TableViewColumn{ role: "description" ; title: "log" }
model: logModel
}
Slider {
id: logLevelSlider
value: gui.getLogLevelInt()
anchors {
right: parent.right
top: parent.top
bottom: parent.bottom
rightMargin: 5
leftMargin: 5
topMargin: 5
bottomMargin: 5
}
orientation: Qt.Vertical
maximumValue: 5
stepSize: 1
onValueChanged: {
gui.setLogLevel(value)
}
}
}
function addDebugMessage(message){
debuggerLog.append({value: message})
}
function addAddress(address) {
addressModel.append({name: address.name, address: address.address})
}
function clearAddress() {
addressModel.clear()
}
function addLog(str) {
// Remove first item once we've reached max log items
if(logModel.count > 250) {
logModel.remove(0)
}
if(str.len != 0) {
if(logView.flickableItem.atYEnd) {
logModel.append({description: str})
logView.positionViewAtRow(logView.rowCount - 1, ListView.Contain)
} else {
logModel.append({description: str})
}
}
}
}

View file

@ -0,0 +1,44 @@
import QtQuick 2.0
import QtQuick.Controls 1.0;
import QtQuick.Layouts 1.0;
import QtQuick.Dialogs 1.0;
import QtQuick.Window 2.1;
import QtQuick.Controls.Styles 1.1
import Ethereum 1.0
Rectangle {
property var title: "Pending Transactions"
property var iconFile: "../tx.png"
objectName: "pendingTxView"
anchors.fill: parent
visible: false
id: pendingTxView
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
}
function addTx(type, tx, inout) {
var isContract
if (tx.contract == true){
isContract = "Yes"
}else{
isContract = "No"
}
pendingTxModel.insert(0, {hash: tx.hash, to: tx.address, from: tx.sender, value: tx.value, contract: isContract})
}
}

View file

@ -0,0 +1,214 @@
import QtQuick 2.0
import QtQuick.Controls 1.0;
import QtQuick.Layouts 1.0;
import QtQuick.Dialogs 1.0;
import QtQuick.Window 2.1;
import QtQuick.Controls.Styles 1.1
import Ethereum 1.0
Rectangle {
property var iconFile: "../new.png"
property var title: "New transaction"
objectName: "newTxView"
visible: false
anchors.fill: parent
color: "#00000000"
Column {
id: mainContractColumn
anchors.fill: parent
states: [
State{
name: "ERROR"
PropertyChanges { target: txResult; visible:true}
PropertyChanges { target: codeView; visible:true}
},
State {
name: "DONE"
PropertyChanges { target: txValue; visible:false}
PropertyChanges { target: txGas; visible:false}
PropertyChanges { target: txGasPrice; visible:false}
PropertyChanges { target: codeView; visible:false}
PropertyChanges { target: txButton; visible:false}
PropertyChanges { target: txDataLabel; visible:false}
PropertyChanges { target: atLabel; visible:false}
PropertyChanges { target: txFuelRecipient; visible:false}
PropertyChanges { target: valueDenom; visible:false}
PropertyChanges { target: gasDenom; visible:false}
PropertyChanges { target: txResult; visible:true}
PropertyChanges { target: txOutput; visible:true}
PropertyChanges { target: newTxButton; visible:true}
},
State {
name: "SETUP"
PropertyChanges { target: txValue; visible:true; text: ""}
PropertyChanges { target: txGas; visible:true;}
PropertyChanges { target: txGasPrice; visible:true;}
PropertyChanges { target: codeView; visible:true; text: ""}
PropertyChanges { target: txButton; visible:true}
PropertyChanges { target: txDataLabel; visible:true}
PropertyChanges { target: valueDenom; visible:true}
PropertyChanges { target: gasDenom; visible:true}
PropertyChanges { target: txResult; visible:false}
PropertyChanges { target: txOutput; visible:false}
PropertyChanges { target: newTxButton; visible:false}
}
]
width: 400
spacing: 5
anchors.left: parent.left
anchors.top: parent.top
anchors.leftMargin: 5
anchors.topMargin: 5
ListModel {
id: denomModel
ListElement { text: "Wei" ; zeros: "" }
ListElement { text: "Ada" ; zeros: "000" }
ListElement { text: "Babbage" ; zeros: "000000" }
ListElement { text: "Shannon" ; zeros: "000000000" }
ListElement { text: "Szabo" ; zeros: "000000000000" }
ListElement { text: "Finney" ; zeros: "000000000000000" }
ListElement { text: "Ether" ; zeros: "000000000000000000" }
ListElement { text: "Einstein" ;zeros: "000000000000000000000" }
ListElement { text: "Douglas" ; zeros: "000000000000000000000000000000000000000000" }
}
TextField {
id: txFuelRecipient
placeholderText: "Address / Name or empty for contract"
//validator: RegExpValidator { regExp: /[a-f0-9]{40}/ }
width: 400
}
RowLayout {
TextField {
id: txValue
width: 222
placeholderText: "Amount"
validator: RegExpValidator { regExp: /\d*/ }
onTextChanged: {
contractFormReady()
}
}
ComboBox {
id: valueDenom
currentIndex: 6
model: denomModel
}
}
RowLayout {
TextField {
id: txGas
width: 50
validator: RegExpValidator { regExp: /\d*/ }
placeholderText: "Gas"
text: "500"
}
Label {
id: atLabel
text: "@"
}
TextField {
id: txGasPrice
width: 200
placeholderText: "Gas price"
text: "10"
validator: RegExpValidator { regExp: /\d*/ }
}
ComboBox {
id: gasDenom
currentIndex: 4
model: denomModel
}
}
Label {
id: txDataLabel
text: "Data"
}
TextArea {
id: codeView
height: 300
anchors.topMargin: 5
width: 400
onTextChanged: {
contractFormReady()
}
}
Button {
id: txButton
/* enabled: false */
states: [
State {
name: "READY"
PropertyChanges { target: txButton; /*enabled: true*/}
},
State {
name: "NOTREADY"
PropertyChanges { target: txButton; /*enabled:false*/}
}
]
text: "Send"
onClicked: {
var value = txValue.text + denomModel.get(valueDenom.currentIndex).zeros;
var gasPrice = txGasPrice.text + denomModel.get(gasDenom.currentIndex).zeros;
var res = gui.create(txFuelRecipient.text, value, txGas.text, gasPrice, codeView.text)
if(res[1]) {
txResult.text = "Your contract <b>could not</b> be sent over the network:\n<b>"
txResult.text += res[1].error()
txResult.text += "</b>"
mainContractColumn.state = "ERROR"
} else {
txResult.text = "Your transaction has been submitted:\n"
txOutput.text = res[0].address
mainContractColumn.state = "DONE"
}
}
}
Text {
id: txResult
visible: false
}
TextField {
id: txOutput
visible: false
width: 530
}
Button {
id: newTxButton
visible: false
text: "Create a new transaction"
onClicked: {
this.visible = false
txResult.text = ""
txOutput.text = ""
mainContractColumn.state = "SETUP"
}
}
}
function contractFormReady(){
if(codeView.text.length > 0 && txValue.text.length > 0 && txGas.text.length > 0 && txGasPrice.length > 0) {
txButton.state = "READY"
}else{
txButton.state = "NOTREADY"
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -21,19 +21,58 @@ 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 uri = this.text;
if(!/.*\:\/\/.*/.test(uri)) {
uri = "http://" + uri;
}
var reg = /(^https?\:\/\/(?:www\.)?)([a-zA-Z0-9_\-]*\.eth)(.*)/
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 += lookup;
} 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 +85,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 +136,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 +230,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")
@ -27,6 +30,7 @@ type Gui struct {
// QML Engine // QML Engine
engine *qml.Engine engine *qml.Engine
component *qml.Common component *qml.Common
qmlDone bool
// The ethereum interface // The ethereum interface
eth *eth.Ethereum eth *eth.Ethereum
@ -74,12 +78,12 @@ func (gui *Gui) Start(assetPath string) {
// Create a new QML engine // Create a new QML engine
gui.engine = qml.NewEngine() gui.engine = qml.NewEngine()
context := gui.engine.Context() context := gui.engine.Context()
gui.uiLib = NewUiLib(gui.engine, gui.eth, assetPath)
// Expose the eth library and the ui library to QML // Expose the eth library and the ui library to QML
context.SetVar("eth", gui) context.SetVar("gui", gui)
context.SetVar("pub", gui.pub) context.SetVar("pub", gui.pub)
gui.uiLib = NewUiLib(gui.engine, gui.eth, assetPath) context.SetVar("eth", gui.uiLib)
context.SetVar("ui", gui.uiLib)
// Load the main QML interface // Load the main QML interface
data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) data, _ := ethutil.Config.Db.Get([]byte("KeyRing"))
@ -102,11 +106,13 @@ func (gui *Gui) Start(assetPath string) {
logger.Infoln("Starting GUI") logger.Infoln("Starting GUI")
gui.open = true gui.open = true
win.Show() win.Show()
// only add the gui logger after window is shown otherwise slider wont be shown // only add the gui logger after window is shown otherwise slider wont be shown
if addlog { if addlog {
ethlog.AddLogSystem(gui) ethlog.AddLogSystem(gui)
} }
win.Wait() win.Wait()
// need to silence gui logger after window closed otherwise logsystem hangs (but do not save loglevel) // need to silence gui logger after window closed otherwise logsystem hangs (but do not save loglevel)
gui.logLevel = ethlog.Silence gui.logLevel = ethlog.Silence
gui.open = false gui.open = false
@ -118,6 +124,9 @@ func (gui *Gui) Stop() {
gui.open = false gui.open = false
gui.win.Hide() gui.win.Hide()
} }
gui.uiLib.jsEngine.Stop()
logger.Infoln("Stopped") logger.Infoln("Stopped")
} }
@ -141,18 +150,19 @@ func (gui *Gui) showWallet(context *qml.Context) (*qml.Window, error) {
return nil, err return nil, err
} }
win := gui.createWindow(component) gui.win = gui.createWindow(component)
go func() { gui.update()
gui.setInitialBlockChain()
gui.loadAddressBook()
gui.readPreviousTransactions()
gui.setPeerInfo()
}()
go gui.update() return gui.win, nil
}
return win, nil // The done handler will be called by QML when all views have been loaded
func (gui *Gui) Done() {
gui.qmlDone = true
}
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) {
@ -218,33 +228,69 @@ type address struct {
} }
func (gui *Gui) loadAddressBook() { func (gui *Gui) loadAddressBook() {
gui.win.Root().Call("clearAddress") view := gui.getObjectByName("infoView")
view.Call("clearAddress")
nameReg := ethpub.EthereumConfig(gui.eth.StateManager()).NameReg() nameReg := ethpub.EthereumConfig(gui.eth.StateManager()).NameReg()
if nameReg != nil { if nameReg != nil {
nameReg.EachStorage(func(name string, value *ethutil.Value) { nameReg.EachStorage(func(name string, value *ethutil.Value) {
if name[0] != 0 { if name[0] != 0 {
value.Decode() value.Decode()
gui.win.Root().Call("addAddress", struct{ Name, Address string }{name, ethutil.Bytes2Hex(value.Bytes())})
view.Call("addAddress", struct{ Name, Address string }{name, ethutil.Bytes2Hex(value.Bytes())})
} }
}) })
} }
} }
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.getObjectByName("transactionView").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()
@ -255,7 +301,7 @@ func (gui *Gui) processBlock(block *ethchain.Block, initial bool) {
b := ethpub.NewPBlock(block) b := ethpub.NewPBlock(block)
b.Name = name b.Name = name
gui.win.Root().Call("addBlock", b, initial) gui.getObjectByName("chainView").Call("addBlock", b, initial)
} }
func (gui *Gui) setWalletValue(amount, unconfirmedFunds *big.Int) { func (gui *Gui) setWalletValue(amount, unconfirmedFunds *big.Int) {
@ -280,17 +326,111 @@ 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() // We have to wait for qml to be done loading all the windows.
for !gui.qmlDone {
time.Sleep(500 * time.Millisecond)
}
go func() {
go gui.setInitialBlockChain()
gui.loadAddressBook()
gui.setPeerInfo()
gui.readPreviousTransactions()
}()
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.getObjectByName("transactionView").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.getObjectByName("transactionView").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 +443,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() {
@ -453,7 +513,9 @@ func (gui *Gui) Printf(format string, v ...interface{}) {
func (gui *Gui) printLog(s string) { func (gui *Gui) printLog(s string) {
str := strings.TrimRight(s, "\n") str := strings.TrimRight(s, "\n")
lines := strings.Split(str, "\n") lines := strings.Split(str, "\n")
view := gui.getObjectByName("infoView")
for _, line := range lines { for _, line := range lines {
gui.win.Root().Call("addLog", line) view.Call("addLog", line)
} }
} }

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,13 @@
package main package main
import ( import (
"github.com/ethereum/eth-go"
"github.com/ethereum/eth-go/ethutil"
"github.com/go-qml/qml"
"path" "path"
"github.com/ethereum/eth-go"
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/go-ethereum/javascript"
"github.com/go-qml/qml"
) )
type memAddr struct { type memAddr struct {
@ -22,10 +25,21 @@ type UiLib struct {
win *qml.Window win *qml.Window
Db *Debugger Db *Debugger
DbWindow *DebuggerWindow DbWindow *DebuggerWindow
jsEngine *javascript.JSRE
} }
func NewUiLib(engine *qml.Engine, eth *eth.Ethereum, assetPath string) *UiLib { func NewUiLib(engine *qml.Engine, eth *eth.Ethereum, assetPath string) *UiLib {
return &UiLib{engine: engine, eth: eth, assetPath: assetPath} return &UiLib{engine: engine, eth: eth, assetPath: assetPath, jsEngine: javascript.NewJSRE(eth)}
}
func (self *UiLib) ImportTx(rlpTx string) {
tx := ethchain.NewTransactionFromBytes(ethutil.Hex2Bytes(rlpTx))
self.eth.TxPool().QueueTransaction(tx)
}
func (self *UiLib) EvalJavascriptFile(path string) {
self.jsEngine.LoadExtFile(path[7:])
} }
func (ui *UiLib) OpenQml(path string) { func (ui *UiLib) OpenQml(path string) {
@ -42,6 +56,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 {
@ -94,7 +112,6 @@ func (self *UiLib) StartDbWithCode(code string) {
func (self *UiLib) StartDebugger() { func (self *UiLib) StartDebugger() {
dbWindow := NewDebuggerWindow(self) dbWindow := NewDebuggerWindow(self)
//self.DbWindow = dbWindow
dbWindow.Show() dbWindow.Show()
} }

View file

@ -1,11 +1,13 @@
package main package main
import ( import (
"github.com/ethereum/eth-go"
"github.com/ethereum/go-ethereum/ethereum/repl"
"github.com/ethereum/go-ethereum/utils"
"io/ioutil" "io/ioutil"
"os" "os"
"github.com/ethereum/eth-go"
"github.com/ethereum/go-ethereum/ethereum/repl"
"github.com/ethereum/go-ethereum/javascript"
"github.com/ethereum/go-ethereum/utils"
) )
func InitJsConsole(ethereum *eth.Ethereum) { func InitJsConsole(ethereum *eth.Ethereum) {
@ -25,7 +27,7 @@ func ExecJsFile(ethereum *eth.Ethereum, InputFile string) {
if err != nil { if err != nil {
logger.Fatalln(err) logger.Fatalln(err)
} }
re := ethrepl.NewJSRE(ethereum) re := javascript.NewJSRE(ethereum)
utils.RegisterInterrupt(func(os.Signal) { utils.RegisterInterrupt(func(os.Signal) {
re.Stop() re.Stop()
}) })

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

@ -3,12 +3,14 @@ package ethrepl
import ( import (
"bufio" "bufio"
"fmt" "fmt"
"github.com/ethereum/eth-go"
"github.com/ethereum/eth-go/ethlog"
"github.com/ethereum/eth-go/ethutil"
"io" "io"
"os" "os"
"path" "path"
"github.com/ethereum/eth-go"
"github.com/ethereum/eth-go/ethlog"
"github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/go-ethereum/javascript"
) )
var logger = ethlog.NewLogger("REPL") var logger = ethlog.NewLogger("REPL")
@ -19,7 +21,7 @@ type Repl interface {
} }
type JSRepl struct { type JSRepl struct {
re *JSRE re *javascript.JSRE
prompt string prompt string
@ -34,7 +36,7 @@ func NewJSRepl(ethereum *eth.Ethereum) *JSRepl {
panic(err) panic(err)
} }
return &JSRepl{re: NewJSRE(ethereum), prompt: "> ", history: hist} return &JSRepl{re: javascript.NewJSRE(ethereum), prompt: "> ", history: hist}
} }
func (self *JSRepl) Start() { func (self *JSRepl) Start() {

View file

@ -115,8 +115,8 @@ L:
} }
func (self *JSRepl) PrintValue(v interface{}) { func (self *JSRepl) PrintValue(v interface{}) {
method, _ := self.re.vm.Get("prettyPrint") method, _ := self.re.Vm.Get("prettyPrint")
v, err := self.re.vm.ToValue(v) v, err := self.re.Vm.ToValue(v)
if err == nil { if err == nil {
method.Call(method, v) method.Call(method, v)
} }

View file

@ -1,30 +1,32 @@
package ethrepl package javascript
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")
type JSRE struct { type JSRE struct {
ethereum *eth.Ethereum ethereum *eth.Ethereum
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
@ -33,9 +35,9 @@ type JSRE struct {
func (jsre *JSRE) LoadExtFile(path string) { func (jsre *JSRE) LoadExtFile(path string) {
result, err := ioutil.ReadFile(path) result, err := ioutil.ReadFile(path)
if err == nil { if err == nil {
jsre.vm.Run(result) jsre.Vm.Run(result)
} else { } else {
jsrelogger.Debugln("Could not load file:", path) jsrelogger.Infoln("Could not load file:", path)
} }
} }
@ -49,14 +51,14 @@ 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),
} }
// Init the JS lib // Init the JS lib
re.vm.Run(jsLib) re.Vm.Run(jsLib)
// Load extra javascript files // Load extra javascript files
re.LoadIntFile("string.js") re.LoadIntFile("string.js")
@ -65,7 +67,11 @@ 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()
re.Bind("eth", &JSEthereum{re.lib, re.vm}) // Subscribe to events
reactor := ethereum.Reactor()
reactor.Subscribe("newBlock", re.blockChan)
re.Bind("eth", &JSEthereum{re.lib, re.Vm, ethereum})
re.initStdFuncs() re.initStdFuncs()
@ -75,11 +81,11 @@ func NewJSRE(ethereum *eth.Ethereum) *JSRE {
} }
func (self *JSRE) Bind(name string, v interface{}) { func (self *JSRE) Bind(name string, v interface{}) {
self.vm.Set(name, v) self.Vm.Set(name, v)
} }
func (self *JSRE) Run(code string) (otto.Value, error) { func (self *JSRE) Run(code string) (otto.Value, error) {
return self.vm.Run(code) return self.Vm.Run(code)
} }
func (self *JSRE) Require(file string) error { func (self *JSRE) Require(file string) error {
@ -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 {
@ -124,12 +126,12 @@ out:
case object := <-self.changeChan: case object := <-self.changeChan:
if stateObject, ok := object.Resource.(*ethstate.StateObject); ok { if stateObject, ok := object.Resource.(*ethstate.StateObject); ok {
for _, cb := range self.objectCb[ethutil.Bytes2Hex(stateObject.Address())] { for _, cb := range self.objectCb[ethutil.Bytes2Hex(stateObject.Address())] {
val, _ := self.vm.ToValue(ethpub.NewPStateObject(stateObject)) val, _ := self.Vm.ToValue(ethpub.NewPStateObject(stateObject))
cb.Call(cb, val) cb.Call(cb, val)
} }
} else if storageObject, ok := object.Resource.(*ethstate.StorageState); ok { } else if storageObject, ok := object.Resource.(*ethstate.StorageState); ok {
for _, cb := range self.objectCb[ethutil.Bytes2Hex(storageObject.StateAddress)+ethutil.Bytes2Hex(storageObject.Address)] { for _, cb := range self.objectCb[ethutil.Bytes2Hex(storageObject.StateAddress)+ethutil.Bytes2Hex(storageObject.Address)] {
val, _ := self.vm.ToValue(ethpub.NewPStorageState(storageObject)) val, _ := self.Vm.ToValue(ethpub.NewPStorageState(storageObject))
cb.Call(cb, val) cb.Call(cb, val)
} }
} }
@ -138,7 +140,7 @@ out:
} }
func (self *JSRE) initStdFuncs() { func (self *JSRE) initStdFuncs() {
t, _ := self.vm.Get("eth") t, _ := self.Vm.Get("eth")
eth := t.Object() eth := t.Object()
eth.Set("watch", self.watch) eth.Set("watch", self.watch)
eth.Set("addPeer", self.addPeer) eth.Set("addPeer", self.addPeer)
@ -146,19 +148,51 @@ 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
} }
func (self *JSRE) startMining(call otto.FunctionCall) otto.Value { func (self *JSRE) startMining(call otto.FunctionCall) otto.Value {
v, _ := self.vm.ToValue(utils.StartMining(self.ethereum)) v, _ := self.Vm.ToValue(utils.StartMining(self.ethereum))
return v return v
} }
@ -211,7 +245,7 @@ func (self *JSRE) require(call otto.FunctionCall) otto.Value {
return otto.UndefinedValue() return otto.UndefinedValue()
} }
t, _ := self.vm.Get("exports") t, _ := self.Vm.Get("exports")
return t return t
} }

View file

@ -1,4 +1,4 @@
package ethrepl package javascript
const jsLib = ` const jsLib = `
function pp(object) { function pp(object) {

View file

@ -1,8 +1,12 @@
package ethrepl package javascript
import ( import (
"fmt" "fmt"
"github.com/ethereum/eth-go"
"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/ethutil" "github.com/ethereum/eth-go/ethutil"
"github.com/obscuren/otto" "github.com/obscuren/otto"
) )
@ -34,9 +38,37 @@ func (self *JSBlock) GetTransaction(hash string) otto.Value {
return self.eth.toVal(self.PBlock.GetTransaction(hash)) return self.eth.toVal(self.PBlock.GetTransaction(hash))
} }
type JSMessage struct {
To, From string
Input string
Output string
Path int
Origin string
Timestamp int32
Coinbase string
Block string
Number int32
}
func NewJSMessage(message *ethstate.Message) JSMessage {
return JSMessage{
To: ethutil.Bytes2Hex(message.To),
From: ethutil.Bytes2Hex(message.From),
Input: ethutil.Bytes2Hex(message.Input),
Output: ethutil.Bytes2Hex(message.Output),
Path: message.Path,
Origin: ethutil.Bytes2Hex(message.Origin),
Timestamp: int32(message.Timestamp),
Coinbase: ethutil.Bytes2Hex(message.Origin),
Block: ethutil.Bytes2Hex(message.Block),
Number: int32(message.Number.Int64()),
}
}
type JSEthereum struct { type JSEthereum struct {
*ethpub.PEthereum *ethpub.PEthereum
vm *otto.Otto vm *otto.Otto
ethereum *eth.Ethereum
} }
func (self *JSEthereum) GetBlock(hash string) otto.Value { func (self *JSEthereum) GetBlock(hash string) otto.Value {
@ -93,3 +125,46 @@ func (self *JSEthereum) toVal(v interface{}) otto.Value {
return result return result
} }
func (self *JSEthereum) Messages(object map[string]interface{}) otto.Value {
filter := ethchain.NewFilter(self.ethereum)
if object["earliest"] != nil {
earliest := object["earliest"]
if e, ok := earliest.(string); ok {
filter.SetEarliestBlock(ethutil.Hex2Bytes(e))
} else {
filter.SetEarliestBlock(earliest)
}
}
if object["latest"] != nil {
latest := object["latest"]
if l, ok := latest.(string); ok {
filter.SetLatestBlock(ethutil.Hex2Bytes(l))
} else {
filter.SetLatestBlock(latest)
}
}
if object["to"] != nil {
filter.SetTo(ethutil.Hex2Bytes(object["to"].(string)))
}
if object["from"] != nil {
filter.SetFrom(ethutil.Hex2Bytes(object["from"].(string)))
}
if object["max"] != nil {
filter.SetMax(object["max"].(int))
}
if object["skip"] != nil {
filter.SetSkip(object["skip"].(int))
}
messages := filter.Find()
var msgs []JSMessage
for _, m := range messages {
msgs = append(msgs, NewJSMessage(m))
}
v, _ := self.vm.ToValue(msgs)
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

View file

@ -1,9 +1,10 @@
package utils package utils
import ( import (
"math/big"
"github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethstate" "github.com/ethereum/eth-go/ethstate"
"math/big"
) )
type VMEnv struct { type VMEnv struct {
@ -29,5 +30,6 @@ func (self *VMEnv) PrevHash() []byte { return self.block.PrevHash }
func (self *VMEnv) Coinbase() []byte { return self.block.Coinbase } func (self *VMEnv) Coinbase() []byte { return self.block.Coinbase }
func (self *VMEnv) Time() int64 { return self.block.Time } func (self *VMEnv) Time() int64 { return self.block.Time }
func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty } func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty }
func (self *VMEnv) BlockHash() []byte { return self.block.Hash() }
func (self *VMEnv) Value() *big.Int { return self.value } func (self *VMEnv) Value() *big.Int { return self.value }
func (self *VMEnv) State() *ethstate.State { return self.state } func (self *VMEnv) State() *ethstate.State { return self.state }