Merge branch 'release/0.3.0'

pull/21/head 0.3.0
obscuren 11 years ago
commit 0adfa489de
  1. 2
      LICENSE
  2. 41
      README.md
  3. 8
      config.go
  4. 51
      dev_console.go
  5. 147
      ethereum.go
  6. BIN
      net.png
  7. BIN
      net.pxm
  8. BIN
      network.png
  9. BIN
      new.png
  10. 35
      test_app.qml
  11. 9
      transactions.qml
  12. BIN
      tx.png
  13. BIN
      tx.pxm
  14. 217
      ui/gui.go
  15. 60
      ui/library.go
  16. 40
      ui/ui_lib.go
  17. 357
      wallet.qml

@ -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

@ -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/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)
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

@ -13,15 +13,23 @@ var AddPeer string
var MaxPeer int
var GenAddr bool
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")
flag.BoolVar(&StartMining, "m", false, "start dagger mining")
flag.BoolVar(&ShowGenesis, "g", false, "prints genesis header and exits")
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")
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")
flag.Parse()

@ -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 {
@ -136,7 +163,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":
@ -151,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)
@ -168,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 := ethchain.Compile(i.Editor())
contract := ethchain.NewTransaction(ethchain.ContractAddr, ethutil.Big(tokens[1]), code)
key := ethutil.Config.Db.GetKeys()[0]
contract.Sign(key.PrivateKey)
i.ethereum.TxPool.QueueTransaction(contract)
fmt.Printf("%x\n", contract.Hash()[12:])
case "exit", "quit", "q":
return false
case "help":

