go-ethereum/cmd/mist/ui_lib.go
Felix Lange d7b5a87b3b miner: provide coinbase when starting the miner
This avoids having to query the coinbase when creating the miner, which
in turn eliminates the dreaded startup error when no accounts are set
up. Later, this will also allow us to simply restart the miner when the
user picks a different coinbase.

This causes a lot of changes in other packages. These are included in
this commit because they're impossible to separate.
2015-03-11 23:43:27 +01:00

300 lines
6.6 KiB
Go

/*
This file is part of go-ethereum
go-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
go-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @authors
* Jeffrey Wilcke <i@jev.io>
*/
package main
import (
"fmt"
"io/ioutil"
"path"
"github.com/ethereum/go-ethereum/core/types"
"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/xeth"
"github.com/obscuren/qml"
)
type memAddr struct {
Num string
Value string
}
// UI Library that has some basic functionality exposed
type UiLib struct {
*xeth.XEth
engine *qml.Engine
eth *eth.Ethereum
connected bool
assetPath string
// The main application window
win *qml.Window
jsEngine *javascript.JSRE
filterCallbacks map[int][]int
filterManager *filter.FilterManager
}
func NewUiLib(engine *qml.Engine, eth *eth.Ethereum, assetPath string) *UiLib {
x := xeth.New(eth, nil)
lib := &UiLib{XEth: x, engine: engine, eth: eth, assetPath: assetPath, jsEngine: javascript.NewJSRE(x), filterCallbacks: make(map[int][]int)} //, filters: make(map[int]*xeth.JSFilter)}
lib.filterManager = filter.NewFilterManager(eth.EventMux())
go lib.filterManager.Start()
return lib
}
func (self *UiLib) Notef(args []interface{}) {
guilogger.Infoln(args...)
}
func (self *UiLib) ImportTx(rlpTx string) {
tx := types.NewTransactionFromBytes(ethutil.Hex2Bytes(rlpTx))
err := self.eth.TxPool().Add(tx)
if err != nil {
guilogger.Infoln("import tx failed ", err)
}
}
func (self *UiLib) EvalJavascriptFile(path string) {
self.jsEngine.LoadExtFile(path[7:])
}
func (self *UiLib) EvalJavascriptString(str string) string {
value, err := self.jsEngine.Run(str)
if err != nil {
return err.Error()
}
return fmt.Sprintf("%v", value)
}
func (ui *UiLib) Muted(content string) {
component, err := ui.engine.LoadFile(ui.AssetPath("qml/muted.qml"))
if err != nil {
guilogger.Debugln(err)
return
}
win := component.CreateWindow(nil)
go func() {
path := "file://" + ui.AssetPath("muted/index.html")
win.Set("url", path)
win.Show()
win.Wait()
}()
}
func (ui *UiLib) Connect(button qml.Object) {
if !ui.connected {
ui.eth.Start()
ui.connected = true
button.Set("enabled", false)
}
}
func (ui *UiLib) ConnectToPeer(nodeURL string) {
if err := ui.eth.SuggestPeer(nodeURL); err != nil {
guilogger.Infoln("SuggestPeer error: " + err.Error())
}
}
func (ui *UiLib) AssetPath(p string) string {
return path.Join(ui.assetPath, p)
}
func (self *UiLib) Transact(params map[string]interface{}) (string, error) {
object := mapToTxParams(params)
return self.XEth.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.XEth.Execute(
object["to"],
object["value"],
object["gas"],
object["gasPrice"],
object["data"],
)
}
func (self *UiLib) AddLocalTransaction(to, data, gas, gasPrice, value string) int {
return 0
/*
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) ToggleMining() bool {
if !self.eth.IsMining() {
err := self.eth.StartMining()
return err == nil
} else {
self.eth.StopMining()
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{}, view *qml.Common) (id int) {
/* TODO remove me
filter := qt.NewFilterFromMap(object, self.eth)
filter.MessageCallback = func(messages state.Messages) {
view.Call("messages", xeth.ToMessages(messages), id)
}
id = self.filterManager.InstallFilter(filter)
return id
*/
return 0
}
func (self *UiLib) NewFilterString(typ string, view *qml.Common) (id int) {
/* TODO remove me
filter := core.NewFilter(self.eth)
filter.BlockCallback = func(block *types.Block) {
view.Call("messages", "{}", id)
}
id = self.filterManager.InstallFilter(filter)
return id
*/
return 0
}
func (self *UiLib) Messages(id int) *ethutil.List {
/* TODO remove me
filter := self.filterManager.GetFilter(id)
if filter != nil {
messages := xeth.ToMessages(filter.Find())
return messages
}
*/
return ethutil.EmptyList()
}
func (self *UiLib) ReadFile(p string) string {
content, err := ioutil.ReadFile(self.AssetPath(path.Join("ext", p)))
if err != nil {
guilogger.Infoln("error reading file", p, ":", err)
}
return string(content)
}
func (self *UiLib) UninstallFilter(id int) {
self.filterManager.UninstallFilter(id)
}
func mapToTxParams(object map[string]interface{}) map[string]string {
// Default values
if object["from"] == nil {
object["from"] = ""
}
if object["to"] == nil {
object["to"] = ""
}
if object["value"] == nil {
object["value"] = ""
}
if object["gas"] == nil {
object["gas"] = ""
}
if object["gasPrice"] == nil {
object["gasPrice"] = ""
}
var dataStr string
var data []string
if list, ok := object["data"].(*qml.List); ok {
list.Convert(&data)
} else if str, ok := object["data"].(string); ok {
data = []string{str}
}
for _, str := range data {
if ethutil.IsHex(str) {
str = str[2:]
if len(str) != 64 {
str = ethutil.LeftPadString(str, 64)
}
} else {
str = ethutil.Bytes2Hex(ethutil.LeftPadBytes(ethutil.Big(str).Bytes(), 32))
}
dataStr += str
}
object["data"] = dataStr
conv := make(map[string]string)
for key, value := range object {
if v, ok := value.(string); ok {
conv[key] = v
}
}
return conv
}