aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorobscuren <geffobscura@gmail.com>2014-11-07 19:18:48 +0800
committerobscuren <geffobscura@gmail.com>2014-11-07 19:18:48 +0800
commit429dd2a100f3b9e2b612b59bcb48f79a805cd6f9 (patch)
treec91fee673e461a192d4d783193c8ddbead4a97d2
parent48488017e498916c81122c01cfe1880afdd00d48 (diff)
downloaddexon-429dd2a100f3b9e2b612b59bcb48f79a805cd6f9.tar
dexon-429dd2a100f3b9e2b612b59bcb48f79a805cd6f9.tar.gz
dexon-429dd2a100f3b9e2b612b59bcb48f79a805cd6f9.tar.bz2
dexon-429dd2a100f3b9e2b612b59bcb48f79a805cd6f9.tar.lz
dexon-429dd2a100f3b9e2b612b59bcb48f79a805cd6f9.tar.xz
dexon-429dd2a100f3b9e2b612b59bcb48f79a805cd6f9.tar.zst
dexon-429dd2a100f3b9e2b612b59bcb48f79a805cd6f9.zip
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
-rw-r--r--block_pool.go7
-rw-r--r--chain/block_manager.go16
-rw-r--r--chain/chain_manager.go34
-rw-r--r--chain/dagger.go3
-rw-r--r--cmd/mist/assets/miner.pngbin0 -> 2100 bytes
-rw-r--r--cmd/mist/assets/qml/main.qml42
-rw-r--r--cmd/mist/assets/qml/views/miner.qml254
-rw-r--r--cmd/mist/bindings.go21
-rw-r--r--cmd/mist/gui.go51
-rw-r--r--cmd/mist/ui_lib.go38
-rw-r--r--cmd/utils/cmd.go2
-rw-r--r--miner/miner.go298
-rw-r--r--p2p/connection.go2
-rw-r--r--p2p/message.go2
-rw-r--r--p2p/messenger_test.go3
-rw-r--r--peer.go4
-rw-r--r--xeth/config.go2
-rw-r--r--xeth/hexface.go4
18 files changed, 554 insertions, 229 deletions
diff --git a/block_pool.go b/block_pool.go
index ff0675c50..ec945fa6e 100644
--- a/block_pool.go
+++ b/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())
}
diff --git a/chain/block_manager.go b/chain/block_manager.go
index ed2fbfe8c..79c18fbe3 100644
--- a/chain/block_manager.go
+++ b/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 {
diff --git a/chain/chain_manager.go b/chain/chain_manager.go
index 31f5f7543..5e62e6771 100644
--- a/chain/chain_manager.go
+++ b/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
}
diff --git a/chain/dagger.go b/chain/dagger.go
index 3333e002d..2cf70e091 100644
--- a/chain/dagger.go
+++ b/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()
}
diff --git a/cmd/mist/assets/miner.png b/cmd/mist/assets/miner.png
new file mode 100644
index 000000000..58e3f4dfe
--- /dev/null
+++ b/cmd/mist/assets/miner.png
Binary files differ
diff --git a/cmd/mist/assets/qml/main.qml b/cmd/mist/assets/qml/main.qml
index cfd227b49..d2a8d1d63 100644
--- a/cmd/mist/assets/qml/main.qml
+++ b/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"
- }
}
}
diff --git a/cmd/mist/assets/qml/views/miner.qml b/cmd/mist/assets/qml/views/miner.qml
new file mode 100644
index 000000000..e162d60a4
--- /dev/null
+++ b/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
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/cmd/mist/bindings.go b/cmd/mist/bindings.go
index ebdd8ec73..480c38b2e 100644
--- a/cmd/mist/bindings.go
+++ b/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)
-}
diff --git a/cmd/mist/gui.go b/cmd/mist/gui.go
index 5af1b5c7b..295011244 100644
--- a/cmd/mist/gui.go
+++ b/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
diff --git a/cmd/mist/ui_lib.go b/cmd/mist/ui_lib.go
index bb978707d..bdf551325 100644
--- a/cmd/mist/ui_lib.go
+++ b/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
+ }
+}
diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go
index e39655403..96590b20f 100644
--- a/cmd/utils/cmd.go
+++ b/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)
diff --git a/miner/miner.go b/miner/miner.go
index 7491ab373..2ab74e516 100644
--- a/miner/miner.go
+++ b/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
+}
diff --git a/p2p/connection.go b/p2p/connection.go
index e999cbe55..be366235d 100644
--- a/p2p/connection.go
+++ b/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 {
diff --git a/p2p/message.go b/p2p/message.go
index 4886eaa1f..446e74dff 100644
--- a/p2p/message.go
+++ b/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
diff --git a/p2p/messenger_test.go b/p2p/messenger_test.go
index bc21d34ba..472d74515 100644
--- a/p2p/messenger_test.go
+++ b/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) {
diff --git a/peer.go b/peer.go
index f5afb4595..e0b2f7355 100644
--- a/peer.go
+++ b/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)
}
diff --git a/xeth/config.go b/xeth/config.go
index 34aa9e32d..ad0660d75 100644
--- a/xeth/config.go
+++ b/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)
}
diff --git a/xeth/hexface.go b/xeth/hexface.go
index 21e82e37d..5ef3eaf1a 100644
--- a/xeth/hexface.go
+++ b/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 {