github.com/jonasnick/go-ethereum@v0.7.12-0.20150216215225-22176f05d387/cmd/mist/ui_lib.go (about) 1 /* 2 This file is part of go-ethereum 3 4 go-ethereum is free software: you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation, either version 3 of the License, or 7 (at your option) any later version. 8 9 go-ethereum is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License 15 along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 /** 18 * @authors 19 * Jeffrey Wilcke <i@jev.io> 20 */ 21 package main 22 23 import ( 24 "fmt" 25 "io/ioutil" 26 "path" 27 28 "github.com/jonasnick/go-ethereum/core/types" 29 "github.com/jonasnick/go-ethereum/eth" 30 "github.com/jonasnick/go-ethereum/ethutil" 31 "github.com/jonasnick/go-ethereum/event/filter" 32 "github.com/jonasnick/go-ethereum/javascript" 33 "github.com/jonasnick/go-ethereum/miner" 34 "github.com/jonasnick/go-ethereum/xeth" 35 "github.com/obscuren/qml" 36 ) 37 38 type memAddr struct { 39 Num string 40 Value string 41 } 42 43 // UI Library that has some basic functionality exposed 44 type UiLib struct { 45 *xeth.XEth 46 engine *qml.Engine 47 eth *eth.Ethereum 48 connected bool 49 assetPath string 50 // The main application window 51 win *qml.Window 52 Db *Debugger 53 DbWindow *DebuggerWindow 54 55 jsEngine *javascript.JSRE 56 57 filterCallbacks map[int][]int 58 filterManager *filter.FilterManager 59 60 miner *miner.Miner 61 } 62 63 func NewUiLib(engine *qml.Engine, eth *eth.Ethereum, assetPath string) *UiLib { 64 lib := &UiLib{XEth: xeth.New(eth), engine: engine, eth: eth, assetPath: assetPath, jsEngine: javascript.NewJSRE(eth), filterCallbacks: make(map[int][]int)} //, filters: make(map[int]*xeth.JSFilter)} 65 lib.miner = miner.New(eth.KeyManager().Address(), eth) 66 lib.filterManager = filter.NewFilterManager(eth.EventMux()) 67 go lib.filterManager.Start() 68 69 return lib 70 } 71 72 func (self *UiLib) Notef(args []interface{}) { 73 guilogger.Infoln(args...) 74 } 75 76 func (self *UiLib) ImportTx(rlpTx string) { 77 tx := types.NewTransactionFromBytes(ethutil.Hex2Bytes(rlpTx)) 78 err := self.eth.TxPool().Add(tx) 79 if err != nil { 80 guilogger.Infoln("import tx failed ", err) 81 } 82 } 83 84 func (self *UiLib) EvalJavascriptFile(path string) { 85 self.jsEngine.LoadExtFile(path[7:]) 86 } 87 88 func (self *UiLib) EvalJavascriptString(str string) string { 89 value, err := self.jsEngine.Run(str) 90 if err != nil { 91 return err.Error() 92 } 93 94 return fmt.Sprintf("%v", value) 95 } 96 97 func (ui *UiLib) OpenQml(path string) { 98 container := NewQmlApplication(path[7:], ui) 99 app := NewExtApplication(container, ui) 100 101 go app.run() 102 } 103 104 func (ui *UiLib) OpenHtml(path string) { 105 container := NewHtmlApplication(path, ui) 106 app := NewExtApplication(container, ui) 107 108 go app.run() 109 } 110 111 func (ui *UiLib) OpenBrowser() { 112 ui.OpenHtml("file://" + ui.AssetPath("ext/home.html")) 113 } 114 115 func (ui *UiLib) Muted(content string) { 116 component, err := ui.engine.LoadFile(ui.AssetPath("qml/muted.qml")) 117 if err != nil { 118 guilogger.Debugln(err) 119 120 return 121 } 122 win := component.CreateWindow(nil) 123 go func() { 124 path := "file://" + ui.AssetPath("muted/index.html") 125 win.Set("url", path) 126 127 win.Show() 128 win.Wait() 129 }() 130 } 131 132 func (ui *UiLib) Connect(button qml.Object) { 133 if !ui.connected { 134 ui.eth.Start() 135 ui.connected = true 136 button.Set("enabled", false) 137 } 138 } 139 140 func (ui *UiLib) ConnectToPeer(nodeURL string) { 141 if err := ui.eth.SuggestPeer(nodeURL); err != nil { 142 guilogger.Infoln("SuggestPeer error: " + err.Error()) 143 } 144 } 145 146 func (ui *UiLib) AssetPath(p string) string { 147 return path.Join(ui.assetPath, p) 148 } 149 150 func (self *UiLib) StartDbWithContractAndData(contractHash, data string) { 151 dbWindow := NewDebuggerWindow(self) 152 object := self.eth.ChainManager().State().GetStateObject(ethutil.Hex2Bytes(contractHash)) 153 if len(object.Code) > 0 { 154 dbWindow.SetCode(ethutil.Bytes2Hex(object.Code)) 155 } 156 dbWindow.SetData(data) 157 158 dbWindow.Show() 159 } 160 161 func (self *UiLib) StartDbWithCode(code string) { 162 dbWindow := NewDebuggerWindow(self) 163 dbWindow.SetCode(code) 164 dbWindow.Show() 165 } 166 167 func (self *UiLib) StartDebugger() { 168 dbWindow := NewDebuggerWindow(self) 169 170 dbWindow.Show() 171 } 172 173 func (self *UiLib) Transact(params map[string]interface{}) (string, error) { 174 object := mapToTxParams(params) 175 176 return self.XEth.Transact( 177 object["to"], 178 object["value"], 179 object["gas"], 180 object["gasPrice"], 181 object["data"], 182 ) 183 } 184 185 func (self *UiLib) Compile(code string) (string, error) { 186 bcode, err := ethutil.Compile(code, false) 187 if err != nil { 188 return err.Error(), err 189 } 190 191 return ethutil.Bytes2Hex(bcode), err 192 } 193 194 func (self *UiLib) Call(params map[string]interface{}) (string, error) { 195 object := mapToTxParams(params) 196 197 return self.XEth.Execute( 198 object["to"], 199 object["value"], 200 object["gas"], 201 object["gasPrice"], 202 object["data"], 203 ) 204 } 205 206 func (self *UiLib) AddLocalTransaction(to, data, gas, gasPrice, value string) int { 207 return 0 208 /* 209 return self.miner.AddLocalTx(&miner.LocalTx{ 210 To: ethutil.Hex2Bytes(to), 211 Data: ethutil.Hex2Bytes(data), 212 Gas: gas, 213 GasPrice: gasPrice, 214 Value: value, 215 }) - 1 216 */ 217 } 218 219 func (self *UiLib) RemoveLocalTransaction(id int) { 220 //self.miner.RemoveLocalTx(id) 221 } 222 223 func (self *UiLib) SetGasPrice(price string) { 224 self.miner.MinAcceptedGasPrice = ethutil.Big(price) 225 } 226 227 func (self *UiLib) SetExtra(extra string) { 228 self.miner.Extra = extra 229 } 230 231 func (self *UiLib) ToggleMining() bool { 232 if !self.miner.Mining() { 233 self.miner.Start() 234 235 return true 236 } else { 237 self.miner.Stop() 238 239 return false 240 } 241 } 242 243 func (self *UiLib) ToHex(data string) string { 244 return "0x" + ethutil.Bytes2Hex([]byte(data)) 245 } 246 247 func (self *UiLib) ToAscii(data string) string { 248 start := 0 249 if len(data) > 1 && data[0:2] == "0x" { 250 start = 2 251 } 252 return string(ethutil.Hex2Bytes(data[start:])) 253 } 254 255 /// Ethereum filter methods 256 func (self *UiLib) NewFilter(object map[string]interface{}, view *qml.Common) (id int) { 257 /* TODO remove me 258 filter := qt.NewFilterFromMap(object, self.eth) 259 filter.MessageCallback = func(messages state.Messages) { 260 view.Call("messages", xeth.ToMessages(messages), id) 261 } 262 id = self.filterManager.InstallFilter(filter) 263 return id 264 */ 265 return 0 266 } 267 268 func (self *UiLib) NewFilterString(typ string, view *qml.Common) (id int) { 269 /* TODO remove me 270 filter := core.NewFilter(self.eth) 271 filter.BlockCallback = func(block *types.Block) { 272 view.Call("messages", "{}", id) 273 } 274 id = self.filterManager.InstallFilter(filter) 275 return id 276 */ 277 return 0 278 } 279 280 func (self *UiLib) Messages(id int) *ethutil.List { 281 /* TODO remove me 282 filter := self.filterManager.GetFilter(id) 283 if filter != nil { 284 messages := xeth.ToMessages(filter.Find()) 285 286 return messages 287 } 288 */ 289 290 return ethutil.EmptyList() 291 } 292 293 func (self *UiLib) ReadFile(p string) string { 294 content, err := ioutil.ReadFile(self.AssetPath(path.Join("ext", p))) 295 if err != nil { 296 guilogger.Infoln("error reading file", p, ":", err) 297 } 298 return string(content) 299 } 300 301 func (self *UiLib) UninstallFilter(id int) { 302 self.filterManager.UninstallFilter(id) 303 } 304 305 func mapToTxParams(object map[string]interface{}) map[string]string { 306 // Default values 307 if object["from"] == nil { 308 object["from"] = "" 309 } 310 if object["to"] == nil { 311 object["to"] = "" 312 } 313 if object["value"] == nil { 314 object["value"] = "" 315 } 316 if object["gas"] == nil { 317 object["gas"] = "" 318 } 319 if object["gasPrice"] == nil { 320 object["gasPrice"] = "" 321 } 322 323 var dataStr string 324 var data []string 325 if list, ok := object["data"].(*qml.List); ok { 326 list.Convert(&data) 327 } else if str, ok := object["data"].(string); ok { 328 data = []string{str} 329 } 330 331 for _, str := range data { 332 if ethutil.IsHex(str) { 333 str = str[2:] 334 335 if len(str) != 64 { 336 str = ethutil.LeftPadString(str, 64) 337 } 338 } else { 339 str = ethutil.Bytes2Hex(ethutil.LeftPadBytes(ethutil.Big(str).Bytes(), 32)) 340 } 341 342 dataStr += str 343 } 344 object["data"] = dataStr 345 346 conv := make(map[string]string) 347 for key, value := range object { 348 if v, ok := value.(string); ok { 349 conv[key] = v 350 } 351 } 352 353 return conv 354 }