forked from cerc-io/plugeth
		
	Added some ui elements to make it easier to connect to nodes
This commit is contained in:
		
							parent
							
								
									2b967558ce
								
							
						
					
					
						commit
						aa33a4b2fb
					
				| @ -16,6 +16,7 @@ var UseSeed bool | |||||||
| var ImportKey string | var ImportKey string | ||||||
| var ExportKey bool | var ExportKey bool | ||||||
| var UseGui bool | var UseGui bool | ||||||
|  | var DataDir string | ||||||
| 
 | 
 | ||||||
| func Init() { | func Init() { | ||||||
| 	flag.BoolVar(&StartConsole, "c", false, "debug and testing console") | 	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(&GenAddr, "genaddr", false, "create a new priv/pub key") | ||||||
| 	flag.BoolVar(&ExportKey, "export", false, "export private key") | 	flag.BoolVar(&ExportKey, "export", false, "export private key") | ||||||
| 	flag.StringVar(&OutboundPort, "p", "30303", "listening port") | 	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.StringVar(&ImportKey, "import", "", "imports the given private key (hex)") | ||||||
| 	flag.IntVar(&MaxPeer, "x", 5, "maximum desired peers") | 	flag.IntVar(&MaxPeer, "x", 5, "maximum desired peers") | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -89,11 +89,12 @@ func main() { | |||||||
| 	runtime.GOMAXPROCS(runtime.NumCPU()) | 	runtime.GOMAXPROCS(runtime.NumCPU()) | ||||||
| 
 | 
 | ||||||
| 	ethchain.InitFees() | 	ethchain.InitFees() | ||||||
| 	ethutil.ReadConfig(".ethereum") | 	ethutil.ReadConfig(DataDir) | ||||||
| 	ethutil.Config.Seed = UseSeed | 	ethutil.Config.Seed = UseSeed | ||||||
| 
 | 
 | ||||||
| 	// Instantiated a eth stack
 | 	// Instantiated a eth stack
 | ||||||
| 	ethereum, err := eth.New(eth.CapDefault, UseUPnP) | 	ethereum, err := eth.New(eth.CapDefault, UseUPnP) | ||||||
|  | 	ethereum.Port = OutboundPort | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		log.Println("eth start err:", err) | 		log.Println("eth start err:", err) | ||||||
| 		return | 		return | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| import QtQuick 2.0 | import QtQuick 2.0 | ||||||
| import QtQuick.Controls 1.0; | import QtQuick.Controls 1.0; | ||||||
| import QtQuick.Layouts 1.0; | import QtQuick.Layouts 1.0; | ||||||
| import GoExtensions 1.0 | import Ethereum 1.0 | ||||||
| 
 | 
 | ||||||
| ApplicationWindow { | ApplicationWindow { | ||||||
| 	minimumWidth: 500 | 	minimumWidth: 500 | ||||||
| @ -29,7 +29,7 @@ ApplicationWindow { | |||||||
| 		anchors.topMargin: 5 | 		anchors.topMargin: 5 | ||||||
| 		text: "Place bet" | 		text: "Place bet" | ||||||
| 		onClicked: { | 		onClicked: { | ||||||
| 			txHash.text = eth.createTx("e6716f9544a56c530d868e4bfbacb172315bdead", parseInt(textField.text)) | 			txHash.text = eth.createTx("e6716f9544a56c530d868e4bfbacb172315bdead", textField.text) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										85
									
								
								ui/gui.go
									
									
									
									
									
								
							
							
						
						
									
										85
									
								
								ui/gui.go
									
									
									
									
									
								
							| @ -12,27 +12,13 @@ import ( | |||||||
| 	"time" | 	"time" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type Gui struct { | // Block interface exposed to QML
 | ||||||
| 	win       *qml.Window |  | ||||||
| 	engine    *qml.Engine |  | ||||||
| 	component *qml.Common |  | ||||||
| 	eth       *eth.Ethereum |  | ||||||
| 
 |  | ||||||
| 	// The Ethereum library
 |  | ||||||
| 	lib *EthLib |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func New(ethereum *eth.Ethereum) *Gui { |  | ||||||
| 	lib := &EthLib{blockManager: ethereum.BlockManager, blockChain: ethereum.BlockManager.BlockChain(), txPool: ethereum.TxPool} |  | ||||||
| 
 |  | ||||||
| 	return &Gui{eth: ethereum, lib: lib} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| type Block struct { | type Block struct { | ||||||
| 	Number int | 	Number int | ||||||
| 	Hash   string | 	Hash   string | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // Creates a new QML Block from a chain block
 | ||||||
| func NewBlockFromBlock(block *ethchain.Block) *Block { | func NewBlockFromBlock(block *ethchain.Block) *Block { | ||||||
| 	info := block.BlockInfo() | 	info := block.BlockInfo() | ||||||
| 	hash := hex.EncodeToString(block.Hash()) | 	hash := hex.EncodeToString(block.Hash()) | ||||||
| @ -40,13 +26,42 @@ func NewBlockFromBlock(block *ethchain.Block) *Block { | |||||||
| 	return &Block{Number: int(info.Number), Hash: 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 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 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} | ||||||
|  | 
 | ||||||
|  | 	data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) | ||||||
|  | 	keyRing := ethutil.NewValueFromBytes(data) | ||||||
|  | 	addr := keyRing.Get(1).Bytes() | ||||||
|  | 
 | ||||||
|  | 	ethereum.BlockManager.WatchAddr(addr) | ||||||
|  | 
 | ||||||
|  | 	return &Gui{eth: ethereum, lib: lib} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (ui *Gui) Start() { | 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 = "" }, | 		Init: func(p *Block, obj qml.Object) { p.Number = 0; p.Hash = "" }, | ||||||
| 	}}) | 	}}) | ||||||
| 
 | 
 | ||||||
| 	ethutil.Config.Log.Infoln("[GUI] Starting GUI") | 	ethutil.Config.Log.Infoln("[GUI] Starting GUI") | ||||||
|  | 	// Create a new QML engine
 | ||||||
| 	ui.engine = qml.NewEngine() | 	ui.engine = qml.NewEngine() | ||||||
|  | 	// Load the main QML interface
 | ||||||
| 	component, err := ui.engine.LoadFile("wallet.qml") | 	component, err := ui.engine.LoadFile("wallet.qml") | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		panic(err) | 		panic(err) | ||||||
| @ -55,13 +70,18 @@ func (ui *Gui) Start() { | |||||||
| 	ui.win = component.CreateWindow(nil) | 	ui.win = component.CreateWindow(nil) | ||||||
| 
 | 
 | ||||||
| 	context := ui.engine.Context() | 	context := ui.engine.Context() | ||||||
|  | 
 | ||||||
|  | 	// Expose the eth library and the ui library to QML
 | ||||||
| 	context.SetVar("eth", ui.lib) | 	context.SetVar("eth", ui.lib) | ||||||
| 	context.SetVar("ui", &UiLib{engine: ui.engine, eth: ui.eth}) | 	context.SetVar("ui", &UiLib{engine: ui.engine, eth: ui.eth}) | ||||||
| 
 | 
 | ||||||
|  | 	// Register the ui as a block processor
 | ||||||
| 	ui.eth.BlockManager.SecondaryBlockProcessor = ui | 	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) | 	ethutil.Config.Log.AddLogSystem(ui) | ||||||
| 
 | 
 | ||||||
|  | 	// Loads previous blocks
 | ||||||
| 	go ui.setInitialBlockChain() | 	go ui.setInitialBlockChain() | ||||||
| 	go ui.updatePeers() | 	go ui.updatePeers() | ||||||
| 
 | 
 | ||||||
| @ -70,6 +90,7 @@ func (ui *Gui) Start() { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (ui *Gui) setInitialBlockChain() { | func (ui *Gui) setInitialBlockChain() { | ||||||
|  | 	// Load previous 10 blocks
 | ||||||
| 	chain := ui.eth.BlockManager.BlockChain().GetChain(ui.eth.BlockManager.BlockChain().CurrentBlock.Hash(), 10) | 	chain := ui.eth.BlockManager.BlockChain().GetChain(ui.eth.BlockManager.BlockChain().CurrentBlock.Hash(), 10) | ||||||
| 	for _, block := range chain { | 	for _, block := range chain { | ||||||
| 		ui.ProcessBlock(block) | 		ui.ProcessBlock(block) | ||||||
| @ -81,17 +102,24 @@ func (ui *Gui) ProcessBlock(block *ethchain.Block) { | |||||||
| 	ui.win.Root().Call("addBlock", NewBlockFromBlock(block)) | 	ui.win.Root().Call("addBlock", NewBlockFromBlock(block)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // Logging functions that log directly to the GUI interface
 | ||||||
| func (ui *Gui) Println(v ...interface{}) { | func (ui *Gui) Println(v ...interface{}) { | ||||||
| 	str := fmt.Sprintln(v...) | 	str := strings.TrimRight(fmt.Sprintln(v...), "\n") | ||||||
| 	// remove last \n
 | 	lines := strings.Split(str, "\n") | ||||||
| 	ui.win.Root().Call("addLog", str[:len(str)-1]) | 	for _, line := range lines { | ||||||
|  | 		ui.win.Root().Call("addLog", line) | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (ui *Gui) Printf(format string, v ...interface{}) { | func (ui *Gui) Printf(format string, v ...interface{}) { | ||||||
| 	str := strings.TrimRight(fmt.Sprintf(format, v...), "\n") | 	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() { | func (ui *Gui) updatePeers() { | ||||||
| 	for { | 	for { | ||||||
| 		ui.win.Root().Call("setPeers", fmt.Sprintf("%d / %d", ui.eth.Peers().Len(), ui.eth.MaxPeers)) | 		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 { | type UiLib struct { | ||||||
| 	engine *qml.Engine | 	engine    *qml.Engine | ||||||
| 	eth    *eth.Ethereum | 	eth       *eth.Ethereum | ||||||
|  | 	connected bool | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // Opens a QML file (external application)
 | ||||||
| func (ui *UiLib) Open(path string) { | func (ui *UiLib) Open(path string) { | ||||||
| 	component, err := ui.engine.LoadFile(path[7:]) | 	component, err := ui.engine.LoadFile(path[7:]) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| @ -118,7 +149,13 @@ func (ui *UiLib) Open(path string) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (ui *UiLib) Connect() { | 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 { | type Tester struct { | ||||||
|  | |||||||
| @ -5,7 +5,6 @@ import ( | |||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"github.com/ethereum/eth-go/ethchain" | 	"github.com/ethereum/eth-go/ethchain" | ||||||
| 	"github.com/ethereum/eth-go/ethutil" | 	"github.com/ethereum/eth-go/ethutil" | ||||||
| 	"math/big" |  | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type EthLib struct { | type EthLib struct { | ||||||
| @ -14,15 +13,18 @@ type EthLib struct { | |||||||
| 	txPool       *ethchain.TxPool | 	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) | 	hash, err := hex.DecodeString(receiver) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err.Error() | 		return err.Error() | ||||||
| 	} | 	} | ||||||
| 
 |  | ||||||
| 	tx := ethchain.NewTransaction(hash, big.NewInt(int64(amount)), []string{""}) |  | ||||||
| 	data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) | 	data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) | ||||||
| 	keyRing := ethutil.NewValueFromBytes(data) | 	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()) | 	tx.Sign(keyRing.Get(0).Bytes()) | ||||||
| 
 | 
 | ||||||
| 	lib.txPool.QueueTransaction(tx) | 	lib.txPool.QueueTransaction(tx) | ||||||
|  | |||||||
							
								
								
									
										70
									
								
								wallet.qml
									
									
									
									
									
								
							
							
						
						
									
										70
									
								
								wallet.qml
									
									
									
									
									
								
							| @ -3,7 +3,7 @@ import QtQuick.Controls 1.0; | |||||||
| import QtQuick.Layouts 1.0; | import QtQuick.Layouts 1.0; | ||||||
| import QtQuick.Dialogs 1.0; | import QtQuick.Dialogs 1.0; | ||||||
| import QtQuick.Window 2.1; | import QtQuick.Window 2.1; | ||||||
| import GoExtensions 1.0 | import Ethereum 1.0 | ||||||
| 
 | 
 | ||||||
| ApplicationWindow { | ApplicationWindow { | ||||||
| 	id: root | 	id: root | ||||||
| @ -22,15 +22,19 @@ ApplicationWindow { | |||||||
| 			width: parent.width | 			width: parent.width | ||||||
| 			Button { | 			Button { | ||||||
| 			      text: "Send" | 			      text: "Send" | ||||||
| 			      onClicked: console.log("SEND") | 			      onClicked: { | ||||||
|  | 				      console.log(eth.createTx(txReceiver.text, txAmount.text)) | ||||||
|  | 			      } | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			TextField { | 			TextField { | ||||||
|  | 			      id: txAmount | ||||||
| 			      width: 200 | 			      width: 200 | ||||||
| 			      placeholderText: "Amount" | 			      placeholderText: "Amount" | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			TextField { | 			TextField { | ||||||
|  | 			      id: txReceiver | ||||||
| 			      width: 300 | 			      width: 300 | ||||||
| 			      placeholderText: "Receiver Address (or empty for contract)" | 			      placeholderText: "Receiver Address (or empty for contract)" | ||||||
| 			      Layout.fillWidth: true | 			      Layout.fillWidth: true | ||||||
| @ -47,15 +51,43 @@ ApplicationWindow { | |||||||
| 		anchors.left: parent.left | 		anchors.left: parent.left | ||||||
| 
 | 
 | ||||||
| 		TextArea { | 		TextArea { | ||||||
| 			      id: codeView | 			id: codeView | ||||||
| 			      width: parent.width /2  | 			width: parent.width /2  | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		TextArea { | 		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 { | 	property var blockModel: ListModel { | ||||||
| 		id: blockModel | 		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) { | 	function addBlock(block) { | ||||||
| 		blockModel.insert(0, {number: block.number, hash: block.hash}) | 		blockModel.insert(0, {number: block.number, hash: block.hash}) | ||||||
| 	} | 	} | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user