Merge branch 'develop' of github.com:ethereum/go-ethereum into develop

pull/84/head
zelig 11 years ago
commit 50fdfb127a
  1. 14
      README.md
  2. 264
      ethereal/assets/debugger/debugger.qml
  3. 4
      ethereal/assets/ext/ethereum.js
  4. BIN
      ethereal/assets/heart.png
  5. 196
      ethereal/assets/qml/newTransaction/_new_contract.qml
  6. 112
      ethereal/assets/qml/newTransaction/_simple_send.qml
  7. 730
      ethereal/assets/qml/wallet.qml
  8. 31
      ethereal/assets/qml/webapp.qml
  9. 2
      ethereal/assets/samplecoin/samplecoin.html
  10. 27
      ethereal/config.go
  11. 15
      ethereal/ethereum.go
  12. 225
      ethereal/ui/debugger.go
  13. 127
      ethereal/ui/gui.go
  14. 82
      ethereal/ui/ui_lib.go
  15. 22
      ethereum/config.go
  16. 12
      ethereum/ethereum.go
  17. 19
      ethereum/javascript_runtime.go
  18. 10
      ethereum/repl.go
  19. 9
      utils/cmd.go

@ -5,7 +5,7 @@ Ethereum
Ethereum Go Client © 2014 Jeffrey Wilcke. Ethereum Go Client © 2014 Jeffrey Wilcke.
Current state: Proof of Concept 5.0 RC8. Current state: Proof of Concept 5.0 RC12.
For the development package please see the [eth-go package](https://github.com/ethereum/eth-go). For the development package please see the [eth-go package](https://github.com/ethereum/eth-go).
@ -27,20 +27,22 @@ General command line options
``` ```
Shared between ethereum and ethereal Shared between ethereum and ethereal
-m Start mining blocks -id Set the custom identifier of the client (shows up on other clients)
-genaddr Generates a new address and private key (destructive action) -port Port on which the server will accept incomming connections
-p Port on which the server will accept incomming connections
-upnp Enable UPnP -upnp Enable UPnP
-x Desired amount of peers -maxpeer Desired amount of peers
-r Start JSON RPC -rpc Start JSON RPC
-dir Data directory used to store configs and databases -dir Data directory used to store configs and databases
-import Import a private key -import Import a private key
-genaddr Generates a new address and private key (destructive action)
-h This -h This
Ethereum only Ethereum only
ethereum [options] [filename] ethereum [options] [filename]
-js Start the JavaScript REPL -js Start the JavaScript REPL
filename Load the given file and interpret as JavaScript filename Load the given file and interpret as JavaScript
-m Start mining blocks
Etheral only Etheral only
-asset_path absolute path to GUI assets directory -asset_path absolute path to GUI assets directory

@ -0,0 +1,264 @@
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
ApplicationWindow {
visible: false
title: "IceCREAM"
minimumWidth: 1280
minimumHeight: 900
width: 1290
height: 900
property alias codeText: codeEditor.text
property alias dataText: rawDataField.text
MenuBar {
Menu {
title: "Debugger"
MenuItem {
text: "Run"
shortcut: "Ctrl+r"
onTriggered: debugCurrent()
}
MenuItem {
text: "Next"
shortcut: "Ctrl+n"
onTriggered: dbg.next()
}
}
}
SplitView {
anchors.fill: parent
property var asmModel: ListModel {
id: asmModel
}
TableView {
id: asmTableView
width: 200
TableViewColumn{ role: "value" ; title: "" ; width: 100 }
model: asmModel
}
Rectangle {
color: "#00000000"
anchors.left: asmTableView.right
anchors.right: parent.right
SplitView {
orientation: Qt.Vertical
anchors.fill: parent
Rectangle {
color: "#00000000"
height: 500
anchors.left: parent.left
anchors.right: parent.right
TextArea {
id: codeEditor
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: settings.left
}
Column {
id: settings
spacing: 5
width: 300
height: parent.height
anchors.right: parent.right
anchors.top: parent.top
anchors.bottom: parent.bottom
Label {
text: "Arbitrary data"
}
TextArea {
id: rawDataField
anchors.left: parent.left
anchors.right: parent.right
height: 150
}
Label {
text: "Amount"
}
TextField {
id: txValue
width: 200
placeholderText: "Amount"
validator: RegExpValidator { regExp: /\d*/ }
}
Label {
text: "Amount of gas"
}
TextField {
id: txGas
width: 200
validator: RegExpValidator { regExp: /\d*/ }
text: "10000"
placeholderText: "Gas"
}
Label {
text: "Gas price"
}
TextField {
id: txGasPrice
width: 200
placeholderText: "Gas price"
text: "1000000000000"
validator: RegExpValidator { regExp: /\d*/ }
}
}
}
SplitView {
orientation: Qt.Vertical
id: inspectorPane
height: 500
SplitView {
orientation: Qt.Horizontal
height: 150
TableView {
id: stackTableView
property var stackModel: ListModel {
id: stackModel
}
height: parent.height
width: 300
TableViewColumn{ role: "value" ; title: "Stack" ; width: 200 }
model: stackModel
}
TableView {
id: memoryTableView
property var memModel: ListModel {
id: memModel
}
height: parent.height
width: parent.width - stackTableView.width
TableViewColumn{ id:mnumColmn ; role: "num" ; title: "#" ; width: 50}
TableViewColumn{ role: "value" ; title: "Memory" ; width: 750}
model: memModel
}
}
Rectangle {
height: 100
width: parent.width
TableView {
id: storageTableView
property var memModel: ListModel {
id: storageModel
}
height: parent.height
width: parent.width
TableViewColumn{ id: key ; role: "key" ; title: "#" ; width: storageTableView.width / 2}
TableViewColumn{ role: "value" ; title: "Storage" ; width: storageTableView.width / 2}
model: storageModel
}
}
Rectangle {
height: 200
width: parent.width
TableView {
id: logTableView
property var logModel: ListModel {
id: logModel
}
height: parent.height
width: parent.width
TableViewColumn{ id: message ; role: "message" ; title: "log" ; width: logTableView.width }
model: logModel
}
}
}
}
}
}
toolBar: ToolBar {
RowLayout {
spacing: 5
Button {
property var enabled: true
id: debugStart
onClicked: {
debugCurrent()
}
text: "Debug"
}
Button {
property var enabled: true
id: debugNextButton
onClicked: {
dbg.next()
}
text: "Next"
}
}
}
function debugCurrent() {
dbg.debug(txValue.text, txGas.text, txGasPrice.text, codeEditor.text, rawDataField.text)
}
function setAsm(asm) {
asmModel.append({asm: asm})
}
function clearAsm() {
asmModel.clear()
}
function setInstruction(num) {
//asmTableView.selection.clear()
//asmTableView.selection.select(num)
}
function setMem(mem) {
memModel.append({num: mem.num, value: mem.value})
}
function clearMem(){
memModel.clear()
}
function setStack(stack) {
stackModel.append({value: stack})
}
function addDebugMessage(message){
debuggerLog.append({value: message})
}
function clearStack() {
stackModel.clear()
}
function clearStorage() {
storageModel.clear()
}
function setStorage(storage) {
storageModel.append({key: storage.key, value: storage.value})
}
function setLog(msg) {
logModel.insert(0, {message: msg})
}
function clearLog() {
logModel.clear()
}
}

@ -32,6 +32,10 @@ window.eth = {
postData({call: "getStorage", args: [address, storageAddress]}, cb); postData({call: "getStorage", args: [address, storageAddress]}, cb);
}, },
getStateKeyVals: function(address, cb){
postData({call: "getStateKeyVals", args: [address]}, cb);
},
getKey: function(cb) { getKey: function(cb) {
postData({call: "getKey"}, cb); postData({call: "getKey"}, cb);
}, },

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

