From 8c8554f5584dcc0efb4526c1d5f4d50bf2ed3b01 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 18 Feb 2014 01:34:33 +0100 Subject: Added license name and updated block output from the dev console --- LICENSE | 2 +- dev_console.go | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/LICENSE b/LICENSE index 803f2ef4e..b77f7909a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2013 Geff Obscura +Copyright (c) 2013 Jeffrey Wilcke Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/dev_console.go b/dev_console.go index f2283e341..6670d2a44 100644 --- a/dev_console.go +++ b/dev_console.go @@ -136,7 +136,8 @@ func (i *Console) ParseInput(input string) bool { case "block": encoded, _ := hex.DecodeString(tokens[1]) block := i.ethereum.BlockManager.BlockChain().GetBlock(encoded) - fmt.Println(block) + info := block.BlockInfo() + fmt.Printf("++++++++++ #%d ++++++++++\n%v\n", info.Number, block) case "say": i.ethereum.Broadcast(ethwire.MsgTalkTy, []interface{}{tokens[1]}) case "addp": -- cgit v1.2.3 From ab7dc924042b4cdb36ec7f2b26ab14c40d34ec9d Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 18 Feb 2014 12:09:26 +0100 Subject: Added import/exporting of private keys --- config.go | 4 ++++ ethereum.go | 51 ++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/config.go b/config.go index d13bb863b..573f5ded2 100644 --- a/config.go +++ b/config.go @@ -13,6 +13,8 @@ var AddPeer string var MaxPeer int var GenAddr bool var UseSeed bool +var ImportKey string +var ExportKey bool func Init() { flag.BoolVar(&StartConsole, "c", false, "debug and testing console") @@ -21,7 +23,9 @@ func Init() { flag.BoolVar(&UseUPnP, "upnp", false, "enable UPnP support") flag.BoolVar(&UseSeed, "seed", true, "seed peers") flag.BoolVar(&GenAddr, "genaddr", false, "create a new priv/pub key") + flag.BoolVar(&ExportKey, "export", false, "export private key") flag.StringVar(&OutboundPort, "p", "30303", "listening port") + flag.StringVar(&ImportKey, "import", "", "imports the given private key (hex)") flag.IntVar(&MaxPeer, "x", 5, "maximum desired peers") flag.Parse() diff --git a/ethereum.go b/ethereum.go index 372d434af..36700a6d4 100644 --- a/ethereum.go +++ b/ethereum.go @@ -38,8 +38,6 @@ func CreateKeyPair(force bool) { fmt.Printf(` Generating new address and keypair. Please keep your keys somewhere save. -Currently Ethereum(G) does not support -exporting keys. ++++++++++++++++ KeyRing +++++++++++++++++++ addr: %x @@ -54,6 +52,29 @@ pubk: %x } } +func ImportPrivateKey(prvKey string) { + key := ethutil.FromHex(prvKey) + msg := []byte("tmp") + // 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:] + + fmt.Printf(` +Importing private key + +++++++++++++++++ KeyRing +++++++++++++++++++ +addr: %x +prvk: %x +pubk: %x +++++++++++++++++++++++++++++++++++++++++++++ + +`, addr, key, pub) + + keyRing := ethutil.NewValue([]interface{}{key, addr, pub[1:]}) + ethutil.Config.Db.Put([]byte("KeyRing"), keyRing.Encode()) +} + func main() { runtime.GOMAXPROCS(runtime.NumCPU()) Init() @@ -87,7 +108,31 @@ func main() { } os.Exit(0) } else { - CreateKeyPair(false) + if len(ImportKey) > 0 { + fmt.Println("This action overwrites your old private key. Are you sure? (y/n)") + var r string + fmt.Scanln(&r) + for ; ; fmt.Scanln(&r) { + if r == "n" || r == "y" { + break + } else { + fmt.Printf("Yes or no?", r) + } + } + + if r == "y" { + ImportPrivateKey(ImportKey) + } + } else { + CreateKeyPair(false) + } + } + + if ExportKey { + data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) + keyRing := ethutil.NewValueFromBytes(data) + fmt.Printf("%x\n", keyRing.Get(0).Bytes()) + os.Exit(0) } if ShowGenesis { -- cgit v1.2.3 From 6736c03711b3ef35285392c12a79bbf6e4cdf914 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 18 Feb 2014 12:09:36 +0100 Subject: Added editor for contracts --- dev_console.go | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/dev_console.go b/dev_console.go index 6670d2a44..2e6b385df 100644 --- a/dev_console.go +++ b/dev_console.go @@ -2,6 +2,7 @@ package main import ( "bufio" + "bytes" "encoding/hex" "errors" "fmt" @@ -78,6 +79,32 @@ func (i *Console) ValidateInput(action string, argumentLength int) error { } } +func (i *Console) Editor() []string { + var buff bytes.Buffer + for { + reader := bufio.NewReader(os.Stdin) + str, _, err := reader.ReadLine() + if len(str) > 0 { + buff.Write(str) + buff.WriteString("\n") + } + + if err != nil && err.Error() == "EOF" { + break + } + } + + scanner := bufio.NewScanner(strings.NewReader(buff.String())) + scanner.Split(bufio.ScanLines) + + var lines []string + for scanner.Scan() { + lines = append(lines, scanner.Text()) + } + + return lines +} + func (i *Console) PrintRoot() { root := ethutil.NewValue(i.trie.Root) if len(root.Bytes()) != 0 { @@ -169,10 +196,17 @@ func (i *Console) ParseInput(input string) bool { fmt.Println("gettx: tx not found") } case "contract": - contract := ethchain.NewTransaction([]byte{}, ethutil.Big(tokens[1]), []string{"PUSH", "1234"}) - fmt.Printf("%x\n", contract.Hash()) + fmt.Println("Contract editor (Ctrl-D = done)") + code := i.Editor() + + contract := ethchain.NewTransaction([]byte{}, ethutil.Big(tokens[1]), code) + data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) + keyRing := ethutil.NewValueFromBytes(data) + contract.Sign(keyRing.Get(0).Bytes()) i.ethereum.TxPool.QueueTransaction(contract) + + fmt.Printf("%x\n", contract.Hash()) case "exit", "quit", "q": return false case "help": -- cgit v1.2.3 From d7ecc92c4134e3987b2b370bb53b0cd560fc0f7b Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 21 Feb 2014 00:47:07 +0100 Subject: Fixed broken links. Fixes #18 --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index d0a08f7b8..e0d19b712 100644 --- a/README.md +++ b/README.md @@ -11,10 +11,10 @@ of Concept 2". For build instructions see the [Wiki](https://github.com/ethereum 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/ethchain-go) - 3. [ethwire](https://github.com/ethereum/ethwire-go) - 4. [ethdb](https://github.com/ethereum/ethdb-go) - 5. [ethutil](https://github.com/ethereum/ethutil-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 -- cgit v1.2.3 From 05c353eca0c4e01457412dd643529200816ab159 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 21 Feb 2014 12:37:40 +0100 Subject: Added a basic UI --- config.go | 2 ++ ethereum.go | 86 +++++++++++++++++++++++++++++++++++-------------------------- ui/gui.go | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ wallet.qml | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 216 insertions(+), 36 deletions(-) create mode 100644 ui/gui.go create mode 100644 wallet.qml diff --git a/config.go b/config.go index 573f5ded2..c25c8f2a3 100644 --- a/config.go +++ b/config.go @@ -15,11 +15,13 @@ var GenAddr bool var UseSeed bool var ImportKey string var ExportKey bool +var UseGui bool func Init() { flag.BoolVar(&StartConsole, "c", false, "debug and testing console") flag.BoolVar(&StartMining, "m", false, "start dagger mining") flag.BoolVar(&ShowGenesis, "g", false, "prints genesis header and exits") + flag.BoolVar(&UseGui, "gui", false, "use the gui") flag.BoolVar(&UseUPnP, "upnp", false, "enable UPnP support") flag.BoolVar(&UseSeed, "seed", true, "seed peers") flag.BoolVar(&GenAddr, "genaddr", false, "create a new priv/pub key") diff --git a/ethereum.go b/ethereum.go index 36700a6d4..5eda09a44 100644 --- a/ethereum.go +++ b/ethereum.go @@ -5,6 +5,8 @@ import ( "github.com/ethereum/eth-go" "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethutil" + "github.com/ethereum/go-ethereum/ui" + "github.com/niemeyer/qml" "github.com/obscuren/secp256k1-go" "log" "os" @@ -76,9 +78,16 @@ pubk: %x } func main() { - runtime.GOMAXPROCS(runtime.NumCPU()) Init() + // Qt has to be initialized in the main thread or it will throw errors + // It has to be called BEFORE setting the maximum procs. + if UseGui { + qml.Init(nil) + } + + runtime.GOMAXPROCS(runtime.NumCPU()) + ethchain.InitFees() ethutil.ReadConfig(".ethereum") ethutil.Config.Seed = UseSeed @@ -156,41 +165,46 @@ func main() { go console.Start() } - RegisterInterupts(ethereum) - - ethereum.Start() - - if StartMining { - log.Printf("Miner started\n") - - // Fake block mining. It broadcasts a new block every 5 seconds - go func() { - pow := ðchain.EasyPow{} - data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) - keyRing := ethutil.NewValueFromBytes(data) - addr := keyRing.Get(1).Bytes() - - for { - txs := ethereum.TxPool.Flush() - // Create a new block which we're going to mine - block := ethereum.BlockManager.BlockChain().NewBlock(addr, txs) - // Apply all transactions to the block - ethereum.BlockManager.ApplyTransactions(block, block.Transactions()) - - ethereum.BlockManager.AccumelateRewards(block, block) - - // Search the nonce - block.Nonce = pow.Search(block) - err := ethereum.BlockManager.ProcessBlock(block) - if err != nil { - log.Println(err) - } else { - log.Println("\n+++++++ MINED BLK +++++++\n", ethereum.BlockManager.BlockChain().CurrentBlock) + if UseGui { + gui := ethui.New(ethereum) + gui.Start() + //ethereum.Stop() + } else { + RegisterInterupts(ethereum) + ethereum.Start() + + if StartMining { + log.Printf("Miner started\n") + + // Fake block mining. It broadcasts a new block every 5 seconds + go func() { + pow := ðchain.EasyPow{} + data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) + keyRing := ethutil.NewValueFromBytes(data) + addr := keyRing.Get(1).Bytes() + + for { + txs := ethereum.TxPool.Flush() + // Create a new block which we're going to mine + block := ethereum.BlockManager.BlockChain().NewBlock(addr, txs) + // Apply all transactions to the block + ethereum.BlockManager.ApplyTransactions(block, block.Transactions()) + + ethereum.BlockManager.AccumelateRewards(block, block) + + // Search the nonce + block.Nonce = pow.Search(block) + err := ethereum.BlockManager.ProcessBlock(block) + if err != nil { + log.Println(err) + } else { + log.Println("\n+++++++ MINED BLK +++++++\n", ethereum.BlockManager.BlockChain().CurrentBlock) + } } - } - }() - } + }() + } - // Wait for shutdown - ethereum.WaitForShutdown() + // Wait for shutdown + ethereum.WaitForShutdown() + } } diff --git a/ui/gui.go b/ui/gui.go new file mode 100644 index 000000000..b2a8dad73 --- /dev/null +++ b/ui/gui.go @@ -0,0 +1,83 @@ +package ethui + +import ( + "bufio" + "encoding/hex" + "fmt" + "github.com/ethereum/eth-go" + "github.com/ethereum/eth-go/ethchain" + "github.com/ethereum/eth-go/ethutil" + "github.com/niemeyer/qml" + "strings" +) + +type Gui struct { + win *qml.Window + engine *qml.Engine + component *qml.Common + eth *eth.Ethereum +} + +func New(ethereum *eth.Ethereum) *Gui { + return &Gui{eth: ethereum} +} + +type Block struct { + Number int + Hash string +} + +func NewBlockFromBlock(block *ethchain.Block) *Block { + info := block.BlockInfo() + hash := hex.EncodeToString(block.Hash()) + + return &Block{Number: int(info.Number), Hash: hash} +} + +func (ui *Gui) Start() { + qml.RegisterTypes("GoExtensions", 1, 0, []qml.TypeSpec{{ + Init: func(p *Block, obj qml.Object) { p.Number = 0; p.Hash = "" }, + }}) + + ethutil.Config.Log.Infoln("[GUI] Starting GUI") + ui.engine = qml.NewEngine() + component, err := ui.engine.LoadFile("wallet.qml") + if err != nil { + panic(err) + } + + ui.win = component.CreateWindow(nil) + root := ui.win.Root() + + context := ui.engine.Context() + context.SetVar("tester", &Tester{root: root}) + + ui.eth.BlockManager.SecondaryBlockProcessor = ui + ui.eth.Start() + + ui.win.Show() + ui.win.Wait() +} + +func (ui *Gui) ProcessBlock(block *ethchain.Block) { + ui.win.Root().Call("addBlock", NewBlockFromBlock(block)) +} + +type Tester struct { + root qml.Object +} + +func (t *Tester) Compile(area qml.Object) { + fmt.Println(area) + ethutil.Config.Log.Infoln("[TESTER] Compiling") + + code := area.String("text") + + scanner := bufio.NewScanner(strings.NewReader(code)) + scanner.Split(bufio.ScanLines) + + var lines []string + for scanner.Scan() { + lines = append(lines, scanner.Text()) + } +} diff --git a/wallet.qml b/wallet.qml new file mode 100644 index 000000000..2bf4e4576 --- /dev/null +++ b/wallet.qml @@ -0,0 +1,81 @@ +import QtQuick 2.0 +import QtQuick.Controls 1.0; +import QtQuick.Layouts 1.0; +import GoExtensions 1.0 + +ApplicationWindow { + id: root + + width: 800 + height: 600 + minimumHeight: 300 + + title: "Ethereal" + + toolBar: ToolBar { + id: mainToolbar + + RowLayout { + width: parent.width + Button { + text: "Send" + onClicked: tester.compile(codeView) + } + + TextField { + width: 200 + placeholderText: "Amount" + } + + TextField { + width: 300 + placeholderText: "Receiver Address (or empty for contract)" + Layout.fillWidth: true + } + + } + } + + SplitView { + id: splitView + height: 200 + anchors.top: parent.top + anchors.right: parent.right + anchors.left: parent.left + + TextArea { + id: codeView + width: parent.width /2 + } + + TextArea { + readOnly: true + } + } + + property var blockModel: ListModel { + id: blockModel + } + + TableView { + width: parent.width + height: 100 + anchors.bottom: parent.bottom + anchors.top: splitView.bottom + TableViewColumn{ role: "number" ; title: "#" ; width: 100 } + TableViewColumn{ role: "hash" ; title: "Hash" ; width: 560 } + + model: blockModel + } + + + statusBar: StatusBar { + RowLayout { + Label { text: "0.0.1" } + } + } + + function addBlock(block) { + blockModel.append({number: block.number, hash: block.hash}) + } +} -- cgit v1.2.3 From aaac0c9998ee78d796c1dbab118f721f886ce426 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 21 Feb 2014 13:06:17 +0100 Subject: Initial block chain fetching of existing blocks --- ui/gui.go | 12 +++++++++++- wallet.qml | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/ui/gui.go b/ui/gui.go index b2a8dad73..aae1320fc 100644 --- a/ui/gui.go +++ b/ui/gui.go @@ -53,12 +53,22 @@ func (ui *Gui) Start() { context.SetVar("tester", &Tester{root: root}) ui.eth.BlockManager.SecondaryBlockProcessor = ui - ui.eth.Start() + + go ui.setInitialBlockChain() ui.win.Show() ui.win.Wait() } +func (ui *Gui) setInitialBlockChain() { + chain := ui.eth.BlockManager.BlockChain().GetChain(ui.eth.BlockManager.BlockChain().CurrentBlock.Hash(), 10) + for _, block := range chain { + ui.ProcessBlock(block) + } + + ui.eth.Start() +} + func (ui *Gui) ProcessBlock(block *ethchain.Block) { ui.win.Root().Call("addBlock", NewBlockFromBlock(block)) } diff --git a/wallet.qml b/wallet.qml index 2bf4e4576..cbce7ebcc 100644 --- a/wallet.qml +++ b/wallet.qml @@ -76,6 +76,6 @@ ApplicationWindow { } function addBlock(block) { - blockModel.append({number: block.number, hash: block.hash}) + blockModel.insert(0, {number: block.number, hash: block.hash}) } } -- cgit v1.2.3 From 95a48cea18eccd4ea2cb298027dbd01bd21f43e8 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 21 Feb 2014 13:23:35 +0100 Subject: Peer amount update --- network.png | Bin 0 -> 2900 bytes ui/gui.go | 9 +++++++++ wallet.qml | 19 +++++++++++++++++++ 3 files changed, 28 insertions(+) create mode 100644 network.png diff --git a/network.png b/network.png new file mode 100644 index 000000000..0a9ffe2ec Binary files /dev/null and b/network.png differ diff --git a/ui/gui.go b/ui/gui.go index aae1320fc..e223fe262 100644 --- a/ui/gui.go +++ b/ui/gui.go @@ -9,6 +9,7 @@ import ( "github.com/ethereum/eth-go/ethutil" "github.com/niemeyer/qml" "strings" + "time" ) type Gui struct { @@ -55,6 +56,7 @@ func (ui *Gui) Start() { ui.eth.BlockManager.SecondaryBlockProcessor = ui go ui.setInitialBlockChain() + go ui.updatePeers() ui.win.Show() ui.win.Wait() @@ -73,6 +75,13 @@ func (ui *Gui) ProcessBlock(block *ethchain.Block) { ui.win.Root().Call("addBlock", NewBlockFromBlock(block)) } +func (ui *Gui) updatePeers() { + for { + ui.win.Root().Call("setPeers", fmt.Sprintf("%d / %d", ui.eth.Peers().Len(), ui.eth.MaxPeers)) + time.Sleep(1 * time.Second) + } +} + type Tester struct { root qml.Object } diff --git a/wallet.qml b/wallet.qml index cbce7ebcc..b19e7f32b 100644 --- a/wallet.qml +++ b/wallet.qml @@ -71,11 +71,30 @@ ApplicationWindow { statusBar: StatusBar { RowLayout { + anchors.fill: parent Label { text: "0.0.1" } + Label { + anchors.right: peerImage.left + anchors.rightMargin: 5 + id: peerLabel + font.pixelSize: 8 + text: "0 / 0" + } + + Image { + id: peerImage + anchors.right: parent.right + width: 10; height: 10 + source: "network.png" + } } } function addBlock(block) { blockModel.insert(0, {number: block.number, hash: block.hash}) } + + function setPeers(text) { + peerLabel.text = text + } } -- cgit v1.2.3 From 3e8b27c9dc78ffeeefae987e67730fae17707df4 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 21 Feb 2014 17:29:59 +0100 Subject: WIP library, sample app --- test_app.qml | 35 +++++++++++++++++++++++++++++++++++ ui/gui.go | 28 +++++++++++++++++++++++++--- ui/library.go | 42 ++++++++++++++++++++++++++++++++++++++++++ wallet.qml | 59 ++++++++++++++++++++++++++++++++++++++--------------------- 4 files changed, 140 insertions(+), 24 deletions(-) create mode 100644 test_app.qml create mode 100644 ui/library.go diff --git a/test_app.qml b/test_app.qml new file mode 100644 index 000000000..c7593bf12 --- /dev/null +++ b/test_app.qml @@ -0,0 +1,35 @@ +import QtQuick 2.0 +import QtQuick.Controls 1.0; +import QtQuick.Layouts 1.0; +import GoExtensions 1.0 + +ApplicationWindow { + minimumWidth: 500 + maximumWidth: 500 + maximumHeight: 100 + minimumHeight: 100 + + title: "Ethereum Dice" + + TextField { + id: textField + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + placeholderText: "Amount" + } + Label { + id: txHash + anchors.bottom: textField.top + anchors.bottomMargin: 5 + anchors.horizontalCenter: parent.horizontalCenter + } + Button { + anchors.top: textField.bottom + anchors.horizontalCenter: parent.horizontalCenter + anchors.topMargin: 5 + text: "Place bet" + onClicked: { + txHash.text = eth.createTx("e6716f9544a56c530d868e4bfbacb172315bdead", parseInt(textField.text)) + } + } +} diff --git a/ui/gui.go b/ui/gui.go index e223fe262..8f063843c 100644 --- a/ui/gui.go +++ b/ui/gui.go @@ -17,10 +17,15 @@ type Gui struct { engine *qml.Engine component *qml.Common eth *eth.Ethereum + + // The Ethereum library + lib *EthLib } func New(ethereum *eth.Ethereum) *Gui { - return &Gui{eth: ethereum} + lib := &EthLib{blockManager: ethereum.BlockManager, blockChain: ethereum.BlockManager.BlockChain(), txPool: ethereum.TxPool} + + return &Gui{eth: ethereum, lib: lib} } type Block struct { @@ -48,10 +53,10 @@ func (ui *Gui) Start() { } ui.win = component.CreateWindow(nil) - root := ui.win.Root() context := ui.engine.Context() - context.SetVar("tester", &Tester{root: root}) + context.SetVar("eth", ui.lib) + context.SetVar("ui", &UiLib{engine: ui.engine}) ui.eth.BlockManager.SecondaryBlockProcessor = ui @@ -82,6 +87,23 @@ func (ui *Gui) updatePeers() { } } +type UiLib struct { + engine *qml.Engine +} + +func (ui *UiLib) Open(path string) { + component, err := ui.engine.LoadFile(path[7:]) + if err != nil { + ethutil.Config.Log.Debugln(err) + } + win := component.CreateWindow(nil) + + go func() { + win.Show() + win.Wait() + }() +} + type Tester struct { root qml.Object } diff --git a/ui/library.go b/ui/library.go new file mode 100644 index 000000000..36952e198 --- /dev/null +++ b/ui/library.go @@ -0,0 +1,42 @@ +package ethui + +import ( + "encoding/hex" + "fmt" + "github.com/ethereum/eth-go/ethchain" + "github.com/ethereum/eth-go/ethutil" + "math/big" +) + +type EthLib struct { + blockManager *ethchain.BlockManager + blockChain *ethchain.BlockChain + txPool *ethchain.TxPool +} + +func (lib *EthLib) CreateTx(receiver string, amount uint64) string { + hash, err := hex.DecodeString(receiver) + if err != nil { + return err.Error() + } + + tx := ethchain.NewTransaction(hash, big.NewInt(int64(amount)), []string{""}) + data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) + keyRing := ethutil.NewValueFromBytes(data) + tx.Sign(keyRing.Get(0).Bytes()) + + lib.txPool.QueueTransaction(tx) + + return ethutil.Hex(tx.Hash()) +} + +func (lib *EthLib) GetBlock(hexHash string) *Block { + hash, err := hex.DecodeString(hexHash) + if err != nil { + return nil + } + + block := lib.blockChain.GetBlock(hash) + fmt.Println(block) + return &Block{Number: int(block.BlockInfo().Number), Hash: ethutil.Hex(block.Hash())} +} diff --git a/wallet.qml b/wallet.qml index b19e7f32b..f9bd8ec76 100644 --- a/wallet.qml +++ b/wallet.qml @@ -1,6 +1,7 @@ import QtQuick 2.0 import QtQuick.Controls 1.0; import QtQuick.Layouts 1.0; +import QtQuick.Dialogs 1.0; import GoExtensions 1.0 ApplicationWindow { @@ -12,6 +13,7 @@ ApplicationWindow { title: "Ethereal" + toolBar: ToolBar { id: mainToolbar @@ -19,7 +21,7 @@ ApplicationWindow { width: parent.width Button { text: "Send" - onClicked: tester.compile(codeView) + onClicked: console.log("SEND") } TextField { @@ -66,35 +68,50 @@ ApplicationWindow { TableViewColumn{ role: "hash" ; title: "Hash" ; width: 560 } model: blockModel + + onDoubleClicked: { + console.log(eth.getBlock(blockModel.get(row).hash)) + } } + FileDialog { + id: openAppDialog + title: "Open QML Application" + onAccepted: { + ui.open(openAppDialog.fileUrl.toString()) + } + } statusBar: StatusBar { - RowLayout { - anchors.fill: parent - Label { text: "0.0.1" } - Label { - anchors.right: peerImage.left - anchors.rightMargin: 5 - id: peerLabel - font.pixelSize: 8 - text: "0 / 0" - } - - Image { - id: peerImage - anchors.right: parent.right - width: 10; height: 10 - source: "network.png" - } + RowLayout { + anchors.fill: parent + Button { + onClicked: openAppDialog.open() + text: "Import App" + } + + Label { text: "0.0.1" } + Label { + anchors.right: peerImage.left + anchors.rightMargin: 5 + id: peerLabel + font.pixelSize: 8 + text: "0 / 0" } + Image { + id: peerImage + anchors.right: parent.right + width: 10; height: 10 + source: "network.png" + } + } } function addBlock(block) { - blockModel.insert(0, {number: block.number, hash: block.hash}) + blockModel.insert(0, {number: block.number, hash: block.hash}) } function setPeers(text) { - peerLabel.text = text - } + peerLabel.text = text + } } -- cgit v1.2.3 From 2b967558cebcef9d3ef9719cbb28a5e596982a5d Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 22 Feb 2014 01:52:47 +0100 Subject: Working out UI --- config.go | 2 +- ui/gui.go | 21 +++++++++++++++++++-- wallet.qml | 46 +++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 63 insertions(+), 6 deletions(-) diff --git a/config.go b/config.go index c25c8f2a3..79d40d706 100644 --- a/config.go +++ b/config.go @@ -21,7 +21,7 @@ func Init() { flag.BoolVar(&StartConsole, "c", false, "debug and testing console") flag.BoolVar(&StartMining, "m", false, "start dagger mining") flag.BoolVar(&ShowGenesis, "g", false, "prints genesis header and exits") - flag.BoolVar(&UseGui, "gui", false, "use the gui") + flag.BoolVar(&UseGui, "gui", true, "use the gui") flag.BoolVar(&UseUPnP, "upnp", false, "enable UPnP support") flag.BoolVar(&UseSeed, "seed", true, "seed peers") flag.BoolVar(&GenAddr, "genaddr", false, "create a new priv/pub key") diff --git a/ui/gui.go b/ui/gui.go index 8f063843c..fad7e9591 100644 --- a/ui/gui.go +++ b/ui/gui.go @@ -56,10 +56,12 @@ func (ui *Gui) Start() { context := ui.engine.Context() context.SetVar("eth", ui.lib) - context.SetVar("ui", &UiLib{engine: ui.engine}) + context.SetVar("ui", &UiLib{engine: ui.engine, eth: ui.eth}) ui.eth.BlockManager.SecondaryBlockProcessor = ui + ethutil.Config.Log.AddLogSystem(ui) + go ui.setInitialBlockChain() go ui.updatePeers() @@ -73,13 +75,23 @@ func (ui *Gui) setInitialBlockChain() { ui.ProcessBlock(block) } - ui.eth.Start() } func (ui *Gui) ProcessBlock(block *ethchain.Block) { ui.win.Root().Call("addBlock", NewBlockFromBlock(block)) } +func (ui *Gui) Println(v ...interface{}) { + str := fmt.Sprintln(v...) + // remove last \n + ui.win.Root().Call("addLog", str[:len(str)-1]) +} + +func (ui *Gui) Printf(format string, v ...interface{}) { + str := strings.TrimRight(fmt.Sprintf(format, v...), "\n") + ui.win.Root().Call("addLog", str) +} + func (ui *Gui) updatePeers() { for { ui.win.Root().Call("setPeers", fmt.Sprintf("%d / %d", ui.eth.Peers().Len(), ui.eth.MaxPeers)) @@ -89,6 +101,7 @@ func (ui *Gui) updatePeers() { type UiLib struct { engine *qml.Engine + eth *eth.Ethereum } func (ui *UiLib) Open(path string) { @@ -104,6 +117,10 @@ func (ui *UiLib) Open(path string) { }() } +func (ui *UiLib) Connect() { + ui.eth.Start() +} + type Tester struct { root qml.Object } diff --git a/wallet.qml b/wallet.qml index f9bd8ec76..e6cb32b18 100644 --- a/wallet.qml +++ b/wallet.qml @@ -2,6 +2,7 @@ import QtQuick 2.0 import QtQuick.Controls 1.0; import QtQuick.Layouts 1.0; import QtQuick.Dialogs 1.0; +import QtQuick.Window 2.1; import GoExtensions 1.0 ApplicationWindow { @@ -60,20 +61,36 @@ ApplicationWindow { } TableView { + id: blockTable width: parent.width - height: 100 - anchors.bottom: parent.bottom anchors.top: splitView.bottom + anchors.bottom: logView.top TableViewColumn{ role: "number" ; title: "#" ; width: 100 } TableViewColumn{ role: "hash" ; title: "Hash" ; width: 560 } model: blockModel onDoubleClicked: { - console.log(eth.getBlock(blockModel.get(row).hash)) + popup.visible = true + popup.block = eth.getBlock(blockModel.get(row).hash) + popup.hashLabel.text = popup.block.hash } } + property var logModel: ListModel { + id: logModel + } + + TableView { + id: logView + width: parent.width + height: 150 + anchors.bottom: parent.bottom + TableViewColumn{ role: "description" ; title: "log" } + + model: logModel + } + FileDialog { id: openAppDialog title: "Open QML Application" @@ -86,6 +103,13 @@ ApplicationWindow { RowLayout { anchors.fill: parent Button { + id: connectButton + onClicked: ui.connect() + text: "Connect" + } + Button { + anchors.left: connectButton.right + anchors.leftMargin: 5 onClicked: openAppDialog.open() text: "Import App" } @@ -107,10 +131,26 @@ ApplicationWindow { } } + Window { + id: popup + visible: false + property var block + Label { + id: hashLabel + anchors.horizontalCenter: parent.horizontalCenter + anchors.verticalCenter: parent.verticalCenter + } + } + function addBlock(block) { blockModel.insert(0, {number: block.number, hash: block.hash}) } + function addLog(str) { + console.log(str) + logModel.insert(0, {description: str}) + } + function setPeers(text) { peerLabel.text = text } -- cgit v1.2.3 From aa33a4b2fb9dc07468498decceb6fdb56d38f54d Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 22 Feb 2014 23:19:38 +0100 Subject: Added some ui elements to make it easier to connect to nodes --- config.go | 2 ++ ethereum.go | 3 ++- test_app.qml | 4 +-- ui/gui.go | 81 +++++++++++++++++++++++++++++++++++++++++++---------------- ui/library.go | 10 +++++--- wallet.qml | 70 +++++++++++++++++++++++++++++++++++++++++++++++---- 6 files changed, 136 insertions(+), 34 deletions(-) diff --git a/config.go b/config.go index 79d40d706..bafc3e300 100644 --- a/config.go +++ b/config.go @@ -16,6 +16,7 @@ var UseSeed bool var ImportKey string var ExportKey bool var UseGui bool +var DataDir string func Init() { flag.BoolVar(&StartConsole, "c", false, "debug and testing console") @@ -27,6 +28,7 @@ func Init() { flag.BoolVar(&GenAddr, "genaddr", false, "create a new priv/pub key") flag.BoolVar(&ExportKey, "export", false, "export private key") flag.StringVar(&OutboundPort, "p", "30303", "listening port") + flag.StringVar(&DataDir, "dir", ".ethereum", "ethereum data directory") flag.StringVar(&ImportKey, "import", "", "imports the given private key (hex)") flag.IntVar(&MaxPeer, "x", 5, "maximum desired peers") diff --git a/ethereum.go b/ethereum.go index 5eda09a44..384b22748 100644 --- a/ethereum.go +++ b/ethereum.go @@ -89,11 +89,12 @@ func main() { runtime.GOMAXPROCS(runtime.NumCPU()) ethchain.InitFees() - ethutil.ReadConfig(".ethereum") + ethutil.ReadConfig(DataDir) ethutil.Config.Seed = UseSeed // Instantiated a eth stack ethereum, err := eth.New(eth.CapDefault, UseUPnP) + ethereum.Port = OutboundPort if err != nil { log.Println("eth start err:", err) return diff --git a/test_app.qml b/test_app.qml index c7593bf12..aace4e881 100644 --- a/test_app.qml +++ b/test_app.qml @@ -1,7 +1,7 @@ import QtQuick 2.0 import QtQuick.Controls 1.0; import QtQuick.Layouts 1.0; -import GoExtensions 1.0 +import Ethereum 1.0 ApplicationWindow { minimumWidth: 500 @@ -29,7 +29,7 @@ ApplicationWindow { anchors.topMargin: 5 text: "Place bet" onClicked: { - txHash.text = eth.createTx("e6716f9544a56c530d868e4bfbacb172315bdead", parseInt(textField.text)) + txHash.text = eth.createTx("e6716f9544a56c530d868e4bfbacb172315bdead", textField.text) } } } diff --git a/ui/gui.go b/ui/gui.go index fad7e9591..51fd6d9a8 100644 --- a/ui/gui.go +++ b/ui/gui.go @@ -12,41 +12,56 @@ import ( "time" ) +// Block interface exposed to QML +type Block struct { + Number int + Hash string +} + +// Creates a new QML Block from a chain block +func NewBlockFromBlock(block *ethchain.Block) *Block { + info := block.BlockInfo() + hash := hex.EncodeToString(block.Hash()) + + return &Block{Number: int(info.Number), Hash: hash} +} + type Gui struct { - win *qml.Window + // The main application window + win *qml.Window + // QML Engine engine *qml.Engine component *qml.Common - eth *eth.Ethereum + // The ethereum interface + eth *eth.Ethereum - // The Ethereum library + // The public Ethereum library lib *EthLib } +// Create GUI, but doesn't start it func New(ethereum *eth.Ethereum) *Gui { lib := &EthLib{blockManager: ethereum.BlockManager, blockChain: ethereum.BlockManager.BlockChain(), txPool: ethereum.TxPool} - return &Gui{eth: ethereum, lib: lib} -} + data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) + keyRing := ethutil.NewValueFromBytes(data) + addr := keyRing.Get(1).Bytes() -type Block struct { - Number int - Hash string -} - -func NewBlockFromBlock(block *ethchain.Block) *Block { - info := block.BlockInfo() - hash := hex.EncodeToString(block.Hash()) + ethereum.BlockManager.WatchAddr(addr) - return &Block{Number: int(info.Number), Hash: hash} + return &Gui{eth: ethereum, lib: lib} } func (ui *Gui) Start() { - qml.RegisterTypes("GoExtensions", 1, 0, []qml.TypeSpec{{ + // Register ethereum functions + qml.RegisterTypes("Ethereum", 1, 0, []qml.TypeSpec{{ Init: func(p *Block, obj qml.Object) { p.Number = 0; p.Hash = "" }, }}) ethutil.Config.Log.Infoln("[GUI] Starting GUI") + // Create a new QML engine ui.engine = qml.NewEngine() + // Load the main QML interface component, err := ui.engine.LoadFile("wallet.qml") if err != nil { panic(err) @@ -55,13 +70,18 @@ func (ui *Gui) Start() { ui.win = component.CreateWindow(nil) context := ui.engine.Context() + + // Expose the eth library and the ui library to QML context.SetVar("eth", ui.lib) context.SetVar("ui", &UiLib{engine: ui.engine, eth: ui.eth}) + // Register the ui as a block processor ui.eth.BlockManager.SecondaryBlockProcessor = ui + // Add the ui as a log system so we can log directly to the UGI ethutil.Config.Log.AddLogSystem(ui) + // Loads previous blocks go ui.setInitialBlockChain() go ui.updatePeers() @@ -70,6 +90,7 @@ func (ui *Gui) Start() { } func (ui *Gui) setInitialBlockChain() { + // Load previous 10 blocks chain := ui.eth.BlockManager.BlockChain().GetChain(ui.eth.BlockManager.BlockChain().CurrentBlock.Hash(), 10) for _, block := range chain { ui.ProcessBlock(block) @@ -81,17 +102,24 @@ func (ui *Gui) ProcessBlock(block *ethchain.Block) { ui.win.Root().Call("addBlock", NewBlockFromBlock(block)) } +// Logging functions that log directly to the GUI interface func (ui *Gui) Println(v ...interface{}) { - str := fmt.Sprintln(v...) - // remove last \n - ui.win.Root().Call("addLog", str[:len(str)-1]) + str := strings.TrimRight(fmt.Sprintln(v...), "\n") + lines := strings.Split(str, "\n") + for _, line := range lines { + ui.win.Root().Call("addLog", line) + } } func (ui *Gui) Printf(format string, v ...interface{}) { str := strings.TrimRight(fmt.Sprintf(format, v...), "\n") - ui.win.Root().Call("addLog", str) + lines := strings.Split(str, "\n") + for _, line := range lines { + ui.win.Root().Call("addLog", line) + } } +// Simple go routine function that updates the list of peers in the GUI func (ui *Gui) updatePeers() { for { ui.win.Root().Call("setPeers", fmt.Sprintf("%d / %d", ui.eth.Peers().Len(), ui.eth.MaxPeers)) @@ -99,11 +127,14 @@ func (ui *Gui) updatePeers() { } } +// UI Library that has some basic functionality exposed type UiLib struct { - engine *qml.Engine - eth *eth.Ethereum + engine *qml.Engine + eth *eth.Ethereum + connected bool } +// Opens a QML file (external application) func (ui *UiLib) Open(path string) { component, err := ui.engine.LoadFile(path[7:]) if err != nil { @@ -118,7 +149,13 @@ func (ui *UiLib) Open(path string) { } func (ui *UiLib) Connect() { - ui.eth.Start() + if !ui.connected { + ui.eth.Start() + } +} + +func (ui *UiLib) ConnectToPeer(addr string) { + ui.eth.ConnectToPeer(addr) } type Tester struct { diff --git a/ui/library.go b/ui/library.go index 36952e198..0dfb10ac7 100644 --- a/ui/library.go +++ b/ui/library.go @@ -5,7 +5,6 @@ import ( "fmt" "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethutil" - "math/big" ) type EthLib struct { @@ -14,15 +13,18 @@ type EthLib struct { txPool *ethchain.TxPool } -func (lib *EthLib) CreateTx(receiver string, amount uint64) string { +func (lib *EthLib) CreateTx(receiver, a string) string { hash, err := hex.DecodeString(receiver) if err != nil { return err.Error() } - - tx := ethchain.NewTransaction(hash, big.NewInt(int64(amount)), []string{""}) data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) keyRing := ethutil.NewValueFromBytes(data) + + amount := ethutil.Big(a) + tx := ethchain.NewTransaction(hash, amount, []string{""}) + tx.Nonce = lib.blockManager.GetAddrState(keyRing.Get(1).Bytes()).Nonce + tx.Sign(keyRing.Get(0).Bytes()) lib.txPool.QueueTransaction(tx) diff --git a/wallet.qml b/wallet.qml index e6cb32b18..b18614801 100644 --- a/wallet.qml +++ b/wallet.qml @@ -3,7 +3,7 @@ import QtQuick.Controls 1.0; import QtQuick.Layouts 1.0; import QtQuick.Dialogs 1.0; import QtQuick.Window 2.1; -import GoExtensions 1.0 +import Ethereum 1.0 ApplicationWindow { id: root @@ -22,15 +22,19 @@ ApplicationWindow { width: parent.width Button { text: "Send" - onClicked: console.log("SEND") + onClicked: { + console.log(eth.createTx(txReceiver.text, txAmount.text)) + } } TextField { + id: txAmount width: 200 placeholderText: "Amount" } TextField { + id: txReceiver width: 300 placeholderText: "Receiver Address (or empty for contract)" Layout.fillWidth: true @@ -47,15 +51,43 @@ ApplicationWindow { anchors.left: parent.left TextArea { - id: codeView - width: parent.width /2 + id: codeView + width: parent.width /2 } TextArea { - readOnly: true + readOnly: true } } + MenuBar { + Menu { + title: "File" + MenuItem { + text: "Import App" + shortcut: "Ctrl+o" + onTriggered: openAppDialog.open() + } + } + + Menu { + title: "Network" + MenuItem { + text: "Add Peer" + shortcut: "Ctrl+p" + onTriggered: { + addPeerWin.visible = true + } + } + + MenuItem { + text: "Start" + onTriggered: ui.connect() + } + } + } + + property var blockModel: ListModel { id: blockModel } @@ -142,6 +174,34 @@ ApplicationWindow { } } + Window { + id: addPeerWin + visible: false + minimumWidth: 230 + maximumWidth: 230 + maximumHeight: 50 + minimumHeight: 50 + + TextField { + id: addrField + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: 10 + placeholderText: "address:port" + } + Button { + anchors.left: addrField.right + anchors.verticalCenter: parent.verticalCenter + anchors.leftMargin: 5 + text: "Add" + onClicked: { + ui.connectToPeer(addrField.text) + addrPeerWin.visible = false + } + } + } + + function addBlock(block) { blockModel.insert(0, {number: block.number, hash: block.hash}) } -- cgit v1.2.3 From 0656f465b0c0690f237e42ac1e8f306dcda6c40b Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 23 Feb 2014 01:56:04 +0100 Subject: Added transactions window --- transactions.qml | 9 +++ ui/gui.go | 19 ++++++ wallet.qml | 177 ++++++++++++++++++++++++++++++++++++++++++------------- 3 files changed, 163 insertions(+), 42 deletions(-) create mode 100644 transactions.qml diff --git a/transactions.qml b/transactions.qml new file mode 100644 index 000000000..e9a035a85 --- /dev/null +++ b/transactions.qml @@ -0,0 +1,9 @@ +import QtQuick 2.0 +import QtQuick.Controls 1.0; +import QtQuick.Layouts 1.0; + +Rectangle { + id: transactionView + visible: false + Text { text: "TX VIEW" } +} diff --git a/ui/gui.go b/ui/gui.go index 51fd6d9a8..f0e281de1 100644 --- a/ui/gui.go +++ b/ui/gui.go @@ -18,6 +18,17 @@ type Block struct { Hash string } +type Tx struct { + Value, Hash, Address string +} + +func NewTxFromTransaction(tx *ethchain.Transaction) *Tx { + hash := hex.EncodeToString(tx.Hash()) + sender := hex.EncodeToString(tx.Recipient) + + return &Tx{Hash: hash[:4], Value: tx.Value.String(), Address: sender} +} + // Creates a new QML Block from a chain block func NewBlockFromBlock(block *ethchain.Block) *Block { info := block.BlockInfo() @@ -56,6 +67,8 @@ func (ui *Gui) Start() { // Register ethereum functions qml.RegisterTypes("Ethereum", 1, 0, []qml.TypeSpec{{ Init: func(p *Block, obj qml.Object) { p.Number = 0; p.Hash = "" }, + }, { + Init: func(p *Tx, obj qml.Object) { p.Value = ""; p.Hash = ""; p.Address = "" }, }}) ethutil.Config.Log.Infoln("[GUI] Starting GUI") @@ -66,6 +79,7 @@ func (ui *Gui) Start() { if err != nil { panic(err) } + ui.engine.LoadFile("transactions.qml") ui.win = component.CreateWindow(nil) @@ -77,6 +91,7 @@ func (ui *Gui) Start() { // Register the ui as a block processor ui.eth.BlockManager.SecondaryBlockProcessor = ui + ui.eth.TxPool.SecondaryProcessor = ui // Add the ui as a log system so we can log directly to the UGI ethutil.Config.Log.AddLogSystem(ui) @@ -102,6 +117,10 @@ func (ui *Gui) ProcessBlock(block *ethchain.Block) { ui.win.Root().Call("addBlock", NewBlockFromBlock(block)) } +func (ui *Gui) ProcessTransaction(tx *ethchain.Transaction) { + ui.win.Root().Call("addTx", NewTxFromTransaction(tx)) +} + // Logging functions that log directly to the GUI interface func (ui *Gui) Println(v ...interface{}) { str := strings.TrimRight(fmt.Sprintln(v...), "\n") diff --git a/wallet.qml b/wallet.qml index b18614801..6ee6ff110 100644 --- a/wallet.qml +++ b/wallet.qml @@ -3,18 +3,18 @@ import QtQuick.Controls 1.0; import QtQuick.Layouts 1.0; import QtQuick.Dialogs 1.0; import QtQuick.Window 2.1; +import QtQuick.Controls.Styles 1.1 import Ethereum 1.0 ApplicationWindow { id: root - width: 800 + width: 900 height: 600 minimumHeight: 300 title: "Ethereal" - toolBar: ToolBar { id: mainToolbar @@ -43,22 +43,6 @@ ApplicationWindow { } } - SplitView { - id: splitView - height: 200 - anchors.top: parent.top - anchors.right: parent.right - anchors.left: parent.left - - TextArea { - id: codeView - width: parent.width /2 - } - - TextArea { - readOnly: true - } - } MenuBar { Menu { @@ -85,42 +69,133 @@ ApplicationWindow { onTriggered: ui.connect() } } + + Menu { + title: "Help" + MenuItem { + text: "About" + onTriggered: { + aboutWin.visible = true + } + } + } + } property var blockModel: ListModel { id: blockModel } + function setView(view) { + mainView.visible = false + transactionView.visible = false + view.visible = true + } - TableView { - id: blockTable - width: parent.width - anchors.top: splitView.bottom - anchors.bottom: logView.top - TableViewColumn{ role: "number" ; title: "#" ; width: 100 } - TableViewColumn{ role: "hash" ; title: "Hash" ; width: 560 } + SplitView { + anchors.fill: parent + + + Rectangle { + id: menu + width: 200 + anchors.bottom: parent.bottom + anchors.top: parent.top + color: "#D9DDE7" + + GridLayout { + columns: 1 + Button { + text: "Main" + onClicked: { + setView(mainView) + } + } + Button { + text: "Transactions" + onClicked: { + setView(transactionView) + } + } + } + + } - model: blockModel + property var txModel: ListModel { + id: txModel + } - onDoubleClicked: { - popup.visible = true - popup.block = eth.getBlock(blockModel.get(row).hash) - popup.hashLabel.text = popup.block.hash + Rectangle { + id: transactionView + visible: false + anchors.right: parent.right + anchors.left: menu.right + anchors.bottom: parent.bottom + anchors.top: parent.top + TableView { + id: txTableView + anchors.fill: parent + TableViewColumn{ role: "hash" ; title: "#" ; width: 150 } + TableViewColumn{ role: "value" ; title: "Value" ; width: 100 } + TableViewColumn{ role: "address" ; title: "Address" ; } + + model: txModel + } } - } - property var logModel: ListModel { - id: logModel - } + Rectangle { + id: mainView + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.top: parent.top + SplitView { + id: splitView + height: 200 + anchors.top: parent.top + anchors.right: parent.right + anchors.left: parent.left + + TextArea { + id: codeView + width: parent.width /2 + } + + TextArea { + readOnly: true + } + } + + TableView { + id: blockTable + width: parent.width + anchors.top: splitView.bottom + anchors.bottom: logView.top + TableViewColumn{ role: "number" ; title: "#" ; width: 100 } + TableViewColumn{ role: "hash" ; title: "Hash" ; width: 560 } + + model: blockModel - TableView { - id: logView - width: parent.width - height: 150 - anchors.bottom: parent.bottom - TableViewColumn{ role: "description" ; title: "log" } + onDoubleClicked: { + popup.visible = true + popup.block = eth.getBlock(blockModel.get(row).hash) + popup.hashLabel.text = popup.block.hash + } + } - model: logModel + property var logModel: ListModel { + id: logModel + } + + TableView { + id: logView + width: parent.width + height: 150 + anchors.bottom: parent.bottom + TableViewColumn{ role: "description" ; title: "log" } + + model: logModel + } + } } FileDialog { @@ -146,7 +221,6 @@ ApplicationWindow { text: "Import App" } - Label { text: "0.0.1" } Label { anchors.right: peerImage.left anchors.rightMargin: 5 @@ -201,6 +275,25 @@ ApplicationWindow { } } + Window { + id: aboutWin + visible: false + title: "About" + minimumWidth: 300 + maximumWidth: 300 + maximumHeight: 200 + minimumHeight: 200 + + Text { + font.pointSize: 18 + text: "Eth Go" + } + + } + + function addTx(tx) { + txModel.insert(0, {hash: tx.hash, address: tx.address, value: tx.value}) + } function addBlock(block) { blockModel.insert(0, {number: block.number, hash: block.hash}) -- cgit v1.2.3 From fe9eb472887baec464cc50657affd85b13bcbeba Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 24 Feb 2014 13:51:16 +0100 Subject: Minor fixes that to reflect changes in library --- dev_console.go | 6 +++--- ethereum.go | 2 ++ ui/library.go | 28 +++++++++++++++++++++------- wallet.qml | 7 ++++--- 4 files changed, 30 insertions(+), 13 deletions(-) diff --git a/dev_console.go b/dev_console.go index 2e6b385df..696493cdd 100644 --- a/dev_console.go +++ b/dev_console.go @@ -197,16 +197,16 @@ func (i *Console) ParseInput(input string) bool { } case "contract": fmt.Println("Contract editor (Ctrl-D = done)") - code := i.Editor() + code := ethchain.Compile(i.Editor()) - contract := ethchain.NewTransaction([]byte{}, ethutil.Big(tokens[1]), code) + 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()) i.ethereum.TxPool.QueueTransaction(contract) - fmt.Printf("%x\n", contract.Hash()) + fmt.Printf("%x\n", contract.Hash()[12:]) case "exit", "quit", "q": return false case "help": diff --git a/ethereum.go b/ethereum.go index 384b22748..0b941dce3 100644 --- a/ethereum.go +++ b/ethereum.go @@ -5,6 +5,7 @@ import ( "github.com/ethereum/eth-go" "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethutil" + "github.com/ethereum/eth-go/ethwire" "github.com/ethereum/go-ethereum/ui" "github.com/niemeyer/qml" "github.com/obscuren/secp256k1-go" @@ -195,6 +196,7 @@ func main() { // Search the nonce block.Nonce = pow.Search(block) + ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val}) err := ethereum.BlockManager.ProcessBlock(block) if err != nil { log.Println(err) diff --git a/ui/library.go b/ui/library.go index 0dfb10ac7..c9273e8c5 100644 --- a/ui/library.go +++ b/ui/library.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethutil" + "strings" ) type EthLib struct { @@ -13,22 +14,34 @@ type EthLib struct { txPool *ethchain.TxPool } -func (lib *EthLib) CreateTx(receiver, a string) string { - hash, err := hex.DecodeString(receiver) - if err != nil { - return err.Error() +func (lib *EthLib) CreateTx(receiver, a, data string) string { + var hash []byte + if len(receiver) == 0 { + hash = ethchain.ContractAddr + } else { + var err error + hash, err = hex.DecodeString(receiver) + if err != nil { + return err.Error() + } } - data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) - keyRing := ethutil.NewValueFromBytes(data) + + k, _ := ethutil.Config.Db.Get([]byte("KeyRing")) + keyRing := ethutil.NewValueFromBytes(k) amount := ethutil.Big(a) - tx := ethchain.NewTransaction(hash, amount, []string{""}) + code := ethchain.Compile(strings.Split(data, "\n")) + tx := ethchain.NewTransaction(hash, amount, code) tx.Nonce = lib.blockManager.GetAddrState(keyRing.Get(1).Bytes()).Nonce tx.Sign(keyRing.Get(0).Bytes()) lib.txPool.QueueTransaction(tx) + if len(receiver) == 0 { + ethutil.Config.Log.Infof("Contract addr %x", tx.Hash()[12:]) + } + return ethutil.Hex(tx.Hash()) } @@ -40,5 +53,6 @@ func (lib *EthLib) GetBlock(hexHash string) *Block { block := lib.blockChain.GetBlock(hash) fmt.Println(block) + return &Block{Number: int(block.BlockInfo().Number), Hash: ethutil.Hex(block.Hash())} } diff --git a/wallet.qml b/wallet.qml index 6ee6ff110..e7145cef3 100644 --- a/wallet.qml +++ b/wallet.qml @@ -23,7 +23,7 @@ ApplicationWindow { Button { text: "Send" onClicked: { - console.log(eth.createTx(txReceiver.text, txAmount.text)) + console.log(eth.createTx(txReceiver.text, txAmount.text, codeView.text)) } } @@ -300,8 +300,9 @@ ApplicationWindow { } function addLog(str) { - console.log(str) - logModel.insert(0, {description: str}) + if(str.len != 0) { + logModel.append({description: str}) + } } function setPeers(text) { -- cgit v1.2.3 From e60ff6ca41832c8124acfab6b8408516d60ac140 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 25 Feb 2014 10:54:15 +0100 Subject: Moved ui lib --- ui/ui_lib.go | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 ui/ui_lib.go diff --git a/ui/ui_lib.go b/ui/ui_lib.go new file mode 100644 index 000000000..93712eba2 --- /dev/null +++ b/ui/ui_lib.go @@ -0,0 +1,38 @@ +package ethui + +import ( + "github.com/ethereum/eth-go" + "github.com/ethereum/eth-go/ethutil" + "github.com/niemeyer/qml" +) + +// UI Library that has some basic functionality exposed +type UiLib struct { + engine *qml.Engine + eth *eth.Ethereum + connected bool +} + +// Opens a QML file (external application) +func (ui *UiLib) Open(path string) { + component, err := ui.engine.LoadFile(path[7:]) + if err != nil { + ethutil.Config.Log.Debugln(err) + } + win := component.CreateWindow(nil) + + go func() { + win.Show() + win.Wait() + }() +} + +func (ui *UiLib) Connect() { + if !ui.connected { + ui.eth.Start() + } +} + +func (ui *UiLib) ConnectToPeer(addr string) { + ui.eth.ConnectToPeer(addr) +} -- cgit v1.2.3 From 78b6e7ad9531461f389c5de3cef10fc665607050 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 25 Feb 2014 10:54:37 +0100 Subject: Proper Nonce --- ui/gui.go | 143 ++++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 79 insertions(+), 64 deletions(-) diff --git a/ui/gui.go b/ui/gui.go index f0e281de1..72e5b976a 100644 --- a/ui/gui.go +++ b/ui/gui.go @@ -1,15 +1,15 @@ package ethui import ( - "bufio" + "bytes" "encoding/hex" "fmt" "github.com/ethereum/eth-go" "github.com/ethereum/eth-go/ethchain" + "github.com/ethereum/eth-go/ethdb" "github.com/ethereum/eth-go/ethutil" "github.com/niemeyer/qml" "strings" - "time" ) // Block interface exposed to QML @@ -26,7 +26,7 @@ func NewTxFromTransaction(tx *ethchain.Transaction) *Tx { hash := hex.EncodeToString(tx.Hash()) sender := hex.EncodeToString(tx.Recipient) - return &Tx{Hash: hash[:4], Value: tx.Value.String(), Address: sender} + return &Tx{Hash: hash, Value: tx.Value.String(), Address: sender} } // Creates a new QML Block from a chain block @@ -48,11 +48,19 @@ type Gui struct { // The public Ethereum library lib *EthLib + + txDb *ethdb.LDBDatabase + + addr []byte } // Create GUI, but doesn't start it func New(ethereum *eth.Ethereum) *Gui { lib := &EthLib{blockManager: ethereum.BlockManager, blockChain: ethereum.BlockManager.BlockChain(), txPool: ethereum.TxPool} + db, err := ethdb.NewLDBDatabase("tx_database") + if err != nil { + panic(err) + } data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) keyRing := ethutil.NewValueFromBytes(data) @@ -60,10 +68,12 @@ func New(ethereum *eth.Ethereum) *Gui { ethereum.BlockManager.WatchAddr(addr) - return &Gui{eth: ethereum, lib: lib} + return &Gui{eth: ethereum, lib: lib, txDb: db, addr: addr} } func (ui *Gui) Start() { + defer ui.txDb.Close() + // Register ethereum functions qml.RegisterTypes("Ethereum", 1, 0, []qml.TypeSpec{{ Init: func(p *Block, obj qml.Object) { p.Number = 0; p.Hash = "" }, @@ -91,17 +101,20 @@ func (ui *Gui) Start() { // Register the ui as a block processor ui.eth.BlockManager.SecondaryBlockProcessor = ui - ui.eth.TxPool.SecondaryProcessor = ui + //ui.eth.TxPool.SecondaryProcessor = ui // Add the ui as a log system so we can log directly to the UGI ethutil.Config.Log.AddLogSystem(ui) // Loads previous blocks go ui.setInitialBlockChain() - go ui.updatePeers() + go ui.readPreviousTransactions() + go ui.update() ui.win.Show() ui.win.Wait() + + ui.eth.Stop() } func (ui *Gui) setInitialBlockChain() { @@ -113,12 +126,72 @@ func (ui *Gui) setInitialBlockChain() { } +func (ui *Gui) readPreviousTransactions() { + it := ui.txDb.Db().NewIterator(nil) + for it.Next() { + tx := ethchain.NewTransactionFromBytes(it.Value()) + + ui.win.Root().Call("addTx", NewTxFromTransaction(tx)) + } + it.Release() +} + 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) + ui.eth.TxPool.Subscribe(txChan) + + account := ui.eth.BlockManager.GetAddrState(ui.addr).Account + ui.win.Root().Call("setWalletValue", fmt.Sprintf("%v", account.Amount)) + for { + select { + case txMsg := <-txChan: + tx := txMsg.Tx + ui.txDb.Put(tx.Hash(), tx.RlpEncode()) + + ui.win.Root().Call("addTx", NewTxFromTransaction(tx)) + // Yeah, yeah, stupid code. Refactor next week + if txMsg.Type == ethchain.TxPre { + if bytes.Compare(tx.Sender(), ui.addr) == 0 { + ui.win.Root().Call("setWalletValue", fmt.Sprintf("%v (- %v)", account.Amount, tx.Value)) + ui.eth.BlockManager.GetAddrState(ui.addr).Nonce += 1 + fmt.Println("Nonce", ui.eth.BlockManager.GetAddrState(ui.addr).Nonce) + } else if bytes.Compare(tx.Recipient, ui.addr) == 0 { + ui.win.Root().Call("setWalletValue", fmt.Sprintf("%v (+ %v)", account.Amount, tx.Value)) + } + } else { + if bytes.Compare(tx.Sender(), ui.addr) == 0 { + amount := account.Amount.Sub(account.Amount, tx.Value) + ui.win.Root().Call("setWalletValue", fmt.Sprintf("%v", amount)) + } 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", amount)) + } + } + } + + /* + accountAmount := ui.eth.BlockManager.GetAddrState(ui.addr).Account.Amount + ui.win.Root().Call("setWalletValue", fmt.Sprintf("%v", accountAmount)) + + ui.win.Root().Call("setPeers", fmt.Sprintf("%d / %d", ui.eth.Peers().Len(), ui.eth.MaxPeers)) + + time.Sleep(1 * time.Second) + */ + + } } // Logging functions that log directly to the GUI interface @@ -137,61 +210,3 @@ func (ui *Gui) Printf(format string, v ...interface{}) { ui.win.Root().Call("addLog", line) } } - -// Simple go routine function that updates the list of peers in the GUI -func (ui *Gui) updatePeers() { - for { - ui.win.Root().Call("setPeers", fmt.Sprintf("%d / %d", ui.eth.Peers().Len(), ui.eth.MaxPeers)) - time.Sleep(1 * time.Second) - } -} - -// UI Library that has some basic functionality exposed -type UiLib struct { - engine *qml.Engine - eth *eth.Ethereum - connected bool -} - -// Opens a QML file (external application) -func (ui *UiLib) Open(path string) { - component, err := ui.engine.LoadFile(path[7:]) - if err != nil { - ethutil.Config.Log.Debugln(err) - } - win := component.CreateWindow(nil) - - go func() { - win.Show() - win.Wait() - }() -} - -func (ui *UiLib) Connect() { - if !ui.connected { - ui.eth.Start() - } -} - -func (ui *UiLib) ConnectToPeer(addr string) { - ui.eth.ConnectToPeer(addr) -} - -type Tester struct { - root qml.Object -} - -func (t *Tester) Compile(area qml.Object) { - fmt.Println(area) - ethutil.Config.Log.Infoln("[TESTER] Compiling") - - code := area.String("text") - - scanner := bufio.NewScanner(strings.NewReader(code)) - scanner.Split(bufio.ScanLines) - - var lines []string - for scanner.Scan() { - lines = append(lines, scanner.Text()) - } -} -- cgit v1.2.3 From 6451a7187a5eeff6ac819ded11b6e7f0a5aa1b1b Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 25 Feb 2014 10:55:44 +0100 Subject: Minor UI change --- ui/library.go | 2 ++ wallet.qml | 10 +++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/ui/library.go b/ui/library.go index c9273e8c5..3bbb01314 100644 --- a/ui/library.go +++ b/ui/library.go @@ -40,6 +40,8 @@ func (lib *EthLib) CreateTx(receiver, a, data string) string { if len(receiver) == 0 { ethutil.Config.Log.Infof("Contract addr %x", tx.Hash()[12:]) + } else { + ethutil.Config.Log.Infof("Tx hash %x", tx.Hash()) } return ethutil.Hex(tx.Hash()) diff --git a/wallet.qml b/wallet.qml index e7145cef3..3e921b78d 100644 --- a/wallet.qml +++ b/wallet.qml @@ -221,6 +221,10 @@ ApplicationWindow { text: "Import App" } + Label { + id: walletValueLabel + } + Label { anchors.right: peerImage.left anchors.rightMargin: 5 @@ -270,7 +274,7 @@ ApplicationWindow { text: "Add" onClicked: { ui.connectToPeer(addrField.text) - addrPeerWin.visible = false + addPeerWin.visible = false } } } @@ -291,6 +295,10 @@ ApplicationWindow { } + function setWalletValue(value) { + walletValueLabel.text = value + } + function addTx(tx) { txModel.insert(0, {hash: tx.hash, address: tx.address, value: tx.value}) } -- cgit v1.2.3 From dba1ba38220c92f96aaeeb2d4cc99c1991220dc4 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 25 Feb 2014 11:24:04 +0100 Subject: Currency to string --- ui/gui.go | 14 +++++++------- wallet.qml | 3 +++ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/ui/gui.go b/ui/gui.go index 72e5b976a..6e30b5891 100644 --- a/ui/gui.go +++ b/ui/gui.go @@ -26,7 +26,7 @@ func NewTxFromTransaction(tx *ethchain.Transaction) *Tx { hash := hex.EncodeToString(tx.Hash()) sender := hex.EncodeToString(tx.Recipient) - return &Tx{Hash: hash, Value: tx.Value.String(), Address: sender} + return &Tx{Hash: hash, Value: ethutil.CurrencyToString(tx.Value), Address: sender} } // Creates a new QML Block from a chain block @@ -154,7 +154,7 @@ func (ui *Gui) update() { ui.eth.TxPool.Subscribe(txChan) account := ui.eth.BlockManager.GetAddrState(ui.addr).Account - ui.win.Root().Call("setWalletValue", fmt.Sprintf("%v", account.Amount)) + ui.win.Root().Call("setWalletValue", fmt.Sprintf("%v", ethutil.CurrencyToString(account.Amount))) for { select { case txMsg := <-txChan: @@ -162,22 +162,22 @@ func (ui *Gui) update() { ui.txDb.Put(tx.Hash(), tx.RlpEncode()) ui.win.Root().Call("addTx", NewTxFromTransaction(tx)) - // Yeah, yeah, stupid code. Refactor next week + // 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)", account.Amount, tx.Value)) + ui.win.Root().Call("setWalletValue", fmt.Sprintf("%v (- %v)", ethutil.CurrencyToString(account.Amount), ethutil.CurrencyToString(tx.Value))) ui.eth.BlockManager.GetAddrState(ui.addr).Nonce += 1 fmt.Println("Nonce", ui.eth.BlockManager.GetAddrState(ui.addr).Nonce) } else if bytes.Compare(tx.Recipient, ui.addr) == 0 { - ui.win.Root().Call("setWalletValue", fmt.Sprintf("%v (+ %v)", account.Amount, tx.Value)) + ui.win.Root().Call("setWalletValue", fmt.Sprintf("%v (+ %v)", ethutil.CurrencyToString(account.Amount), ethutil.CurrencyToString(tx.Value))) } } else { if bytes.Compare(tx.Sender(), ui.addr) == 0 { amount := account.Amount.Sub(account.Amount, tx.Value) - ui.win.Root().Call("setWalletValue", fmt.Sprintf("%v", amount)) + ui.win.Root().Call("setWalletValue", fmt.Sprintf("%v", ethutil.CurrencyToString(amount))) } 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", amount)) + ui.win.Root().Call("setWalletValue", fmt.Sprintf("%v", ethutil.CurrencyToString(amount))) } } } diff --git a/wallet.qml b/wallet.qml index 3e921b78d..04c1ffaed 100644 --- a/wallet.qml +++ b/wallet.qml @@ -215,6 +215,7 @@ ApplicationWindow { text: "Connect" } Button { + id: importAppButton anchors.left: connectButton.right anchors.leftMargin: 5 onClicked: openAppDialog.open() @@ -222,6 +223,8 @@ ApplicationWindow { } Label { + anchors.left: importAppButton.right + anchors.leftMargin: 5 id: walletValueLabel } -- cgit v1.2.3 From 8d1d72abeeee68ddcdffe02a28587a9bec1647e9 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 28 Feb 2014 12:16:46 +0100 Subject: Improved overall UI design and added a bunch of icons --- net.png | Bin 0 -> 4669 bytes net.pxm | Bin 0 -> 95418 bytes new.png | Bin 0 -> 4776 bytes tx.png | Bin 0 -> 4070 bytes tx.pxm | Bin 0 -> 93227 bytes ui/gui.go | 51 +++++++++++--------- wallet.qml | 157 +++++++++++++++++++++++++++++++++++++------------------------ 7 files changed, 124 insertions(+), 84 deletions(-) create mode 100644 net.png create mode 100644 net.pxm create mode 100644 new.png create mode 100644 tx.png create mode 100644 tx.pxm 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/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 { -- cgit v1.2.3 From 5e7f8cca4f83566fdfbd1eb76c8b565094958e6c Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 28 Feb 2014 12:17:02 +0100 Subject: Exit after importing a key --- ethereum.go | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) 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) } -- cgit v1.2.3 From 075acec9e709d3cda8a791cb0829720f5a1ae142 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 28 Feb 2014 12:17:26 +0100 Subject: Changed to new get keys method on database interface --- dev_console.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) 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) -- cgit v1.2.3 From 3a35d45ea84e055a4574a7a1d1b4b5485bea1331 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 28 Feb 2014 12:17:43 +0100 Subject: Updated readme --- README.md | 41 +++++++++-------------------------------- 1 file changed, 9 insertions(+), 32 deletions(-) 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 -- cgit v1.2.3 From 560a7073f457a32c9d053f1a4b20f76d949f519d Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 28 Feb 2014 12:18:19 +0100 Subject: Fixed connection button spamming --- ui/ui_lib.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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) } } -- cgit v1.2.3