Forráskód Böngészése

Implemented new miner w/ ui interface for merged mining. Closes #177

* Miner has been rewritten
* Added new miner pane
* Added option for local txs
* Added option to read from MergeMining contract and list them for
  merged mining
obscuren 11 éve
szülő
commit
429dd2a100

+ 5 - 2
block_pool.go

@@ -315,9 +315,12 @@ out:
 			// otherwise process and don't emit anything
 			if len(blocks) > 0 {
 				chainManager := self.eth.ChainManager()
+				// Test and import
 				chain := chain.NewChain(blocks)
-				_, err := chainManager.TestChain(chain)
+				_, err := chainManager.TestChain(chain, true)
 				if err != nil {
+					poollogger.Debugln(err)
+
 					self.Reset()
 
 					poollogger.Debugf("Punishing peer for supplying bad chain (%v)\n", self.peer.conn.RemoteAddr())
@@ -327,7 +330,7 @@ out:
 					self.td = ethutil.Big0
 					self.peer = nil
 				} else {
-					chainManager.InsertChain(chain)
+					//chainManager.InsertChain(chain)
 					for _, block := range blocks {
 						self.Remove(block.Hash())
 					}

+ 9 - 7
chain/block_manager.go

@@ -228,7 +228,7 @@ func (sm *BlockManager) Process(block *Block) (td *big.Int, err error) {
 func (sm *BlockManager) ProcessWithParent(block, parent *Block) (td *big.Int, err error) {
 	sm.lastAttemptedBlock = block
 
-	state := parent.State()
+	state := parent.State().Copy()
 
 	// Defer the Undo on the Trie. If the block processing happened
 	// we don't want to undo but since undo only happens on dirty
@@ -240,20 +240,22 @@ func (sm *BlockManager) ProcessWithParent(block, parent *Block) (td *big.Int, er
 		fmt.Printf("## %x %x ##\n", block.Hash(), block.Number)
 	}
 
+	_, err = sm.ApplyDiff(state, parent, block)
+	if err != nil {
+		return nil, err
+	}
+
+	/* Go and C++ don't have consensus here. FIXME
 	txSha := DeriveSha(block.transactions)
 	if bytes.Compare(txSha, block.TxSha) != 0 {
 		return nil, fmt.Errorf("Error validating transaction sha. Received %x, got %x", block.TxSha, txSha)
 	}
 
-	receipts, err := sm.ApplyDiff(state, parent, block)
-	if err != nil {
-		return nil, err
-	}
-
 	receiptSha := DeriveSha(receipts)
 	if bytes.Compare(receiptSha, block.ReceiptSha) != 0 {
 		return nil, fmt.Errorf("Error validating receipt sha. Received %x, got %x", block.ReceiptSha, receiptSha)
 	}
+	*/
 
 	// Block validation
 	if err = sm.ValidateBlock(block, parent); err != nil {
@@ -374,7 +376,7 @@ func (sm *BlockManager) AccumelateRewards(state *state.State, block, parent *Blo
 
 		uncleParent := sm.bc.GetBlock(uncle.PrevHash)
 		if uncleParent == nil {
-			return UncleError("Uncle's parent unknown")
+			return UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.PrevHash[0:4]))
 		}
 
 		if uncleParent.Number.Cmp(new(big.Int).Sub(parent.Number, big.NewInt(6))) < 0 {

+ 29 - 5
chain/chain_manager.go

@@ -23,6 +23,8 @@ type ChainManager struct {
 
 	CurrentBlock  *Block
 	LastBlockHash []byte
+
+	workingChain *BlockChain
 }
 
 func NewChainManager(ethereum EthManager) *ChainManager {
@@ -225,9 +227,18 @@ func (self *ChainManager) CalcTotalDiff(block *Block) (*big.Int, error) {
 	return td, nil
 }
 
-func (bc *ChainManager) GetBlock(hash []byte) *Block {
+func (self *ChainManager) GetBlock(hash []byte) *Block {
 	data, _ := ethutil.Config.Db.Get(hash)
 	if len(data) == 0 {
+		if self.workingChain != nil {
+			// Check the temp chain
+			for e := self.workingChain.Front(); e != nil; e = e.Next() {
+				if bytes.Compare(e.Value.(*link).block.Hash(), hash) == 0 {
+					return e.Value.(*link).block
+				}
+			}
+		}
+
 		return nil
 	}
 
@@ -310,6 +321,7 @@ func NewChain(blocks Blocks) *BlockChain {
 }
 
 // This function assumes you've done your checking. No checking is done at this stage anymore
+/*
 func (self *ChainManager) InsertChain(chain *BlockChain) {
 	for e := chain.Front(); e != nil; e = e.Next() {
 		link := e.Value.(*link)
@@ -318,8 +330,11 @@ func (self *ChainManager) InsertChain(chain *BlockChain) {
 		self.add(link.block)
 	}
 }
+*/
+
+func (self *ChainManager) TestChain(chain *BlockChain, imp bool) (td *big.Int, err error) {
+	self.workingChain = chain
 
-func (self *ChainManager) TestChain(chain *BlockChain) (td *big.Int, err error) {
 	for e := chain.Front(); e != nil; e = e.Next() {
 		var (
 			l      = e.Value.(*link)
@@ -348,12 +363,21 @@ func (self *ChainManager) TestChain(chain *BlockChain) (td *big.Int, err error)
 			return
 		}
 		l.td = td
+
+		if imp {
+			self.SetTotalDifficulty(td)
+			self.add(block)
+		}
 	}
 
-	if td.Cmp(self.TD) <= 0 {
-		err = &TDError{td, self.TD}
-		return
+	if !imp {
+		if td.Cmp(self.TD) <= 0 {
+			err = &TDError{td, self.TD}
+			return
+		}
 	}
 
+	self.workingChain = nil
+
 	return
 }

+ 2 - 1
chain/dagger.go

@@ -47,6 +47,7 @@ func (pow *EasyPow) Search(block *Block, stop <-chan struct{}) []byte {
 		select {
 		case <-stop:
 			powlogger.Infoln("Breaking from mining")
+			pow.HashRate = 0
 			return nil
 		default:
 			i++
@@ -55,7 +56,7 @@ func (pow *EasyPow) Search(block *Block, stop <-chan struct{}) []byte {
 				elapsed := time.Now().UnixNano() - start
 				hashes := ((float64(1e9) / float64(elapsed)) * float64(i)) / 1000
 				pow.HashRate = int64(hashes)
-				powlogger.Infoln("Hashing @", int64(pow.HashRate), "khash")
+				powlogger.Infoln("Hashing @", pow.HashRate, "khash")
 
 				t = time.Now()
 			}

BIN
cmd/mist/assets/miner.png


+ 13 - 29
cmd/mist/assets/qml/main.qml

@@ -12,7 +12,6 @@ import "../ext/http.js" as Http
 ApplicationWindow {
 	id: root
 
-	property alias miningButtonText: miningButton.text
 	property var ethx : Eth.ethx
 	property var browser
 
@@ -47,6 +46,7 @@ ApplicationWindow {
 	Component.onCompleted: {
 		var wallet = addPlugin("./views/wallet.qml", {noAdd: true, close: false, section: "ethereum", active: true});
 		var browser = addPlugin("./webapp.qml", {noAdd: true, close: false, section: "ethereum", active: true});
+		var browser = addPlugin("./views/miner.qml", {noAdd: true, close: false, section: "ethereum", active: true});
 		root.browser = browser;
 
 		addPlugin("./views/transaction.qml", {noAdd: true, close: false, section: "legacy"});
@@ -252,29 +252,18 @@ ApplicationWindow {
 	}
 
 	statusBar: StatusBar {
-		height: 32
+		//height: 32
 		id: statusBar
-		RowLayout {
-			Button {
-				id: miningButton
-				text: "Start Mining"
-				onClicked: {
-					gui.toggleMining()
-				}
-			}
-
-			RowLayout {
-				Label {
-					id: walletValueLabel
+		Label {
+			//y: 6
+			id: walletValueLabel
 
-					font.pixelSize: 10
-					styleColor: "#797979"
-				}
-			}
+			font.pixelSize: 10
+			styleColor: "#797979"
 		}
 
 		Label {
-			y: 6
+			//y: 6
 			objectName: "miningLabel"
 			visible: true
 			font.pixelSize: 10
@@ -283,7 +272,7 @@ ApplicationWindow {
 		}
 
 		Label {
-			y: 6
+			//y: 6
 			id: lastBlockLabel
 			objectName: "lastBlockLabel"
 			visible: true
@@ -297,14 +286,14 @@ ApplicationWindow {
 			id: downloadIndicator
 			value: 0
 			objectName: "downloadIndicator"
-			y: 3
+			y: -4
 			x: statusBar.width / 2 - this.width / 2
 			width: 160
 		}
 
 		Label {
 			objectName: "downloadLabel"
-			y: 7
+			//y: 7
 			anchors.left: downloadIndicator.right
 			anchors.leftMargin: 5
 			font.pixelSize: 10
@@ -314,7 +303,7 @@ ApplicationWindow {
 
 		RowLayout {
 			id: peerGroup
-			y: 7
+			//y: 7
 			anchors.right: parent.right
 			MouseArea {
 				onDoubleClicked:  peerWindow.visible = true
@@ -323,14 +312,9 @@ ApplicationWindow {
 
 			Label {
 				id: peerLabel
-				font.pixelSize: 8
+				font.pixelSize: 10
 				text: "0 / 0"
 			}
-			Image {
-				id: peerImage
-				width: 10; height: 10
-				source: "../network.png"
-			}
 		}
 	}
 

+ 254 - 0
cmd/mist/assets/qml/views/miner.qml

@@ -0,0 +1,254 @@
+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
+
+Rectangle {
+	id: root
+	property var title: "Miner"
+	property var iconSource: "../miner.png"
+	property var menuItem
+
+	color: "#00000000"
+
+	ColumnLayout {
+		spacing: 10
+		anchors.fill: parent
+
+		Rectangle {
+			id: mainPane
+			color: "#00000000"
+			anchors {
+				top: parent.top
+				bottom: localTxPane.top
+				left: parent.left
+				right: parent.right
+			}
+
+			Rectangle {
+				id: menu
+				height: 25
+				anchors {
+					left: parent.left
+				}
+
+				RowLayout {
+					id: tools
+					anchors {
+						left: parent.left
+						right: parent.right
+					}
+
+					Button {
+						text: "Start"
+						onClicked: {
+							eth.setGasPrice(minGasPrice.text || "10000000000000");
+							if (eth.toggleMining()) {
+								this.text = "Stop";
+							} else {
+								this.text = "Start";
+							}
+						}
+					}
+
+					Rectangle {
+						anchors.top: parent.top
+						anchors.topMargin: 2
+						width: 200
+						TextField {
+							id: minGasPrice
+							placeholderText: "Min Gas: 10000000000000"
+							width: 200
+							validator: RegExpValidator { regExp: /\d*/ }
+						}
+					}
+				}
+			}
+
+			Column {
+				anchors {
+					left: parent.left
+					right: parent.right
+					top: menu.bottom
+					topMargin: 5
+				}
+
+				Text {
+					text: "<b>Merged mining options</b>"
+				}
+
+				TableView {
+					id: mergedMiningTable
+					height: 300
+					anchors {
+						left: parent.left
+						right: parent.right
+					}
+					Component {
+						id: checkBoxDelegate
+
+						Item {
+							id: test
+							CheckBox {
+								anchors.fill: parent
+								checked: styleData.value
+
+								onClicked: {
+									var model = mergedMiningModel.get(styleData.row)
+
+									if (this.checked) {
+										model.id = txModel.createLocalTx(model.address, "0", "5000", "0", "")
+									} else {
+										txModel.removeWithId(model.id);
+										model.id = 0;
+									}
+								}
+							}
+						}
+					}
+					TableViewColumn{ role: "checked" ; title: "" ; width: 40 ; delegate: checkBoxDelegate }
+					TableViewColumn{ role: "name" ; title: "Name" ; width: 480 }
+					model: ListModel {
+						objectName: "mergedMiningModel"
+						id: mergedMiningModel 
+						function addMergedMiningOption(model) {
+							this.append(model);
+						}
+					}
+					Component.onCompleted: {
+						/* interface test stuff
+						// XXX Temp. replace with above eventually
+						var tmpItems = ["JEVCoin", "Some coin", "Other coin", "Etc coin"];
+						var address = "e6716f9544a56c530d868e4bfbacb172315bdead";
+						for (var i = 0; i < tmpItems.length; i++) {
+							mergedMiningModel.append({checked: false, name: tmpItems[i], address: address, id: 0, itemId: i});
+						}
+						*/
+					}
+				}
+			}
+		}
+
+		Rectangle {
+			id: localTxPane
+			color: "#ececec"
+			border.color: "#cccccc"
+			border.width: 1
+			anchors {
+				left: parent.left
+				right: parent.right
+				bottom: parent.bottom
+			}
+			height: 300
+
+			ColumnLayout {
+				spacing: 10
+				anchors.fill: parent
+				RowLayout {
+					id: newLocalTx
+					anchors {
+						left: parent.left
+						leftMargin: 5
+						top: parent.top
+						topMargin: 5
+						bottomMargin: 5
+					}
+
+					Text {
+						text: "Local tx"
+					}
+
+					Rectangle {
+						width: 250
+						color: "#00000000"
+						anchors.top: parent.top
+						anchors.topMargin: 2
+
+						TextField {
+							id: to
+							placeholderText: "To"
+							width: 250
+							validator: RegExpValidator { regExp: /[abcdefABCDEF1234567890]*/ }
+						}
+					}
+					TextField {
+						property var defaultGas: "5000"
+						id: gas
+						placeholderText: "Gas"
+						text: defaultGas
+						validator: RegExpValidator { regExp: /\d*/ }
+					}
+					TextField {
+						id: gasPrice
+						placeholderText: "Price"
+						validator: RegExpValidator { regExp: /\d*/ }
+					}
+					TextField {
+						id: value 
+						placeholderText: "Amount"
+						text: "0"
+						validator: RegExpValidator { regExp: /\d*/ }
+					}
+					TextField {
+						id: data
+						placeholderText: "Data"
+						validator: RegExpValidator { regExp: /[abcdefABCDEF1234567890]*/ }
+					}
+					Button {
+						text: "Create"
+						onClicked: {
+							if (to.text.length == 40 && gasPrice.text.length != 0 && value.text.length != 0 && gas.text.length != 0) {
+								txModel.createLocalTx(to.text, gasPrice.text, gas.text, value.text, data.text);
+
+								to.text = ""; gasPrice.text = "";
+								gas.text = gas.defaultGas;
+								value.text = "0"
+							}
+						}
+					}
+				}
+
+				TableView {
+					id: txTableView
+					anchors {
+						top: newLocalTx.bottom
+						topMargin: 5
+						left: parent.left
+						right: parent.right
+						bottom: parent.bottom
+					}
+					TableViewColumn{ role: "to" ; title: "To" ; width: 480 }
+					TableViewColumn{ role: "gas" ; title: "Gas" ; width: 100 }
+					TableViewColumn{ role: "gasPrice" ; title: "Gas Price" ; width: 100 }
+					TableViewColumn{ role: "value" ; title: "Amount" ; width: 100 }
+					TableViewColumn{ role: "data" ; title: "Data" ; width: 100 }
+
+					model: ListModel {
+						id: txModel
+						Component.onCompleted: {
+						}
+						function removeWithId(id) {
+							for (var i = 0; i < this.count; i++) {
+								if (txModel.get(i).id == id) {
+									this.remove(i);
+									eth.removeLocalTransaction(id)
+									break;
+								}
+							}
+						}
+
+						function createLocalTx(to, gasPrice, gas, value, data) {
+							var id = eth.addLocalTransaction(to, data, gas, gasPrice, value)
+							txModel.insert(0, {to: to, gas: gas, gasPrice: gasPrice, value: value, data: data, id: id});
+
+							return id
+						}
+					}
+				}
+			}
+		}
+	}
+}

+ 0 - 21
cmd/mist/bindings.go

@@ -70,10 +70,6 @@ func (gui *Gui) GetCustomIdentifier() string {
 	return gui.clientIdentity.GetCustomIdentifier()
 }
 
-func (gui *Gui) ToggleTurboMining() {
-	gui.miner.ToggleTurbo()
-}
-
 // functions that allow Gui to implement interface guilogger.LogSystem
 func (gui *Gui) SetLogLevel(level logger.LogLevel) {
 	gui.logLevel = level
@@ -137,20 +133,3 @@ func (self *Gui) DumpState(hash, path string) {
 
 	file.Write(stateDump)
 }
-func (gui *Gui) ToggleMining() {
-	var txt string
-	if gui.eth.Mining {
-		utils.StopMining(gui.eth)
-		txt = "Start mining"
-
-		gui.getObjectByName("miningLabel").Set("visible", false)
-	} else {
-		utils.StartMining(gui.eth)
-		gui.miner = utils.GetMiner()
-		txt = "Stop mining"
-
-		gui.getObjectByName("miningLabel").Set("visible", true)
-	}
-
-	gui.win.Root().Set("miningButtonText", txt)
-}

+ 38 - 13
cmd/mist/gui.go

@@ -272,8 +272,6 @@ type address struct {
 
 func (gui *Gui) loadAddressBook() {
 	view := gui.getObjectByName("infoView")
-	view.Call("clearAddress")
-
 	nameReg := gui.pipe.World().Config().Get("NameReg")
 	if nameReg != nil {
 		nameReg.EachStorage(func(name string, value *ethutil.Value) {
@@ -286,6 +284,28 @@ func (gui *Gui) loadAddressBook() {
 	}
 }
 
+func (self *Gui) loadMergedMiningOptions() {
+	view := self.getObjectByName("mergedMiningModel")
+
+	nameReg := self.pipe.World().Config().Get("MergeMining")
+	if nameReg != nil {
+		i := 0
+		nameReg.EachStorage(func(name string, value *ethutil.Value) {
+			if name[0] != 0 {
+				value.Decode()
+
+				view.Call("addMergedMiningOption", struct {
+					Checked       bool
+					Name, Address string
+					Id, ItemId    int
+				}{false, name, ethutil.Bytes2Hex(value.Bytes()), 0, i})
+
+				i++
+			}
+		})
+	}
+}
+
 func (gui *Gui) insertTransaction(window string, tx *chain.Transaction) {
 	pipe := xeth.New(gui.eth)
 	nameReg := pipe.World().Config().Get("NameReg")
@@ -382,6 +402,7 @@ func (gui *Gui) update() {
 	go func() {
 		go gui.setInitialChainManager()
 		gui.loadAddressBook()
+		gui.loadMergedMiningOptions()
 		gui.setPeerInfo()
 		gui.readPreviousTransactions()
 	}()
@@ -410,7 +431,6 @@ func (gui *Gui) update() {
 		chain.NewBlockEvent{},
 		chain.TxPreEvent{},
 		chain.TxPostEvent{},
-		miner.Event{},
 	)
 
 	// nameReg := gui.pipe.World().Config().Get("NameReg")
@@ -469,12 +489,14 @@ func (gui *Gui) update() {
 				case eth.PeerListEvent:
 					gui.setPeerInfo()
 
-				case miner.Event:
-					if ev.Type == miner.Started {
-						gui.miner = ev.Miner
-					} else {
-						gui.miner = nil
-					}
+					/*
+						case miner.Event:
+							if ev.Type == miner.Started {
+								gui.miner = ev.Miner
+							} else {
+								gui.miner = nil
+							}
+					*/
 				}
 
 			case <-peerUpdateTicker.C:
@@ -483,10 +505,13 @@ func (gui *Gui) update() {
 				statusText := "#" + gui.eth.ChainManager().CurrentBlock.Number.String()
 				lastBlockLabel.Set("text", statusText)
 
-				if gui.miner != nil {
-					pow := gui.miner.GetPow()
-					miningLabel.Set("text", "Mining @ "+strconv.FormatInt(pow.GetHashrate(), 10)+"Khash")
-				}
+				miningLabel.Set("text", "Mining @ "+strconv.FormatInt(gui.uiLib.miner.GetPow().GetHashrate(), 10)+"Khash")
+				/*
+					if gui.miner != nil {
+						pow := gui.miner.GetPow()
+						miningLabel.Set("text", "Mining @ "+strconv.FormatInt(pow.GetHashrate(), 10)+"Khash")
+					}
+				*/
 
 				blockLength := gui.eth.BlockPool().BlocksProcessed
 				chainLength := gui.eth.BlockPool().ChainLength

+ 37 - 1
cmd/mist/ui_lib.go

@@ -29,6 +29,7 @@ import (
 	"github.com/ethereum/go-ethereum/crypto"
 	"github.com/ethereum/go-ethereum/ethutil"
 	"github.com/ethereum/go-ethereum/javascript"
+	"github.com/ethereum/go-ethereum/miner"
 	"github.com/ethereum/go-ethereum/state"
 	"github.com/ethereum/go-ethereum/ui/qt"
 	"github.com/ethereum/go-ethereum/xeth"
@@ -55,10 +56,15 @@ type UiLib struct {
 	jsEngine *javascript.JSRE
 
 	filterCallbacks map[int][]int
+
+	miner *miner.Miner
 }
 
 func NewUiLib(engine *qml.Engine, eth *eth.Ethereum, assetPath string) *UiLib {
-	return &UiLib{JSXEth: xeth.NewJSXEth(eth), engine: engine, eth: eth, assetPath: assetPath, jsEngine: javascript.NewJSRE(eth), filterCallbacks: make(map[int][]int)} //, filters: make(map[int]*xeth.JSFilter)}
+	lib := &UiLib{JSXEth: xeth.NewJSXEth(eth), engine: engine, eth: eth, assetPath: assetPath, jsEngine: javascript.NewJSRE(eth), filterCallbacks: make(map[int][]int)} //, filters: make(map[int]*xeth.JSFilter)}
+	lib.miner = miner.New(eth.KeyManager().Address(), eth)
+
+	return lib
 }
 
 func (self *UiLib) Notef(args []interface{}) {
@@ -328,3 +334,33 @@ func (self *UiLib) Call(params map[string]interface{}) (string, error) {
 		object["data"],
 	)
 }
+
+func (self *UiLib) AddLocalTransaction(to, data, gas, gasPrice, value string) int {
+	return self.miner.AddLocalTx(&miner.LocalTx{
+		To:       ethutil.Hex2Bytes(to),
+		Data:     ethutil.Hex2Bytes(data),
+		Gas:      gas,
+		GasPrice: gasPrice,
+		Value:    value,
+	}) - 1
+}
+
+func (self *UiLib) RemoveLocalTransaction(id int) {
+	self.miner.RemoveLocalTx(id)
+}
+
+func (self *UiLib) SetGasPrice(price string) {
+	self.miner.MinAcceptedGasPrice = ethutil.Big(price)
+}
+
+func (self *UiLib) ToggleMining() bool {
+	if !self.miner.Mining() {
+		self.miner.Start()
+
+		return true
+	} else {
+		self.miner.Stop()
+
+		return false
+	}
+}

+ 1 - 1
cmd/utils/cmd.go

@@ -266,7 +266,7 @@ func StartMining(ethereum *eth.Ethereum) bool {
 		go func() {
 			clilogger.Infoln("Start mining")
 			if gminer == nil {
-				gminer = miner.NewDefaultMiner(addr, ethereum)
+				gminer = miner.New(addr, ethereum)
 			}
 			// Give it some time to connect with peers
 			time.Sleep(3 * time.Second)

+ 154 - 144
miner/miner.go

@@ -1,220 +1,230 @@
 package miner
 
 import (
-	"bytes"
+	"math/big"
 	"sort"
 
+	"github.com/ethereum/go-ethereum"
+	"github.com/ethereum/go-ethereum/ethutil"
+
 	"github.com/ethereum/go-ethereum/chain"
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/logger"
 	"github.com/ethereum/go-ethereum/wire"
 )
 
+type LocalTx struct {
+	To       []byte `json:"to"`
+	Data     []byte `json:"data"`
+	Gas      string `json:"gas"`
+	GasPrice string `json:"gasPrice"`
+	Value    string `json:"value"`
+}
+
+func (self *LocalTx) Sign(key []byte) *chain.Transaction {
+	return nil
+}
+
 var minerlogger = logger.NewLogger("MINER")
 
 type Miner struct {
-	pow      chain.PoW
-	ethereum chain.EthManager
-	coinbase []byte
-	txs      chain.Transactions
-	uncles   []*chain.Block
-	block    *chain.Block
-
-	events      event.Subscription
-	powQuitChan chan struct{}
-	powDone     chan struct{}
-
-	turbo bool
-}
+	eth    *eth.Ethereum
+	events event.Subscription
 
-const (
-	Started = iota
-	Stopped
-)
+	uncles    chain.Blocks
+	localTxs  map[int]*LocalTx
+	localTxId int
+
+	pow       chain.PoW
+	quitCh    chan struct{}
+	powQuitCh chan struct{}
+
+	Coinbase []byte
 
-type Event struct {
-	Type  int // Started || Stopped
-	Miner *Miner
+	mining bool
+
+	MinAcceptedGasPrice *big.Int
+}
+
+func New(coinbase []byte, eth *eth.Ethereum) *Miner {
+	return &Miner{
+		eth:                 eth,
+		powQuitCh:           make(chan struct{}),
+		pow:                 &chain.EasyPow{},
+		mining:              false,
+		localTxs:            make(map[int]*LocalTx),
+		MinAcceptedGasPrice: big.NewInt(10000000000000),
+		Coinbase:            coinbase,
+	}
 }
 
 func (self *Miner) GetPow() chain.PoW {
 	return self.pow
 }
 
-func NewDefaultMiner(coinbase []byte, ethereum chain.EthManager) *Miner {
-	miner := Miner{
-		pow:      &chain.EasyPow{},
-		ethereum: ethereum,
-		coinbase: coinbase,
+func (self *Miner) AddLocalTx(tx *LocalTx) int {
+	minerlogger.Infof("Added local tx (%x %v / %v)\n", tx.To[0:4], tx.GasPrice, tx.Value)
+
+	self.localTxId++
+	self.localTxs[self.localTxId] = tx
+	self.eth.EventMux().Post(tx)
+
+	return self.localTxId
+}
+
+func (self *Miner) RemoveLocalTx(id int) {
+	if tx := self.localTxs[id]; tx != nil {
+		minerlogger.Infof("Removed local tx (%x %v / %v)\n", tx.To[0:4], tx.GasPrice, tx.Value)
 	}
+	self.eth.EventMux().Post(&LocalTx{})
 
-	return &miner
+	delete(self.localTxs, id)
 }
 
-func (self *Miner) ToggleTurbo() {
-	self.turbo = !self.turbo
+func (self *Miner) Start() {
+	if self.mining {
+		return
+	}
 
-	self.pow.Turbo(self.turbo)
+	minerlogger.Infoln("Starting mining operations")
+	self.mining = true
+	self.quitCh = make(chan struct{})
+	self.powQuitCh = make(chan struct{})
+
+	mux := self.eth.EventMux()
+	self.events = mux.Subscribe(chain.NewBlockEvent{}, chain.TxPreEvent{}, &LocalTx{})
+
+	go self.update()
+	go self.mine()
 }
 
-func (miner *Miner) Start() {
+func (self *Miner) Stop() {
+	if !self.mining {
+		return
+	}
 
-	// Insert initial TXs in our little miner 'pool'
-	miner.txs = miner.ethereum.TxPool().Flush()
-	miner.block = miner.ethereum.ChainManager().NewBlock(miner.coinbase)
+	self.mining = false
 
-	mux := miner.ethereum.EventMux()
-	miner.events = mux.Subscribe(chain.NewBlockEvent{}, chain.TxPreEvent{})
+	minerlogger.Infoln("Stopping mining operations")
 
-	// Prepare inital block
-	//miner.ethereum.BlockManager().Prepare(miner.block.State(), miner.block.State())
-	go miner.listener()
+	self.events.Unsubscribe()
 
-	minerlogger.Infoln("Started")
-	mux.Post(Event{Started, miner})
+	close(self.quitCh)
+	close(self.powQuitCh)
 }
 
-func (miner *Miner) Stop() {
-	minerlogger.Infoln("Stopping...")
-	miner.events.Unsubscribe()
-	miner.ethereum.EventMux().Post(Event{Stopped, miner})
+func (self *Miner) Mining() bool {
+	return self.mining
 }
 
-func (miner *Miner) listener() {
-	miner.startMining()
-
+func (self *Miner) update() {
+out:
 	for {
 		select {
-		case event := <-miner.events.Chan():
+		case event := <-self.events.Chan():
 			switch event := event.(type) {
 			case chain.NewBlockEvent:
-				miner.stopMining()
-
 				block := event.Block
-				//minerlogger.Infoln("Got new block via Reactor")
-				if bytes.Compare(miner.ethereum.ChainManager().CurrentBlock.Hash(), block.Hash()) == 0 {
-					// TODO: Perhaps continue mining to get some uncle rewards
-					//minerlogger.Infoln("New top block found resetting state")
-
-					// Filter out which Transactions we have that were not in this block
-					var newtxs []*chain.Transaction
-					for _, tx := range miner.txs {
-						found := false
-						for _, othertx := range block.Transactions() {
-							if bytes.Compare(tx.Hash(), othertx.Hash()) == 0 {
-								found = true
-							}
-						}
-						if found == false {
-							newtxs = append(newtxs, tx)
-						}
-					}
-					miner.txs = newtxs
-				} else {
-					if bytes.Compare(block.PrevHash, miner.ethereum.ChainManager().CurrentBlock.PrevHash) == 0 {
-						minerlogger.Infoln("Adding uncle block")
-						miner.uncles = append(miner.uncles, block)
-					}
-				}
-				miner.startMining()
-
-			case chain.TxPreEvent:
-				miner.stopMining()
-
-				found := false
-				for _, ctx := range miner.txs {
-					if found = bytes.Compare(ctx.Hash(), event.Tx.Hash()) == 0; found {
-						break
-					}
-
-					miner.startMining()
-				}
-				if found == false {
-					// Undo all previous commits
-					miner.block.Undo()
-					// Apply new transactions
-					miner.txs = append(miner.txs, event.Tx)
+				if self.eth.ChainManager().HasBlock(block.Hash()) {
+					self.reset()
+					self.eth.TxPool().RemoveSet(block.Transactions())
+					go self.mine()
+				} else if true {
+					// do uncle stuff
 				}
+			case chain.TxPreEvent, *LocalTx:
+				self.reset()
+				go self.mine()
 			}
-
-		case <-miner.powDone:
-			miner.startMining()
+		case <-self.quitCh:
+			break out
 		}
 	}
 }
 
-func (miner *Miner) startMining() {
-	if miner.powDone == nil {
-		miner.powDone = make(chan struct{})
-	}
-	miner.powQuitChan = make(chan struct{})
-	go miner.mineNewBlock()
-}
-
-func (miner *Miner) stopMining() {
-	println("stop mining")
-	_, isopen := <-miner.powQuitChan
-	if isopen {
-		close(miner.powQuitChan)
-	}
-	//<-miner.powDone
+func (self *Miner) reset() {
+	println("reset")
+	close(self.powQuitCh)
+	self.powQuitCh = make(chan struct{})
 }
 
-func (self *Miner) mineNewBlock() {
-	blockManager := self.ethereum.BlockManager()
-	chainMan := self.ethereum.ChainManager()
-
-	self.block = chainMan.NewBlock(self.coinbase)
+func (self *Miner) mine() {
+	var (
+		blockManager = self.eth.BlockManager()
+		chainMan     = self.eth.ChainManager()
+		block        = chainMan.NewBlock(self.Coinbase)
+	)
+	block.MinGasPrice = self.MinAcceptedGasPrice
 
 	// Apply uncles
 	if len(self.uncles) > 0 {
-		self.block.SetUncles(self.uncles)
+		block.SetUncles(self.uncles)
 	}
 
-	// Sort the transactions by nonce in case of odd network propagation
-	sort.Sort(chain.TxByNonce{self.txs})
+	parent := chainMan.GetBlock(block.PrevHash)
+	coinbase := block.State().GetOrNewStateObject(block.Coinbase)
+	coinbase.SetGasPool(block.CalcGasLimit(parent))
+
+	transactions := self.finiliseTxs()
 
 	// Accumulate all valid transactions and apply them to the new state
 	// Error may be ignored. It's not important during mining
-	parent := self.ethereum.ChainManager().GetBlock(self.block.PrevHash)
-	coinbase := self.block.State().GetOrNewStateObject(self.block.Coinbase)
-	coinbase.SetGasPool(self.block.CalcGasLimit(parent))
-	receipts, txs, unhandledTxs, erroneous, err := blockManager.ProcessTransactions(coinbase, self.block.State(), self.block, self.block, self.txs)
+	receipts, txs, _, erroneous, err := blockManager.ProcessTransactions(coinbase, block.State(), block, block, transactions)
 	if err != nil {
 		minerlogger.Debugln(err)
 	}
-	self.ethereum.TxPool().RemoveSet(erroneous)
-	self.txs = append(txs, unhandledTxs...)
+	self.eth.TxPool().RemoveSet(erroneous)
 
-	self.block.SetTransactions(txs)
-	self.block.SetReceipts(receipts)
+	block.SetTransactions(txs)
+	block.SetReceipts(receipts)
 
 	// Accumulate the rewards included for this block
-	blockManager.AccumelateRewards(self.block.State(), self.block, parent)
+	blockManager.AccumelateRewards(block.State(), block, parent)
 
-	self.block.State().Update()
+	block.State().Update()
 
-	minerlogger.Infof("Mining on block. Includes %v transactions", len(self.txs))
+	minerlogger.Infof("Mining on block. Includes %v transactions", len(transactions))
 
 	// Find a valid nonce
-	nonce := self.pow.Search(self.block, self.powQuitChan)
+	nonce := self.pow.Search(block, self.powQuitCh)
 	if nonce != nil {
-		self.block.Nonce = nonce
-		lchain := chain.NewChain(chain.Blocks{self.block})
-		_, err := chainMan.TestChain(lchain)
+		block.Nonce = nonce
+		lchain := chain.NewChain(chain.Blocks{block})
+		_, err := chainMan.TestChain(lchain, true)
 		if err != nil {
 			minerlogger.Infoln(err)
 		} else {
-			self.ethereum.ChainManager().InsertChain(lchain)
-			self.ethereum.Broadcast(wire.MsgBlockTy, []interface{}{self.block.Value().Val})
-			minerlogger.Infof("🔨  Mined block %x\n", self.block.Hash())
-			minerlogger.Infoln(self.block)
-			// Gather the new batch of transactions currently in the tx pool
-			self.txs = self.ethereum.TxPool().CurrentTransactions()
-			self.ethereum.EventMux().Post(chain.NewBlockEvent{self.block})
+			//chainMan.InsertChain(lchain)
+			self.eth.EventMux().Post(chain.NewBlockEvent{block})
+			self.eth.Broadcast(wire.MsgBlockTy, []interface{}{block.Value().Val})
+
+			minerlogger.Infof("🔨  Mined block %x\n", block.Hash())
+			minerlogger.Infoln(block)
 		}
 
-		// Continue mining on the next block
-		self.startMining()
+		go self.mine()
 	}
 }
+
+func (self *Miner) finiliseTxs() chain.Transactions {
+	// Sort the transactions by nonce in case of odd network propagation
+	var txs chain.Transactions
+
+	state := self.eth.BlockManager().TransState()
+	// XXX This has to change. Coinbase is, for new, same as key.
+	key := self.eth.KeyManager()
+	for _, ltx := range self.localTxs {
+		tx := chain.NewTransactionMessage(ltx.To, ethutil.Big(ltx.Value), ethutil.Big(ltx.Gas), ethutil.Big(ltx.GasPrice), ltx.Data)
+		tx.Nonce = state.GetNonce(self.Coinbase)
+		state.SetNonce(self.Coinbase, tx.Nonce+1)
+
+		tx.Sign(key.PrivateKey())
+
+		txs = append(txs, tx)
+	}
+
+	txs = append(txs, self.eth.TxPool().CurrentTransactions()...)
+	sort.Sort(chain.TxByNonce{txs})
+
+	return txs
+}

+ 1 - 1
p2p/connection.go

@@ -6,7 +6,7 @@ import (
 	"net"
 	"time"
 
-	"github.com/ethereum/eth-go/ethutil"
+	"github.com/ethereum/go-ethereum/ethutil"
 )
 
 type Connection struct {

+ 1 - 1
p2p/message.go

@@ -2,7 +2,7 @@ package p2p
 
 import (
 	// "fmt"
-	"github.com/ethereum/eth-go/ethutil"
+	"github.com/ethereum/go-ethereum/ethutil"
 )
 
 type MsgCode uint8

+ 2 - 1
p2p/messenger_test.go

@@ -3,9 +3,10 @@ package p2p
 import (
 	// "fmt"
 	"bytes"
-	"github.com/ethereum/eth-go/ethutil"
 	"testing"
 	"time"
+
+	"github.com/ethereum/go-ethereum/ethutil"
 )
 
 func setupMessenger(handlers Handlers) (*TestNetworkConnection, chan *PeerError, *Messenger) {

+ 2 - 2
peer.go

@@ -24,7 +24,7 @@ const (
 	// The size of the output buffer for writing messages
 	outputBufferSize = 50
 	// Current protocol version
-	ProtocolVersion = 37
+	ProtocolVersion = 39
 	// Current P2P version
 	P2PVersion = 2
 	// Ethereum network version
@@ -863,7 +863,7 @@ func (p *Peer) String() string {
 		strConnectType = "disconnected"
 	}
 
-	return fmt.Sprintf("[%s] (%s) %v %s [%s]", strConnectType, strBoundType, p.conn.RemoteAddr(), p.version, p.caps)
+	return fmt.Sprintf("[%s] (%s) %v %s", strConnectType, strBoundType, p.conn.RemoteAddr(), p.version)
 
 }
 

+ 2 - 0
xeth/config.go

@@ -19,6 +19,8 @@ func (self *Config) Get(name string) *Object {
 		objectAddr := configCtrl.GetStorage(ethutil.BigD([]byte{0}))
 		domainAddr := (&Object{self.pipe.World().safeGet(objectAddr.Bytes())}).StorageString("DnsReg").Bytes()
 		return &Object{self.pipe.World().safeGet(domainAddr)}
+	case "MergeMining":
+		addr = []byte{4}
 	default:
 		addr = ethutil.RightPadBytes([]byte(name), 32)
 	}

+ 4 - 0
xeth/hexface.go

@@ -254,6 +254,10 @@ func (self *JSXEth) CompileMutan(code string) string {
 	return ethutil.Bytes2Hex(data)
 }
 
+func (self *JSXEth) FindInConfig(str string) string {
+	return ethutil.Bytes2Hex(self.World().Config().Get(str).Address())
+}
+
 func ToJSMessages(messages state.Messages) *ethutil.List {
 	var msgs []JSMessage
 	for _, m := range messages {