Compare commits

...

65 Commits

Author SHA1 Message Date
b3f25a6ade Merge branch 'release/0.6.0' 2014-07-25 10:42:14 +02:00
44da1801d8 Fixed strange issue where qml will crash first run after go install 2014-07-24 14:34:22 +02:00
82a84dca80 Move to goroutine for faster startup time 2014-07-24 14:16:43 +02:00
0ca776a6b8 Merge branch 'feature/new_vm' into develop 2014-07-24 14:16:25 +02:00
2e39efbe7c New State object 2014-07-24 12:34:48 +02:00
a06a84d19b Refactored to reflect the new VM and State 2014-07-24 12:30:41 +02:00
e7a80ec681 set asm 2014-07-22 19:54:33 +02:00
15960a5c04 changed iterator 2014-07-21 11:55:50 +02:00
f702e27485 Fixed miner stopping / starting:wq 2014-07-18 13:49:52 +02:00
0c5a747ef1 Add mining hash to GUI 2014-07-18 12:29:14 +02:00
75df148ba2 Fixed miner channel 2014-07-18 12:21:34 +02:00
4572d4940c Windows don't like dem flags 2014-07-18 12:02:45 +02:00
2b9f16802d WIP to expose hashrate to gui 2014-07-18 12:01:26 +02:00
34e2ab9f9f Added block update 2014-07-18 11:57:58 +02:00
44296c0b33 html tags not allowed 2014-07-17 23:17:10 +02:00
01d9107bce Add namecoin name if available to block 2014-07-17 22:30:17 +02:00
ba3fabda77 Added a catch up indicator 2014-07-17 22:01:39 +02:00
edf10ef8c5 Fixed name reg 2014-07-17 17:10:35 +02:00
6c565eae74 bump 2014-07-17 15:36:16 +02:00
c951702423 Merge branch 'develop' 2014-07-17 15:32:44 +02:00
7d64b589b4 h scroll 2014-07-17 15:02:25 +02:00
c302afd411 Merge branch 'develop' of github.com-obscure:ethereum/go-ethereum into develop 2014-07-15 20:36:45 +02:00
28948d061c Moved the repl to a new package 2014-07-15 20:34:25 +02:00
223432fa1e Work around crash issues when building OSX binary 2014-07-15 16:21:16 +02:00
c0ae5c58a6 Rewrote mnemonic word loading to facilitate deployable builds. 2014-07-15 12:52:30 +02:00
e53acdc2ac Work around race condition with qt webinspector for windows builds 2014-07-14 16:46:00 +02:00
dce0ccf490 Don't silently fail on watcher creation 2014-07-14 15:29:02 +02:00
e6a428f85f Make the reload watcher use windows-safe paths 2014-07-14 15:25:01 +02:00
288f1c5387 Removed timer 2014-07-12 11:02:50 +02:00
d3e31a4a6d Special diff output + debugger changes 2014-07-11 16:04:27 +02:00
fc8bd7229e Merge branch 'develop' 2014-07-10 21:54:46 +02:00
c2bca5939d Added path check for Windows when loading external QML windows/components 2014-07-09 14:01:53 +02:00
05c1899895 Windos case for assetPath had a typo 2014-07-08 14:58:33 +02:00
7e88dd4e6b Setup default asset path for windows 2014-07-08 14:58:23 +02:00
61d5d107b6 Make script inclusion via QML also relative to asset path 2014-07-08 14:27:22 +02:00
7f9e614b5d Forgot two images 2014-07-08 14:25:30 +02:00
79259c916d Use relative image paths to help with windows builds 2014-07-08 14:05:42 +02:00
685aebc72e Merge branch 'develop' 2014-07-07 22:15:35 +02:00
0360e60dd5 Merge pull request #101 from ethereum/revert-100-feature/ethutil-refactor
Revert "ethreact - Feature/ethutil refactor"
2014-07-07 10:59:30 +02:00
0c132e4c9e Revert "ethreact - Feature/ethutil refactor" 2014-07-07 10:58:42 +02:00
f9e2e5276f Merge pull request #100 from ethersphere/feature/ethutil-refactor
ethreact - Feature/ethutil refactor
2014-07-07 10:55:39 +02:00
8e5117444e New type of debugger 2014-07-05 13:25:16 +02:00
1e4ae24126 use ethreact.Event, unbuffered event channels, subscribe after loop reading from channel starts 2014-07-04 19:48:37 +01:00
0ae3bbc3f5 deleted 2014-07-04 15:53:16 +02:00
b9fa4dada8 Merge branch 'develop' 2014-07-04 15:53:03 +02:00
9754c01f56 Added sample coin as a submodule 2014-07-04 15:49:51 +02:00
043920d157 Removed sample coin 2014-07-04 15:49:32 +02:00
3ebcd36667 Merge branch 'develop' 2014-07-04 15:32:25 +02:00
9e38ca555d Visual updates 2014-07-04 15:31:13 +02:00
de183e80db Silent compiler errors when continues compiling 2014-07-04 13:42:43 +02:00
ca395306e3 Updated debugger
* Compile on the go. Continues compilation in order to update the ASM
  view
* Short cuts commands
2014-07-04 13:04:25 +02:00
24ff81d14e Merge branch 'ethersphere-feature/clientid' into develop 2014-07-04 00:14:17 +02:00
9de30d96f0 Modify main wrappers
- clientIdentifier now set in main wrappers
- version handled within wrapper
- modify InitConfig now returning *ethutil.ConfigManager (passed to gui)
- added NewClientIdentity returning *ethwire.SimpleClientIdentiy (passed to ethereum)
2014-07-03 17:36:24 +01:00
a3c4823511 Gui saves custom client id and loglevel
- gui NewWindow takes SimpleClientIdentity as argument
- gui NewWindow takes ethutil.ConfigManager as argument to manage flag persistence
- gui now saves loglevel and custom client id via config.Save
- rename custom client id methods consistently also in wallet.qml
- clientIdentifier now set in main wrappers
- version handled within wrapper
- modify InitConfig now returning *ethutil.ConfigManager (passed to gui)
2014-07-03 17:35:48 +01:00
0076fa583c Merge branch 'develop' 2014-07-02 17:48:35 +02:00
a0dd1ebb6d . 2014-07-02 13:44:59 +02:00
50c0938226 Break points and debugger commands 2014-07-02 13:08:18 +02:00
98f21669c7 Merge branch 'develop' 2014-07-02 11:30:37 +02:00
7d0004f058 For namreg only show items starting without leading zeros. 2014-07-02 11:29:59 +02:00
e5b45d1c86 VM Update 2014-07-02 01:04:32 +02:00
677de48f6c Listen for namereg changes 2014-07-02 00:28:45 +02:00
c4f9151c67 Moved files 2014-07-02 00:13:50 +02:00
4918531dd5 Merge branch 'develop' 2014-07-01 20:10:49 +02:00
2835321377 Fixed namereg 2014-07-01 20:10:38 +02:00
74ef489fe2 Merge branch 'release/0.5.16' into develop 2014-07-01 16:24:54 +02:00
32 changed files with 871 additions and 567 deletions

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "ethereal/assets/samplecoin"]
path = ethereal/assets/samplecoin
url = git@github.com:obscuren/SampleCoin.git

View File

