diff options
-rw-r--r-- | README.md | 8 | ||||
-rw-r--r-- | ethereum/flags.go | 8 | ||||
-rw-r--r-- | ethereum/main.go | 12 | ||||
-rw-r--r-- | ethereum/repl/console_colors_windows.go | 80 | ||||
-rw-r--r-- | ethereum/repl/repl_darwin.go | 6 | ||||
-rw-r--r-- | ethereum/repl/repl_windows.go | 57 | ||||
-rwxr-xr-x | install.sh | 6 | ||||
-rw-r--r-- | javascript/javascript_runtime.go | 39 | ||||
-rw-r--r-- | javascript/js_lib.go | 4 | ||||
-rw-r--r-- | javascript/types.go | 4 | ||||
-rw-r--r-- | mist/assets/qml/main.qml | 19 | ||||
-rw-r--r-- | mist/assets/qml/views/chain.qml | 41 | ||||
-rw-r--r-- | mist/assets/qml/views/history.qml | 1 | ||||
-rw-r--r-- | mist/assets/qml/views/info.qml | 3 | ||||
-rw-r--r-- | mist/assets/qml/views/javascript.qml | 45 | ||||
-rw-r--r-- | mist/assets/qml/views/pending_tx.qml | 1 | ||||
-rw-r--r-- | mist/assets/qml/views/transaction.qml | 3 | ||||
-rw-r--r-- | mist/assets/qml/webapp.qml | 727 | ||||
-rw-r--r-- | mist/bindings.go | 17 | ||||
-rw-r--r-- | mist/debugger.go | 27 | ||||
-rw-r--r-- | mist/ext_app.go | 74 | ||||
-rw-r--r-- | mist/flags.go | 52 | ||||
-rw-r--r-- | mist/gui.go | 135 | ||||
-rw-r--r-- | mist/main.go | 8 | ||||
-rw-r--r-- | mist/ui_lib.go | 15 | ||||
-rw-r--r-- | utils/cmd.go | 17 | ||||
-rw-r--r-- | utils/vm_env.go | 5 |
27 files changed, 737 insertions, 677 deletions
@@ -15,9 +15,9 @@ For the development package please see the [eth-go package](https://github.com/e Build ======= -To build Ethereal (GUI): +To build Mist (GUI): -`go get github.com/ethereum/go-ethereum/ethereal` +`go get github.com/ethereum/go-ethereum/mist` To build the node (CLI): @@ -29,7 +29,7 @@ General command line options ==================== ``` -Shared between ethereum and ethereal +Shared between ethereum and Mist -id Set the custom identifier of the client (shows up on other clients) -port Port on which the server will accept incomming connections -upnp Enable UPnP @@ -47,7 +47,7 @@ ethereum [options] [filename] filename Load the given file and interpret as JavaScript -m Start mining blocks -Etheral only +Mist only -asset_path absolute path to GUI assets directory ``` diff --git a/ethereum/flags.go b/ethereum/flags.go index 58220f4e6..af7b3365a 100644 --- a/ethereum/flags.go +++ b/ethereum/flags.go @@ -3,11 +3,13 @@ package main import ( "flag" "fmt" + "log" "os" "os/user" "path" "github.com/ethereum/eth-go/ethlog" + "github.com/ethereum/eth-go/vm" ) var ( @@ -37,6 +39,7 @@ var ( Dump bool DumpHash string DumpNumber int + VmType int ) // flags specific to cli client @@ -59,6 +62,7 @@ func Init() { flag.PrintDefaults() } + flag.IntVar(&VmType, "vm", 0, "Virtual Machine type: 0-1: standard, debug") flag.StringVar(&Identifier, "id", "", "Custom client identifier") flag.StringVar(&KeyRing, "keyring", "", "identifier for keyring to use") flag.StringVar(&KeyStore, "keystore", "db", "system to store keyrings: db|file (db)") @@ -91,5 +95,9 @@ func Init() { flag.Parse() + if VmType >= int(vm.MaxVmTy) { + log.Fatal("Invalid VM type ", VmType) + } + InputFile = flag.Arg(0) } diff --git a/ethereum/main.go b/ethereum/main.go index 0f0df20bb..21668ad25 100644 --- a/ethereum/main.go +++ b/ethereum/main.go @@ -13,7 +13,7 @@ import ( const ( ClientIdentifier = "Ethereum(G)" - Version = "0.6.7" + Version = "0.7.0" ) var logger = ethlog.NewLogger("CLI") @@ -31,7 +31,7 @@ func main() { LogLevel = 0 } - utils.InitConfig(ConfigFile, Datadir, "ETH") + utils.InitConfig(VmType, ConfigFile, Datadir, "ETH") ethutil.Config.Diff = DiffTool ethutil.Config.DiffType = DiffType @@ -42,7 +42,7 @@ func main() { db := utils.NewDatabase() err := utils.DBSanityCheck(db) if err != nil { - logger.Errorln(err) + fmt.Println(err) os.Exit(1) } @@ -60,11 +60,11 @@ func main() { var block *ethchain.Block if len(DumpHash) == 0 && DumpNumber == -1 { - block = ethereum.BlockChain().CurrentBlock + block = ethereum.ChainManager().CurrentBlock } else if len(DumpHash) > 0 { - block = ethereum.BlockChain().GetBlock(ethutil.Hex2Bytes(DumpHash)) + block = ethereum.ChainManager().GetBlock(ethutil.Hex2Bytes(DumpHash)) } else { - block = ethereum.BlockChain().GetBlockByNumber(uint64(DumpNumber)) + block = ethereum.ChainManager().GetBlockByNumber(uint64(DumpNumber)) } if block == nil { diff --git a/ethereum/repl/console_colors_windows.go b/ethereum/repl/console_colors_windows.go new file mode 100644 index 000000000..1f517bd8c --- /dev/null +++ b/ethereum/repl/console_colors_windows.go @@ -0,0 +1,80 @@ +/* Inspired by https://github.com/xuyu/logging/blob/master/colorful_win.go */ + +package ethrepl + +import ( + "syscall" + "unsafe" +) + +type color uint16 + +const ( + green = color(0x0002) + red = color(0x0004) + yellow = color(0x000E) +) + +const ( + mask = uint16(yellow | green | red) +) + +var ( + kernel32 = syscall.NewLazyDLL("kernel32.dll") + procGetStdHandle = kernel32.NewProc("GetStdHandle") + procSetConsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute") + procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo") + hStdout uintptr + initScreenInfo *consoleScreenBufferInfo +) + +func setConsoleTextAttribute(hConsoleOutput uintptr, wAttributes uint16) bool { + ret, _, _ := procSetConsoleTextAttribute.Call(hConsoleOutput, uintptr(wAttributes)) + return ret != 0 +} + +type coord struct { + X, Y int16 +} + +type smallRect struct { + Left, Top, Right, Bottom int16 +} + +type consoleScreenBufferInfo struct { + DwSize coord + DwCursorPosition coord + WAttributes uint16 + SrWindow smallRect + DwMaximumWindowSize coord +} + +func getConsoleScreenBufferInfo(hConsoleOutput uintptr) *consoleScreenBufferInfo { + var csbi consoleScreenBufferInfo + ret, _, _ := procGetConsoleScreenBufferInfo.Call(hConsoleOutput, uintptr(unsafe.Pointer(&csbi))) + if ret == 0 { + return nil + } + return &csbi +} + +const ( + stdOutputHandle = uint32(-11 & 0xFFFFFFFF) +) + +func init() { + hStdout, _, _ = procGetStdHandle.Call(uintptr(stdOutputHandle)) + initScreenInfo = getConsoleScreenBufferInfo(hStdout) +} + +func resetColorful() { + if initScreenInfo == nil { + return + } + setConsoleTextAttribute(hStdout, initScreenInfo.WAttributes) +} + +func changeColor(c color) { + attr := uint16(0) & ^mask | uint16(c) + setConsoleTextAttribute(hStdout, attr) +} diff --git a/ethereum/repl/repl_darwin.go b/ethereum/repl/repl_darwin.go index 4c07280f7..ba7dae996 100644 --- a/ethereum/repl/repl_darwin.go +++ b/ethereum/repl/repl_darwin.go @@ -9,6 +9,7 @@ package ethrepl // #include <readline/history.h> import "C" import ( + "fmt" "os" "os/signal" "strings" @@ -118,6 +119,9 @@ func (self *JSRepl) PrintValue(v interface{}) { method, _ := self.re.Vm.Get("prettyPrint") v, err := self.re.Vm.ToValue(v) if err == nil { - method.Call(method, v) + val, err := method.Call(method, v) + if err == nil { + fmt.Printf("%v", val) + } } } diff --git a/ethereum/repl/repl_windows.go b/ethereum/repl/repl_windows.go index 4106c89bc..bfae57088 100644 --- a/ethereum/repl/repl_windows.go +++ b/ethereum/repl/repl_windows.go @@ -4,6 +4,7 @@ import ( "bufio" "fmt" "os" + "strings" ) func (self *JSRepl) read() { @@ -14,11 +15,61 @@ func (self *JSRepl) read() { if err != nil { fmt.Println("Error reading input", err) } else { - self.parseInput(string(str)) + if (string(str) == "exit") { + self.Stop() + break + } else { + self.parseInput(string(str)) + } } } } -func (self *JSRepl) PrintValue(value otto.Value) { - fmt.Println(value) +func addHistory(s string) { +} + +func printColored(outputVal string) { + for ; outputVal != "" ; { + codePart := "" + if (strings.HasPrefix(outputVal, "\033[32m")) { + codePart = "\033[32m" + changeColor(2) + } + if (strings.HasPrefix(outputVal, "\033[1m\033[30m")) { + codePart = "\033[1m\033[30m" + changeColor(8) + } + if (strings.HasPrefix(outputVal, "\033[31m")) { + codePart = "\033[31m" + changeColor(red) + } + if (strings.HasPrefix(outputVal, "\033[35m")) { + codePart = "\033[35m" + changeColor(5) + } + if (strings.HasPrefix(outputVal, "\033[0m")) { + codePart = "\033[0m" + resetColorful() + } + textPart := outputVal[len(codePart):len(outputVal)] + index := strings.Index(textPart, "\033") + if index == -1 { + outputVal = "" + } else { + outputVal = textPart[index:len(textPart)] + textPart = textPart[0:index] + } + fmt.Printf("%v", textPart) + } +} + +func (self *JSRepl) PrintValue(v interface{}) { + method, _ := self.re.Vm.Get("prettyPrint") + v, err := self.re.Vm.ToValue(v) + if err == nil { + val, err := method.Call(method, v) + if err == nil { + printColored(fmt.Sprintf("%v", val)) + } + } } diff --git a/install.sh b/install.sh index 9719a1afc..f880aa39b 100755 --- a/install.sh +++ b/install.sh @@ -2,7 +2,7 @@ if [ "$1" == "" ]; then echo "Usage $0 executable branch ethereum develop" - echo "executable ethereum or ethereal" + echo "executable ethereum or mist" echo "branch develop or master" exit fi @@ -41,8 +41,8 @@ echo "go-ethereum" cd $GOPATH/src/github.com/ethereum/go-ethereum/$exe git checkout $branch -if [ "$exe" == "ethereal" ]; then - echo "Building ethereal GUI. Assuming Qt is installed. If this step" +if [ "$exe" == "mist" ]; then + echo "Building Mist GUI. Assuming Qt is installed. If this step" echo "fails; please refer to: https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)" else echo "Building ethereum CLI." diff --git a/javascript/javascript_runtime.go b/javascript/javascript_runtime.go index ffc672a63..189106ae9 100644 --- a/javascript/javascript_runtime.go +++ b/javascript/javascript_runtime.go @@ -11,9 +11,9 @@ import ( "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethpipe" - "github.com/ethereum/eth-go/ethreact" "github.com/ethereum/eth-go/ethstate" "github.com/ethereum/eth-go/ethutil" + "github.com/ethereum/eth-go/event" "github.com/ethereum/go-ethereum/utils" "github.com/obscuren/otto" ) @@ -25,9 +25,8 @@ type JSRE struct { Vm *otto.Otto pipe *ethpipe.JSPipe - blockChan chan ethreact.Event - changeChan chan ethreact.Event - quitChan chan bool + events event.Subscription + quitChan chan bool objectCb map[string][]otto.Value } @@ -51,8 +50,7 @@ func NewJSRE(ethereum *eth.Ethereum) *JSRE { ethereum, otto.New(), ethpipe.NewJSPipe(ethereum), - make(chan ethreact.Event, 10), - make(chan ethreact.Event, 10), + nil, make(chan bool), make(map[string][]otto.Value), } @@ -68,8 +66,8 @@ func NewJSRE(ethereum *eth.Ethereum) *JSRE { go re.mainLoop() // Subscribe to events - reactor := ethereum.Reactor() - reactor.Subscribe("newBlock", re.blockChan) + mux := ethereum.EventMux() + re.events = mux.Subscribe(ethchain.NewBlockEvent{}) re.Bind("eth", &JSEthereum{re.pipe, re.Vm, ethereum}) @@ -105,25 +103,16 @@ func (self *JSRE) Require(file string) error { } func (self *JSRE) Stop() { + self.events.Unsubscribe() // Kill the main loop self.quitChan <- true - close(self.blockChan) close(self.quitChan) - close(self.changeChan) jsrelogger.Infoln("stopped") } func (self *JSRE) mainLoop() { -out: - for { - select { - case <-self.quitChan: - break out - case block := <-self.blockChan: - if _, ok := block.Resource.(*ethchain.Block); ok { - } - } + for _ = range self.events.Chan() { } } @@ -150,10 +139,10 @@ func (self *JSRE) dump(call otto.FunctionCall) otto.Value { var block *ethchain.Block if call.Argument(0).IsNumber() { num, _ := call.Argument(0).ToInteger() - block = self.ethereum.BlockChain().GetBlockByNumber(uint64(num)) + block = self.ethereum.ChainManager().GetBlockByNumber(uint64(num)) } else if call.Argument(0).IsString() { hash, _ := call.Argument(0).ToString() - block = self.ethereum.BlockChain().GetBlock(ethutil.Hex2Bytes(hash)) + block = self.ethereum.ChainManager().GetBlock(ethutil.Hex2Bytes(hash)) } else { fmt.Println("invalid argument for dump. Either hex string or number") } @@ -201,13 +190,13 @@ func (self *JSRE) watch(call otto.FunctionCall) otto.Value { if storageCallback { self.objectCb[addr+storageAddr] = append(self.objectCb[addr+storageAddr], cb) - event := "storage:" + string(ethutil.Hex2Bytes(addr)) + ":" + string(ethutil.Hex2Bytes(storageAddr)) - self.ethereum.Reactor().Subscribe(event, self.changeChan) + // event := "storage:" + string(ethutil.Hex2Bytes(addr)) + ":" + string(ethutil.Hex2Bytes(storageAddr)) + // self.ethereum.EventMux().Subscribe(event, self.changeChan) } else { self.objectCb[addr] = append(self.objectCb[addr], cb) - event := "object:" + string(ethutil.Hex2Bytes(addr)) - self.ethereum.Reactor().Subscribe(event, self.changeChan) + // event := "object:" + string(ethutil.Hex2Bytes(addr)) + // self.ethereum.EventMux().Subscribe(event, self.changeChan) } return otto.UndefinedValue() diff --git a/javascript/js_lib.go b/javascript/js_lib.go index a3e9b8a5b..dd1fe5f4d 100644 --- a/javascript/js_lib.go +++ b/javascript/js_lib.go @@ -44,9 +44,11 @@ function pp(object) { function prettyPrint(/* */) { var args = arguments; + var ret = ""; for(var i = 0, l = args.length; i < l; i++) { - console.log(pp(args[i])) + ret += pp(args[i]) + "\n"; } + return ret; } var print = prettyPrint; diff --git a/javascript/types.go b/javascript/types.go index 53a2977a8..560960f54 100644 --- a/javascript/types.go +++ b/javascript/types.go @@ -4,10 +4,10 @@ import ( "fmt" "github.com/ethereum/eth-go" - "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethpipe" "github.com/ethereum/eth-go/ethstate" "github.com/ethereum/eth-go/ethutil" + "github.com/ethereum/eth-go/ui" "github.com/obscuren/otto" ) @@ -128,7 +128,7 @@ func (self *JSEthereum) toVal(v interface{}) otto.Value { } func (self *JSEthereum) Messages(object map[string]interface{}) otto.Value { - filter := ethchain.NewFilterFromMap(object, self.ethereum) + filter := ui.NewFilterFromMap(object, self.ethereum) messages := filter.Find() var msgs []JSMessage diff --git a/mist/assets/qml/main.qml b/mist/assets/qml/main.qml index 3d9204ce8..cfd227b49 100644 --- a/mist/assets/qml/main.qml +++ b/mist/assets/qml/main.qml @@ -51,9 +51,8 @@ ApplicationWindow { addPlugin("./views/transaction.qml", {noAdd: true, close: false, section: "legacy"}); addPlugin("./views/chain.qml", {noAdd: true, close: false, section: "legacy"}); - addPlugin("./views/info.qml", {noAdd: true, close: false, section: "legacy"}); addPlugin("./views/pending_tx.qml", {noAdd: true, close: false, section: "legacy"}); - addPlugin("./views/javascript.qml", {noAdd: true, close: false, section: "legacy"}); + addPlugin("./views/info.qml", {noAdd: true, close: false, section: "legacy"}); addPlugin("./views/jeffcoin/jeffcoin.qml", {noAdd: true, close: false, section: "apps"}) @@ -363,12 +362,7 @@ ApplicationWindow { view.visible = false view.anchors.fill = mainView - if( !view.hasOwnProperty("iconSource") ) { - console.log("Could not load plugin. Property 'iconSourc' not found on view."); - return; - } - - var menuItem = menu.createMenuItem(view.iconSource, view, options); + var menuItem = menu.createMenuItem(view, options); if( view.hasOwnProperty("menuItem") ) { view.menuItem = menuItem; } @@ -525,7 +519,7 @@ ApplicationWindow { } } - function createMenuItem(icon, view, options) { + function createMenuItem(view, options) { if(options === undefined) { options = {}; } @@ -547,7 +541,10 @@ ApplicationWindow { comp.view = view comp.title = view.title - comp.icon = view.iconSource + + if(view.hasOwnProperty("iconSource")) { + comp.icon = view.iconSource; + } comp.closable = options.close; return comp @@ -889,7 +886,7 @@ ApplicationWindow { pastPeers.append({text: ips.get(i)}) } - pastPeers.insert(0, {text: "poc-6.ethdev.com:30303"}) + pastPeers.insert(0, {text: "poc-7.ethdev.com:30303"}) } } diff --git a/mist/assets/qml/views/chain.qml b/mist/assets/qml/views/chain.qml index 130ff8bb9..c4ceecfc0 100644 --- a/mist/assets/qml/views/chain.qml +++ b/mist/assets/qml/views/chain.qml @@ -8,8 +8,7 @@ import Ethereum 1.0 Rectangle { id: root - property var title: "Network" - property var iconSource: "../net.png" + property var title: "Block Chain" property var menuItem objectName: "chainView" @@ -64,12 +63,12 @@ Rectangle { Menu { id: contextMenu - property var row; + property var row MenuItem { text: "Details" onTriggered: { popup.visible = true - popup.setDetails(blockModel.get(this.row)) + popup.setDetails(blockModel.get(contextMenu.row)) } } @@ -78,7 +77,7 @@ Rectangle { MenuItem { text: "Copy" onTriggered: { - copyToClipboard(blockModel.get(this.row).hash) + copyToClipboard(blockModel.get(contextMenu.row).hash) } } @@ -86,7 +85,7 @@ Rectangle { text: "Dump State" onTriggered: { generalFileDialog.show(false, function(path) { - var hash = blockModel.get(this.row).hash; + var hash = blockModel.get(contextMenu.row).hash; gui.dumpState(hash, path); }); @@ -102,22 +101,18 @@ Rectangle { initial = false } - /* - var txs = JSON.parse(block.transactions); - if(txs != null){ - amount = txs.length - } - */ - var txs = block.transactions; var amount = block.transactions.length; + var txs = []; + for(var i = 0; i < block.transactions.length; i++) { + var tx = JSON.parse(block.transactions.getAsJson(i)); + txs.push(tx); + } if(initial){ blockModel.append({size: block.size, 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, {size: block.size, number: block.number, name: block.name, gasLimit: block.gasLimit, gasUsed: block.gasUsed, coinbase: block.coinbase, hash: block.hash, txs: txs, txAmount: amount, time: block.time, prettyTime: convertToPretty(block.time)}) } - - //root.secondary.text = "#" + block.number; } Window { @@ -215,7 +210,7 @@ Rectangle { anchors.topMargin: 10 text: "Debug contract" onClicked: { - if(tx.createsContract){ + if(tx && tx.createsContract){ eth.startDbWithCode(tx.rawData) }else { eth.startDbWithContractAndData(tx.address, tx.rawData) @@ -240,16 +235,16 @@ Rectangle { property var singleBlock: ListModel { id: singleBlock } - function setDetails(block){ - singleBlock.set(0,block) + function setDetails(bl){ + singleBlock.set(0, bl) popup.height = 300 transactionModel.clear() - if(block.txs !== undefined){ - for(var i = 0; i < block.txs.length; i++) { - transactionModel.insert(0, block.txs.get(i)) + if(bl.txs !== undefined){ + for(var i = 0; i < bl.txs.count; i++) { + transactionModel.insert(0, bl.txs.get(i)) } - if(block.txs.length > 0 && block.txs.get(0).data){ - popup.showContractData(block.txs.get(0)) + if(bl.txs.count > 0 && bl.txs.get(0).data){ + popup.showContractData(bl.txs.get(0)) } } txView.forceActiveFocus() diff --git a/mist/assets/qml/views/history.qml b/mist/assets/qml/views/history.qml index 9eee883e3..c72f8f3ae 100644 --- a/mist/assets/qml/views/history.qml +++ b/mist/assets/qml/views/history.qml @@ -7,7 +7,6 @@ import QtQuick.Controls.Styles 1.1 import Ethereum 1.0 Rectangle { - property var iconSource: "../tx.png" property var title: "Transactions" property var menuItem diff --git a/mist/assets/qml/views/info.qml b/mist/assets/qml/views/info.qml index 158e2c960..3ff551b05 100644 --- a/mist/assets/qml/views/info.qml +++ b/mist/assets/qml/views/info.qml @@ -7,8 +7,7 @@ import QtQuick.Controls.Styles 1.1 import Ethereum 1.0 Rectangle { - property var title: "Information" - property var iconSource: "../heart.png" + property var title: "Debug Info" property var menuItem objectName: "infoView" diff --git a/mist/assets/qml/views/javascript.qml b/mist/assets/qml/views/javascript.qml deleted file mode 100644 index ea05c4148..000000000 --- a/mist/assets/qml/views/javascript.qml +++ /dev/null @@ -1,45 +0,0 @@ -import QtQuick 2.0 -import QtQuick.Controls 1.0; -import QtQuick.Layouts 1.0; -import QtQuick.Dialogs 1.0; -import QtQuick.Window 2.1; -import QtQuick.Controls.Styles 1.1 -import Ethereum 1.0 - -Rectangle { - property var title: "JavaScript" - property var iconSource: "../tx.png" - property var menuItem - - objectName: "javascriptView" - visible: false - anchors.fill: parent - - TextField { - id: input - anchors { - left: parent.left - right: parent.right - bottom: parent.bottom - } - height: 20 - - Keys.onReturnPressed: { - var res = eth.evalJavascriptString(this.text); - this.text = ""; - - output.append(res) - } - } - - TextArea { - id: output - text: "> JSRE Ready..." - anchors { - top: parent.top - left: parent.left - right: parent.right - bottom: input.top - } - } -} diff --git a/mist/assets/qml/views/pending_tx.qml b/mist/assets/qml/views/pending_tx.qml index abfa25790..4442a69db 100644 --- a/mist/assets/qml/views/pending_tx.qml +++ b/mist/assets/qml/views/pending_tx.qml @@ -8,7 +8,6 @@ import Ethereum 1.0 Rectangle { property var title: "Pending Transactions" - property var iconSource: "../tx.png" property var menuItem objectName: "pendingTxView" diff --git a/mist/assets/qml/views/transaction.qml b/mist/assets/qml/views/transaction.qml index 7d689733f..8792e31eb 100644 --- a/mist/assets/qml/views/transaction.qml +++ b/mist/assets/qml/views/transaction.qml @@ -7,8 +7,7 @@ import QtQuick.Controls.Styles 1.1 import Ethereum 1.0 Rectangle { - property var iconSource: "../new.png" - property var title: "New transaction" + property var title: "New Transaction" property var menuItem objectName: "newTxView" diff --git a/mist/assets/qml/webapp.qml b/mist/assets/qml/webapp.qml index 09e6a83ad..c35f325d5 100644 --- a/mist/assets/qml/webapp.qml +++ b/mist/assets/qml/webapp.qml @@ -7,411 +7,402 @@ import QtQuick.Layouts 1.0; import QtQuick.Window 2.1; import Ethereum 1.0 -import "../ext/qml_messaging.js" as Messaging - -//ApplicationWindow { - Rectangle { - id: window - property var title: "Browser" - property var iconSource: "../browser.png" - property var menuItem - - property alias url: webview.url - property alias webView: webview - - property var cleanPath: false - property var open: function(url) { - if(!window.cleanPath) { - var uri = url; - if(!/.*\:\/\/.*/.test(uri)) { - uri = "http://" + uri; - } - - var reg = /(^https?\:\/\/(?:www\.)?)([a-zA-Z0-9_\-]*\.eth)(.*)/ - - if(reg.test(uri)) { - uri.replace(reg, function(match, pre, domain, path) { - uri = pre; - - var lookup = eth.lookupDomain(domain.substring(0, domain.length - 4)); - var ip = []; - for(var i = 0, l = lookup.length; i < l; i++) { - ip.push(lookup.charCodeAt(i)) - } - - if(ip.length != 0) { - uri += lookup; - } else { - uri += domain; - } - - uri += path; - }); - } - - window.cleanPath = true; - - webview.url = uri; - - //uriNav.text = uri.text.replace(/(^https?\:\/\/(?:www\.)?)([a-zA-Z0-9_\-]*\.\w{2,3})(.*)/, "$1$2<span style='color:#CCC'>$3</span>"); - uriNav.text = uri; - } else { - // Prevent inf loop. - window.cleanPath = false; - } - } - - Component.onCompleted: { - webview.url = "http://etherian.io" - } - - signal messages(var messages, int id); - onMessages: { - // Bit of a cheat to get proper JSON - var m = JSON.parse(JSON.parse(JSON.stringify(messages))) - webview.postEvent("messages", [m, id]); - } - - Item { - objectName: "root" - id: root - anchors.fill: parent - state: "inspectorShown" - - RowLayout { - id: navBar - height: 40 - anchors { - left: parent.left - right: parent.right - leftMargin: 7 - } - - Button { - id: back - onClicked: { - webview.goBack() - } - style: ButtonStyle { - background: Image { - source: "../back.png" - width: 30 - height: 30 - } - } - } - - TextField { - anchors { - left: back.right - right: toggleInspector.left - leftMargin: 5 - rightMargin: 5 - } - text: "http://etherian.io" - id: uriNav - y: parent.height / 2 - this.height / 2 - - Keys.onReturnPressed: { - webview.url = this.text; - } - } - - Button { - id: toggleInspector - anchors { - right: parent.right - } - iconSource: "../bug.png" - onClicked: { - if(inspector.visible == true){ - inspector.visible = false - }else{ - inspector.visible = true - inspector.url = webview.experimental.remoteInspectorUrl - } - } - } - } - - - WebView { - objectName: "webView" - id: webview - anchors { - left: parent.left - right: parent.right - bottom: parent.bottom - top: navBar.bottom - } - - //property var cleanPath: false - onNavigationRequested: { - window.open(request.url.toString()); - } - - function sendMessage(data) { - webview.experimental.postMessage(JSON.stringify(data)) - } - - onTitleChanged: { - var data = Messaging.HandleMessage(title); - if(data) { - sendMessage(data) - } - } - - experimental.preferences.javascriptEnabled: true - experimental.preferences.navigatorQtObjectEnabled: true - experimental.preferences.developerExtrasEnabled: true - experimental.userScripts: ["../ext/qt_messaging_adapter.js", "../ext/q.js", "../ext/big.js", "../ext/string.js", "../ext/html_messaging.js"] - experimental.onMessageReceived: { - console.log("[onMessageReceived]: ", message.data) - // TODO move to messaging.js - var data = JSON.parse(message.data) - - try { - switch(data.call) { - case "compile": - postData(data._seed, eth.compile(data.args[0])) - break - - case "getCoinBase": - postData(data._seed, eth.coinBase()) - - break - - case "getIsListening": - postData(data._seed, eth.isListening()) - - break - - case "getIsMining": - postData(data._seed, eth.isMining()) - - break +Rectangle { + id: window + property var title: "Browser" + property var iconSource: "../browser.png" + property var menuItem + + property alias url: webview.url + property alias webView: webview + + property var cleanPath: false + property var open: function(url) { + if(!window.cleanPath) { + var uri = url; + if(!/.*\:\/\/.*/.test(uri)) { + uri = "http://" + uri; + } + + var reg = /(^https?\:\/\/(?:www\.)?)([a-zA-Z0-9_\-]*\.eth)(.*)/ + + if(reg.test(uri)) { + uri.replace(reg, function(match, pre, domain, path) { + uri = pre; + + var lookup = eth.lookupDomain(domain.substring(0, domain.length - 4)); + var ip = []; + for(var i = 0, l = lookup.length; i < l; i++) { + ip.push(lookup.charCodeAt(i)) + } + + if(ip.length != 0) { + uri += lookup; + } else { + uri += domain; + } + + uri += path; + }); + } + + window.cleanPath = true; + + webview.url = uri; + + //uriNav.text = uri.text.replace(/(^https?\:\/\/(?:www\.)?)([a-zA-Z0-9_\-]*\.\w{2,3})(.*)/, "$1$2<span style='color:#CCC'>$3</span>"); + uriNav.text = uri; + } else { + // Prevent inf loop. + window.cleanPath = false; + } + } + + Component.onCompleted: { + webview.url = "http://etherian.io" + } + + signal messages(var messages, int id); + onMessages: { + // Bit of a cheat to get proper JSON + var m = JSON.parse(JSON.parse(JSON.stringify(messages))) + webview.postEvent("messages", [m, id]); + } + + Item { + objectName: "root" + id: root + anchors.fill: parent + state: "inspectorShown" + + RowLayout { + id: navBar + height: 40 + anchors { + left: parent.left + right: parent.right + leftMargin: 7 + } + + Button { + id: back + onClicked: { + webview.goBack() + } + style: ButtonStyle { + background: Image { + source: "../back.png" + width: 30 + height: 30 + } + } + } + + TextField { + anchors { + left: back.right + right: toggleInspector.left + leftMargin: 5 + rightMargin: 5 + } + text: "http://etherian.io" + id: uriNav + y: parent.height / 2 - this.height / 2 + + Keys.onReturnPressed: { + webview.url = this.text; + } + } + + Button { + id: toggleInspector + anchors { + right: parent.right + } + iconSource: "../bug.png" + onClicked: { + if(inspector.visible == true){ + inspector.visible = false + }else{ + inspector.visible = true + inspector.url = webview.experimental.remoteInspectorUrl + } + } + } + } + + + WebView { + objectName: "webView" + id: webview + anchors { + left: parent.left + right: parent.right + bottom: parent.bottom + top: navBar.bottom + } + + //property var cleanPath: false + onNavigationRequested: { + window.open(request.url.toString()); + } + + function sendMessage(data) { + webview.experimental.postMessage(JSON.stringify(data)) + } + + + experimental.preferences.javascriptEnabled: true + experimental.preferences.navigatorQtObjectEnabled: true + experimental.preferences.developerExtrasEnabled: true + experimental.userScripts: ["../ext/qt_messaging_adapter.js", "../ext/q.js", "../ext/big.js", "../ext/string.js", "../ext/html_messaging.js"] + experimental.onMessageReceived: { + console.log("[onMessageReceived]: ", message.data) + // TODO move to messaging.js + var data = JSON.parse(message.data) + + try { + switch(data.call) { + case "compile": + postData(data._seed, eth.compile(data.args[0])) + break + + case "getCoinBase": + postData(data._seed, eth.coinBase()) + + break + + case "getIsListening": + postData(data._seed, eth.isListening()) - case "getPeerCount": - postData(data._seed, eth.peerCount()) + break + + case "getIsMining": + postData(data._seed, eth.isMining()) - break + break - case "getCountAt": - require(1) - postData(data._seed, eth.txCountAt(data.args[0])) + case "getPeerCount": + postData(data._seed, eth.peerCount()) - break + break - case "getCodeAt": - require(1) - var code = eth.codeAt(data.args[0]) - postData(data._seed, code); + case "getCountAt": + require(1) + postData(data._seed, eth.txCountAt(data.args[0])) - break + break - case "getBlockByNumber": - var block = eth.blockByNumber(data.args[0]) - postData(data._seed, block) + case "getCodeAt": + require(1) + var code = eth.codeAt(data.args[0]) + postData(data._seed, code); - break + break - case "getBlockByHash": - var block = eth.blockByHash(data.args[0]) - postData(data._seed, block) + case "getBlockByNumber": + var block = eth.blockByNumber(data.args[0]) + postData(data._seed, block) - break + break - case "transact": - require(5) + case "getBlockByHash": + var block = eth.blockByHash(data.args[0]) + postData(data._seed, block) - var tx = eth.transact(data.args) - postData(data._seed, tx) + break - break + case "transact": + require(5) - case "getStorageAt": - require(2); + var tx = eth.transact(data.args) + postData(data._seed, tx) - var storage = eth.storageAt(data.args[0], data.args[1]); - postData(data._seed, storage) + break - break + case "getStorageAt": + require(2); - case "call": - require(1); - var ret = eth.call(data.args) - postData(data._seed, ret) + var storage = eth.storageAt(data.args[0], data.args[1]); + postData(data._seed, storage) - break + break - case "getEachStorage": - require(1); - var storage = JSON.parse(eth.eachStorage(data.args[0])) - postData(data._seed, storage) + case "call": + require(1); + var ret = eth.call(data.args) + postData(data._seed, ret) - break + break - case "getTransactionsFor": - require(1); - var txs = eth.transactionsFor(data.args[0], true) - postData(data._seed, txs) + case "getEachStorage": + require(1); + var storage = JSON.parse(eth.eachStorage(data.args[0])) + postData(data._seed, storage) - break + break - case "getBalanceAt": - require(1); + case "getTransactionsFor": + require(1); + var txs = eth.transactionsFor(data.args[0], true) + postData(data._seed, txs) - postData(data._seed, eth.balanceAt(data.args[0])); + break - break + case "getBalanceAt": + require(1); - case "getKey": - var key = eth.key().privateKey; + postData(data._seed, eth.balanceAt(data.args[0])); - postData(data._seed, key) - break + break - case "watch": - require(2) - eth.watch(data.args[0], data.args[1]) + case "getKey": + var key = eth.key().privateKey; - case "disconnect": - require(1) - postData(data._seed, null) + postData(data._seed, key) + break - break; + case "watch": + require(2) + eth.watch(data.args[0], data.args[1]) - case "getSecretToAddress": - require(1) + case "disconnect": + require(1) + postData(data._seed, null) - var addr = eth.secretToAddress(data.args[0]) - console.log("getsecret", addr) - postData(data._seed, addr) + break; - break; + case "getSecretToAddress": + require(1) - case "messages": - require(1); + var addr = eth.secretToAddress(data.args[0]) + console.log("getsecret", addr) + postData(data._seed, addr) - var messages = JSON.parse(eth.getMessages(data.args[0])) - postData(data._seed, messages) + break; - break + case "messages": + require(1); - case "mutan": - require(1) + var messages = JSON.parse(eth.getMessages(data.args[0])) + postData(data._seed, messages) - var code = eth.compileMutan(data.args[0]) - postData(data._seed, "0x"+code) + break - break; + case "mutan": + require(1) - case "newFilterString": - require(1) - var id = eth.newFilterString(data.args[0]) - postData(data._seed, id); - break; - case "newFilter": - require(1) - var id = eth.newFilter(data.args[0]) - - postData(data._seed, id); - break; - - case "getMessages": - require(1); - - var messages = eth.messages(data.args[0]); - var m = JSON.parse(JSON.parse(JSON.stringify(messages))) - postData(data._seed, m); - - break; - - case "deleteFilter": - require(1); - eth.uninstallFilter(data.args[0]) - break; - } - } catch(e) { - console.log(data.call + ": " + e) - - postData(data._seed, null); - } - } - - - function post(seed, data) { - postData(data._seed, data) - } - - function require(args, num) { - if(args.length < num) { - throw("required argument count of "+num+" got "+args.length); - } - } - function postData(seed, data) { - webview.experimental.postMessage(JSON.stringify({data: data, _seed: seed})) - } - function postEvent(event, data) { - webview.experimental.postMessage(JSON.stringify({data: data, _event: event})) - } - - function onWatchedCb(data, id) { - var messages = JSON.parse(data) - postEvent("watched:"+id, messages) - } - - function onNewBlockCb(block) { - postEvent("block:new", block) - } - function onObjectChangeCb(stateObject) { - postEvent("object:"+stateObject.address(), stateObject) - } - function onStorageChangeCb(storageObject) { - var ev = ["storage", storageObject.stateAddress, storageObject.address].join(":"); - postEvent(ev, [storageObject.address, storageObject.value]) - } - } - - - Rectangle { - id: sizeGrip - color: "gray" - visible: false - height: 10 - anchors { - left: root.left - right: root.right - } - y: Math.round(root.height * 2 / 3) - - MouseArea { - anchors.fill: parent - drag.target: sizeGrip - drag.minimumY: 0 - drag.maximumY: root.height - drag.axis: Drag.YAxis - } - } - - WebView { - id: inspector - visible: false - anchors { - left: root.left - right: root.right - top: sizeGrip.bottom - bottom: root.bottom - } - } - - states: [ - State { - name: "inspectorShown" - PropertyChanges { - target: inspector - } - } - ] - } - } + var code = eth.compileMutan(data.args[0]) + postData(data._seed, "0x"+code) + + break; + + case "newFilterString": + require(1) + var id = eth.newFilterString(data.args[0]) + postData(data._seed, id); + break; + case "newFilter": + require(1) + var id = eth.newFilter(data.args[0]) + + postData(data._seed, id); + break; + + case "getMessages": + require(1); + + var messages = eth.messages(data.args[0]); + var m = JSON.parse(JSON.parse(JSON.stringify(messages))) + postData(data._seed, m); + + break; + + case "deleteFilter": + require(1); + eth.uninstallFilter(data.args[0]) + break; + } + } catch(e) { + console.log(data.call + ": " + e) + + postData(data._seed, null); + } + } + + + function post(seed, data) { + postData(data._seed, data) + } + + function require(args, num) { + if(args.length < num) { + throw("required argument count of "+num+" got "+args.length); + } + } + function postData(seed, data) { + webview.experimental.postMessage(JSON.stringify({data: data, _seed: seed})) + } + function postEvent(event, data) { + webview.experimental.postMessage(JSON.stringify({data: data, _event: event})) + } + + function onWatchedCb(data, id) { + var messages = JSON.parse(data) + postEvent("watched:"+id, messages) + } + + function onNewBlockCb(block) { + postEvent("block:new", block) + } + function onObjectChangeCb(stateObject) { + postEvent("object:"+stateObject.address(), stateObject) + } + function onStorageChangeCb(storageObject) { + var ev = ["storage", storageObject.stateAddress, storageObject.address].join(":"); + postEvent(ev, [storageObject.address, storageObject.value]) + } + } + + + Rectangle { + id: sizeGrip + color: "gray" + visible: false + height: 10 + anchors { + left: root.left + right: root.right + } + y: Math.round(root.height * 2 / 3) + + MouseArea { + anchors.fill: parent + drag.target: sizeGrip + drag.minimumY: 0 + drag.maximumY: root.height + drag.axis: Drag.YAxis + } + } + + WebView { + id: inspector + visible: false + anchors { + left: root.left + right: root.right + top: sizeGrip.bottom + bottom: root.bottom + } + } + + states: [ + State { + name: "inspectorShown" + PropertyChanges { + target: inspector + } + } + ] + } +} diff --git a/mist/bindings.go b/mist/bindings.go index 141c4a469..972e4e8ed 100644 --- a/mist/bindings.go +++ b/mist/bindings.go @@ -2,7 +2,6 @@ package main import ( "encoding/json" - "fmt" "os" "strconv" @@ -18,16 +17,8 @@ type plugin struct { Path string `json:"path"` } -func (gui *Gui) Println(v ...interface{}) { - gui.printLog(fmt.Sprintln(v...)) -} - -func (gui *Gui) Printf(format string, v ...interface{}) { - gui.printLog(fmt.Sprintf(format, v...)) -} - -// Print function that logs directly to the GUI -func (gui *Gui) printLog(s string) { +// LogPrint writes to the GUI log. +func (gui *Gui) LogPrint(level ethlog.LogLevel, msg string) { /* str := strings.TrimRight(s, "\n") lines := strings.Split(str, "\n") @@ -105,9 +96,9 @@ func (self *Gui) DumpState(hash, path string) { var block *ethchain.Block if hash[0] == '#' { i, _ := strconv.Atoi(hash[1:]) - block = self.eth.BlockChain().GetBlockByNumber(uint64(i)) + block = self.eth.ChainManager().GetBlockByNumber(uint64(i)) } else { - block = self.eth.BlockChain().GetBlock(ethutil.Hex2Bytes(hash)) + block = self.eth.ChainManager().GetBlock(ethutil.Hex2Bytes(hash)) } if block == nil { diff --git a/mist/debugger.go b/mist/debugger.go index 9d1de8c42..ebe18c78f 100644 --- a/mist/debugger.go +++ b/mist/debugger.go @@ -10,7 +10,7 @@ import ( "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/eth-go/vm" "github.com/ethereum/go-ethereum/utils" "gopkg.in/qml.v1" ) @@ -20,7 +20,7 @@ type DebuggerWindow struct { engine *qml.Engine lib *UiLib - vm *ethvm.Vm + vm *vm.DebugVm Db *Debugger state *ethstate.State @@ -37,7 +37,7 @@ func NewDebuggerWindow(lib *UiLib) *DebuggerWindow { win := component.CreateWindow(nil) - w := &DebuggerWindow{engine: engine, win: win, lib: lib, vm: ðvm.Vm{}} + w := &DebuggerWindow{engine: engine, win: win, lib: lib, vm: &vm.DebugVm{}} w.Db = NewDebugger(w) return w @@ -127,23 +127,22 @@ func (self *DebuggerWindow) Debug(valueStr, gasStr, gasPriceStr, scriptStr, data state := self.lib.eth.StateManager().TransState() account := self.lib.eth.StateManager().TransState().GetAccount(keyPair.Address()) contract := ethstate.NewStateObject([]byte{0}) - contract.Balance = value + contract.SetBalance(value) self.SetAsm(script) - block := self.lib.eth.BlockChain().CurrentBlock + block := self.lib.eth.ChainManager().CurrentBlock - callerClosure := ethvm.NewClosure(ðstate.Message{}, account, contract, script, gas, gasPrice) + callerClosure := vm.NewClosure(ðstate.Message{}, account, contract, script, gas, gasPrice) env := utils.NewEnv(state, block, account.Address(), value) - vm := ethvm.New(env) - vm.Verbose = true - vm.Dbg = self.Db + evm := vm.NewDebugVm(env) + evm.Dbg = self.Db - self.vm = vm + self.vm = evm self.Db.done = false self.Logf("callsize %d", len(script)) go func() { - ret, g, err := callerClosure.Call(vm, data) + ret, g, err := callerClosure.Call(evm, 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 { @@ -251,13 +250,13 @@ 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 { +func (self *Debugger) BreakHook(pc int, op vm.OpCode, mem *vm.Memory, stack *vm.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 { +func (self *Debugger) StepHook(pc int, op vm.OpCode, mem *vm.Memory, stack *vm.Stack, stateObject *ethstate.StateObject) bool { return self.halting(pc, op, mem, stack, stateObject) } @@ -269,7 +268,7 @@ 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 { +func (d *Debugger) halting(pc int, op vm.OpCode, mem *vm.Memory, stack *vm.Stack, stateObject *ethstate.StateObject) bool { d.win.Root().Call("setInstruction", pc) d.win.Root().Call("clearMem") d.win.Root().Call("clearStack") diff --git a/mist/ext_app.go b/mist/ext_app.go index 514084c97..c4e6fd394 100644 --- a/mist/ext_app.go +++ b/mist/ext_app.go @@ -5,8 +5,9 @@ import ( "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethpipe" - "github.com/ethereum/eth-go/ethreact" "github.com/ethereum/eth-go/ethstate" + "github.com/ethereum/eth-go/event" + "github.com/ethereum/eth-go/ui/qt" "github.com/ethereum/go-ethereum/javascript" "gopkg.in/qml.v1" ) @@ -28,9 +29,7 @@ type ExtApplication struct { *ethpipe.JSPipe eth ethchain.EthManager - blockChan chan ethreact.Event - messageChan chan ethreact.Event - quitChan chan bool + events event.Subscription watcherQuitChan chan bool filters map[string]*ethchain.Filter @@ -40,19 +39,14 @@ type ExtApplication struct { } func NewExtApplication(container AppContainer, lib *UiLib) *ExtApplication { - app := &ExtApplication{ - ethpipe.NewJSPipe(lib.eth), - lib.eth, - make(chan ethreact.Event, 100), - make(chan ethreact.Event, 100), - make(chan bool), - make(chan bool), - make(map[string]*ethchain.Filter), - container, - lib, + return &ExtApplication{ + JSPipe: ethpipe.NewJSPipe(lib.eth), + eth: lib.eth, + watcherQuitChan: make(chan bool), + filters: make(map[string]*ethchain.Filter), + container: container, + lib: lib, } - - return app } func (app *ExtApplication) run() { @@ -67,14 +61,13 @@ func (app *ExtApplication) run() { return } + // Subscribe to events + mux := app.lib.eth.EventMux() + app.events = mux.Subscribe(ethchain.NewBlockEvent{}, ethstate.Messages(nil)) + // Call the main loop go app.mainLoop() - // Subscribe to events - reactor := app.lib.eth.Reactor() - reactor.Subscribe("newBlock", app.blockChan) - reactor.Subscribe("messages", app.messageChan) - app.container.NewWatcher(app.watcherQuitChan) win := app.container.Window() @@ -85,50 +78,37 @@ func (app *ExtApplication) run() { } func (app *ExtApplication) stop() { - // Clean up - reactor := app.lib.eth.Reactor() - reactor.Unsubscribe("newBlock", app.blockChan) + app.events.Unsubscribe() // Kill the main loop - app.quitChan <- true app.watcherQuitChan <- true - close(app.blockChan) - close(app.quitChan) - app.container.Destroy() } func (app *ExtApplication) mainLoop() { -out: - for { - select { - case <-app.quitChan: - break out - case block := <-app.blockChan: - if block, ok := block.Resource.(*ethchain.Block); ok { - app.container.NewBlock(block) - } - case msg := <-app.messageChan: - if messages, ok := msg.Resource.(ethstate.Messages); ok { - for id, filter := range app.filters { - msgs := filter.FilterMessages(messages) - if len(msgs) > 0 { - app.container.Messages(msgs, id) - } + for ev := range app.events.Chan() { + switch ev := ev.(type) { + case ethchain.NewBlockEvent: + app.container.NewBlock(ev.Block) + + case ethstate.Messages: + for id, filter := range app.filters { + msgs := filter.FilterMessages(ev) + if len(msgs) > 0 { + app.container.Messages(msgs, id) } } } } - } func (self *ExtApplication) Watch(filterOptions map[string]interface{}, identifier string) { - self.filters[identifier] = ethchain.NewFilterFromMap(filterOptions, self.eth) + self.filters[identifier] = qt.NewFilterFromMap(filterOptions, self.eth) } func (self *ExtApplication) GetMessages(object map[string]interface{}) string { - filter := ethchain.NewFilterFromMap(object, self.eth) + filter := qt.NewFilterFromMap(object, self.eth) messages := filter.Find() var msgs []javascript.JSMessage diff --git a/mist/flags.go b/mist/flags.go index d2e7d3fb0..68accf1bc 100644 --- a/mist/flags.go +++ b/mist/flags.go @@ -3,6 +3,7 @@ package main import ( "flag" "fmt" + "log" "os" "os/user" "path" @@ -11,28 +12,33 @@ import ( "bitbucket.org/kardianos/osext" "github.com/ethereum/eth-go/ethlog" + "github.com/ethereum/eth-go/vm" ) -var Identifier string -var KeyRing string -var KeyStore string -var StartRpc bool -var RpcPort int -var UseUPnP bool -var OutboundPort string -var ShowGenesis bool -var AddPeer string -var MaxPeer int -var GenAddr bool -var UseSeed bool -var SecretFile string -var ExportDir string -var NonInteractive bool -var Datadir string -var LogFile string -var ConfigFile string -var DebugFile string -var LogLevel int +var ( + Identifier string + KeyRing string + KeyStore string + StartRpc bool + StartWebSockets bool + RpcPort int + UseUPnP bool + OutboundPort string + ShowGenesis bool + AddPeer string + MaxPeer int + GenAddr bool + UseSeed bool + SecretFile string + ExportDir string + NonInteractive bool + Datadir string + LogFile string + ConfigFile string + DebugFile string + LogLevel int + VmType int +) // flags specific to gui client var AssetPath string @@ -75,6 +81,7 @@ func Init() { flag.PrintDefaults() } + flag.IntVar(&VmType, "vm", 0, "Virtual Machine type: 0-1: standard, debug") flag.StringVar(&Identifier, "id", "", "Custom client identifier") flag.StringVar(&KeyRing, "keyring", "", "identifier for keyring to use") flag.StringVar(&KeyStore, "keystore", "db", "system to store keyrings: db|file (db)") @@ -83,6 +90,7 @@ func Init() { flag.IntVar(&MaxPeer, "maxpeer", 10, "maximum desired peers") flag.IntVar(&RpcPort, "rpcport", 8080, "port to start json-rpc server on") flag.BoolVar(&StartRpc, "rpc", false, "start rpc server") + flag.BoolVar(&StartWebSockets, "ws", false, "start websocket server") flag.BoolVar(&NonInteractive, "y", false, "non-interactive mode (say yes to confirmations)") flag.BoolVar(&UseSeed, "seed", true, "seed peers") flag.BoolVar(&GenAddr, "genaddr", false, "create a new priv/pub key") @@ -97,4 +105,8 @@ func Init() { flag.StringVar(&AssetPath, "asset_path", defaultAssetPath(), "absolute path to GUI assets directory") flag.Parse() + + if VmType >= int(vm.MaxVmTy) { + log.Fatal("Invalid VM type ", VmType) + } } diff --git a/mist/gui.go b/mist/gui.go index 80d4a1fc3..2c19680c0 100644 --- a/mist/gui.go +++ b/mist/gui.go @@ -19,7 +19,6 @@ import ( "github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethminer" "github.com/ethereum/eth-go/ethpipe" - "github.com/ethereum/eth-go/ethreact" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" "gopkg.in/qml.v1" @@ -229,10 +228,10 @@ func (gui *Gui) CreateAndSetPrivKey() (string, string, string, string) { return gui.eth.KeyManager().KeyPair().AsStrings() } -func (gui *Gui) setInitialBlockChain() { - sBlk := gui.eth.BlockChain().LastBlockHash - blk := gui.eth.BlockChain().GetBlock(sBlk) - for ; blk != nil; blk = gui.eth.BlockChain().GetBlock(sBlk) { +func (gui *Gui) setInitialChainManager() { + sBlk := gui.eth.ChainManager().LastBlockHash + blk := gui.eth.ChainManager().GetBlock(sBlk) + for ; blk != nil; blk = gui.eth.ChainManager().GetBlock(sBlk) { sBlk = blk.PrevHash addr := gui.address() @@ -364,7 +363,7 @@ func (gui *Gui) update() { } go func() { - go gui.setInitialBlockChain() + go gui.setInitialChainManager() gui.loadAddressBook() gui.setPeerInfo() gui.readPreviousTransactions() @@ -376,15 +375,6 @@ func (gui *Gui) update() { gui.win.Root().Call("addPlugin", plugin.Path, "") } - var ( - blockChan = make(chan ethreact.Event, 100) - txChan = make(chan ethreact.Event, 100) - objectChan = make(chan ethreact.Event, 100) - peerChan = make(chan ethreact.Event, 100) - chainSyncChan = make(chan ethreact.Event, 100) - miningChan = make(chan ethreact.Event, 100) - ) - peerUpdateTicker := time.NewTicker(5 * time.Second) generalUpdateTicker := time.NewTicker(500 * time.Millisecond) statsUpdateTicker := time.NewTicker(5 * time.Second) @@ -392,68 +382,89 @@ func (gui *Gui) update() { state := gui.eth.StateManager().TransState() unconfirmedFunds := new(big.Int) - gui.win.Root().Call("setWalletValue", fmt.Sprintf("%v", ethutil.CurrencyToString(state.GetAccount(gui.address()).Balance))) + gui.win.Root().Call("setWalletValue", fmt.Sprintf("%v", ethutil.CurrencyToString(state.GetAccount(gui.address()).Balance()))) lastBlockLabel := gui.getObjectByName("lastBlockLabel") miningLabel := gui.getObjectByName("miningLabel") + events := gui.eth.EventMux().Subscribe( + eth.ChainSyncEvent{}, + eth.PeerListEvent{}, + ethchain.NewBlockEvent{}, + ethchain.TxEvent{}, + ethminer.Event{}, + ) + + // nameReg := gui.pipe.World().Config().Get("NameReg") + // mux.Subscribe("object:"+string(nameReg.Address()), objectChan) + go func() { + defer events.Unsubscribe() for { select { - case b := <-blockChan: - block := b.Resource.(*ethchain.Block) - gui.processBlock(block, false) - if bytes.Compare(block.Coinbase, gui.address()) == 0 { - gui.setWalletValue(gui.eth.StateManager().CurrentState().GetAccount(gui.address()).Balance, nil) + case ev, isopen := <-events.Chan(): + if !isopen { + return } - case txMsg := <-txChan: - tx := txMsg.Resource.(*ethchain.Transaction) + switch ev := ev.(type) { + case ethchain.NewBlockEvent: + gui.processBlock(ev.Block, false) + if bytes.Compare(ev.Block.Coinbase, gui.address()) == 0 { + gui.setWalletValue(gui.eth.StateManager().CurrentState().GetAccount(gui.address()).Balance(), nil) + } - if txMsg.Name == "newTx:pre" { - object := state.GetAccount(gui.address()) + case ethchain.TxEvent: + tx := ev.Tx + if ev.Type == ethchain.TxPre { + object := state.GetAccount(gui.address()) - if bytes.Compare(tx.Sender(), gui.address()) == 0 { - unconfirmedFunds.Sub(unconfirmedFunds, tx.Value) - } else if bytes.Compare(tx.Recipient, gui.address()) == 0 { - unconfirmedFunds.Add(unconfirmedFunds, tx.Value) - } + if bytes.Compare(tx.Sender(), gui.address()) == 0 { + unconfirmedFunds.Sub(unconfirmedFunds, tx.Value) + } else if bytes.Compare(tx.Recipient, gui.address()) == 0 { + unconfirmedFunds.Add(unconfirmedFunds, tx.Value) + } + + gui.setWalletValue(object.Balance(), unconfirmedFunds) + + gui.insertTransaction("pre", tx) - gui.setWalletValue(object.Balance, unconfirmedFunds) + } else if ev.Type == ethchain.TxPost { + object := state.GetAccount(gui.address()) + if bytes.Compare(tx.Sender(), gui.address()) == 0 { + object.SubAmount(tx.Value) - gui.insertTransaction("pre", tx) - } else { - object := state.GetAccount(gui.address()) - if bytes.Compare(tx.Sender(), gui.address()) == 0 { - object.SubAmount(tx.Value) + //gui.getObjectByName("transactionView").Call("addTx", ethpipe.NewJSTx(tx), "send") + gui.txDb.Put(tx.Hash(), tx.RlpEncode()) + } else if bytes.Compare(tx.Recipient, gui.address()) == 0 { + object.AddAmount(tx.Value) - //gui.getObjectByName("transactionView").Call("addTx", ethpipe.NewJSTx(tx), "send") - gui.txDb.Put(tx.Hash(), tx.RlpEncode()) - } else if bytes.Compare(tx.Recipient, gui.address()) == 0 { - object.AddAmount(tx.Value) + //gui.getObjectByName("transactionView").Call("addTx", ethpipe.NewJSTx(tx), "recv") + gui.txDb.Put(tx.Hash(), tx.RlpEncode()) + } - //gui.getObjectByName("transactionView").Call("addTx", ethpipe.NewJSTx(tx), "recv") - gui.txDb.Put(tx.Hash(), tx.RlpEncode()) + gui.setWalletValue(object.Balance(), nil) + + state.UpdateStateObject(object) } - gui.setWalletValue(object.Balance, nil) + // case object: + // gui.loadAddressBook() + + case eth.PeerListEvent: + gui.setPeerInfo() - state.UpdateStateObject(object) + case ethminer.Event: + if ev.Type == ethminer.Started { + gui.miner = ev.Miner + } else { + gui.miner = nil + } } - case <-objectChan: - gui.loadAddressBook() - case <-peerChan: - gui.setPeerInfo() case <-peerUpdateTicker.C: gui.setPeerInfo() - case msg := <-miningChan: - if msg.Name == "miner:start" { - gui.miner = msg.Resource.(*ethminer.Miner) - } else { - gui.miner = nil - } case <-generalUpdateTicker.C: - statusText := "#" + gui.eth.BlockChain().CurrentBlock.Number.String() + statusText := "#" + gui.eth.ChainManager().CurrentBlock.Number.String() lastBlockLabel.Set("text", statusText) if gui.miner != nil { @@ -478,20 +489,6 @@ func (gui *Gui) update() { } } }() - - reactor := gui.eth.Reactor() - - reactor.Subscribe("newBlock", blockChan) - reactor.Subscribe("newTx:pre", txChan) - reactor.Subscribe("newTx:post", txChan) - reactor.Subscribe("chainSync", chainSyncChan) - reactor.Subscribe("miner:start", miningChan) - reactor.Subscribe("miner:stop", miningChan) - - nameReg := gui.pipe.World().Config().Get("NameReg") - reactor.Subscribe("object:"+string(nameReg.Address()), objectChan) - - reactor.Subscribe("peerList", peerChan) } func (gui *Gui) setStatsPane() { diff --git a/mist/main.go b/mist/main.go index 6e4554352..116bd78fd 100644 --- a/mist/main.go +++ b/mist/main.go @@ -12,7 +12,7 @@ import ( const ( ClientIdentifier = "Mist" - Version = "0.6.7" + Version = "0.7.1" ) var ethereum *eth.Ethereum @@ -21,7 +21,7 @@ func run() error { // precedence: code-internal flag default < config file < environment variables < command line Init() // parsing command line - config := utils.InitConfig(ConfigFile, Datadir, "ETH") + config := utils.InitConfig(VmType, ConfigFile, Datadir, "ETH") utils.InitDataDir(Datadir) @@ -80,6 +80,10 @@ func main() { utils.HandleInterrupt() + if StartWebSockets { + utils.StartWebSockets(ethereum) + } + // we need to run the interrupt callbacks in case gui is closed // this skips if we got here by actual interrupt stopping the GUI if !interrupted { diff --git a/mist/ui_lib.go b/mist/ui_lib.go index e77336c90..90ba0bbaf 100644 --- a/mist/ui_lib.go +++ b/mist/ui_lib.go @@ -13,6 +13,7 @@ import ( "github.com/ethereum/eth-go/ethpipe" "github.com/ethereum/eth-go/ethstate" "github.com/ethereum/eth-go/ethutil" + "github.com/ethereum/eth-go/ui/qt" "github.com/ethereum/go-ethereum/javascript" "gopkg.in/qml.v1" ) @@ -51,7 +52,7 @@ func (self *UiLib) LookupDomain(domain string) string { world := self.World() if len(domain) > 32 { - domain = string(ethcrypto.Sha3Bin([]byte(domain))) + domain = string(ethcrypto.Sha3([]byte(domain))) } data := world.Config().Get("DnsReg").StorageString(domain).Bytes() @@ -193,21 +194,21 @@ func (self *UiLib) StartDebugger() { dbWindow.Show() } -func (self *UiLib) NewFilter(object map[string]interface{}) int { - filter, id := self.eth.InstallFilter(object) +func (self *UiLib) NewFilter(object map[string]interface{}) (id int) { + filter := qt.NewFilterFromMap(object, self.eth) filter.MessageCallback = func(messages ethstate.Messages) { self.win.Root().Call("invokeFilterCallback", ethpipe.ToJSMessages(messages), id) } - + id = self.eth.InstallFilter(filter) return id } -func (self *UiLib) NewFilterString(typ string) int { - filter, id := self.eth.InstallFilter(nil) +func (self *UiLib) NewFilterString(typ string) (id int) { + filter := ethchain.NewFilter(self.eth) filter.BlockCallback = func(block *ethchain.Block) { self.win.Root().Call("invokeFilterCallback", "{}", id) } - + id = self.eth.InstallFilter(filter) return id } diff --git a/utils/cmd.go b/utils/cmd.go index 700542cae..32aebc91e 100644 --- a/utils/cmd.go +++ b/utils/cmd.go @@ -19,9 +19,9 @@ import ( "github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethminer" "github.com/ethereum/eth-go/ethpipe" - "github.com/ethereum/eth-go/ethrpc" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" + "github.com/ethereum/eth-go/rpc" ) var logger = ethlog.NewLogger("CLI") @@ -118,9 +118,12 @@ func InitLogging(Datadir string, LogFile string, LogLevel int, DebugFile string) return sys } -func InitConfig(ConfigFile string, Datadir string, EnvPrefix string) *ethutil.ConfigManager { +func InitConfig(vmType int, ConfigFile string, Datadir string, EnvPrefix string) *ethutil.ConfigManager { InitDataDir(Datadir) - return ethutil.ReadConfig(ConfigFile, Datadir, EnvPrefix) + cfg := ethutil.ReadConfig(ConfigFile, Datadir, EnvPrefix) + cfg.VmType = vmType + + return cfg } func exit(err error) { @@ -166,7 +169,7 @@ func StartEthereum(ethereum *eth.Ethereum, UseSeed bool) { } func ShowGenesis(ethereum *eth.Ethereum) { - logger.Infoln(ethereum.BlockChain().Genesis()) + logger.Infoln(ethereum.ChainManager().Genesis()) exit(nil) } @@ -241,7 +244,7 @@ func KeyTasks(keyManager *ethcrypto.KeyManager, KeyRing string, GenAddr bool, Se func StartRpc(ethereum *eth.Ethereum, RpcPort int) { var err error - ethereum.RpcServer, err = ethrpc.NewJsonRpcServer(ethpipe.NewJSPipe(ethereum), RpcPort) + ethereum.RpcServer, err = rpc.NewJsonRpcServer(ethpipe.NewJSPipe(ethereum), RpcPort) if err != nil { logger.Errorf("Could not start RPC interface (port %v): %v", RpcPort, err) } else { @@ -307,12 +310,12 @@ func StopMining(ethereum *eth.Ethereum) bool { // Replay block func BlockDo(ethereum *eth.Ethereum, hash []byte) error { - block := ethereum.BlockChain().GetBlock(hash) + block := ethereum.ChainManager().GetBlock(hash) if block == nil { return fmt.Errorf("unknown block %x", hash) } - parent := ethereum.BlockChain().GetBlock(block.PrevHash) + parent := ethereum.ChainManager().GetBlock(block.PrevHash) _, err := ethereum.StateManager().ApplyDiff(parent.State(), parent, block) if err != nil { diff --git a/utils/vm_env.go b/utils/vm_env.go index 30568c421..21341ab04 100644 --- a/utils/vm_env.go +++ b/utils/vm_env.go @@ -5,6 +5,7 @@ import ( "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethstate" + "github.com/ethereum/eth-go/vm" ) type VMEnv struct { @@ -33,3 +34,7 @@ func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty } func (self *VMEnv) BlockHash() []byte { return self.block.Hash() } func (self *VMEnv) Value() *big.Int { return self.value } func (self *VMEnv) State() *ethstate.State { return self.state } +func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit } +func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) error { + return vm.Transfer(from, to, amount) +} |