aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ethereal/assets/back.pngbin0 -> 1004 bytes
-rw-r--r--ethereal/assets/bug.pngbin0 -> 1671 bytes
-rw-r--r--ethereal/assets/close.pngbin0 -> 905 bytes
-rw-r--r--ethereal/assets/ext/ethereum.js162
-rw-r--r--ethereal/assets/ext/home.html5
-rw-r--r--ethereal/assets/ext/messaging.js117
-rw-r--r--ethereal/assets/ext/pre.js21
-rw-r--r--ethereal/assets/ext/test.html33
-rw-r--r--ethereal/assets/pick.pngbin0 -> 932 bytes
-rw-r--r--ethereal/assets/qml/views/history.qml2
-rw-r--r--ethereal/assets/qml/views/info.qml27
-rw-r--r--ethereal/assets/qml/views/javascript.qml45
-rw-r--r--ethereal/assets/qml/views/pending_tx.qml2
-rw-r--r--ethereal/assets/qml/views/transaction.qml17
-rw-r--r--ethereal/assets/qml/wallet.qml104
-rw-r--r--ethereal/assets/qml/webapp.qml205
-rw-r--r--ethereal/ext_app.go51
-rw-r--r--ethereal/gui.go26
-rw-r--r--ethereal/html_container.go13
-rw-r--r--ethereal/main.go3
-rw-r--r--ethereal/qml_container.go8
-rw-r--r--ethereal/ui_lib.go10
-rw-r--r--javascript/javascript_runtime.go2
-rw-r--r--javascript/types.go24
-rw-r--r--utils/cmd.go21
25 files changed, 571 insertions, 327 deletions
diff --git a/ethereal/assets/back.png b/ethereal/assets/back.png
new file mode 100644
index 000000000..38fc84d6e
--- /dev/null
+++ b/ethereal/assets/back.png
Binary files differ
diff --git a/ethereal/assets/bug.png b/ethereal/assets/bug.png
new file mode 100644
index 000000000..f5e85dc99
--- /dev/null
+++ b/ethereal/assets/bug.png
Binary files differ
diff --git a/ethereal/assets/close.png b/ethereal/assets/close.png
new file mode 100644
index 000000000..88df442c5
--- /dev/null
+++ b/ethereal/assets/close.png
Binary files differ
diff --git a/ethereal/assets/ext/ethereum.js b/ethereal/assets/ext/ethereum.js
index de6fb0255..03b25179b 100644
--- a/ethereal/assets/ext/ethereum.js
+++ b/ethereal/assets/ext/ethereum.js
@@ -1,39 +1,112 @@
// Main Ethereum library
window.eth = {
prototype: Object(),
+ _callbacks: {},
+ _onCallbacks: {},
+
+ mutan: function(code) {
+ },
+
+ toHex: function(str) {
+ var hex = "";
+ for(var i = 0; i < str.length; i++) {
+ var n = str.charCodeAt(i).toString(16);
+ hex += n.length < 2 ? '0' + n : n;
+ }
+
+ return hex;
+ },
+
+ toAscii: function(hex) {
+ // Find termination
+ var str = "";
+ var i = 0, l = hex.length;
+ for(; i < l; i+=2) {
+ var code = hex.charCodeAt(i)
+ if(code == 0) {
+ break;
+ }
+
+ str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
+ }
+
+ return str;
+ },
+
+ fromAscii: function(str, pad) {
+ if(pad === undefined) {
+ pad = 32
+ }
+
+ var hex = this.toHex(str);
+
+ while(hex.length < pad*2)
+ hex += "00";
+
+ return hex
+ },
+
// Retrieve block
//
// Either supply a number or a string. Type is determent for the lookup method
// string - Retrieves the block by looking up the hash
// number - Retrieves the block by looking up the block number
- getBlock: function(numberOrHash, cb) {
- var func;
- if(typeof numberOrHash == "string") {
- func = "getBlockByHash";
- } else {
- func = "getBlockByNumber";
- }
- postData({call: func, args: [numberOrHash]}, cb);
- },
+ getBlock: function(numberOrHash, cb) {
+ var func;
+ if(typeof numberOrHash == "string") {
+ func = "getBlockByHash";
+ } else {
+ func = "getBlockByNumber";
+ }
+ postData({call: func, args: [numberOrHash]}, cb);
+ },
// Create transaction
//
// Transact between two state objects
- transact: function(sec, recipient, value, gas, gasPrice, data, cb) {
- postData({call: "transact", args: [sec, recipient, value, gas, gasPrice, data]}, cb);
+ transact: function(params, cb) {
+ if(params === undefined) {
+ params = {};
+ }
+
+ if(params.endowment !== undefined)
+ params.value = params.endowment;
+ if(params.code !== undefined)
+ params.data = params.code;
+
+ // Make sure everything is string
+ var fields = ["to", "from", "value", "gas", "gasPrice"];
+ for(var i = 0; i < fields.length; i++) {
+ if(params[fields[i]] === undefined) {
+ params[fields[i]] = "";
+ }
+ params[fields[i]] = params[fields[i]].toString();
+ }
+
+ var data;
+ if(typeof params.data === "object") {
+ data = "";
+ for(var i = 0; i < params.data.length; i++) {
+ data += params.data[i]
+ }
+ } else {
+ data = params.data;
+ }
+
+ postData({call: "transact", args: [params.from, params.to, params.value, params.gas, params.gasPrice, "0x"+data]}, cb);
},
- create: function(sec, value, gas, gasPrice, init, body, cb) {
- postData({call: "create", args: [sec, value, gas, gasPrice, init, body]}, cb);
+ getMessages: function(filter, cb) {
+ postData({call: "messages", args: [filter]}, cb);
},
getStorageAt: function(address, storageAddress, cb) {
postData({call: "getStorage", args: [address, storageAddress]}, cb);
},
- getStateKeyVals: function(address, cb){
- postData({call: "getStateKeyVals", args: [address]}, cb);
+ getEachStorageAt: function(address, cb){
+ postData({call: "getEachStorage", args: [address]}, cb);
},
getKey: function(cb) {
@@ -66,6 +139,7 @@ window.eth = {
postData({call: "getSecretToAddress", args: [sec]}, cb);
},
+ /*
watch: function(address, storageAddrOrCb, cb) {
var ev;
if(cb === undefined) {
@@ -95,6 +169,16 @@ window.eth = {
postData({call: "disconnect", args: [address, storageAddrOrCb]});
},
+ */
+
+ watch: function(options) {
+ var filter = new Filter(options);
+ filter.number = newWatchNum().toString()
+
+ postData({call: "watch", args: [options, filter.number]})
+
+ return filter;
+ },
set: function(props) {
postData({call: "set", args: props});
@@ -137,9 +221,53 @@ window.eth = {
}
}
},
+}
+var Filter = function(options) {
+ this.options = options;
+};
+Filter.prototype.changed = function(callback) {
+ // Register the watched:<number>. Qml will call the appropriate event if anything
+ // interesting happens in the land of Go.
+ eth.on("watched:"+this.number, callback)
}
-window.eth._callbacks = {}
-window.eth._onCallbacks = {}
+Filter.prototype.getMessages = function(cb) {
+ return eth.getMessages(this.options, cb)
+}
+
+var watchNum = 0;
+function newWatchNum() {
+ return watchNum++;
+}
+
+function postData(data, cb) {
+ data._seed = Math.floor(Math.random() * 1000000)
+ if(cb) {
+ eth._callbacks[data._seed] = cb;
+ }
+
+ if(data.args === undefined) {
+ data.args = [];
+ }
+
+ navigator.qt.postMessage(JSON.stringify(data));
+}
+
+navigator.qt.onmessage = function(ev) {
+ var data = JSON.parse(ev.data)
+
+ if(data._event !== undefined) {
+ eth.trigger(data._event, data.data);
+ } else {
+ if(data._seed) {
+ var cb = eth._callbacks[data._seed];
+ if(cb) {
+ cb.call(this, data.data)
+ // Remove the "trigger" callback
+ delete eth._callbacks[ev._seed];
+ }
+ }
+ }
+}
diff --git a/ethereal/assets/ext/home.html b/ethereal/assets/ext/home.html
index 86a659d65..a524e8403 100644
--- a/ethereal/assets/ext/home.html
+++ b/ethereal/assets/ext/home.html
@@ -8,14 +8,15 @@ h1 {
text-align: center;
font-family: Courier;
font-size: 50pt;
- margin-top: 25%
}
</style>
</head>
<body>
<h1>... Ethereum ...</h1>
-<!-- ĐΞV --!>
+<ul>
+ <li><a href="http://std.eth">std::Service</a></li>
+</ul>
</body>
</html>
diff --git a/ethereal/assets/ext/messaging.js b/ethereal/assets/ext/messaging.js
deleted file mode 100644
index e7bc63020..000000000
--- a/ethereal/assets/ext/messaging.js
+++ /dev/null
@@ -1,117 +0,0 @@
-function handleMessage(message) {
- console.log("[onMessageReceived]: ", message.data)
- // TODO move to messaging.js
- var data = JSON.parse(message.data)
-
- try {
- switch(data.call) {
- case "getCoinBase":
- postData(data._seed, eth.getCoinBase())
-
- break
- case "getIsListening":
- postData(data._seed, eth.getIsListening())
-
- break
- case "getIsMining":
- postData(data._seed, eth.getIsMining())
-
- break
- case "getPeerCount":
- postData(data._seed, eth.getPeerCount())
-
- break
-
- case "getTxCountAt":
- require(1)
- postData(data._seed, eth.getTxCountAt(data.args[0]))
-
- break
- case "getBlockByNumber":
- var block = eth.getBlock(data.args[0])
- postData(data._seed, block)
-
- break
- case "getBlockByHash":
- var block = eth.getBlock(data.args[0])
- postData(data._seed, block)
-
- break
- case "transact":
- require(5)
-
- var tx = eth.transact(data.args[0], data.args[1], data.args[2],data.args[3],data.args[4],data.args[5])
- postData(data._seed, tx)
-
- break
- case "create":
- postData(data._seed, null)
-
- break
- case "getStorage":
- require(2);
-
- var stateObject = eth.getStateObject(data.args[0])
- var storage = stateObject.getStorage(data.args[1])
- postData(data._seed, storage)
-
- break
- case "getStateKeyVals":
- require(1);
- var stateObject = eth.getStateObject(data.args[0]).stateKeyVal(true)
- postData(data._seed,stateObject)
-
- break
- case "getTransactionsFor":
- require(1);
- var txs = eth.getTransactionsFor(data.args[0], true)
- postData(data._seed, txs)
-
- break
- case "getBalance":
- require(1);
-
- postData(data._seed, eth.getStateObject(data.args[0]).value());
-
- break
- case "getKey":
- var key = eth.getKey().privateKey;
-
- postData(data._seed, key)
- break
- case "watch":
- require(1)
- eth.watch(data.args[0], data.args[1]);
- break
- case "disconnect":
- require(1)
- postData(data._seed, null)
- break;
- case "set":
- console.log("'Set' has been depcrecated")
- /*
- for(var key in data.args) {
- if(webview.hasOwnProperty(key)) {
- window[key] = data.args[key];
- }
- }
- */
- break;
- case "getSecretToAddress":
- require(1)
- postData(data._seed, eth.secretToAddress(data.args[0]))
- break;
- case "debug":
- console.log(data.args[0]);
- break;
- }
- } catch(e) {
- console.log(data.call + ": " + e)
-
- postData(data._seed, null);
- }
-}
-
-function postData(seed, data) {
- webview.experimental.postMessage(JSON.stringify({data: data, _seed: seed}))
-}
diff --git a/ethereal/assets/ext/pre.js b/ethereal/assets/ext/pre.js
index ca520f152..3e8a534e9 100644
--- a/ethereal/assets/ext/pre.js
+++ b/ethereal/assets/ext/pre.js
@@ -1,18 +1,3 @@
-function debug(/**/) {
- var args = arguments;
- var msg = ""
- for(var i = 0; i < args.length; i++){
- if(typeof args[i] === "object") {
- msg += " " + JSON.stringify(args[i])
- } else {
- msg += " " + args[i]
- }
- }
-
- postData({call:"debug", args:[msg]})
- document.getElementById("debug").innerHTML += "<br>" + msg
-}
-
// Helper function for generating pseudo callbacks and sending data to the QML part of the application
function postData(data, cb) {
data._seed = Math.floor(Math.random() * 1000000)
@@ -50,9 +35,3 @@ navigator.qt.onmessage = function(ev) {
}
}
}
-
-window.onerror = function(message, file, lineNumber, column, errorObj) {
- debug(file, message, lineNumber+":"+column, errorObj);
-
- return false;
-}
diff --git a/ethereal/assets/ext/test.html b/ethereal/assets/ext/test.html
new file mode 100644
index 000000000..0d6b710fa
--- /dev/null
+++ b/ethereal/assets/ext/test.html
@@ -0,0 +1,33 @@
+<!doctype>
+<html>
+<head>
+<title>Tests</title>
+</head>
+
+<body>
+<button onclick="test();">Test me</button>
+
+<script type="text/javascript">
+function test() {
+ var filter = eth.watch({
+ latest: -1,
+ from: "e6716f9544a56c530d868e4bfbacb172315bdead",
+ });
+
+ filter.changed(function(messages) {
+ console.log("messages", messages)
+ })
+
+ filter.getMessages(function(messages) {
+ console.log("getMessages", messages)
+ });
+
+ eth.getEachStorageAt("9ef0f0d81e040012600b0c1abdef7c48f720f88a", function(a, b) {
+ console.log(a,b)
+ })
+}
+</script>
+
+</body>
+
+</html>
diff --git a/ethereal/assets/pick.png b/ethereal/assets/pick.png
new file mode 100644
index 000000000..2f5a261c2
--- /dev/null
+++ b/ethereal/assets/pick.png
Binary files differ
diff --git a/ethereal/assets/qml/views/history.qml b/ethereal/assets/qml/views/history.qml
index f50ae8004..a73b7367d 100644
--- a/ethereal/assets/qml/views/history.qml
+++ b/ethereal/assets/qml/views/history.qml
@@ -29,7 +29,7 @@ Rectangle {
model: txModel
}
- function addTx(type, tx, inout) {
+ function addTx(tx, inout) {
var isContract
if (tx.contract == true){
isContract = "Yes"
diff --git a/ethereal/assets/qml/views/info.qml b/ethereal/assets/qml/views/info.qml
index 9e05e2f8e..fcddd46e2 100644
--- a/ethereal/assets/qml/views/info.qml
+++ b/ethereal/assets/qml/views/info.qml
@@ -17,6 +17,7 @@ Rectangle {
color: "#00000000"
Column {
+ id: info
spacing: 3
anchors.fill: parent
anchors.topMargin: 5
@@ -49,7 +50,7 @@ Rectangle {
}
TableView {
id: addressView
- width: parent.width - 200
+ width: parent.width
height: 200
anchors.bottom: logLayout.top
TableViewColumn{ role: "name"; title: "name" }
@@ -58,30 +59,6 @@ Rectangle {
model: addressModel
}
- Rectangle {
- anchors.top: addressView.top
- anchors.left: addressView.right
- anchors.leftMargin: 20
-
- TextField {
- placeholderText: "Name to register"
- id: nameToReg
- width: 150
- }
-
- Button {
- anchors.top: nameToReg.bottom
- text: "Register"
- MouseArea{
- anchors.fill: parent
- onClicked: {
- gui.registerName(nameToReg.text)
- nameToReg.text = ""
- }
- }
- }
- }
-
property var logModel: ListModel {
id: logModel
}
diff --git a/ethereal/assets/qml/views/javascript.qml b/ethereal/assets/qml/views/javascript.qml
new file mode 100644
index 000000000..376397130
--- /dev/null
+++ b/ethereal/assets/qml/views/javascript.qml
@@ -0,0 +1,45 @@
+import QtQuick 2.0
+import QtQuick.Controls 1.0;
+import QtQuick.Layouts 1.0;
+import QtQuick.Dialogs 1.0;
+import QtQuick.Window 2.1;
+import QtQuick.Controls.Styles 1.1
+import Ethereum 1.0
+
+Rectangle {
+ property var title: "JavaScript"
+ property var iconFile: "../tx.png"
+
+ objectName: "javascriptView"
+ visible: false
+ anchors.fill: parent
+
+ TextField {
+ id: input
+ anchors {
+ left: parent.left
+ right: parent.right
+ bottom: parent.bottom
+ }
+ height: 20
+
+ Keys.onReturnPressed: {
+ var res = eth.evalJavascriptString(this.text);
+ this.text = "";
+
+ output.append(res)
+ }
+ }
+
+ TextArea {
+ id: output
+ verticalAlignment: TextEdit.AlignBottom
+ text: "> JSRE Ready..."
+ anchors {
+ top: parent.top
+ left: parent.left
+ right: parent.right
+ bottom: input.top
+ }
+ }
+}
diff --git a/ethereal/assets/qml/views/pending_tx.qml b/ethereal/assets/qml/views/pending_tx.qml
index 18572e3e2..5c5c496d6 100644
--- a/ethereal/assets/qml/views/pending_tx.qml
+++ b/ethereal/assets/qml/views/pending_tx.qml
@@ -30,7 +30,7 @@ Rectangle {
model: pendingTxModel
}
- function addTx(type, tx, inout) {
+ function addTx(tx, inout) {
var isContract
if (tx.contract == true){
isContract = "Yes"
diff --git a/ethereal/assets/qml/views/transaction.qml b/ethereal/assets/qml/views/transaction.qml
index 61a1b81cd..80e1670f8 100644
--- a/ethereal/assets/qml/views/transaction.qml
+++ b/ethereal/assets/qml/views/transaction.qml
@@ -18,13 +18,8 @@ Rectangle {
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"
@@ -208,4 +203,12 @@ Rectangle {
}
}
}
+
+ 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"
+ }
+ }
}
diff --git a/ethereal/assets/qml/wallet.qml b/ethereal/assets/qml/wallet.qml
index 58d39381b..b35500209 100644
--- a/ethereal/assets/qml/wallet.qml
+++ b/ethereal/assets/qml/wallet.qml
@@ -19,11 +19,12 @@ ApplicationWindow {
// Takes care of loading all default plugins
Component.onCompleted: {
- var historyView = addPlugin("./views/history.qml")
- var newTxView = addPlugin("./views/transaction.qml")
- var chainView = addPlugin("./views/chain.qml")
- var infoView = addPlugin("./views/info.qml")
- var pendingTxView = addPlugin("./views/pending_tx.qml")
+ var historyView = addPlugin("./views/history.qml", {title: "History"})
+ var newTxView = addPlugin("./views/transaction.qml", {title: "New Transaction"})
+ var chainView = addPlugin("./views/chain.qml", {title: "Block chain"})
+ var infoView = addPlugin("./views/info.qml", {title: "Info"})
+ var pendingTxView = addPlugin("./views/pending_tx.qml", {title: "Pending", canClose: true})
+ var pendingTxView = addPlugin("./views/javascript.qml", {title: "JavaScript", canClose: true})
// Call the ready handler
gui.done()
@@ -38,7 +39,7 @@ ApplicationWindow {
return
}
- return mainSplit.addComponent(component, {objectName: objectName})
+ return mainSplit.addComponent(component, options)
}
MenuBar {
@@ -97,7 +98,7 @@ ApplicationWindow {
MenuItem {
text: "Debugger"
shortcut: "Ctrl+d"
- onTriggered: ui.startDebugger()
+ onTriggered: eth.startDebugger()
}
MenuItem {
@@ -111,7 +112,7 @@ ApplicationWindow {
text: "Run JS file"
onTriggered: {
generalFileDialog.callback = function(path) {
- lib.evalJavascriptFile(path)
+ eth.evalJavascriptFile(path)
}
generalFileDialog.open()
}
@@ -169,8 +170,6 @@ ApplicationWindow {
RowLayout {
Label {
- anchors.left: importAppButton.right
- anchors.leftMargin: 5
id: walletValueLabel
font.pixelSize: 10
@@ -250,7 +249,7 @@ ApplicationWindow {
return;
}
- menu.createMenuItem(view.iconFile, view);
+ menu.createMenuItem(view.iconFile, view, options);
mainSplit.views.push(view);
return view
@@ -280,11 +279,82 @@ ApplicationWindow {
}
}
+ /*
+ Component {
+ id: menuItemTemplate
+
+ RowLayout {
+ property var view;
+ property alias source: icon.source;
+ property alias title: title.text
+ height: 25
+
+ id: tab
+
+ anchors {
+ left: parent.left
+ right: parent.right
+ }
+
+ Image {
+ id: icon
+ //anchors.horizontalCenter: parent.horizontalCenter
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ mainSplit.setView(view)
+ }
+ }
+
+ Rectangle {
+ color: "#bbbbbb"
+ Label {
+ id: title
+ y: parent.height / 2 - this.height / 2
+ //x: 5
+ font.pixelSize: 10
+ }
+
+
+ Image {
+ id: closeButton
+ y: parent.height / 2 - this.height / 2
+ visible: false
+
+ source: "../close.png"
+ anchors {
+ right: parent.right
+ rightMargin: 5
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ console.log("should close")
+ }
+ }
+ }
+ }
+ }
+ }
+ */
+
+ function createMenuItem(icon, view, options) {
+ if(options === undefined) {
+ options = {};
+ }
- function createMenuItem(icon, view) {
var comp = menuItemTemplate.createObject(menuColumn)
comp.view = view
comp.source = icon
+ //comp.title = options.title
+ /*
+ if(options.canClose) {
+ //comp.closeButton.visible = options.canClose
+ }
+ */
}
ColumnLayout {
@@ -338,9 +408,9 @@ ApplicationWindow {
function importApp(path) {
var ext = path.split('.').pop()
if(ext == "html" || ext == "htm") {
- ui.openHtml(path)
+ eth.openHtml(path)
}else if(ext == "qml"){
- ui.openQml(path)
+ eth.openQml(path)
}
}
@@ -459,7 +529,7 @@ ApplicationWindow {
anchors.leftMargin: 5
text: "Import"
onClicked: {
- lib.importTx(txImportField.text)
+ eth.importTx(txImportField.text)
txImportField.visible = false
}
}
@@ -483,7 +553,7 @@ ApplicationWindow {
anchors.leftMargin: 10
placeholderText: "address:port"
onAccepted: {
- ui.connectToPeer(addrField.text)
+ eth.connectToPeer(addrField.text)
addPeerWin.visible = false
}
}
@@ -493,7 +563,7 @@ ApplicationWindow {
anchors.leftMargin: 5
text: "Add"
onClicked: {
- ui.connectToPeer(addrField.text)
+ eth.connectToPeer(addrField.text)
addPeerWin.visible = false
}
}
diff --git a/ethereal/assets/qml/webapp.qml b/ethereal/assets/qml/webapp.qml
index 15177e3fd..5faf50e91 100644
--- a/ethereal/assets/qml/webapp.qml
+++ b/ethereal/assets/qml/webapp.qml
@@ -2,6 +2,7 @@ import QtQuick 2.0
import QtWebKit 3.0
import QtWebKit.experimental 1.0
import QtQuick.Controls 1.0;
+import QtQuick.Controls.Styles 1.0
import QtQuick.Layouts 1.0;
import QtQuick.Window 2.1;
import Ethereum 1.0
@@ -9,8 +10,8 @@ import Ethereum 1.0
ApplicationWindow {
id: window
title: "Ethereum"
- width: 900
- height: 600
+ width: 1000
+ height: 800
minimumHeight: 300
property alias url: webview.url
@@ -21,42 +22,59 @@ ApplicationWindow {
id: root
anchors.fill: parent
state: "inspectorShown"
- TextField {
+
+ RowLayout {
+ id: navBar
+ height: 40
anchors {
- top: parent.top
left: parent.left
right: parent.right
+ leftMargin: 7
+ }
+
+ Button {
+ id: back
+ onClicked: {
+ webview.goBack()
+ }
+ style: ButtonStyle {
+ background: Image {
+ source: "../back.png"
+ width: 30
+ height: 30
+ }
+ }
}
- id: uriNav
- //text: webview.url
-
- Keys.onReturnPressed: {
- var reg = /(^https?\:\/\/(?:www\.)?)([a-zA-Z0-9_\-]*\.eth)(.*)/
-
- var uri = this.text;
- if(reg.test(uri)) {
- this.text.replace(reg, function(match, pre, domain, path) {
- uri = pre;
-
- var lookup = eth.lookupDomain(domain.substring(0, domain.length - 4));
- var ip = [];
- for(var i = 0, l = lookup.length; i < l; i++) {
- ip.push(lookup.charCodeAt(i))
- }
-
- if(ip.length != 0) {
- uri += ip.join(".");
- } else {
- uri += domain;
- }
-
- uri += path;
- });
+
+ TextField {
+ anchors {
+ left: back.right
+ right: toggleInspector.left
+ leftMargin: 5
+ rightMargin: 5
}
+ id: uriNav
+ y: parent.height / 2 - this.height / 2
- console.log("connecting to ...", uri)
+ Keys.onReturnPressed: {
+ webview.url = this.text;
+ }
+ }
- webview.url = uri;
+ Button {
+ id: toggleInspector
+ anchors {
+ right: parent.right
+ }
+ iconSource: "../bug.png"
+ onClicked: {
+ if(inspector.visible == true){
+ inspector.visible = false
+ }else{
+ inspector.visible = true
+ inspector.url = webview.experimental.remoteInspectorUrl
+ }
+ }
}
}
@@ -67,9 +85,48 @@ ApplicationWindow {
left: parent.left
right: parent.right
bottom: parent.bottom
- top: uriNav.bottom
+ top: navBar.bottom
}
onTitleChanged: { window.title = title }
+
+ property var cleanPath: false
+ onNavigationRequested: {
+ if(!this.cleanPath) {
+ var uri = request.url.toString();
+ if(!/.*\:\/\/.*/.test(uri)) {
+ uri = "http://" + uri;
+ }
+
+ var reg = /(^https?\:\/\/(?:www\.)?)([a-zA-Z0-9_\-]*\.eth)(.*)/
+
+ if(reg.test(uri)) {
+ uri.replace(reg, function(match, pre, domain, path) {
+ uri = pre;
+
+ var lookup = eth.lookupDomain(domain.substring(0, domain.length - 4));
+ var ip = [];
+ for(var i = 0, l = lookup.length; i < l; i++) {
+ ip.push(lookup.charCodeAt(i))
+ }
+
+ if(ip.length != 0) {
+ uri += lookup;
+ } else {
+ uri += domain;
+ }
+
+ uri += path;
+ });
+ }
+
+ this.cleanPath = true;
+
+ webview.url = uri;
+ } else {
+ // Prevent inf loop.
+ this.cleanPath = false;
+ }
+ }
experimental.preferences.javascriptEnabled: true
experimental.preferences.navigatorQtObjectEnabled: true
experimental.preferences.developerExtrasEnabled: true
@@ -85,14 +142,17 @@ ApplicationWindow {
postData(data._seed, eth.getCoinBase())
break
+
case "getIsListening":
postData(data._seed, eth.getIsListening())
break
+
case "getIsMining":
postData(data._seed, eth.getIsMining())
break
+
case "getPeerCount":
postData(data._seed, eth.getPeerCount())
@@ -103,16 +163,19 @@ ApplicationWindow {
postData(data._seed, eth.getTxCountAt(data.args[0]))
break
+
case "getBlockByNumber":
var block = eth.getBlock(data.args[0])
postData(data._seed, block)
break
+
case "getBlockByHash":
var block = eth.getBlock(data.args[0])
postData(data._seed, block)
break
+
case "transact":
require(5)
@@ -120,10 +183,7 @@ ApplicationWindow {
postData(data._seed, tx)
break
- case "create":
- postData(data._seed, null)
- break
case "getStorage":
require(2);
@@ -132,53 +192,67 @@ ApplicationWindow {
postData(data._seed, storage)
break
- case "getStateKeyVals":
+
+ case "getEachStorage":
require(1);
var stateObject = eth.getStateObject(data.args[0]).stateKeyVal(true)
postData(data._seed,stateObject)
break
+
case "getTransactionsFor":
require(1);
var txs = eth.getTransactionsFor(data.args[0], true)
postData(data._seed, txs)
break
+
case "getBalance":
require(1);
postData(data._seed, eth.getStateObject(data.args[0]).value());
break
+
case "getKey":
var key = eth.getKey().privateKey;
postData(data._seed, key)
break
+
+ /*
case "watch":
- require(1)
- eth.watch(data.args[0], data.args[1]);
- break
+ require(1)
+ eth.watch(data.args[0], data.args[1]);
+
+ break
+ */
+ case "watch":
+ require(2)
+ eth.watch(data.args[0], data.args[1])
+
case "disconnect":
require(1)
postData(data._seed, null)
+
break;
- case "set":
- console.log("'Set' has been depcrecated")
- /*
- for(var key in data.args) {
- if(webview.hasOwnProperty(key)) {
- window[key] = data.args[key];
- }
- }
- */
- break;
+
case "getSecretToAddress":
require(1)
postData(data._seed, eth.secretToAddress(data.args[0]))
+
break;
+
+ case "messages":
+ require(1);
+
+ var messages = JSON.parse(eth.getMessages(data.args[0]))
+ postData(data._seed, messages)
+
+ break
+
case "debug":
- console.log(data.args[0]);
+ console.log(data.args[0]);
break;
}
} catch(e) {
@@ -200,6 +274,11 @@ ApplicationWindow {
webview.experimental.postMessage(JSON.stringify({data: data, _event: event}))
}
+ function onWatchedCb(data, id) {
+ var messages = JSON.parse(data)
+ postEvent("watched:"+id, messages)
+ }
+
function onNewBlockCb(block) {
postEvent("block:new", block)
}
@@ -211,31 +290,7 @@ ApplicationWindow {
postEvent(ev, [storageObject.address, storageObject.value])
}
}
- Rectangle {
- id: toggleInspector
- color: "#bcbcbc"
- visible: true
- height: 12
- width: 12
- anchors {
- right: root.right
- }
- MouseArea {
- onClicked: {
- if(inspector.visible == true){
- inspector.visible = false
- }else{
- inspector.visible = true
- inspector.url = webview.experimental.remoteInspectorUrl
- }
- }
- onDoubleClicked: {
- console.log('refreshing')
- webView.reload()
- }
- anchors.fill: parent
- }
- }
+
Rectangle {
id: sizeGrip
diff --git a/ethereal/ext_app.go b/ethereal/ext_app.go
index 697630504..37e9676ff 100644
--- a/ethereal/ext_app.go
+++ b/ethereal/ext_app.go
@@ -1,11 +1,13 @@
package main
import (
+ "encoding/json"
+
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethpub"
"github.com/ethereum/eth-go/ethreact"
"github.com/ethereum/eth-go/ethstate"
- "github.com/ethereum/eth-go/ethutil"
+ "github.com/ethereum/go-ethereum/javascript"
"github.com/go-qml/qml"
)
@@ -20,16 +22,21 @@ type AppContainer interface {
ObjectChanged(*ethstate.StateObject)
StorageChanged(*ethstate.StorageState)
NewWatcher(chan bool)
+ Messages(ethstate.Messages, string)
}
type ExtApplication struct {
*ethpub.PEthereum
+ eth ethchain.EthManager
blockChan chan ethreact.Event
changeChan chan ethreact.Event
+ messageChan chan ethreact.Event
quitChan chan bool
watcherQuitChan chan bool
+ filters map[string]*ethchain.Filter
+
container AppContainer
lib *UiLib
registeredEvents []string
@@ -37,11 +44,14 @@ type ExtApplication struct {
func NewExtApplication(container AppContainer, lib *UiLib) *ExtApplication {
app := &ExtApplication{
- ethpub.NewPEthereum(lib.eth),
+ ethpub.New(lib.eth),
+ lib.eth,
+ make(chan ethreact.Event, 100),
make(chan ethreact.Event, 100),
make(chan ethreact.Event, 100),
make(chan bool),
make(chan bool),
+ make(map[string]*ethchain.Filter),
container,
lib,
nil,
@@ -68,6 +78,7 @@ func (app *ExtApplication) run() {
// Subscribe to events
reactor := app.lib.eth.Reactor()
reactor.Subscribe("newBlock", app.blockChan)
+ reactor.Subscribe("messages", app.messageChan)
app.container.NewWatcher(app.watcherQuitChan)
@@ -113,20 +124,38 @@ out:
} else if storageObject, ok := object.Resource.(*ethstate.StorageState); ok {
app.container.StorageChanged(storageObject)
}
+
+ case msg := <-app.messageChan:
+ if messages, ok := msg.Resource.(ethstate.Messages); ok {
+ for id, filter := range app.filters {
+ msgs := filter.FilterMessages(messages)
+ if len(msgs) > 0 {
+ app.container.Messages(msgs, id)
+ }
+ }
+ }
}
}
}
-func (app *ExtApplication) Watch(addr, storageAddr string) {
- var event string
- if len(storageAddr) == 0 {
- event = "object:" + string(ethutil.Hex2Bytes(addr))
- app.lib.eth.Reactor().Subscribe(event, app.changeChan)
- } else {
- event = "storage:" + string(ethutil.Hex2Bytes(addr)) + ":" + string(ethutil.Hex2Bytes(storageAddr))
- app.lib.eth.Reactor().Subscribe(event, app.changeChan)
+func (self *ExtApplication) Watch(filterOptions map[string]interface{}, identifier string) {
+ self.filters[identifier] = ethchain.NewFilterFromMap(filterOptions, self.eth)
+}
+
+func (self *ExtApplication) GetMessages(object map[string]interface{}) string {
+ filter := ethchain.NewFilterFromMap(object, self.eth)
+
+ messages := filter.Find()
+ var msgs []javascript.JSMessage
+ for _, m := range messages {
+ msgs = append(msgs, javascript.NewJSMessage(m))
+ }
+
+ b, err := json.Marshal(msgs)
+ if err != nil {
+ return "{\"error\":" + err.Error() + "}"
}
- app.registeredEvents = append(app.registeredEvents, event)
+ return string(b)
}
diff --git a/ethereal/gui.go b/ethereal/gui.go
index 78a930e02..c0584936d 100644
--- a/ethereal/gui.go
+++ b/ethereal/gui.go
@@ -57,7 +57,7 @@ func NewWindow(ethereum *eth.Ethereum, config *ethutil.ConfigManager, clientIden
panic(err)
}
- pub := ethpub.NewPEthereum(ethereum)
+ pub := ethpub.New(ethereum)
return &Gui{eth: ethereum, txDb: db, pub: pub, logLevel: ethlog.LogLevel(logLevel), Session: session, open: false, clientIdentity: clientIdentity, config: config}
}
@@ -282,7 +282,11 @@ func (gui *Gui) insertTransaction(window string, tx *ethchain.Transaction) {
ptx.Sender = s
ptx.Address = r
- gui.getObjectByName("transactionView").Call("addTx", window, ptx, inout)
+ if window == "post" {
+ gui.getObjectByName("transactionView").Call("addTx", ptx, inout)
+ } else {
+ gui.getObjectByName("pendingTxView").Call("addTx", ptx, inout)
+ }
}
func (gui *Gui) readPreviousTransactions() {
@@ -387,12 +391,12 @@ func (gui *Gui) update() {
if bytes.Compare(tx.Sender(), gui.address()) == 0 {
object.SubAmount(tx.Value)
- gui.win.Root().Call("addTx", "post", ethpub.NewPTx(tx), "send")
+ gui.getObjectByName("transactionView").Call("addTx", ethpub.NewPTx(tx), "send")
gui.txDb.Put(tx.Hash(), tx.RlpEncode())
} else if bytes.Compare(tx.Recipient, gui.address()) == 0 {
object.AddAmount(tx.Value)
- gui.win.Root().Call("addTx", "post", ethpub.NewPTx(tx), "recv")
+ gui.getObjectByName("transactionView").Call("addTx", ethpub.NewPTx(tx), "recv")
gui.txDb.Put(tx.Hash(), tx.RlpEncode())
}
@@ -511,11 +515,13 @@ func (gui *Gui) Printf(format string, v ...interface{}) {
// Print function that logs directly to the GUI
func (gui *Gui) printLog(s string) {
- str := strings.TrimRight(s, "\n")
- lines := strings.Split(str, "\n")
+ /*
+ str := strings.TrimRight(s, "\n")
+ lines := strings.Split(str, "\n")
- view := gui.getObjectByName("infoView")
- for _, line := range lines {
- view.Call("addLog", line)
- }
+ view := gui.getObjectByName("infoView")
+ for _, line := range lines {
+ view.Call("addLog", line)
+ }
+ */
}
diff --git a/ethereal/html_container.go b/ethereal/html_container.go
index 40a9f5584..7deee487d 100644
--- a/ethereal/html_container.go
+++ b/ethereal/html_container.go
@@ -1,6 +1,7 @@
package main
import (
+ "encoding/json"
"errors"
"io/ioutil"
"net/url"
@@ -12,6 +13,7 @@ import (
"github.com/ethereum/eth-go/ethpub"
"github.com/ethereum/eth-go/ethstate"
"github.com/ethereum/eth-go/ethutil"
+ "github.com/ethereum/go-ethereum/javascript"
"github.com/go-qml/qml"
"github.com/howeyc/fsnotify"
)
@@ -131,6 +133,17 @@ func (app *HtmlApplication) StorageChanged(storageObject *ethstate.StorageState)
app.webView.Call("onStorageChangeCb", ethpub.NewPStorageState(storageObject))
}
+func (self *HtmlApplication) Messages(messages ethstate.Messages, id string) {
+ var msgs []javascript.JSMessage
+ for _, m := range messages {
+ msgs = append(msgs, javascript.NewJSMessage(m))
+ }
+
+ b, _ := json.Marshal(msgs)
+
+ self.webView.Call("onWatchedCb", string(b), id)
+}
+
func (app *HtmlApplication) Destroy() {
app.engine.Destroy()
}
diff --git a/ethereal/main.go b/ethereal/main.go
index 04a04536d..431307c6f 100644
--- a/ethereal/main.go
+++ b/ethereal/main.go
@@ -17,6 +17,9 @@ const (
func main() {
runtime.GOMAXPROCS(runtime.NumCPU())
+ // This is a bit of a cheat, but ey!
+ os.Setenv("QTWEBKIT_INSPECTOR_SERVER", "127.0.0.1:99999")
+
qml.Init(nil)
var interrupted = false
diff --git a/ethereal/qml_container.go b/ethereal/qml_container.go
index 53ff13c2f..45a6c0327 100644
--- a/ethereal/qml_container.go
+++ b/ethereal/qml_container.go
@@ -1,12 +1,14 @@
package main
import (
+ "fmt"
+ "runtime"
+
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethpub"
"github.com/ethereum/eth-go/ethstate"
"github.com/ethereum/eth-go/ethutil"
"github.com/go-qml/qml"
- "runtime"
)
type QmlApplication struct {
@@ -59,6 +61,10 @@ func (app *QmlApplication) StorageChanged(storageObject *ethstate.StorageState)
app.win.Call("onStorageChangeCb", ethpub.NewPStorageState(storageObject))
}
+func (self *QmlApplication) Messages(msgs ethstate.Messages, id string) {
+ fmt.Println("IMPLEMENT QML APPLICATION MESSAGES METHOD")
+}
+
// Getters
func (app *QmlApplication) Engine() *qml.Engine {
return app.engine
diff --git a/ethereal/ui_lib.go b/ethereal/ui_lib.go
index b7cabf3a8..f900fcaee 100644
--- a/ethereal/ui_lib.go
+++ b/ethereal/ui_lib.go
@@ -1,6 +1,7 @@
package main
import (
+ "fmt"
"path"
"github.com/ethereum/eth-go"
@@ -42,6 +43,15 @@ func (self *UiLib) EvalJavascriptFile(path string) {
self.jsEngine.LoadExtFile(path[7:])
}
+func (self *UiLib) EvalJavascriptString(str string) string {
+ value, err := self.jsEngine.Run(str)
+ if err != nil {
+ return err.Error()
+ }
+
+ return fmt.Sprintf("%v", value)
+}
+
func (ui *UiLib) OpenQml(path string) {
container := NewQmlApplication(path[7:], ui)
app := NewExtApplication(container, ui)
diff --git a/javascript/javascript_runtime.go b/javascript/javascript_runtime.go
index 158fc93cf..d384c5048 100644
--- a/javascript/javascript_runtime.go
+++ b/javascript/javascript_runtime.go
@@ -50,7 +50,7 @@ func NewJSRE(ethereum *eth.Ethereum) *JSRE {
re := &JSRE{
ethereum,
otto.New(),
- ethpub.NewPEthereum(ethereum),
+ ethpub.New(ethereum),
make(chan ethreact.Event, 10),
make(chan ethreact.Event, 10),
make(chan bool),
diff --git a/javascript/types.go b/javascript/types.go
index f9d18b26a..fb1e54ae7 100644
--- a/javascript/types.go
+++ b/javascript/types.go
@@ -39,15 +39,16 @@ func (self *JSBlock) GetTransaction(hash string) otto.Value {
}
type JSMessage struct {
- To, From string
- Input string
- Output string
- Path int
- Origin string
- Timestamp int32
- Coinbase string
- Block string
- Number int32
+ To string `json:"to"`
+ From string `json:"from"`
+ Input string `json:"input"`
+ Output string `json:"output"`
+ Path int `json:"path"`
+ Origin string `json:"origin"`
+ Timestamp int32 `json:"timestamp"`
+ Coinbase string `json:"coinbase"`
+ Block string `json:"block"`
+ Number int32 `json:"number"`
}
func NewJSMessage(message *ethstate.Message) JSMessage {
@@ -137,6 +138,7 @@ func (self *JSEthereum) Messages(object map[string]interface{}) otto.Value {
filter.SetEarliestBlock(earliest)
}
}
+
if object["latest"] != nil {
latest := object["latest"]
if l, ok := latest.(string); ok {
@@ -146,10 +148,10 @@ func (self *JSEthereum) Messages(object map[string]interface{}) otto.Value {
}
}
if object["to"] != nil {
- filter.SetTo(ethutil.Hex2Bytes(object["to"].(string)))
+ filter.AddTo(ethutil.Hex2Bytes(object["to"].(string)))
}
if object["from"] != nil {
- filter.SetFrom(ethutil.Hex2Bytes(object["from"].(string)))
+ filter.AddFrom(ethutil.Hex2Bytes(object["from"].(string)))
}
if object["max"] != nil {
filter.SetMax(object["max"].(int))
diff --git a/utils/cmd.go b/utils/cmd.go
index 4b9d0644c..7b508e0bc 100644
--- a/utils/cmd.go
+++ b/utils/cmd.go
@@ -1,8 +1,17 @@
package utils
import (
- "bitbucket.org/kardianos/osext"
"fmt"
+ "io"
+ "log"
+ "os"
+ "os/signal"
+ "path"
+ "path/filepath"
+ "runtime"
+ "time"
+
+ "bitbucket.org/kardianos/osext"
"github.com/ethereum/eth-go"
"github.com/ethereum/eth-go/ethcrypto"
"github.com/ethereum/eth-go/ethdb"
@@ -12,14 +21,6 @@ import (
"github.com/ethereum/eth-go/ethrpc"
"github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/eth-go/ethwire"
- "io"
- "log"
- "os"
- "os/signal"
- "path"
- "path/filepath"
- "runtime"
- "time"
)
var logger = ethlog.NewLogger("CLI")
@@ -226,7 +227,7 @@ func KeyTasks(keyManager *ethcrypto.KeyManager, KeyRing string, GenAddr bool, Se
func StartRpc(ethereum *eth.Ethereum, RpcPort int) {
var err error
- ethereum.RpcServer, err = ethrpc.NewJsonRpcServer(ethpub.NewPEthereum(ethereum), RpcPort)
+ ethereum.RpcServer, err = ethrpc.NewJsonRpcServer(ethpub.New(ethereum), RpcPort)
if err != nil {
logger.Errorf("Could not start RPC interface (port %v): %v", RpcPort, err)
} else {