mirror of https://github.com/ethereum/go-ethereum
commit
1f59c37b89
@ -1,21 +1,16 @@ |
|||||||
The MIT License (MIT) |
Copyright (c) 2013-2014, Jeffrey Wilcke. All rights reserved. |
||||||
|
|
||||||
Copyright (c) 2013 Jeffrey Wilcke |
This library is free software; you can redistribute it and/or |
||||||
|
modify it under the terms of the GNU General Public |
||||||
|
License as published by the Free Software Foundation; either |
||||||
|
version 2.1 of the License, or (at your option) any later version. |
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
This library is distributed in the hope that it will be useful, |
||||||
of this software and associated documentation files (the "Software"), to deal |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
in the Software without restriction, including without limitation the rights |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
General Public License for more details. |
||||||
copies of the Software, and to permit persons to whom the Software is |
|
||||||
furnished to do so, subject to the following conditions: |
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in |
You should have received a copy of the GNU General Public License |
||||||
all copies or substantial portions of the Software. |
along with this library; if not, write to the Free Software |
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
MA 02110-1301 USA |
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
||||||
THE SOFTWARE. |
|
||||||
|
After Width: | Height: | Size: 1004 B |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 905 B |
@ -0,0 +1,31 @@ |
|||||||
|
var Filter = function(options) { |
||||||
|
this.callbacks = {}; |
||||||
|
this.seed = Math.floor(Math.random() * 1000000); |
||||||
|
this.options = options; |
||||||
|
|
||||||
|
if(options == "chain") { |
||||||
|
eth.registerFilterString(options, this.seed); |
||||||
|
} else if(typeof options === "object") { |
||||||
|
eth.registerFilter(options, this.seed); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
Filter.prototype.changed = function(callback) { |
||||||
|
var cbseed = Math.floor(Math.random() * 1000000); |
||||||
|
eth.registerFilterCallback(this.seed, cbseed); |
||||||
|
|
||||||
|
var self = this; |
||||||
|
message.connect(function(messages, seed, callbackSeed) { |
||||||
|
if(seed == self.seed && callbackSeed == cbseed) { |
||||||
|
callback.call(self, messages); |
||||||
|
} |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
Filter.prototype.uninstall = function() { |
||||||
|
eth.uninstallFilter(this.seed) |
||||||
|
} |
||||||
|
|
||||||
|
Filter.prototype.messages = function() { |
||||||
|
return JSON.parse(eth.messages(this.options)) |
||||||
|
} |
@ -0,0 +1,22 @@ |
|||||||
|
<!doctype> |
||||||
|
<html> |
||||||
|
<head> |
||||||
|
<title>Ethereum</title> |
||||||
|
|
||||||
|
<style type="text/css"> |
||||||
|
h1 { |
||||||
|
text-align: center; |
||||||
|
font-family: Courier; |
||||||
|
font-size: 50pt; |
||||||
|
} |
||||||
|
</style> |
||||||
|
</head> |
||||||
|
|
||||||
|
<body> |
||||||
|
<h1>... Ethereum ...</h1> |
||||||
|
<ul> |
||||||
|
<li><a href="http://std.eth">std::Service</a></li> |
||||||
|
</ul> |
||||||
|
</body> |
||||||
|
</html> |
||||||
|
|
@ -0,0 +1,44 @@ |
|||||||
|
<!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", |
||||||
|
altered: ["aabb", {id: "eeff", "at": "aabb"}], |
||||||
|
}); |
||||||
|
|
||||||
|
filter.changed(function(messages) { |
||||||
|
console.log("messages", messages) |
||||||
|
}) |
||||||
|
|
||||||
|
filter.getMessages(function(messages) { |
||||||
|
console.log("getMessages", messages) |
||||||
|
}); |
||||||
|
|
||||||
|
eth.getEachStorageAt("9ef0f0d81e040012600b0c1abdef7c48f720f88a", function(entries) { |
||||||
|
for(var i = 0; i < entries.length; i++) { |
||||||
|
console.log(entries[i].key, " : ", entries[i].value) |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
eth.getBlock("f70097659f329a09642a27f11338d9269de64f1d4485786e36bfc410832148cd", function(block) { |
||||||
|
console.log(block) |
||||||
|
}) |
||||||
|
|
||||||
|
eth.mutan("var a = 10", function(code) { |
||||||
|
console.log("code", code) |
||||||
|
}); |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
</body> |
||||||
|
|
||||||
|
</html> |
After Width: | Height: | Size: 932 B |
@ -0,0 +1,256 @@ |
|||||||
|
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 { |
||||||
|
id: root |
||||||
|
property var title: "Network" |
||||||
|
property var iconSource: "../net.png" |
||||||
|
property var secondary: "Hi" |
||||||
|
property var menuItem |
||||||
|
|
||||||
|
objectName: "chainView" |
||||||
|
visible: false |
||||||
|
anchors.fill: parent |
||||||
|
|
||||||
|
TableView { |
||||||
|
id: blockTable |
||||||
|
width: parent.width |
||||||
|
anchors.top: parent.top |
||||||
|
anchors.bottom: parent.bottom |
||||||
|
TableViewColumn{ role: "number" ; title: "#" ; width: 100 } |
||||||
|
TableViewColumn{ role: "hash" ; title: "Hash" ; width: 560 } |
||||||
|
TableViewColumn{ role: "txAmount" ; title: "Tx amount" ; width: 100 } |
||||||
|
|
||||||
|
model: blockModel |
||||||
|
|
||||||
|
itemDelegate: Item { |
||||||
|
Text { |
||||||
|
anchors { |
||||||
|
left: parent.left |
||||||
|
right: parent.right |
||||||
|
leftMargin: 10 |
||||||
|
verticalCenter: parent.verticalCenter |
||||||
|
} |
||||||
|
color: styleData.textColor |
||||||
|
elide: styleData.elideMode |
||||||
|
text: styleData.value |
||||||
|
font.pixelSize: 11 |
||||||
|
MouseArea { |
||||||
|
acceptedButtons: Qt.LeftButton | Qt.RightButton |
||||||
|
propagateComposedEvents: true |
||||||
|
anchors.fill: parent |
||||||
|
onClicked: { |
||||||
|
blockTable.selection.clear() |
||||||
|
blockTable.selection.select(styleData.row) |
||||||
|
|
||||||
|
if(mouse.button == Qt.RightButton) { |
||||||
|
contextMenu.row = styleData.row; |
||||||
|
contextMenu.popup() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
onDoubleClicked: { |
||||||
|
popup.visible = true |
||||||
|
popup.setDetails(blockModel.get(styleData.row)) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
Menu { |
||||||
|
id: contextMenu |
||||||
|
property var row; |
||||||
|
MenuItem { |
||||||
|
text: "Details" |
||||||
|
onTriggered: { |
||||||
|
popup.visible = true |
||||||
|
popup.setDetails(blockModel.get(this.row)) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
MenuSeparator{} |
||||||
|
|
||||||
|
MenuItem { |
||||||
|
text: "Copy" |
||||||
|
onTriggered: { |
||||||
|
copyToClipboard(blockModel.get(this.row).hash) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
MenuItem { |
||||||
|
text: "Dump State" |
||||||
|
onTriggered: { |
||||||
|
generalFileDialog.show(false, function(path) { |
||||||
|
var hash = blockModel.get(this.row).hash; |
||||||
|
|
||||||
|
gui.dumpState(hash, path); |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function addBlock(block, initial) { |
||||||
|
var txs = JSON.parse(block.transactions); |
||||||
|
var amount = 0 |
||||||
|
if(initial == undefined){ |
||||||
|
initial = false |
||||||
|
} |
||||||
|
|
||||||
|
if(txs != null){ |
||||||
|
amount = txs.length |
||||||
|
} |
||||||
|
|
||||||
|
if(initial){ |
||||||
|
blockModel.append({number: block.number, name: block.name, gasLimit: block.gasLimit, gasUsed: block.gasUsed, coinbase: block.coinbase, hash: block.hash, txs: txs, txAmount: amount, time: block.time, prettyTime: convertToPretty(block.time)}) |
||||||
|
} else { |
||||||
|
blockModel.insert(0, {number: block.number, name: block.name, gasLimit: block.gasLimit, gasUsed: block.gasUsed, coinbase: block.coinbase, hash: block.hash, txs: txs, txAmount: amount, time: block.time, prettyTime: convertToPretty(block.time)}) |
||||||
|
} |
||||||
|
|
||||||
|
//root.secondary.text = "#" + block.number; |
||||||
|
} |
||||||
|
|
||||||
|
Window { |
||||||
|
id: popup |
||||||
|
visible: false |
||||||
|
//flags: Qt.CustomizeWindowHint | Qt.Tool | Qt.WindowCloseButtonHint |
||||||
|
property var block |
||||||
|
width: root.width |
||||||
|
height: 300 |
||||||
|
Component{ |
||||||
|
id: blockDetailsDelegate |
||||||
|
Rectangle { |
||||||
|
color: "#252525" |
||||||
|
width: popup.width |
||||||
|
height: 150 |
||||||
|
Column { |
||||||
|
anchors.leftMargin: 10 |
||||||
|
anchors.topMargin: 5 |
||||||
|
anchors.top: parent.top |
||||||
|
anchors.left: parent.left |
||||||
|
Text { text: '<h3>Block details</h3>'; color: "#F2F2F2"} |
||||||
|
Text { text: '<b>Block number:</b> ' + number; color: "#F2F2F2"} |
||||||
|
Text { text: '<b>Hash:</b> ' + hash; color: "#F2F2F2"} |
||||||
|
Text { text: '<b>Coinbase:</b> <' + name + '> ' + coinbase; color: "#F2F2F2"} |
||||||
|
Text { text: '<b>Block found at:</b> ' + prettyTime; color: "#F2F2F2"} |
||||||
|
Text { text: '<b>Gas used:</b> ' + gasUsed + " / " + gasLimit; color: "#F2F2F2"} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
ListView { |
||||||
|
model: singleBlock |
||||||
|
delegate: blockDetailsDelegate |
||||||
|
anchors.top: parent.top |
||||||
|
height: 100 |
||||||
|
anchors.leftMargin: 20 |
||||||
|
id: listViewThing |
||||||
|
Layout.maximumHeight: 40 |
||||||
|
} |
||||||
|
TableView { |
||||||
|
id: txView |
||||||
|
anchors.top: listViewThing.bottom |
||||||
|
anchors.topMargin: 50 |
||||||
|
width: parent.width |
||||||
|
|
||||||
|
TableViewColumn{width: 90; role: "value" ; title: "Value" } |
||||||
|
TableViewColumn{width: 200; role: "hash" ; title: "Hash" } |
||||||
|
TableViewColumn{width: 200; role: "sender" ; title: "Sender" } |
||||||
|
TableViewColumn{width: 200;role: "address" ; title: "Receiver" } |
||||||
|
TableViewColumn{width: 60; role: "gas" ; title: "Gas" } |
||||||
|
TableViewColumn{width: 60; role: "gasPrice" ; title: "Gas Price" } |
||||||
|
TableViewColumn{width: 60; role: "isContract" ; title: "Contract" } |
||||||
|
|
||||||
|
model: transactionModel |
||||||
|
onClicked: { |
||||||
|
var tx = transactionModel.get(row) |
||||||
|
if(tx.data) { |
||||||
|
popup.showContractData(tx) |
||||||
|
}else{ |
||||||
|
popup.height = 440 |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function showContractData(tx) { |
||||||
|
txDetailsDebugButton.tx = tx |
||||||
|
if(tx.createsContract) { |
||||||
|
contractData.text = tx.data |
||||||
|
contractLabel.text = "<h4> Transaction created contract " + tx.address + "</h4>" |
||||||
|
}else{ |
||||||
|
contractLabel.text = "<h4> Transaction ran contract " + tx.address + "</h4>" |
||||||
|
contractData.text = tx.rawData |
||||||
|
} |
||||||
|
popup.height = 540 |
||||||
|
} |
||||||
|
|
||||||
|
Rectangle { |
||||||
|
id: txDetails |
||||||
|
width: popup.width |
||||||
|
height: 300 |
||||||
|
anchors.left: listViewThing.left |
||||||
|
anchors.top: txView.bottom |
||||||
|
Label { |
||||||
|
text: "<h4>Contract data</h4>" |
||||||
|
anchors.top: parent.top |
||||||
|
anchors.left: parent.left |
||||||
|
id: contractLabel |
||||||
|
anchors.leftMargin: 10 |
||||||
|
} |
||||||
|
Button { |
||||||
|
property var tx |
||||||
|
id: txDetailsDebugButton |
||||||
|
anchors.right: parent.right |
||||||
|
anchors.rightMargin: 10 |
||||||
|
anchors.top: parent.top |
||||||
|
anchors.topMargin: 10 |
||||||
|
text: "Debug contract" |
||||||
|
onClicked: { |
||||||
|
if(tx.createsContract){ |
||||||
|
eth.startDbWithCode(tx.rawData) |
||||||
|
}else { |
||||||
|
eth.startDbWithContractAndData(tx.address, tx.rawData) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
TextArea { |
||||||
|
id: contractData |
||||||
|
text: "Contract" |
||||||
|
anchors.top: contractLabel.bottom |
||||||
|
anchors.left: parent.left |
||||||
|
anchors.bottom: popup.bottom |
||||||
|
wrapMode: Text.Wrap |
||||||
|
width: parent.width - 30 |
||||||
|
height: 80 |
||||||
|
anchors.leftMargin: 10 |
||||||
|
} |
||||||
|
} |
||||||
|
property var transactionModel: ListModel { |
||||||
|
id: transactionModel |
||||||
|
} |
||||||
|
property var singleBlock: ListModel { |
||||||
|
id: singleBlock |
||||||
|
} |
||||||
|
function setDetails(block){ |
||||||
|
singleBlock.set(0,block) |
||||||
|
popup.height = 300 |
||||||
|
transactionModel.clear() |
||||||
|
if(block.txs != undefined){ |
||||||
|
for(var i = 0; i < block.txs.count; ++i) { |
||||||
|
transactionModel.insert(0, block.txs.get(i)) |
||||||
|
} |
||||||
|
if(block.txs.get(0).data){ |
||||||
|
popup.showContractData(block.txs.get(0)) |
||||||
|
} |
||||||
|
} |
||||||
|
txView.forceActiveFocus() |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,52 @@ |
|||||||
|
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 iconSource: "../tx.png" |
||||||
|
property var title: "Transactions" |
||||||
|
property var menuItem |
||||||
|
|
||||||
|
|
||||||
|
id: historyView |
||||||
|
visible: false |
||||||
|
anchors.fill: parent |
||||||
|
objectName: "transactionView" |
||||||
|
|
||||||
|
property var txModel: ListModel { |
||||||
|
id: txModel |
||||||
|
} |
||||||
|
TableView { |
||||||
|
id: txTableView |
||||||
|
anchors.fill: parent |
||||||
|
TableViewColumn{ role: "inout" ; title: "" ; width: 40 } |
||||||
|
TableViewColumn{ role: "value" ; title: "Value" ; width: 100 } |
||||||
|
TableViewColumn{ role: "address" ; title: "Address" ; width: 430 } |
||||||
|
TableViewColumn{ role: "contract" ; title: "Contract" ; width: 100 } |
||||||
|
|
||||||
|
model: txModel |
||||||
|
} |
||||||
|
|
||||||
|
function addTx(tx, inout) { |
||||||
|
var isContract |
||||||
|
if (tx.contract == true){ |
||||||
|
isContract = "Yes" |
||||||
|
}else{ |
||||||
|
isContract = "No" |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
var address; |
||||||
|
if(inout == "recv") { |
||||||
|
address = tx.sender; |
||||||
|
} else { |
||||||
|
address = tx.address; |
||||||
|
} |
||||||
|
|
||||||
|
txModel.insert(0, {inout: inout, hash: tx.hash, address: address, value: tx.value, contract: isContract}) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,179 @@ |
|||||||
|
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: "Information" |
||||||
|
property var iconSource: "../heart.png" |
||||||
|
property var menuItem |
||||||
|
|
||||||
|
objectName: "infoView" |
||||||
|
visible: false |
||||||
|
anchors.fill: parent |
||||||
|
|
||||||
|
color: "#00000000" |
||||||
|
|
||||||
|
Column { |
||||||
|
id: info |
||||||
|
spacing: 3 |
||||||
|
anchors.fill: parent |
||||||
|
anchors.topMargin: 5 |
||||||
|
anchors.leftMargin: 5 |
||||||
|
|
||||||
|
Label { |
||||||
|
id: addressLabel |
||||||
|
text: "Address" |
||||||
|
} |
||||||
|
TextField { |
||||||
|
text: eth.key().address |
||||||
|
width: 500 |
||||||
|
} |
||||||
|
|
||||||
|
Label { |
||||||
|
text: "Client ID" |
||||||
|
} |
||||||
|
TextField { |
||||||
|
text: gui.getCustomIdentifier() |
||||||
|
width: 500 |
||||||
|
placeholderText: "Anonymous" |
||||||
|
onTextChanged: { |
||||||
|
gui.setCustomIdentifier(text) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
property var addressModel: ListModel { |
||||||
|
id: addressModel |
||||||
|
} |
||||||
|
TableView { |
||||||
|
id: addressView |
||||||
|
width: parent.width |
||||||
|
height: 200 |
||||||
|
anchors.bottom: logLayout.top |
||||||
|
TableViewColumn{ role: "name"; title: "name" } |
||||||
|
TableViewColumn{ role: "address"; title: "address"; width: 300} |
||||||
|
|
||||||
|
model: addressModel |
||||||
|
itemDelegate: Item { |
||||||
|
Text { |
||||||
|
anchors { |
||||||
|
left: parent.left |
||||||
|
right: parent.right |
||||||
|
leftMargin: 10 |
||||||
|
verticalCenter: parent.verticalCenter |
||||||
|
} |
||||||
|
color: styleData.textColor |
||||||
|
elide: styleData.elideMode |
||||||
|
text: styleData.value |
||||||
|
font.pixelSize: 11 |
||||||
|
MouseArea { |
||||||
|
acceptedButtons: Qt.LeftButton | Qt.RightButton |
||||||
|
propagateComposedEvents: true |
||||||
|
anchors.fill: parent |
||||||
|
onClicked: { |
||||||
|
addressView.selection.clear() |
||||||
|
addressView.selection.select(styleData.row) |
||||||
|
|
||||||
|
if(mouse.button == Qt.RightButton) { |
||||||
|
contextMenu.row = styleData.row; |
||||||
|
contextMenu.popup() |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
Menu { |
||||||
|
id: contextMenu |
||||||
|
property var row; |
||||||
|
|
||||||
|
MenuItem { |
||||||
|
text: "Copy" |
||||||
|
onTriggered: { |
||||||
|
copyToClipboard(addressModel.get(this.row).address) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
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: gui.getLogLevelInt() |
||||||
|
anchors { |
||||||
|
right: parent.right |
||||||
|
top: parent.top |
||||||
|
bottom: parent.bottom |
||||||
|
|
||||||
|
rightMargin: 5 |
||||||
|
leftMargin: 5 |
||||||
|
topMargin: 5 |
||||||
|
bottomMargin: 5 |
||||||
|
} |
||||||
|
|
||||||
|
orientation: Qt.Vertical |
||||||
|
maximumValue: 5 |
||||||
|
stepSize: 1 |
||||||
|
|
||||||
|
onValueChanged: { |
||||||
|
gui.setLogLevel(value) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function addDebugMessage(message){ |
||||||
|
debuggerLog.append({value: message}) |
||||||
|
} |
||||||
|
|
||||||
|
function addAddress(address) { |
||||||
|
addressModel.append({name: address.name, address: address.address}) |
||||||
|
} |
||||||
|
|
||||||
|
function clearAddress() { |
||||||
|
addressModel.clear() |
||||||
|
} |
||||||
|
|
||||||
|
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(logView.flickableItem.atYEnd) { |
||||||
|
logModel.append({description: str}) |
||||||
|
logView.positionViewAtRow(logView.rowCount - 1, ListView.Contain) |
||||||
|
} else { |
||||||
|
logModel.append({description: str}) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -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 iconSource: "../tx.png" |
||||||
|
property var menuItem |
||||||
|
|
||||||
|
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 |
||||||
|
text: "> JSRE Ready..." |
||||||
|
anchors { |
||||||
|
top: parent.top |
||||||
|
left: parent.left |
||||||
|
right: parent.right |
||||||
|
bottom: input.top |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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: "Pending Transactions" |
||||||
|
property var iconSource: "../tx.png" |
||||||
|
property var menuItem |
||||||
|
|
||||||
|
objectName: "pendingTxView" |
||||||
|
anchors.fill: parent |
||||||
|
visible: false |
||||||
|
id: pendingTxView |
||||||
|
|
||||||
|
property var pendingTxModel: ListModel { |
||||||
|
id: pendingTxModel |
||||||
|
} |
||||||
|
|
||||||
|
TableView { |
||||||
|
id: pendingTxTableView |
||||||
|
anchors.fill: parent |
||||||
|
TableViewColumn{ role: "value" ; title: "Value" ; width: 100 } |
||||||
|
TableViewColumn{ role: "from" ; title: "sender" ; width: 230 } |
||||||
|
TableViewColumn{ role: "to" ; title: "Reciever" ; width: 230 } |
||||||
|
TableViewColumn{ role: "contract" ; title: "Contract" ; width: 100 } |
||||||
|
|
||||||
|
model: pendingTxModel |
||||||
|
} |
||||||
|
|
||||||
|
function addTx(tx, inout) { |
||||||
|
var isContract |
||||||
|
if (tx.contract == true){ |
||||||
|
isContract = "Yes" |
||||||
|
}else{ |
||||||
|
isContract = "No" |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
pendingTxModel.insert(0, {hash: tx.hash, to: tx.address, from: tx.sender, value: tx.value, contract: isContract}) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,215 @@ |
|||||||
|
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 iconSource: "../new.png" |
||||||
|
property var title: "New transaction" |
||||||
|
property var menuItem |
||||||
|
|
||||||
|
objectName: "newTxView" |
||||||
|
visible: false |
||||||
|
anchors.fill: parent |
||||||
|
color: "#00000000" |
||||||
|
|
||||||
|
Column { |
||||||
|
id: mainContractColumn |
||||||
|
anchors.fill: parent |
||||||
|
|
||||||
|
|
||||||
|
states: [ |
||||||
|
State{ |
||||||
|
name: "ERROR" |
||||||
|
|
||||||
|
PropertyChanges { target: txResult; visible:true} |
||||||
|
PropertyChanges { target: codeView; visible:true} |
||||||
|
}, |
||||||
|
State { |
||||||
|
name: "DONE" |
||||||
|
|
||||||
|
PropertyChanges { target: txValue; visible:false} |
||||||
|
PropertyChanges { target: txGas; visible:false} |
||||||
|
PropertyChanges { target: txGasPrice; visible:false} |
||||||
|
PropertyChanges { target: codeView; visible:false} |
||||||
|
PropertyChanges { target: txButton; visible:false} |
||||||
|
PropertyChanges { target: txDataLabel; visible:false} |
||||||
|
PropertyChanges { target: atLabel; visible:false} |
||||||
|
PropertyChanges { target: txFuelRecipient; visible:false} |
||||||
|
PropertyChanges { target: valueDenom; visible:false} |
||||||
|
PropertyChanges { target: gasDenom; visible:false} |
||||||
|
|
||||||
|
PropertyChanges { target: txResult; visible:true} |
||||||
|
PropertyChanges { target: txOutput; visible:true} |
||||||
|
PropertyChanges { target: newTxButton; visible:true} |
||||||
|
}, |
||||||
|
State { |
||||||
|
name: "SETUP" |
||||||
|
|
||||||
|
PropertyChanges { target: txValue; visible:true; text: ""} |
||||||
|
PropertyChanges { target: txGas; visible:true;} |
||||||
|
PropertyChanges { target: txGasPrice; visible:true;} |
||||||
|
PropertyChanges { target: codeView; visible:true; text: ""} |
||||||
|
PropertyChanges { target: txButton; visible:true} |
||||||
|
PropertyChanges { target: txDataLabel; visible:true} |
||||||
|
PropertyChanges { target: valueDenom; visible:true} |
||||||
|
PropertyChanges { target: gasDenom; visible:true} |
||||||
|
|
||||||
|
PropertyChanges { target: txResult; visible:false} |
||||||
|
PropertyChanges { target: txOutput; visible:false} |
||||||
|
PropertyChanges { target: newTxButton; visible:false} |
||||||
|
} |
||||||
|
] |
||||||
|
width: 400 |
||||||
|
spacing: 5 |
||||||
|
anchors.left: parent.left |
||||||
|
anchors.top: parent.top |
||||||
|
anchors.leftMargin: 5 |
||||||
|
anchors.topMargin: 5 |
||||||
|
|
||||||
|
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 { |
||||||
|
id: txValue |
||||||
|
width: 222 |
||||||
|
placeholderText: "Amount" |
||||||
|
validator: RegExpValidator { regExp: /\d*/ } |
||||||
|
onTextChanged: { |
||||||
|
contractFormReady() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
ComboBox { |
||||||
|
id: valueDenom |
||||||
|
currentIndex: 6 |
||||||
|
model: denomModel |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
RowLayout { |
||||||
|
TextField { |
||||||
|
id: txGas |
||||||
|
width: 50 |
||||||
|
validator: RegExpValidator { regExp: /\d*/ } |
||||||
|
placeholderText: "Gas" |
||||||
|
text: "500" |
||||||
|
} |
||||||
|
Label { |
||||||
|
id: atLabel |
||||||
|
text: "@" |
||||||
|
} |
||||||
|
|
||||||
|
TextField { |
||||||
|
id: txGasPrice |
||||||
|
width: 200 |
||||||
|
placeholderText: "Gas price" |
||||||
|
text: "10" |
||||||
|
validator: RegExpValidator { regExp: /\d*/ } |
||||||
|
} |
||||||
|
|
||||||
|
ComboBox { |
||||||
|
id: gasDenom |
||||||
|
currentIndex: 4 |
||||||
|
model: denomModel |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Label { |
||||||
|
id: txDataLabel |
||||||
|
text: "Data" |
||||||
|
} |
||||||
|
|
||||||
|
TextArea { |
||||||
|
id: codeView |
||||||
|
height: 300 |
||||||
|
anchors.topMargin: 5 |
||||||
|
width: 400 |
||||||
|
onTextChanged: { |
||||||
|
contractFormReady() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
Button { |
||||||
|
id: txButton |
||||||
|
/* enabled: false */ |
||||||
|
states: [ |
||||||
|
State { |
||||||
|
name: "READY" |
||||||
|
PropertyChanges { target: txButton; /*enabled: true*/} |
||||||
|
}, |
||||||
|
State { |
||||||
|
name: "NOTREADY" |
||||||
|
PropertyChanges { target: txButton; /*enabled:false*/} |
||||||
|
} |
||||||
|
] |
||||||
|
text: "Send" |
||||||
|
onClicked: { |
||||||
|
var value = txValue.text + denomModel.get(valueDenom.currentIndex).zeros; |
||||||
|
var gasPrice = txGasPrice.text + denomModel.get(gasDenom.currentIndex).zeros; |
||||||
|
var res = gui.transact(txFuelRecipient.text, value, txGas.text, gasPrice, codeView.text) |
||||||
|
if(res[1]) { |
||||||
|
txResult.text = "Your contract <b>could not</b> be sent over the network:\n<b>" |
||||||
|
txResult.text += res[1].error() |
||||||
|
txResult.text += "</b>" |
||||||
|
mainContractColumn.state = "ERROR" |
||||||
|
} else { |
||||||
|
txResult.text = "Your transaction has been submitted:\n" |
||||||
|
txOutput.text = res[0].address |
||||||
|
mainContractColumn.state = "DONE" |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
Text { |
||||||
|
id: txResult |
||||||
|
visible: false |
||||||
|
} |
||||||
|
TextField { |
||||||
|
id: txOutput |
||||||
|
visible: false |
||||||
|
width: 530 |
||||||
|
} |
||||||
|
Button { |
||||||
|
id: newTxButton |
||||||
|
visible: false |
||||||
|
text: "Create a new transaction" |
||||||
|
onClicked: { |
||||||
|
this.visible = false |
||||||
|
txResult.text = "" |
||||||
|
txOutput.text = "" |
||||||
|
mainContractColumn.state = "SETUP" |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
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" |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,165 @@ |
|||||||
|
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 { |
||||||
|
id: root |
||||||
|
property var title: "Wallet" |
||||||
|
property var iconSource: "../wallet.png" |
||||||
|
property var menuItem |
||||||
|
|
||||||
|
objectName: "walletView" |
||||||
|
anchors.fill: parent |
||||||
|
|
||||||
|
function onReady() { |
||||||
|
menuItem.secondaryTitle = eth.numberToHuman(eth.balanceAt(eth.key().address)) |
||||||
|
} |
||||||
|
|
||||||
|
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" } |
||||||
|
} |
||||||
|
|
||||||
|
ColumnLayout { |
||||||
|
spacing: 10 |
||||||
|
y: 40 |
||||||
|
anchors.fill: parent |
||||||
|
|
||||||
|
Text { |
||||||
|
id: balance |
||||||
|
text: "<b>Balance</b>: " + eth.numberToHuman(eth.balanceAt(eth.key().address)) |
||||||
|
font.pixelSize: 24 |
||||||
|
anchors { |
||||||
|
horizontalCenter: parent.horizontalCenter |
||||||
|
top: parent.top |
||||||
|
topMargin: 20 |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Rectangle { |
||||||
|
id: newTxPane |
||||||
|
color: "#ececec" |
||||||
|
border.color: "#cccccc" |
||||||
|
border.width: 1 |
||||||
|
anchors { |
||||||
|
top: balance.bottom |
||||||
|
topMargin: 10 |
||||||
|
left: parent.left |
||||||
|
leftMargin: 5 |
||||||
|
right: parent.right |
||||||
|
rightMargin: 5 |
||||||
|
} |
||||||
|
height: 100 |
||||||
|
|
||||||
|
RowLayout { |
||||||
|
id: amountFields |
||||||
|
spacing: 10 |
||||||
|
anchors { |
||||||
|
top: parent.top |
||||||
|
topMargin: 20 |
||||||
|
left: parent.left |
||||||
|
leftMargin: 20 |
||||||
|
} |
||||||
|
|
||||||
|
Text { |
||||||
|
text: "Ξ " |
||||||
|
} |
||||||
|
|
||||||
|
// There's something off with the row layout where textfields won't listen to the width setting |
||||||
|
Rectangle { |
||||||
|
width: 50 |
||||||
|
height: 20 |
||||||
|
TextField { |
||||||
|
id: txValue |
||||||
|
width: parent.width |
||||||
|
placeholderText: "0.00" |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
ComboBox { |
||||||
|
id: valueDenom |
||||||
|
currentIndex: 6 |
||||||
|
model: denomModel |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
RowLayout { |
||||||
|
id: toFields |
||||||
|
spacing: 10 |
||||||
|
anchors { |
||||||
|
top: amountFields.bottom |
||||||
|
topMargin: 5 |
||||||
|
left: parent.left |
||||||
|
leftMargin: 20 |
||||||
|
} |
||||||
|
|
||||||
|
Text { |
||||||
|
text: "To" |
||||||
|
} |
||||||
|
|
||||||
|
Rectangle { |
||||||
|
width: 200 |
||||||
|
height: 20 |
||||||
|
TextField { |
||||||
|
id: txTo |
||||||
|
width: parent.width |
||||||
|
placeholderText: "Address or name" |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Button { |
||||||
|
text: "Send" |
||||||
|
onClicked: { |
||||||
|
var value = txValue.text + denomModel.get(valueDenom.currentIndex).zeros; |
||||||
|
var gasPrice = "10000000000000" |
||||||
|
var res = eth.transact({from: eth.key().privateKey, to: txTo.text, value: value, gas: "500", gasPrice: gasPrice}) |
||||||
|
console.log(res) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Rectangle { |
||||||
|
anchors { |
||||||
|
left: parent.left |
||||||
|
right: parent.right |
||||||
|
top: newTxPane.bottom |
||||||
|
topMargin: 10 |
||||||
|
bottom: parent.bottom |
||||||
|
} |
||||||
|
TableView { |
||||||
|
id: txTableView |
||||||
|
anchors.fill : parent |
||||||
|
TableViewColumn{ role: "num" ; title: "#" ; width: 30 } |
||||||
|
TableViewColumn{ role: "from" ; title: "From" ; width: 280 } |
||||||
|
TableViewColumn{ role: "to" ; title: "To" ; width: 280 } |
||||||
|
TableViewColumn{ role: "value" ; title: "Amount" ; width: 100 } |
||||||
|
|
||||||
|
model: ListModel { |
||||||
|
id: txModel |
||||||
|
Component.onCompleted: { |
||||||
|
var messages = JSON.parse(eth.messages({latest: -1, from: "e6716f9544a56c530d868e4bfbacb172315bdead"})) |
||||||
|
for(var i = 0; i < messages.length; i++) { |
||||||
|
var message = messages[i]; |
||||||
|
this.insert(0, {num: i, from: message.from, to: message.to, value: eth.numberToHuman(message.value)}) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 1.1 KiB |
@ -1,95 +0,0 @@ |
|||||||
package ethrepl |
|
||||||
|
|
||||||
import ( |
|
||||||
"fmt" |
|
||||||
"github.com/ethereum/eth-go/ethpub" |
|
||||||
"github.com/ethereum/eth-go/ethutil" |
|
||||||
"github.com/obscuren/otto" |
|
||||||
) |
|
||||||
|
|
||||||
type JSStateObject struct { |
|
||||||
*ethpub.PStateObject |
|
||||||
eth *JSEthereum |
|
||||||
} |
|
||||||
|
|
||||||
func (self *JSStateObject) EachStorage(call otto.FunctionCall) otto.Value { |
|
||||||
cb := call.Argument(0) |
|
||||||
self.PStateObject.EachStorage(func(key string, value *ethutil.Value) { |
|
||||||
value.Decode() |
|
||||||
|
|
||||||
cb.Call(self.eth.toVal(self), self.eth.toVal(key), self.eth.toVal(ethutil.Bytes2Hex(value.Bytes()))) |
|
||||||
}) |
|
||||||
|
|
||||||
return otto.UndefinedValue() |
|
||||||
} |
|
||||||
|
|
||||||
// The JSEthereum object attempts to wrap the PEthereum object and returns
|
|
||||||
// meaningful javascript objects
|
|
||||||
type JSBlock struct { |
|
||||||
*ethpub.PBlock |
|
||||||
eth *JSEthereum |
|
||||||
} |
|
||||||
|
|
||||||
func (self *JSBlock) GetTransaction(hash string) otto.Value { |
|
||||||
return self.eth.toVal(self.PBlock.GetTransaction(hash)) |
|
||||||
} |
|
||||||
|
|
||||||
type JSEthereum struct { |
|
||||||
*ethpub.PEthereum |
|
||||||
vm *otto.Otto |
|
||||||
} |
|
||||||
|
|
||||||
func (self *JSEthereum) GetBlock(hash string) otto.Value { |
|
||||||
return self.toVal(&JSBlock{self.PEthereum.GetBlock(hash), self}) |
|
||||||
} |
|
||||||
|
|
||||||
func (self *JSEthereum) GetPeers() otto.Value { |
|
||||||
return self.toVal(self.PEthereum.GetPeers()) |
|
||||||
} |
|
||||||
|
|
||||||
func (self *JSEthereum) GetKey() otto.Value { |
|
||||||
return self.toVal(self.PEthereum.GetKey()) |
|
||||||
} |
|
||||||
|
|
||||||
func (self *JSEthereum) GetStateObject(addr string) otto.Value { |
|
||||||
return self.toVal(&JSStateObject{self.PEthereum.GetStateObject(addr), self}) |
|
||||||
} |
|
||||||
|
|
||||||
func (self *JSEthereum) GetStateKeyVals(addr string) otto.Value { |
|
||||||
return self.toVal(self.PEthereum.GetStateObject(addr).StateKeyVal(false)) |
|
||||||
} |
|
||||||
|
|
||||||
func (self *JSEthereum) Transact(key, recipient, valueStr, gasStr, gasPriceStr, dataStr string) otto.Value { |
|
||||||
r, err := self.PEthereum.Transact(key, recipient, valueStr, gasStr, gasPriceStr, dataStr) |
|
||||||
if err != nil { |
|
||||||
fmt.Println(err) |
|
||||||
|
|
||||||
return otto.UndefinedValue() |
|
||||||
} |
|
||||||
|
|
||||||
return self.toVal(r) |
|
||||||
} |
|
||||||
|
|
||||||
func (self *JSEthereum) Create(key, valueStr, gasStr, gasPriceStr, scriptStr string) otto.Value { |
|
||||||
r, err := self.PEthereum.Create(key, valueStr, gasStr, gasPriceStr, scriptStr) |
|
||||||
|
|
||||||
if err != nil { |
|
||||||
fmt.Println(err) |
|
||||||
|
|
||||||
return otto.UndefinedValue() |
|
||||||
} |
|
||||||
|
|
||||||
return self.toVal(r) |
|
||||||
} |
|
||||||
|
|
||||||
func (self *JSEthereum) toVal(v interface{}) otto.Value { |
|
||||||
result, err := self.vm.ToValue(v) |
|
||||||
|
|
||||||
if err != nil { |
|
||||||
fmt.Println("Value unknown:", err) |
|
||||||
|
|
||||||
return otto.UndefinedValue() |
|
||||||
} |
|
||||||
|
|
||||||
return result |
|
||||||
} |
|
@ -1,4 +1,4 @@ |
|||||||
package ethrepl |
package javascript |
||||||
|
|
||||||
const jsLib = ` |
const jsLib = ` |
||||||
function pp(object) { |
function pp(object) { |
@ -0,0 +1,138 @@ |
|||||||
|
package javascript |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
|
||||||
|
"github.com/ethereum/eth-go" |
||||||
|
"github.com/ethereum/eth-go/ethchain" |
||||||
|
"github.com/ethereum/eth-go/ethpipe" |
||||||
|
"github.com/ethereum/eth-go/ethstate" |
||||||
|
"github.com/ethereum/eth-go/ethutil" |
||||||
|
"github.com/obscuren/otto" |
||||||
|
) |
||||||
|
|
||||||
|
type JSStateObject struct { |
||||||
|
*ethpipe.JSObject |
||||||
|
eth *JSEthereum |
||||||
|
} |
||||||
|
|
||||||
|
func (self *JSStateObject) EachStorage(call otto.FunctionCall) otto.Value { |
||||||
|
cb := call.Argument(0) |
||||||
|
self.JSObject.EachStorage(func(key string, value *ethutil.Value) { |
||||||
|
value.Decode() |
||||||
|
|
||||||
|
cb.Call(self.eth.toVal(self), self.eth.toVal(key), self.eth.toVal(ethutil.Bytes2Hex(value.Bytes()))) |
||||||
|
}) |
||||||
|
|
||||||
|
return otto.UndefinedValue() |
||||||
|
} |
||||||
|
|
||||||
|
// The JSEthereum object attempts to wrap the PEthereum object and returns
|
||||||
|
// meaningful javascript objects
|
||||||
|
type JSBlock struct { |
||||||
|
*ethpipe.JSBlock |
||||||
|
eth *JSEthereum |
||||||
|
} |
||||||
|
|
||||||
|
func (self *JSBlock) GetTransaction(hash string) otto.Value { |
||||||
|
return self.eth.toVal(self.JSBlock.GetTransaction(hash)) |
||||||
|
} |
||||||
|
|
||||||
|
type JSMessage struct { |
||||||
|
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 { |
||||||
|
return JSMessage{ |
||||||
|
To: ethutil.Bytes2Hex(message.To), |
||||||
|
From: ethutil.Bytes2Hex(message.From), |
||||||
|
Input: ethutil.Bytes2Hex(message.Input), |
||||||
|
Output: ethutil.Bytes2Hex(message.Output), |
||||||
|
Path: message.Path, |
||||||
|
Origin: ethutil.Bytes2Hex(message.Origin), |
||||||
|
Timestamp: int32(message.Timestamp), |
||||||
|
Coinbase: ethutil.Bytes2Hex(message.Origin), |
||||||
|
Block: ethutil.Bytes2Hex(message.Block), |
||||||
|
Number: int32(message.Number.Int64()), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
type JSEthereum struct { |
||||||
|
*ethpipe.JSPipe |
||||||
|
vm *otto.Otto |
||||||
|
ethereum *eth.Ethereum |
||||||
|
} |
||||||
|
|
||||||
|
func (self *JSEthereum) GetBlock(hash string) otto.Value { |
||||||
|
return self.toVal(&JSBlock{self.JSPipe.BlockByHash(hash), self}) |
||||||
|
} |
||||||
|
|
||||||
|
func (self *JSEthereum) GetPeers() otto.Value { |
||||||
|
return self.toVal(self.JSPipe.Peers()) |
||||||
|
} |
||||||
|
|
||||||
|
func (self *JSEthereum) GetKey() otto.Value { |
||||||
|
return self.toVal(self.JSPipe.Key()) |
||||||
|
} |
||||||
|
|
||||||
|
func (self *JSEthereum) GetStateObject(addr string) otto.Value { |
||||||
|
return self.toVal(&JSStateObject{ethpipe.NewJSObject(self.JSPipe.World().SafeGet(ethutil.Hex2Bytes(addr))), self}) |
||||||
|
} |
||||||
|
|
||||||
|
func (self *JSEthereum) Transact(key, recipient, valueStr, gasStr, gasPriceStr, dataStr string) otto.Value { |
||||||
|
r, err := self.JSPipe.Transact(key, recipient, valueStr, gasStr, gasPriceStr, dataStr) |
||||||
|
if err != nil { |
||||||
|
fmt.Println(err) |
||||||
|
|
||||||
|
return otto.UndefinedValue() |
||||||
|
} |
||||||
|
|
||||||
|
return self.toVal(r) |
||||||
|
} |
||||||
|
|
||||||
|
func (self *JSEthereum) Create(key, valueStr, gasStr, gasPriceStr, scriptStr string) otto.Value { |
||||||
|
r, err := self.JSPipe.Transact(key, "", valueStr, gasStr, gasPriceStr, scriptStr) |
||||||
|
|
||||||
|
if err != nil { |
||||||
|
fmt.Println(err) |
||||||
|
|
||||||
|
return otto.UndefinedValue() |
||||||
|
} |
||||||
|
|
||||||
|
return self.toVal(r) |
||||||
|
} |
||||||
|
|
||||||
|
func (self *JSEthereum) toVal(v interface{}) otto.Value { |
||||||
|
result, err := self.vm.ToValue(v) |
||||||
|
|
||||||
|
if err != nil { |
||||||
|
fmt.Println("Value unknown:", err) |
||||||
|
|
||||||
|
return otto.UndefinedValue() |
||||||
|
} |
||||||
|
|
||||||
|
return result |
||||||
|
} |
||||||
|
|
||||||
|
func (self *JSEthereum) Messages(object map[string]interface{}) otto.Value { |
||||||
|
filter := ethchain.NewFilterFromMap(object, self.ethereum) |
||||||
|
|
||||||
|
messages := filter.Find() |
||||||
|
var msgs []JSMessage |
||||||
|
for _, m := range messages { |
||||||
|
msgs = append(msgs, NewJSMessage(m)) |
||||||
|
} |
||||||
|
|
||||||
|
v, _ := self.vm.ToValue(msgs) |
||||||
|
|
||||||
|
return v |
||||||
|
} |
Loading…
Reference in new issue