@ -5,6 +5,9 @@ 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"
"log"
"os"
@ -33,13 +36,12 @@ 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 := &ethutil.Key{PrivateKey: prv, PublicKey: pub}
ethutil.Config.Db.Put([]byte("KeyRing"), pair.RlpEncode())
fmt.Printf(`
Generating new address and keypair.
Please keep your keys somewhere save.
Currently Ethereum(G) does not support
exporting keys.
++++++++++++++++ KeyRing +++++++++++++++++++
addr: %x
@ -47,19 +49,45 @@ 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())
}
}
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)
pair := &ethutil.Key{PrivateKey: key, PublicKey: pub}
ethutil.Config.Db.Put([]byte("KeyRing"), pair.RlpEncode())
fmt.Printf(`
Importing private key
++++++++++++++++ KeyRing +++++++++++++++++++
addr: %x
prvk: %x
pubk: %x
++++++++++++++++++++++++++++++++++++++++++++
`, pair.Address(), key, pub)
}
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.ReadConfig(DataDir)
ethutil.Config.Seed = UseSeed
// Instantiated a eth stack
@ -68,6 +96,7 @@ func main() {
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)")
@ -87,7 +116,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)
os.Exit(0)
}
} else {
CreateKeyPair(false)
}
}
if ExportKey {
key := ethutil.Config.Db.GetKeys()[0]
fmt.Printf("%x\n", key.PrivateKey)
os.Exit(0)
}
if ShowGenesis {
@ -111,41 +164,47 @@ 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 := &ethchain.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 := &ethchain.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)
ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val})
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()
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

@ -0,0 +1,35 @@
import QtQuick 2.0
import QtQuick.Controls 1.0;
import QtQuick.Layouts 1.0;
import Ethereum 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", textField.text)
}
}
}

@ -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" }
}

BIN
tx.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

BIN
tx.pxm

Binary file not shown.

@ -0,0 +1,217 @@
package ethui
import (
"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"
"math/big"
"strings"
)
// Block interface exposed to QML
type Block struct {
Number int
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, Value: ethutil.CurrencyToString(tx.Value), Address: sender}
}
// 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 {
// The main application window
win *qml.Window
// QML Engine
engine *qml.Engine
component *qml.Common
// The ethereum interface
eth *eth.Ethereum
// 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)
}
key := ethutil.Config.Db.GetKeys()[0]
addr := key.Address()
ethereum.BlockManager.WatchAddr(addr)
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 = "" },
}, {
Init: func(p *Tx, obj qml.Object) { p.Value = ""; p.Hash = ""; p.Address = "" },
}})
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)
}
ui.engine.LoadFile("transactions.qml")
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
//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.readPreviousTransactions()
go ui.update()
ui.win.Show()
ui.win.Wait()
ui.eth.Stop()
}
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)
}
}
func (ui *Gui) readPreviousTransactions() {
it := ui.txDb.Db().NewIterator(nil, 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))
}
// Simple go routine function that updates the list of peers in the GUI
func (ui *Gui) update() {
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
if txMsg.Type == ethchain.TxPre {
if bytes.Compare(tx.Sender(), ui.addr) == 0 {
ui.win.Root().Call("addTx", NewTxFromTransaction(tx))
ui.txDb.Put(tx.Hash(), tx.RlpEncode())
ui.eth.BlockManager.GetAddrState(ui.addr).Nonce += 1
unconfirmedFunds.Sub(unconfirmedFunds, tx.Value)
} else if bytes.Compare(tx.Recipient, ui.addr) == 0 {
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.Sub(account.Amount, tx.Value)
} else if bytes.Compare(tx.Recipient, ui.addr) == 0 {
amount.Add(account.Amount, tx.Value)
}
ui.win.Root().Call("setWalletValue", fmt.Sprintf("%v", ethutil.CurrencyToString(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
func (ui *Gui) Println(v ...interface{}) {
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")
lines := strings.Split(str, "\n")
for _, line := range lines {
ui.win.Root().Call("addLog", line)
}
}

@ -0,0 +1,60 @@
package ethui
import (
"encoding/hex"
"fmt"
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethutil"
"strings"
)
type EthLib struct {
blockManager *ethchain.BlockManager
blockChain *ethchain.BlockChain
txPool *ethchain.TxPool
}
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()
}
}
k, _ := ethutil.Config.Db.Get([]byte("KeyRing"))
keyRing := ethutil.NewValueFromBytes(k)
amount := ethutil.Big(a)
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:])
} else {
ethutil.Config.Log.Infof("Tx hash %x", tx.Hash())
}
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())}
}

@ -0,0 +1,40 @@
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(button qml.Object) {
if !ui.connected {
ui.eth.Start()
ui.connected = true
button.Set("enabled", false)
}
}
func (ui *UiLib) ConnectToPeer(addr string) {
ui.eth.ConnectToPeer(addr)
}

@ -0,0 +1,357 @@
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 QtQuick.Controls.Styles 1.1
import Ethereum 1.0
ApplicationWindow {
id: root
width: 900
height: 600
minimumHeight: 300
title: "Ethereal"
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()
}
}
Menu {
title: "Help"
MenuItem {
text: "About"
onTriggered: {
aboutWin.visible = true
}
}
}
}
property var blockModel: ListModel {
id: blockModel
}
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
Layout.minimumWidth: 80
Layout.maximumWidth: 80
anchors.bottom: parent.bottom
anchors.top: parent.top
//color: "#D9DDE7"
color: "#252525"
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)
}
}
}
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)
}
}
}
}
}
property var txModel: ListModel {
id: txModel
}
Rectangle {
id: historyView
property var title: "Transactions"
anchors.right: parent.right
anchors.left: menu.right
anchors.bottom: parent.bottom
anchors.top: parent.top
TableView {
id: txTableView
anchors.fill: parent
TableViewColumn{ role: "value" ; title: "Value" ; width: 100 }
TableViewColumn{ role: "address" ; title: "Address" ; width: 430 }
model: txModel
}
}
Rectangle {
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
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
}
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: parent.top
anchors.bottom: logView.top
TableViewColumn{ role: "number" ; title: "#" ; width: 100 }
TableViewColumn{ role: "hash" ; title: "Hash" ; width: 560 }
model: blockModel
onDoubleClicked: {
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"
onAccepted: {
ui.open(openAppDialog.fileUrl.toString())
}
}
statusBar: StatusBar {
RowLayout {
anchors.fill: parent
Button {
property var enabled: true
id: connectButton
onClicked: {
if(this.enabled) {
ui.connect(this)
}
}
text: "Connect"
}
Button {
id: importAppButton
anchors.left: connectButton.right
anchors.leftMargin: 5
onClicked: openAppDialog.open()
text: "Import App"
}
Label {
anchors.left: importAppButton.right
anchors.leftMargin: 5
id: walletValueLabel
}
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"
}
}
}
Window {
id: popup
visible: false
property var block
Label {
id: hashLabel
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
}
}
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)
addPeerWin.visible = false
}
}
}
Window {
id: aboutWin
visible: false
title: "About"
minimumWidth: 300
maximumWidth: 300
maximumHeight: 200
minimumHeight: 200
Text {
font.pointSize: 18
text: "Eth Go"
}
}
function setWalletValue(value) {
walletValueLabel.text = value
}
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})
}
function addLog(str) {
if(str.len != 0) {
logModel.append({description: str})
}
}
function setPeers(text) {
peerLabel.text = text
}
}
Loading…
Cancel
Save