aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md14
-rw-r--r--ethereal/assets/debugger/debugger.qml264
-rw-r--r--ethereal/assets/ext/ethereum.js4
-rw-r--r--ethereal/assets/heart.pngbin0 -> 4277 bytes
-rw-r--r--ethereal/assets/qml/newTransaction/_new_contract.qml196
-rw-r--r--ethereal/assets/qml/newTransaction/_simple_send.qml112
-rw-r--r--ethereal/assets/qml/wallet.qml806
-rw-r--r--ethereal/assets/qml/webapp.qml31
-rw-r--r--ethereal/assets/samplecoin/samplecoin.html2
-rw-r--r--ethereal/config.go27
-rw-r--r--ethereal/ethereum.go21
-rw-r--r--ethereal/ui/debugger.go225
-rw-r--r--ethereal/ui/gui.go127
-rw-r--r--ethereal/ui/ui_lib.go86
-rw-r--r--ethereum/config.go22
-rw-r--r--ethereum/ethereum.go12
-rw-r--r--ethereum/javascript_runtime.go19
-rw-r--r--ethereum/repl.go10
-rw-r--r--utils/cmd.go9
19 files changed, 1392 insertions, 595 deletions
diff --git a/README.md b/README.md
index e5818ffca..104e4725c 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@ Ethereum
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).
@@ -27,20 +27,22 @@ General command line options
```
Shared between ethereum and ethereal
--m Start mining blocks
--genaddr Generates a new address and private key (destructive action)
--p Port on which the server will accept incomming connections
+-id Set the custom identifier of the client (shows up on other clients)
+-port Port on which the server will accept incomming connections
-upnp Enable UPnP
--x Desired amount of peers
--r Start JSON RPC
+-maxpeer Desired amount of peers
+-rpc Start JSON RPC
+
-dir Data directory used to store configs and databases
-import Import a private key
+-genaddr Generates a new address and private key (destructive action)
-h This
Ethereum only
ethereum [options] [filename]
-js Start the JavaScript REPL
filename Load the given file and interpret as JavaScript
+-m Start mining blocks
Etheral only
-asset_path absolute path to GUI assets directory
diff --git a/ethereal/assets/debugger/debugger.qml b/ethereal/assets/debugger/debugger.qml
new file mode 100644
index 000000000..bc34233fd
--- /dev/null
+++ b/ethereal/assets/debugger/debugger.qml
@@ -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()
+ }
+}
diff --git a/ethereal/assets/ext/ethereum.js b/ethereal/assets/ext/ethereum.js
index d4eaf97fd..c58fe24c2 100644
--- a/ethereal/assets/ext/ethereum.js
+++ b/ethereal/assets/ext/ethereum.js
@@ -32,6 +32,10 @@ window.eth = {
postData({call: "getStorage", args: [address, storageAddress]}, cb);
},
+ getStateKeyVals: function(address, cb){
+ postData({call: "getStateKeyVals", args: [address]}, cb);
+ },
+
getKey: function(cb) {
postData({call: "getKey"}, cb);
},
diff --git a/ethereal/assets/heart.png b/ethereal/assets/heart.png
new file mode 100644
index 000000000..3c874ab7f
--- /dev/null
+++ b/ethereal/assets/heart.png
Binary files differ
diff --git a/ethereal/assets/qml/newTransaction/_new_contract.qml b/ethereal/assets/qml/newTransaction/_new_contract.qml
deleted file mode 100644
index e3c7229eb..000000000
--- a/ethereal/assets/qml/newTransaction/_new_contract.qml
+++ /dev/null
@@ -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
- }
- }
- }
-}
diff --git a/ethereal/assets/qml/newTransaction/_simple_send.qml b/ethereal/assets/qml/newTransaction/_simple_send.qml
deleted file mode 100644
index cd1ef55b6..000000000
--- a/ethereal/assets/qml/newTransaction/_simple_send.qml
+++ /dev/null
@@ -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"
- }
- }
- }
-}
diff --git a/ethereal/assets/qml/wallet.qml b/ethereal/assets/qml/wallet.qml
index 51f064adf..0555cd2f2 100644
--- a/ethereal/assets/qml/wallet.qml
+++ b/ethereal/assets/qml/wallet.qml
@@ -6,9 +6,12 @@ import QtQuick.Window 2.1;
import QtQuick.Controls.Styles 1.1
import Ethereum 1.0
+
ApplicationWindow {
id: root
+ property alias miningButtonText: miningButton.text
+
width: 900
height: 600
minimumHeight: 300
@@ -23,10 +26,13 @@ ApplicationWindow {
shortcut: "Ctrl+o"
onTriggered: openAppDialog.open()
}
+ }
+
+ Menu {
MenuItem {
- text: "Muted"
- shortcut: "Ctrl+e"
- onTriggered: ui.muted("")
+ text: "Debugger"
+ shortcut: "Ctrl+d"
+ onTriggered: ui.startDebugger()
}
}
@@ -39,10 +45,12 @@ ApplicationWindow {
addPeerWin.visible = true
}
}
-
MenuItem {
- text: "Start"
- onTriggered: ui.connect()
+ text: "Show Peers"
+ shortcut: "Ctrl+e"
+ onTriggered: {
+ peerWindow.visible = true
+ }
}
}
@@ -85,7 +93,6 @@ ApplicationWindow {
//color: "#D9DDE7"
color: "#252525"
-
ColumnLayout {
y: 50
anchors.left: parent.left
@@ -123,7 +130,7 @@ ApplicationWindow {
}
Image {
- source: ui.assetPath("net.png")
+ source: ui.assetPath("heart.png")
anchors.horizontalCenter: parent.horizontalCenter
MouseArea {
anchors.fill: parent
@@ -155,6 +162,7 @@ ApplicationWindow {
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 }
@@ -169,6 +177,7 @@ ApplicationWindow {
visible: false
anchors.fill: parent
color: "#00000000"
+ /*
TabView{
anchors.fill: parent
anchors.rightMargin: 5
@@ -177,16 +186,14 @@ ApplicationWindow {
anchors.bottomMargin: 5
id: newTransactionTab
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("Contracts", newContract)
}
}
+ */
+ Component.onCompleted: {
+ newContract.createObject(newTxView)
+ }
}
Rectangle {
@@ -199,34 +206,19 @@ ApplicationWindow {
id: blockTable
width: parent.width
anchors.top: parent.top
- anchors.bottom: logView.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.block = eth.getBlock(blockModel.get(row).hash)
- popup.hashLabel.text = popup.block.hash
- }
- */
- }
-
- property var logModel: ListModel {
- id: logModel
+ onDoubleClicked: {
+ popup.visible = true
+ popup.setDetails(blockModel.get(row))
+ }
}
- TableView {
- id: logView
- width: parent.width
- height: 150
- anchors.bottom: parent.bottom
- TableViewColumn{ role: "description" ; title: "log" }
-
- model: logModel
- }
}
Rectangle {
@@ -236,23 +228,82 @@ ApplicationWindow {
color: "#00000000"
anchors.fill: parent
- Label {
- id: addressLabel
- text: "Address"
- anchors {
- margins: 5
- top: parent.top
- left: parent.left
+ 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: eth.clientId()
+ onTextChanged: {
+ eth.changeClientId(text)
+ }
}
}
- TextField {
- anchors {
- margins: 5
- left: addressLabel.right
- top: parent.top
+
+ 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 = ""
+ }
+ }
}
- text: pub.getKey().address
- width: 500
+ }
+
+
+ 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
}
}
@@ -285,29 +336,34 @@ ApplicationWindow {
title: "Open QML Application"
onAccepted: {
//ui.open(openAppDialog.fileUrl.toString())
- //ui.openHtml(Qt.resolvedUrl(ui.assetPath("test.html")))
- ui.openHtml(openAppDialog.fileUrl.toString())
-
+ //ui.openHtml(Qt.resolvedUrl(ui.assetPath("test.html")))
+ ui.openHtml(openAppDialog.fileUrl.toString())
}
}
statusBar: StatusBar {
+ height: 30
RowLayout {
- anchors.fill: parent
+ Button {
+ id: miningButton
+ onClicked: {
+ eth.toggleMining()
+ }
+ text: "Start Mining"
+ }
+
Button {
property var enabled: true
- id: connectButton
+ id: debuggerWindow
onClicked: {
- if(this.enabled) {
- ui.connect(this)
- }
+ ui.startDebugger()
}
- text: "Connect"
+ text: "Debugger"
}
Button {
id: importAppButton
- anchors.left: connectButton.right
+ anchors.left: debuggerWindow.right
anchors.leftMargin: 5
onClicked: openAppDialog.open()
text: "Import App"
@@ -318,20 +374,26 @@ ApplicationWindow {
anchors.leftMargin: 5
id: walletValueLabel
}
+ }
- Label {
- anchors.right: peerImage.left
- anchors.rightMargin: 5
- id: peerLabel
- font.pixelSize: 8
- text: "0 / 0"
- }
- Image {
- id: peerImage
- anchors.right: parent.right
- width: 10; height: 10
- source: ui.assetPath("network.png")
+ Label {
+ y: 7
+ anchors.right: peerImage.left
+ anchors.rightMargin: 5
+ id: peerLabel
+ font.pixelSize: 8
+ text: "0 / 0"
+ }
+ Image {
+ y: 7
+ id: peerImage
+ anchors.right: parent.right
+ width: 10; height: 10
+ MouseArea {
+ onDoubleClicked: peerWindow.visible = true
+ anchors.fill: parent
}
+ source: ui.assetPath("network.png")
}
}
@@ -339,10 +401,134 @@ ApplicationWindow {
id: popup
visible: false
property var block
- Label {
- id: hashLabel
- anchors.horizontalCenter: parent.horizontalCenter
- anchors.verticalCenter: parent.verticalCenter
+ 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 {
+ 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){
+ 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,115 +590,19 @@ ApplicationWindow {
anchors.left: aboutIcon.right
anchors.leftMargin: 10
font.pointSize: 12
- text: "<h2>Ethereal</h2><br><h3>Development</h3>Jeffrey Wilcke<br>Maran Hidskes<br><h3>Binary Distribution</h3>Jarrad Hope<br>"
- }
-
- }
-
- Window {
- id: debugWindow
- visible: false
- title: "Debugger"
- minimumWidth: 600
- minimumHeight: 600
- width: 800
- height: 600
-
-
- Item {
- id: keyHandler
- focus: true
- Keys.onPressed: {
- if (event.key == Qt.Key_Space) {
- ui.next()
- }
- }
+ text: "<h2>Ethereal</h2><br><h3>Development</h3>Jeffrey Wilcke<br>Maran Hidskes<br>"
}
- SplitView {
-
- anchors.fill: parent
- property var asmModel: ListModel {
- id: asmModel
- }
- TableView {
- id: asmTableView
- width: 200
- TableViewColumn{ role: "value" ; title: "" ; width: 100 }
- model: asmModel
- }
-
- Rectangle {
- anchors.left: asmTableView.right
- anchors.right: parent.right
- SplitView {
- orientation: Qt.Vertical
- anchors.fill: parent
-
- TableView {
- property var memModel: ListModel {
- id: memModel
- }
- 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 {
- orientation: Qt.Horizontal
- TableView {
- property var debuggerLog: ListModel {
- id: debuggerLog
- }
- TableViewColumn{ role: "value"; title: "Debug messages" }
- model: debuggerLog
- }
- TableView {
- property var stackModel: ListModel {
- id: stackModel
- }
- height: parent.height/2
- width: parent.width
- TableViewColumn{ role: "value" ; title: "Stack" ; width: parent.width }
- model: stackModel
- }
- }
- }
- }
- }
- }
-
- function setAsm(asm) {
- asmModel.append({asm: asm})
}
- function setInstruction(num) {
- asmTableView.selection.clear()
- asmTableView.selection.select(num-1)
- }
-
- function clearAsm() {
- asmModel.clear()
- }
-
- 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){
- console.log("WOOP:")
debuggerLog.append({value: message})
}
- function clearStack() {
- stackModel.clear()
+ function addAddress(address) {
+ addressModel.append({name: address.name, address: address.address})
+ }
+ function clearAddress() {
+ addressModel.clear()
}
function loadPlugin(name) {
@@ -524,27 +614,379 @@ ApplicationWindow {
walletValueLabel.text = value
}
- function addTx(tx) {
+ function addTx(tx, inout) {
var isContract
if (tx.contract == true){
isContract = "Yes"
}else{
isContract = "No"
}
- txModel.insert(0, {hash: tx.hash, address: tx.address, value: tx.value, contract: isContract})
+
+ 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})
}
- function addBlock(block) {
- blockModel.insert(0, {number: block.number, hash: block.hash})
+ 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, 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, gasLimit: block.gasLimit, gasUsed: block.gasUsed, coinbase: block.coinbase, hash: block.hash, txs: txs, txAmount: amount, time: block.time, prettyTime: convertToPretty(block.time)})
+ }
}
function addLog(str) {
if(str.len != 0) {
- logModel.append({description: str})
+ logModel.insert(0, {description: str})
}
}
function setPeers(text) {
peerLabel.text = text
}
+
+ 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})
+ }
+
+ function resetPeers(){
+ peerModel.clear()
+ }
+
+ function timeAgo(unixTs){
+ var lapsed = (Date.now() - new Date(unixTs*1000)) / 1000
+ 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" }
+ }
+ }
+ }
+
+ // *******************************************
+ // Components
+ // *******************************************
+
+ // New Contract component
+ Component {
+ 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
+ }
+
+ TextField {
+ id: txValue
+ width: 222
+ placeholderText: "Amount"
+ validator: RegExpValidator { regExp: /\d*/ }
+ onTextChanged: {
+ contractFormReady()
+ }
+ }
+
+ RowLayout {
+ TextField {
+ id: txGas
+ width: 50
+ validator: RegExpValidator { regExp: /\d*/ }
+ placeholderText: "Gas"
+ text: "500"
+ /*
+ onTextChanged: {
+ contractFormReady()
+ }
+ */
+ }
+ Label {
+ id: atLabel
+ text: "@"
+ }
+
+ TextField {
+ id: txGasPrice
+ width: 200
+ placeholderText: "Gas price"
+ text: "1000000"
+ validator: RegExpValidator { regExp: /\d*/ }
+ /*
+ onTextChanged: {
+ contractFormReady()
+ }
+ */
+ }
+ }
+
+ 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: {
+ //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 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, "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"
+ }
+ }
+ }
+ 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"
+ }
+ }
+ }
+ }
}
diff --git a/ethereal/assets/qml/webapp.qml b/ethereal/assets/qml/webapp.qml
index d3cffeeca..4a5a1293a 100644
--- a/ethereal/assets/qml/webapp.qml
+++ b/ethereal/assets/qml/webapp.qml
@@ -34,7 +34,6 @@ ApplicationWindow {
top: parent.top
}
*/
-
onTitleChanged: { window.title = title }
experimental.preferences.javascriptEnabled: true
experimental.preferences.navigatorQtObjectEnabled: true
@@ -98,6 +97,12 @@ ApplicationWindow {
postData(data._seed, storage)
break
+ case "getStateKeyVals":
+ require(1);
+ var stateObject = eth.getStateObject(data.args[0]).stateKeyVal(true)
+ postData(data._seed,stateObject)
+
+ break
case "getBalance":
require(1);
@@ -165,6 +170,30 @@ ApplicationWindow {
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 {
id: sizeGrip
diff --git a/ethereal/assets/samplecoin/samplecoin.html b/ethereal/assets/samplecoin/samplecoin.html
index 3892141cd..dc8d0b7e9 100644
--- a/ethereal/assets/samplecoin/samplecoin.html
+++ b/ethereal/assets/samplecoin/samplecoin.html
@@ -9,7 +9,7 @@
<script type="text/javascript">
-var jefcoinAddr = "fc0a9436890478bb9b1c6ed7455c2535366f4a99"
+var jefcoinAddr = "de0bd4ea1947deabf1749d7ed633f289358c9f6c"
var mAddr = ""
function createTransaction() {
diff --git a/ethereal/config.go b/ethereal/config.go
index 3864126db..2315d1435 100644
--- a/ethereal/config.go
+++ b/ethereal/config.go
@@ -5,8 +5,8 @@ import (
)
var Identifier string
-var StartConsole bool
-var StartMining bool
+
+//var StartMining bool
var StartRpc bool
var RpcPort int
var UseUPnP bool
@@ -18,25 +18,26 @@ var GenAddr bool
var UseSeed bool
var ImportKey string
var ExportKey bool
-var DataDir string
var AssetPath string
+var Datadir string
+
func Init() {
- flag.StringVar(&Identifier, "i", "", "Custom client identifier")
- flag.BoolVar(&StartConsole, "c", false, "debug and testing console")
- 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.StringVar(&Identifier, "id", "", "Custom client identifier")
+ flag.StringVar(&OutboundPort, "port", "30303", "listening port")
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(&GenAddr, "genaddr", false, "create a new priv/pub key")
flag.BoolVar(&ExportKey, "export", false, "export private key")
- flag.IntVar(&RpcPort, "rpcport", 8080, "port to start json-rpc server on")
- flag.StringVar(&OutboundPort, "p", "30303", "listening port")
- flag.StringVar(&DataDir, "dir", ".ethereal", "ethereum data directory")
flag.StringVar(&ImportKey, "import", "", "imports the given private key (hex)")
- 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()
}
diff --git a/ethereal/ethereum.go b/ethereal/ethereum.go
index 30187d956..7ace16760 100644
--- a/ethereal/ethereum.go
+++ b/ethereal/ethereum.go
@@ -8,9 +8,11 @@ import (
"github.com/ethereum/go-ethereum/ethereal/ui"
"github.com/ethereum/go-ethereum/utils"
"github.com/go-qml/qml"
+ "github.com/rakyll/globalconf"
"log"
"os"
"os/signal"
+ "path"
"runtime"
)
@@ -39,7 +41,16 @@ func main() {
runtime.GOMAXPROCS(runtime.NumCPU())
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
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)
}
- if StartMining {
- utils.DoMining(ethereum)
- }
+ /*
+ if StartMining {
+ utils.DoMining(ethereum)
+ }
+ */
if StartRpc {
utils.DoRpc(ethereum, RpcPort)
diff --git a/ethereal/ui/debugger.go b/ethereal/ui/debugger.go
new file mode 100644
index 000000000..919407b34
--- /dev/null
+++ b/ethereal/ui/debugger.go
@@ -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
+ }
+}
diff --git a/ethereal/ui/gui.go b/ethereal/ui/gui.go
index 022f192bf..2ba89ce22 100644
--- a/ethereal/ui/gui.go
+++ b/ethereal/ui/gui.go
@@ -8,9 +8,11 @@ import (
"github.com/ethereum/eth-go/ethdb"
"github.com/ethereum/eth-go/ethpub"
"github.com/ethereum/eth-go/ethutil"
+ "github.com/ethereum/go-ethereum/utils"
"github.com/go-qml/qml"
"math/big"
"strings"
+ "time"
)
type Gui struct {
@@ -54,7 +56,7 @@ func New(ethereum *eth.Ethereum) *Gui {
}
func (gui *Gui) Start(assetPath string) {
- const version = "0.5.0 RC8"
+ const version = "0.5.0 RC12"
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.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.Log.Infoln("[GUI] Starting GUI")
+
// Create a new QML engine
gui.engine = qml.NewEngine()
context := gui.engine.Context()
@@ -86,19 +90,36 @@ func (gui *Gui) Start(assetPath string) {
win, err = gui.showKeyImport(context)
} else {
win, err = gui.showWallet(context)
+
+ ethutil.Config.Log.AddLogSystem(gui)
}
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)
}
+ ethutil.Config.Log.Infoln("[GUI] Starting GUI")
+
win.Show()
win.Wait()
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) {
component, err := gui.engine.LoadFile(gui.uiLib.AssetPath("qml/wallet.qml"))
if err != nil {
@@ -107,8 +128,11 @@ func (gui *Gui) showWallet(context *qml.Context) (*qml.Window, error) {
win := gui.createWindow(component)
- go gui.setInitialBlockChain()
- go gui.readPreviousTransactions()
+ gui.setInitialBlockChain()
+ gui.loadAddressBook()
+ gui.readPreviousTransactions()
+ gui.setPeerInfo()
+
go gui.update()
return win, nil
@@ -130,20 +154,46 @@ func (gui *Gui) createWindow(comp qml.Object) *qml.Window {
gui.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.uiLib.Db = db
return gui.win
}
-
func (gui *Gui) setInitialBlockChain() {
- // Load previous 10 blocks
- chain := gui.eth.BlockChain().GetChain(gui.eth.BlockChain().CurrentBlock.Hash(), 10)
- for _, block := range chain {
- gui.processBlock(block)
+ sBlk := gui.eth.BlockChain().LastBlockHash
+ blk := gui.eth.BlockChain().GetBlock(sBlk)
+ for ; blk != nil; blk = gui.eth.BlockChain().GetBlock(sBlk) {
+ 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() {
@@ -151,13 +201,21 @@ func (gui *Gui) readPreviousTransactions() {
for it.Next() {
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()
}
-func (gui *Gui) processBlock(block *ethchain.Block) {
- gui.win.Root().Call("addBlock", ethpub.NewPBlock(block))
+func (gui *Gui) processBlock(block *ethchain.Block, initial bool) {
+ gui.win.Root().Call("addBlock", ethpub.NewPBlock(block), initial)
}
func (gui *Gui) setWalletValue(amount, unconfirmedFunds *big.Int) {
@@ -182,10 +240,16 @@ func (gui *Gui) update() {
blockChan := 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("newTx:pre", 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()
@@ -196,6 +260,7 @@ func (gui *Gui) update() {
select {
case b := <-blockChan:
block := b.Resource.(*ethchain.Block)
+ gui.processBlock(block, false)
if bytes.Compare(block.Coinbase, gui.addr) == 0 {
gui.setWalletValue(gui.eth.StateManager().CurrentState().GetAccount(gui.addr).Amount, nil)
}
@@ -207,12 +272,12 @@ func (gui *Gui) update() {
object := state.GetAccount(gui.addr)
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())
unconfirmedFunds.Sub(unconfirmedFunds, tx.Value)
} 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())
unconfirmedFunds.Add(unconfirmedFunds, tx.Value)
@@ -231,10 +296,25 @@ func (gui *Gui) update() {
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
func (gui *Gui) Println(v ...interface{}) {
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)
}
}
+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) {
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) {
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
}
diff --git a/ethereal/ui/ui_lib.go b/ethereal/ui/ui_lib.go
index 1c88b0181..9f2cca1e0 100644
--- a/ethereal/ui/ui_lib.go
+++ b/ethereal/ui/ui_lib.go
@@ -2,13 +2,10 @@ package ethui
import (
"bitbucket.org/kardianos/osext"
- "fmt"
"github.com/ethereum/eth-go"
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethutil"
- "github.com/ethereum/go-ethereum/utils"
"github.com/go-qml/qml"
- "github.com/obscuren/mutan"
"os"
"path"
"path/filepath"
@@ -27,8 +24,9 @@ type UiLib struct {
connected bool
assetPath string
// The main application window
- win *qml.Window
- Db *Debugger
+ win *qml.Window
+ Db *Debugger
+ DbWindow *DebuggerWindow
}
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 {
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 {
var base string
@@ -121,27 +142,28 @@ func DefaultAssetPath() string {
func (ui *UiLib) DebugTx(recipient, valueStr, gasStr, gasPriceStr, data string) {
state := ui.eth.BlockChain().CurrentBlock.State()
- mainInput, _ := mutan.PreParse(data)
- callerScript, err := utils.Compile(mainInput)
+ script, err := ethutil.Compile(data)
if err != nil {
ethutil.Config.Log.Debugln(err)
return
}
- dis := ethchain.Disassemble(callerScript)
+ dis := ethchain.Disassemble(script)
ui.win.Root().Call("clearAsm")
for _, str := range dis {
ui.win.Root().Call("setAsm", str)
}
- callerTx := ethchain.NewContractCreationTx(ethutil.Big(valueStr), ethutil.Big(gasStr), ethutil.Big(gasPriceStr), nil)
-
// Contract addr as test address
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())
- c := ethchain.MakeContract(callerTx, state)
- callerClosure := ethchain.NewClosure(account, c, c.Script(), state, ethutil.Big(gasStr), ethutil.Big(gasPriceStr))
+ contract := ethchain.MakeContract(callerTx, state)
+ callerClosure := ethchain.NewClosure(account, contract, contract.Init(), state, ethutil.Big(gasStr), ethutil.Big(gasPriceStr))
block := ui.eth.BlockChain().CurrentBlock
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,
Time: block.Time,
Diff: block.Difficulty,
- TxData: nil,
})
+ ui.Db.done = false
go func() {
- callerClosure.Call(vm, nil, ui.Db.halting)
+ callerClosure.Call(vm, contract.Init(), ui.Db.halting)
state.Reset()
+
+ ui.Db.done = true
}()
}
func (ui *UiLib) 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
-}
diff --git a/ethereum/config.go b/ethereum/config.go
index 5da910f2b..a80b47a8e 100644
--- a/ethereum/config.go
+++ b/ethereum/config.go
@@ -20,33 +20,35 @@ var UseSeed bool
var ImportKey string
var ExportKey bool
var LogFile string
-var DataDir string
var NonInteractive bool
var StartJsConsole bool
var InputFile string
+var Datadir string
+
func Init() {
flag.Usage = func() {
fmt.Fprintf(os.Stderr, "%s [options] [filename]:\n", os.Args[0])
flag.PrintDefaults()
}
- flag.StringVar(&Identifier, "i", "", "custom client identifier")
- flag.BoolVar(&StartMining, "m", false, "start dagger mining")
- flag.BoolVar(&ShowGenesis, "g", false, "prints genesis header and exits")
- flag.BoolVar(&StartRpc, "r", false, "start rpc server")
+ flag.StringVar(&Identifier, "id", "", "Custom client identifier")
+ flag.StringVar(&OutboundPort, "port", "30303", "listening port")
+ 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.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(&UseUPnP, "upnp", false, "enable UPnP support")
flag.BoolVar(&UseSeed, "seed", true, "seed peers")
flag.BoolVar(&GenAddr, "genaddr", false, "create a new priv/pub key")
flag.BoolVar(&ExportKey, "export", false, "export private key")
- flag.StringVar(&OutboundPort, "p", "30303", "listening port")
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.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()
diff --git a/ethereum/ethereum.go b/ethereum/ethereum.go
index 34bacb7b9..179a3f462 100644
--- a/ethereum/ethereum.go
+++ b/ethereum/ethereum.go
@@ -6,10 +6,12 @@ import (
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/go-ethereum/utils"
+ "github.com/rakyll/globalconf"
"io/ioutil"
"log"
"os"
"os/signal"
+ "path"
"runtime"
"strings"
)
@@ -59,7 +61,15 @@ func main() {
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
diff --git a/ethereum/javascript_runtime.go b/ethereum/javascript_runtime.go
index 93297f604..b05d39232 100644
--- a/ethereum/javascript_runtime.go
+++ b/ethereum/javascript_runtime.go
@@ -10,6 +10,7 @@ import (
"github.com/obscuren/otto"
"io/ioutil"
"os"
+ "path"
"path/filepath"
)
@@ -25,6 +26,20 @@ type JSRE struct {
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 {
re := &JSRE{
ethereum,
@@ -39,6 +54,10 @@ func NewJSRE(ethereum *eth.Ethereum) *JSRE {
// Init the JS lib
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"
go re.mainLoop()
diff --git a/ethereum/repl.go b/ethereum/repl.go
index 10f51675e..0208459ad 100644
--- a/ethereum/repl.go
+++ b/ethereum/repl.go
@@ -66,6 +66,10 @@ func (self *JSEthereum) GetBlock(hash string) otto.Value {
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 {
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))
}
+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 {
r, err := self.PEthereum.Transact(key, recipient, valueStr, gasStr, gasPriceStr, dataStr)
if err != nil {
@@ -101,7 +109,7 @@ func (self *JSEthereum) toVal(v interface{}) otto.Value {
result, err := self.vm.ToValue(v)
if err != nil {
- fmt.Println(err)
+ fmt.Println("Value unknown:", err)
return otto.UndefinedValue()
}
diff --git a/utils/cmd.go b/utils/cmd.go
index 98005d7de..e1fc0fc00 100644
--- a/utils/cmd.go
+++ b/utils/cmd.go
@@ -33,13 +33,18 @@ func DoMining(ethereum *eth.Ethereum) {
addr := keyPair.Address()
go func() {
- ethutil.Config.Log.Infoln("Miner started")
-
miner = ethminer.NewDefaultMiner(addr, ethereum)
// Give it some time to connect with peers
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()
}()
}