diff --git a/README.md b/README.md index e0d19b712..034b35f97 100644 --- a/README.md +++ b/README.md @@ -3,44 +3,18 @@ Ethereum [![Build Status](https://travis-ci.org/ethereum/go-ethereum.png?branch=master)](https://travis-ci.org/ethereum/go-ethereum) -Ethereum Go developer client (c) Jeffrey Wilcke - -Ethereum is currently in its testing phase. The current state is "Proof -of Concept 2". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Edge). - -Ethereum Go is split up in several sub packages Please refer to each -individual package for more information. - 1. [eth](https://github.com/ethereum/eth-go) - 2. [ethchain](https://github.com/ethereum/eth-go/ethchain) - 3. [ethwire](https://github.com/ethereum/eth-go/ethwire) - 4. [ethdb](https://github.com/ethereum/eth-go/ethdb) - 5. [ethutil](https://github.com/ethereum/eth-go/ethutil) - -The [eth](https://github.com/ethereum/eth-go) is the top-level package -of the Ethereum protocol. It functions as the Ethereum bootstrapping and -peer communication layer. The [ethchain](https://github.com/ethereum/ethchain-go) -contains the Ethereum blockchain, block manager, transaction and -transaction handlers. The [ethwire](https://github.com/ethereum/ethwire-go) contains -the Ethereum [wire protocol](http://wiki.ethereum.org/index.php/Wire_Protocol) which can be used -to hook in to the Ethereum network. [ethutil](https://github.com/ethereum/ethutil-go) contains -utility functions which are not Ethereum specific. The utility package -contains the [patricia trie](http://wiki.ethereum.org/index.php/Patricia_Tree), -[RLP Encoding](http://wiki.ethereum.org/index.php/RLP) and hex encoding -helpers. The [ethdb](https://github.com/ethereum/ethdb-go) package -contains the LevelDB interface and memory DB interface. - -This executable is the front-end (currently nothing but a dev console) for -the Ethereum Go implementation. - -If you'd like to start developing your own tools please check out the -[development](https://github.com/ethereum/eth-go) package. +Ethereum Go Client (c) Jeffrey Wilcke + +The current state is "Proof of Concept 3". For build instructions see +the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Edge). + +For the development Go Package please see [eth-go package](https://github.com/ethereum/eth-go). Build ======= For build instruction please see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Edge) - Command line options ==================== @@ -52,6 +26,9 @@ Command line options -upnp Enable UPnP (= false) -x Desired amount of peers (= 5) -h This help +-gui Launch with GUI (= true) +-dir Data directory used to store configs and databases (=".ethereum") +-import Import a private key (hex) ``` Developer console commands diff --git a/dev_console.go b/dev_console.go index 696493cdd..09e06aa22 100644 --- a/dev_console.go +++ b/dev_console.go @@ -179,13 +179,13 @@ func (i *Console) ParseInput(input string) bool { fmt.Println("recipient err:", err) } else { tx := ethchain.NewTransaction(recipient, ethutil.Big(tokens[2]), []string{""}) - data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) - keyRing := ethutil.NewValueFromBytes(data) - tx.Sign(keyRing.Get(0).Bytes()) - fmt.Printf("%x\n", tx.Hash()) + + key := ethutil.Config.Db.GetKeys()[0] + tx.Sign(key.PrivateKey) i.ethereum.TxPool.QueueTransaction(tx) - } + fmt.Printf("%x\n", tx.Hash()) + } case "gettx": addr, _ := hex.DecodeString(tokens[1]) data, _ := ethutil.Config.Db.Get(addr) @@ -200,9 +200,9 @@ func (i *Console) ParseInput(input string) bool { code := ethchain.Compile(i.Editor()) contract := ethchain.NewTransaction(ethchain.ContractAddr, ethutil.Big(tokens[1]), code) - data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) - keyRing := ethutil.NewValueFromBytes(data) - contract.Sign(keyRing.Get(0).Bytes()) + + key := ethutil.Config.Db.GetKeys()[0] + contract.Sign(key.PrivateKey) i.ethereum.TxPool.QueueTransaction(contract) diff --git a/ethereum.go b/ethereum.go index 0b941dce3..336cd4d00 100644 --- a/ethereum.go +++ b/ethereum.go @@ -36,7 +36,8 @@ func CreateKeyPair(force bool) { data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) if len(data) == 0 || force { pub, prv := secp256k1.GenerateKeyPair() - addr := ethutil.Sha3Bin(pub[1:])[12:] + pair := ðutil.Key{PrivateKey: prv, PublicKey: pub} + ethutil.Config.Db.Put([]byte("KeyRing"), pair.RlpEncode()) fmt.Printf(` Generating new address and keypair. @@ -48,10 +49,8 @@ prvk: %x pubk: %x ++++++++++++++++++++++++++++++++++++++++++++ -`, addr, prv, pub) +`, pair.Address(), prv, pub) - keyRing := ethutil.NewValue([]interface{}{prv, addr, pub[1:]}) - ethutil.Config.Db.Put([]byte("KeyRing"), keyRing.Encode()) } } @@ -61,7 +60,8 @@ func ImportPrivateKey(prvKey string) { // Couldn't think of a better way to get the pub key sig, _ := secp256k1.Sign(msg, key) pub, _ := secp256k1.RecoverPubkey(msg, sig) - addr := ethutil.Sha3Bin(pub[1:])[12:] + pair := ðutil.Key{PrivateKey: key, PublicKey: pub} + ethutil.Config.Db.Put([]byte("KeyRing"), pair.RlpEncode()) fmt.Printf(` Importing private key @@ -72,10 +72,7 @@ prvk: %x pubk: %x ++++++++++++++++++++++++++++++++++++++++++++ -`, addr, key, pub) - - keyRing := ethutil.NewValue([]interface{}{key, addr, pub[1:]}) - ethutil.Config.Db.Put([]byte("KeyRing"), keyRing.Encode()) +`, pair.Address(), key, pub) } func main() { @@ -95,11 +92,11 @@ func main() { // Instantiated a eth stack ethereum, err := eth.New(eth.CapDefault, UseUPnP) - ethereum.Port = OutboundPort if err != nil { log.Println("eth start err:", err) return } + ethereum.Port = OutboundPort if GenAddr { fmt.Println("This action overwrites your old private key. Are you sure? (y/n)") @@ -133,6 +130,7 @@ func main() { if r == "y" { ImportPrivateKey(ImportKey) + os.Exit(0) } } else { CreateKeyPair(false) @@ -140,9 +138,8 @@ func main() { } if ExportKey { - data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) - keyRing := ethutil.NewValueFromBytes(data) - fmt.Printf("%x\n", keyRing.Get(0).Bytes()) + key := ethutil.Config.Db.GetKeys()[0] + fmt.Printf("%x\n", key.PrivateKey) os.Exit(0) } diff --git a/net.png b/net.png new file mode 100644 index 000000000..65a20ea00 Binary files /dev/null and b/net.png differ diff --git a/net.pxm b/net.pxm new file mode 100644 index 000000000..20d45d08c Binary files /dev/null and b/net.pxm differ diff --git a/new.png b/new.png new file mode 100644 index 000000000..e80096748 Binary files /dev/null and b/new.png differ diff --git a/tx.png b/tx.png new file mode 100644 index 000000000..62204c315 Binary files /dev/null and b/tx.png differ diff --git a/tx.pxm b/tx.pxm new file mode 100644 index 000000000..881420da9 Binary files /dev/null and b/tx.pxm differ diff --git a/ui/gui.go b/ui/gui.go index 6e30b5891..556e682a9 100644 --- a/ui/gui.go +++ b/ui/gui.go @@ -9,6 +9,7 @@ import ( "github.com/ethereum/eth-go/ethdb" "github.com/ethereum/eth-go/ethutil" "github.com/niemeyer/qml" + "math/big" "strings" ) @@ -62,9 +63,8 @@ func New(ethereum *eth.Ethereum) *Gui { panic(err) } - data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) - keyRing := ethutil.NewValueFromBytes(data) - addr := keyRing.Get(1).Bytes() + key := ethutil.Config.Db.GetKeys()[0] + addr := key.Address() ethereum.BlockManager.WatchAddr(addr) @@ -127,7 +127,7 @@ func (ui *Gui) setInitialBlockChain() { } func (ui *Gui) readPreviousTransactions() { - it := ui.txDb.Db().NewIterator(nil) + it := ui.txDb.Db().NewIterator(nil, nil) for it.Next() { tx := ethchain.NewTransactionFromBytes(it.Value()) @@ -140,45 +140,50 @@ func (ui *Gui) ProcessBlock(block *ethchain.Block) { ui.win.Root().Call("addBlock", NewBlockFromBlock(block)) } -func (ui *Gui) ProcessTransaction(tx *ethchain.Transaction) { - ui.txDb.Put(tx.Hash(), tx.RlpEncode()) - - ui.win.Root().Call("addTx", NewTxFromTransaction(tx)) - - // TODO replace with general subscribe model -} - // Simple go routine function that updates the list of peers in the GUI func (ui *Gui) update() { - txChan := make(chan ethchain.TxMsg) + txChan := make(chan ethchain.TxMsg, 1) ui.eth.TxPool.Subscribe(txChan) account := ui.eth.BlockManager.GetAddrState(ui.addr).Account + unconfirmedFunds := new(big.Int) ui.win.Root().Call("setWalletValue", fmt.Sprintf("%v", ethutil.CurrencyToString(account.Amount))) for { select { case txMsg := <-txChan: tx := txMsg.Tx - ui.txDb.Put(tx.Hash(), tx.RlpEncode()) - ui.win.Root().Call("addTx", NewTxFromTransaction(tx)) - // TODO FOR THE LOVE OF EVERYTHING GOOD IN THIS WORLD REFACTOR ME if txMsg.Type == ethchain.TxPre { if bytes.Compare(tx.Sender(), ui.addr) == 0 { - ui.win.Root().Call("setWalletValue", fmt.Sprintf("%v (- %v)", ethutil.CurrencyToString(account.Amount), ethutil.CurrencyToString(tx.Value))) + ui.win.Root().Call("addTx", NewTxFromTransaction(tx)) + ui.txDb.Put(tx.Hash(), tx.RlpEncode()) + ui.eth.BlockManager.GetAddrState(ui.addr).Nonce += 1 - fmt.Println("Nonce", ui.eth.BlockManager.GetAddrState(ui.addr).Nonce) + unconfirmedFunds.Sub(unconfirmedFunds, tx.Value) } else if bytes.Compare(tx.Recipient, ui.addr) == 0 { - ui.win.Root().Call("setWalletValue", fmt.Sprintf("%v (+ %v)", ethutil.CurrencyToString(account.Amount), ethutil.CurrencyToString(tx.Value))) + ui.win.Root().Call("addTx", NewTxFromTransaction(tx)) + ui.txDb.Put(tx.Hash(), tx.RlpEncode()) + + unconfirmedFunds.Add(unconfirmedFunds, tx.Value) + } + + pos := "+" + if unconfirmedFunds.Cmp(big.NewInt(0)) >= 0 { + pos = "-" } + val := ethutil.CurrencyToString(new(big.Int).Abs(ethutil.BigCopy(unconfirmedFunds))) + str := fmt.Sprintf("%v (%s %v)", ethutil.CurrencyToString(account.Amount), pos, val) + + ui.win.Root().Call("setWalletValue", str) } else { + amount := account.Amount if bytes.Compare(tx.Sender(), ui.addr) == 0 { - amount := account.Amount.Sub(account.Amount, tx.Value) - ui.win.Root().Call("setWalletValue", fmt.Sprintf("%v", ethutil.CurrencyToString(amount))) + amount.Sub(account.Amount, tx.Value) } else if bytes.Compare(tx.Recipient, ui.addr) == 0 { - amount := account.Amount.Sub(account.Amount, tx.Value) - ui.win.Root().Call("setWalletValue", fmt.Sprintf("%v", ethutil.CurrencyToString(amount))) + amount.Add(account.Amount, tx.Value) } + + ui.win.Root().Call("setWalletValue", fmt.Sprintf("%v", ethutil.CurrencyToString(amount))) } } diff --git a/ui/ui_lib.go b/ui/ui_lib.go index 93712eba2..c956fd032 100644 --- a/ui/ui_lib.go +++ b/ui/ui_lib.go @@ -27,9 +27,11 @@ func (ui *UiLib) Open(path string) { }() } -func (ui *UiLib) Connect() { +func (ui *UiLib) Connect(button qml.Object) { if !ui.connected { ui.eth.Start() + ui.connected = true + button.Set("enabled", false) } } diff --git a/wallet.qml b/wallet.qml index 04c1ffaed..8c91039fc 100644 --- a/wallet.qml +++ b/wallet.qml @@ -15,35 +15,6 @@ ApplicationWindow { title: "Ethereal" - toolBar: ToolBar { - id: mainToolbar - - RowLayout { - width: parent.width - Button { - text: "Send" - onClicked: { - console.log(eth.createTx(txReceiver.text, txAmount.text, codeView.text)) - } - } - - TextField { - id: txAmount - width: 200 - placeholderText: "Amount" - } - - TextField { - id: txReceiver - width: 300 - placeholderText: "Receiver Address (or empty for contract)" - Layout.fillWidth: true - } - - } - } - - MenuBar { Menu { title: "File" @@ -86,35 +57,61 @@ ApplicationWindow { property var blockModel: ListModel { id: blockModel } - function setView(view) { - mainView.visible = false - transactionView.visible = false - view.visible = true - } + + function setView(view) { + networkView.visible = false + historyView.visible = false + newTxView.visible = false + view.visible = true + //root.title = "Ethereal - " = view.title + } SplitView { anchors.fill: parent - + resizing: false Rectangle { id: menu - width: 200 + Layout.minimumWidth: 80 + Layout.maximumWidth: 80 anchors.bottom: parent.bottom anchors.top: parent.top - color: "#D9DDE7" + //color: "#D9DDE7" + color: "#252525" - GridLayout { - columns: 1 - Button { - text: "Main" - onClicked: { - setView(mainView) + ColumnLayout { + y: 50 + anchors.left: parent.left + anchors.right: parent.right + height: 200 + Image { + source: "tx.png" + anchors.horizontalCenter: parent.horizontalCenter + MouseArea { + anchors.fill: parent + onClicked: { + setView(historyView) + } } } - Button { - text: "Transactions" - onClicked: { - setView(transactionView) + Image { + source: "new.png" + anchors.horizontalCenter: parent.horizontalCenter + MouseArea { + anchors.fill: parent + onClicked: { + setView(newTxView) + } + } + } + Image { + source: "net.png" + anchors.horizontalCenter: parent.horizontalCenter + MouseArea { + anchors.fill: parent + onClicked: { + setView(networkView) + } } } } @@ -126,8 +123,8 @@ ApplicationWindow { } Rectangle { - id: transactionView - visible: false + id: historyView + property var title: "Transactions" anchors.right: parent.right anchors.left: menu.right anchors.bottom: parent.bottom @@ -135,40 +132,73 @@ ApplicationWindow { TableView { id: txTableView anchors.fill: parent - TableViewColumn{ role: "hash" ; title: "#" ; width: 150 } TableViewColumn{ role: "value" ; title: "Value" ; width: 100 } - TableViewColumn{ role: "address" ; title: "Address" ; } + TableViewColumn{ role: "address" ; title: "Address" ; width: 430 } model: txModel } } Rectangle { - id: mainView + id: newTxView + property var title: "New transaction" + visible: false anchors.right: parent.right + anchors.left: menu.right anchors.bottom: parent.bottom anchors.top: parent.top - SplitView { - id: splitView - height: 200 - anchors.top: parent.top - anchors.right: parent.right + color: "#00000000" + + ColumnLayout { + width: 400 anchors.left: parent.left + anchors.top: parent.top + anchors.leftMargin: 5 + anchors.topMargin: 5 + TextField { + id: txAmount + width: 200 + placeholderText: "Amount" + } + + TextField { + id: txReceiver + placeholderText: "Receiver Address (or empty for contract)" + Layout.fillWidth: true + } + Label { + text: "Transaction data" + } TextArea { id: codeView + anchors.topMargin: 5 + Layout.fillWidth: true width: parent.width /2 } - TextArea { - readOnly: true + Button { + text: "Send" + onClicked: { + console.log(eth.createTx(txReceiver.text, txAmount.text, codeView.text)) + } } } + } + + + Rectangle { + id: networkView + property var title: "Network" + visible: false + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.top: parent.top TableView { id: blockTable width: parent.width - anchors.top: splitView.bottom + anchors.top: parent.top anchors.bottom: logView.top TableViewColumn{ role: "number" ; title: "#" ; width: 100 } TableViewColumn{ role: "hash" ; title: "Hash" ; width: 560 } @@ -210,8 +240,13 @@ ApplicationWindow { RowLayout { anchors.fill: parent Button { + property var enabled: true id: connectButton - onClicked: ui.connect() + onClicked: { + if(this.enabled) { + ui.connect(this) + } + } text: "Connect" } Button {