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.
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).

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
ApplicationWindow {
id: win
visible: false
title: "IceCREAM"
minimumWidth: 1280
minimumHeight: 700
width: 1290
height: 700
height: 750
property alias codeText: codeEditor.text
property alias dataText: rawDataField.text
onClosing: {
//compileTimer.stop()
}
MenuBar {
Menu {
title: "Debugger"
@ -31,18 +36,57 @@ ApplicationWindow {
shortcut: "Ctrl+n"
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 {
anchors.fill: parent
property var asmModel: ListModel {
id: asmModel
}
TableView {
id: asmTableView
width: 200
TableViewColumn{ role: "value" ; title: "" ; width: 200 }
TableViewColumn{ role: "value" ; title: "" ; width: asmTableView.width - 2 }
model: asmModel
}
@ -66,6 +110,17 @@ ApplicationWindow {
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: settings.left
focus: true
/*
Timer {
id: compileTimer
interval: 500 ; running: true ; repeat: true
onTriggered: {
dbg.autoComp(codeEditor.text)
}
}
*/
}
Column {
@ -178,7 +233,7 @@ ApplicationWindow {
}
height: parent.height
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
}
}
@ -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 {
height: 30
RowLayout {
spacing: 5
@ -208,13 +284,32 @@ ApplicationWindow {
}
text: "Next"
}
CheckBox {
id: breakEachLine
objectName: "breakEachLine"
text: "Break each instruction"
checked: true
Button {
id: debugContinueButton
onClicked: {
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() {
@ -261,7 +356,19 @@ ApplicationWindow {
}
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() {

View File

@ -100,7 +100,7 @@ ApplicationWindow {
anchors.right: parent.right
height: 200
Image {
source: ui.assetPath("tx.png")
source: "../tx.png"
anchors.horizontalCenter: parent.horizontalCenter
MouseArea {
anchors.fill: parent
@ -110,7 +110,7 @@ ApplicationWindow {
}
}
Image {
source: ui.assetPath("new.png")
source: "../new.png"
anchors.horizontalCenter: parent.horizontalCenter
MouseArea {
anchors.fill: parent
@ -120,7 +120,7 @@ ApplicationWindow {
}
}
Image {
source: ui.assetPath("net.png")
source: "../net.png"
anchors.horizontalCenter: parent.horizontalCenter
MouseArea {
anchors.fill: parent
@ -131,7 +131,7 @@ ApplicationWindow {
}
Image {
source: ui.assetPath("heart.png")
source: "../heart.png"
anchors.horizontalCenter: parent.horizontalCenter
MouseArea {
anchors.fill: parent
@ -248,9 +248,11 @@ ApplicationWindow {
text: "Client ID"
}
TextField {
text: eth.clientId()
text: eth.getCustomIdentifier()
width: 500
placeholderText: "Anonymous"
onTextChanged: {
eth.changeClientId(text)
eth.setCustomIdentifier(text)
}
}
}
@ -419,30 +421,54 @@ ApplicationWindow {
}
}
Label {
y: 7
anchors.right: peerImage.left
anchors.rightMargin: 5
id: peerLabel
font.pixelSize: 8
text: "0 / 0"
}
Image {
y: 7
id: peerImage
anchors.right: parent.right
width: 10; height: 10
MouseArea {
onDoubleClicked: peerWindow.visible = true
anchors.fill: parent
}
source: ui.assetPath("network.png")
}
Label {
y: 6
id: lastBlockLabel
objectName: "lastBlockLabel"
visible: true
text: ""
font.pixelSize: 10
anchors.right: peerGroup.left
anchors.rightMargin: 5
}
ProgressBar {
id: syncProgressIndicator
visible: false
objectName: "syncProgressIndicator"
y: 3
width: 140
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 {
id: popup
visible: false
//flags: Qt.CustomizeWindowHint | Qt.Tool | Qt.WindowCloseButtonHint
property var block
width: root.width
height: 300
@ -460,7 +486,7 @@ ApplicationWindow {
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> ' + 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>Gas used:</b> ' + gasUsed + " / " + gasLimit; color: "#F2F2F2"}
}
@ -577,6 +603,7 @@ ApplicationWindow {
Window {
id: addPeerWin
//flags: Qt.CustomizeWindowHint | Qt.Tool | Qt.WindowCloseButtonHint
visible: false
minimumWidth: 230
maximumWidth: 230
@ -624,7 +651,7 @@ ApplicationWindow {
width: 150
fillMode: Image.PreserveAspectFit
smooth: true
source: ui.assetPath("facet.png")
source: "../facet.png"
x: 10
y: 10
}
@ -633,7 +660,7 @@ ApplicationWindow {
anchors.left: aboutIcon.right
anchors.leftMargin: 10
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){
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{
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 {
id: peerWindow
//flags: Qt.CustomizeWindowHint | Qt.Tool | Qt.WindowCloseButtonHint
height: 200
width: 700
Rectangle {

View File

@ -38,7 +38,7 @@ ApplicationWindow {
experimental.preferences.javascriptEnabled: true
experimental.preferences.navigatorQtObjectEnabled: 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: {
console.log("[onMessageReceived]: ", message.data)
// TODO move to messaging.js
@ -191,6 +191,7 @@ ApplicationWindow {
inspector.visible = false
}else{
inspector.visible = true
inspector.url = webview.experimental.remoteInspectorUrl
}
}
onDoubleClicked: {
@ -224,7 +225,6 @@ ApplicationWindow {
WebView {
id: inspector
visible: false
url: webview.experimental.remoteInspectorUrl
anchors {
left: root.left
right: root.right
@ -238,7 +238,6 @@ ApplicationWindow {
name: "inspectorShown"
PropertyChanges {
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 (
"fmt"
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethpub"
"github.com/ethereum/eth-go/ethstate"
"github.com/ethereum/eth-go/ethutil"
"github.com/go-qml/qml"
)
@ -16,8 +17,8 @@ type AppContainer interface {
Engine() *qml.Engine
NewBlock(*ethchain.Block)
ObjectChanged(*ethchain.StateObject)
StorageChanged(*ethchain.StorageState)
ObjectChanged(*ethstate.StateObject)
StorageChanged(*ethstate.StorageState)
NewWatcher(chan bool)
}
@ -108,9 +109,9 @@ out:
app.container.NewBlock(block)
}
case object := <-app.changeChan:
if stateObject, ok := object.Resource.(*ethchain.StateObject); ok {
if stateObject, ok := object.Resource.(*ethstate.StateObject); ok {
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)
}
}

View File

@ -36,6 +36,7 @@ var LogLevel int
// flags specific to gui client
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 {
var assetPath string
// If the current working directory is the go-ethereum dir
@ -52,15 +53,14 @@ func defaultAssetPath() string {
assetPath = filepath.Join(exedir, "../Resources")
case "linux":
assetPath = "/usr/share/ethereal"
case "window":
fallthrough
case "windows":
assetPath = "./assets"
default:
assetPath = "."
}
}
return assetPath
}
func defaultDataDir() string {
usr, _ := user.Current()
return path.Join(usr.HomeDir, ".ethereal")

View File

@ -1,4 +1,4 @@
package ethui
package main
import (
"bytes"
@ -7,11 +7,14 @@ import (
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethdb"
"github.com/ethereum/eth-go/ethlog"
"github.com/ethereum/eth-go/ethminer"
"github.com/ethereum/eth-go/ethpub"
"github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/eth-go/ethwire"
"github.com/ethereum/go-ethereum/utils"
"github.com/go-qml/qml"
"math/big"
"strconv"
"strings"
"time"
)
@ -36,12 +39,15 @@ type Gui struct {
logLevel ethlog.LogLevel
open bool
Session string
Session string
clientIdentity *ethwire.SimpleClientIdentity
config *ethutil.ConfigManager
miner *ethminer.Miner
}
// 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")
if err != nil {
panic(err)
@ -49,11 +55,10 @@ func New(ethereum *eth.Ethereum, session string, logLevel int) *Gui {
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) {
const version = "0.5.16"
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 = "" },
}})
ethutil.Config.SetClientString("Ethereal")
// Create a new QML engine
gui.engine = qml.NewEngine()
context := gui.engine.Context()
@ -104,14 +107,14 @@ func (gui *Gui) Start(assetPath string) {
ethlog.AddLogSystem(gui)
}
win.Wait()
// need to silence gui logger after window closed otherwise logsystem hangs
gui.SetLogLevel(ethlog.Silence)
// need to silence gui logger after window closed otherwise logsystem hangs (but do not save loglevel)
gui.logLevel = ethlog.Silence
gui.open = false
}
func (gui *Gui) Stop() {
if gui.open {
gui.SetLogLevel(ethlog.Silence)
gui.logLevel = ethlog.Silence
gui.open = false
gui.win.Hide()
}
@ -125,6 +128,7 @@ func (gui *Gui) ToggleMining() {
txt = "Start mining"
} else {
utils.StartMining(gui.eth)
gui.miner = utils.GetMiner()
txt = "Stop mining"
}
@ -139,10 +143,12 @@ func (gui *Gui) showWallet(context *qml.Context) (*qml.Window, error) {
win := gui.createWindow(component)
gui.setInitialBlockChain()
gui.loadAddressBook()
gui.readPreviousTransactions()
gui.setPeerInfo()
go func() {
gui.setInitialBlockChain()
gui.loadAddressBook()
gui.readPreviousTransactions()
gui.setPeerInfo()
}()
go gui.update()
@ -211,14 +217,16 @@ type address struct {
Name, Address string
}
var namereg = ethutil.Hex2Bytes("bb5f186604d057c1c5240ca2ae0f6430138ac010")
func (gui *Gui) loadAddressBook() {
gui.win.Root().Call("clearAddress")
stateObject := gui.eth.StateManager().CurrentState().GetStateObject(namereg)
if stateObject != nil {
stateObject.State().EachStorage(func(name string, value *ethutil.Value) {
gui.win.Root().Call("addAddress", struct{ Name, Address string }{name, ethutil.Bytes2Hex(value.Bytes())})
nameReg := ethpub.EthereumConfig(gui.eth.StateManager()).NameReg()
if nameReg != nil {
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) {
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) {
@ -262,27 +274,46 @@ func (gui *Gui) setWalletValue(amount, unconfirmedFunds *big.Int) {
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
func (gui *Gui) update() {
reactor := gui.eth.Reactor()
blockChan := make(chan ethutil.React, 1)
txChan := make(chan ethutil.React, 1)
objectChan := make(chan ethutil.React, 1)
peerChan := make(chan ethutil.React, 1)
var (
blockChan = make(chan ethutil.React, 1)
txChan = 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("newTx:pre", 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)
ticker := time.NewTicker(5 * time.Second)
peerUpdateTicker := time.NewTicker(5 * time.Second)
generalUpdateTicker := time.NewTicker(1 * time.Second)
state := gui.eth.StateManager().TransState()
unconfirmedFunds := new(big.Int)
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 {
select {
@ -324,12 +355,32 @@ func (gui *Gui) update() {
state.UpdateStateObject(object)
}
case msg := <-chainSyncChan:
sync := msg.Resource.(bool)
gui.win.Root().ObjectByName("syncProgressIndicator").Set("visible", sync)
case <-objectChan:
gui.loadAddressBook()
case <-peerChan:
gui.setPeerInfo()
case <-ticker.C:
case <-peerUpdateTicker.C:
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) {
name = fmt.Sprintf("\"%s\"\n1", name)
gui.pub.Transact(gui.privateKey(), "namereg", "1000", "1000000", "150", name)
name = fmt.Sprintf("\"register\"\n\"%s\"", name)
gui.pub.Transact(gui.privateKey(), "NameReg", "", "10000", "10000000000000", name)
}
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)
}
func (gui *Gui) ChangeClientId(id string) {
ethutil.Config.SetIdentifier(id)
func (gui *Gui) SetCustomIdentifier(customIdentifier string) {
gui.clientIdentity.SetCustomIdentifier(customIdentifier)
gui.config.Save("id", customIdentifier)
}
func (gui *Gui) ClientId() string {
return ethutil.Config.Identifier
func (gui *Gui) GetCustomIdentifier() string {
return gui.clientIdentity.GetCustomIdentifier()
}
// functions that allow Gui to implement interface ethlog.LogSystem
func (gui *Gui) SetLogLevel(level ethlog.LogLevel) {
gui.logLevel = level
gui.config.Save("loglevel", level)
}
func (gui *Gui) GetLogLevel() ethlog.LogLevel {

View File

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

View File

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

View File

@ -1,10 +1,12 @@
package ethui
package main
import (
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethpub"
"github.com/ethereum/eth-go/ethstate"
"github.com/ethereum/eth-go/ethutil"
"github.com/go-qml/qml"
"runtime"
)
type QmlApplication struct {
@ -20,7 +22,14 @@ func NewQmlApplication(path string, lib *UiLib) *QmlApplication {
}
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 {
logger.Warnln(err)
}
@ -42,11 +51,11 @@ func (app *QmlApplication) NewBlock(block *ethchain.Block) {
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))
}
func (app *QmlApplication) StorageChanged(storageObject *ethchain.StorageState) {
func (app *QmlApplication) StorageChanged(storageObject *ethstate.StorageState) {
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 (
"github.com/ethereum/eth-go"
@ -78,8 +78,8 @@ func (ui *UiLib) AssetPath(p string) string {
func (self *UiLib) StartDbWithContractAndData(contractHash, data string) {
dbWindow := NewDebuggerWindow(self)
object := self.eth.StateManager().CurrentState().GetStateObject(ethutil.Hex2Bytes(contractHash))
if len(object.Script()) > 0 {
dbWindow.SetCode("0x" + ethutil.Bytes2Hex(object.Script()))
if len(object.Code) > 0 {
dbWindow.SetCode("0x" + ethutil.Bytes2Hex(object.Code))
}
dbWindow.SetData("0x" + data)

View File

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

View File

@ -11,6 +11,8 @@ import (
var Identifier string
var KeyRing string
var DiffTool bool
var DiffType string
var KeyStore string
var StartRpc bool
var RpcPort int
@ -66,6 +68,8 @@ func Init() {
flag.StringVar(&ConfigFile, "conf", defaultConfigFile, "config file")
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.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(&StartJsConsole, "js", false, "launches javascript console")

View File

@ -2,10 +2,16 @@ package main
import (
"github.com/ethereum/eth-go/ethlog"
"github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/go-ethereum/utils"
"runtime"
)
const (
ClientIdentifier = "Ethereum(G)"
Version = "0.6.0"
)
var logger = ethlog.NewLogger("CLI")
func main() {
@ -15,7 +21,15 @@ func main() {
// precedence: code-internal flag default < config file < environment variables < 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)
@ -28,7 +42,9 @@ func main() {
// create, import, export keys
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 {
utils.ShowGenesis(ethereum)

View File

@ -1,4 +1,4 @@
package main
package ethrepl
import (
"fmt"
@ -6,6 +6,7 @@ import (
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethlog"
"github.com/ethereum/eth-go/ethpub"
"github.com/ethereum/eth-go/ethstate"
"github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/go-ethereum/utils"
"github.com/obscuren/otto"
@ -121,12 +122,12 @@ out:
if _, ok := block.Resource.(*ethchain.Block); ok {
}
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())] {
val, _ := self.vm.ToValue(ethpub.NewPStateObject(stateObject))
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)] {
val, _ := self.vm.ToValue(ethpub.NewPStorageState(storageObject))
cb.Call(cb, val)

View File

@ -1,4 +1,4 @@
package main
package ethrepl
const jsLib = `
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 LDFLAGS: -L/usr/local/opt/readline/lib

View File

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

View File

@ -1,84 +1,26 @@
package main
package ethrepl
import (
"bufio"
"fmt"
"github.com/ethereum/eth-go"
"github.com/ethereum/eth-go/ethpub"
"github.com/ethereum/eth-go/ethutil"
"github.com/obscuren/otto"
"io"
"os"
"path"
)
type Repl interface {
Start()
Stop()
type JSStateObject struct {
*ethpub.PStateObject
eth *JSEthereum
}
type JSRepl struct {
re *JSRE
func (self *JSStateObject) EachStorage(call otto.FunctionCall) otto.Value {
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
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)
return otto.UndefinedValue()
}
// 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 {
return self.toVal(self.PEthereum.GetStateObject(addr))
return self.toVal(&JSStateObject{self.PEthereum.GetStateObject(addr), self})
}
func (self *JSEthereum) GetStateKeyVals(addr string) otto.Value {

View File

@ -1,6 +1,7 @@
package utils
import (
"bitbucket.org/kardianos/osext"
"fmt"
"github.com/ethereum/eth-go"
"github.com/ethereum/eth-go/ethcrypto"
@ -10,11 +11,14 @@ import (
"github.com/ethereum/eth-go/ethpub"
"github.com/ethereum/eth-go/ethrpc"
"github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/eth-go/ethwire"
"io"
"log"
"os"
"os/signal"
"path"
"path/filepath"
"runtime"
"time"
)
@ -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)
ethutil.ReadConfig(ConfigFile, Datadir, Identifier, EnvPrefix)
return ethutil.ReadConfig(ConfigFile, Datadir, EnvPrefix)
}
func exit(err error) {
status := 0
if err != nil {
fmt.Println(err)
logger.Errorln("Fatal: ", err)
status = 1
}
@ -121,8 +126,12 @@ func NewDatabase() ethutil.Database {
return db
}
func NewEthereum(db ethutil.Database, keyManager *ethcrypto.KeyManager, usePnp bool, OutboundPort string, MaxPeer int) *eth.Ethereum {
ethereum, err := eth.New(db, keyManager, eth.CapDefault, usePnp)
func NewClientIdentity(clientIdentifier, version, customIdentifier string) *ethwire.SimpleClientIdentity {
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 {
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) {
logger.Infof("Starting Ethereum v%s", ethutil.Config.Ver)
logger.Infof("Starting %s", ethereum.ClientIdentity())
ethereum.Start(UseSeed)
RegisterInterrupt(func(sig os.Signal) {
ethereum.Stop()
@ -158,7 +167,34 @@ func NewKeyManager(KeyStore string, Datadir string, db ethutil.Database) *ethcry
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) {
ethcrypto.InitWords(DefaultAssetPath()) // Init mnemonic word list
var err error
switch {
case GenAddr:
@ -167,6 +203,8 @@ func KeyTasks(keyManager *ethcrypto.KeyManager, KeyRing string, GenAddr bool, Se
}
exit(err)
case len(SecretFile) > 0:
SecretFile = ethutil.ExpandHomePath(SecretFile)
if NonInteractive || confirm("This action overwrites your old private key.") {
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 {
if !ethereum.Mining {
@ -205,7 +247,10 @@ func StartMining(ethereum *eth.Ethereum) bool {
addr := ethereum.KeyManager().Address()
go func() {
miner = ethminer.NewDefaultMiner(addr, ethereum)
if miner == nil {
miner = ethminer.NewDefaultMiner(addr, ethereum)
}
// Give it some time to connect with peers
time.Sleep(3 * time.Second)
for !ethereum.IsUpToDate() {
@ -213,7 +258,6 @@ func StartMining(ethereum *eth.Ethereum) bool {
}
logger.Infoln("Miner started")
miner := ethminer.NewDefaultMiner(addr, ethereum)
miner.Start()
}()
RegisterInterrupt(func(os.Signal) {
@ -225,12 +269,16 @@ func StartMining(ethereum *eth.Ethereum) bool {
}
func StopMining(ethereum *eth.Ethereum) bool {
if ethereum.Mining {
if ethereum.Mining && miner != nil {
miner.Stop()
logger.Infoln("Miner stopped")
ethereum.Mining = false
return true
}
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 }