@ -1,196 +0,0 @@
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
Component {
id: newContract
Column {
id: mainContractColumn
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"
}
}
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: 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; text: ""}
PropertyChanges { target: txGasPrice; visible:true; text: ""}
PropertyChanges { target: codeView; visible:true; text: ""}
PropertyChanges { target: txButton; visible:true}
PropertyChanges { target: txDataLabel; 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
TextField {
id: txValue
width: 200
placeholderText: "Amount"
validator: RegExpValidator { regExp: /\d*/ }
onTextChanged: {
contractFormReady()
}
}
TextField {
id: txGas
width: 200
validator: RegExpValidator { regExp: /\d*/ }
placeholderText: "Gas"
onTextChanged: {
contractFormReady()
}
}
TextField {
id: txGasPrice
width: 200
placeholderText: "Gas price"
validator: RegExpValidator { regExp: /\d*/ }
onTextChanged: {
contractFormReady()
}
}
Row {
id: rowContract
ExclusiveGroup { id: contractTypeGroup }
RadioButton {
id: createContractRadio
text: "Create contract"
checked: true
exclusiveGroup: contractTypeGroup
onClicked: {
txFuelRecipient.visible = false
txDataLabel.text = "Contract code"
}
}
RadioButton {
id: runContractRadio
text: "Run contract"
exclusiveGroup: contractTypeGroup
onClicked: {
txFuelRecipient.visible = true
txDataLabel.text = "Contract arguments"
}
}
}
Label {
id: txDataLabel
text: "Contract code"
}
TextArea {
id: codeView
height: 300
anchors.topMargin: 5
Layout.fillWidth: true
width: parent.width /2
onTextChanged: {
contractFormReady()
}
}
TextField {
id: txFuelRecipient
placeholderText: "Contract address"
validator: RegExpValidator { regExp: /[a-f0-9]{40}/ }
visible: false
width: 530
}
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: {
//this.enabled = false
var res = eth.create(txFuelRecipient.text, txValue.text, txGas.text, txGasPrice.text, codeView.text)
if(res[1]) {
txResult.text = "Your contract <b>could not</b> be send 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 an other contract"
onClicked: {
this.visible = false
txResult.text = ""
txOutput.text = ""
mainContractColumn.state = "SETUP"
}
}
Button {
id: debugButton
text: "Debug"
onClicked: {
var res = ui.debugTx("", txValue.text, txGas.text, txGasPrice.text, codeView.text)
debugWindow.visible = true
}
}
}
}

@ -1,112 +0,0 @@
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
Component {
id: newTransaction
Column {
id: simpleSendColumn
states: [
State{
name: "ERROR"
},
State {
name: "DONE"
PropertyChanges { target: txSimpleValue; visible:false}
PropertyChanges { target: txSimpleRecipient; visible:false}
PropertyChanges { target:newSimpleTxButton; visible:false}
PropertyChanges { target: txSimpleResult; visible:true}
PropertyChanges { target: txSimpleOutput; visible:true}
PropertyChanges { target:newSimpleTxButton; visible:true}
},
State {
name: "SETUP"
PropertyChanges { target: txSimpleValue; visible:true; text: ""}
PropertyChanges { target: txSimpleRecipient; visible:true; text: ""}
PropertyChanges { target: txSimpleButton; visible:true}
PropertyChanges { target:newSimpleTxButton; visible:false}
}
]
spacing: 5
anchors.leftMargin: 5
anchors.topMargin: 5
anchors.top: parent.top
anchors.left: parent.left
function checkFormState(){
if(txSimpleRecipient.text.length == 40 && txSimpleValue.text.length > 0) {
txSimpleButton.state = "READY"
}else{
txSimpleButton.state = "NOTREADY"
}
}
TextField {
id: txSimpleRecipient
placeholderText: "Recipient address"
Layout.fillWidth: true
validator: RegExpValidator { regExp: /[a-f0-9]{40}/ }
width: 530
onTextChanged: { checkFormState() }
}
TextField {
id: txSimpleValue
width: 200
placeholderText: "Amount"
anchors.rightMargin: 5
validator: RegExpValidator { regExp: /\d*/ }
onTextChanged: { checkFormState() }
}
Button {
id: txSimpleButton
/*enabled: false*/
states: [
State {
name: "READY"
PropertyChanges { target: txSimpleButton; /*enabled: true*/}
},
State {
name: "NOTREADY"
PropertyChanges { target: txSimpleButton; /*enabled: false*/}
}
]
text: "Send"
onClicked: {
//this.enabled = false
var res = eth.transact(txSimpleRecipient.text, txSimpleValue.text,"","","")
if(res[1]) {
txSimpleResult.text = "There has been an error broadcasting your transaction:" + res[1].error()
} else {
txSimpleResult.text = "Your transaction has been broadcasted over the network.\nYour transaction id is:"
txSimpleOutput.text = res[0].hash
this.visible = false
simpleSendColumn.state = "DONE"
}
}
}
Text {
id: txSimpleResult
visible: false
}
TextField {
id: txSimpleOutput
visible: false
width: 530
}
Button {
id: newSimpleTxButton
visible: false
text: "Create an other transaction"
onClicked: {
this.visible = false
simpleSendColumn.state = "SETUP"
}
}
}
}

