diff --git a/ethereal/assets/ext/ethereum.js b/ethereal/assets/ext/ethereum.js index c58fe24c24..de6fb02553 100644 --- a/ethereal/assets/ext/ethereum.js +++ b/ethereal/assets/ext/ethereum.js @@ -58,6 +58,9 @@ window.eth = { getBalanceAt: function(address, cb) { postData({call: "getBalance", args: [address]}, cb); }, + getTransactionsFor: function(address, cb) { + postData({call: "getTransactionsFor", args: [address]}, cb); + }, getSecretToAddress: function(sec, cb) { postData({call: "getSecretToAddress", args: [sec]}, cb); diff --git a/ethereal/assets/qml/QmlApp.qml b/ethereal/assets/qml/QmlApp.qml new file mode 100644 index 0000000000..f5c503f4c3 --- /dev/null +++ b/ethereal/assets/qml/QmlApp.qml @@ -0,0 +1,22 @@ +import QtQuick 2.0 +import QtQuick.Controls 1.0; +import QtQuick.Layouts 1.0; +import Ethereum 1.0 + +ApplicationWindow { + minimumWidth: 500 + maximumWidth: 500 + maximumHeight: 400 + minimumHeight: 400 + + function onNewBlockCb(block) { + console.log("Please overwrite onNewBlock(block):", block) + } + function onObjectChangeCb(stateObject) { + console.log("Please overwrite onObjectChangeCb(object)", stateObject) + } + function onStorageChangeCb(storageObject) { + var ev = ["storage", storageObject.stateAddress, storageObject.address].join(":"); + console.log("Please overwrite onStorageChangeCb(object)", ev) + } +} diff --git a/ethereal/assets/qml/test_app.qml b/ethereal/assets/qml/test_app.qml index aace4e881f..c69587839e 100644 --- a/ethereal/assets/qml/test_app.qml +++ b/ethereal/assets/qml/test_app.qml @@ -3,33 +3,68 @@ import QtQuick.Controls 1.0; import QtQuick.Layouts 1.0; import Ethereum 1.0 -ApplicationWindow { - minimumWidth: 500 - maximumWidth: 500 - maximumHeight: 100 - minimumHeight: 100 +QmlApp { + minimumWidth: 350 + maximumWidth: 350 + maximumHeight: 80 + minimumHeight: 80 - title: "Ethereum Dice" + title: "Generic Coin" - TextField { - id: textField - anchors.verticalCenter: parent.verticalCenter - anchors.horizontalCenter: parent.horizontalCenter - placeholderText: "Amount" + property string contractAddr: "f299f6c74515620e4c4cd8fe3d205b5c4f2e25c8" + property string addr: "2ef47100e0787b915105fd5e3f4ff6752079d5cb" + + Component.onCompleted: { + eth.watch(contractAddr, addr) + eth.watch(addr, contractAddr) + setAmount() } - Label { - id: txHash - anchors.bottom: textField.top - anchors.bottomMargin: 5 - anchors.horizontalCenter: parent.horizontalCenter + + function onStorageChangeCb(storageObject) { + setAmount() } - Button { - anchors.top: textField.bottom - anchors.horizontalCenter: parent.horizontalCenter - anchors.topMargin: 5 - text: "Place bet" - onClicked: { - txHash.text = eth.createTx("e6716f9544a56c530d868e4bfbacb172315bdead", textField.text) + + function setAmount(){ + var state = eth.getStateObject(contractAddr) + var storage = state.getStorage(addr) + amountLabel.text = storage + } + Column { + spacing: 5 + Row { + spacing: 20 + Label { + id: genLabel + text: "Generic coin balance:" + } + Label { + id: amountLabel + } + } + Row { + spacing: 20 + TextField { + id: address + placeholderText: "Address" + } + TextField { + id: amount + placeholderText: "Amount" + } + } + Button { + text: "Send coins" + onClicked: { + var privKey = eth.getKey().privateKey + if(privKey){ + var result = eth.transact(privKey, contractAddr, 0,"100000","250", "0x" + address.text + "\n" + amount.text) + resultTx.text = result.hash + } + } + } + Label { + id: resultTx } } + } diff --git a/ethereal/assets/qml/wallet.qml b/ethereal/assets/qml/wallet.qml index a7c03f6d18..454d0f3f01 100644 --- a/ethereal/assets/qml/wallet.qml +++ b/ethereal/assets/qml/wallet.qml @@ -372,7 +372,15 @@ ApplicationWindow { onAccepted: { //ui.open(openAppDialog.fileUrl.toString()) //ui.openHtml(Qt.resolvedUrl(ui.assetPath("test.html"))) - ui.openHtml(openAppDialog.fileUrl.toString()) + var path = openAppDialog.fileUrl.toString() + console.log(path) + var ext = path.split('.').pop() + console.log(ext) + if(ext == "html" || ext == "htm") { + ui.openHtml(path) + }else if(ext == "qml"){ + ui.openQml(path) + } } } diff --git a/ethereal/assets/qml/webapp.qml b/ethereal/assets/qml/webapp.qml index 4a5a1293a3..63927f0ebe 100644 --- a/ethereal/assets/qml/webapp.qml +++ b/ethereal/assets/qml/webapp.qml @@ -103,6 +103,12 @@ ApplicationWindow { postData(data._seed,stateObject) break + case "getTransactionsFor": + require(1); + var txs = eth.getTransactionsFor(data.args[0], true) + postData(data._seed, txs) + + break case "getBalance": require(1); diff --git a/ethereal/ui/qml_app.go b/ethereal/ui/qml_app.go new file mode 100644 index 0000000000..d47751616e --- /dev/null +++ b/ethereal/ui/qml_app.go @@ -0,0 +1,59 @@ +package ethui + +import ( + "github.com/ethereum/eth-go/ethchain" + "github.com/ethereum/eth-go/ethpub" + "github.com/ethereum/eth-go/ethutil" + "github.com/go-qml/qml" +) + +type QmlApplication struct { + win *qml.Window + engine *qml.Engine + lib *UiLib + path string +} + +func NewQmlApplication(path string, lib *UiLib) *QmlApplication { + engine := qml.NewEngine() + return &QmlApplication{engine: engine, path: path, lib: lib} +} + +func (app *QmlApplication) Create() error { + component, err := app.engine.LoadFile(app.path) + if err != nil { + ethutil.Config.Log.Debugln(err) + } + app.win = component.CreateWindow(nil) + + return nil +} + +func (app *QmlApplication) Destroy() { + app.engine.Destroy() +} + +func (app *QmlApplication) NewWatcher(quitChan chan bool) { +} + +// Events +func (app *QmlApplication) NewBlock(block *ethchain.Block) { + pblock := ðpub.PBlock{Number: int(block.BlockInfo().Number), Hash: ethutil.Hex(block.Hash())} + app.win.Call("onNewBlockCb", pblock) +} + +func (app *QmlApplication) ObjectChanged(stateObject *ethchain.StateObject) { + app.win.Call("onObjectChangeCb", ethpub.NewPStateObject(stateObject)) +} + +func (app *QmlApplication) StorageChanged(storageObject *ethchain.StorageState) { + app.win.Call("onStorageChangeCb", ethpub.NewPStorageState(storageObject)) +} + +// Getters +func (app *QmlApplication) Engine() *qml.Engine { + return app.engine +} +func (app *QmlApplication) Window() *qml.Window { + return app.win +} diff --git a/ethereal/ui/ui_lib.go b/ethereal/ui/ui_lib.go index 5f6a9ef0bf..ddc955176c 100644 --- a/ethereal/ui/ui_lib.go +++ b/ethereal/ui/ui_lib.go @@ -28,18 +28,11 @@ func NewUiLib(engine *qml.Engine, eth *eth.Ethereum, assetPath string) *UiLib { return &UiLib{engine: engine, eth: eth, assetPath: assetPath} } -// Opens a QML file (external application) -func (ui *UiLib) Open(path string) { - component, err := ui.engine.LoadFile(path[7:]) - if err != nil { - logger.Debugln(err) - } - win := component.CreateWindow(nil) +func (ui *UiLib) OpenQml(path string) { + container := NewQmlApplication(path[7:], ui) + app := NewExtApplication(container, ui) - go func() { - win.Show() - win.Wait() - }() + go app.run() } func (ui *UiLib) OpenHtml(path string) { diff --git a/ethereum/javascript_runtime.go b/ethereum/javascript_runtime.go index ac05be69bc..0a9a882adb 100644 --- a/ethereum/javascript_runtime.go +++ b/ethereum/javascript_runtime.go @@ -144,7 +144,7 @@ func (self *JSRE) initStdFuncs() { eth.Set("require", self.require) eth.Set("stopMining", self.stopMining) eth.Set("startMining", self.startMining) - eth.Set("blockDo", self.execBlock) + eth.Set("execBlock", self.execBlock) } /* @@ -221,7 +221,7 @@ func (self *JSRE) execBlock(call otto.FunctionCall) otto.Value { return otto.UndefinedValue() } - err = self.ethereum.BlockDo(ethutil.FromHex(hash)) + err = utils.BlockDo(self.ethereum, ethutil.FromHex(hash)) if err != nil { fmt.Println(err) return otto.FalseValue() diff --git a/ethereum/repl.go b/ethereum/repl.go index a95d733002..c162c78b08 100644 --- a/ethereum/repl.go +++ b/ethereum/repl.go @@ -1,10 +1,15 @@ package main import ( + "bufio" "fmt" "github.com/ethereum/eth-go" "github.com/ethereum/eth-go/ethpub" + "github.com/ethereum/eth-go/ethutil" "github.com/obscuren/otto" + "io" + "os" + "path" ) type Repl interface { @@ -16,20 +21,40 @@ type JSRepl struct { re *JSRE prompt string + + history *os.File } func NewJSRepl(ethereum *eth.Ethereum) *JSRepl { - return &JSRepl{re: NewJSRE(ethereum), prompt: "> "} + hist, err := os.OpenFile(path.Join(ethutil.Config.ExecPath, "history"), os.O_RDWR|os.O_CREATE, os.ModePerm) + if err != nil { + panic(err) + } + + return &JSRepl{re: NewJSRE(ethereum), prompt: "> ", history: hist} } func (self *JSRepl) Start() { logger.Infoln("init JS Console") + reader := bufio.NewReader(self.history) + for { + line, err := reader.ReadString('\n') + if err != nil && err == io.EOF { + break + } else if err != nil { + fmt.Println("error reading history", err) + break + } + + addHistory(line[:len(line)-1]) + } self.read() } func (self *JSRepl) Stop() { self.re.Stop() logger.Infoln("exit JS Console") + self.history.Close() } func (self *JSRepl) parseInput(code string) { diff --git a/ethereum/repl_darwin.go b/ethereum/repl_darwin.go index b61d4edd7e..62b40059ac 100644 --- a/ethereum/repl_darwin.go +++ b/ethereum/repl_darwin.go @@ -102,7 +102,9 @@ L: break L } - addHistory(str[:len(str)-1]) //allow user to recall this line + hist := str[:len(str)-1] + addHistory(hist) //allow user to recall this line + self.history.WriteString(str) self.parseInput(str) diff --git a/utils/cmd.go b/utils/cmd.go index 8bc9c63faf..34716b94a0 100644 --- a/utils/cmd.go +++ b/utils/cmd.go @@ -219,3 +219,21 @@ func StopMining(ethereum *eth.Ethereum) bool { } return false } + +// Replay block +func BlockDo(ethereum *eth.Ethereum, hash []byte) error { + block := ethereum.BlockChain().GetBlock(hash) + if block == nil { + return fmt.Errorf("unknown block %x", hash) + } + + parent := ethereum.BlockChain().GetBlock(block.PrevHash) + + _, err := ethereum.StateManager().ApplyDiff(parent.State(), parent, block) + if err != nil { + return err + } + + return nil + +}