Compare commits

...

55 Commits
2 ... 0.5.13

Author SHA1 Message Date
98335d2040 Merge branch 'release/0.5.13' 2014-06-16 18:24:57 +02:00
c1220e8729 bump 2014-06-16 18:24:24 +02:00
3744151359 Removed init fees 2014-06-16 11:15:08 +02:00
7ab735eb02 Max 250 log 2014-06-15 00:02:41 +02:00
ef1b923b31 Added a log level slider which can change the log level 2014-06-14 15:44:32 +02:00
e7a22af0e6 Minor UI adjustments 2014-06-12 10:06:02 +02:00
1d300bbc10 Toggle inspector / reload using magic rectangle 2014-06-11 15:55:47 +02:00
e36badd744 Reimplement -datadir flag. Implements #79
The config file is actually loaded from the folder that datadir points at
2014-06-11 12:33:11 +02:00
57e3b1b093 Implemented usedGas to the explorer 2014-06-11 11:40:13 +02:00
0ee258bb75 Add GasLimit to the block explorer 2014-06-11 10:27:58 +02:00
66199497a0 Merge branch 'release/poc5-rc12' into develop 2014-06-09 22:24:30 +02:00
aa8a86f0a6 Merge branch 'release/poc5-rc12' 2014-06-09 22:24:24 +02:00
d929c63474 bump 2014-06-09 22:23:33 +02:00
ba3623d0cc Fixed debugger hang 2014-06-09 22:04:16 +02:00
cc20b0e3a0 debugger output 2014-06-06 12:13:13 +02:00
a107a5db05 Merge branch 'develop' of github.com-obscure:ethereum/go-ethereum into develop 2014-06-05 09:01:10 +02:00
964587b14a Added more debugger output 2014-06-05 09:00:57 +02:00
7843390ecd Implement getStateKeyVal for JS bindings.
Gives JS the option to 'loop' over contract key/val storage
2014-06-04 15:54:33 +02:00
307fe4a3cd Add loading of extra build in js files to JS-Repl. Implements #67 2014-06-04 12:19:50 +02:00
3755616a29 Added namereg register option to qml wallet 2014-06-03 14:30:26 +02:00
cc1d043423 Implemented transaction catching up. Implements #73 2014-06-03 11:48:44 +02:00
9e411d785b Tweaks and latency added to peeroverview 2014-06-03 10:42:36 +02:00
a6f4eef1da Added Peer Window 2014-06-02 15:16:37 +02:00
98811f11e5 ethereum instead of ethereal. Fixes #69 2014-05-31 11:43:08 +02:00
d6acb74ac9 fixed logging issue that would otherwise crash the client. Fixes #68 2014-05-31 11:34:37 +02:00
397e99fcc6 Merge branch 'develop' 2014-05-30 20:35:44 +02:00
be27309dbb show first? 2014-05-30 20:35:37 +02:00
4dfce5d347 Merge branch 'develop' 2014-05-30 19:36:21 +02:00
0bdb0a9d58 Added ini file for ethereum. fixes #66 2014-05-30 19:36:05 +02:00
5f28013f79 Merge branch 'develop' 2014-05-30 16:58:17 +02:00
65c5a20e1c Added config file setup. Fixes #59
* Also fixes asset path problems
2014-05-30 16:56:56 +02:00
1020d7ff67 Unified the contract interface and tx interface. Fixes #62 2014-05-30 16:14:46 +02:00
e7c9b86a5a Improved UI
* Added mining button
2014-05-30 13:28:31 +02:00
0938b56829 Update peer info 2014-05-30 13:04:23 +02:00
fcbf99a30a Minor GUI updates
* IceCream => IceCREAM
* Added coin base to block info
2014-05-30 11:50:30 +02:00
40d72ff40b . 2014-05-29 12:24:56 +02:00
efadfbfb17 Minor UI changes
* Moved log from block view
* Prepend instead of append for logs
2014-05-29 12:24:14 +02:00
8ee6574d12 Minimal fee for sending transactions 2014-05-29 12:14:25 +02:00
efb3ee044b Removed regexp for namereg 2014-05-29 11:49:59 +02:00
0b4c42d756 Disabled instruction selection 2014-05-29 02:05:06 +02:00
f0f205004c Merge branch 'develop' 2014-05-28 23:23:52 +02:00
f802e17626 merge 2014-05-28 23:16:15 +02:00
8fab7ce37d Fixes and improved debugger 2014-05-28 23:14:23 +02:00
44db1a1eb2 Add 0x when feeding data to debugger 2014-05-28 18:11:27 +02:00
0aee830bde Fix merge conflict 2014-05-28 16:20:36 +02:00
06d41794f9 Merge branch 'release/poc5-rc11' into develop 2014-05-28 16:20:05 +02:00
2114218ed8 Merge branch 'release/poc5-rc11' 2014-05-28 16:19:58 +02:00
58032d60e7 Bump to RC11 2014-05-28 16:17:57 +02:00
d4f9daa631 Refactor hex encode and remove coupling of popup to main window 2014-05-28 16:14:24 +02:00
1eda1d25b0 Hooked up the Block Explorer to the Debugger so we can instantly debug made transactions 2014-05-28 15:48:17 +02:00
aaeb268522 Merge branch 'develop' of github.com-obscure:ethereum/go-ethereum into develop 2014-05-28 13:01:04 +02:00
540d39220d Merge branch 'master' into develop 2014-05-28 13:00:51 +02:00
09728bf43c Debugger script&data now accept "0x" values 2014-05-28 13:00:45 +02:00
090447c664 Data and script in the debugger accept "0x" values and regular scripting 2014-05-28 12:59:10 +02:00
d4af5a5763 Merge branch 'hotfix/2' into develop 2014-05-28 11:53:31 +02:00
16 changed files with 1597 additions and 1254 deletions