@ -6,9 +6,12 @@ import QtQuick.Window 2.1;
import QtQuick.Controls.Styles 1.1 import QtQuick.Controls.Styles 1.1
import Ethereum 1.0 import Ethereum 1.0
ApplicationWindow { ApplicationWindow {
id: root id: root
property alias miningButtonText: miningButton.text
width: 900 width: 900
height: 600 height: 600
minimumHeight: 300 minimumHeight: 300
@ -23,10 +26,13 @@ ApplicationWindow {
shortcut: "Ctrl+o" shortcut: "Ctrl+o"
onTriggered: openAppDialog.open() onTriggered: openAppDialog.open()
} }
}
Menu {
MenuItem { MenuItem {
text: "Muted" text: "Debugger"
shortcut: "Ctrl+e" shortcut: "Ctrl+d"
onTriggered: ui.muted("") onTriggered: ui.startDebugger()
} }
} }
@ -39,10 +45,12 @@ ApplicationWindow {
addPeerWin.visible = true addPeerWin.visible = true
} }
} }
MenuItem { MenuItem {
text: "Start" text: "Show Peers"
onTriggered: ui.connect() shortcut: "Ctrl+e"
onTriggered: {
peerWindow.visible = true
}
} }
} }
@ -85,7 +93,6 @@ ApplicationWindow {
//color: "#D9DDE7" //color: "#D9DDE7"
color: "#252525" color: "#252525"
ColumnLayout { ColumnLayout {
y: 50 y: 50
anchors.left: parent.left anchors.left: parent.left
@ -123,7 +130,7 @@ ApplicationWindow {
} }
Image { Image {
source: ui.assetPath("net.png") source: ui.assetPath("heart.png")
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
@ -155,6 +162,7 @@ ApplicationWindow {
TableView { TableView {
id: txTableView id: txTableView
anchors.fill: parent anchors.fill: parent
TableViewColumn{ role: "inout" ; title: "" ; width: 40 }
TableViewColumn{ role: "value" ; title: "Value" ; width: 100 } TableViewColumn{ role: "value" ; title: "Value" ; width: 100 }
TableViewColumn{ role: "address" ; title: "Address" ; width: 430 } TableViewColumn{ role: "address" ; title: "Address" ; width: 430 }
TableViewColumn{ role: "contract" ; title: "Contract" ; width: 100 } TableViewColumn{ role: "contract" ; title: "Contract" ; width: 100 }
@ -169,6 +177,7 @@ ApplicationWindow {
visible: false visible: false
anchors.fill: parent anchors.fill: parent
color: "#00000000" color: "#00000000"
/*
TabView{ TabView{
anchors.fill: parent anchors.fill: parent
anchors.rightMargin: 5 anchors.rightMargin: 5
@ -177,16 +186,14 @@ ApplicationWindow {
anchors.bottomMargin: 5 anchors.bottomMargin: 5
id: newTransactionTab id: newTransactionTab
Component.onCompleted:{ Component.onCompleted:{
var component = Qt.createComponent("newTransaction/_simple_send.qml")
var newTransaction = component.createObject("newTransaction")
component = Qt.createComponent("newTransaction/_new_contract.qml")
var newContract = component.createObject("newContract")
addTab("Simple send", newTransaction) addTab("Simple send", newTransaction)
addTab("Contracts", newContract) addTab("Contracts", newContract)
} }
} }
*/
Component.onCompleted: {
newContract.createObject(newTxView)
}
} }
Rectangle { Rectangle {
@ -199,34 +206,19 @@ ApplicationWindow {
id: blockTable id: blockTable
width: parent.width width: parent.width
anchors.top: parent.top anchors.top: parent.top
anchors.bottom: logView.top anchors.bottom: parent.bottom
TableViewColumn{ role: "number" ; title: "#" ; width: 100 } TableViewColumn{ role: "number" ; title: "#" ; width: 100 }
TableViewColumn{ role: "hash" ; title: "Hash" ; width: 560 } TableViewColumn{ role: "hash" ; title: "Hash" ; width: 560 }
TableViewColumn{ role: "txAmount" ; title: "Tx amount" ; width: 100 }
model: blockModel model: blockModel
/*
onDoubleClicked: { onDoubleClicked: {
popup.visible = true popup.visible = true
popup.block = eth.getBlock(blockModel.get(row).hash) popup.setDetails(blockModel.get(row))
popup.hashLabel.text = popup.block.hash
} }
*/
} }
property var logModel: ListModel {
id: logModel
}
TableView {
id: logView
width: parent.width
height: 150
anchors.bottom: parent.bottom
TableViewColumn{ role: "description" ; title: "log" }
model: logModel
}
} }
Rectangle { Rectangle {
@ -236,24 +228,83 @@ ApplicationWindow {
color: "#00000000" color: "#00000000"
anchors.fill: parent anchors.fill: parent
Column {
spacing: 3
anchors.fill: parent
anchors.topMargin: 5
anchors.leftMargin: 5
Label { Label {
id: addressLabel id: addressLabel
text: "Address" text: "Address"
anchors {
margins: 5
top: parent.top
left: parent.left
}
} }
TextField { TextField {
anchors {
margins: 5
left: addressLabel.right
top: parent.top
}
text: pub.getKey().address text: pub.getKey().address
width: 500 width: 500
} }
Label {
text: "Client ID"
}
TextField {
text: eth.clientId()
onTextChanged: {
eth.changeClientId(text)
}
}
}
property var addressModel: ListModel {
id: addressModel
}
TableView {
id: addressView
width: parent.width - 200
height: 200
anchors.bottom: logView.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: {
eth.registerName(nameToReg.text)
nameToReg.text = ""
}
}
}
}
property var logModel: ListModel {
id: logModel
}
TableView {
id: logView
width: parent.width
height: 200
anchors.bottom: parent.bottom
TableViewColumn{ role: "description" ; title: "log" }
model: logModel
}
} }
/* /*
@ -287,27 +338,32 @@ 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")))
ui.openHtml(openAppDialog.fileUrl.toString()) ui.openHtml(openAppDialog.fileUrl.toString())
} }
} }
statusBar: StatusBar { statusBar: StatusBar {
height: 30
RowLayout { RowLayout {
anchors.fill: parent
Button { Button {
property var enabled: true id: miningButton
id: connectButton
onClicked: { onClicked: {
if(this.enabled) { eth.toggleMining()
ui.connect(this) }
text: "Start Mining"
} }
Button {
property var enabled: true
id: debuggerWindow
onClicked: {
ui.startDebugger()
} }
text: "Connect" text: "Debugger"
} }
Button { Button {
id: importAppButton id: importAppButton
anchors.left: connectButton.right anchors.left: debuggerWindow.right
anchors.leftMargin: 5 anchors.leftMargin: 5
onClicked: openAppDialog.open() onClicked: openAppDialog.open()
text: "Import App" text: "Import App"
@ -318,8 +374,10 @@ ApplicationWindow {
anchors.leftMargin: 5 anchors.leftMargin: 5
id: walletValueLabel id: walletValueLabel
} }
}
Label { Label {
y: 7
anchors.right: peerImage.left anchors.right: peerImage.left
anchors.rightMargin: 5 anchors.rightMargin: 5
id: peerLabel id: peerLabel
@ -327,11 +385,15 @@ ApplicationWindow {
text: "0 / 0" text: "0 / 0"
} }
Image { Image {
y: 7
id: peerImage id: peerImage
anchors.right: parent.right anchors.right: parent.right
width: 10; height: 10 width: 10; height: 10
source: ui.assetPath("network.png") MouseArea {
onDoubleClicked: peerWindow.visible = true
anchors.fill: parent
} }
source: ui.assetPath("network.png")
} }
} }
@ -339,10 +401,134 @@ ApplicationWindow {
id: popup id: popup
visible: false visible: false
property var block 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> ' + 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 { Label {
id: hashLabel text: "<h4>Contract data</h4>"
anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top
anchors.verticalCenter: parent.verticalCenter 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){
ui.startDbWithCode(tx.rawData)
}else {
ui.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()
} }
} }
@ -404,147 +590,403 @@ 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><h3>Binary Distribution</h3>Jarrad Hope<br>" text: "<h2>Ethereal</h2><br><h3>Development</h3>Jeffrey Wilcke<br>Maran Hidskes<br>"
}
} }
function addDebugMessage(message){
debuggerLog.append({value: message})
} }
Window { function addAddress(address) {
id: debugWindow addressModel.append({name: address.name, address: address.address})
visible: false }
title: "Debugger" function clearAddress() {
minimumWidth: 600 addressModel.clear()
minimumHeight: 600 }
width: 800
height: 600
function loadPlugin(name) {
console.log("Loading plugin" + name)
mainView.addPlugin(name)
}
function setWalletValue(value) {
walletValueLabel.text = value
}
Item { function addTx(tx, inout) {
id: keyHandler var isContract
focus: true if (tx.contract == true){
Keys.onPressed: { isContract = "Yes"
if (event.key == Qt.Key_Space) { }else{
ui.next() 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})
} }
SplitView {
anchors.fill: parent function addBlock(block, initial) {
property var asmModel: ListModel { var txs = JSON.parse(block.transactions);
id: asmModel var amount = 0
if(initial == undefined){
initial = false
} }
TableView {
id: asmTableView if(txs != null){
width: 200 amount = txs.length
TableViewColumn{ role: "value" ; title: "" ; width: 100 }
model: asmModel
} }
Rectangle { if(initial){
anchors.left: asmTableView.right blockModel.append({number: block.number, gasLimit: block.gasLimit, gasUsed: block.gasUsed, coinbase: block.coinbase, hash: block.hash, txs: txs, txAmount: amount, time: block.time, prettyTime: convertToPretty(block.time)})
anchors.right: parent.right }else{
SplitView { blockModel.insert(0, {number: block.number, gasLimit: block.gasLimit, gasUsed: block.gasUsed, coinbase: block.coinbase, hash: block.hash, txs: txs, txAmount: amount, time: block.time, prettyTime: convertToPretty(block.time)})
orientation: Qt.Vertical }
anchors.fill: parent }
TableView { function addLog(str) {
property var memModel: ListModel { if(str.len != 0) {
id: memModel logModel.insert(0, {description: str})
} }
height: parent.height/2
width: parent.width
TableViewColumn{ id:mnumColmn ; role: "num" ; title: "#" ; width: 50}
TableViewColumn{ role: "value" ; title: "Memory" ; width: 750}
model: memModel
} }
SplitView { function setPeers(text) {
orientation: Qt.Horizontal peerLabel.text = text
TableView {
property var debuggerLog: ListModel {
id: debuggerLog
} }
TableViewColumn{ role: "value"; title: "Debug messages" }
model: debuggerLog function addPeer(peer) {
// We could just append the whole peer object but it cries if you try to alter them
peerModel.append({ip: peer.ip, port: peer.port, lastResponse:timeAgo(peer.lastSend), latency: peer.latency, version: peer.version})
} }
TableView {
property var stackModel: ListModel { function resetPeers(){
id: stackModel peerModel.clear()
} }
height: parent.height/2
width: parent.width function timeAgo(unixTs){
TableViewColumn{ role: "value" ; title: "Stack" ; width: parent.width } var lapsed = (Date.now() - new Date(unixTs*1000)) / 1000
model: stackModel return (lapsed + " seconds ago")
} }
function convertToPretty(unixTs){
var a = new Date(unixTs*1000);
var months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
var year = a.getFullYear();
var month = months[a.getMonth()];
var date = a.getDate();
var hour = a.getHours();
var min = a.getMinutes();
var sec = a.getSeconds();
var time = date+' '+month+' '+year+' '+hour+':'+min+':'+sec ;
return time;
} }
// ******************************************
// Windows
// ******************************************
Window {
id: peerWindow
height: 200
width: 700
Rectangle {
anchors.fill: parent
property var peerModel: ListModel {
id: peerModel
} }
TableView {
anchors.fill: parent
id: peerTable
model: peerModel
TableViewColumn{width: 100; role: "ip" ; title: "IP" }
TableViewColumn{width: 60; role: "port" ; title: "Port" }
TableViewColumn{width: 140; role: "lastResponse"; title: "Last event" }
TableViewColumn{width: 100; role: "latency"; title: "Latency" }
TableViewColumn{width: 260; role: "version" ; title: "Version" }
} }
} }
} }
function setAsm(asm) { // *******************************************
asmModel.append({asm: asm}) // Components
} // *******************************************
function setInstruction(num) { // New Contract component
asmTableView.selection.clear() Component {
asmTableView.selection.select(num-1) id: newContract
Column {
id: mainContractColumn
anchors.fill: parent
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"
}
}
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: 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; text: ""}
PropertyChanges { target: txGasPrice; visible:true; text: ""}
PropertyChanges { target: codeView; visible:true; text: ""}
PropertyChanges { target: txButton; visible:true}
PropertyChanges { target: txDataLabel; 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
TextField {
id: txFuelRecipient
placeholderText: "Address / Name or empty for contract"
//validator: RegExpValidator { regExp: /[a-f0-9]{40}/ }
width: 400
} }
function clearAsm() { TextField {
asmModel.clear() id: txValue
width: 222
placeholderText: "Amount"
validator: RegExpValidator { regExp: /\d*/ }
onTextChanged: {
contractFormReady()
}
} }
function setMem(mem) { RowLayout {
memModel.append({num: mem.num, value: mem.value}) TextField {
id: txGas
width: 50
validator: RegExpValidator { regExp: /\d*/ }
placeholderText: "Gas"
text: "500"
/*
onTextChanged: {
contractFormReady()
} }
function clearMem(){ */
memModel.clear() }
Label {
id: atLabel
text: "@"
} }
function setStack(stack) { TextField {
stackModel.append({value: stack}) id: txGasPrice
width: 200
placeholderText: "Gas price"
text: "1000000"
validator: RegExpValidator { regExp: /\d*/ }
/*
onTextChanged: {
contractFormReady()
}
*/
} }
function addDebugMessage(message){
console.log("WOOP:")
debuggerLog.append({value: message})
} }
function clearStack() { Label {
stackModel.clear() id: txDataLabel
text: "Data"
} }
function loadPlugin(name) { TextArea {
console.log("Loading plugin" + name) id: codeView
mainView.addPlugin(name) height: 300
anchors.topMargin: 5
width: 400
onTextChanged: {
contractFormReady()
}
} }
function setWalletValue(value) {
walletValueLabel.text = value 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: {
//this.enabled = false
var res = eth.create(txFuelRecipient.text, txValue.text, txGas.text, txGasPrice.text, codeView.text)
if(res[1]) {
txResult.text = "Your contract <b>could not</b> be send 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"
}
}
} }
}
// New Transaction component
Component {
id: newTransaction
Column {
id: simpleSendColumn
states: [
State{
name: "ERROR"
},
State {
name: "DONE"
PropertyChanges { target: txSimpleValue; visible:false}
PropertyChanges { target: txSimpleRecipient; visible:false}
PropertyChanges { target:newSimpleTxButton; visible:false}
PropertyChanges { target: txSimpleResult; visible:true}
PropertyChanges { target: txSimpleOutput; visible:true}
PropertyChanges { target:newSimpleTxButton; visible:true}
},
State {
name: "SETUP"
PropertyChanges { target: txSimpleValue; visible:true; text: ""}
PropertyChanges { target: txSimpleRecipient; visible:true; text: ""}
PropertyChanges { target: txSimpleButton; visible:true}
PropertyChanges { target:newSimpleTxButton; visible:false}
}
]
spacing: 5
anchors.leftMargin: 5
anchors.topMargin: 5
anchors.top: parent.top
anchors.left: parent.left
function addTx(tx) { function checkFormState(){
var isContract if(txSimpleRecipient.text.length == 40 && txSimpleValue.text.length > 0) {
if (tx.contract == true){ txSimpleButton.state = "READY"
isContract = "Yes"
}else{ }else{
isContract = "No" txSimpleButton.state = "NOTREADY"
} }
txModel.insert(0, {hash: tx.hash, address: tx.address, value: tx.value, contract: isContract})
} }
function addBlock(block) { TextField {
blockModel.insert(0, {number: block.number, hash: block.hash}) id: txSimpleRecipient
placeholderText: "Recipient address"
Layout.fillWidth: true
//validator: RegExpValidator { regExp: /[a-f0-9]{40}/ }
width: 530
onTextChanged: { checkFormState() }
}
TextField {
id: txSimpleValue
width: 200
placeholderText: "Amount"
anchors.rightMargin: 5
validator: RegExpValidator { regExp: /\d*/ }
onTextChanged: { checkFormState() }
}
Button {
id: txSimpleButton
/*enabled: false*/
states: [
State {
name: "READY"
PropertyChanges { target: txSimpleButton; /*enabled: true*/}
},
State {
name: "NOTREADY"
PropertyChanges { target: txSimpleButton; /*enabled: false*/}
}
]
text: "Send"
onClicked: {
//this.enabled = false
var res = eth.transact(txSimpleRecipient.text, txSimpleValue.text, "500", "1000000", "")
if(res[1]) {
txSimpleResult.text = "There has been an error broadcasting your transaction:" + res[1].error()
} else {
txSimpleResult.text = "Your transaction has been broadcasted over the network.\nYour transaction id is:"
txSimpleOutput.text = res[0].hash
this.visible = false
simpleSendColumn.state = "DONE"
} }
function addLog(str) {
if(str.len != 0) {
logModel.append({description: str})
} }
} }
Text {
id: txSimpleResult
visible: false
function setPeers(text) { }
peerLabel.text = text TextField {
id: txSimpleOutput
visible: false
width: 530
}
Button {
id: newSimpleTxButton
visible: false
text: "Create an other transaction"
onClicked: {
this.visible = false
simpleSendColumn.state = "SETUP"
}
}
}
} }
} }

