diff --git a/cmd/mist/assets/ext/eth.js/.gitignore b/cmd/mist/assets/ext/eth.js/.gitignore
new file mode 100644
index 0000000000..de3a847ace
--- /dev/null
+++ b/cmd/mist/assets/ext/eth.js/.gitignore
@@ -0,0 +1,14 @@
+# See http://help.github.com/ignore-files/ for more about ignoring files.
+#
+# If you find yourself ignoring temporary files generated by your text editor
+# or operating system, you probably want to add a global ignore instead:
+# git config --global core.excludesfile ~/.gitignore_global
+
+/tmp
+*/**/*un~
+*un~
+.DS_Store
+*/**/.DS_Store
+ethereum/ethereum
+ethereal/ethereal
+
diff --git a/cmd/mist/assets/ext/eth.js/README.md b/cmd/mist/assets/ext/eth.js/README.md
new file mode 100644
index 0000000000..86e2969bef
--- /dev/null
+++ b/cmd/mist/assets/ext/eth.js/README.md
@@ -0,0 +1,18 @@
+# Ethereum JavaScript API
+
+This is the Ethereum compatible JavaScript API using `Promise`s
+which implements the [Generic JSON RPC](https://github.com/ethereum/wiki/wiki/Generic-JSON-RPC) spec.
+
+For an example see `index.html`.
+
+**Please note this repo is in it's early stage.**
+
+If you'd like to run a WebSocket ethereum node check out
+[go-ethereum](https://github.com/ethereum/go-ethereum).
+
+To install ethereum and spawn a node:
+
+```
+go get github.com/ethereum/go-ethereum/ethereum
+ethereum -ws -loglevel=4
+```
diff --git a/cmd/mist/assets/ext/eth.js/httprpc.js b/cmd/mist/assets/ext/eth.js/httprpc.js
new file mode 100644
index 0000000000..085b4693d4
--- /dev/null
+++ b/cmd/mist/assets/ext/eth.js/httprpc.js
@@ -0,0 +1,70 @@
+(function () {
+ var HttpRpcProvider = function (host) {
+ this.handlers = [];
+ this.host = host;
+ };
+
+ function formatJsonRpcObject(object) {
+ return {
+ jsonrpc: '2.0',
+ method: object.call,
+ params: object.args,
+ id: object._id
+ }
+ };
+
+ function formatJsonRpcMessage(message) {
+ var object = JSON.parse(message);
+
+ return {
+ _id: object.id,
+ data: object.result
+ };
+ };
+
+ HttpRpcProvider.prototype.sendRequest = function (payload, cb) {
+ var data = formatJsonRpcObject(payload);
+
+ var request = new XMLHttpRequest();
+ request.open("POST", this.host, true);
+ request.send(JSON.stringify(data));
+ request.onreadystatechange = function () {
+ if (request.readyState === 4 && cb) {
+ cb(request);
+ }
+ }
+ };
+
+ HttpRpcProvider.prototype.send = function (payload) {
+ var self = this;
+ this.sendRequest(payload, function (request) {
+ self.handlers.forEach(function (handler) {
+ handler.call(self, formatJsonRpcMessage(request.responseText));
+ });
+ });
+ };
+
+ HttpRpcProvider.prototype.poll = function (payload, id) {
+ var self = this;
+ this.sendRequest(payload, function (request) {
+ var parsed = JSON.parse(request.responseText);
+ if (parsed.result instanceof Array ? parsed.result.length === 0 : !parsed.result) {
+ return;
+ }
+ self.handlers.forEach(function (handler) {
+ handler.call(self, {_event: payload.call, _id: id, data: parsed.result});
+ });
+ });
+ };
+
+ Object.defineProperty(HttpRpcProvider.prototype, "onmessage", {
+ set: function (handler) {
+ this.handlers.push(handler);
+ }
+ });
+
+ if (typeof(web3) !== "undefined" && web3.providers !== undefined) {
+ web3.providers.HttpRpcProvider = HttpRpcProvider;
+ }
+})();
+
diff --git a/cmd/mist/assets/ext/eth.js/index.html b/cmd/mist/assets/ext/eth.js/index.html
new file mode 100644
index 0000000000..2b3f50a141
--- /dev/null
+++ b/cmd/mist/assets/ext/eth.js/index.html
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+std::name_reg
+
+
+
+
+
+
+
diff --git a/cmd/mist/assets/ext/eth.js/main.js b/cmd/mist/assets/ext/eth.js/main.js
new file mode 100644
index 0000000000..5c7ca06034
--- /dev/null
+++ b/cmd/mist/assets/ext/eth.js/main.js
@@ -0,0 +1,432 @@
+(function(window) {
+ function isPromise(o) {
+ return o instanceof Promise
+ }
+
+ function flattenPromise (obj) {
+ if (obj instanceof Promise) {
+ return Promise.resolve(obj);
+ }
+
+ if (obj instanceof Array) {
+ return new Promise(function (resolve) {
+ var promises = obj.map(function (o) {
+ return flattenPromise(o);
+ });
+
+ return Promise.all(promises).then(function (res) {
+ for (var i = 0; i < obj.length; i++) {
+ obj[i] = res[i];
+ }
+ resolve(obj);
+ });
+ });
+ }
+
+ if (obj instanceof Object) {
+ return new Promise(function (resolve) {
+ var keys = Object.keys(obj);
+ var promises = keys.map(function (key) {
+ return flattenPromise(obj[key]);
+ });
+
+ return Promise.all(promises).then(function (res) {
+ for (var i = 0; i < keys.length; i++) {
+ obj[keys[i]] = res[i];
+ }
+ resolve(obj);
+ });
+ });
+ }
+
+ return Promise.resolve(obj);
+ };
+
+ var ethMethods = function () {
+ var blockCall = function (args) {
+ return typeof args[0] === "string" ? "blockByHash" : "blockByNumber";
+ };
+
+ var transactionCall = function (args) {
+ return typeof args[0] === "string" ? 'transactionByHash' : 'transactionByNumber';
+ };
+
+ var uncleCall = function (args) {
+ return typeof args[0] === "string" ? 'uncleByHash' : 'uncleByNumber';
+ };
+
+ var methods = [
+ { name: 'balanceAt', call: 'balanceAt' },
+ { name: 'stateAt', call: 'stateAt' },
+ { name: 'countAt', call: 'countAt'},
+ { name: 'codeAt', call: 'codeAt' },
+ { name: 'transact', call: 'transact' },
+ { name: 'call', call: 'call' },
+ { name: 'block', call: blockCall },
+ { name: 'transaction', call: transactionCall },
+ { name: 'uncle', call: uncleCall },
+ { name: 'compile', call: 'compile' }
+ ];
+ return methods;
+ };
+
+ var ethProperties = function () {
+ return [
+ { name: 'coinbase', getter: 'coinbase', setter: 'setCoinbase' },
+ { name: 'listening', getter: 'listening', setter: 'setListening' },
+ { name: 'mining', getter: 'mining', setter: 'setMining' },
+ { name: 'gasPrice', getter: 'gasPrice' },
+ { name: 'account', getter: 'account' },
+ { name: 'accounts', getter: 'accounts' },
+ { name: 'peerCount', getter: 'peerCount' },
+ { name: 'defaultBlock', getter: 'defaultBlock', setter: 'setDefaultBlock' },
+ { name: 'number', getter: 'number'}
+ ];
+ };
+
+ var dbMethods = function () {
+ return [
+ { name: 'put', call: 'put' },
+ { name: 'get', call: 'get' },
+ { name: 'putString', call: 'putString' },
+ { name: 'getString', call: 'getString' }
+ ];
+ };
+
+ var shhMethods = function () {
+ return [
+ { name: 'post', call: 'post' },
+ { name: 'newIdentity', call: 'newIdentity' },
+ { name: 'haveIdentity', call: 'haveIdentity' },
+ { name: 'newGroup', call: 'newGroup' },
+ { name: 'addToGroup', call: 'addToGroup' }
+ ];
+ };
+
+ var ethWatchMethods = function () {
+ var newFilter = function (args) {
+ return typeof args[0] === 'string' ? 'newFilterString' : 'newFilter';
+ };
+
+ return [
+ { name: 'newFilter', call: newFilter },
+ { name: 'uninstallFilter', call: 'uninstallFilter' },
+ { name: 'getMessages', call: 'getMessages' }
+ ];
+ };
+
+ var shhWatchMethods = function () {
+ return [
+ { name: 'newFilter', call: 'shhNewFilter' },
+ { name: 'uninstallFilter', call: 'shhUninstallFilter' },
+ { name: 'getMessage', call: 'shhGetMessages' }
+ ];
+ };
+
+ var setupMethods = function (obj, methods) {
+ methods.forEach(function (method) {
+ obj[method.name] = function () {
+ return flattenPromise(Array.prototype.slice.call(arguments)).then(function (args) {
+ var call = typeof method.call === "function" ? method.call(args) : method.call;
+ return {call: call, args: args};
+ }).then(function (request) {
+ return new Promise(function (resolve, reject) {
+ web3.provider.send(request, function (result) {
+ //if (result || typeof result === "boolean") {
+ resolve(result);
+ return;
+ //}
+ //reject(result);
+ });
+ });
+ }).catch(function( err) {
+ console.error(err);
+ });
+ };
+ });
+ };
+
+ var setupProperties = function (obj, properties) {
+ properties.forEach(function (property) {
+ var proto = {};
+ proto.get = function () {
+ return new Promise(function(resolve, reject) {
+ web3.provider.send({call: property.getter}, function(result) {
+ resolve(result);
+ });
+ });
+ };
+ if (property.setter) {
+ proto.set = function (val) {
+ return flattenPromise([val]).then(function (args) {
+ return new Promise(function (resolve) {
+ web3.provider.send({call: property.setter, args: args}, function (result) {
+ resolve(result);
+ });
+ });
+ }).catch(function (err) {
+ console.error(err);
+ });
+ }
+ }
+ Object.defineProperty(obj, property.name, proto);
+ });
+ };
+
+ var web3 = {
+ _callbacks: {},
+ _events: {},
+ providers: {},
+ 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;
+ },
+
+ toDecimal: function (val) {
+ return parseInt(val, 16);
+ },
+
+ fromAscii: function(str, pad) {
+ pad = pad === undefined ? 32 : pad;
+ var hex = this.toHex(str);
+ while(hex.length < pad*2)
+ hex += "00";
+ return hex
+ },
+
+ eth: {
+ prototype: Object(),
+ watch: function (params) {
+ return new Filter(params, ethWatch);
+ },
+ },
+
+ db: {
+ prototype: Object()
+ },
+
+ shh: {
+ prototype: Object(),
+ watch: function (params) {
+ return new Filter(params, shhWatch);
+ }
+ },
+
+ on: function(event, id, cb) {
+ if(web3._events[event] === undefined) {
+ web3._events[event] = {};
+ }
+
+ web3._events[event][id] = cb;
+ return this
+ },
+
+ off: function(event, id) {
+ if(web3._events[event] !== undefined) {
+ delete web3._events[event][id];
+ }
+
+ return this
+ },
+
+ trigger: function(event, id, data) {
+ var callbacks = web3._events[event];
+ if (!callbacks || !callbacks[id]) {
+ return;
+ }
+ var cb = callbacks[id];
+ cb(data);
+ },
+ };
+
+ var eth = web3.eth;
+ setupMethods(eth, ethMethods());
+ setupProperties(eth, ethProperties());
+ setupMethods(web3.db, dbMethods());
+ setupMethods(web3.shh, shhMethods());
+
+ var ethWatch = {
+ changed: 'changed'
+ };
+ setupMethods(ethWatch, ethWatchMethods());
+ var shhWatch = {
+ changed: 'shhChanged'
+ };
+ setupMethods(shhWatch, shhWatchMethods());
+
+ var ProviderManager = function() {
+ this.queued = [];
+ this.polls = [];
+ this.ready = false;
+ this.provider = undefined;
+ this.id = 1;
+
+ var self = this;
+ var poll = function () {
+ if (self.provider && self.provider.poll) {
+ self.polls.forEach(function (data) {
+ data.data._id = self.id;
+ self.id++;
+ self.provider.poll(data.data, data.id);
+ });
+ }
+ setTimeout(poll, 12000);
+ };
+ poll();
+ };
+
+ ProviderManager.prototype.send = function(data, cb) {
+ data._id = this.id;
+ if (cb) {
+ web3._callbacks[data._id] = cb;
+ }
+
+ data.args = data.args || [];
+ this.id++;
+
+ if(this.provider !== undefined) {
+ this.provider.send(data);
+ } else {
+ console.warn("provider is not set");
+ this.queued.push(data);
+ }
+ };
+
+ ProviderManager.prototype.set = function(provider) {
+ if(this.provider !== undefined && this.provider.unload !== undefined) {
+ this.provider.unload();
+ }
+
+ this.provider = provider;
+ this.ready = true;
+ };
+
+ ProviderManager.prototype.sendQueued = function() {
+ for(var i = 0; this.queued.length; i++) {
+ // Resend
+ this.send(this.queued[i]);
+ }
+ };
+
+ ProviderManager.prototype.installed = function() {
+ return this.provider !== undefined;
+ };
+
+ ProviderManager.prototype.startPolling = function (data, pollId) {
+ if (!this.provider || !this.provider.poll) {
+ return;
+ }
+ this.polls.push({data: data, id: pollId});
+ };
+
+ ProviderManager.prototype.stopPolling = function (pollId) {
+ for (var i = this.polls.length; i--;) {
+ var poll = this.polls[i];
+ if (poll.id === pollId) {
+ this.polls.splice(i, 1);
+ }
+ }
+ };
+
+ web3.provider = new ProviderManager();
+
+ web3.setProvider = function(provider) {
+ provider.onmessage = messageHandler;
+ web3.provider.set(provider);
+ web3.provider.sendQueued();
+ };
+
+ var Filter = function(options, impl) {
+ this.impl = impl;
+ this.callbacks = [];
+
+ var self = this;
+ this.promise = impl.newFilter(options);
+ this.promise.then(function (id) {
+ self.id = id;
+ web3.on(impl.changed, id, self.trigger.bind(self));
+ web3.provider.startPolling({call: impl.changed, args: [id]}, id);
+ });
+ };
+
+ Filter.prototype.arrived = function(callback) {
+ this.changed(callback);
+ }
+
+ Filter.prototype.changed = function(callback) {
+ var self = this;
+ this.promise.then(function(id) {
+ self.callbacks.push(callback);
+ });
+ };
+
+ Filter.prototype.trigger = function(messages) {
+ for(var i = 0; i < this.callbacks.length; i++) {
+ this.callbacks[i].call(this, messages);
+ }
+ };
+
+ Filter.prototype.uninstall = function() {
+ var self = this;
+ this.promise.then(function (id) {
+ self.impl.uninstallFilter(id);
+ web3.provider.stopPolling(id);
+ web3.off(impl.changed, id);
+ });
+ };
+
+ Filter.prototype.messages = function() {
+ var self = this;
+ return this.promise.then(function (id) {
+ return self.impl.getMessages(id);
+ });
+ };
+
+ function messageHandler(data) {
+ if(data._event !== undefined) {
+ web3.trigger(data._event, data._id, data.data);
+ return;
+ }
+
+ if(data._id) {
+ var cb = web3._callbacks[data._id];
+ if (cb) {
+ cb.call(this, data.data)
+ delete web3._callbacks[data._id];
+ }
+ }
+ }
+
+ /*
+ // Install default provider
+ if(!web3.provider.installed()) {
+ var sock = new web3.WebSocket("ws://localhost:40404/eth");
+
+ web3.setProvider(sock);
+ }
+ */
+
+ window.web3 = web3;
+
+})(this);
diff --git a/cmd/mist/assets/ext/eth.js/qt.js b/cmd/mist/assets/ext/eth.js/qt.js
new file mode 100644
index 0000000000..644c377378
--- /dev/null
+++ b/cmd/mist/assets/ext/eth.js/qt.js
@@ -0,0 +1,27 @@
+(function() {
+ var QtProvider = function() {
+ this.handlers = [];
+
+ var self = this;
+ navigator.qt.onmessage = function (message) {
+ self.handlers.forEach(function (handler) {
+ handler.call(self, JSON.parse(message.data));
+ });
+ }
+ };
+
+ QtProvider.prototype.send = function(payload) {
+ navigator.qt.postMessage(JSON.stringify(payload));
+ };
+
+ Object.defineProperty(QtProvider.prototype, "onmessage", {
+ set: function(handler) {
+ this.handlers.push(handler);
+ },
+ });
+
+ if(typeof(web3) !== "undefined" && web3.providers !== undefined) {
+ web3.providers.QtProvider = QtProvider;
+ }
+})();
+
diff --git a/cmd/mist/assets/ext/eth.js/websocket.js b/cmd/mist/assets/ext/eth.js/websocket.js
new file mode 100644
index 0000000000..732a086f29
--- /dev/null
+++ b/cmd/mist/assets/ext/eth.js/websocket.js
@@ -0,0 +1,51 @@
+(function() {
+ var WebSocketProvider = function(host) {
+ // onmessage handlers
+ this.handlers = [];
+ // queue will be filled with messages if send is invoked before the ws is ready
+ this.queued = [];
+ this.ready = false;
+
+ this.ws = new WebSocket(host);
+
+ var self = this;
+ this.ws.onmessage = function(event) {
+ for(var i = 0; i < self.handlers.length; i++) {
+ self.handlers[i].call(self, JSON.parse(event.data), event)
+ }
+ };
+
+ this.ws.onopen = function() {
+ self.ready = true;
+
+ for(var i = 0; i < self.queued.length; i++) {
+ // Resend
+ self.send(self.queued[i]);
+ }
+ };
+ };
+ WebSocketProvider.prototype.send = function(payload) {
+ if(this.ready) {
+ var data = JSON.stringify(payload);
+
+ this.ws.send(data);
+ } else {
+ this.queued.push(payload);
+ }
+ };
+
+ WebSocketProvider.prototype.onMessage = function(handler) {
+ this.handlers.push(handler);
+ };
+
+ WebSocketProvider.prototype.unload = function() {
+ this.ws.close();
+ };
+ Object.defineProperty(WebSocketProvider.prototype, "onmessage", {
+ set: function(provider) { this.onMessage(provider); }
+ });
+
+ if(typeof(web3) !== "undefined" && web3.providers !== undefined) {
+ web3.providers.WebSocketProvider = WebSocketProvider;
+ }
+})();
diff --git a/cmd/mist/assets/ext/setup.js b/cmd/mist/assets/ext/setup.js
new file mode 100644
index 0000000000..8317937b3a
--- /dev/null
+++ b/cmd/mist/assets/ext/setup.js
@@ -0,0 +1,8 @@
+(function() {
+ if (typeof(Promise) === "undefined")
+ window.Promise = Q.Promise;
+
+ var eth = web3.eth;
+
+ web3.setProvider(new web3.providers.QtProvider());
+})()
diff --git a/cmd/mist/assets/qml/webapp.qml b/cmd/mist/assets/qml/webapp.qml
index c35f325d52..bd7399dc9b 100644
--- a/cmd/mist/assets/qml/webapp.qml
+++ b/cmd/mist/assets/qml/webapp.qml
@@ -155,7 +155,8 @@ Rectangle {
experimental.preferences.javascriptEnabled: true
experimental.preferences.navigatorQtObjectEnabled: true
experimental.preferences.developerExtrasEnabled: true
- experimental.userScripts: ["../ext/qt_messaging_adapter.js", "../ext/q.js", "../ext/big.js", "../ext/string.js", "../ext/html_messaging.js"]
+ //experimental.userScripts: ["../ext/qt_messaging_adapter.js", "../ext/q.js", "../ext/big.js", "../ext/string.js", "../ext/html_messaging.js"]
+ experimental.userScripts: ["../ext/q.js", "../ext/eth.js/main.js", "../ext/eth.js/qt.js", "../ext/setup.js"]
experimental.onMessageReceived: {
console.log("[onMessageReceived]: ", message.data)
// TODO move to messaging.js
@@ -164,51 +165,88 @@ Rectangle {
try {
switch(data.call) {
case "compile":
- postData(data._seed, eth.compile(data.args[0]))
+ postData(data._id, eth.compile(data.args[0]))
break
- case "getCoinBase":
- postData(data._seed, eth.coinBase())
+ case "coinbase":
+ postData(data._id, eth.coinBase())
- break
+ case "account":
+ postData(data._id, eth.key().address);
- case "getIsListening":
- postData(data._seed, eth.isListening())
+ case "isListening":
+ postData(data._id, eth.isListening())
break
- case "getIsMining":
- postData(data._seed, eth.isMining())
+ case "isMining":
+ postData(data._id, eth.isMining())
break
- case "getPeerCount":
- postData(data._seed, eth.peerCount())
+ case "peerCount":
+ postData(data._id, eth.peerCount())
break
- case "getCountAt":
+ case "countAt":
require(1)
- postData(data._seed, eth.txCountAt(data.args[0]))
+ postData(data._id, eth.txCountAt(data.args[0]))
break
- case "getCodeAt":
+ case "codeAt":
require(1)
var code = eth.codeAt(data.args[0])
- postData(data._seed, code);
+ postData(data._id, code);
break
- case "getBlockByNumber":
+ case "blockByNumber":
+ require(1)
var block = eth.blockByNumber(data.args[0])
- postData(data._seed, block)
+ postData(data._id, block)
+ break
+ case "blockByHash":
+ require(1)
+ var block = eth.blockByHash(data.args[0])
+ postData(data._id, block)
break
- case "getBlockByHash":
+ require(2)
var block = eth.blockByHash(data.args[0])
- postData(data._seed, block)
+ postData(data._id, block.transactions[data.args[1]])
+ break
+
+ case "transactionByHash":
+ case "transactionByNumber":
+ require(2)
+
+ var block;
+ if (data.call === "transactionByHash")
+ block = eth.blockByHash(data.args[0])
+ else
+ block = eth.blockByNumber(data.args[0])
+
+ var tx = block.transactions.get(data.args[1])
+
+ postData(data._id, tx)
+ break
+
+ case "uncleByHash":
+ case "uncleByNumber":
+ require(2)
+
+ var block;
+ if (data.call === "uncleByHash")
+ block = eth.blockByHash(data.args[0])
+ else
+ block = eth.blockByNumber(data.args[0])
+
+ var uncle = block.uncles.get(data.args[1])
+
+ postData(data._id, uncle)
break
@@ -216,50 +254,28 @@ Rectangle {
require(5)
var tx = eth.transact(data.args)
- postData(data._seed, tx)
+ postData(data._id, tx)
break
- case "getStorageAt":
+ case "stateAt":
require(2);
var storage = eth.storageAt(data.args[0], data.args[1]);
- postData(data._seed, storage)
+ postData(data._id, storage)
break
case "call":
require(1);
var ret = eth.call(data.args)
- postData(data._seed, ret)
-
- break
-
- case "getEachStorage":
- require(1);
- var storage = JSON.parse(eth.eachStorage(data.args[0]))
- postData(data._seed, storage)
-
- break
-
- case "getTransactionsFor":
- require(1);
- var txs = eth.transactionsFor(data.args[0], true)
- postData(data._seed, txs)
-
+ postData(data._id, ret)
break
- case "getBalanceAt":
+ case "balanceAt":
require(1);
- postData(data._seed, eth.balanceAt(data.args[0]));
-
- break
-
- case "getKey":
- var key = eth.key().privateKey;
-
- postData(data._seed, key)
+ postData(data._id, eth.balanceAt(data.args[0]));
break
case "watch":
@@ -268,45 +284,34 @@ Rectangle {
case "disconnect":
require(1)
- postData(data._seed, null)
-
- break;
-
- case "getSecretToAddress":
- require(1)
-
- var addr = eth.secretToAddress(data.args[0])
- console.log("getsecret", addr)
- postData(data._seed, addr)
-
+ postData(data._id, null)
break;
case "messages":
require(1);
var messages = JSON.parse(eth.getMessages(data.args[0]))
- postData(data._seed, messages)
-
+ postData(data._id, messages)
break
case "mutan":
require(1)
var code = eth.compileMutan(data.args[0])
- postData(data._seed, "0x"+code)
-
+ postData(data._id, "0x"+code)
break;
case "newFilterString":
require(1)
var id = eth.newFilterString(data.args[0])
- postData(data._seed, id);
+ postData(data._id, id);
break;
+
case "newFilter":
require(1)
var id = eth.newFilter(data.args[0])
- postData(data._seed, id);
+ postData(data._id, id);
break;
case "getMessages":
@@ -314,7 +319,7 @@ Rectangle {
var messages = eth.messages(data.args[0]);
var m = JSON.parse(JSON.parse(JSON.stringify(messages)))
- postData(data._seed, m);
+ postData(data._id, m);
break;
@@ -326,13 +331,13 @@ Rectangle {
} catch(e) {
console.log(data.call + ": " + e)
- postData(data._seed, null);
+ postData(data._id, null);
}
}
function post(seed, data) {
- postData(data._seed, data)
+ postData(data._id, data)
}
function require(args, num) {
@@ -341,7 +346,7 @@ Rectangle {
}
}
function postData(seed, data) {
- webview.experimental.postMessage(JSON.stringify({data: data, _seed: seed}))
+ webview.experimental.postMessage(JSON.stringify({data: data, _id: seed}))
}
function postEvent(event, data) {
webview.experimental.postMessage(JSON.stringify({data: data, _event: event}))
diff --git a/ethchain/filter.go b/ethchain/filter.go
index b0edea7a05..a88d36467b 100644
--- a/ethchain/filter.go
+++ b/ethchain/filter.go
@@ -90,7 +90,7 @@ func (self *Filter) Find() []*ethstate.Message {
for i := 0; !quit && block != nil; i++ {
// Quit on latest
switch {
- case block.Number.Uint64() == earliestBlockNo:
+ case block.Number.Uint64() == earliestBlockNo, block.Number.Uint64() == 0:
quit = true
case self.max <= len(messages):
break
diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go
index 62970f6213..d48d96a516 100644
--- a/ethchain/state_manager.go
+++ b/ethchain/state_manager.go
@@ -194,7 +194,7 @@ done:
}
// Notify all subscribers
- self.eth.EventMux().Post(TxPostEvent{tx})
+ go self.eth.EventMux().Post(TxPostEvent{tx})
receipts = append(receipts, receipt)
handled = append(handled, tx)
diff --git a/ethpipe/js_types.go b/ethpipe/js_types.go
index 05c12fbf6c..956a49ab77 100644
--- a/ethpipe/js_types.go
+++ b/ethpipe/js_types.go
@@ -19,6 +19,7 @@ type JSBlock struct {
Number int `json:"number"`
Hash string `json:"hash"`
Transactions *ethutil.List `json:"transactions"`
+ Uncles *ethutil.List `json:"uncles"`
Time int64 `json:"time"`
Coinbase string `json:"coinbase"`
Name string `json:"name"`
@@ -33,18 +34,24 @@ func NewJSBlock(block *ethchain.Block) *JSBlock {
return &JSBlock{}
}
- var ptxs []*JSTransaction
- for _, tx := range block.Transactions() {
- ptxs = append(ptxs, NewJSTx(tx, block.State()))
+ ptxs := make([]*JSTransaction, len(block.Transactions()))
+ for i, tx := range block.Transactions() {
+ ptxs[i] = NewJSTx(tx, block.State())
}
+ txlist := ethutil.NewList(ptxs)
- list := ethutil.NewList(ptxs)
+ puncles := make([]*JSBlock, len(block.Uncles))
+ for i, uncle := range block.Uncles {
+ puncles[i] = NewJSBlock(uncle)
+ }
+ ulist := ethutil.NewList(puncles)
return &JSBlock{
ref: block, Size: block.Size().String(),
Number: int(block.Number.Uint64()), GasUsed: block.GasUsed.String(),
GasLimit: block.GasLimit.String(), Hash: ethutil.Bytes2Hex(block.Hash()),
- Transactions: list, Time: block.Time,
+ Transactions: txlist, Uncles: ulist,
+ Time: block.Time,
Coinbase: ethutil.Bytes2Hex(block.Coinbase),
PrevHash: ethutil.Bytes2Hex(block.PrevHash),
}
diff --git a/ethutil/list.go b/ethutil/list.go
index 6919a02f56..db276f1e3b 100644
--- a/ethutil/list.go
+++ b/ethutil/list.go
@@ -69,7 +69,8 @@ func (self *List) Interface() interface{} {
// For JavaScript <3
func (self *List) ToJSON() string {
- var list []interface{}
+ // make(T, 0) != nil
+ list := make([]interface{}, 0)
for i := 0; i < self.Length; i++ {
list = append(list, self.Get(i))
}