diff --git a/README.md b/README.md
index 085030ce2..c32b51037 100644
--- a/README.md
+++ b/README.md
@@ -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
index bff653fb8..ca67e857d 100644
--- a/ethereal/assets/debugger/debugger.qml
+++ b/ethereal/assets/debugger/debugger.qml
@@ -8,7 +8,7 @@ import Ethereum 1.0
ApplicationWindow {
visible: false
- title: "IceCream"
+ title: "IceCREAM"
minimumWidth: 1280
minimumHeight: 900
width: 1290
@@ -224,8 +224,8 @@ ApplicationWindow {
}
function setInstruction(num) {
- asmTableView.selection.clear()
- asmTableView.selection.select(num)
+ //asmTableView.selection.clear()
+ //asmTableView.selection.select(num)
}
function setMem(mem) {
@@ -255,6 +255,10 @@ ApplicationWindow {
}
function setLog(msg) {
- logModel.append({message: msg})
+ logModel.insert(0, {message: msg})
+ }
+
+ function clearLog() {
+ logModel.clear()
}
}
diff --git a/ethereal/assets/qml/wallet.qml b/ethereal/assets/qml/wallet.qml
index 847f219a9..458ce90e4 100644
--- a/ethereal/assets/qml/wallet.qml
+++ b/ethereal/assets/qml/wallet.qml
@@ -8,1004 +8,905 @@ import Ethereum 1.0
ApplicationWindow {
- id: root
-
- width: 900
- height: 600
- minimumHeight: 300
-
- title: "Ethereal"
-
- MenuBar {
- Menu {
- title: "File"
- MenuItem {
- text: "Import App"
- shortcut: "Ctrl+o"
- onTriggered: openAppDialog.open()
- }
- }
-
- Menu {
- title: "Tools"
- MenuItem {
- text: "Muted"
- shortcut: "Ctrl+e"
- onTriggered: ui.muted("")
- }
-
- MenuItem {
- text: "Debugger"
- shortcut: "Ctrl+d"
- onTriggered: ui.startDebugger()
- }
- }
-
- Menu {
- title: "Network"
- MenuItem {
- text: "Add Peer"
- shortcut: "Ctrl+p"
- onTriggered: {
- addPeerWin.visible = true
- }
- }
-
- MenuItem {
- text: "Start"
- onTriggered: ui.connect()
- }
- }
-
- Menu {
- title: "Help"
- MenuItem {
- text: "About"
- onTriggered: {
- aboutWin.visible = true
- }
- }
- }
-
- }
-
-
- property var blockModel: ListModel {
- id: blockModel
- }
-
- function setView(view) {
- networkView.visible = false
- historyView.visible = false
- newTxView.visible = false
- infoView.visible = false
- view.visible = true
- //root.title = "Ethereal - " = view.title
- }
-
- SplitView {
- anchors.fill: parent
- resizing: false
-
- Rectangle {
- id: menu
- Layout.minimumWidth: 80
- Layout.maximumWidth: 80
- anchors.bottom: parent.bottom
- anchors.top: parent.top
- //color: "#D9DDE7"
- color: "#252525"
-
- ColumnLayout {
- y: 50
- anchors.left: parent.left
- anchors.right: parent.right
- height: 200
- Image {
- source: ui.assetPath("tx.png")
- anchors.horizontalCenter: parent.horizontalCenter
- MouseArea {
- anchors.fill: parent
- onClicked: {
- setView(historyView)
- }
- }
- }
- Image {
- source: ui.assetPath("new.png")
- anchors.horizontalCenter: parent.horizontalCenter
- MouseArea {
- anchors.fill: parent
- onClicked: {
- setView(newTxView)
- }
- }
- }
- Image {
- source: ui.assetPath("net.png")
- anchors.horizontalCenter: parent.horizontalCenter
- MouseArea {
- anchors.fill: parent
- onClicked: {
- setView(networkView)
- }
- }
- }
-
- Image {
- source: ui.assetPath("heart.png")
- anchors.horizontalCenter: parent.horizontalCenter
- MouseArea {
- anchors.fill: parent
- onClicked: {
- setView(infoView)
- }
- }
- }
- }
- }
-
- Rectangle {
- id: mainView
- color: "#00000000"
- anchors.right: parent.right
- anchors.left: menu.right
- anchors.bottom: parent.bottom
- anchors.top: parent.top
-
- property var txModel: ListModel {
- id: txModel
- }
-
- Rectangle {
- id: historyView
- anchors.fill: parent
-
- property var title: "Transactions"
- TableView {
- id: txTableView
- anchors.fill: parent
- TableViewColumn{ role: "inout" ; title: "" ; width: 40 }
- TableViewColumn{ role: "value" ; title: "Value" ; width: 100 }
- TableViewColumn{ role: "address" ; title: "Address" ; width: 430 }
- TableViewColumn{ role: "contract" ; title: "Contract" ; width: 100 }
-
- model: txModel
- }
- }
-
- Rectangle {
- id: newTxView
- property var title: "New transaction"
- visible: false
- anchors.fill: parent
- color: "#00000000"
- TabView{
- anchors.fill: parent
- anchors.rightMargin: 5
- anchors.leftMargin: 5
- anchors.topMargin: 5
- anchors.bottomMargin: 5
- id: newTransactionTab
- Component.onCompleted:{
- addTab("Simple send", newTransaction)
- addTab("Contracts", newContract)
- }
- }
- }
-
- Rectangle {
- id: networkView
- property var title: "Network"
- visible: false
- anchors.fill: parent
-
- TableView {
- id: blockTable
- width: parent.width
- anchors.top: parent.top
- anchors.bottom: logView.top
- TableViewColumn{ role: "number" ; title: "#" ; width: 100 }
- TableViewColumn{ role: "hash" ; title: "Hash" ; width: 560 }
- TableViewColumn{ role: "txAmount" ; title: "Tx amount" ; width: 100 }
-
- model: blockModel
-
- onDoubleClicked: {
- popup.visible = true
- popup.setDetails(blockModel.get(row))
- }
- }
-
- 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 {
- id: infoView
- property var title: "Information"
- visible: false
- color: "#00000000"
- anchors.fill: parent
-
- Label {
- id: addressLabel
- text: "Address"
- anchors {
- margins: 5
- top: parent.top
- left: parent.left
- }
- }
- TextField {
- anchors {
- margins: 5
- left: addressLabel.right
- top: parent.top
- }
- text: pub.getKey().address
- width: 500
- }
- }
-
- /*
- signal addPlugin(string name)
- Component {
- id: pluginWindow
- Rectangle {
- anchors.fill: parent
- Label {
- id: pluginTitle
- anchors.centerIn: parent
- text: "Hello world"
- }
- Component.onCompleted: setView(this)
- }
- }
-
- onAddPlugin: {
- var pluginWin = pluginWindow.createObject(mainView)
- console.log(pluginWin)
- pluginWin.pluginTitle.text = "Test"
- }
- */
- }
- }
-
- FileDialog {
- id: openAppDialog
- title: "Open QML Application"
- onAccepted: {
- //ui.open(openAppDialog.fileUrl.toString())
- //ui.openHtml(Qt.resolvedUrl(ui.assetPath("test.html")))
- ui.openHtml(openAppDialog.fileUrl.toString())
- }
- }
-
- statusBar: StatusBar {
- RowLayout {
- anchors.fill: parent
-
- Button {
- property var enabled: true
- id: debuggerWindow
- onClicked: {
- ui.startDebugger()
- }
- text: "Debugger"
- }
-
- Button {
- id: importAppButton
- anchors.left: debuggerWindow.right
- anchors.leftMargin: 5
- onClicked: openAppDialog.open()
- text: "Import App"
- }
-
- Label {
- anchors.left: importAppButton.right
- 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")
- }
- }
- }
-
- Window {
- id: popup
- visible: false
- property var block
- width: root.width
- height: 240
- Component{
- id: blockDetailsDelegate
- Rectangle {
- color: "#252525"
- width: popup.width
- height: 200
- Column {
- anchors.leftMargin: 10
- anchors.topMargin: 5
- anchors.top: parent.top
- anchors.left: parent.left
- Text { text: '
Block details
'; color: "#F2F2F2"}
- Text { text: 'Block number: ' + number; color: "#F2F2F2"}
- Text { text: 'Hash: ' + hash; color: "#F2F2F2"}
- Text { text: 'Block found at: ' + prettyTime; color: "#F2F2F2"}
- }
- }
- }
- ListView {
- model: singleBlock
- delegate: blockDetailsDelegate
- anchors.top: parent.top
- height: 70
- 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 = 230
- }
- }
- }
-
- function showContractData(tx) {
- txDetailsDebugButton.tx = tx
- if(tx.createsContract) {
- contractData.text = tx.data
- contractLabel.text = " Transaction created contract " + tx.address + "
"
- }else{
- contractLabel.text = " Transaction ran contract " + tx.address + "
"
- contractData.text = tx.rawData
- }
- popup.height = 400
- }
-
- Rectangle {
- id: txDetails
- width: popup.width
- height: 300
- anchors.left: listViewThing.left
- anchors.top: txView.bottom
- Label {
- text: "Contract data
"
- 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 = 230
- 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()
- }
- }
-
- Window {
- id: addPeerWin
- visible: false
- minimumWidth: 230
- maximumWidth: 230
- maximumHeight: 50
- minimumHeight: 50
-
- TextField {
- id: addrField
- anchors.verticalCenter: parent.verticalCenter
- anchors.left: parent.left
- anchors.leftMargin: 10
- placeholderText: "address:port"
- onAccepted: {
- ui.connectToPeer(addrField.text)
- addPeerWin.visible = false
- }
- }
- Button {
- anchors.left: addrField.right
- anchors.verticalCenter: parent.verticalCenter
- anchors.leftMargin: 5
- text: "Add"
- onClicked: {
- ui.connectToPeer(addrField.text)
- addPeerWin.visible = false
- }
- }
- Component.onCompleted: {
- addrField.focus = true
- }
- }
-
- Window {
- id: aboutWin
- visible: false
- title: "About"
- minimumWidth: 350
- maximumWidth: 350
- maximumHeight: 200
- minimumHeight: 200
-
- Image {
- id: aboutIcon
- height: 150
- width: 150
- fillMode: Image.PreserveAspectFit
- smooth: true
- source: ui.assetPath("facet.png")
- x: 10
- y: 10
- }
-
- Text {
- anchors.left: aboutIcon.right
- anchors.leftMargin: 10
- font.pointSize: 12
- text: "Ethereal
Development
Jeffrey Wilcke
Maran Hidskes
"
- }
-
- }
-
- ApplicationWindow {
- 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()
- }
- }
- }
- 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
- id: debugSplitView
- 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: debugSplitView.width }
- model: stackModel
- }
- }
- }
- }
- }
- statusBar: StatusBar {
- RowLayout {
- anchors.fill: parent
- Button {
- property var enabled: true
- id: debugNextButton
- onClicked: {
- ui.next()
- }
- text: "Next"
- }
- }
- }
- }
-
- 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 loadPlugin(name) {
- console.log("Loading plugin" + name)
- mainView.addPlugin(name)
- }
-
- function setWalletValue(value) {
- walletValueLabel.text = value
- }
-
- function addTx(tx, inout) {
- var isContract
- if (tx.contract == true){
- isContract = "Yes"
- }else{
- isContract = "No"
- }
- txModel.insert(0, {inout: inout, hash: tx.hash, address: tx.address, value: tx.value, contract: isContract})
- }
-
- 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, hash: block.hash, txs: txs, txAmount: amount, time: block.time, prettyTime: convertToPretty(block.time)})
- }else{
- blockModel.insert(0, {number: block.number, 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})
- }
- }
-
- function setPeers(text) {
- peerLabel.text = text
- }
- 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;
- }
- // *******************************************
- // Components
- // *******************************************
-
- // New Contract component
- 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 could not be send over the network:\n"
- txResult.text += res[1].error()
- txResult.text += ""
- 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
- }
- }
- }
- }
-
- // 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,"","","")
- 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"
- }
- }
- }
- }
+ id: root
+
+ property alias miningButtonText: miningButton.text
+
+ width: 900
+ height: 600
+ minimumHeight: 300
+
+ title: "Ethereal"
+
+ MenuBar {
+ Menu {
+ title: "File"
+ MenuItem {
+ text: "Import App"
+ shortcut: "Ctrl+o"
+ onTriggered: openAppDialog.open()
+ }
+ }
+
+ Menu {
+ MenuItem {
+ text: "Debugger"
+ shortcut: "Ctrl+d"
+ onTriggered: ui.startDebugger()
+ }
+ }
+
+ Menu {
+ title: "Network"
+ MenuItem {
+ text: "Add Peer"
+ shortcut: "Ctrl+p"
+ onTriggered: {
+ addPeerWin.visible = true
+ }
+ }
+ }
+
+ Menu {
+ title: "Help"
+ MenuItem {
+ text: "About"
+ onTriggered: {
+ aboutWin.visible = true
+ }
+ }
+ }
+
+ }
+
+
+ property var blockModel: ListModel {
+ id: blockModel
+ }
+
+ function setView(view) {
+ networkView.visible = false
+ historyView.visible = false
+ newTxView.visible = false
+ infoView.visible = false
+ view.visible = true
+ //root.title = "Ethereal - " = view.title
+ }
+
+ SplitView {
+ anchors.fill: parent
+ resizing: false
+
+ Rectangle {
+ id: menu
+ Layout.minimumWidth: 80
+ Layout.maximumWidth: 80
+ anchors.bottom: parent.bottom
+ anchors.top: parent.top
+ //color: "#D9DDE7"
+ color: "#252525"
+
+ ColumnLayout {
+ y: 50
+ anchors.left: parent.left
+ anchors.right: parent.right
+ height: 200
+ Image {
+ source: ui.assetPath("tx.png")
+ anchors.horizontalCenter: parent.horizontalCenter
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ setView(historyView)
+ }
+ }
+ }
+ Image {
+ source: ui.assetPath("new.png")
+ anchors.horizontalCenter: parent.horizontalCenter
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ setView(newTxView)
+ }
+ }
+ }
+ Image {
+ source: ui.assetPath("net.png")
+ anchors.horizontalCenter: parent.horizontalCenter
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ setView(networkView)
+ }
+ }
+ }
+
+ Image {
+ source: ui.assetPath("heart.png")
+ anchors.horizontalCenter: parent.horizontalCenter
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ setView(infoView)
+ }
+ }
+ }
+ }
+ }
+
+ Rectangle {
+ id: mainView
+ color: "#00000000"
+ anchors.right: parent.right
+ anchors.left: menu.right
+ anchors.bottom: parent.bottom
+ anchors.top: parent.top
+
+ property var txModel: ListModel {
+ id: txModel
+ }
+
+ Rectangle {
+ id: historyView
+ anchors.fill: parent
+
+ property var title: "Transactions"
+ TableView {
+ id: txTableView
+ anchors.fill: parent
+ TableViewColumn{ role: "inout" ; title: "" ; width: 40 }
+ TableViewColumn{ role: "value" ; title: "Value" ; width: 100 }
+ TableViewColumn{ role: "address" ; title: "Address" ; width: 430 }
+ TableViewColumn{ role: "contract" ; title: "Contract" ; width: 100 }
+
+ model: txModel
+ }
+ }
+
+ Rectangle {
+ id: newTxView
+ property var title: "New transaction"
+ visible: false
+ anchors.fill: parent
+ color: "#00000000"
+ /*
+ TabView{
+ anchors.fill: parent
+ anchors.rightMargin: 5
+ anchors.leftMargin: 5
+ anchors.topMargin: 5
+ anchors.bottomMargin: 5
+ id: newTransactionTab
+ Component.onCompleted:{
+ addTab("Simple send", newTransaction)
+ addTab("Contracts", newContract)
+ }
+ }
+ */
+ Component.onCompleted: {
+ newContract.createObject(newTxView)
+ }
+ }
+
+ Rectangle {
+ id: networkView
+ property var title: "Network"
+ visible: false
+ anchors.fill: parent
+
+ TableView {
+ id: blockTable
+ width: parent.width
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ TableViewColumn{ role: "number" ; title: "#" ; width: 100 }
+ TableViewColumn{ role: "hash" ; title: "Hash" ; width: 560 }
+ TableViewColumn{ role: "txAmount" ; title: "Tx amount" ; width: 100 }
+
+ model: blockModel
+
+ onDoubleClicked: {
+ popup.visible = true
+ popup.setDetails(blockModel.get(row))
+ }
+ }
+
+ }
+
+ Rectangle {
+ id: infoView
+ property var title: "Information"
+ visible: false
+ color: "#00000000"
+ anchors.fill: parent
+
+ Label {
+ id: addressLabel
+ text: "Address"
+ anchors {
+ margins: 5
+ top: parent.top
+ left: parent.left
+ }
+ }
+ TextField {
+ anchors {
+ margins: 5
+ left: addressLabel.right
+ top: parent.top
+ }
+ text: pub.getKey().address
+ width: 500
+ }
+
+
+ property var addressModel: ListModel {
+ id: addressModel
+ }
+ TableView {
+ id: addressView
+ width: parent.width
+ height: 200
+ anchors.bottom: logView.top
+ TableViewColumn{ role: "name"; title: "name" }
+ TableViewColumn{ role: "address"; title: "address"; width: 300}
+
+ model: addressModel
+ }
+
+
+ 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
+ }
+ }
+
+ /*
+ signal addPlugin(string name)
+ Component {
+ id: pluginWindow
+ Rectangle {
+ anchors.fill: parent
+ Label {
+ id: pluginTitle
+ anchors.centerIn: parent
+ text: "Hello world"
+ }
+ Component.onCompleted: setView(this)
+ }
+ }
+
+ onAddPlugin: {
+ var pluginWin = pluginWindow.createObject(mainView)
+ console.log(pluginWin)
+ pluginWin.pluginTitle.text = "Test"
+ }
+ */
+ }
+ }
+
+ FileDialog {
+ id: openAppDialog
+ title: "Open QML Application"
+ onAccepted: {
+ //ui.open(openAppDialog.fileUrl.toString())
+ //ui.openHtml(Qt.resolvedUrl(ui.assetPath("test.html")))
+ ui.openHtml(openAppDialog.fileUrl.toString())
+ }
+ }
+
+ statusBar: StatusBar {
+ height: 30
+ RowLayout {
+ Button {
+ id: miningButton
+ onClicked: {
+ eth.toggleMining()
+ }
+ text: "Start Mining"
+ }
+
+ Button {
+ property var enabled: true
+ id: debuggerWindow
+ onClicked: {
+ ui.startDebugger()
+ }
+ text: "Debugger"
+ }
+
+ Button {
+ id: importAppButton
+ anchors.left: debuggerWindow.right
+ anchors.leftMargin: 5
+ onClicked: openAppDialog.open()
+ text: "Import App"
+ }
+
+ Label {
+ anchors.left: importAppButton.right
+ anchors.leftMargin: 5
+ id: walletValueLabel
+ }
+ }
+
+ 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
+ source: ui.assetPath("network.png")
+ }
+ }
+
+ Window {
+ id: popup
+ visible: false
+ 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: 'Block details
'; color: "#F2F2F2"}
+ Text { text: 'Block number: ' + number; color: "#F2F2F2"}
+ Text { text: 'Hash: ' + hash; color: "#F2F2F2"}
+ Text { text: 'Coinbase: ' + coinbase; color: "#F2F2F2"}
+ Text { text: 'Block found at: ' + prettyTime; 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 = " Transaction created contract " + tx.address + "
"
+ }else{
+ contractLabel.text = " Transaction ran contract " + tx.address + "
"
+ 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: "Contract data
"
+ 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()
+ }
+ }
+
+ Window {
+ id: addPeerWin
+ visible: false
+ minimumWidth: 230
+ maximumWidth: 230
+ maximumHeight: 50
+ minimumHeight: 50
+
+ TextField {
+ id: addrField
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.left: parent.left
+ anchors.leftMargin: 10
+ placeholderText: "address:port"
+ onAccepted: {
+ ui.connectToPeer(addrField.text)
+ addPeerWin.visible = false
+ }
+ }
+ Button {
+ anchors.left: addrField.right
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.leftMargin: 5
+ text: "Add"
+ onClicked: {
+ ui.connectToPeer(addrField.text)
+ addPeerWin.visible = false
+ }
+ }
+ Component.onCompleted: {
+ addrField.focus = true
+ }
+ }
+
+ Window {
+ id: aboutWin
+ visible: false
+ title: "About"
+ minimumWidth: 350
+ maximumWidth: 350
+ maximumHeight: 200
+ minimumHeight: 200
+
+ Image {
+ id: aboutIcon
+ height: 150
+ width: 150
+ fillMode: Image.PreserveAspectFit
+ smooth: true
+ source: ui.assetPath("facet.png")
+ x: 10
+ y: 10
+ }
+
+ Text {
+ anchors.left: aboutIcon.right
+ anchors.leftMargin: 10
+ font.pointSize: 12
+ text: "Ethereal
Development
Jeffrey Wilcke
Maran Hidskes
"
+ }
+ }
+
+ function addDebugMessage(message){
+ debuggerLog.append({value: message})
+ }
+
+ function addAddress(address) {
+ addressModel.append({name: address.name, address: address.address})
+ }
+ function clearAddress() {
+ addressModel.clear()
+ }
+
+ function loadPlugin(name) {
+ console.log("Loading plugin" + name)
+ mainView.addPlugin(name)
+ }
+
+ function setWalletValue(value) {
+ walletValueLabel.text = value
+ }
+
+ function addTx(tx, inout) {
+ var isContract
+ if (tx.contract == true){
+ isContract = "Yes"
+ }else{
+ isContract = "No"
+ }
+
+ var address;
+ if(inout == "recv") {
+ address = tx.sender;
+ } else {
+ address = tx.address;
+ }
+ txModel.insert(0, {inout: inout, hash: tx.hash, address: address, value: tx.value, contract: isContract})
+ }
+
+ 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, coinbase: block.coinbase, hash: block.hash, txs: txs, txAmount: amount, time: block.time, prettyTime: convertToPretty(block.time)})
+ }else{
+ blockModel.insert(0, {number: block.number, 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.insert(0, {description: str})
+ }
+ }
+
+ function setPeers(text) {
+ peerLabel.text = text
+ }
+ 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;
+ }
+ // *******************************************
+ // 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 could not be send over the network:\n"
+ txResult.text += res[1].error()
+ txResult.text += ""
+ 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/config.go b/ethereal/config.go
index 3864126db..6a42663e7 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,22 @@ var GenAddr bool
var UseSeed bool
var ImportKey string
var ExportKey bool
-var DataDir string
var AssetPath 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.Parse()
}
diff --git a/ethereal/ethereum.go b/ethereal/ethereum.go
index 30187d956..a7e43cd9a 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(".ethereal"), "conf.ini"),
+ })
+ if err != nil {
+ fmt.Println(err)
+ } else {
+ g.ParseAll()
+ }
+ ethutil.ReadConfig(".ethereal", ethutil.LogFile|ethutil.LogStd, 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
index 9bca7e4fe..a6b8e16d0 100644
--- a/ethereal/ui/debugger.go
+++ b/ethereal/ui/debugger.go
@@ -71,6 +71,7 @@ func (self *DebuggerWindow) Debug(valueStr, gasStr, gasPriceStr, scriptStr, data
var err error
script := ethutil.StringToByteFunc(scriptStr, func(s string) (ret []byte) {
ret, err = ethutil.Compile(s)
+ fmt.Printf("%x\n", ret)
return
})
@@ -82,6 +83,7 @@ func (self *DebuggerWindow) Debug(valueStr, gasStr, gasPriceStr, scriptStr, data
dis := ethchain.Disassemble(script)
self.win.Root().Call("clearAsm")
+ self.win.Root().Call("clearLog")
for _, str := range dis {
self.win.Root().Call("setAsm", str)
diff --git a/ethereal/ui/gui.go b/ethereal/ui/gui.go
index 1698f5de0..d6430d1fe 100644
--- a/ethereal/ui/gui.go
+++ b/ethereal/ui/gui.go
@@ -8,6 +8,7 @@ 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"
@@ -66,7 +67,6 @@ func (gui *Gui) Start(assetPath string) {
}})
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()
@@ -93,12 +93,28 @@ func (gui *Gui) Start(assetPath string) {
panic(err)
}
+ ethutil.Config.Log.AddLogSystem(gui)
+ 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 +123,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
@@ -145,6 +164,19 @@ func (gui *Gui) setInitialBlockChain() {
}
}
+type address struct {
+ Name, Address string
+}
+
+var namereg = ethutil.FromHex("bb5f186604d057c1c5240ca2ae0f6430138ac010")
+
+func (gui *Gui) loadAddressBook() {
+ gui.win.Root().Call("clearAddress")
+ gui.eth.StateManager().CurrentState().GetStateObject(namereg).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() {
it := gui.txDb.Db().NewIterator(nil, nil)
for it.Next() {
@@ -189,10 +221,14 @@ 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)
state := gui.eth.StateManager().TransState()
@@ -239,10 +275,18 @@ func (gui *Gui) update() {
state.UpdateStateObject(object)
}
+ case <-objectChan:
+ gui.loadAddressBook()
+ case <-peerChan:
+ gui.setPeerInfo()
}
}
}
+func (gui *Gui) setPeerInfo() {
+ gui.win.Root().Call("setPeers", fmt.Sprintf("%d / %d", gui.eth.PeerCount(), gui.eth.MaxPeers))
+}
+
// Logging functions that log directly to the GUI interface
func (gui *Gui) Println(v ...interface{}) {
str := strings.TrimRight(fmt.Sprintln(v...), "\n")
diff --git a/ethereum/config.go b/ethereum/config.go
index 5da910f2b..39dc11727 100644
--- a/ethereum/config.go
+++ b/ethereum/config.go
@@ -20,7 +20,6 @@ var UseSeed bool
var ImportKey string
var ExportKey bool
var LogFile string
-var DataDir string
var NonInteractive bool
var StartJsConsole bool
var InputFile string
@@ -31,22 +30,21 @@ func Init() {
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.IntVar(&RpcPort, "rpcport", 8080, "port to start json-rpc server on")
- flag.BoolVar(&NonInteractive, "y", false, "non-interactive mode (say yes to confirmations)")
+ 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(&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.Parse()
diff --git a/ethereum/ethereum.go b/ethereum/ethereum.go
index 34bacb7b9..7bb668235 100644
--- a/ethereum/ethereum.go
+++ b/ethereum/ethereum.go
@@ -59,7 +59,7 @@ func main() {
lt = ethutil.LogFile | ethutil.LogStd
}
- ethutil.ReadConfig(DataDir, lt, Identifier)
+ ethutil.ReadConfig(".ethereum", lt, Identifier)
logger := ethutil.Config.Log
diff --git a/utils/cmd.go b/utils/cmd.go
index f8b7b5fe2..e1fc0fc00 100644
--- a/utils/cmd.go
+++ b/utils/cmd.go
@@ -33,8 +33,6 @@ 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