@ -5,7 +5,7 @@ Ethereum
Ethereum Go Client © 2014 Jeffrey Wilcke. Ethereum Go Client © 2014 Jeffrey Wilcke.
Current state: Proof of Concept 0.5.16. Current state: Proof of Concept 0.6.0.
For the development package please see the [eth-go package](https://github.com/ethereum/eth-go). For the development package please see the [eth-go package](https://github.com/ethereum/eth-go).

View File

@ -1,22 +0,0 @@
UNAME = $(shell uname)
FILES=qml *.png
GOPATH=$(PWD)
# Default is building
all:
go get -d
cp *.go $(GOPATH)/src/github.com/ethereum/go-ethereum
cp -r ui $(GOPATH)/src/github.com/ethereum/go-ethereum
go build
install:
# Linux build
ifeq ($(UNAME),Linux)
cp -r assets/* /usr/share/ethereal
cp go-ethereum /usr/local/bin/ethereal
endif
# OS X build
ifeq ($(UNAME),Darwin)
# Execute py script
endif

View File

@ -7,16 +7,21 @@ import QtQuick.Controls.Styles 1.1
import Ethereum 1.0 import Ethereum 1.0
ApplicationWindow { ApplicationWindow {
id: win
visible: false visible: false
title: "IceCREAM" title: "IceCREAM"
minimumWidth: 1280 minimumWidth: 1280
minimumHeight: 700 minimumHeight: 700
width: 1290 width: 1290
height: 700 height: 750
property alias codeText: codeEditor.text property alias codeText: codeEditor.text
property alias dataText: rawDataField.text property alias dataText: rawDataField.text
onClosing: {
//compileTimer.stop()
}
MenuBar { MenuBar {
Menu { Menu {
title: "Debugger" title: "Debugger"
@ -31,18 +36,57 @@ ApplicationWindow {
shortcut: "Ctrl+n" shortcut: "Ctrl+n"
onTriggered: dbg.next() onTriggered: dbg.next()
} }
MenuItem {
text: "Continue"
shortcut: "Ctrl+g"
onTriggered: dbg.continue()
}
MenuItem {
text: "Command"
shortcut: "Ctrl+l"
onTriggered: {
dbgCommand.focus = true
}
}
MenuItem {
text: "Focus code"
shortcut: "Ctrl+1"
onTriggered: {
codeEditor.focus = true
}
}
MenuItem {
text: "Focus data"
shortcut: "Ctrl+2"
onTriggered: {
rawDataField.focus = true
}
}
/*
MenuItem {
text: "Close window"
shortcut: "Ctrl+w"
onTriggered: {
win.close()
}
}
*/
} }
} }
SplitView { SplitView {
anchors.fill: parent anchors.fill: parent
property var asmModel: ListModel { property var asmModel: ListModel {
id: asmModel id: asmModel
} }
TableView { TableView {
id: asmTableView id: asmTableView
width: 200 width: 200
TableViewColumn{ role: "value" ; title: "" ; width: 200 } TableViewColumn{ role: "value" ; title: "" ; width: asmTableView.width - 2 }
model: asmModel model: asmModel
} }
@ -66,6 +110,17 @@ ApplicationWindow {
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.left: parent.left anchors.left: parent.left
anchors.right: settings.left anchors.right: settings.left
focus: true
/*
Timer {
id: compileTimer
interval: 500 ; running: true ; repeat: true
onTriggered: {
dbg.autoComp(codeEditor.text)
}
}
*/
} }
Column { Column {
@ -178,7 +233,7 @@ ApplicationWindow {
} }
height: parent.height height: parent.height
width: parent.width width: parent.width
TableViewColumn{ id: message ; role: "message" ; title: "log" ; width: logTableView.width } TableViewColumn{ id: message ; role: "message" ; title: "log" ; width: logTableView.width - 2 }
model: logModel model: logModel
} }
} }
@ -187,7 +242,28 @@ ApplicationWindow {
} }
} }
function exec() {
dbg.execCommand(dbgCommand.text);
dbgCommand.text = "";
}
statusBar: StatusBar {
height: 30
TextField {
id: dbgCommand
y: 1
x: asmTableView.width
width: 500
placeholderText: "Debugger (type 'help')"
Keys.onReturnPressed: {
exec()
}
}
}
toolBar: ToolBar { toolBar: ToolBar {
height: 30
RowLayout { RowLayout {
spacing: 5 spacing: 5
@ -208,13 +284,32 @@ ApplicationWindow {
} }
text: "Next" text: "Next"
} }
CheckBox {
id: breakEachLine Button {
objectName: "breakEachLine" id: debugContinueButton
text: "Break each instruction" onClicked: {
checked: true dbg.continue()
}
text: "Continue"
} }
} }
ComboBox {
id: snippets
anchors.right: parent.right
model: ListModel {
ListElement { text: "Snippets" ; value: "" }
ListElement { text: "Call Contract" ; value: "var[2] in;\nvar ret;\n\nin[0] = \"arg1\"\nin[1] = 0xdeadbeef\n\nvar success = call(0x0c542ddea93dae0c2fcb2cf175f03ad80d6be9a0, 0, 7000, in, ret)\n\nreturn ret" }
}
onCurrentIndexChanged: {
if(currentIndex != 0) {
var code = snippets.model.get(currentIndex).value;
codeEditor.insert(codeEditor.cursorPosition, code)
}
}
}
} }
function debugCurrent() { function debugCurrent() {
@ -261,7 +356,19 @@ ApplicationWindow {
} }
function setLog(msg) { function setLog(msg) {
logModel.insert(0, {message: msg}) // Remove first item once we've reached max log items
if(logModel.count > 250) {
logModel.remove(0)
}
if(msg.len != 0) {
if(logTableView.flickableItem.atYEnd) {
logModel.append({message: msg})
logTableView.positionViewAtRow(logTableView.rowCount - 1, ListView.Contain)
} else {
logModel.append({message: msg})
}
}
} }
function clearLog() { function clearLog() {

View File

@ -100,7 +100,7 @@ ApplicationWindow {
anchors.right: parent.right anchors.right: parent.right
height: 200 height: 200
Image { Image {
source: ui.assetPath("tx.png") source: "../tx.png"
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
@ -110,7 +110,7 @@ ApplicationWindow {
} }
} }
Image { Image {
source: ui.assetPath("new.png") source: "../new.png"
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
@ -120,7 +120,7 @@ ApplicationWindow {
} }
} }
Image { Image {
source: ui.assetPath("net.png") source: "../net.png"
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
@ -131,7 +131,7 @@ ApplicationWindow {
} }
Image { Image {
source: ui.assetPath("heart.png") source: "../heart.png"
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
@ -248,9 +248,11 @@ ApplicationWindow {
text: "Client ID" text: "Client ID"
} }
TextField { TextField {
text: eth.clientId() text: eth.getCustomIdentifier()
width: 500
placeholderText: "Anonymous"
onTextChanged: { onTextChanged: {
eth.changeClientId(text) eth.setCustomIdentifier(text)
} }
} }
} }
@ -419,30 +421,54 @@ ApplicationWindow {
} }
} }
Label { Label {
y: 7 y: 6
anchors.right: peerImage.left id: lastBlockLabel
anchors.rightMargin: 5 objectName: "lastBlockLabel"
id: peerLabel visible: true
font.pixelSize: 8 text: ""
text: "0 / 0" font.pixelSize: 10
} anchors.right: peerGroup.left
Image { anchors.rightMargin: 5
y: 7 }
id: peerImage
anchors.right: parent.right ProgressBar {
width: 10; height: 10 id: syncProgressIndicator
MouseArea { visible: false
onDoubleClicked: peerWindow.visible = true objectName: "syncProgressIndicator"
anchors.fill: parent y: 3
} width: 140
source: ui.assetPath("network.png") indeterminate: true
} anchors.right: peerGroup.left
anchors.rightMargin: 5
}
RowLayout {
id: peerGroup
y: 7
anchors.right: parent.right
MouseArea {
onDoubleClicked: peerWindow.visible = true
anchors.fill: parent
}
Label {
id: peerLabel
font.pixelSize: 8
text: "0 / 0"
}
Image {
id: peerImage
width: 10; height: 10
source: "../network.png"
}
}
} }
Window { Window {
id: popup id: popup
visible: false visible: false
//flags: Qt.CustomizeWindowHint | Qt.Tool | Qt.WindowCloseButtonHint
property var block property var block
width: root.width width: root.width
height: 300 height: 300
@ -460,7 +486,7 @@ ApplicationWindow {
Text { text: '<h3>Block details</h3>'; color: "#F2F2F2"} Text { text: '<h3>Block details</h3>'; color: "#F2F2F2"}
Text { text: '<b>Block number:</b> ' + number; color: "#F2F2F2"} Text { text: '<b>Block number:</b> ' + number; color: "#F2F2F2"}
Text { text: '<b>Hash:</b> ' + hash; color: "#F2F2F2"} Text { text: '<b>Hash:</b> ' + hash; color: "#F2F2F2"}
Text { text: '<b>Coinbase:</b> ' + coinbase; color: "#F2F2F2"} Text { text: '<b>Coinbase:</b> &lt;' + name + '&gt; ' + coinbase; color: "#F2F2F2"}
Text { text: '<b>Block found at:</b> ' + prettyTime; color: "#F2F2F2"} Text { text: '<b>Block found at:</b> ' + prettyTime; color: "#F2F2F2"}
Text { text: '<b>Gas used:</b> ' + gasUsed + " / " + gasLimit; color: "#F2F2F2"} Text { text: '<b>Gas used:</b> ' + gasUsed + " / " + gasLimit; color: "#F2F2F2"}
} }
@ -577,6 +603,7 @@ ApplicationWindow {
Window { Window {
id: addPeerWin id: addPeerWin
//flags: Qt.CustomizeWindowHint | Qt.Tool | Qt.WindowCloseButtonHint
visible: false visible: false
minimumWidth: 230 minimumWidth: 230
maximumWidth: 230 maximumWidth: 230
@ -624,7 +651,7 @@ ApplicationWindow {
width: 150 width: 150
fillMode: Image.PreserveAspectFit fillMode: Image.PreserveAspectFit
smooth: true smooth: true
source: ui.assetPath("facet.png") source: "../facet.png"
x: 10 x: 10
y: 10 y: 10
} }
@ -633,7 +660,7 @@ ApplicationWindow {
anchors.left: aboutIcon.right anchors.left: aboutIcon.right
anchors.leftMargin: 10 anchors.leftMargin: 10
font.pointSize: 12 font.pointSize: 12
text: "<h2>Ethereal</h2><br><h3>Development</h3>Jeffrey Wilcke<br>Maran Hidskes<br>" text: "<h2>Ethereal</h2><br><h3>Development</h3>Jeffrey Wilcke<br>Maran Hidskes<br>Viktor Trón<br>"
} }
} }
@ -686,9 +713,9 @@ ApplicationWindow {
} }
if(initial){ if(initial){
blockModel.append({number: block.number, gasLimit: block.gasLimit, gasUsed: block.gasUsed, coinbase: block.coinbase, hash: block.hash, txs: txs, txAmount: amount, time: block.time, prettyTime: convertToPretty(block.time)}) 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{ }else{
blockModel.insert(0, {number: block.number, gasLimit: block.gasLimit, gasUsed: block.gasUsed, coinbase: block.coinbase, hash: block.hash, txs: txs, txAmount: amount, time: block.time, prettyTime: convertToPretty(block.time)}) 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)})
} }
} }
@ -743,6 +770,7 @@ ApplicationWindow {
// ****************************************** // ******************************************
Window { Window {
id: peerWindow id: peerWindow
//flags: Qt.CustomizeWindowHint | Qt.Tool | Qt.WindowCloseButtonHint
height: 200 height: 200
width: 700 width: 700
Rectangle { Rectangle {

View File

@ -38,7 +38,7 @@ ApplicationWindow {
experimental.preferences.javascriptEnabled: true experimental.preferences.javascriptEnabled: true
experimental.preferences.navigatorQtObjectEnabled: true experimental.preferences.navigatorQtObjectEnabled: true
experimental.preferences.developerExtrasEnabled: true experimental.preferences.developerExtrasEnabled: true
experimental.userScripts: [ui.assetPath("ext/pre.js"), ui.assetPath("ext/big.js"), ui.assetPath("ext/string.js"), ui.assetPath("ext/ethereum.js")] experimental.userScripts: ["../ext/pre.js", "../ext/big.js", "../ext/string.js", "../ext/ethereum.js"]
experimental.onMessageReceived: { experimental.onMessageReceived: {
console.log("[onMessageReceived]: ", message.data) console.log("[onMessageReceived]: ", message.data)
// TODO move to messaging.js // TODO move to messaging.js
@ -191,6 +191,7 @@ ApplicationWindow {
inspector.visible = false inspector.visible = false
}else{ }else{
inspector.visible = true inspector.visible = true
inspector.url = webview.experimental.remoteInspectorUrl
} }
} }
onDoubleClicked: { onDoubleClicked: {
@ -224,7 +225,6 @@ ApplicationWindow {
WebView { WebView {
id: inspector id: inspector
visible: false visible: false
url: webview.experimental.remoteInspectorUrl
anchors { anchors {
left: root.left left: root.left
right: root.right right: root.right
@ -238,7 +238,6 @@ ApplicationWindow {
name: "inspectorShown" name: "inspectorShown"
PropertyChanges { PropertyChanges {
target: inspector target: inspector
url: webview.experimental.remoteInspectorUrl
} }
} }
] ]

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 85 KiB

View File

@ -1,34 +0,0 @@
/* Space out content a bit */
body {
padding-top: 20px;
padding-bottom: 20px;
}
/* Everything but the jumbotron gets side spacing for mobile first
* views */
.header,
.marketing,
.footer {
padding-right: 15px;
padding-left: 15px;
}
/* Custom page header */
.header {
border-bottom: 1px solid #e5e5e5;
}
/* Make the masthead heading the same height as the navigation */
.header h3 {
padding-bottom: 19px;
margin-top: 0;
margin-bottom: 0;
line-height: 40px;
}
.jumbotron {
text-align: center;
border-bottom: 1px solid #e5e5e5;
margin: 0 auto;
width: 300px;
}

View File

@ -1,68 +0,0 @@
<html>
<head>
<title>jeffcoin</title>
<link rel="stylesheet" href="bootstrap.min.css">
<link rel="stylesheet" href="bootstrap-theme.min.css">
<link rel="stylesheet" href="samplecoin.css">
<meta name="viewport" content="minimum-scale=1; maximum-scale=1; initial-scale=1;">
<script type="text/javascript">
var jefcoinAddr = "22fa3ebce6ef9ca661a960104d3087eec040011e"
var mAddr = ""
function createTransaction() {
var addr = ("0x" + document.querySelector("#addr").value).pad(32);
var amount = document.querySelector("#amount").value.pad(32);
var data = (addr + amount).unbin();
eth.transact(mAddr, jefcoinAddr, 0, "50000", "1000000", data, function(receipt) {
debug("received tx hash:", reciept.address)
})
}
function init() {
eth.getKey(function(sec) {
mAddr = sec;
eth.getSecretToAddress(sec, function(addr) {
eth.getStorageAt(jefcoinAddr, addr, function(storage) {
document.querySelector("#current-amount").innerHTML = storage;
});
eth.watch(jefcoinAddr, addr, function(addr, value) {
document.querySelector("#current-amount").innerHTML = value
});
});
});
}
</script>
</head>
<body onload="init();">
<div class="container">
<div class="header">
<h3 class="text-muted">JeffCoin</h3>
</div>
<div class="jumbotron ">
<img src="icon.png">
<div>Amount: <strong id="current-amount"></strong></div>
<div id="transactions">
<div class="form-group">
<input id="addr" class="form-control" type="text" placeholder="Receiver address"></input><br>
<input id="amount" class="form-control" type="text" placeholder="Amount"></input><br>
</div>
<button class="btn btn-default" onclick="createTransaction();">Send Tx</button>
</div>
</div>
</div>
<div id="debug" style="border: 1px solid black; min-height: 30px;"></div>
</body>
</html>

339
ethereal/debugger.go Normal file
View File

@ -0,0 +1,339 @@
package main
import (
"fmt"
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethstate"
"github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/eth-go/ethvm"
"github.com/ethereum/go-ethereum/utils"
"github.com/go-qml/qml"
"math/big"
"strconv"
"strings"
)
type DebuggerWindow struct {
win *qml.Window
engine *qml.Engine
lib *UiLib
vm *ethvm.Vm
Db *Debugger
state *ethstate.State
}
func NewDebuggerWindow(lib *UiLib) *DebuggerWindow {
engine := qml.NewEngine()
component, err := engine.LoadFile(lib.AssetPath("debugger/debugger.qml"))
if err != nil {
fmt.Println(err)
return nil
}
win := component.CreateWindow(nil)
w := &DebuggerWindow{engine: engine, win: win, lib: lib, vm: &ethvm.Vm{}}
w.Db = NewDebugger(w)
return w
}
func (self *DebuggerWindow) Show() {
context := self.engine.Context()
context.SetVar("dbg", self)
go func() {
self.win.Show()
self.win.Wait()
}()
}
func (self *DebuggerWindow) SetCode(code string) {
self.win.Set("codeText", code)
}
func (self *DebuggerWindow) SetData(data string) {
self.win.Set("dataText", data)
}
func (self *DebuggerWindow) SetAsm(data []byte) {
self.win.Root().Call("clearAsm")
dis := ethchain.Disassemble(data)
for _, str := range dis {
self.win.Root().Call("setAsm", str)
}
}
func (self *DebuggerWindow) Compile(code string) {
var err error
script := ethutil.StringToByteFunc(code, func(s string) (ret []byte) {
ret, err = ethutil.Compile(s, true)
return
})
if err == nil {
self.SetAsm(script)
}
}
// Used by QML
func (self *DebuggerWindow) AutoComp(code string) {
if self.Db.done {
self.Compile(code)
}
}
func (self *DebuggerWindow) ClearLog() {
self.win.Root().Call("clearLog")
}
func (self *DebuggerWindow) Debug(valueStr, gasStr, gasPriceStr, scriptStr, dataStr string) {
if !self.Db.done {
self.Db.Q <- true
}
defer func() {
if r := recover(); r != nil {
self.Logf("compile FAULT: %v", r)
}
}()
data := ethutil.StringToByteFunc(dataStr, func(s string) (ret []byte) {
slice := strings.Split(dataStr, "\n")
for _, dataItem := range slice {
d := ethutil.FormatData(dataItem)
ret = append(ret, d...)
}
return
})
var err error
script := ethutil.StringToByteFunc(scriptStr, func(s string) (ret []byte) {
ret, err = ethutil.Compile(s, false)
return
})
if err != nil {
self.Logln(err)
return
}
var (
gas = ethutil.Big(gasStr)
gasPrice = ethutil.Big(gasPriceStr)
value = ethutil.Big(valueStr)
// Contract addr as test address
keyPair = self.lib.eth.KeyManager().KeyPair()
)
state := self.lib.eth.StateManager().TransState()
account := self.lib.eth.StateManager().TransState().GetAccount(keyPair.Address())
contract := ethstate.NewStateObject([]byte{0})
contract.Amount = value
self.SetAsm(script)
callerClosure := ethvm.NewClosure(account, contract, script, gas, gasPrice)
block := self.lib.eth.BlockChain().CurrentBlock
/*
vm := ethchain.NewVm(state, self.lib.eth.StateManager(), ethchain.RuntimeVars{
Block: block,
Origin: account.Address(),
BlockNumber: block.Number,
PrevHash: block.PrevHash,
Coinbase: block.Coinbase,
Time: block.Time,
Diff: block.Difficulty,
Value: ethutil.Big(valueStr),
})
*/
env := utils.NewEnv(state, block, account.Address(), value)
vm := ethvm.New(env)
vm.Verbose = true
vm.Dbg = self.Db
self.vm = vm
self.Db.done = false
self.Logf("callsize %d", len(script))
go func() {
ret, g, err := callerClosure.Call(vm, data)
tot := new(big.Int).Mul(g, gasPrice)
self.Logf("gas usage %v total price = %v (%v)", g, tot, ethutil.CurrencyToString(tot))
if err != nil {
self.Logln("exited with errors:", err)
} else {
if len(ret) > 0 {
self.Logf("exited: % x", ret)
} else {
self.Logf("exited: nil")
}
}
state.Reset()
if !self.Db.interrupt {
self.Db.done = true
} else {
self.Db.interrupt = false
}
}()
}
func (self *DebuggerWindow) Logf(format string, v ...interface{}) {
self.win.Root().Call("setLog", fmt.Sprintf(format, v...))
}
func (self *DebuggerWindow) Logln(v ...interface{}) {
str := fmt.Sprintln(v...)
self.Logf("%s", str[:len(str)-1])
}
func (self *DebuggerWindow) Next() {
self.Db.Next()
}
func (self *DebuggerWindow) Continue() {
self.vm.Stepping = false
self.Next()
}
func (self *DebuggerWindow) ExecCommand(command string) {
if len(command) > 0 {
cmd := strings.Split(command, " ")
switch cmd[0] {
case "help":
self.Logln("Debugger commands:")
self.Logln("break, bp Set breakpoint on instruction")
self.Logln("clear [log, break, bp] Clears previous set sub-command(s)")
case "break", "bp":
if len(cmd) > 1 {
lineNo, err := strconv.Atoi(cmd[1])
if err != nil {
self.Logln(err)
break
}
self.Db.breakPoints = append(self.Db.breakPoints, int64(lineNo))
self.Logf("break point set on instruction %d", lineNo)
} else {
self.Logf("'%s' requires line number", cmd[0])
}
case "clear":
if len(cmd) > 1 {
switch cmd[1] {
case "break", "bp":
self.Db.breakPoints = nil
self.Logln("Breakpoints cleared")
case "log":
self.ClearLog()
default:
self.Logf("clear '%s' is not valid", cmd[1])
}
} else {
self.Logln("'clear' requires sub command")
}
default:
self.Logf("Unknown command %s", cmd[0])
}
}
}
type Debugger struct {
N chan bool
Q chan bool
done, interrupt bool
breakPoints []int64
main *DebuggerWindow
win *qml.Window
}
func NewDebugger(main *DebuggerWindow) *Debugger {
db := &Debugger{make(chan bool), make(chan bool), true, false, nil, main, main.win}
return db
}
type storeVal struct {
Key, Value string
}
func (self *Debugger) BreakHook(pc int, op ethvm.OpCode, mem *ethvm.Memory, stack *ethvm.Stack, stateObject *ethstate.StateObject) bool {
self.main.Logln("break on instr:", pc)
return self.halting(pc, op, mem, stack, stateObject)
}
func (self *Debugger) StepHook(pc int, op ethvm.OpCode, mem *ethvm.Memory, stack *ethvm.Stack, stateObject *ethstate.StateObject) bool {
return self.halting(pc, op, mem, stack, stateObject)
}
func (self *Debugger) SetCode(byteCode []byte) {
self.main.SetAsm(byteCode)
}
func (self *Debugger) BreakPoints() []int64 {
return self.breakPoints
}
func (d *Debugger) halting(pc int, op ethvm.OpCode, mem *ethvm.Memory, stack *ethvm.Stack, stateObject *ethstate.StateObject) bool {
d.win.Root().Call("setInstruction", pc)
d.win.Root().Call("clearMem")
d.win.Root().Call("clearStack")
d.win.Root().Call("clearStorage")
addr := 0
for i := 0; i+32 <= mem.Len(); i += 32 {
d.win.Root().Call("setMem", memAddr{fmt.Sprintf("%03d", addr), fmt.Sprintf("% x", mem.Data()[i:i+32])})
addr++
}
for _, val := range stack.Data() {
d.win.Root().Call("setStack", val.String())
}
stateObject.EachStorage(func(key string, node *ethutil.Value) {
d.win.Root().Call("setStorage", storeVal{fmt.Sprintf("% x", key), fmt.Sprintf("% x", node.Str())})
})
out:
for {
select {
case <-d.N:
break out
case <-d.Q:
d.interrupt = true
d.clearBuffers()
return false
}
}
return true
}
func (d *Debugger) clearBuffers() {
out:
// drain
for {
select {
case <-d.N:
case <-d.Q:
default:
break out
}
}
}
func (d *Debugger) Next() {
if !d.done {
d.N <- true
}
}

View File

@ -1,9 +1,10 @@
package ethui package main
import ( import (
"fmt" "fmt"
"github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethpub" "github.com/ethereum/eth-go/ethpub"
"github.com/ethereum/eth-go/ethstate"
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethutil"
"github.com/go-qml/qml" "github.com/go-qml/qml"
) )
@ -16,8 +17,8 @@ type AppContainer interface {
Engine() *qml.Engine Engine() *qml.Engine
NewBlock(*ethchain.Block) NewBlock(*ethchain.Block)
ObjectChanged(*ethchain.StateObject) ObjectChanged(*ethstate.StateObject)
StorageChanged(*ethchain.StorageState) StorageChanged(*ethstate.StorageState)
NewWatcher(chan bool) NewWatcher(chan bool)
} }
@ -108,9 +109,9 @@ out:
app.container.NewBlock(block) app.container.NewBlock(block)
} }
case object := <-app.changeChan: case object := <-app.changeChan:
if stateObject, ok := object.Resource.(*ethchain.StateObject); ok { if stateObject, ok := object.Resource.(*ethstate.StateObject); ok {
app.container.ObjectChanged(stateObject) app.container.ObjectChanged(stateObject)
} else if storageObject, ok := object.Resource.(*ethchain.StorageState); ok { } else if storageObject, ok := object.Resource.(*ethstate.StorageState); ok {
app.container.StorageChanged(storageObject) app.container.StorageChanged(storageObject)
} }
} }

View File

@ -36,6 +36,7 @@ var LogLevel int
// flags specific to gui client // flags specific to gui client
var AssetPath string var AssetPath string
//TODO: If we re-use the one defined in cmd.go the binary osx image crashes. If somebody finds out why we can dry this up.
func defaultAssetPath() string { func defaultAssetPath() string {
var assetPath string var assetPath string
// If the current working directory is the go-ethereum dir // If the current working directory is the go-ethereum dir
@ -52,15 +53,14 @@ func defaultAssetPath() string {
assetPath = filepath.Join(exedir, "../Resources") assetPath = filepath.Join(exedir, "../Resources")
case "linux": case "linux":
assetPath = "/usr/share/ethereal" assetPath = "/usr/share/ethereal"
case "window": case "windows":
fallthrough assetPath = "./assets"
default: default:
assetPath = "." assetPath = "."
} }
} }
return assetPath return assetPath
} }
func defaultDataDir() string { func defaultDataDir() string {
usr, _ := user.Current() usr, _ := user.Current()
return path.Join(usr.HomeDir, ".ethereal") return path.Join(usr.HomeDir, ".ethereal")

View File

@ -1,4 +1,4 @@
package ethui package main
import ( import (
"bytes" "bytes"
@ -7,11 +7,14 @@ import (
"github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethdb" "github.com/ethereum/eth-go/ethdb"
"github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethlog"
"github.com/ethereum/eth-go/ethminer"
"github.com/ethereum/eth-go/ethpub" "github.com/ethereum/eth-go/ethpub"
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/eth-go/ethwire"
"github.com/ethereum/go-ethereum/utils" "github.com/ethereum/go-ethereum/utils"
"github.com/go-qml/qml" "github.com/go-qml/qml"
"math/big" "math/big"
"strconv"
"strings" "strings"
"time" "time"
) )
@ -36,12 +39,15 @@ type Gui struct {
logLevel ethlog.LogLevel logLevel ethlog.LogLevel
open bool open bool
Session string Session string
clientIdentity *ethwire.SimpleClientIdentity
config *ethutil.ConfigManager
miner *ethminer.Miner
} }
// Create GUI, but doesn't start it // Create GUI, but doesn't start it
func New(ethereum *eth.Ethereum, session string, logLevel int) *Gui { func NewWindow(ethereum *eth.Ethereum, config *ethutil.ConfigManager, clientIdentity *ethwire.SimpleClientIdentity, session string, logLevel int) *Gui {
db, err := ethdb.NewLDBDatabase("tx_database") db, err := ethdb.NewLDBDatabase("tx_database")
if err != nil { if err != nil {
panic(err) panic(err)
@ -49,11 +55,10 @@ func New(ethereum *eth.Ethereum, session string, logLevel int) *Gui {
pub := ethpub.NewPEthereum(ethereum) pub := ethpub.NewPEthereum(ethereum)
return &Gui{eth: ethereum, txDb: db, pub: pub, logLevel: ethlog.LogLevel(logLevel), Session: session, open: false} return &Gui{eth: ethereum, txDb: db, pub: pub, logLevel: ethlog.LogLevel(logLevel), Session: session, open: false, clientIdentity: clientIdentity, config: config}
} }
func (gui *Gui) Start(assetPath string) { func (gui *Gui) Start(assetPath string) {
const version = "0.5.16"
defer gui.txDb.Close() defer gui.txDb.Close()
@ -66,8 +71,6 @@ func (gui *Gui) Start(assetPath string) {
Init: func(p *ethpub.KeyVal, obj qml.Object) { p.Key = ""; p.Value = "" }, Init: func(p *ethpub.KeyVal, obj qml.Object) { p.Key = ""; p.Value = "" },
}}) }})
ethutil.Config.SetClientString("Ethereal")
// Create a new QML engine // Create a new QML engine
gui.engine = qml.NewEngine() gui.engine = qml.NewEngine()
context := gui.engine.Context() context := gui.engine.Context()
@ -104,14 +107,14 @@ func (gui *Gui) Start(assetPath string) {
ethlog.AddLogSystem(gui) ethlog.AddLogSystem(gui)
} }
win.Wait() win.Wait()
// need to silence gui logger after window closed otherwise logsystem hangs // need to silence gui logger after window closed otherwise logsystem hangs (but do not save loglevel)
gui.SetLogLevel(ethlog.Silence) gui.logLevel = ethlog.Silence
gui.open = false gui.open = false
} }
func (gui *Gui) Stop() { func (gui *Gui) Stop() {
if gui.open { if gui.open {
gui.SetLogLevel(ethlog.Silence) gui.logLevel = ethlog.Silence
gui.open = false gui.open = false
gui.win.Hide() gui.win.Hide()
} }
@ -125,6 +128,7 @@ func (gui *Gui) ToggleMining() {
txt = "Start mining" txt = "Start mining"
} else { } else {
utils.StartMining(gui.eth) utils.StartMining(gui.eth)
gui.miner = utils.GetMiner()
txt = "Stop mining" txt = "Stop mining"
} }
@ -139,10 +143,12 @@ func (gui *Gui) showWallet(context *qml.Context) (*qml.Window, error) {
win := gui.createWindow(component) win := gui.createWindow(component)
gui.setInitialBlockChain() go func() {
gui.loadAddressBook() gui.setInitialBlockChain()
gui.readPreviousTransactions() gui.loadAddressBook()
gui.setPeerInfo() gui.readPreviousTransactions()
gui.setPeerInfo()
}()
go gui.update() go gui.update()
@ -211,14 +217,16 @@ type address struct {
Name, Address string Name, Address string
} }
var namereg = ethutil.Hex2Bytes("bb5f186604d057c1c5240ca2ae0f6430138ac010")
func (gui *Gui) loadAddressBook() { func (gui *Gui) loadAddressBook() {
gui.win.Root().Call("clearAddress") gui.win.Root().Call("clearAddress")
stateObject := gui.eth.StateManager().CurrentState().GetStateObject(namereg)
if stateObject != nil { nameReg := ethpub.EthereumConfig(gui.eth.StateManager()).NameReg()
stateObject.State().EachStorage(func(name string, value *ethutil.Value) { if nameReg != nil {
gui.win.Root().Call("addAddress", struct{ Name, Address string }{name, ethutil.Bytes2Hex(value.Bytes())}) nameReg.EachStorage(func(name string, value *ethutil.Value) {
if name[0] != 0 {
value.Decode()
gui.win.Root().Call("addAddress", struct{ Name, Address string }{name, ethutil.Bytes2Hex(value.Bytes())})
}
}) })
} }
} }
@ -243,7 +251,11 @@ func (gui *Gui) readPreviousTransactions() {
} }
func (gui *Gui) processBlock(block *ethchain.Block, initial bool) { func (gui *Gui) processBlock(block *ethchain.Block, initial bool) {
gui.win.Root().Call("addBlock", ethpub.NewPBlock(block), initial) name := ethpub.FindNameInNameReg(gui.eth.StateManager(), block.Coinbase)
b := ethpub.NewPBlock(block)
b.Name = name
gui.win.Root().Call("addBlock", b, initial)
} }
func (gui *Gui) setWalletValue(amount, unconfirmedFunds *big.Int) { func (gui *Gui) setWalletValue(amount, unconfirmedFunds *big.Int) {
@ -262,27 +274,46 @@ func (gui *Gui) setWalletValue(amount, unconfirmedFunds *big.Int) {
gui.win.Root().Call("setWalletValue", str) gui.win.Root().Call("setWalletValue", str)
} }
func (self *Gui) getObjectByName(objectName string) qml.Object {
return self.win.Root().ObjectByName(objectName)
}
// Simple go routine function that updates the list of peers in the GUI // Simple go routine function that updates the list of peers in the GUI
func (gui *Gui) update() { func (gui *Gui) update() {
reactor := gui.eth.Reactor() reactor := gui.eth.Reactor()
blockChan := make(chan ethutil.React, 1) var (
txChan := make(chan ethutil.React, 1) blockChan = make(chan ethutil.React, 1)
objectChan := make(chan ethutil.React, 1) txChan = make(chan ethutil.React, 1)
peerChan := make(chan ethutil.React, 1) objectChan = make(chan ethutil.React, 1)
peerChan = make(chan ethutil.React, 1)
chainSyncChan = make(chan ethutil.React, 1)
miningChan = make(chan ethutil.React, 1)
)
reactor.Subscribe("newBlock", blockChan) reactor.Subscribe("newBlock", blockChan)
reactor.Subscribe("newTx:pre", txChan) reactor.Subscribe("newTx:pre", txChan)
reactor.Subscribe("newTx:post", txChan) reactor.Subscribe("newTx:post", txChan)
reactor.Subscribe("object:"+string(namereg), objectChan) reactor.Subscribe("chainSync", chainSyncChan)
reactor.Subscribe("miner:start", miningChan)
reactor.Subscribe("miner:stop", miningChan)
nameReg := ethpub.EthereumConfig(gui.eth.StateManager()).NameReg()
if nameReg != nil {
reactor.Subscribe("object:"+string(nameReg.Address()), objectChan)
}
reactor.Subscribe("peerList", peerChan) reactor.Subscribe("peerList", peerChan)
ticker := time.NewTicker(5 * time.Second) peerUpdateTicker := time.NewTicker(5 * time.Second)
generalUpdateTicker := time.NewTicker(1 * time.Second)
state := gui.eth.StateManager().TransState() state := gui.eth.StateManager().TransState()
unconfirmedFunds := new(big.Int) unconfirmedFunds := new(big.Int)
gui.win.Root().Call("setWalletValue", fmt.Sprintf("%v", ethutil.CurrencyToString(state.GetAccount(gui.address()).Amount))) gui.win.Root().Call("setWalletValue", fmt.Sprintf("%v", ethutil.CurrencyToString(state.GetAccount(gui.address()).Amount)))
gui.getObjectByName("syncProgressIndicator").Set("visible", !gui.eth.IsUpToDate())
lastBlockLabel := gui.getObjectByName("lastBlockLabel")
for { for {
select { select {
@ -324,12 +355,32 @@ func (gui *Gui) update() {
state.UpdateStateObject(object) state.UpdateStateObject(object)
} }
case msg := <-chainSyncChan:
sync := msg.Resource.(bool)
gui.win.Root().ObjectByName("syncProgressIndicator").Set("visible", sync)
case <-objectChan: case <-objectChan:
gui.loadAddressBook() gui.loadAddressBook()
case <-peerChan: case <-peerChan:
gui.setPeerInfo() gui.setPeerInfo()
case <-ticker.C: case <-peerUpdateTicker.C:
gui.setPeerInfo() gui.setPeerInfo()
case msg := <-miningChan:
if msg.Event == "miner:start" {
gui.miner = msg.Resource.(*ethminer.Miner)
} else {
gui.miner = nil
}
case <-generalUpdateTicker.C:
statusText := "#" + gui.eth.BlockChain().CurrentBlock.Number.String()
if gui.miner != nil {
pow := gui.miner.GetPow()
if pow.GetHashrate() != 0 {
statusText = "Mining @ " + strconv.FormatInt(pow.GetHashrate(), 10) + "Khash - " + statusText
}
}
lastBlockLabel.Set("text", statusText)
} }
} }
} }
@ -352,8 +403,9 @@ func (gui *Gui) address() []byte {
} }
func (gui *Gui) RegisterName(name string) { func (gui *Gui) RegisterName(name string) {
name = fmt.Sprintf("\"%s\"\n1", name) name = fmt.Sprintf("\"register\"\n\"%s\"", name)
gui.pub.Transact(gui.privateKey(), "namereg", "1000", "1000000", "150", name)
gui.pub.Transact(gui.privateKey(), "NameReg", "", "10000", "10000000000000", name)
} }
func (gui *Gui) Transact(recipient, value, gas, gasPrice, data string) (*ethpub.PReceipt, error) { func (gui *Gui) Transact(recipient, value, gas, gasPrice, data string) (*ethpub.PReceipt, error) {
@ -364,17 +416,19 @@ func (gui *Gui) Create(recipient, value, gas, gasPrice, data string) (*ethpub.PR
return gui.pub.Transact(gui.privateKey(), recipient, value, gas, gasPrice, data) return gui.pub.Transact(gui.privateKey(), recipient, value, gas, gasPrice, data)
} }
func (gui *Gui) ChangeClientId(id string) { func (gui *Gui) SetCustomIdentifier(customIdentifier string) {
ethutil.Config.SetIdentifier(id) gui.clientIdentity.SetCustomIdentifier(customIdentifier)
gui.config.Save("id", customIdentifier)
} }
func (gui *Gui) ClientId() string { func (gui *Gui) GetCustomIdentifier() string {
return ethutil.Config.Identifier return gui.clientIdentity.GetCustomIdentifier()
} }
// functions that allow Gui to implement interface ethlog.LogSystem // functions that allow Gui to implement interface ethlog.LogSystem
func (gui *Gui) SetLogLevel(level ethlog.LogLevel) { func (gui *Gui) SetLogLevel(level ethlog.LogLevel) {
gui.logLevel = level gui.logLevel = level
gui.config.Save("loglevel", level)
} }
func (gui *Gui) GetLogLevel() ethlog.LogLevel { func (gui *Gui) GetLogLevel() ethlog.LogLevel {

View File

@ -1,14 +1,14 @@
package ethui package main
import ( import (
"errors" "errors"
"github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethpub" "github.com/ethereum/eth-go/ethpub"
"github.com/ethereum/eth-go/ethstate"
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethutil"
"github.com/go-qml/qml" "github.com/go-qml/qml"
"github.com/howeyc/fsnotify" "github.com/howeyc/fsnotify"
"io/ioutil" "io/ioutil"
"log"
"net/url" "net/url"
"os" "os"
"path" "path"
@ -59,7 +59,7 @@ func (app *HtmlApplication) RootFolder() string {
if err != nil { if err != nil {
return "" return ""
} }
return path.Dir(folder.RequestURI()) return path.Dir(ethutil.WindonizePath(folder.RequestURI()))
} }
func (app *HtmlApplication) RecursiveFolders() []os.FileInfo { func (app *HtmlApplication) RecursiveFolders() []os.FileInfo {
files, _ := ioutil.ReadDir(app.RootFolder()) files, _ := ioutil.ReadDir(app.RootFolder())
@ -77,11 +77,13 @@ func (app *HtmlApplication) NewWatcher(quitChan chan bool) {
app.watcher, err = fsnotify.NewWatcher() app.watcher, err = fsnotify.NewWatcher()
if err != nil { if err != nil {
logger.Infoln("Could not create new auto-reload watcher:", err)
return return
} }
err = app.watcher.Watch(app.RootFolder()) err = app.watcher.Watch(app.RootFolder())
if err != nil { if err != nil {
log.Fatal(err) logger.Infoln("Could not start auto-reload watcher:", err)
return
} }
for _, folder := range app.RecursiveFolders() { for _, folder := range app.RecursiveFolders() {
fullPath := app.RootFolder() + "/" + folder.Name() fullPath := app.RootFolder() + "/" + folder.Name()
@ -120,11 +122,11 @@ func (app *HtmlApplication) NewBlock(block *ethchain.Block) {
app.webView.Call("onNewBlockCb", b) app.webView.Call("onNewBlockCb", b)
} }
func (app *HtmlApplication) ObjectChanged(stateObject *ethchain.StateObject) { func (app *HtmlApplication) ObjectChanged(stateObject *ethstate.StateObject) {
app.webView.Call("onObjectChangeCb", ethpub.NewPStateObject(stateObject)) app.webView.Call("onObjectChangeCb", ethpub.NewPStateObject(stateObject))
} }
func (app *HtmlApplication) StorageChanged(storageObject *ethchain.StorageState) { func (app *HtmlApplication) StorageChanged(storageObject *ethstate.StorageState) {
app.webView.Call("onStorageChangeCb", ethpub.NewPStorageState(storageObject)) app.webView.Call("onStorageChangeCb", ethpub.NewPStorageState(storageObject))
} }

View File

@ -2,19 +2,22 @@ package main
import ( import (
"github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethlog"
"github.com/ethereum/go-ethereum/ethereal/ui"
"github.com/ethereum/go-ethereum/utils" "github.com/ethereum/go-ethereum/utils"
"github.com/go-qml/qml" "github.com/go-qml/qml"
"os" "os"
"runtime" "runtime"
) )
func main() { const (
// Leave QT on top at ALL times. Qt Needs to be initialized from the main thread ClientIdentifier = "Ethereal"
qml.Init(nil) Version = "0.6.0"
)
func main() {
runtime.GOMAXPROCS(runtime.NumCPU()) runtime.GOMAXPROCS(runtime.NumCPU())
qml.Init(nil)
var interrupted = false var interrupted = false
utils.RegisterInterrupt(func(os.Signal) { utils.RegisterInterrupt(func(os.Signal) {
interrupted = true interrupted = true
@ -24,7 +27,8 @@ func main() {
// precedence: code-internal flag default < config file < environment variables < command line // precedence: code-internal flag default < config file < environment variables < command line
Init() // parsing command line Init() // parsing command line
utils.InitConfig(ConfigFile, Datadir, Identifier, "ETH")
config := utils.InitConfig(ConfigFile, Datadir, "ETH")
utils.InitDataDir(Datadir) utils.InitDataDir(Datadir)
@ -37,7 +41,9 @@ func main() {
// create, import, export keys // create, import, export keys
utils.KeyTasks(keyManager, KeyRing, GenAddr, SecretFile, ExportDir, NonInteractive) utils.KeyTasks(keyManager, KeyRing, GenAddr, SecretFile, ExportDir, NonInteractive)
ethereum := utils.NewEthereum(db, keyManager, UseUPnP, OutboundPort, MaxPeer) clientIdentity := utils.NewClientIdentity(ClientIdentifier, Version, Identifier)
ethereum := utils.NewEthereum(db, clientIdentity, keyManager, UseUPnP, OutboundPort, MaxPeer)
if ShowGenesis { if ShowGenesis {
utils.ShowGenesis(ethereum) utils.ShowGenesis(ethereum)
@ -47,7 +53,7 @@ func main() {
utils.StartRpc(ethereum, RpcPort) utils.StartRpc(ethereum, RpcPort)
} }
gui := ethui.New(ethereum, KeyRing, LogLevel) gui := NewWindow(ethereum, config, clientIdentity, KeyRing, LogLevel)
utils.RegisterInterrupt(func(os.Signal) { utils.RegisterInterrupt(func(os.Signal) {
gui.Stop() gui.Stop()

View File

@ -1,10 +1,12 @@
package ethui package main
import ( import (
"github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethpub" "github.com/ethereum/eth-go/ethpub"
"github.com/ethereum/eth-go/ethstate"
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethutil"
"github.com/go-qml/qml" "github.com/go-qml/qml"
"runtime"
) )
type QmlApplication struct { type QmlApplication struct {
@ -20,7 +22,14 @@ func NewQmlApplication(path string, lib *UiLib) *QmlApplication {
} }
func (app *QmlApplication) Create() error { func (app *QmlApplication) Create() error {
component, err := app.engine.LoadFile(app.path) path := string(app.path)
// For some reason for windows we get /c:/path/to/something, windows doesn't like the first slash but is fine with the others so we are removing it
if string(app.path[0]) == "/" && runtime.GOOS == "windows" {
path = app.path[1:]
}
component, err := app.engine.LoadFile(path)
if err != nil { if err != nil {
logger.Warnln(err) logger.Warnln(err)
} }
@ -42,11 +51,11 @@ func (app *QmlApplication) NewBlock(block *ethchain.Block) {
app.win.Call("onNewBlockCb", pblock) app.win.Call("onNewBlockCb", pblock)
} }
func (app *QmlApplication) ObjectChanged(stateObject *ethchain.StateObject) { func (app *QmlApplication) ObjectChanged(stateObject *ethstate.StateObject) {
app.win.Call("onObjectChangeCb", ethpub.NewPStateObject(stateObject)) app.win.Call("onObjectChangeCb", ethpub.NewPStateObject(stateObject))
} }
func (app *QmlApplication) StorageChanged(storageObject *ethchain.StorageState) { func (app *QmlApplication) StorageChanged(storageObject *ethstate.StorageState) {
app.win.Call("onStorageChangeCb", ethpub.NewPStorageState(storageObject)) app.win.Call("onStorageChangeCb", ethpub.NewPStorageState(storageObject))
} }

View File

@ -1,234 +0,0 @@
package ethui
import (
"fmt"
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethutil"
"github.com/go-qml/qml"
"math/big"
"strings"
)
type DebuggerWindow struct {
win *qml.Window
engine *qml.Engine
lib *UiLib
Db *Debugger
}
func NewDebuggerWindow(lib *UiLib) *DebuggerWindow {
engine := qml.NewEngine()
component, err := engine.LoadFile(lib.AssetPath("debugger/debugger.qml"))
if err != nil {
fmt.Println(err)
return nil
}
win := component.CreateWindow(nil)
db := &Debugger{win, make(chan bool), make(chan bool), true, false, true}
return &DebuggerWindow{engine: engine, win: win, lib: lib, Db: db}
}
func (self *DebuggerWindow) Show() {
context := self.engine.Context()
context.SetVar("dbg", self)
go func() {
self.win.Show()
self.win.Wait()
}()
}
func (self *DebuggerWindow) SetCode(code string) {
self.win.Set("codeText", code)
}
func (self *DebuggerWindow) SetData(data string) {
self.win.Set("dataText", data)
}
func (self *DebuggerWindow) SetAsm(data string) {
dis := ethchain.Disassemble(ethutil.Hex2Bytes(data))
for _, str := range dis {
self.win.Root().Call("setAsm", str)
}
}
func (self *DebuggerWindow) Debug(valueStr, gasStr, gasPriceStr, scriptStr, dataStr string) {
if !self.Db.done {
self.Db.Q <- true
}
self.Db.breakOnInstr = self.win.Root().ObjectByName("breakEachLine").Bool("checked")
defer func() {
if r := recover(); r != nil {
self.Logf("compile FAULT: %v", r)
}
}()
data := ethutil.StringToByteFunc(dataStr, func(s string) (ret []byte) {
slice := strings.Split(dataStr, "\n")
for _, dataItem := range slice {
d := ethutil.FormatData(dataItem)
ret = append(ret, d...)
}
return
})
var err error
script := ethutil.StringToByteFunc(scriptStr, func(s string) (ret []byte) {
ret, err = ethutil.Compile(s)
return
})
if err != nil {
self.Logln(err)
return
}
dis := ethchain.Disassemble(script)
self.win.Root().Call("clearAsm")
self.win.Root().Call("clearLog")
for _, str := range dis {
self.win.Root().Call("setAsm", str)
}
var (
gas = ethutil.Big(gasStr)
gasPrice = ethutil.Big(gasPriceStr)
value = ethutil.Big(valueStr)
// Contract addr as test address
keyPair = self.lib.eth.KeyManager().KeyPair()
callerTx = ethchain.NewContractCreationTx(ethutil.Big(valueStr), gas, gasPrice, script)
)
callerTx.Sign(keyPair.PrivateKey)
state := self.lib.eth.BlockChain().CurrentBlock.State()
account := self.lib.eth.StateManager().TransState().GetAccount(keyPair.Address())
contract := ethchain.MakeContract(callerTx, state)
contract.Amount = value
callerClosure := ethchain.NewClosure(account, contract, script, state, gas, gasPrice)
block := self.lib.eth.BlockChain().CurrentBlock
vm := ethchain.NewVm(state, self.lib.eth.StateManager(), ethchain.RuntimeVars{
Block: block,
Origin: account.Address(),
BlockNumber: block.Number,
PrevHash: block.PrevHash,
Coinbase: block.Coinbase,
Time: block.Time,
Diff: block.Difficulty,
Value: ethutil.Big(valueStr),
})
vm.Verbose = true
self.Db.done = false
self.Logf("callsize %d", len(script))
go func() {
ret, g, err := callerClosure.Call(vm, data, self.Db.halting)
tot := new(big.Int).Mul(g, gasPrice)
self.Logf("gas usage %v total price = %v (%v)", g, tot, ethutil.CurrencyToString(tot))
if err != nil {
self.Logln("exited with errors:", err)
} else {
if len(ret) > 0 {
self.Logf("exited: % x", ret)
} else {
self.Logf("exited: nil")
}
}
state.Reset()
if !self.Db.interrupt {
self.Db.done = true
} else {
self.Db.interrupt = false
}
}()
}
func (self *DebuggerWindow) Logf(format string, v ...interface{}) {
self.win.Root().Call("setLog", fmt.Sprintf(format, v...))
}
func (self *DebuggerWindow) Logln(v ...interface{}) {
str := fmt.Sprintln(v...)
self.Logf("%s", str[:len(str)-1])
}
func (self *DebuggerWindow) Next() {
self.Db.Next()
}
type Debugger struct {
win *qml.Window
N chan bool
Q chan bool
done, interrupt bool
breakOnInstr bool
}
type storeVal struct {
Key, Value string
}
func (d *Debugger) halting(pc int, op ethchain.OpCode, mem *ethchain.Memory, stack *ethchain.Stack, stateObject *ethchain.StateObject) bool {
d.win.Root().Call("setInstruction", pc)
d.win.Root().Call("clearMem")
d.win.Root().Call("clearStack")
d.win.Root().Call("clearStorage")
addr := 0
for i := 0; i+32 <= mem.Len(); i += 32 {
d.win.Root().Call("setMem", memAddr{fmt.Sprintf("%03d", addr), fmt.Sprintf("% x", mem.Data()[i:i+32])})
addr++
}
for _, val := range stack.Data() {
d.win.Root().Call("setStack", val.String())
}
stateObject.State().EachStorage(func(key string, node *ethutil.Value) {
d.win.Root().Call("setStorage", storeVal{fmt.Sprintf("% x", key), fmt.Sprintf("% x", node.Str())})
})
if d.breakOnInstr {
out:
for {
select {
case <-d.N:
break out
case <-d.Q:
d.interrupt = true
d.clearBuffers()
return false
}
}
}
return true
}
func (d *Debugger) clearBuffers() {
out:
// drain
for {
select {
case <-d.N:
case <-d.Q:
default:
break out
}
}
}
func (d *Debugger) Next() {
if !d.done {
d.N <- true
}
}

View File

@ -1,4 +1,4 @@
package ethui package main
import ( import (
"github.com/ethereum/eth-go" "github.com/ethereum/eth-go"
@ -78,8 +78,8 @@ func (ui *UiLib) AssetPath(p string) string {
func (self *UiLib) StartDbWithContractAndData(contractHash, data string) { func (self *UiLib) StartDbWithContractAndData(contractHash, data string) {
dbWindow := NewDebuggerWindow(self) dbWindow := NewDebuggerWindow(self)
object := self.eth.StateManager().CurrentState().GetStateObject(ethutil.Hex2Bytes(contractHash)) object := self.eth.StateManager().CurrentState().GetStateObject(ethutil.Hex2Bytes(contractHash))
if len(object.Script()) > 0 { if len(object.Code) > 0 {
dbWindow.SetCode("0x" + ethutil.Bytes2Hex(object.Script())) dbWindow.SetCode("0x" + ethutil.Bytes2Hex(object.Code))
} }
dbWindow.SetData("0x" + data) dbWindow.SetData("0x" + data)

View File

@ -2,13 +2,14 @@ package main
import ( import (
"github.com/ethereum/eth-go" "github.com/ethereum/eth-go"
"github.com/ethereum/go-ethereum/ethereum/repl"
"github.com/ethereum/go-ethereum/utils" "github.com/ethereum/go-ethereum/utils"
"io/ioutil" "io/ioutil"
"os" "os"
) )
func InitJsConsole(ethereum *eth.Ethereum) { func InitJsConsole(ethereum *eth.Ethereum) {
repl := NewJSRepl(ethereum) repl := ethrepl.NewJSRepl(ethereum)
go repl.Start() go repl.Start()
utils.RegisterInterrupt(func(os.Signal) { utils.RegisterInterrupt(func(os.Signal) {
repl.Stop() repl.Stop()
@ -24,7 +25,7 @@ func ExecJsFile(ethereum *eth.Ethereum, InputFile string) {
if err != nil { if err != nil {
logger.Fatalln(err) logger.Fatalln(err)
} }
re := NewJSRE(ethereum) re := ethrepl.NewJSRE(ethereum)
utils.RegisterInterrupt(func(os.Signal) { utils.RegisterInterrupt(func(os.Signal) {
re.Stop() re.Stop()
}) })

View File

@ -11,6 +11,8 @@ import (
var Identifier string var Identifier string
var KeyRing string var KeyRing string
var DiffTool bool
var DiffType string
var KeyStore string var KeyStore string
var StartRpc bool var StartRpc bool
var RpcPort int var RpcPort int
@ -66,6 +68,8 @@ func Init() {
flag.StringVar(&ConfigFile, "conf", defaultConfigFile, "config file") flag.StringVar(&ConfigFile, "conf", defaultConfigFile, "config file")
flag.StringVar(&DebugFile, "debug", "", "debug file (no debugging if not set)") flag.StringVar(&DebugFile, "debug", "", "debug file (no debugging if not set)")
flag.IntVar(&LogLevel, "loglevel", int(ethlog.InfoLevel), "loglevel: 0-5: silent,error,warn,info,debug,debug detail)") flag.IntVar(&LogLevel, "loglevel", int(ethlog.InfoLevel), "loglevel: 0-5: silent,error,warn,info,debug,debug detail)")
flag.BoolVar(&DiffTool, "difftool", false, "creates output for diff'ing. Sets LogLevel=0")
flag.StringVar(&DiffType, "diff", "all", "sets the level of diff output [vm, all]. Has no effect if difftool=false")
flag.BoolVar(&StartMining, "mine", false, "start dagger mining") flag.BoolVar(&StartMining, "mine", false, "start dagger mining")
flag.BoolVar(&StartJsConsole, "js", false, "launches javascript console") flag.BoolVar(&StartJsConsole, "js", false, "launches javascript console")

View File

@ -2,10 +2,16 @@ package main
import ( import (
"github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethlog"
"github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/go-ethereum/utils" "github.com/ethereum/go-ethereum/utils"
"runtime" "runtime"
) )
const (
ClientIdentifier = "Ethereum(G)"
Version = "0.6.0"
)
var logger = ethlog.NewLogger("CLI") var logger = ethlog.NewLogger("CLI")
func main() { func main() {
@ -15,7 +21,15 @@ func main() {
// precedence: code-internal flag default < config file < environment variables < command line // precedence: code-internal flag default < config file < environment variables < command line
Init() // parsing command line Init() // parsing command line
utils.InitConfig(ConfigFile, Datadir, Identifier, "ETH")
// If the difftool option is selected ignore all other log output
if DiffTool {
LogLevel = 0
}
utils.InitConfig(ConfigFile, Datadir, "ETH")
ethutil.Config.Diff = DiffTool
ethutil.Config.DiffType = DiffType
utils.InitDataDir(Datadir) utils.InitDataDir(Datadir)
@ -28,7 +42,9 @@ func main() {
// create, import, export keys // create, import, export keys
utils.KeyTasks(keyManager, KeyRing, GenAddr, SecretFile, ExportDir, NonInteractive) utils.KeyTasks(keyManager, KeyRing, GenAddr, SecretFile, ExportDir, NonInteractive)
ethereum := utils.NewEthereum(db, keyManager, UseUPnP, OutboundPort, MaxPeer) clientIdentity := utils.NewClientIdentity(ClientIdentifier, Version, Identifier)
ethereum := utils.NewEthereum(db, clientIdentity, keyManager, UseUPnP, OutboundPort, MaxPeer)
if ShowGenesis { if ShowGenesis {
utils.ShowGenesis(ethereum) utils.ShowGenesis(ethereum)

View File

@ -1,4 +1,4 @@
package main package ethrepl
import ( import (
"fmt" "fmt"
@ -6,6 +6,7 @@ import (
"github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethlog"
"github.com/ethereum/eth-go/ethpub" "github.com/ethereum/eth-go/ethpub"
"github.com/ethereum/eth-go/ethstate"
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/go-ethereum/utils" "github.com/ethereum/go-ethereum/utils"
"github.com/obscuren/otto" "github.com/obscuren/otto"
@ -121,12 +122,12 @@ out:
if _, ok := block.Resource.(*ethchain.Block); ok { if _, ok := block.Resource.(*ethchain.Block); ok {
} }
case object := <-self.changeChan: case object := <-self.changeChan:
if stateObject, ok := object.Resource.(*ethchain.StateObject); ok { if stateObject, ok := object.Resource.(*ethstate.StateObject); ok {
for _, cb := range self.objectCb[ethutil.Bytes2Hex(stateObject.Address())] { for _, cb := range self.objectCb[ethutil.Bytes2Hex(stateObject.Address())] {
val, _ := self.vm.ToValue(ethpub.NewPStateObject(stateObject)) val, _ := self.vm.ToValue(ethpub.NewPStateObject(stateObject))
cb.Call(cb, val) cb.Call(cb, val)
} }
} else if storageObject, ok := object.Resource.(*ethchain.StorageState); ok { } else if storageObject, ok := object.Resource.(*ethstate.StorageState); ok {
for _, cb := range self.objectCb[ethutil.Bytes2Hex(storageObject.StateAddress)+ethutil.Bytes2Hex(storageObject.Address)] { for _, cb := range self.objectCb[ethutil.Bytes2Hex(storageObject.StateAddress)+ethutil.Bytes2Hex(storageObject.Address)] {
val, _ := self.vm.ToValue(ethpub.NewPStorageState(storageObject)) val, _ := self.vm.ToValue(ethpub.NewPStorageState(storageObject))
cb.Call(cb, val) cb.Call(cb, val)

View File

@ -1,4 +1,4 @@
package main package ethrepl
const jsLib = ` const jsLib = `
function pp(object) { function pp(object) {

83
ethereum/repl/repl.go Normal file
View File

@ -0,0 +1,83 @@
package ethrepl
import (
"bufio"
"fmt"
"github.com/ethereum/eth-go"
"github.com/ethereum/eth-go/ethlog"
"github.com/ethereum/eth-go/ethutil"
"io"
"os"
"path"
)
var logger = ethlog.NewLogger("REPL")
type Repl interface {
Start()
Stop()
}
type JSRepl struct {
re *JSRE
prompt string
history *os.File
running bool
}
func NewJSRepl(ethereum *eth.Ethereum) *JSRepl {
hist, err := os.OpenFile(path.Join(ethutil.Config.ExecPath, "history"), os.O_RDWR|os.O_CREATE, os.ModePerm)
if err != nil {
panic(err)
}
return &JSRepl{re: NewJSRE(ethereum), prompt: "> ", history: hist}
}
func (self *JSRepl) Start() {
if !self.running {
self.running = true
logger.Infoln("init JS Console")
reader := bufio.NewReader(self.history)
for {
line, err := reader.ReadString('\n')
if err != nil && err == io.EOF {
break
} else if err != nil {
fmt.Println("error reading history", err)
break
}
addHistory(line[:len(line)-1])
}
self.read()
}
}
func (self *JSRepl) Stop() {
if self.running {
self.running = false
self.re.Stop()
logger.Infoln("exit JS Console")
self.history.Close()
}
}
func (self *JSRepl) parseInput(code string) {
defer func() {
if r := recover(); r != nil {
fmt.Println("[native] error", r)
}
}()
value, err := self.re.Run(code)
if err != nil {
fmt.Println(err)
return
}
self.PrintValue(value)
}

View File

@ -1,4 +1,4 @@
package main package ethrepl
// #cgo darwin CFLAGS: -I/usr/local/opt/readline/include // #cgo darwin CFLAGS: -I/usr/local/opt/readline/include
// #cgo darwin LDFLAGS: -L/usr/local/opt/readline/lib // #cgo darwin LDFLAGS: -L/usr/local/opt/readline/lib

View File

@ -1,4 +1,4 @@
package main package ethrepl
import ( import (
"bufio" "bufio"

View File

@ -1,84 +1,26 @@
package main package ethrepl
import ( import (
"bufio"
"fmt" "fmt"
"github.com/ethereum/eth-go"
"github.com/ethereum/eth-go/ethpub" "github.com/ethereum/eth-go/ethpub"
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethutil"
"github.com/obscuren/otto" "github.com/obscuren/otto"
"io"
"os"
"path"
) )
type Repl interface { type JSStateObject struct {
Start() *ethpub.PStateObject
Stop() eth *JSEthereum
} }
type JSRepl struct { func (self *JSStateObject) EachStorage(call otto.FunctionCall) otto.Value {
re *JSRE cb := call.Argument(0)
self.PStateObject.EachStorage(func(key string, value *ethutil.Value) {
value.Decode()
prompt string cb.Call(self.eth.toVal(self), self.eth.toVal(key), self.eth.toVal(ethutil.Bytes2Hex(value.Bytes())))
})
history *os.File return otto.UndefinedValue()
running bool
}
func NewJSRepl(ethereum *eth.Ethereum) *JSRepl {
hist, err := os.OpenFile(path.Join(ethutil.Config.ExecPath, "history"), os.O_RDWR|os.O_CREATE, os.ModePerm)
if err != nil {
panic(err)
}
return &JSRepl{re: NewJSRE(ethereum), prompt: "> ", history: hist}
}
func (self *JSRepl) Start() {
if !self.running {
self.running = true
logger.Infoln("init JS Console")
reader := bufio.NewReader(self.history)
for {
line, err := reader.ReadString('\n')
if err != nil && err == io.EOF {
break
} else if err != nil {
fmt.Println("error reading history", err)
break
}
addHistory(line[:len(line)-1])
}
self.read()
}
}
func (self *JSRepl) Stop() {
if self.running {
self.running = false
self.re.Stop()
logger.Infoln("exit JS Console")
self.history.Close()
}
}
func (self *JSRepl) parseInput(code string) {
defer func() {
if r := recover(); r != nil {
fmt.Println("[native] error", r)
}
}()
value, err := self.re.Run(code)
if err != nil {
fmt.Println(err)
return
}
self.PrintValue(value)
} }
// The JSEthereum object attempts to wrap the PEthereum object and returns // The JSEthereum object attempts to wrap the PEthereum object and returns
@ -110,7 +52,7 @@ func (self *JSEthereum) GetKey() otto.Value {
} }
func (self *JSEthereum) GetStateObject(addr string) otto.Value { func (self *JSEthereum) GetStateObject(addr string) otto.Value {
return self.toVal(self.PEthereum.GetStateObject(addr)) return self.toVal(&JSStateObject{self.PEthereum.GetStateObject(addr), self})
} }
func (self *JSEthereum) GetStateKeyVals(addr string) otto.Value { func (self *JSEthereum) GetStateKeyVals(addr string) otto.Value {

View File

@ -1,6 +1,7 @@
package utils package utils
import ( import (
"bitbucket.org/kardianos/osext"
"fmt" "fmt"
"github.com/ethereum/eth-go" "github.com/ethereum/eth-go"
"github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethcrypto"
@ -10,11 +11,14 @@ import (
"github.com/ethereum/eth-go/ethpub" "github.com/ethereum/eth-go/ethpub"
"github.com/ethereum/eth-go/ethrpc" "github.com/ethereum/eth-go/ethrpc"
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/eth-go/ethwire"
"io" "io"
"log" "log"
"os" "os"
"os/signal" "os/signal"
"path" "path"
"path/filepath"
"runtime"
"time" "time"
) )
@ -98,14 +102,15 @@ func InitLogging(Datadir string, LogFile string, LogLevel int, DebugFile string)
} }
} }
func InitConfig(ConfigFile string, Datadir string, Identifier string, EnvPrefix string) { func InitConfig(ConfigFile string, Datadir string, EnvPrefix string) *ethutil.ConfigManager {
InitDataDir(Datadir) InitDataDir(Datadir)
ethutil.ReadConfig(ConfigFile, Datadir, Identifier, EnvPrefix) return ethutil.ReadConfig(ConfigFile, Datadir, EnvPrefix)
} }
func exit(err error) { func exit(err error) {
status := 0 status := 0
if err != nil { if err != nil {
fmt.Println(err)
logger.Errorln("Fatal: ", err) logger.Errorln("Fatal: ", err)
status = 1 status = 1
} }
@ -121,8 +126,12 @@ func NewDatabase() ethutil.Database {
return db return db
} }
func NewEthereum(db ethutil.Database, keyManager *ethcrypto.KeyManager, usePnp bool, OutboundPort string, MaxPeer int) *eth.Ethereum { func NewClientIdentity(clientIdentifier, version, customIdentifier string) *ethwire.SimpleClientIdentity {
ethereum, err := eth.New(db, keyManager, eth.CapDefault, usePnp) return ethwire.NewSimpleClientIdentity(clientIdentifier, version, customIdentifier)
}
func NewEthereum(db ethutil.Database, clientIdentity ethwire.ClientIdentity, keyManager *ethcrypto.KeyManager, usePnp bool, OutboundPort string, MaxPeer int) *eth.Ethereum {
ethereum, err := eth.New(db, clientIdentity, keyManager, eth.CapDefault, usePnp)
if err != nil { if err != nil {
logger.Fatalln("eth start err:", err) logger.Fatalln("eth start err:", err)
} }
@ -132,7 +141,7 @@ func NewEthereum(db ethutil.Database, keyManager *ethcrypto.KeyManager, usePnp b
} }
func StartEthereum(ethereum *eth.Ethereum, UseSeed bool) { func StartEthereum(ethereum *eth.Ethereum, UseSeed bool) {
logger.Infof("Starting Ethereum v%s", ethutil.Config.Ver) logger.Infof("Starting %s", ethereum.ClientIdentity())
ethereum.Start(UseSeed) ethereum.Start(UseSeed)
RegisterInterrupt(func(sig os.Signal) { RegisterInterrupt(func(sig os.Signal) {
ethereum.Stop() ethereum.Stop()
@ -158,7 +167,34 @@ func NewKeyManager(KeyStore string, Datadir string, db ethutil.Database) *ethcry
return keyManager return keyManager
} }
func DefaultAssetPath() string {
var assetPath string
// If the current working directory is the go-ethereum dir
// assume a debug build and use the source directory as
// asset directory.
pwd, _ := os.Getwd()
if pwd == path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "ethereal") {
assetPath = path.Join(pwd, "assets")
} else {
switch runtime.GOOS {
case "darwin":
// Get Binary Directory
exedir, _ := osext.ExecutableFolder()
assetPath = filepath.Join(exedir, "../Resources")
case "linux":
assetPath = "/usr/share/ethereal"
case "windows":
assetPath = "./assets"
default:
assetPath = "."
}
}
return assetPath
}
func KeyTasks(keyManager *ethcrypto.KeyManager, KeyRing string, GenAddr bool, SecretFile string, ExportDir string, NonInteractive bool) { func KeyTasks(keyManager *ethcrypto.KeyManager, KeyRing string, GenAddr bool, SecretFile string, ExportDir string, NonInteractive bool) {
ethcrypto.InitWords(DefaultAssetPath()) // Init mnemonic word list
var err error var err error
switch { switch {
case GenAddr: case GenAddr:
@ -167,6 +203,8 @@ func KeyTasks(keyManager *ethcrypto.KeyManager, KeyRing string, GenAddr bool, Se
} }
exit(err) exit(err)
case len(SecretFile) > 0: case len(SecretFile) > 0:
SecretFile = ethutil.ExpandHomePath(SecretFile)
if NonInteractive || confirm("This action overwrites your old private key.") { if NonInteractive || confirm("This action overwrites your old private key.") {
err = keyManager.InitFromSecretsFile(KeyRing, 0, SecretFile) err = keyManager.InitFromSecretsFile(KeyRing, 0, SecretFile)
} }
@ -196,7 +234,11 @@ func StartRpc(ethereum *eth.Ethereum, RpcPort int) {
} }
} }
var miner ethminer.Miner var miner *ethminer.Miner
func GetMiner() *ethminer.Miner {
return miner
}
func StartMining(ethereum *eth.Ethereum) bool { func StartMining(ethereum *eth.Ethereum) bool {
if !ethereum.Mining { if !ethereum.Mining {
@ -205,7 +247,10 @@ func StartMining(ethereum *eth.Ethereum) bool {
addr := ethereum.KeyManager().Address() addr := ethereum.KeyManager().Address()
go func() { go func() {
miner = ethminer.NewDefaultMiner(addr, ethereum) if miner == nil {
miner = ethminer.NewDefaultMiner(addr, ethereum)
}
// Give it some time to connect with peers // Give it some time to connect with peers
time.Sleep(3 * time.Second) time.Sleep(3 * time.Second)
for !ethereum.IsUpToDate() { for !ethereum.IsUpToDate() {
@ -213,7 +258,6 @@ func StartMining(ethereum *eth.Ethereum) bool {
} }
logger.Infoln("Miner started") logger.Infoln("Miner started")
miner := ethminer.NewDefaultMiner(addr, ethereum)
miner.Start() miner.Start()
}() }()
RegisterInterrupt(func(os.Signal) { RegisterInterrupt(func(os.Signal) {
@ -225,12 +269,16 @@ func StartMining(ethereum *eth.Ethereum) bool {
} }
func StopMining(ethereum *eth.Ethereum) bool { func StopMining(ethereum *eth.Ethereum) bool {
if ethereum.Mining { if ethereum.Mining && miner != nil {
miner.Stop() miner.Stop()
logger.Infoln("Miner stopped") logger.Infoln("Miner stopped")
ethereum.Mining = false ethereum.Mining = false
return true return true
} }
return false return false
} }

33
utils/vm_env.go Normal file
View File

@ -0,0 +1,33 @@
package utils
import (
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethstate"
"math/big"
)
type VMEnv struct {
state *ethstate.State
block *ethchain.Block
transactor []byte
value *big.Int
}
func NewEnv(state *ethstate.State, block *ethchain.Block, transactor []byte, value *big.Int) *VMEnv {
return &VMEnv{
state: state,
block: block,
transactor: transactor,
value: value,
}
}
func (self *VMEnv) Origin() []byte { return self.transactor }
func (self *VMEnv) BlockNumber() *big.Int { return self.block.Number }
func (self *VMEnv) PrevHash() []byte { return self.block.PrevHash }
func (self *VMEnv) Coinbase() []byte { return self.block.Coinbase }
func (self *VMEnv) Time() int64 { return self.block.Time }
func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty }
func (self *VMEnv) Value() *big.Int { return self.value }
func (self *VMEnv) State() *ethstate.State { return self.state }