diff --git a/ethereal/assets/ext/home.html b/ethereal/assets/ext/home.html index 54af769911..86a659d65f 100644 --- a/ethereal/assets/ext/home.html +++ b/ethereal/assets/ext/home.html @@ -14,7 +14,7 @@ h1 { -

Ethereum

+

... Ethereum ...

diff --git a/ethereal/assets/ext/messaging.js b/ethereal/assets/ext/messaging.js new file mode 100644 index 0000000000..e7bc630202 --- /dev/null +++ b/ethereal/assets/ext/messaging.js @@ -0,0 +1,117 @@ +function handleMessage(message) { + console.log("[onMessageReceived]: ", message.data) + // TODO move to messaging.js + var data = JSON.parse(message.data) + + try { + switch(data.call) { + case "getCoinBase": + postData(data._seed, eth.getCoinBase()) + + break + case "getIsListening": + postData(data._seed, eth.getIsListening()) + + break + case "getIsMining": + postData(data._seed, eth.getIsMining()) + + break + case "getPeerCount": + postData(data._seed, eth.getPeerCount()) + + break + + case "getTxCountAt": + require(1) + postData(data._seed, eth.getTxCountAt(data.args[0])) + + break + case "getBlockByNumber": + var block = eth.getBlock(data.args[0]) + postData(data._seed, block) + + break + case "getBlockByHash": + var block = eth.getBlock(data.args[0]) + postData(data._seed, block) + + break + case "transact": + require(5) + + var tx = eth.transact(data.args[0], data.args[1], data.args[2],data.args[3],data.args[4],data.args[5]) + postData(data._seed, tx) + + break + case "create": + postData(data._seed, null) + + break + case "getStorage": + require(2); + + var stateObject = eth.getStateObject(data.args[0]) + var storage = stateObject.getStorage(data.args[1]) + postData(data._seed, storage) + + break + case "getStateKeyVals": + require(1); + var stateObject = eth.getStateObject(data.args[0]).stateKeyVal(true) + 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); + + postData(data._seed, eth.getStateObject(data.args[0]).value()); + + break + case "getKey": + var key = eth.getKey().privateKey; + + postData(data._seed, key) + break + case "watch": + require(1) + eth.watch(data.args[0], data.args[1]); + break + case "disconnect": + require(1) + postData(data._seed, null) + break; + case "set": + console.log("'Set' has been depcrecated") + /* + for(var key in data.args) { + if(webview.hasOwnProperty(key)) { + window[key] = data.args[key]; + } + } + */ + break; + case "getSecretToAddress": + require(1) + postData(data._seed, eth.secretToAddress(data.args[0])) + break; + case "debug": + console.log(data.args[0]); + break; + } + } catch(e) { + console.log(data.call + ": " + e) + + postData(data._seed, null); + } +} + +function postData(seed, data) { + webview.experimental.postMessage(JSON.stringify({data: data, _seed: seed})) +} diff --git a/ethereal/assets/qml/wallet.qml b/ethereal/assets/qml/wallet.qml index 92641fb3ef..e3ef148b0b 100644 --- a/ethereal/assets/qml/wallet.qml +++ b/ethereal/assets/qml/wallet.qml @@ -56,6 +56,13 @@ ApplicationWindow { shortcut: "Ctrl+d" onTriggered: ui.startDebugger() } + + MenuItem { + text: "Import Tx" + onTriggered: { + txImportDialog.visible = true + } + } } Menu { @@ -98,6 +105,7 @@ ApplicationWindow { historyView.visible = false newTxView.visible = false infoView.visible = false + pendingTxView.visible = false view.visible = true //root.title = "Ethereal - " = view.title } @@ -161,6 +169,17 @@ ApplicationWindow { } } } + + Image { + source: "../tx.png" + anchors.horizontalCenter: parent.horizontalCenter + MouseArea { + anchors.fill: parent + onClicked: { + setView(pendingTxView) + } + } + } } } @@ -365,6 +384,28 @@ ApplicationWindow { } } + Rectangle { + anchors.fill: parent + visible: false + id: pendingTxView + property var title: "Pending Transactions" + + property var pendingTxModel: ListModel { + id: pendingTxModel + } + + TableView { + id: pendingTxTableView + anchors.fill: parent + TableViewColumn{ role: "value" ; title: "Value" ; width: 100 } + TableViewColumn{ role: "from" ; title: "sender" ; width: 230 } + TableViewColumn{ role: "to" ; title: "Reciever" ; width: 230 } + TableViewColumn{ role: "contract" ; title: "Contract" ; width: 100 } + + model: pendingTxModel + } + } + /* signal addPlugin(string name) Component { @@ -500,6 +541,36 @@ ApplicationWindow { } } + Window { + id: txImportDialog + minimumWidth: 270 + maximumWidth: 270 + maximumHeight: 50 + minimumHeight: 50 + TextField { + id: txImportField + width: 170 + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: 10 + onAccepted: { + } + } + Button { + anchors.left: txImportField.right + anchors.verticalCenter: parent.verticalCenter + anchors.leftMargin: 5 + text: "Import" + onClicked: { + eth.importTx(txImportField.text) + txImportField.visible = false + } + } + Component.onCompleted: { + addrField.focus = true + } + } + Window { id: popup visible: false @@ -719,7 +790,7 @@ ApplicationWindow { walletValueLabel.text = value } - function addTx(tx, inout) { + function addTx(type, tx, inout) { var isContract if (tx.contract == true){ isContract = "Yes" @@ -727,13 +798,19 @@ ApplicationWindow { isContract = "No" } - var address; - if(inout == "recv") { - address = tx.sender; - } else { - address = tx.address; + + if(type == "post") { + var address; + if(inout == "recv") { + address = tx.sender; + } else { + address = tx.address; + } + + txModel.insert(0, {inout: inout, hash: tx.hash, address: address, value: tx.value, contract: isContract}) + } else if(type == "pre") { + pendingTxModel.insert(0, {hash: tx.hash, to: tx.address, from: tx.sender, value: tx.value, contract: isContract}) } - txModel.insert(0, {inout: inout, hash: tx.hash, address: address, value: tx.value, contract: isContract}) } function addBlock(block, initial) { @@ -749,7 +826,7 @@ ApplicationWindow { if(initial){ blockModel.append({number: block.number, name: block.name, gasLimit: block.gasLimit, gasUsed: block.gasUsed, coinbase: block.coinbase, hash: block.hash, txs: txs, txAmount: amount, time: block.time, prettyTime: convertToPretty(block.time)}) - }else{ + } else { blockModel.insert(0, {number: block.number, name: block.name, gasLimit: block.gasLimit, gasUsed: block.gasUsed, coinbase: block.coinbase, hash: block.hash, txs: txs, txAmount: amount, time: block.time, prettyTime: convertToPretty(block.time)}) } } @@ -805,7 +882,7 @@ ApplicationWindow { // ****************************************** Window { id: peerWindow - //flags: Qt.CustomizeWindowHint | Qt.Tool | Qt.WindowCloseButtonHint + //flags: Qt.CustomizeWindowHint | Qt.Tool | Qt.WindowCloseButtonHint height: 200 width: 700 Rectangle { @@ -932,10 +1009,10 @@ ApplicationWindow { placeholderText: "Gas" text: "500" /* - onTextChanged: { - contractFormReady() - } - */ + onTextChanged: { + contractFormReady() + } + */ } Label { id: atLabel @@ -949,10 +1026,10 @@ ApplicationWindow { text: "10" validator: RegExpValidator { regExp: /\d*/ } /* - onTextChanged: { - contractFormReady() - } - */ + onTextChanged: { + contractFormReady() + } + */ } ComboBox { diff --git a/ethereal/gui.go b/ethereal/gui.go index 61f7b1099a..36e147ba97 100644 --- a/ethereal/gui.go +++ b/ethereal/gui.go @@ -13,6 +13,7 @@ import ( "github.com/ethereum/eth-go/ethdb" "github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethminer" + "github.com/ethereum/eth-go/ethpipe" "github.com/ethereum/eth-go/ethpub" "github.com/ethereum/eth-go/ethreact" "github.com/ethereum/eth-go/ethutil" @@ -236,20 +237,54 @@ func (gui *Gui) loadAddressBook() { } } -func (gui *Gui) readPreviousTransactions() { - it := gui.txDb.Db().NewIterator(nil, nil) +func (gui *Gui) insertTransaction(window string, tx *ethchain.Transaction) { + nameReg := ethpipe.New(gui.eth).World().Config().Get("NameReg") addr := gui.address() - for it.Next() { - tx := ethchain.NewTransactionFromBytes(it.Value()) - var inout string - if bytes.Compare(tx.Sender(), addr) == 0 { - inout = "send" + var inout string + if bytes.Compare(tx.Sender(), addr) == 0 { + inout = "send" + } else { + inout = "recv" + } + + var ( + ptx = ethpub.NewPTx(tx) + send = nameReg.Storage(tx.Sender()) + rec = nameReg.Storage(tx.Recipient) + s, r string + ) + + if tx.CreatesContract() { + rec = nameReg.Storage(tx.CreationAddress()) + } + + if send.Len() != 0 { + s = strings.Trim(send.Str(), "\x00") + } else { + s = ethutil.Bytes2Hex(tx.Sender()) + } + if rec.Len() != 0 { + r = strings.Trim(rec.Str(), "\x00") + } else { + if tx.CreatesContract() { + r = ethutil.Bytes2Hex(tx.CreationAddress()) } else { - inout = "recv" + r = ethutil.Bytes2Hex(tx.Recipient) } + } + ptx.Sender = s + ptx.Address = r + + gui.win.Root().Call("addTx", window, ptx, inout) +} - gui.win.Root().Call("addTx", ethpub.NewPTx(tx), inout) +func (gui *Gui) readPreviousTransactions() { + it := gui.txDb.Db().NewIterator(nil, nil) + for it.Next() { + tx := ethchain.NewTransactionFromBytes(it.Value()) + + gui.insertTransaction("post", tx) } it.Release() @@ -322,24 +357,26 @@ func (gui *Gui) update() { object := state.GetAccount(gui.address()) if bytes.Compare(tx.Sender(), gui.address()) == 0 { - gui.win.Root().Call("addTx", ethpub.NewPTx(tx), "send") - gui.txDb.Put(tx.Hash(), tx.RlpEncode()) - unconfirmedFunds.Sub(unconfirmedFunds, tx.Value) } else if bytes.Compare(tx.Recipient, gui.address()) == 0 { - gui.win.Root().Call("addTx", ethpub.NewPTx(tx), "recv") - gui.txDb.Put(tx.Hash(), tx.RlpEncode()) - unconfirmedFunds.Add(unconfirmedFunds, tx.Value) } gui.setWalletValue(object.Balance, unconfirmedFunds) + + gui.insertTransaction("pre", tx) } else { object := state.GetAccount(gui.address()) if bytes.Compare(tx.Sender(), gui.address()) == 0 { object.SubAmount(tx.Value) + + gui.win.Root().Call("addTx", "post", ethpub.NewPTx(tx), "send") + gui.txDb.Put(tx.Hash(), tx.RlpEncode()) } else if bytes.Compare(tx.Recipient, gui.address()) == 0 { object.AddAmount(tx.Value) + + gui.win.Root().Call("addTx", "post", ethpub.NewPTx(tx), "recv") + gui.txDb.Put(tx.Hash(), tx.RlpEncode()) } gui.setWalletValue(object.Balance, nil) @@ -422,6 +459,11 @@ func (gui *Gui) Create(recipient, value, gas, gasPrice, data string) (*ethpub.PR return gui.pub.Transact(gui.privateKey(), recipient, value, gas, gasPrice, data) } +func (self *Gui) ImportTx(rlpTx string) { + tx := ethchain.NewTransactionFromBytes(ethutil.Hex2Bytes(rlpTx)) + self.eth.TxPool().QueueTransaction(tx) +} + func (gui *Gui) SetCustomIdentifier(customIdentifier string) { gui.clientIdentity.SetCustomIdentifier(customIdentifier) gui.config.Save("id", customIdentifier)