View File

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

View File

@ -8,12 +8,15 @@ import Ethereum 1.0
ApplicationWindow { ApplicationWindow {
visible: false visible: false
title: "IceCream" title: "IceCREAM"
minimumWidth: 1280 minimumWidth: 1280
minimumHeight: 900 minimumHeight: 900
width: 1290 width: 1290
height: 900 height: 900
property alias codeText: codeEditor.text
property alias dataText: rawDataField.text
MenuBar { MenuBar {
Menu { Menu {
title: "Debugger" title: "Debugger"
@ -123,7 +126,7 @@ ApplicationWindow {
SplitView { SplitView {
orientation: Qt.Horizontal orientation: Qt.Horizontal
height: 250 height: 150
TableView { TableView {
id: stackTableView id: stackTableView
@ -132,7 +135,7 @@ ApplicationWindow {
} }
height: parent.height height: parent.height
width: 300 width: 300
TableViewColumn{ role: "value" ; title: "Stack" ; width: 200 } TableViewColumn{ role: "value" ; title: "Temp" ; width: 200 }
model: stackModel model: stackModel
} }
@ -149,24 +152,41 @@ ApplicationWindow {
} }
} }
SplitView { Rectangle {
height: 300 height: 100
width: parent.width
TableView { TableView {
id: storageTableView id: storageTableView
property var memModel: ListModel { property var memModel: ListModel {
id: storageModel id: storageModel
} }
height: parent.height height: parent.height
width: parent.width - stackTableView.width width: parent.width
TableViewColumn{ id: key ; role: "key" ; title: "#" ; width: storageTableView.width / 2} TableViewColumn{ id: key ; role: "key" ; title: "#" ; width: storageTableView.width / 2}
TableViewColumn{ role: "value" ; title: "value" ; width: storageTableView.width / 2} TableViewColumn{ role: "value" ; title: "Storage" ; width: storageTableView.width / 2}
model: storageModel 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 { toolBar: ToolBar {
RowLayout { RowLayout {
spacing: 5 spacing: 5
@ -205,7 +225,7 @@ ApplicationWindow {
function setInstruction(num) { function setInstruction(num) {
asmTableView.selection.clear() asmTableView.selection.clear()
asmTableView.selection.select(num-1) asmTableView.selection.select(num)
} }
function setMem(mem) { function setMem(mem) {
@ -233,4 +253,12 @@ ApplicationWindow {
function setStorage(storage) { function setStorage(storage) {
storageModel.append({key: storage.key, value: storage.value}) storageModel.append({key: storage.key, value: storage.value})
} }
function setLog(msg) {
logModel.insert(0, {message: msg})
}
function clearLog() {
logModel.clear()
}
} }

View File

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

View File

@ -10,6 +10,8 @@ import Ethereum 1.0
ApplicationWindow { ApplicationWindow {
id: root id: root
property alias miningButtonText: miningButton.text
width: 900 width: 900
height: 600 height: 600
minimumHeight: 300 minimumHeight: 300
@ -27,13 +29,7 @@ ApplicationWindow {
} }
Menu { Menu {
title: "Tools" title: "Developer"
MenuItem {
text: "Muted"
shortcut: "Ctrl+e"
onTriggered: ui.muted("")
}
MenuItem { MenuItem {
text: "Debugger" text: "Debugger"
shortcut: "Ctrl+d" shortcut: "Ctrl+d"
@ -50,10 +46,12 @@ ApplicationWindow {
addPeerWin.visible = true addPeerWin.visible = true
} }
} }
MenuItem { MenuItem {
text: "Start" text: "Show Peers"
onTriggered: ui.connect() shortcut: "Ctrl+e"
onTriggered: {
peerWindow.visible = true
}
} }
} }
@ -180,6 +178,7 @@ ApplicationWindow {
visible: false visible: false
anchors.fill: parent anchors.fill: parent
color: "#00000000" color: "#00000000"
/*
TabView{ TabView{
anchors.fill: parent anchors.fill: parent
anchors.rightMargin: 5 anchors.rightMargin: 5
@ -192,6 +191,10 @@ ApplicationWindow {
addTab("Contracts", newContract) addTab("Contracts", newContract)
} }
} }
*/
Component.onCompleted: {
newContract.createObject(newTxView)
}
} }
Rectangle { Rectangle {
@ -204,7 +207,7 @@ ApplicationWindow {
id: blockTable id: blockTable
width: parent.width width: parent.width
anchors.top: parent.top anchors.top: parent.top
anchors.bottom: logView.top anchors.bottom: parent.bottom
TableViewColumn{ role: "number" ; title: "#" ; width: 100 } TableViewColumn{ role: "number" ; title: "#" ; width: 100 }
TableViewColumn{ role: "hash" ; title: "Hash" ; width: 560 } TableViewColumn{ role: "hash" ; title: "Hash" ; width: 560 }
TableViewColumn{ role: "txAmount" ; title: "Tx amount" ; width: 100 } TableViewColumn{ role: "txAmount" ; title: "Tx amount" ; width: 100 }
@ -217,19 +220,6 @@ ApplicationWindow {
} }
} }
property var logModel: ListModel {
id: logModel
}
TableView {
id: logView
width: parent.width
height: 150
anchors.bottom: parent.bottom
TableViewColumn{ role: "description" ; title: "log" }
model: logModel
}
} }
Rectangle { Rectangle {
@ -239,24 +229,117 @@ ApplicationWindow {
color: "#00000000" color: "#00000000"
anchors.fill: parent anchors.fill: parent
Column {
spacing: 3
anchors.fill: parent
anchors.topMargin: 5
anchors.leftMargin: 5
Label { Label {
id: addressLabel id: addressLabel
text: "Address" text: "Address"
anchors {
margins: 5
top: parent.top
left: parent.left
}
} }
TextField { TextField {
anchors {
margins: 5
left: addressLabel.right
top: parent.top
}
text: pub.getKey().address text: pub.getKey().address
width: 500 width: 500
} }
Label {
text: "Client ID"
}
TextField {
text: eth.clientId()
onTextChanged: {
eth.changeClientId(text)
}
}
}
property var addressModel: ListModel {
id: addressModel
}
TableView {
id: addressView
width: parent.width - 200
height: 200
anchors.bottom: logLayout.top
TableViewColumn{ role: "name"; title: "name" }
TableViewColumn{ role: "address"; title: "address"; width: 300}
model: addressModel
}
Rectangle {
anchors.top: addressView.top
anchors.left: addressView.right
anchors.leftMargin: 20
TextField {
placeholderText: "Name to register"
id: nameToReg
width: 150
}
Button {
anchors.top: nameToReg.bottom
text: "Register"
MouseArea{
anchors.fill: parent
onClicked: {
eth.registerName(nameToReg.text)
nameToReg.text = ""
}
}
}
}
property var logModel: ListModel {
id: logModel
}
RowLayout {
id: logLayout
width: parent.width
height: 200
anchors.bottom: parent.bottom
TableView {
id: logView
headerVisible: false
anchors {
right: logLevelSlider.left
left: parent.left
bottom: parent.bottom
top: parent.top
}
TableViewColumn{ role: "description" ; title: "log" }
model: logModel
}
Slider {
id: logLevelSlider
value: 1
anchors {
right: parent.right
top: parent.top
bottom: parent.bottom
rightMargin: 5
leftMargin: 5
topMargin: 5
bottomMargin: 5
}
orientation: Qt.Vertical
maximumValue: 3
stepSize: 1
onValueChanged: {
eth.setLogLevel(value)
}
}
}
} }
/* /*
@ -294,8 +377,15 @@ ApplicationWindow {
} }
statusBar: StatusBar { statusBar: StatusBar {
height: 30
RowLayout { RowLayout {
anchors.fill: parent Button {
id: miningButton
onClicked: {
eth.toggleMining()
}
text: "Start Mining"
}
Button { Button {
property var enabled: true property var enabled: true
@ -319,8 +409,10 @@ ApplicationWindow {
anchors.leftMargin: 5 anchors.leftMargin: 5
id: walletValueLabel id: walletValueLabel
} }
}
Label { Label {
y: 7
anchors.right: peerImage.left anchors.right: peerImage.left
anchors.rightMargin: 5 anchors.rightMargin: 5
id: peerLabel id: peerLabel
@ -328,11 +420,15 @@ ApplicationWindow {
text: "0 / 0" text: "0 / 0"
} }
Image { Image {
y: 7
id: peerImage id: peerImage
anchors.right: parent.right anchors.right: parent.right
width: 10; height: 10 width: 10; height: 10
source: ui.assetPath("network.png") MouseArea {
onDoubleClicked: peerWindow.visible = true
anchors.fill: parent
} }
source: ui.assetPath("network.png")
} }
} }
@ -340,16 +436,14 @@ ApplicationWindow {
id: popup id: popup
visible: false visible: false
property var block property var block
width: 800 width: root.width
height: 280 height: 300
x: root.x
y: root.y + root.height
Component{ Component{
id: blockDetailsDelegate id: blockDetailsDelegate
Rectangle { Rectangle {
color: "#252525" color: "#252525"
width: popup.width width: popup.width
height: 200 height: 150
Column { Column {
anchors.leftMargin: 10 anchors.leftMargin: 10
anchors.topMargin: 5 anchors.topMargin: 5
@ -358,7 +452,9 @@ ApplicationWindow {
Text { text: '<h3>Block details</h3>'; color: "#F2F2F2"} Text { text: '<h3>Block details</h3>'; color: "#F2F2F2"}
Text { text: '<b>Block number:</b> ' + number; color: "#F2F2F2"} Text { text: '<b>Block number:</b> ' + number; color: "#F2F2F2"}
Text { text: '<b>Hash:</b> ' + hash; 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>Block found at:</b> ' + prettyTime; color: "#F2F2F2"}
Text { text: '<b>Gas used:</b> ' + gasUsed + " / " + gasLimit; color: "#F2F2F2"}
} }
} }
} }
@ -366,7 +462,7 @@ ApplicationWindow {
model: singleBlock model: singleBlock
delegate: blockDetailsDelegate delegate: blockDetailsDelegate
anchors.top: parent.top anchors.top: parent.top
height: 70 height: 100
anchors.leftMargin: 20 anchors.leftMargin: 20
id: listViewThing id: listViewThing
Layout.maximumHeight: 40 Layout.maximumHeight: 40
@ -389,17 +485,27 @@ ApplicationWindow {
onClicked: { onClicked: {
var tx = transactionModel.get(row) var tx = transactionModel.get(row)
if(tx.data) { if(tx.data) {
popup.showContractData(tx.data) popup.showContractData(tx)
}else{ }else{
popup.height = 230 popup.height = 440
} }
} }
} }
function showContractData(data) {
contractData.text = data function showContractData(tx) {
popup.height = 400 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 { Rectangle {
id: txDetails
width: popup.width width: popup.width
height: 300 height: 300
anchors.left: listViewThing.left anchors.left: listViewThing.left
@ -411,11 +517,28 @@ ApplicationWindow {
id: contractLabel id: contractLabel
anchors.leftMargin: 10 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 { TextArea {
id: contractData id: contractData
text: "Contract" text: "Contract"
anchors.top: contractLabel.bottom anchors.top: contractLabel.bottom
anchors.left: parent.left anchors.left: parent.left
anchors.bottom: popup.bottom
wrapMode: Text.Wrap wrapMode: Text.Wrap
width: parent.width - 30 width: parent.width - 30
height: 80 height: 80
@ -430,14 +553,14 @@ ApplicationWindow {
} }
function setDetails(block){ function setDetails(block){
singleBlock.set(0,block) singleBlock.set(0,block)
popup.height = 230 popup.height = 300
transactionModel.clear() transactionModel.clear()
if(block.txs != undefined){ if(block.txs != undefined){
for(var i = 0; i < block.txs.count; ++i) { for(var i = 0; i < block.txs.count; ++i) {
transactionModel.insert(0, block.txs.get(i)) transactionModel.insert(0, block.txs.get(i))
} }
if(block.txs.get(0).data){ if(block.txs.get(0).data){
popup.showContractData(block.txs.get(0).data) popup.showContractData(block.txs.get(0))
} }
} }
txView.forceActiveFocus() txView.forceActiveFocus()
@ -504,126 +627,17 @@ ApplicationWindow {
font.pointSize: 12 font.pointSize: 12
text: "<h2>Ethereal</h2><br><h3>Development</h3>Jeffrey Wilcke<br>Maran Hidskes<br>" text: "<h2>Ethereal</h2><br><h3>Development</h3>Jeffrey Wilcke<br>Maran Hidskes<br>"
} }
} }
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){ function addDebugMessage(message){
console.log("WOOP:")
debuggerLog.append({value: message}) debuggerLog.append({value: message})
} }
function clearStack() { function addAddress(address) {
stackModel.clear() addressModel.append({name: address.name, address: address.address})
}
function clearAddress() {
addressModel.clear()
} }
function loadPlugin(name) { function loadPlugin(name) {
@ -642,7 +656,14 @@ ApplicationWindow {
}else{ }else{
isContract = "No" isContract = "No"
} }
txModel.insert(0, {inout: inout, 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, initial) { function addBlock(block, initial) {
@ -657,21 +678,46 @@ ApplicationWindow {
} }
if(initial){ if(initial){
blockModel.append({number: block.number, hash: block.hash, txs: txs, txAmount: amount, time: block.time, prettyTime: convertToPretty(block.time)}) 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{ }else{
blockModel.insert(0, {number: block.number, hash: block.hash, txs: txs, txAmount: amount, time: block.time, prettyTime: convertToPretty(block.time)}) 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) { function addLog(str) {
// Remove first item once we've reached max log items
if(logModel.count > 250) {
logModel.remove(0)
}
if(str.len != 0) { if(str.len != 0) {
if(logView.flickableItem.atYEnd) {
logModel.append({description: str})
logView.positionViewAtRow(logView.rowCount - 1, ListView.Contain)
} else {
logModel.append({description: str}) logModel.append({description: str})
} }
} }
}
function setPeers(text) { function setPeers(text) {
peerLabel.text = 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){ function convertToPretty(unixTs){
var a = new Date(unixTs*1000); var a = new Date(unixTs*1000);
var months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']; var months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
@ -684,6 +730,31 @@ ApplicationWindow {
var time = date+' '+month+' '+year+' '+hour+':'+min+':'+sec ; var time = date+' '+month+' '+year+' '+hour+':'+min+':'+sec ;
return time; 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 // Components
// ******************************************* // *******************************************
@ -693,6 +764,7 @@ ApplicationWindow {
id: newContract id: newContract
Column { Column {
id: mainContractColumn id: mainContractColumn
anchors.fill: parent
function contractFormReady(){ function contractFormReady(){
if(codeView.text.length > 0 && txValue.text.length > 0 && txGas.text.length > 0 && txGasPrice.length > 0) { if(codeView.text.length > 0 && txValue.text.length > 0 && txGas.text.length > 0 && txGasPrice.length > 0) {
txButton.state = "READY" txButton.state = "READY"
@ -714,6 +786,8 @@ ApplicationWindow {
PropertyChanges { target: codeView; visible:false} PropertyChanges { target: codeView; visible:false}
PropertyChanges { target: txButton; visible:false} PropertyChanges { target: txButton; visible:false}
PropertyChanges { target: txDataLabel; visible:false} PropertyChanges { target: txDataLabel; visible:false}
PropertyChanges { target: atLabel; visible:false}
PropertyChanges { target: txFuelRecipient; visible:false}
PropertyChanges { target: txResult; visible:true} PropertyChanges { target: txResult; visible:true}
PropertyChanges { target: txOutput; visible:true} PropertyChanges { target: txOutput; visible:true}
@ -740,82 +814,98 @@ ApplicationWindow {
anchors.leftMargin: 5 anchors.leftMargin: 5
anchors.topMargin: 5 anchors.topMargin: 5
ListModel {
id: denomModel
ListElement { text: "Wei" ; zeros: "" }
ListElement { text: "Ada" ; zeros: "000" }
ListElement { text: "Babbage" ; zeros: "000000" }
ListElement { text: "Shannon" ; zeros: "000000000" }
ListElement { text: "Szabo" ; zeros: "000000000000" }
ListElement { text: "Finney" ; zeros: "000000000000000" }
ListElement { text: "Ether" ; zeros: "000000000000000000" }
ListElement { text: "Einstein" ;zeros: "000000000000000000000" }
ListElement { text: "Douglas" ; zeros: "000000000000000000000000000000000000000000" }
}
TextField {
id: txFuelRecipient
placeholderText: "Address / Name or empty for contract"
//validator: RegExpValidator { regExp: /[a-f0-9]{40}/ }
width: 400
}
RowLayout {
TextField { TextField {
id: txValue id: txValue
width: 200 width: 222
placeholderText: "Amount" placeholderText: "Amount"
validator: RegExpValidator { regExp: /\d*/ } validator: RegExpValidator { regExp: /\d*/ }
onTextChanged: { onTextChanged: {
contractFormReady() contractFormReady()
} }
} }
ComboBox {
id: valueDenom
currentIndex: 6
model: denomModel
}
}
RowLayout {
TextField { TextField {
id: txGas id: txGas
width: 200 width: 50
validator: RegExpValidator { regExp: /\d*/ } validator: RegExpValidator { regExp: /\d*/ }
placeholderText: "Gas" placeholderText: "Gas"
text: "500"
/*
onTextChanged: { onTextChanged: {
contractFormReady() contractFormReady()
} }
*/
} }
Label {
id: atLabel
text: "@"
}
TextField { TextField {
id: txGasPrice id: txGasPrice
width: 200 width: 200
placeholderText: "Gas price" placeholderText: "Gas price"
text: "10"
validator: RegExpValidator { regExp: /\d*/ } validator: RegExpValidator { regExp: /\d*/ }
/*
onTextChanged: { onTextChanged: {
contractFormReady() contractFormReady()
} }
*/
} }
Row { ComboBox {
id: rowContract id: gasDenom
ExclusiveGroup { id: contractTypeGroup } currentIndex: 4
RadioButton { model: denomModel
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 { Label {
id: txDataLabel id: txDataLabel
text: "Contract code" text: "Data"
} }
TextArea { TextArea {
id: codeView id: codeView
height: 300 height: 300
anchors.topMargin: 5 anchors.topMargin: 5
Layout.fillWidth: true width: 400
width: parent.width /2
onTextChanged: { onTextChanged: {
contractFormReady() contractFormReady()
} }
} }
TextField {
id: txFuelRecipient
placeholderText: "Contract address"
validator: RegExpValidator { regExp: /[a-f0-9]{40}/ }
visible: false
width: 530
}
Button { Button {
id: txButton id: txButton
@ -832,8 +922,9 @@ ApplicationWindow {
] ]
text: "Send" text: "Send"
onClicked: { onClicked: {
//this.enabled = false var value = txValue.text + denomModel.get(valueDenom.currentIndex).zeros;
var res = eth.create(txFuelRecipient.text, txValue.text, txGas.text, txGasPrice.text, codeView.text) var gasPrice = txGasPrice.text + denomModel.get(gasDenom.currentIndex).zeros;
var res = eth.create(txFuelRecipient.text, value, txGas.text, gasPrice, codeView.text)
if(res[1]) { if(res[1]) {
txResult.text = "Your contract <b>could not</b> be send over the network:\n<b>" txResult.text = "Your contract <b>could not</b> be send over the network:\n<b>"
txResult.text += res[1].error() txResult.text += res[1].error()
@ -858,7 +949,7 @@ ApplicationWindow {
Button { Button {
id: newTxButton id: newTxButton
visible: false visible: false
text: "Create an other contract" text: "Create a new transaction"
onClicked: { onClicked: {
this.visible = false this.visible = false
txResult.text = "" txResult.text = ""
@ -866,18 +957,8 @@ ApplicationWindow {
mainContractColumn.state = "SETUP" 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 // New Transaction component
Component { Component {
id: newTransaction id: newTransaction
@ -923,7 +1004,7 @@ ApplicationWindow {
id: txSimpleRecipient id: txSimpleRecipient
placeholderText: "Recipient address" placeholderText: "Recipient address"
Layout.fillWidth: true Layout.fillWidth: true
validator: RegExpValidator { regExp: /[a-f0-9]{40}/ } //validator: RegExpValidator { regExp: /[a-f0-9]{40}/ }
width: 530 width: 530
onTextChanged: { checkFormState() } onTextChanged: { checkFormState() }
} }
@ -951,7 +1032,7 @@ ApplicationWindow {
text: "Send" text: "Send"
onClicked: { onClicked: {
//this.enabled = false //this.enabled = false
var res = eth.transact(txSimpleRecipient.text, txSimpleValue.text,"","","") var res = eth.transact(txSimpleRecipient.text, txSimpleValue.text, "500", "1000000", "")
if(res[1]) { if(res[1]) {
txSimpleResult.text = "There has been an error broadcasting your transaction:" + res[1].error() txSimpleResult.text = "There has been an error broadcasting your transaction:" + res[1].error()
} else { } else {
@ -983,5 +1064,4 @@ ApplicationWindow {
} }
} }
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

@ -26,7 +26,7 @@ func NewDebuggerWindow(lib *UiLib) *DebuggerWindow {
} }
win := component.CreateWindow(nil) win := component.CreateWindow(nil)
db := &Debugger{win, make(chan bool), make(chan bool), true} db := &Debugger{win, make(chan bool), make(chan bool), true, false}
return &DebuggerWindow{engine: engine, win: win, lib: lib, Db: db} return &DebuggerWindow{engine: engine, win: win, lib: lib, Db: db}
} }
@ -41,21 +41,18 @@ func (self *DebuggerWindow) Show() {
}() }()
} }
func formatData(data string) []byte { func (self *DebuggerWindow) SetCode(code string) {
if len(data) == 0 { self.win.Set("codeText", code)
return nil }
}
// Simple stupid
d := new(big.Int)
if data[0:1] == "\"" && data[len(data)-1:] == "\"" {
d.SetBytes([]byte(data[1 : len(data)-1]))
} else if data[:2] == "0x" {
d.SetBytes(ethutil.FromHex(data[2:]))
} else {
d.SetString(data, 0)
}
return ethutil.BigToBytes(d, 256) 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) { func (self *DebuggerWindow) Debug(valueStr, gasStr, gasPriceStr, scriptStr, dataStr string) {
@ -63,42 +60,53 @@ func (self *DebuggerWindow) Debug(valueStr, gasStr, gasPriceStr, scriptStr, data
self.Db.Q <- true self.Db.Q <- true
} }
dataSlice := strings.Split(dataStr, "\n")
var data []byte
for _, dataItem := range dataSlice {
d := formatData(dataItem)
data = append(data, d...)
}
state := self.lib.eth.BlockChain().CurrentBlock.State()
defer func() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
fmt.Println(r) self.Logf("compile FAULT: %v", r)
} }
}() }()
script, err := ethutil.Compile(scriptStr) 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 { if err != nil {
ethutil.Config.Log.Debugln(err) self.Logln(err)
return return
} }
dis := ethchain.Disassemble(script) dis := ethchain.Disassemble(script)
self.win.Root().Call("clearAsm") self.win.Root().Call("clearAsm")
self.win.Root().Call("clearLog")
for _, str := range dis { for _, str := range dis {
self.win.Root().Call("setAsm", str) self.win.Root().Call("setAsm", str)
} }
gas := ethutil.Big(gasStr)
gasPrice := ethutil.Big(gasPriceStr)
// Contract addr as test address // Contract addr as test address
keyPair := ethutil.GetKeyRing().Get(0) keyPair := ethutil.GetKeyRing().Get(0)
callerTx := ethchain.NewContractCreationTx(ethutil.Big(valueStr), ethutil.Big(gasStr), ethutil.Big(gasPriceStr), script) callerTx := ethchain.NewContractCreationTx(ethutil.Big(valueStr), gas, gasPrice, script)
callerTx.Sign(keyPair.PrivateKey) callerTx.Sign(keyPair.PrivateKey)
state := self.lib.eth.BlockChain().CurrentBlock.State()
account := self.lib.eth.StateManager().TransState().GetAccount(keyPair.Address()) account := self.lib.eth.StateManager().TransState().GetAccount(keyPair.Address())
contract := ethchain.MakeContract(callerTx, state) contract := ethchain.MakeContract(callerTx, state)
callerClosure := ethchain.NewClosure(account, contract, script, state, ethutil.Big(gasStr), ethutil.Big(gasPriceStr)) callerClosure := ethchain.NewClosure(account, contract, script, state, gas, gasPrice)
block := self.lib.eth.BlockChain().CurrentBlock block := self.lib.eth.BlockChain().CurrentBlock
vm := ethchain.NewVm(state, self.lib.eth.StateManager(), ethchain.RuntimeVars{ vm := ethchain.NewVm(state, self.lib.eth.StateManager(), ethchain.RuntimeVars{
@ -108,18 +116,44 @@ func (self *DebuggerWindow) Debug(valueStr, gasStr, gasPriceStr, scriptStr, data
Coinbase: block.Coinbase, Coinbase: block.Coinbase,
Time: block.Time, Time: block.Time,
Diff: block.Difficulty, Diff: block.Difficulty,
Value: ethutil.Big(valueStr),
}) })
self.Db.done = false self.Db.done = false
self.Logf("callsize %d", len(script))
go func() { go func() {
callerClosure.Call(vm, data, self.Db.halting) 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() state.Reset()
if !self.Db.interrupt {
self.Db.done = true 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() { func (self *DebuggerWindow) Next() {
self.Db.Next() self.Db.Next()
} }
@ -128,7 +162,7 @@ type Debugger struct {
win *qml.Window win *qml.Window
N chan bool N chan bool
Q chan bool Q chan bool
done bool done, interrupt bool
} }
type storeVal struct { type storeVal struct {
@ -161,7 +195,8 @@ out:
case <-d.N: case <-d.N:
break out break out
case <-d.Q: case <-d.Q:
d.done = true d.interrupt = true
d.clearBuffers()
return false return false
} }
@ -170,6 +205,19 @@ out:
return true return true
} }
func (d *Debugger) clearBuffers() {
out:
// drain
for {
select {
case <-d.N:
case <-d.Q:
default:
break out
}
}
}
func (d *Debugger) Next() { func (d *Debugger) Next() {
if !d.done { if !d.done {
d.N <- true d.N <- true

View File

@ -8,9 +8,11 @@ import (
"github.com/ethereum/eth-go/ethdb" "github.com/ethereum/eth-go/ethdb"
"github.com/ethereum/eth-go/ethpub" "github.com/ethereum/eth-go/ethpub"
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/go-ethereum/utils"
"github.com/go-qml/qml" "github.com/go-qml/qml"
"math/big" "math/big"
"strings" "strings"
"time"
) )
type Gui struct { type Gui struct {
@ -54,7 +56,7 @@ func New(ethereum *eth.Ethereum) *Gui {
} }
func (gui *Gui) Start(assetPath string) { func (gui *Gui) Start(assetPath string) {
const version = "0.5.0 RC10" const version = "0.5.0 RC13"
defer gui.txDb.Close() defer gui.txDb.Close()
@ -63,10 +65,12 @@ func (gui *Gui) Start(assetPath string) {
Init: func(p *ethpub.PBlock, obj qml.Object) { p.Number = 0; p.Hash = "" }, Init: func(p *ethpub.PBlock, obj qml.Object) { p.Number = 0; p.Hash = "" },
}, { }, {
Init: func(p *ethpub.PTx, obj qml.Object) { p.Value = ""; p.Hash = ""; p.Address = "" }, Init: func(p *ethpub.PTx, obj qml.Object) { p.Value = ""; p.Hash = ""; p.Address = "" },
}, {
Init: func(p *ethpub.KeyVal, obj qml.Object) { p.Key = ""; p.Value = "" },
}}) }})
ethutil.Config.SetClientString(fmt.Sprintf("/Ethereal v%s", version)) ethutil.Config.SetClientString("Ethereal")
ethutil.Config.Log.Infoln("[GUI] Starting GUI")
// Create a new QML engine // Create a new QML engine
gui.engine = qml.NewEngine() gui.engine = qml.NewEngine()
context := gui.engine.Context() context := gui.engine.Context()
@ -86,19 +90,36 @@ func (gui *Gui) Start(assetPath string) {
win, err = gui.showKeyImport(context) win, err = gui.showKeyImport(context)
} else { } else {
win, err = gui.showWallet(context) win, err = gui.showWallet(context)
ethutil.Config.Log.AddLogSystem(gui)
} }
if err != nil { if err != nil {
ethutil.Config.Log.Infoln("FATAL: asset not found: you can set an alternative asset path on on the command line using option 'asset_path'") ethutil.Config.Log.Infoln("FATAL: asset not found: you can set an alternative asset path on on the command line using option 'asset_path'", err)
panic(err) panic(err)
} }
ethutil.Config.Log.Infoln("[GUI] Starting GUI")
win.Show() win.Show()
win.Wait() win.Wait()
gui.eth.Stop() gui.eth.Stop()
} }
func (gui *Gui) ToggleMining() {
var txt string
if gui.eth.Mining {
utils.StopMining(gui.eth)
txt = "Start mining"
} else {
utils.StartMining(gui.eth)
txt = "Stop mining"
}
gui.win.Root().Set("miningButtonText", txt)
}
func (gui *Gui) showWallet(context *qml.Context) (*qml.Window, error) { func (gui *Gui) showWallet(context *qml.Context) (*qml.Window, error) {
component, err := gui.engine.LoadFile(gui.uiLib.AssetPath("qml/wallet.qml")) component, err := gui.engine.LoadFile(gui.uiLib.AssetPath("qml/wallet.qml"))
if err != nil { if err != nil {
@ -107,8 +128,11 @@ func (gui *Gui) showWallet(context *qml.Context) (*qml.Window, error) {
win := gui.createWindow(component) win := gui.createWindow(component)
go gui.setInitialBlockChain() gui.setInitialBlockChain()
go gui.readPreviousTransactions() gui.loadAddressBook()
gui.readPreviousTransactions()
gui.setPeerInfo()
go gui.update() go gui.update()
return win, nil return win, nil
@ -130,7 +154,7 @@ func (gui *Gui) createWindow(comp qml.Object) *qml.Window {
gui.win = win gui.win = win
gui.uiLib.win = win gui.uiLib.win = win
db := &Debugger{gui.win, make(chan bool), make(chan bool), true} db := &Debugger{gui.win, make(chan bool), make(chan bool), true, false}
gui.lib.Db = db gui.lib.Db = db
gui.uiLib.Db = db gui.uiLib.Db = db
@ -141,10 +165,37 @@ func (gui *Gui) setInitialBlockChain() {
blk := gui.eth.BlockChain().GetBlock(sBlk) blk := gui.eth.BlockChain().GetBlock(sBlk)
for ; blk != nil; blk = gui.eth.BlockChain().GetBlock(sBlk) { for ; blk != nil; blk = gui.eth.BlockChain().GetBlock(sBlk) {
sBlk = blk.PrevHash 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) gui.processBlock(blk, true)
} }
} }
type address struct {
Name, Address string
}
var namereg = ethutil.FromHex("bb5f186604d057c1c5240ca2ae0f6430138ac010")
func (gui *Gui) loadAddressBook() {
gui.win.Root().Call("clearAddress")
stateObject := gui.eth.StateManager().CurrentState().GetStateObject(namereg)
if stateObject != nil {
stateObject.State().EachStorage(func(name string, value *ethutil.Value) {
gui.win.Root().Call("addAddress", struct{ Name, Address string }{name, ethutil.Hex(value.Bytes())})
})
}
}
func (gui *Gui) readPreviousTransactions() { func (gui *Gui) readPreviousTransactions() {
it := gui.txDb.Db().NewIterator(nil, nil) it := gui.txDb.Db().NewIterator(nil, nil)
for it.Next() { for it.Next() {
@ -189,10 +240,16 @@ func (gui *Gui) update() {
blockChan := make(chan ethutil.React, 1) blockChan := make(chan ethutil.React, 1)
txChan := make(chan ethutil.React, 1) txChan := make(chan ethutil.React, 1)
objectChan := make(chan ethutil.React, 1)
peerChan := make(chan ethutil.React, 1)
reactor.Subscribe("newBlock", blockChan) reactor.Subscribe("newBlock", blockChan)
reactor.Subscribe("newTx:pre", txChan) reactor.Subscribe("newTx:pre", txChan)
reactor.Subscribe("newTx:post", txChan) reactor.Subscribe("newTx:post", txChan)
reactor.Subscribe("object:"+string(namereg), objectChan)
reactor.Subscribe("peerList", peerChan)
ticker := time.NewTicker(5 * time.Second)
state := gui.eth.StateManager().TransState() state := gui.eth.StateManager().TransState()
@ -239,10 +296,25 @@ func (gui *Gui) update() {
state.UpdateStateObject(object) state.UpdateStateObject(object)
} }
case <-objectChan:
gui.loadAddressBook()
case <-peerChan:
gui.setPeerInfo()
case <-ticker.C:
gui.setPeerInfo()
} }
} }
} }
func (gui *Gui) setPeerInfo() {
gui.win.Root().Call("setPeers", fmt.Sprintf("%d / %d", gui.eth.PeerCount(), gui.eth.MaxPeers))
gui.win.Root().Call("resetPeers")
for _, peer := range gui.pub.GetPeers() {
gui.win.Root().Call("addPeer", peer)
}
}
// Logging functions that log directly to the GUI interface // Logging functions that log directly to the GUI interface
func (gui *Gui) Println(v ...interface{}) { func (gui *Gui) Println(v ...interface{}) {
str := strings.TrimRight(fmt.Sprintln(v...), "\n") str := strings.TrimRight(fmt.Sprintln(v...), "\n")
@ -259,6 +331,11 @@ func (gui *Gui) Printf(format string, v ...interface{}) {
gui.win.Root().Call("addLog", line) gui.win.Root().Call("addLog", line)
} }
} }
func (gui *Gui) RegisterName(name string) {
keyPair := ethutil.GetKeyRing().Get(0)
name = fmt.Sprintf("\"%s\"\n1", name)
gui.pub.Transact(ethutil.Hex(keyPair.PrivateKey), "namereg", "1000", "1000000", "150", name)
}
func (gui *Gui) Transact(recipient, value, gas, gasPrice, data string) (*ethpub.PReceipt, error) { func (gui *Gui) Transact(recipient, value, gas, gasPrice, data string) (*ethpub.PReceipt, error) {
keyPair := ethutil.GetKeyRing().Get(0) keyPair := ethutil.GetKeyRing().Get(0)
@ -269,5 +346,17 @@ func (gui *Gui) Transact(recipient, value, gas, gasPrice, data string) (*ethpub.
func (gui *Gui) Create(recipient, value, gas, gasPrice, data string) (*ethpub.PReceipt, error) { func (gui *Gui) Create(recipient, value, gas, gasPrice, data string) (*ethpub.PReceipt, error) {
keyPair := ethutil.GetKeyRing().Get(0) keyPair := ethutil.GetKeyRing().Get(0)
return gui.pub.Create(ethutil.Hex(keyPair.PrivateKey), value, gas, gasPrice, data) return gui.pub.Transact(ethutil.Hex(keyPair.PrivateKey), recipient, value, gas, gasPrice, data)
}
func (gui *Gui) ChangeClientId(id string) {
ethutil.Config.SetIdentifier(id)
}
func (gui *Gui) ClientId() string {
return ethutil.Config.Identifier
}
func (gui *Gui) SetLogLevel(level int) {
ethutil.Config.Log.SetLevel(level)
} }

View File

@ -26,6 +26,7 @@ type UiLib struct {
// The main application window // The main application window
win *qml.Window win *qml.Window
Db *Debugger Db *Debugger
DbWindow *DebuggerWindow
} }
func NewUiLib(engine *qml.Engine, eth *eth.Ethereum, assetPath string) *UiLib { func NewUiLib(engine *qml.Engine, eth *eth.Ethereum, assetPath string) *UiLib {
@ -88,9 +89,26 @@ func (ui *UiLib) ConnectToPeer(addr string) {
func (ui *UiLib) AssetPath(p string) string { func (ui *UiLib) AssetPath(p string) string {
return path.Join(ui.assetPath, p) return path.Join(ui.assetPath, p)
} }
func (self *UiLib) StartDbWithContractAndData(contractHash, data string) {
dbWindow := NewDebuggerWindow(self)
object := self.eth.StateManager().CurrentState().GetStateObject(ethutil.FromHex(contractHash))
if len(object.Script()) > 0 {
dbWindow.SetCode("0x" + ethutil.Hex(object.Script()))
}
dbWindow.SetData("0x" + data)
dbWindow.Show()
}
func (self *UiLib) StartDbWithCode(code string) {
dbWindow := NewDebuggerWindow(self)
dbWindow.SetCode("0x" + code)
dbWindow.Show()
}
func (self *UiLib) StartDebugger() { func (self *UiLib) StartDebugger() {
dbWindow := NewDebuggerWindow(self) dbWindow := NewDebuggerWindow(self)
//self.DbWindow = dbWindow
dbWindow.Show() dbWindow.Show()
} }

View File

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

View File

@ -3,13 +3,14 @@ package main
import ( import (
"fmt" "fmt"
"github.com/ethereum/eth-go" "github.com/ethereum/eth-go"
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/go-ethereum/utils" "github.com/ethereum/go-ethereum/utils"
"github.com/rakyll/globalconf"
"io/ioutil" "io/ioutil"
"log" "log"
"os" "os"
"os/signal" "os/signal"
"path"
"runtime" "runtime"
"strings" "strings"
) )
@ -59,7 +60,15 @@ func main() {
lt = ethutil.LogFile | ethutil.LogStd lt = ethutil.LogFile | ethutil.LogStd
} }
ethutil.ReadConfig(DataDir, lt, Identifier) g, err := globalconf.NewWithOptions(&globalconf.Options{
Filename: path.Join(ethutil.ApplicationFolder(Datadir), "conf.ini"),
})
if err != nil {
fmt.Println(err)
} else {
g.ParseAll()
}
ethutil.ReadConfig(Datadir, lt, g, Identifier)
logger := ethutil.Config.Log logger := ethutil.Config.Log
@ -76,8 +85,6 @@ func main() {
logSys = log.New(os.Stdout, "", flags) logSys = log.New(os.Stdout, "", flags)
} }
ethchain.InitFees()
// Instantiated a eth stack // Instantiated a eth stack
ethereum, err := eth.New(eth.CapDefault, UseUPnP) ethereum, err := eth.New(eth.CapDefault, UseUPnP)
if err != nil { if err != nil {

View File

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

View File

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

View File

@ -33,8 +33,6 @@ func DoMining(ethereum *eth.Ethereum) {
addr := keyPair.Address() addr := keyPair.Address()
go func() { go func() {
ethutil.Config.Log.Infoln("Miner started")
miner = ethminer.NewDefaultMiner(addr, ethereum) miner = ethminer.NewDefaultMiner(addr, ethereum)
// Give it some time to connect with peers // Give it some time to connect with peers