@ -34,7 +34,6 @@ ApplicationWindow {
top: parent.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
@ -97,6 +96,12 @@ ApplicationWindow {
var storage = stateObject.getStorage(data.args[1]) var storage = stateObject.getStorage(data.args[1])
postData(data._seed, storage) postData(data._seed, storage)
break
case "getStateKeyVals":
require(1);
var stateObject = eth.getStateObject(data.args[0]).stateKeyVal(true)
postData(data._seed,stateObject)
break break
case "getBalance": case "getBalance":
require(1); require(1);
@ -165,6 +170,30 @@ ApplicationWindow {
postEvent(ev, [storageObject.address, storageObject.value]) postEvent(ev, [storageObject.address, storageObject.value])
} }
} }
Rectangle {
id: toggleInspector
color: "#bcbcbc"
visible: true
height: 12
width: 12
anchors {
right: root.right
}
MouseArea {
onClicked: {
if(inspector.visible == true){
inspector.visible = false
}else{
inspector.visible = true
}
}
onDoubleClicked: {
console.log('refreshing')
webView.reload()
}
anchors.fill: parent
}
}
Rectangle { Rectangle {
id: sizeGrip id: sizeGrip

@ -9,7 +9,7 @@
<script type="text/javascript"> <script type="text/javascript">
var jefcoinAddr = "fc0a9436890478bb9b1c6ed7455c2535366f4a99" var jefcoinAddr = "de0bd4ea1947deabf1749d7ed633f289358c9f6c"
var mAddr = "" var mAddr = ""
function createTransaction() { function createTransaction() {

@ -5,8 +5,8 @@ import (
) )
var Identifier string var Identifier string
var StartConsole bool
var StartMining bool //var StartMining bool
var StartRpc bool var StartRpc bool
var RpcPort int var RpcPort int
var UseUPnP bool var UseUPnP bool
@ -18,25 +18,26 @@ var GenAddr bool
var UseSeed bool var UseSeed bool
var ImportKey string var ImportKey string
var ExportKey bool var ExportKey bool
var DataDir string
var AssetPath string var AssetPath string
var Datadir string
func Init() { func Init() {
flag.StringVar(&Identifier, "i", "", "Custom client identifier") flag.StringVar(&Identifier, "id", "", "Custom client identifier")
flag.BoolVar(&StartConsole, "c", false, "debug and testing console") flag.StringVar(&OutboundPort, "port", "30303", "listening port")
flag.BoolVar(&StartMining, "m", false, "start dagger mining")
flag.BoolVar(&StartRpc, "r", false, "start rpc server")
flag.BoolVar(&ShowGenesis, "g", false, "prints genesis header and exits")
flag.BoolVar(&UseUPnP, "upnp", false, "enable UPnP support") flag.BoolVar(&UseUPnP, "upnp", false, "enable UPnP support")
flag.IntVar(&MaxPeer, "maxpeer", 10, "maximum desired peers")
flag.IntVar(&RpcPort, "rpcport", 8080, "port to start json-rpc server on")
flag.BoolVar(&StartRpc, "rpc", false, "start rpc server")
flag.StringVar(&AssetPath, "asset_path", "", "absolute path to GUI assets directory")
flag.BoolVar(&ShowGenesis, "genesis", false, "prints genesis header and exits")
flag.BoolVar(&UseSeed, "seed", true, "seed peers") flag.BoolVar(&UseSeed, "seed", true, "seed peers")
flag.BoolVar(&GenAddr, "genaddr", false, "create a new priv/pub key") flag.BoolVar(&GenAddr, "genaddr", false, "create a new priv/pub key")
flag.BoolVar(&ExportKey, "export", false, "export private key") flag.BoolVar(&ExportKey, "export", false, "export private key")
flag.IntVar(&RpcPort, "rpcport", 8080, "port to start json-rpc server on")
flag.StringVar(&OutboundPort, "p", "30303", "listening port")
flag.StringVar(&DataDir, "dir", ".ethereal", "ethereum data directory")
flag.StringVar(&ImportKey, "import", "", "imports the given private key (hex)") flag.StringVar(&ImportKey, "import", "", "imports the given private key (hex)")
flag.IntVar(&MaxPeer, "x", 10, "maximum desired peers")
flag.StringVar(&AssetPath, "asset_path", "", "absolute path to GUI assets directory") flag.StringVar(&Datadir, "datadir", ".ethereal", "specifies the datadir to use. Takes precedence over config file.")
flag.Parse() flag.Parse()
} }

@ -8,9 +8,11 @@ import (
"github.com/ethereum/go-ethereum/ethereal/ui" "github.com/ethereum/go-ethereum/ethereal/ui"
"github.com/ethereum/go-ethereum/utils" "github.com/ethereum/go-ethereum/utils"
"github.com/go-qml/qml" "github.com/go-qml/qml"
"github.com/rakyll/globalconf"
"log" "log"
"os" "os"
"os/signal" "os/signal"
"path"
"runtime" "runtime"
) )
@ -39,7 +41,16 @@ func main() {
runtime.GOMAXPROCS(runtime.NumCPU()) runtime.GOMAXPROCS(runtime.NumCPU())
ethchain.InitFees() ethchain.InitFees()
ethutil.ReadConfig(DataDir, ethutil.LogFile|ethutil.LogStd, Identifier)
g, err := globalconf.NewWithOptions(&globalconf.Options{
Filename: path.Join(ethutil.ApplicationFolder(Datadir), "conf.ini"),
})
if err != nil {
fmt.Println(err)
} else {
g.ParseAll()
}
ethutil.ReadConfig(Datadir, ethutil.LogFile|ethutil.LogStd, g, Identifier)
// Instantiated a eth stack // Instantiated a eth stack
ethereum, err := eth.New(eth.CapDefault, UseUPnP) ethereum, err := eth.New(eth.CapDefault, UseUPnP)
@ -108,9 +119,11 @@ save these words so you can restore your account later: %s
os.Exit(0) os.Exit(0)
} }
/*
if StartMining { if StartMining {
utils.DoMining(ethereum) utils.DoMining(ethereum)
} }
*/
if StartRpc { if StartRpc {
utils.DoRpc(ethereum, RpcPort) utils.DoRpc(ethereum, RpcPort)

@ -0,0 +1,225 @@
package ethui
import (
"fmt"
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethutil"
"github.com/go-qml/qml"
"math/big"
"strings"
)
type DebuggerWindow struct {
win *qml.Window
engine *qml.Engine
lib *UiLib
Db *Debugger
}
func NewDebuggerWindow(lib *UiLib) *DebuggerWindow {
engine := qml.NewEngine()
component, err := engine.LoadFile(lib.AssetPath("debugger/debugger.qml"))
if err != nil {
fmt.Println(err)
return nil
}
win := component.CreateWindow(nil)
db := &Debugger{win, make(chan bool), make(chan bool), true, false}
return &DebuggerWindow{engine: engine, win: win, lib: lib, Db: db}
}
func (self *DebuggerWindow) Show() {
context := self.engine.Context()
context.SetVar("dbg", self)
go func() {
self.win.Show()
self.win.Wait()
}()
}
func (self *DebuggerWindow) SetCode(code string) {
self.win.Set("codeText", code)
}
func (self *DebuggerWindow) SetData(data string) {
self.win.Set("dataText", data)
}
func (self *DebuggerWindow) SetAsm(data string) {
dis := ethchain.Disassemble(ethutil.FromHex(data))
for _, str := range dis {
self.win.Root().Call("setAsm", str)
}
}
func (self *DebuggerWindow) Debug(valueStr, gasStr, gasPriceStr, scriptStr, dataStr string) {
if !self.Db.done {
self.Db.Q <- true
}
defer func() {
if r := recover(); r != nil {
self.Logf("compile FAULT: %v", r)
}
}()
data := ethutil.StringToByteFunc(dataStr, func(s string) (ret []byte) {
slice := strings.Split(dataStr, "\n")
for _, dataItem := range slice {
d := ethutil.FormatData(dataItem)
ret = append(ret, d...)
}
return
})
var err error
script := ethutil.StringToByteFunc(scriptStr, func(s string) (ret []byte) {
ret, err = ethutil.Compile(s)
fmt.Printf("%x\n", ret)
return
})
if err != nil {
self.Logln(err)
return
}
dis := ethchain.Disassemble(script)
self.win.Root().Call("clearAsm")
self.win.Root().Call("clearLog")
for _, str := range dis {
self.win.Root().Call("setAsm", str)
}
gas := ethutil.Big(gasStr)
gasPrice := ethutil.Big(gasPriceStr)
// Contract addr as test address
keyPair := ethutil.GetKeyRing().Get(0)
callerTx := ethchain.NewContractCreationTx(ethutil.Big(valueStr), gas, gasPrice, script)
callerTx.Sign(keyPair.PrivateKey)
state := self.lib.eth.BlockChain().CurrentBlock.State()
account := self.lib.eth.StateManager().TransState().GetAccount(keyPair.Address())
contract := ethchain.MakeContract(callerTx, state)
callerClosure := ethchain.NewClosure(account, contract, script, state, gas, gasPrice)
block := self.lib.eth.BlockChain().CurrentBlock
vm := ethchain.NewVm(state, self.lib.eth.StateManager(), ethchain.RuntimeVars{
Origin: account.Address(),
BlockNumber: block.BlockInfo().Number,
PrevHash: block.PrevHash,
Coinbase: block.Coinbase,
Time: block.Time,
Diff: block.Difficulty,
Value: ethutil.Big(valueStr),
})
self.Db.done = false
self.Logf("callsize %d", len(script))
go func() {
ret, g, err := callerClosure.Call(vm, data, self.Db.halting)
tot := new(big.Int).Mul(g, gasPrice)
self.Logf("gas usage %v total price = %v (%v)", g, tot, ethutil.CurrencyToString(tot))
if err != nil {
self.Logln("exited with errors:", err)
} else {
if len(ret) > 0 {
self.Logf("exited: % x", ret)
} else {
self.Logf("exited: nil")
}
}
state.Reset()
if !self.Db.interrupt {
self.Db.done = true
} else {
self.Db.interrupt = false
}
}()
}
func (self *DebuggerWindow) Logf(format string, v ...interface{}) {
self.win.Root().Call("setLog", fmt.Sprintf(format, v...))
}
func (self *DebuggerWindow) Logln(v ...interface{}) {
str := fmt.Sprintln(v...)
self.Logf("%s", str[:len(str)-1])
}
func (self *DebuggerWindow) Next() {
self.Db.Next()
}
type Debugger struct {
win *qml.Window
N chan bool
Q chan bool
done, interrupt bool
}
type storeVal struct {
Key, Value string
}
func (d *Debugger) halting(pc int, op ethchain.OpCode, mem *ethchain.Memory, stack *ethchain.Stack, stateObject *ethchain.StateObject) bool {
d.win.Root().Call("setInstruction", pc)
d.win.Root().Call("clearMem")
d.win.Root().Call("clearStack")
d.win.Root().Call("clearStorage")
addr := 0
for i := 0; i+32 <= mem.Len(); i += 32 {
d.win.Root().Call("setMem", memAddr{fmt.Sprintf("%03d", addr), fmt.Sprintf("% x", mem.Data()[i:i+32])})
addr++
}
for _, val := range stack.Data() {
d.win.Root().Call("setStack", val.String())
}
stateObject.State().EachStorage(func(key string, node *ethutil.Value) {
d.win.Root().Call("setStorage", storeVal{fmt.Sprintf("% x", key), fmt.Sprintf("% x", node.Str())})
})
out:
for {
select {
case <-d.N:
break out
case <-d.Q:
d.interrupt = true
d.clearBuffers()
return false
}
}
return true
}
func (d *Debugger) clearBuffers() {
out:
// drain
for {
select {
case <-d.N:
case <-d.Q:
default:
break out
}
}
}
func (d *Debugger) Next() {
if !d.done {
d.N <- true
}
}

@ -8,9 +8,11 @@ import (
"github.com/ethereum/eth-go/ethdb" "github.com/ethereum/eth-go/ethdb"
"github.com/ethereum/eth-go/ethpub" "github.com/ethereum/eth-go/ethpub"
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/go-ethereum/utils"
"github.com/go-qml/qml" "github.com/go-qml/qml"
"math/big" "math/big"
"strings" "strings"
"time"
) )
type Gui struct { type Gui struct {
@ -54,7 +56,7 @@ func New(ethereum *eth.Ethereum) *Gui {
} }
func (gui *Gui) Start(assetPath string) { func (gui *Gui) Start(assetPath string) {
const version = "0.5.0 RC8" const version = "0.5.0 RC12"
defer gui.txDb.Close() defer gui.txDb.Close()
@ -63,10 +65,12 @@ func (gui *Gui) Start(assetPath string) {
Init: func(p *ethpub.PBlock, obj qml.Object) { p.Number = 0; p.Hash = "" }, Init: func(p *ethpub.PBlock, obj qml.Object) { p.Number = 0; p.Hash = "" },
}, { }, {
Init: func(p *ethpub.PTx, obj qml.Object) { p.Value = ""; p.Hash = ""; p.Address = "" }, Init: func(p *ethpub.PTx, obj qml.Object) { p.Value = ""; p.Hash = ""; p.Address = "" },
}, {
Init: func(p *ethpub.KeyVal, obj qml.Object) { p.Key = ""; p.Value = "" },
}}) }})
ethutil.Config.SetClientString(fmt.Sprintf("/Ethereal v%s", version)) ethutil.Config.SetClientString(fmt.Sprintf("/Ethereal v%s", version))
ethutil.Config.Log.Infoln("[GUI] Starting GUI")
// 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()
@ -86,19 +90,36 @@ func (gui *Gui) Start(assetPath string) {
win, err = gui.showKeyImport(context) win, err = gui.showKeyImport(context)
} else { } else {
win, err = gui.showWallet(context) win, err = gui.showWallet(context)
ethutil.Config.Log.AddLogSystem(gui)
} }
if err != nil { if err != nil {
ethutil.Config.Log.Infoln("FATAL: asset not found: you can set an alternative asset path on on the command line using option 'asset_path'") ethutil.Config.Log.Infoln("FATAL: asset not found: you can set an alternative asset path on on the command line using option 'asset_path'", err)
panic(err) panic(err)
} }
ethutil.Config.Log.Infoln("[GUI] Starting GUI")
win.Show() win.Show()
win.Wait() win.Wait()
gui.eth.Stop() gui.eth.Stop()
} }
func (gui *Gui) ToggleMining() {
var txt string
if gui.eth.Mining {
utils.StopMining(gui.eth)
txt = "Start mining"
} else {
utils.StartMining(gui.eth)
txt = "Stop mining"
}
gui.win.Root().Set("miningButtonText", txt)
}
func (gui *Gui) showWallet(context *qml.Context) (*qml.Window, error) { func (gui *Gui) showWallet(context *qml.Context) (*qml.Window, error) {
component, err := gui.engine.LoadFile(gui.uiLib.AssetPath("qml/wallet.qml")) component, err := gui.engine.LoadFile(gui.uiLib.AssetPath("qml/wallet.qml"))
if err != nil { if err != nil {
@ -107,8 +128,11 @@ func (gui *Gui) showWallet(context *qml.Context) (*qml.Window, error) {
win := gui.createWindow(component) win := gui.createWindow(component)
go gui.setInitialBlockChain() gui.setInitialBlockChain()
go gui.readPreviousTransactions() gui.loadAddressBook()
gui.readPreviousTransactions()
gui.setPeerInfo()
go gui.update() go gui.update()
return win, nil return win, nil
@ -130,20 +154,46 @@ func (gui *Gui) createWindow(comp qml.Object) *qml.Window {
gui.win = win gui.win = win
gui.uiLib.win = win gui.uiLib.win = win
db := &Debugger{gui.win, make(chan bool)} db := &Debugger{gui.win, make(chan bool), make(chan bool), true, false}
gui.lib.Db = db gui.lib.Db = db
gui.uiLib.Db = db gui.uiLib.Db = db
return gui.win return gui.win
} }
func (gui *Gui) setInitialBlockChain() { func (gui *Gui) setInitialBlockChain() {
// Load previous 10 blocks sBlk := gui.eth.BlockChain().LastBlockHash
chain := gui.eth.BlockChain().GetChain(gui.eth.BlockChain().CurrentBlock.Hash(), 10) blk := gui.eth.BlockChain().GetBlock(sBlk)
for _, block := range chain { for ; blk != nil; blk = gui.eth.BlockChain().GetBlock(sBlk) {
gui.processBlock(block) sBlk = blk.PrevHash
// Loop through all transactions to see if we missed any while being offline
for _, tx := range blk.Transactions() {
if bytes.Compare(tx.Sender(), gui.addr) == 0 || bytes.Compare(tx.Recipient, gui.addr) == 0 {
if ok, _ := gui.txDb.Get(tx.Hash()); ok == nil {
gui.txDb.Put(tx.Hash(), tx.RlpEncode())
}
}
} }
gui.processBlock(blk, true)
}
}
type address struct {
Name, Address string
}
var namereg = ethutil.FromHex("bb5f186604d057c1c5240ca2ae0f6430138ac010")
func (gui *Gui) loadAddressBook() {
gui.win.Root().Call("clearAddress")
stateObject := gui.eth.StateManager().CurrentState().GetStateObject(namereg)
if stateObject != nil {
stateObject.State().EachStorage(func(name string, value *ethutil.Value) {
gui.win.Root().Call("addAddress", struct{ Name, Address string }{name, ethutil.Hex(value.Bytes())})
})
}
} }
func (gui *Gui) readPreviousTransactions() { func (gui *Gui) readPreviousTransactions() {
@ -151,13 +201,21 @@ func (gui *Gui) readPreviousTransactions() {
for it.Next() { for it.Next() {
tx := ethchain.NewTransactionFromBytes(it.Value()) tx := ethchain.NewTransactionFromBytes(it.Value())
gui.win.Root().Call("addTx", ethpub.NewPTx(tx)) var inout string
if bytes.Compare(tx.Sender(), gui.addr) == 0 {
inout = "send"
} else {
inout = "recv"
}
gui.win.Root().Call("addTx", ethpub.NewPTx(tx), inout)
} }
it.Release() it.Release()
} }
func (gui *Gui) processBlock(block *ethchain.Block) { func (gui *Gui) processBlock(block *ethchain.Block, initial bool) {
gui.win.Root().Call("addBlock", ethpub.NewPBlock(block)) gui.win.Root().Call("addBlock", ethpub.NewPBlock(block), initial)
} }
func (gui *Gui) setWalletValue(amount, unconfirmedFunds *big.Int) { func (gui *Gui) setWalletValue(amount, unconfirmedFunds *big.Int) {
@ -182,10 +240,16 @@ func (gui *Gui) update() {
blockChan := make(chan ethutil.React, 1) blockChan := make(chan ethutil.React, 1)
txChan := make(chan ethutil.React, 1) txChan := make(chan ethutil.React, 1)
objectChan := make(chan ethutil.React, 1)
peerChan := make(chan ethutil.React, 1)
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)
reactor.Subscribe("object:"+string(namereg), objectChan)
reactor.Subscribe("peerList", peerChan)
ticker := time.NewTicker(5 * time.Second)
state := gui.eth.StateManager().TransState() state := gui.eth.StateManager().TransState()
@ -196,6 +260,7 @@ func (gui *Gui) update() {
select { select {
case b := <-blockChan: case b := <-blockChan:
block := b.Resource.(*ethchain.Block) block := b.Resource.(*ethchain.Block)
gui.processBlock(block, false)
if bytes.Compare(block.Coinbase, gui.addr) == 0 { if bytes.Compare(block.Coinbase, gui.addr) == 0 {
gui.setWalletValue(gui.eth.StateManager().CurrentState().GetAccount(gui.addr).Amount, nil) gui.setWalletValue(gui.eth.StateManager().CurrentState().GetAccount(gui.addr).Amount, nil)
} }
@ -207,12 +272,12 @@ func (gui *Gui) update() {
object := state.GetAccount(gui.addr) object := state.GetAccount(gui.addr)
if bytes.Compare(tx.Sender(), gui.addr) == 0 { if bytes.Compare(tx.Sender(), gui.addr) == 0 {
gui.win.Root().Call("addTx", ethpub.NewPTx(tx)) gui.win.Root().Call("addTx", ethpub.NewPTx(tx), "send")
gui.txDb.Put(tx.Hash(), tx.RlpEncode()) gui.txDb.Put(tx.Hash(), tx.RlpEncode())
unconfirmedFunds.Sub(unconfirmedFunds, tx.Value) unconfirmedFunds.Sub(unconfirmedFunds, tx.Value)
} else if bytes.Compare(tx.Recipient, gui.addr) == 0 { } else if bytes.Compare(tx.Recipient, gui.addr) == 0 {
gui.win.Root().Call("addTx", ethpub.NewPTx(tx)) gui.win.Root().Call("addTx", ethpub.NewPTx(tx), "recv")
gui.txDb.Put(tx.Hash(), tx.RlpEncode()) gui.txDb.Put(tx.Hash(), tx.RlpEncode())
unconfirmedFunds.Add(unconfirmedFunds, tx.Value) unconfirmedFunds.Add(unconfirmedFunds, tx.Value)
@ -231,10 +296,25 @@ func (gui *Gui) update() {
state.UpdateStateObject(object) state.UpdateStateObject(object)
} }
case <-objectChan:
gui.loadAddressBook()
case <-peerChan:
gui.setPeerInfo()
case <-ticker.C:
gui.setPeerInfo()
} }
} }
} }
func (gui *Gui) setPeerInfo() {
gui.win.Root().Call("setPeers", fmt.Sprintf("%d / %d", gui.eth.PeerCount(), gui.eth.MaxPeers))
gui.win.Root().Call("resetPeers")
for _, peer := range gui.pub.GetPeers() {
gui.win.Root().Call("addPeer", peer)
}
}
// Logging functions that log directly to the GUI interface // Logging functions that log directly to the GUI interface
func (gui *Gui) Println(v ...interface{}) { func (gui *Gui) Println(v ...interface{}) {
str := strings.TrimRight(fmt.Sprintln(v...), "\n") str := strings.TrimRight(fmt.Sprintln(v...), "\n")
@ -251,6 +331,11 @@ func (gui *Gui) Printf(format string, v ...interface{}) {
gui.win.Root().Call("addLog", line) gui.win.Root().Call("addLog", line)
} }
} }
func (gui *Gui) RegisterName(name string) {
keyPair := ethutil.GetKeyRing().Get(0)
name = fmt.Sprintf("\"%s\"\n1", name)
gui.pub.Transact(ethutil.Hex(keyPair.PrivateKey), "namereg", "1000", "1000000", "150", name)
}
func (gui *Gui) Transact(recipient, value, gas, gasPrice, data string) (*ethpub.PReceipt, error) { func (gui *Gui) Transact(recipient, value, gas, gasPrice, data string) (*ethpub.PReceipt, error) {
keyPair := ethutil.GetKeyRing().Get(0) keyPair := ethutil.GetKeyRing().Get(0)
@ -261,7 +346,13 @@ func (gui *Gui) Transact(recipient, value, gas, gasPrice, data string) (*ethpub.
func (gui *Gui) Create(recipient, value, gas, gasPrice, data string) (*ethpub.PReceipt, error) { func (gui *Gui) Create(recipient, value, gas, gasPrice, data string) (*ethpub.PReceipt, error) {
keyPair := ethutil.GetKeyRing().Get(0) keyPair := ethutil.GetKeyRing().Get(0)
//mainInput, initInput := mutan.PreParse(data) return gui.pub.Transact(ethutil.Hex(keyPair.PrivateKey), recipient, value, gas, gasPrice, data)
}
func (gui *Gui) ChangeClientId(id string) {
ethutil.Config.SetIdentifier(id)
}
return gui.pub.Create(ethutil.Hex(keyPair.PrivateKey), value, gas, gasPrice, data) func (gui *Gui) ClientId() string {
return ethutil.Config.Identifier
} }

@ -2,13 +2,10 @@ package ethui
import ( import (
"bitbucket.org/kardianos/osext" "bitbucket.org/kardianos/osext"
"fmt"
"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/ethutil" "github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/go-ethereum/utils"
"github.com/go-qml/qml" "github.com/go-qml/qml"
"github.com/obscuren/mutan"
"os" "os"
"path" "path"
"path/filepath" "path/filepath"
@ -29,6 +26,7 @@ type UiLib struct {
// The main application window // The main application window
win *qml.Window win *qml.Window
Db *Debugger Db *Debugger
DbWindow *DebuggerWindow
} }
func NewUiLib(engine *qml.Engine, eth *eth.Ethereum, assetPath string) *UiLib { func NewUiLib(engine *qml.Engine, eth *eth.Ethereum, assetPath string) *UiLib {
@ -91,6 +89,29 @@ func (ui *UiLib) ConnectToPeer(addr string) {
func (ui *UiLib) AssetPath(p string) string { func (ui *UiLib) AssetPath(p string) string {
return path.Join(ui.assetPath, p) return path.Join(ui.assetPath, p)
} }
func (self *UiLib) StartDbWithContractAndData(contractHash, data string) {
dbWindow := NewDebuggerWindow(self)
object := self.eth.StateManager().CurrentState().GetStateObject(ethutil.FromHex(contractHash))
if len(object.Script()) > 0 {
dbWindow.SetCode("0x" + ethutil.Hex(object.Script()))
}
dbWindow.SetData("0x" + data)
dbWindow.Show()
}
func (self *UiLib) StartDbWithCode(code string) {
dbWindow := NewDebuggerWindow(self)
dbWindow.SetCode("0x" + code)
dbWindow.Show()
}
func (self *UiLib) StartDebugger() {
dbWindow := NewDebuggerWindow(self)
//self.DbWindow = dbWindow
dbWindow.Show()
}
func DefaultAssetPath() string { func DefaultAssetPath() string {
var base string var base string
@ -121,27 +142,28 @@ func DefaultAssetPath() string {
func (ui *UiLib) DebugTx(recipient, valueStr, gasStr, gasPriceStr, data string) { func (ui *UiLib) DebugTx(recipient, valueStr, gasStr, gasPriceStr, data string) {
state := ui.eth.BlockChain().CurrentBlock.State() state := ui.eth.BlockChain().CurrentBlock.State()
mainInput, _ := mutan.PreParse(data) script, err := ethutil.Compile(data)
callerScript, err := utils.Compile(mainInput)
if err != nil { if err != nil {
ethutil.Config.Log.Debugln(err) ethutil.Config.Log.Debugln(err)
return return
} }
dis := ethchain.Disassemble(callerScript) dis := ethchain.Disassemble(script)
ui.win.Root().Call("clearAsm") ui.win.Root().Call("clearAsm")
for _, str := range dis { for _, str := range dis {
ui.win.Root().Call("setAsm", str) ui.win.Root().Call("setAsm", str)
} }
callerTx := ethchain.NewContractCreationTx(ethutil.Big(valueStr), ethutil.Big(gasStr), ethutil.Big(gasPriceStr), nil)
// Contract addr as test address // Contract addr as test address
keyPair := ethutil.GetKeyRing().Get(0) keyPair := ethutil.GetKeyRing().Get(0)
callerTx :=
ethchain.NewContractCreationTx(ethutil.Big(valueStr), ethutil.Big(gasStr), ethutil.Big(gasPriceStr), script)
callerTx.Sign(keyPair.PrivateKey)
account := ui.eth.StateManager().TransState().GetStateObject(keyPair.Address()) account := ui.eth.StateManager().TransState().GetStateObject(keyPair.Address())
c := ethchain.MakeContract(callerTx, state) contract := ethchain.MakeContract(callerTx, state)
callerClosure := ethchain.NewClosure(account, c, c.Script(), state, ethutil.Big(gasStr), ethutil.Big(gasPriceStr)) callerClosure := ethchain.NewClosure(account, contract, contract.Init(), state, ethutil.Big(gasStr), ethutil.Big(gasPriceStr))
block := ui.eth.BlockChain().CurrentBlock block := ui.eth.BlockChain().CurrentBlock
vm := ethchain.NewVm(state, ui.eth.StateManager(), ethchain.RuntimeVars{ vm := ethchain.NewVm(state, ui.eth.StateManager(), ethchain.RuntimeVars{
@ -151,50 +173,18 @@ func (ui *UiLib) DebugTx(recipient, valueStr, gasStr, gasPriceStr, data string)
Coinbase: block.Coinbase, Coinbase: block.Coinbase,
Time: block.Time, Time: block.Time,
Diff: block.Difficulty, Diff: block.Difficulty,
TxData: nil,
}) })
ui.Db.done = false
go func() { go func() {
callerClosure.Call(vm, nil, ui.Db.halting) callerClosure.Call(vm, contract.Init(), ui.Db.halting)
state.Reset() state.Reset()
ui.Db.done = true
}() }()
} }
func (ui *UiLib) Next() { func (ui *UiLib) Next() {
ui.Db.Next() ui.Db.Next()
} }
type Debugger struct {
win *qml.Window
N chan bool
}
func (d *Debugger) halting(pc int, op ethchain.OpCode, mem *ethchain.Memory, stack *ethchain.Stack) {
d.win.Root().Call("setInstruction", pc)
d.win.Root().Call("clearMem")
d.win.Root().Call("clearStack")
addr := 0
for i := 0; i+32 <= mem.Len(); i += 32 {
d.win.Root().Call("setMem", memAddr{fmt.Sprintf("%03d", addr), fmt.Sprintf("% x", mem.Data()[i:i+32])})
addr++
}
for _, val := range stack.Data() {
d.win.Root().Call("setStack", val.String())
}
out:
for {
select {
case <-d.N:
break out
default:
}
}
}
func (d *Debugger) Next() {
d.N <- true
}

@ -20,33 +20,35 @@ var UseSeed bool
var ImportKey string var ImportKey string
var ExportKey bool var ExportKey bool
var LogFile string var LogFile string
var DataDir string
var NonInteractive bool var NonInteractive bool
var StartJsConsole bool var StartJsConsole bool
var InputFile string var InputFile string
var Datadir string
func Init() { func Init() {
flag.Usage = func() { flag.Usage = func() {
fmt.Fprintf(os.Stderr, "%s [options] [filename]:\n", os.Args[0]) fmt.Fprintf(os.Stderr, "%s [options] [filename]:\n", os.Args[0])
flag.PrintDefaults() flag.PrintDefaults()
} }
flag.StringVar(&Identifier, "i", "", "custom client identifier") flag.StringVar(&Identifier, "id", "", "Custom client identifier")
flag.BoolVar(&StartMining, "m", false, "start dagger mining") flag.StringVar(&OutboundPort, "port", "30303", "listening port")
flag.BoolVar(&ShowGenesis, "g", false, "prints genesis header and exits") flag.BoolVar(&UseUPnP, "upnp", false, "enable UPnP support")
flag.BoolVar(&StartRpc, "r", false, "start rpc server") flag.IntVar(&MaxPeer, "maxpeer", 10, "maximum desired peers")
flag.IntVar(&RpcPort, "rpcport", 8080, "port to start json-rpc server on") flag.IntVar(&RpcPort, "rpcport", 8080, "port to start json-rpc server on")
flag.BoolVar(&StartRpc, "rpc", false, "start rpc server")
flag.BoolVar(&StartJsConsole, "js", false, "exp")
flag.BoolVar(&StartMining, "mine", false, "start dagger mining")
flag.BoolVar(&NonInteractive, "y", false, "non-interactive mode (say yes to confirmations)") flag.BoolVar(&NonInteractive, "y", false, "non-interactive mode (say yes to confirmations)")
flag.BoolVar(&UseUPnP, "upnp", false, "enable UPnP support")
flag.BoolVar(&UseSeed, "seed", true, "seed peers") flag.BoolVar(&UseSeed, "seed", true, "seed peers")
flag.BoolVar(&GenAddr, "genaddr", false, "create a new priv/pub key") flag.BoolVar(&GenAddr, "genaddr", false, "create a new priv/pub key")
flag.BoolVar(&ExportKey, "export", false, "export private key") flag.BoolVar(&ExportKey, "export", false, "export private key")
flag.StringVar(&OutboundPort, "p", "30303", "listening port")
flag.StringVar(&LogFile, "logfile", "", "log file (defaults to standard output)") flag.StringVar(&LogFile, "logfile", "", "log file (defaults to standard output)")
flag.StringVar(&DataDir, "dir", ".ethereum", "ethereum data directory")
flag.StringVar(&ImportKey, "import", "", "imports the given private key (hex)") flag.StringVar(&ImportKey, "import", "", "imports the given private key (hex)")
flag.IntVar(&MaxPeer, "x", 10, "maximum desired peers")
flag.BoolVar(&StartJsConsole, "js", false, "exp") flag.StringVar(&Datadir, "datadir", ".ethereum", "specifies the datadir to use. Takes precedence over config file.")
flag.Parse() flag.Parse()

@ -6,10 +6,12 @@ import (
"github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/go-ethereum/utils" "github.com/ethereum/go-ethereum/utils"
"github.com/rakyll/globalconf"
"io/ioutil" "io/ioutil"
"log" "log"
"os" "os"
"os/signal" "os/signal"
"path"
"runtime" "runtime"
"strings" "strings"
) )
@ -59,7 +61,15 @@ func main() {
lt = ethutil.LogFile | ethutil.LogStd lt = ethutil.LogFile | ethutil.LogStd
} }
ethutil.ReadConfig(DataDir, lt, Identifier) g, err := globalconf.NewWithOptions(&globalconf.Options{
Filename: path.Join(ethutil.ApplicationFolder(Datadir), "conf.ini"),
})
if err != nil {
fmt.Println(err)
} else {
g.ParseAll()
}
ethutil.ReadConfig(Datadir, lt, g, Identifier)
logger := ethutil.Config.Log logger := ethutil.Config.Log

@ -10,6 +10,7 @@ import (
"github.com/obscuren/otto" "github.com/obscuren/otto"
"io/ioutil" "io/ioutil"
"os" "os"
"path"
"path/filepath" "path/filepath"
) )
@ -25,6 +26,20 @@ type JSRE struct {
objectCb map[string][]otto.Value objectCb map[string][]otto.Value
} }
func (jsre *JSRE) LoadExtFile(path string) {
result, err := ioutil.ReadFile(path)
if err == nil {
jsre.vm.Run(result)
} else {
ethutil.Config.Log.Debugln("Could not load file:", path)
}
}
func (jsre *JSRE) LoadIntFile(file string) {
assetPath := path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "ethereal", "assets", "ext")
jsre.LoadExtFile(path.Join(assetPath, file))
}
func NewJSRE(ethereum *eth.Ethereum) *JSRE { func NewJSRE(ethereum *eth.Ethereum) *JSRE {
re := &JSRE{ re := &JSRE{
ethereum, ethereum,
@ -39,6 +54,10 @@ func NewJSRE(ethereum *eth.Ethereum) *JSRE {
// Init the JS lib // Init the JS lib
re.vm.Run(jsLib) re.vm.Run(jsLib)
// Load extra javascript files
re.LoadIntFile("string.js")
re.LoadIntFile("big.js")
// 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()

@ -66,6 +66,10 @@ func (self *JSEthereum) GetBlock(hash string) otto.Value {
return self.toVal(&JSBlock{self.PEthereum.GetBlock(hash), self}) return self.toVal(&JSBlock{self.PEthereum.GetBlock(hash), self})
} }
func (self *JSEthereum) GetPeers() otto.Value {
return self.toVal(self.PEthereum.GetPeers())
}
func (self *JSEthereum) GetKey() otto.Value { func (self *JSEthereum) GetKey() otto.Value {
return self.toVal(self.PEthereum.GetKey()) return self.toVal(self.PEthereum.GetKey())
} }
@ -74,6 +78,10 @@ func (self *JSEthereum) GetStateObject(addr string) otto.Value {
return self.toVal(self.PEthereum.GetStateObject(addr)) return self.toVal(self.PEthereum.GetStateObject(addr))
} }
func (self *JSEthereum) GetStateKeyVals(addr string) otto.Value {
return self.toVal(self.PEthereum.GetStateObject(addr).StateKeyVal(false))
}
func (self *JSEthereum) Transact(key, recipient, valueStr, gasStr, gasPriceStr, dataStr string) otto.Value { func (self *JSEthereum) Transact(key, recipient, valueStr, gasStr, gasPriceStr, dataStr string) otto.Value {
r, err := self.PEthereum.Transact(key, recipient, valueStr, gasStr, gasPriceStr, dataStr) r, err := self.PEthereum.Transact(key, recipient, valueStr, gasStr, gasPriceStr, dataStr)
if err != nil { if err != nil {
@ -101,7 +109,7 @@ func (self *JSEthereum) toVal(v interface{}) otto.Value {
result, err := self.vm.ToValue(v) result, err := self.vm.ToValue(v)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println("Value unknown:", err)
return otto.UndefinedValue() return otto.UndefinedValue()
} }

@ -33,13 +33,18 @@ func DoMining(ethereum *eth.Ethereum) {
addr := keyPair.Address() addr := keyPair.Address()
go func() { go func() {
ethutil.Config.Log.Infoln("Miner started")
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() == false {
time.Sleep(5 * time.Second)
}
ethutil.Config.Log.Infoln("Miner started")
miner := ethminer.NewDefaultMiner(addr, ethereum)
miner.Start() miner.Start()
}() }()
} }

Loading…
Cancel
Save