diff options
Diffstat (limited to 'cmd/mist')
-rw-r--r-- | cmd/mist/assets/qml/browser.qml (renamed from cmd/mist/assets/qml/webapp.qml) | 37 | ||||
-rw-r--r-- | cmd/mist/assets/qml/main.qml | 3 | ||||
-rw-r--r-- | cmd/mist/assets/qml/views/whisper.qml | 76 | ||||
-rw-r--r-- | cmd/mist/flags.go | 4 | ||||
-rw-r--r-- | cmd/mist/gui.go | 114 | ||||
-rw-r--r-- | cmd/mist/main.go | 16 | ||||
-rw-r--r-- | cmd/mist/ui_lib.go | 159 |
7 files changed, 270 insertions, 139 deletions
diff --git a/cmd/mist/assets/qml/webapp.qml b/cmd/mist/assets/qml/browser.qml index bd7399dc9..867260507 100644 --- a/cmd/mist/assets/qml/webapp.qml +++ b/cmd/mist/assets/qml/browser.qml @@ -66,7 +66,11 @@ Rectangle { onMessages: { // Bit of a cheat to get proper JSON var m = JSON.parse(JSON.parse(JSON.stringify(messages))) - webview.postEvent("messages", [m, id]); + webview.postEvent("messages", id, m); + } + + function onShhMessage(message, id) { + webview.postEvent("shhChanged", id, message) } Item { @@ -327,6 +331,33 @@ Rectangle { require(1); eth.uninstallFilter(data.args[0]) break; + + + case "shhNewFilter": + require(1); + var id = shh.watch(data.args[0], window); + postData(data._id, id); + break; + + case "newIdentity": + postData(data._id, shh.newIdentity()) + break + + case "post": + require(1); + var params = data.args[0]; + var fields = ["payload", "to", "from"]; + for(var i = 0; i < fields.length; i++) { + params[fields[i]] = params[fields[i]] || ""; + } + if(typeof params.payload === "object") { params.payload = params.payload.join(""); } + params.topics = params.topics || []; + params.priority = params.priority || 1000; + params.ttl = params.ttl || 100; + + console.log(JSON.stringify(params)) + shh.post(params.payload, params.to, params.from, params.topics, params.priority, params.ttl); + break; } } catch(e) { console.log(data.call + ": " + e) @@ -348,8 +379,8 @@ Rectangle { function postData(seed, data) { webview.experimental.postMessage(JSON.stringify({data: data, _id: seed})) } - function postEvent(event, data) { - webview.experimental.postMessage(JSON.stringify({data: data, _event: event})) + function postEvent(event, id, data) { + webview.experimental.postMessage(JSON.stringify({data: data, _id: id, _event: event})) } function onWatchedCb(data, id) { diff --git a/cmd/mist/assets/qml/main.qml b/cmd/mist/assets/qml/main.qml index a08a8b4ef..06a7bc2a8 100644 --- a/cmd/mist/assets/qml/main.qml +++ b/cmd/mist/assets/qml/main.qml @@ -45,11 +45,12 @@ ApplicationWindow { // Takes care of loading all default plugins Component.onCompleted: { var wallet = addPlugin("./views/wallet.qml", {noAdd: true, close: false, section: "ethereum", active: true}); - var browser = addPlugin("./webapp.qml", {noAdd: true, close: false, section: "ethereum", active: true}); + var browser = addPlugin("./browser.qml", {noAdd: true, close: false, section: "ethereum", active: true}); root.browser = browser; addPlugin("./views/miner.qml", {noAdd: true, close: false, section: "ethereum", active: true}); addPlugin("./views/transaction.qml", {noAdd: true, close: false, section: "legacy"}); + addPlugin("./views/whisper.qml", {noAdd: true, close: false, section: "legacy"}); addPlugin("./views/chain.qml", {noAdd: true, close: false, section: "legacy"}); addPlugin("./views/pending_tx.qml", {noAdd: true, close: false, section: "legacy"}); addPlugin("./views/info.qml", {noAdd: true, close: false, section: "legacy"}); diff --git a/cmd/mist/assets/qml/views/whisper.qml b/cmd/mist/assets/qml/views/whisper.qml new file mode 100644 index 000000000..ffe391666 --- /dev/null +++ b/cmd/mist/assets/qml/views/whisper.qml @@ -0,0 +1,76 @@ + +import QtQuick 2.0 +import QtQuick.Controls 1.0; +import QtQuick.Layouts 1.0; +import QtQuick.Dialogs 1.0; +import QtQuick.Window 2.1; +import QtQuick.Controls.Styles 1.1 +import Ethereum 1.0 + +Rectangle { + id: root + property var title: "Whisper Traffic" + property var iconSource: "../facet.png" + property var menuItem + + objectName: "whisperView" + anchors.fill: parent + + property var identity: "" + Component.onCompleted: { + identity = shh.newIdentity() + console.log("New identity:", identity) + + var t = shh.watch({}, root) + } + + function onShhMessage(message, i) { + whisperModel.insert(0, {from: message.from, payload: eth.toAscii(message.payload)}) + } + + RowLayout { + id: input + anchors { + left: parent.left + leftMargin: 20 + top: parent.top + topMargin: 20 + } + + TextField { + id: to + placeholderText: "To" + } + TextField { + id: data + placeholderText: "Data" + } + TextField { + id: topics + placeholderText: "topic1, topic2, topic3, ..." + } + Button { + text: "Send" + onClicked: { + shh.post(eth.toHex(data.text), "", identity, topics.text.split(","), 500, 50) + } + } + } + + TableView { + id: txTableView + anchors { + top: input.bottom + topMargin: 10 + bottom: parent.bottom + left: parent.left + right: parent.right + } + TableViewColumn{ id: fromRole; role: "from" ; title: "From"; width: 300 } + TableViewColumn{ role: "payload" ; title: "Payload" ; width: parent.width - fromRole.width - 2 } + + model: ListModel { + id: whisperModel + } + } +} diff --git a/cmd/mist/flags.go b/cmd/mist/flags.go index e49408181..fcee28f19 100644 --- a/cmd/mist/flags.go +++ b/cmd/mist/flags.go @@ -36,10 +36,12 @@ var ( Identifier string KeyRing string KeyStore string + PMPGateway string StartRpc bool StartWebSockets bool RpcPort int UseUPnP bool + NatType string OutboundPort string ShowGenesis bool AddPeer string @@ -111,10 +113,12 @@ func Init() { 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") + flag.StringVar(&NatType, "nat", "", "NAT support (UPNP|PMP) (none)") flag.StringVar(&SecretFile, "import", "", "imports the file given (hex or mnemonic formats)") flag.StringVar(&ExportDir, "export", "", "exports the session keyring to files in the directory given") flag.StringVar(&LogFile, "logfile", "", "log file (defaults to standard output)") flag.StringVar(&Datadir, "datadir", defaultDataDir(), "specifies the datadir to use") + flag.StringVar(&PMPGateway, "pmp", "", "Gateway IP for PMP") flag.StringVar(&ConfigFile, "conf", defaultConfigFile, "config file") flag.StringVar(&DebugFile, "debug", "", "debug file (no debugging if not set)") flag.IntVar(&LogLevel, "loglevel", int(logger.InfoLevel), "loglevel: 0-5: silent,error,warn,info,debug,debug detail)") diff --git a/cmd/mist/gui.go b/cmd/mist/gui.go index 7775889cc..1152f0dcd 100644 --- a/cmd/mist/gui.go +++ b/cmd/mist/gui.go @@ -30,50 +30,19 @@ import ( "strings" "time" - "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/miner" - "github.com/ethereum/go-ethereum/wire" + "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/ui/qt/qwhisper" "github.com/ethereum/go-ethereum/xeth" "gopkg.in/qml.v1" ) -/* -func LoadExtension(path string) (uintptr, error) { - lib, err := ffi.NewLibrary(path) - if err != nil { - return 0, err - } - - so, err := lib.Fct("sharedObject", ffi.Pointer, nil) - if err != nil { - return 0, err - } - - ptr := so() - - err = lib.Close() - if err != nil { - return 0, err - } - - return ptr.Interface().(uintptr), nil -} -*/ -/* - vec, errr := LoadExtension("/Users/jeffrey/Desktop/build-libqmltest-Desktop_Qt_5_2_1_clang_64bit-Debug/liblibqmltest_debug.dylib") - fmt.Printf("Fetched vec with addr: %#x\n", vec) - if errr != nil { - fmt.Println(errr) - } else { - context.SetVar("vec", (unsafe.Pointer)(vec)) - } -*/ - var guilogger = logger.NewLogger("GUI") type Gui struct { @@ -87,7 +56,8 @@ type Gui struct { eth *eth.Ethereum // The public Ethereum library - uiLib *UiLib + uiLib *UiLib + whisper *qwhisper.Whisper txDb *ethdb.LDBDatabase @@ -97,7 +67,7 @@ type Gui struct { pipe *xeth.JSXEth Session string - clientIdentity *wire.SimpleClientIdentity + clientIdentity *p2p.SimpleClientIdentity config *ethutil.ConfigManager plugins map[string]plugin @@ -107,7 +77,7 @@ type Gui struct { } // Create GUI, but doesn't start it -func NewWindow(ethereum *eth.Ethereum, config *ethutil.ConfigManager, clientIdentity *wire.SimpleClientIdentity, session string, logLevel int) *Gui { +func NewWindow(ethereum *eth.Ethereum, config *ethutil.ConfigManager, clientIdentity *p2p.SimpleClientIdentity, session string, logLevel int) *Gui { db, err := ethdb.NewLDBDatabase("tx_database") if err != nil { panic(err) @@ -138,10 +108,12 @@ func (gui *Gui) Start(assetPath string) { gui.engine = qml.NewEngine() context := gui.engine.Context() gui.uiLib = NewUiLib(gui.engine, gui.eth, assetPath) + gui.whisper = qwhisper.New(gui.eth.Whisper()) // Expose the eth library and the ui library to QML context.SetVar("gui", gui) context.SetVar("eth", gui.uiLib) + context.SetVar("shh", gui.whisper) // Load the main QML interface data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) @@ -297,7 +269,7 @@ func (gui *Gui) insertTransaction(window string, tx *types.Transaction) { addr := gui.address() var inout string - if bytes.Compare(tx.Sender(), addr) == 0 { + if bytes.Compare(tx.From(), addr) == 0 { inout = "send" } else { inout = "recv" @@ -317,7 +289,7 @@ func (gui *Gui) insertTransaction(window string, tx *types.Transaction) { if send.Len() != 0 { s = strings.Trim(send.Str(), "\x00") } else { - s = ethutil.Bytes2Hex(tx.Sender()) + s = ethutil.Bytes2Hex(tx.From()) } if rec.Len() != 0 { r = strings.Trim(rec.Str(), "\x00") @@ -391,6 +363,8 @@ func (gui *Gui) update() { gui.setPeerInfo() }() + gui.whisper.SetView(gui.win.Root().ObjectByName("whisperView")) + for _, plugin := range gui.plugins { guilogger.Infoln("Loading plugin ", plugin.Name) @@ -409,8 +383,7 @@ func (gui *Gui) update() { miningLabel := gui.getObjectByName("miningLabel") events := gui.eth.EventMux().Subscribe( - eth.ChainSyncEvent{}, - eth.PeerListEvent{}, + //eth.PeerListEvent{}, core.NewBlockEvent{}, core.TxPreEvent{}, core.TxPostEvent{}, @@ -448,7 +421,7 @@ func (gui *Gui) update() { tx := ev.Tx object := state.GetAccount(gui.address()) - if bytes.Compare(tx.Sender(), gui.address()) == 0 { + if bytes.Compare(tx.From(), gui.address()) == 0 { object.SubAmount(tx.Value()) gui.txDb.Put(tx.Hash(), tx.RlpEncode()) @@ -460,9 +433,6 @@ func (gui *Gui) update() { gui.setWalletValue(object.Balance(), nil) state.UpdateStateObject(object) - - case eth.PeerListEvent: - gui.setPeerInfo() } case <-peerUpdateTicker.C: @@ -472,16 +442,18 @@ func (gui *Gui) update() { lastBlockLabel.Set("text", statusText) miningLabel.Set("text", "Mining @ "+strconv.FormatInt(gui.uiLib.miner.GetPow().GetHashrate(), 10)+"Khash") - blockLength := gui.eth.BlockPool().BlocksProcessed - chainLength := gui.eth.BlockPool().ChainLength + /* + blockLength := gui.eth.BlockPool().BlocksProcessed + chainLength := gui.eth.BlockPool().ChainLength - var ( - pct float64 = 1.0 / float64(chainLength) * float64(blockLength) - dlWidget = gui.win.Root().ObjectByName("downloadIndicator") - dlLabel = gui.win.Root().ObjectByName("downloadLabel") - ) - dlWidget.Set("value", pct) - dlLabel.Set("text", fmt.Sprintf("%d / %d", blockLength, chainLength)) + var ( + pct float64 = 1.0 / float64(chainLength) * float64(blockLength) + dlWidget = gui.win.Root().ObjectByName("downloadIndicator") + dlLabel = gui.win.Root().ObjectByName("downloadLabel") + ) + dlWidget.Set("value", pct) + dlLabel.Set("text", fmt.Sprintf("%d / %d", blockLength, chainLength)) + */ case <-statsUpdateTicker.C: gui.setStatsPane() @@ -509,7 +481,7 @@ Heap Alloc: %d CGNext: %x NumGC: %d `, Version, runtime.Version(), - eth.ProtocolVersion, eth.P2PVersion, + eth.ProtocolVersion, 2, runtime.NumCPU, runtime.NumGoroutine(), runtime.NumCgoCall(), memStats.Alloc, memStats.HeapAlloc, memStats.NextGC, memStats.NumGC, @@ -531,3 +503,35 @@ func (gui *Gui) privateKey() string { func (gui *Gui) address() []byte { return gui.eth.KeyManager().Address() } + +/* +func LoadExtension(path string) (uintptr, error) { + lib, err := ffi.NewLibrary(path) + if err != nil { + return 0, err + } + + so, err := lib.Fct("sharedObject", ffi.Pointer, nil) + if err != nil { + return 0, err + } + + ptr := so() + + err = lib.Close() + if err != nil { + return 0, err + } + + return ptr.Interface().(uintptr), nil +} +*/ +/* + vec, errr := LoadExtension("/Users/jeffrey/Desktop/build-libqmltest-Desktop_Qt_5_2_1_clang_64bit-Debug/liblibqmltest_debug.dylib") + fmt.Printf("Fetched vec with addr: %#x\n", vec) + if errr != nil { + fmt.Println(errr) + } else { + context.SetVar("vec", (unsafe.Pointer)(vec)) + } +*/ diff --git a/cmd/mist/main.go b/cmd/mist/main.go index eaf0af0c7..72e77940d 100644 --- a/cmd/mist/main.go +++ b/cmd/mist/main.go @@ -23,8 +23,8 @@ import ( "runtime" "time" - "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/cmd/utils" + "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/logger" "gopkg.in/qml.v1" ) @@ -58,8 +58,8 @@ func run() error { // create, import, export keys utils.KeyTasks(keyManager, KeyRing, GenAddr, SecretFile, ExportDir, NonInteractive) - clientIdentity := utils.NewClientIdentity(ClientIdentifier, Version, Identifier) - ethereum = utils.NewEthereum(db, clientIdentity, keyManager, UseUPnP, OutboundPort, MaxPeer) + clientIdentity := utils.NewClientIdentity(ClientIdentifier, Version, Identifier, string(keyManager.PublicKey())) + ethereum := utils.NewEthereum(db, clientIdentity, keyManager, utils.NatType(NatType, PMPGateway), OutboundPort, MaxPeer) if ShowGenesis { utils.ShowGenesis(ethereum) @@ -69,6 +69,10 @@ func run() error { utils.StartRpc(ethereum, RpcPort) } + if StartWebSockets { + utils.StartWebSockets(ethereum) + } + gui := NewWindow(ethereum, config, clientIdentity, KeyRing, LogLevel) gui.stdLog = stdLog @@ -100,16 +104,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 { utils.RunInterruptCallbacks(os.Interrupt) } - // this blocks the thread - ethereum.WaitForShutdown() logger.Flush() } diff --git a/cmd/mist/ui_lib.go b/cmd/mist/ui_lib.go index fdbde50fd..4a92f6479 100644 --- a/cmd/mist/ui_lib.go +++ b/cmd/mist/ui_lib.go @@ -24,11 +24,12 @@ import ( "strconv" "strings" - "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/ethutil" + "github.com/ethereum/go-ethereum/event/filter" "github.com/ethereum/go-ethereum/javascript" "github.com/ethereum/go-ethereum/miner" "github.com/ethereum/go-ethereum/state" @@ -57,6 +58,7 @@ type UiLib struct { jsEngine *javascript.JSRE filterCallbacks map[int][]int + filterManager *filter.FilterManager miner *miner.Miner } @@ -64,6 +66,7 @@ type UiLib struct { func NewUiLib(engine *qml.Engine, eth *eth.Ethereum, assetPath string) *UiLib { lib := &UiLib{JSXEth: xeth.NewJSXEth(eth), engine: engine, eth: eth, assetPath: assetPath, jsEngine: javascript.NewJSRE(eth), filterCallbacks: make(map[int][]int)} //, filters: make(map[int]*xeth.JSFilter)} lib.miner = miner.New(eth.KeyManager().Address(), eth) + lib.filterManager = filter.NewFilterManager(eth.EventMux()) return lib } @@ -123,7 +126,8 @@ func (self *UiLib) LookupAddress(name string) string { } func (self *UiLib) PastPeers() *ethutil.List { - return ethutil.NewList(eth.PastPeers()) + return ethutil.NewList([]string{}) + //return ethutil.NewList(eth.PastPeers()) } func (self *UiLib) ImportTx(rlpTx string) { @@ -191,7 +195,7 @@ func (ui *UiLib) Connect(button qml.Object) { } func (ui *UiLib) ConnectToPeer(addr string) { - ui.eth.ConnectToPeer(addr) + ui.eth.SuggestPeer(addr) } func (ui *UiLib) AssetPath(p string) string { @@ -221,12 +225,89 @@ func (self *UiLib) StartDebugger() { dbWindow.Show() } +func (self *UiLib) Transact(params map[string]interface{}) (string, error) { + object := mapToTxParams(params) + + return self.JSXEth.Transact( + object["from"], + object["to"], + object["value"], + object["gas"], + object["gasPrice"], + object["data"], + ) +} + +func (self *UiLib) Compile(code string) (string, error) { + bcode, err := ethutil.Compile(code, false) + if err != nil { + return err.Error(), err + } + + return ethutil.Bytes2Hex(bcode), err +} + +func (self *UiLib) Call(params map[string]interface{}) (string, error) { + object := mapToTxParams(params) + + return self.JSXEth.Execute( + object["to"], + object["value"], + object["gas"], + object["gasPrice"], + object["data"], + ) +} + +func (self *UiLib) AddLocalTransaction(to, data, gas, gasPrice, value string) int { + return self.miner.AddLocalTx(&miner.LocalTx{ + To: ethutil.Hex2Bytes(to), + Data: ethutil.Hex2Bytes(data), + Gas: gas, + GasPrice: gasPrice, + Value: value, + }) - 1 +} + +func (self *UiLib) RemoveLocalTransaction(id int) { + self.miner.RemoveLocalTx(id) +} + +func (self *UiLib) SetGasPrice(price string) { + self.miner.MinAcceptedGasPrice = ethutil.Big(price) +} + +func (self *UiLib) ToggleMining() bool { + if !self.miner.Mining() { + self.miner.Start() + + return true + } else { + self.miner.Stop() + + return false + } +} + +func (self *UiLib) ToHex(data string) string { + return "0x" + ethutil.Bytes2Hex([]byte(data)) +} + +func (self *UiLib) ToAscii(data string) string { + start := 0 + if len(data) > 1 && data[0:2] == "0x" { + start = 2 + } + return string(ethutil.Hex2Bytes(data[start:])) +} + +/// Ethereum filter methods func (self *UiLib) NewFilter(object map[string]interface{}) (id int) { filter := qt.NewFilterFromMap(object, self.eth) filter.MessageCallback = func(messages state.Messages) { self.win.Root().Call("invokeFilterCallback", xeth.ToJSMessages(messages), id) } - id = self.eth.InstallFilter(filter) + id = self.filterManager.InstallFilter(filter) return id } @@ -239,12 +320,12 @@ func (self *UiLib) NewFilterString(typ string) (id int) { fmt.Println("QML is lagging") } } - id = self.eth.InstallFilter(filter) + id = self.filterManager.InstallFilter(filter) return id } func (self *UiLib) Messages(id int) *ethutil.List { - filter := self.eth.GetFilter(id) + filter := self.filterManager.GetFilter(id) if filter != nil { messages := xeth.ToJSMessages(filter.Find()) @@ -255,7 +336,7 @@ func (self *UiLib) Messages(id int) *ethutil.List { } func (self *UiLib) UninstallFilter(id int) { - self.eth.UninstallFilter(id) + self.filterManager.UninstallFilter(id) } func mapToTxParams(object map[string]interface{}) map[string]string { @@ -308,67 +389,3 @@ func mapToTxParams(object map[string]interface{}) map[string]string { return conv } - -func (self *UiLib) Transact(params map[string]interface{}) (string, error) { - object := mapToTxParams(params) - - return self.JSXEth.Transact( - object["from"], - object["to"], - object["value"], - object["gas"], - object["gasPrice"], - object["data"], - ) -} - -func (self *UiLib) Compile(code string) (string, error) { - bcode, err := ethutil.Compile(code, false) - if err != nil { - return err.Error(), err - } - - return ethutil.Bytes2Hex(bcode), err -} - -func (self *UiLib) Call(params map[string]interface{}) (string, error) { - object := mapToTxParams(params) - - return self.JSXEth.Execute( - object["to"], - object["value"], - object["gas"], - object["gasPrice"], - object["data"], - ) -} - -func (self *UiLib) AddLocalTransaction(to, data, gas, gasPrice, value string) int { - return self.miner.AddLocalTx(&miner.LocalTx{ - To: ethutil.Hex2Bytes(to), - Data: ethutil.Hex2Bytes(data), - Gas: gas, - GasPrice: gasPrice, - Value: value, - }) - 1 -} - -func (self *UiLib) RemoveLocalTransaction(id int) { - self.miner.RemoveLocalTx(id) -} - -func (self *UiLib) SetGasPrice(price string) { - self.miner.MinAcceptedGasPrice = ethutil.Big(price) -} - -func (self *UiLib) ToggleMining() bool { - if !self.miner.Mining() { - self.miner.Start() - - return true - } else { - self.miner.Stop() - - return false - } -} |