diff --git a/cmd/mist/assets/ext/eth.js/main.js b/cmd/mist/assets/ext/eth.js/main.js index 5c7ca06034..71e304a550 100644 --- a/cmd/mist/assets/ext/eth.js/main.js +++ b/cmd/mist/assets/ext/eth.js/main.js @@ -352,6 +352,7 @@ web3.provider = new ProviderManager(); web3.setProvider = function(provider) { + console.log("setprovider", provider) provider.onmessage = messageHandler; web3.provider.set(provider); web3.provider.sendQueued(); diff --git a/cmd/mist/assets/qml/browser.qml b/cmd/mist/assets/qml/browser.qml index abaab4f15c..c2f8741bc3 100644 --- a/cmd/mist/assets/qml/browser.qml +++ b/cmd/mist/assets/qml/browser.qml @@ -109,7 +109,8 @@ Rectangle { leftMargin: 5 rightMargin: 5 } - text: "http://etherian.io" + //text: "http://etherian.io" + text: webview.url; id: uriNav y: parent.height / 2 - this.height / 2 @@ -151,6 +152,12 @@ Rectangle { window.open(request.url.toString()); } + function injectJs(js) { + //webview.experimental.navigatorQtObjectEnabled = true; + //webview.experimental.evaluateJavaScript(js) + //webview.experimental.javascriptEnabled = true; + } + function sendMessage(data) { webview.experimental.postMessage(JSON.stringify(data)) } @@ -159,7 +166,6 @@ Rectangle { 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.userScripts: ["../ext/q.js", "../ext/eth.js/main.js", "../ext/eth.js/qt.js", "../ext/setup.js"] experimental.onMessageReceived: { console.log("[onMessageReceived]: ", message.data) @@ -340,24 +346,28 @@ Rectangle { break; case "newIdentity": - postData(data._id, shh.newIdentity()) - break + var id = shh.newIdentity() + console.log("newIdentity", id) + postData(data._id, id) + + 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]; } //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; + 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]; } //params.payload = params.payload.join(""); } + params.topics = params.topics || []; + params.priority = params.priority || 1000; + params.ttl = params.ttl || 100; + + shh.post(params.payload, params.to, params.from, params.topics, params.priority, params.ttl); + + break; } } catch(e) { console.log(data.call + ": " + e) diff --git a/cmd/mist/assets/qml/main.qml b/cmd/mist/assets/qml/main.qml index 111bef8bb4..e287e384f2 100644 --- a/cmd/mist/assets/qml/main.qml +++ b/cmd/mist/assets/qml/main.qml @@ -59,8 +59,8 @@ ApplicationWindow { mainSplit.setView(wallet.view, wallet.menuItem); - // Call the ready handler - gui.done(); + // Command setup + gui.sendCommand(0) } function addViews(view, path, options) { diff --git a/cmd/mist/gui.go b/cmd/mist/gui.go index 2e3f329b2a..083fd5d0a3 100644 --- a/cmd/mist/gui.go +++ b/cmd/mist/gui.go @@ -26,7 +26,9 @@ import ( "bytes" "encoding/json" "fmt" + "io/ioutil" "math/big" + "os" "path" "runtime" "strconv" @@ -48,15 +50,22 @@ import ( var guilogger = logger.NewLogger("GUI") +type ServEv byte + +const ( + setup ServEv = iota + update +) + type Gui struct { // The main application window win *qml.Window // QML Engine engine *qml.Engine component *qml.Common - qmlDone bool // The ethereum interface - eth *eth.Ethereum + eth *eth.Ethereum + serviceEvents chan ServEv // The public Ethereum library uiLib *UiLib @@ -86,7 +95,17 @@ func NewWindow(ethereum *eth.Ethereum, config *ethutil.ConfigManager, clientIden } xeth := xeth.NewJSXEth(ethereum) - gui := &Gui{eth: ethereum, txDb: db, xeth: xeth, logLevel: logger.LogLevel(logLevel), Session: session, open: false, clientIdentity: clientIdentity, config: config, plugins: make(map[string]plugin)} + gui := &Gui{eth: ethereum, + txDb: db, + xeth: xeth, + logLevel: logger.LogLevel(logLevel), + Session: session, + open: false, + clientIdentity: clientIdentity, + config: config, + plugins: make(map[string]plugin), + serviceEvents: make(chan ServEv, 1), + } data, _ := ethutil.ReadAllFile(path.Join(ethutil.Config.ExecPath, "plugins.json")) json.Unmarshal([]byte(data), &gui.plugins) @@ -98,6 +117,8 @@ func (gui *Gui) Start(assetPath string) { guilogger.Infoln("Starting GUI") + go gui.service() + // Register ethereum functions qml.RegisterTypes("Ethereum", 1, 0, []qml.TypeSpec{{ Init: func(p *xeth.JSBlock, obj qml.Object) { p.Number = 0; p.Hash = "" }, @@ -154,18 +175,11 @@ func (gui *Gui) showWallet(context *qml.Context) (*qml.Window, error) { return nil, err } - gui.win = gui.createWindow(component) - - gui.update() + gui.createWindow(component) return gui.win, nil } -// The done handler will be called by QML when all views have been loaded -func (gui *Gui) Done() { - gui.qmlDone = true -} - func (gui *Gui) ImportKey(filePath string) { } @@ -179,10 +193,8 @@ func (gui *Gui) showKeyImport(context *qml.Context) (*qml.Window, error) { } func (gui *Gui) createWindow(comp qml.Object) *qml.Window { - win := comp.CreateWindow(nil) - - gui.win = win - gui.uiLib.win = win + gui.win = comp.CreateWindow(nil) + gui.uiLib.win = gui.win return gui.win } @@ -335,11 +347,48 @@ 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() { - // We have to wait for qml to be done loading all the windows. - for !gui.qmlDone { - time.Sleep(300 * time.Millisecond) +func loadJavascriptAssets(gui *Gui) (jsfiles string) { + for _, fn := range []string{"ext/q.js", "ext/eth.js/main.js", "ext/eth.js/qt.js", "ext/setup.js"} { + f, err := os.Open(gui.uiLib.AssetPath(fn)) + if err != nil { + fmt.Println(err) + continue + } + + content, err := ioutil.ReadAll(f) + if err != nil { + fmt.Println(err) + continue + } + jsfiles += string(content) + } + + return +} + +func (gui *Gui) SendCommand(cmd ServEv) { + gui.serviceEvents <- cmd +} + +func (gui *Gui) service() { + for ev := range gui.serviceEvents { + switch ev { + case setup: + go gui.setup() + case update: + go gui.update() + } + } +} + +func (gui *Gui) setup() { + for gui.win == nil { + time.Sleep(time.Millisecond * 200) + } + + for _, plugin := range gui.plugins { + guilogger.Infoln("Loading plugin ", plugin.Name) + gui.win.Root().Call("addPlugin", plugin.Path, "") } go func() { @@ -349,14 +398,21 @@ func (gui *Gui) update() { gui.setPeerInfo() }() - gui.whisper.SetView(gui.win.Root().ObjectByName("whisperView")) + // Inject javascript files each time navigation is requested. + // Unfortunately webview.experimental.userScripts injects _after_ + // the page has loaded which kind of renders it useless... + jsfiles := loadJavascriptAssets(gui) + gui.getObjectByName("webView").On("navigationRequested", func() { + gui.getObjectByName("webView").Call("injectJs", jsfiles) + }) - for _, plugin := range gui.plugins { - guilogger.Infoln("Loading plugin ", plugin.Name) + gui.whisper.SetView(gui.getObjectByName("whisperView")) - gui.win.Root().Call("addPlugin", plugin.Path, "") - } + gui.SendCommand(update) +} +// Simple go routine function that updates the list of peers in the GUI +func (gui *Gui) update() { peerUpdateTicker := time.NewTicker(5 * time.Second) generalUpdateTicker := time.NewTicker(500 * time.Millisecond) statsUpdateTicker := time.NewTicker(5 * time.Second) @@ -375,77 +431,75 @@ func (gui *Gui) update() { core.TxPostEvent{}, ) - go func() { - defer events.Unsubscribe() - for { - select { - case ev, isopen := <-events.Chan(): - if !isopen { - return + defer events.Unsubscribe() + for { + select { + case ev, isopen := <-events.Chan(): + if !isopen { + return + } + switch ev := ev.(type) { + case core.NewBlockEvent: + gui.processBlock(ev.Block, false) + if bytes.Compare(ev.Block.Coinbase(), gui.address()) == 0 { + gui.setWalletValue(gui.eth.ChainManager().State().GetBalance(gui.address()), nil) } - switch ev := ev.(type) { - case core.NewBlockEvent: - gui.processBlock(ev.Block, false) - if bytes.Compare(ev.Block.Coinbase(), gui.address()) == 0 { - gui.setWalletValue(gui.eth.ChainManager().State().GetBalance(gui.address()), nil) - } - - case core.TxPreEvent: - tx := ev.Tx - tstate := gui.eth.ChainManager().TransState() - cstate := gui.eth.ChainManager().State() + case core.TxPreEvent: + tx := ev.Tx - taccount := tstate.GetAccount(gui.address()) - caccount := cstate.GetAccount(gui.address()) - unconfirmedFunds := new(big.Int).Sub(taccount.Balance(), caccount.Balance()) + tstate := gui.eth.ChainManager().TransState() + cstate := gui.eth.ChainManager().State() - gui.setWalletValue(taccount.Balance(), unconfirmedFunds) - gui.insertTransaction("pre", tx) + taccount := tstate.GetAccount(gui.address()) + caccount := cstate.GetAccount(gui.address()) + unconfirmedFunds := new(big.Int).Sub(taccount.Balance(), caccount.Balance()) - case core.TxPostEvent: - tx := ev.Tx - object := state.GetAccount(gui.address()) + gui.setWalletValue(taccount.Balance(), unconfirmedFunds) + gui.insertTransaction("pre", tx) - if bytes.Compare(tx.From(), gui.address()) == 0 { - object.SubAmount(tx.Value()) + case core.TxPostEvent: + tx := ev.Tx + object := state.GetAccount(gui.address()) - gui.txDb.Put(tx.Hash(), tx.RlpEncode()) - } else if bytes.Compare(tx.To(), gui.address()) == 0 { - object.AddAmount(tx.Value()) + if bytes.Compare(tx.From(), gui.address()) == 0 { + object.SubAmount(tx.Value()) - gui.txDb.Put(tx.Hash(), tx.RlpEncode()) - } + gui.txDb.Put(tx.Hash(), tx.RlpEncode()) + } else if bytes.Compare(tx.To(), gui.address()) == 0 { + object.AddAmount(tx.Value()) - gui.setWalletValue(object.Balance(), nil) - state.UpdateStateObject(object) + gui.txDb.Put(tx.Hash(), tx.RlpEncode()) } - case <-peerUpdateTicker.C: - gui.setPeerInfo() - case <-generalUpdateTicker.C: - statusText := "#" + gui.eth.ChainManager().CurrentBlock().Number().String() - 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 - - 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() + gui.setWalletValue(object.Balance(), nil) + state.UpdateStateObject(object) } + + case <-peerUpdateTicker.C: + gui.setPeerInfo() + case <-generalUpdateTicker.C: + statusText := "#" + gui.eth.ChainManager().CurrentBlock().Number().String() + 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 + + 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() } - }() + } } func (gui *Gui) setStatsPane() { diff --git a/core/chain_manager.go b/core/chain_manager.go index 0b57406228..3e0a3fb23a 100644 --- a/core/chain_manager.go +++ b/core/chain_manager.go @@ -139,7 +139,7 @@ func (bc *ChainManager) setLastBlock() { bc.Reset() } - chainlogger.Infof("Last block (#%d) %x\n", bc.lastBlockNumber, bc.currentBlock.Hash()) + chainlogger.Infof("Last block (#%d) %x TD=%v\n", bc.lastBlockNumber, bc.currentBlock.Hash(), bc.td) } // Block creation & chain handling @@ -215,7 +215,7 @@ func (bc *ChainManager) insert(block *types.Block) { func (bc *ChainManager) write(block *types.Block) { bc.writeBlockInfo(block) - encodedBlock := ethutil.Encode(block) + encodedBlock := ethutil.Encode(block.RlpDataForStorage()) bc.db.Put(block.Hash(), encodedBlock) } diff --git a/core/chain_manager_test.go b/core/chain_manager_test.go index b384c49264..725352dafa 100644 --- a/core/chain_manager_test.go +++ b/core/chain_manager_test.go @@ -1,10 +1,10 @@ package core import ( + "bytes" "fmt" "os" "path" - "reflect" "runtime" "strconv" "testing" @@ -76,11 +76,11 @@ func TestChainInsertions(t *testing.T) { <-done } - if reflect.DeepEqual(chain2[len(chain2)-1], chainMan.CurrentBlock()) { + if bytes.Equal(chain2[len(chain2)-1].Hash(), chainMan.CurrentBlock().Hash()) { t.Error("chain2 is canonical and shouldn't be") } - if !reflect.DeepEqual(chain1[len(chain1)-1], chainMan.CurrentBlock()) { + if !bytes.Equal(chain1[len(chain1)-1].Hash(), chainMan.CurrentBlock().Hash()) { t.Error("chain1 isn't canonical and should be") } } @@ -124,7 +124,7 @@ func TestChainMultipleInsertions(t *testing.T) { <-done } - if !reflect.DeepEqual(chains[longest][len(chains[longest])-1], chainMan.CurrentBlock()) { + if !bytes.Equal(chains[longest][len(chains[longest])-1].Hash(), chainMan.CurrentBlock().Hash()) { t.Error("Invalid canonical chain") } } diff --git a/core/genesis.go b/core/genesis.go index 1590818a8f..d9edaace23 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -25,6 +25,7 @@ func GenesisBlock(db ethutil.Database) *types.Block { genesis.Header().GasLimit = big.NewInt(1000000) genesis.Header().GasUsed = ethutil.Big0 genesis.Header().Time = 0 + genesis.Td = ethutil.Big0 genesis.SetUncles([]*types.Header{}) genesis.SetTransactions(types.Transactions{}) diff --git a/eth/backend.go b/eth/backend.go index 02d3dc942f..ad04863092 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -134,24 +134,20 @@ func New(config *Config) (*Ethereum, error) { eth.blockPool = NewBlockPool(hasBlock, insertChain, ezp.Verify) ethProto := EthProtocol(eth.txPool, eth.chainManager, eth.blockPool) - protocols := []p2p.Protocol{ethProto} - - if config.Shh { - eth.whisper = whisper.New() - protocols = append(protocols, eth.whisper.Protocol()) - } + protocols := []p2p.Protocol{ethProto, eth.whisper.Protocol()} nat, err := p2p.ParseNAT(config.NATType, config.PMPGateway) if err != nil { return nil, err } + fmt.Println(nat) eth.net = &p2p.Server{ Identity: clientId, MaxPeers: config.MaxPeers, Protocols: protocols, Blacklist: eth.blacklist, - NAT: nat, + NAT: p2p.UPNP(), NoDial: !config.Dial, } diff --git a/ethutil/path.go b/ethutil/path.go index f64e3849e0..e545c87315 100644 --- a/ethutil/path.go +++ b/ethutil/path.go @@ -12,7 +12,7 @@ func ExpandHomePath(p string) (path string) { path = p // Check in case of paths like "/something/~/something/" - if path[:2] == "~/" { + if len(path) > 1 && path[:2] == "~/" { usr, _ := user.Current() dir := usr.HomeDir diff --git a/ethutil/rlp.go b/ethutil/rlp.go index 1bc1a58a71..0cb0d611ce 100644 --- a/ethutil/rlp.go +++ b/ethutil/rlp.go @@ -137,7 +137,7 @@ func Encode(object interface{}) []byte { case byte: buff.Write(Encode(big.NewInt(int64(t)))) case *big.Int: - // Not sure how this is possible while we check for + // Not sure how this is possible while we check for nil if t == nil { buff.WriteByte(0xc0) } else { diff --git a/ui/qt/qwhisper/whisper.go b/ui/qt/qwhisper/whisper.go index 0627acd298..8a064c81cd 100644 --- a/ui/qt/qwhisper/whisper.go +++ b/ui/qt/qwhisper/whisper.go @@ -6,10 +6,13 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethutil" + "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/whisper" "gopkg.in/qml.v1" ) +var qlogger = logger.NewLogger("QSHH") + func fromHex(s string) []byte { if len(s) > 1 { return ethutil.Hex2Bytes(s[2:]) @@ -36,9 +39,10 @@ func (self *Whisper) SetView(view qml.Object) { func (self *Whisper) Post(payload []string, to, from string, topics []string, priority, ttl uint32) { var data []byte for _, d := range payload { - data = append(data, fromHex(d)...) + data = append(data, ethutil.Hex2Bytes(d)...) } + fmt.Println(payload, data, "from", from, fromHex(from), crypto.ToECDSA(fromHex(from))) msg := whisper.NewMessage(data) envelope, err := msg.Seal(time.Duration(priority*100000), whisper.Opts{ Ttl: time.Duration(ttl), @@ -47,13 +51,13 @@ func (self *Whisper) Post(payload []string, to, from string, topics []string, pr Topics: whisper.TopicsFromString(topics...), }) if err != nil { - fmt.Println(err) + qlogger.Infoln(err) // handle error return } if err := self.Whisper.Send(envelope); err != nil { - fmt.Println(err) + qlogger.Infoln(err) // handle error return } diff --git a/whisper/message.go b/whisper/message.go index db0110b4a7..5bda849ec8 100644 --- a/whisper/message.go +++ b/whisper/message.go @@ -2,6 +2,7 @@ package whisper import ( "crypto/ecdsa" + "fmt" "time" "github.com/ethereum/go-ethereum/crypto" @@ -53,6 +54,7 @@ type Opts struct { } func (self *Message) Seal(pow time.Duration, opts Opts) (*Envelope, error) { + fmt.Println(opts) if opts.From != nil { err := self.sign(opts.From) if err != nil { diff --git a/whisper/peer.go b/whisper/peer.go index d42b374b53..f82cc6e3e7 100644 --- a/whisper/peer.go +++ b/whisper/peer.go @@ -55,7 +55,7 @@ out: case <-relay.C: err := self.broadcast(self.host.envelopes()) if err != nil { - self.peer.Infoln(err) + self.peer.Infoln("broadcast err:", err) break out } diff --git a/whisper/whisper.go b/whisper/whisper.go index ffcdd7d409..71a4e841ed 100644 --- a/whisper/whisper.go +++ b/whisper/whisper.go @@ -4,6 +4,7 @@ import ( "bytes" "crypto/ecdsa" "errors" + "fmt" "sync" "time" @@ -143,6 +144,7 @@ func (self *Whisper) msgHandler(peer *p2p.Peer, ws p2p.MsgReadWriter) error { if err != nil { return err } + fmt.Println("reading message") envelope, err := NewEnvelopeFromReader(msg.Payload) if err != nil { @@ -160,6 +162,7 @@ func (self *Whisper) msgHandler(peer *p2p.Peer, ws p2p.MsgReadWriter) error { // takes care of adding envelopes to the messages pool. At this moment no sanity checks are being performed. func (self *Whisper) add(envelope *Envelope) error { + fmt.Println("adding") if !envelope.valid() { return errors.New("invalid pow provided for envelope") } @@ -229,11 +232,11 @@ func (self *Whisper) envelopes() (envelopes []*Envelope) { func (self *Whisper) postEvent(envelope *Envelope) { for _, key := range self.keys { if message, err := envelope.Open(key); err == nil || (err != nil && err == ecies.ErrInvalidPublicKey) { - // Create a custom filter? self.filters.Notify(filter.Generic{ Str1: string(crypto.FromECDSA(key)), Str2: string(crypto.FromECDSAPub(message.Recover())), Data: bytesToMap(envelope.Topics), }, message) + break } else { wlogger.Infoln(err) }