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 |
||||
of this software and associated documentation files (the "Software"), to deal |
||||
in the Software without restriction, including without limitation the rights |
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
copies of the Software, and to permit persons to whom the Software is |
||||
furnished to do so, subject to the following conditions: |
||||
This library is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||||
General Public License for more details. |
||||
|
||||
The above copyright notice and this permission notice shall be included in |
||||
all copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
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. |
||||
You should have received a copy of the GNU General Public License |
||||
along with this library; if not, write to the Free Software |
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
||||
MA 02110-1301 USA |
||||
|
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 = ` |
||||
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