浏览代码

Basic structure miner

obscuren 10 年之前
父节点
当前提交
da2fae0e43
共有 9 个文件被更改,包括 198 次插入293 次删除
  1. 1 1
      cmd/mist/gui.go
  2. 11 8
      cmd/mist/ui_lib.go
  3. 5 5
      core/block_processor.go
  4. 10 1
      core/chain_manager.go
  5. 74 0
      miner/agent.go
  6. 30 254
      miner/miner.go
  7. 49 12
      miner/worker.go
  8. 18 11
      pow/ezp/pow.go
  9. 0 1
      xeth/types.go

+ 1 - 1
cmd/mist/gui.go

@@ -455,7 +455,7 @@ func (gui *Gui) update() {
 		case <-generalUpdateTicker.C:
 			statusText := "#" + gui.eth.ChainManager().CurrentBlock().Number().String()
 			lastBlockLabel.Set("text", statusText)
-			miningLabel.Set("text", "Mining @ "+strconv.FormatInt(gui.uiLib.miner.GetPow().GetHashrate(), 10)+"Khash")
+			miningLabel.Set("text", "Mining @ "+strconv.FormatInt(gui.uiLib.miner.HashRate(), 10)+"/Khash")
 
 			/*
 				blockLength := gui.eth.BlockPool().BlocksProcessed

+ 11 - 8
cmd/mist/ui_lib.go

@@ -209,17 +209,20 @@ func (self *UiLib) Call(params map[string]interface{}) (string, error) {
 }
 
 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
+	return 0
+	/*
+		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)
+	//self.miner.RemoveLocalTx(id)
 }
 
 func (self *UiLib) SetGasPrice(price string) {

+ 5 - 5
core/block_processor.go

@@ -7,7 +7,6 @@ import (
 	"sync"
 	"time"
 
-	"github.com/ethereum/c-ethash/go-ethash"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/crypto"
 	"github.com/ethereum/go-ethereum/ethutil"
@@ -15,7 +14,7 @@ import (
 	"github.com/ethereum/go-ethereum/logger"
 	"github.com/ethereum/go-ethereum/p2p"
 	"github.com/ethereum/go-ethereum/pow"
-	_ "github.com/ethereum/go-ethereum/pow/ezp"
+	"github.com/ethereum/go-ethereum/pow/ezp"
 	"github.com/ethereum/go-ethereum/state"
 	"gopkg.in/fatih/set.v0"
 )
@@ -65,9 +64,10 @@ type BlockProcessor struct {
 
 func NewBlockProcessor(db ethutil.Database, txpool *TxPool, chainManager *ChainManager, eventMux *event.TypeMux) *BlockProcessor {
 	sm := &BlockProcessor{
-		db:       db,
-		mem:      make(map[string]*big.Int),
-		Pow:      &ethash.Ethash{},
+		db:  db,
+		mem: make(map[string]*big.Int),
+		//Pow:      &ethash.Ethash{},
+		Pow:      ezp.New(),
 		bc:       chainManager,
 		eventMux: eventMux,
 		txpool:   txpool,

+ 10 - 1
core/chain_manager.go

@@ -16,6 +16,11 @@ import (
 
 var chainlogger = logger.NewLogger("CHAIN")
 
+type ChainEvent struct {
+	Block *types.Block
+	Td    *big.Int
+}
+
 type StateQuery interface {
 	GetAccount(addr []byte) *state.StateObject
 }
@@ -175,6 +180,9 @@ func (bc *ChainManager) NewBlock(coinbase []byte) *types.Block {
 		ethutil.BigPow(2, 32),
 		nil,
 		"")
+	block.SetUncles(nil)
+	block.SetTransactions(nil)
+	block.SetReceipts(nil)
 
 	parent := bc.currentBlock
 	if parent != nil {
@@ -385,8 +393,9 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error {
 				self.setTotalDifficulty(td)
 				self.insert(block)
 				self.transState = state.New(cblock.Root(), self.db) //state.New(cblock.Trie().Copy())
-			}
 
+				self.eventMux.Post(ChainEvent{block, td})
+			}
 		}
 		self.mu.Unlock()
 

+ 74 - 0
miner/agent.go

@@ -0,0 +1,74 @@
+package miner
+
+import (
+	"github.com/ethereum/go-ethereum/core/types"
+	"github.com/ethereum/go-ethereum/pow"
+)
+
+type CpuMiner struct {
+	c             chan *types.Block
+	quit          chan struct{}
+	quitCurrentOp chan struct{}
+	returnCh      chan<- []byte
+
+	index int
+	pow   pow.PoW
+}
+
+func NewCpuMiner(index int, pow pow.PoW) *CpuMiner {
+	miner := &CpuMiner{
+		c:             make(chan *types.Block, 1),
+		quit:          make(chan struct{}),
+		quitCurrentOp: make(chan struct{}, 1),
+		pow:           pow,
+		index:         index,
+	}
+	go miner.update()
+
+	return miner
+}
+
+func (self *CpuMiner) Work() chan<- *types.Block   { return self.c }
+func (self *CpuMiner) Pow() pow.PoW                { return self.pow }
+func (self *CpuMiner) SetNonceCh(ch chan<- []byte) { self.returnCh = ch }
+
+func (self *CpuMiner) Stop() {
+	close(self.quit)
+	close(self.quitCurrentOp)
+}
+
+func (self *CpuMiner) update() {
+out:
+	for {
+		select {
+		case block := <-self.c:
+			minerlogger.Infof("miner[%d] got block\n", self.index)
+			// make sure it's open
+			self.quitCurrentOp <- struct{}{}
+
+			go self.mine(block)
+		case <-self.quit:
+			break out
+		}
+	}
+
+done:
+	// Empty channel
+	for {
+		select {
+		case <-self.c:
+		default:
+			close(self.c)
+
+			break done
+		}
+	}
+}
+
+func (self *CpuMiner) mine(block *types.Block) {
+	minerlogger.Infof("started agent[%d]. mining...\n", self.index)
+	nonce := self.pow.Search(block, self.quitCurrentOp)
+	if nonce != nil {
+		self.returnCh <- nonce
+	}
+}

+ 30 - 254
miner/miner.go

@@ -1,291 +1,67 @@
-/*
-	This file is part of go-ethereum
-
-	go-ethereum is free software: you can redistribute it and/or modify
-	it under the terms of the GNU Lesser General Public License as published by
-	the Free Software Foundation, either version 3 of the License, or
-	(at your option) any later version.
-
-	go-ethereum is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU Lesser General Public License
-	along with go-ethereum.  If not, see <http://www.gnu.org/licenses/>.
-*/
-/**
- * @authors
- * 	Jeffrey Wilcke <i@jev.io>
- * @date 2014
- *
- */
-
 package miner
 
 import (
-	"fmt"
 	"math/big"
-	"sort"
 
-	"github.com/ethereum/c-ethash/go-ethash"
-	"github.com/ethereum/go-ethereum/core"
-	"github.com/ethereum/go-ethereum/core/types"
-	"github.com/ethereum/go-ethereum/crypto"
 	"github.com/ethereum/go-ethereum/eth"
-	"github.com/ethereum/go-ethereum/ethutil"
-	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/logger"
-	"github.com/ethereum/go-ethereum/pow"
-	"github.com/ethereum/go-ethereum/state"
+	"github.com/ethereum/go-ethereum/pow/ezp"
 )
 
-var dx = []byte{0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42}
-var dy = []byte{0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43}
-
-const epochLen = uint64(1000)
-
-func getSeed(chainMan *core.ChainManager, block *types.Block) (x []byte, y []byte) {
-	if block.Number().Uint64() == 0 {
-		return dx, dy
-	} else if block.Number().Uint64()%epochLen == 0 {
-		x, y = getSeed(chainMan, chainMan.GetBlock(block.ParentHash()))
-		if (block.Number().Uint64()/epochLen)%2 > 0 {
-			y = crypto.Sha3(append(y, block.ParentHash()...))
-		} else {
-			x = crypto.Sha3(append(x, block.ParentHash()...))
-		}
-		return x, y
-	} else {
-		return getSeed(chainMan, chainMan.GetBlock(block.ParentHash()))
-	}
-}
-
-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) *types.Transaction {
-	return nil
-}
-
 var minerlogger = logger.NewLogger("MINER")
 
 type Miner struct {
-	eth    *eth.Ethereum
-	events event.Subscription
-
-	uncles    []*types.Header
-	localTxs  map[int]*LocalTx
-	localTxId int
-
-	pow       pow.PoW
-	quitCh    chan struct{}
-	powQuitCh chan struct{}
-
-	Coinbase []byte
-
-	mining bool
+	worker *worker
 
 	MinAcceptedGasPrice *big.Int
 	Extra               string
-}
-
-func New(coinbase []byte, eth *eth.Ethereum) *Miner {
-	return &Miner{
-		eth:                 eth,
-		powQuitCh:           make(chan struct{}),
-		mining:              false,
-		localTxs:            make(map[int]*LocalTx),
-		MinAcceptedGasPrice: big.NewInt(10000000000000),
-		Coinbase:            coinbase,
-	}
-}
-
-func (self *Miner) GetPow() pow.PoW {
-	return self.pow
-}
-
-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
+	coinbase []byte
+	mining   bool
 }
 
-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)
+func New(coinbase []byte, eth *eth.Ethereum) *Miner {
+	miner := &Miner{
+		coinbase: coinbase,
+		worker:   newWorker(coinbase, eth),
 	}
-	self.eth.EventMux().Post(&LocalTx{})
-
-	delete(self.localTxs, id)
-}
 
-func (self *Miner) Start() {
-	if self.mining {
-		return
+	for i := 0; i < 4; i++ {
+		miner.worker.register(NewCpuMiner(i, ezp.New()))
 	}
 
-	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(core.NewBlockEvent{}, core.TxPreEvent{}, &LocalTx{})
-
-	go self.update()
-	go self.mine()
-}
-
-func (self *Miner) Stop() {
-	if !self.mining {
-		return
-	}
-
-	self.mining = false
-
-	minerlogger.Infoln("Stopping mining operations")
-
-	self.events.Unsubscribe()
-
-	close(self.quitCh)
-	close(self.powQuitCh)
+	return miner
 }
 
 func (self *Miner) Mining() bool {
 	return self.mining
 }
 
-func (self *Miner) update() {
-out:
-	for {
-		select {
-		case event := <-self.events.Chan():
-			switch event := event.(type) {
-			case core.NewBlockEvent:
-				block := event.Block
-				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 core.TxPreEvent, *LocalTx:
-				self.reset()
-				go self.mine()
-			}
-		case <-self.quitCh:
-			break out
-		}
-	}
-}
-
-func (self *Miner) reset() {
-	close(self.powQuitCh)
-	self.powQuitCh = make(chan struct{})
-}
-
-func (self *Miner) mine() {
-	var (
-		blockProcessor = self.eth.BlockProcessor()
-		chainMan       = self.eth.ChainManager()
-		block          = chainMan.NewBlock(self.Coinbase)
-		state          = state.New(block.Root(), self.eth.Db())
-	)
-	block.Header().Extra = self.Extra
-
-	// Apply uncles
-	block.SetUncles(self.uncles)
-
-	parent := chainMan.GetBlock(block.ParentHash())
-	coinbase := state.GetOrNewStateObject(block.Coinbase())
-	coinbase.SetGasPool(core.CalcGasLimit(parent, block))
-
-	transactions := self.finiliseTxs()
-
-	// Accumulate all valid transactions and apply them to the new state
-	// Error may be ignored. It's not important during mining
-	receipts, txs, _, erroneous, err := blockProcessor.ApplyTransactions(coinbase, state, block, transactions, true)
-	if err != nil {
-		minerlogger.Debugln(err)
-	}
-	self.eth.TxPool().RemoveSet(erroneous)
-
-	block.SetTransactions(txs)
-	block.SetReceipts(receipts)
-
-	// Accumulate the rewards included for this block
-	blockProcessor.AccumulateRewards(state, block, parent)
-
-	state.Update(ethutil.Big0)
-	block.SetRoot(state.Root())
-
-	minerlogger.Infof("Mining on block. Includes %v transactions", len(transactions))
-
-	x, _ := getSeed(chainMan, block)
-	self.pow, err = ethash.New(x, block)
-	if err != nil {
-		fmt.Println("miner gave back err", err)
-		return
-	}
+func (self *Miner) Start() {
+	self.worker.start()
 
-	// Find a valid nonce
-	nonce := self.pow.Search(block, self.powQuitCh)
-	if nonce != nil {
-		block.Header().Nonce = nonce
-		err := chainMan.InsertChain(types.Blocks{block})
-		if err != nil {
-			minerlogger.Infoln(err)
-		} else {
-			self.eth.EventMux().Post(core.NewMinedBlockEvent{block})
+	self.worker.commitNewWork()
 
-			minerlogger.Infof("🔨  Mined block %x\n", block.Hash())
-			minerlogger.Infoln(block)
+	/*
+		timer := time.NewTicker(time.Second)
+		for {
+			select {
+			case <-timer.C:
+				fmt.Printf("%d workers. %d/Khash\n", len(self.worker.agents), self.HashRate())
+			}
 		}
-
-		go self.mine()
-	}
+	*/
 }
 
-func (self *Miner) finiliseTxs() types.Transactions {
-	// Sort the transactions by nonce in case of odd network propagation
-	actualSize := len(self.localTxs) // See copy below
-	txs := make(types.Transactions, actualSize+self.eth.TxPool().Size())
-
-	state := self.eth.ChainManager().TransState()
-	// XXX This has to change. Coinbase is, for new, same as key.
-	key := self.eth.KeyManager()
-	for i, ltx := range self.localTxs {
-		tx := types.NewTransactionMessage(ltx.To, ethutil.Big(ltx.Value), ethutil.Big(ltx.Gas), ethutil.Big(ltx.GasPrice), ltx.Data)
-		tx.SetNonce(state.GetNonce(self.Coinbase))
-		state.SetNonce(self.Coinbase, tx.Nonce()+1)
-
-		tx.Sign(key.PrivateKey())
-
-		txs[i] = tx
-	}
+func (self *Miner) Stop() {
+	self.worker.stop()
+}
 
-	// Faster than append
-	for _, tx := range self.eth.TxPool().GetTransactions() {
-		if tx.GasPrice().Cmp(self.MinAcceptedGasPrice) >= 0 {
-			txs[actualSize] = tx
-			actualSize++
-		}
+func (self *Miner) HashRate() int64 {
+	var tot int64
+	for _, agent := range self.worker.agents {
+		tot += agent.Pow().GetHashrate()
 	}
 
-	newTransactions := make(types.Transactions, actualSize)
-	copy(newTransactions, txs[:actualSize])
-	sort.Sort(types.TxByNonce{newTransactions})
-
-	return newTransactions
+	return tot
 }

+ 49 - 12
miner/worker.go

@@ -42,11 +42,15 @@ func env(block *types.Block, eth *eth.Ethereum) *environment {
 }
 
 type Agent interface {
-	Comms() chan<- *types.Block
+	Work() chan<- *types.Block
+	SetNonceCh(chan<- []byte)
+	Stop()
+	Pow() pow.PoW
 }
 
 type worker struct {
-	agents []chan<- *types.Block
+	agents []Agent
+	recv   chan []byte
 	mux    *event.TypeMux
 	quit   chan struct{}
 	pow    pow.PoW
@@ -59,24 +63,44 @@ type worker struct {
 	current *environment
 }
 
-func (self *worker) register(agent chan<- *types.Block) {
+func newWorker(coinbase []byte, eth *eth.Ethereum) *worker {
+	return &worker{
+		eth:      eth,
+		mux:      eth.EventMux(),
+		recv:     make(chan []byte),
+		chain:    eth.ChainManager(),
+		proc:     eth.BlockProcessor(),
+		coinbase: coinbase,
+	}
+}
+
+func (self *worker) start() {
+	go self.update()
+	go self.wait()
+}
+
+func (self *worker) stop() {
+	close(self.quit)
+}
+
+func (self *worker) register(agent Agent) {
 	self.agents = append(self.agents, agent)
+	agent.SetNonceCh(self.recv)
 }
 
 func (self *worker) update() {
-	events := self.mux.Subscribe(core.NewBlockEvent{}, core.TxPreEvent{}, &LocalTx{})
+	events := self.mux.Subscribe(core.ChainEvent{}, core.TxPreEvent{})
 
 out:
 	for {
 		select {
 		case event := <-events.Chan():
 			switch event := event.(type) {
-			case core.NewBlockEvent:
-				if self.eth.ChainManager().HasBlock(event.Block.Hash()) {
-				}
+			case core.ChainEvent:
+				self.commitNewWork()
 			case core.TxPreEvent:
 				if err := self.commitTransaction(event.Tx); err != nil {
-					self.commit()
+					self.push()
 				}
 			}
 		case <-self.quit:
@@ -85,12 +109,24 @@ out:
 	}
 }
 
-func (self *worker) commit() {
+func (self *worker) wait() {
+	for {
+		for nonce := range self.recv {
+			self.current.block.Header().Nonce = nonce
+			fmt.Println(self.current.block)
+
+			self.chain.InsertChain(types.Blocks{self.current.block})
+			break
+		}
+	}
+}
+
+func (self *worker) push() {
 	self.current.state.Update(ethutil.Big0)
 	self.current.block.SetRoot(self.current.state.Root())
 
 	for _, agent := range self.agents {
-		agent <- self.current.block
+		agent.Work() <- self.current.block
 	}
 }
 
@@ -110,7 +146,8 @@ func (self *worker) commitNewWork() {
 		case core.IsNonceErr(err):
 			remove = append(remove, tx)
 		case core.IsGasLimitErr(err):
-			// ignore
+			// Break on gas limit
+			break
 		default:
 			minerlogger.Infoln(err)
 			remove = append(remove, tx)
@@ -120,7 +157,7 @@ func (self *worker) commitNewWork() {
 
 	self.current.coinbase.AddAmount(core.BlockReward)
 
-	self.commit()
+	self.push()
 }
 
 var (

+ 18 - 11
pow/ezp/pow.go

@@ -21,7 +21,7 @@ type EasyPow struct {
 }
 
 func New() *EasyPow {
-	return &EasyPow{turbo: false}
+	return &EasyPow{turbo: true}
 }
 
 func (pow *EasyPow) GetHashrate() int64 {
@@ -36,26 +36,33 @@ func (pow *EasyPow) Search(block pow.Block, stop <-chan struct{}) []byte {
 	r := rand.New(rand.NewSource(time.Now().UnixNano()))
 	hash := block.HashNoNonce()
 	diff := block.Difficulty()
-	i := int64(0)
+	//i := int64(0)
+	// TODO fix offset
+	i := rand.Int63()
+	starti := i
 	start := time.Now().UnixNano()
-	t := time.Now()
+
+	// Make sure stop is empty
+empty:
+	for {
+		select {
+		case <-stop:
+		default:
+			break empty
+		}
+	}
 
 	for {
 		select {
 		case <-stop:
-			powlogger.Infoln("Breaking from mining")
 			pow.HashRate = 0
 			return nil
 		default:
 			i++
 
-			if time.Since(t) > (1 * time.Second) {
-				elapsed := time.Now().UnixNano() - start
-				hashes := ((float64(1e9) / float64(elapsed)) * float64(i)) / 1000
-				pow.HashRate = int64(hashes)
-
-				t = time.Now()
-			}
+			elapsed := time.Now().UnixNano() - start
+			hashes := ((float64(1e9) / float64(elapsed)) * float64(i-starti)) / 1000
+			pow.HashRate = int64(hashes)
 
 			sha := crypto.Sha3(big.NewInt(r.Int63()).Bytes())
 			if verify(hash, diff, sha) {

+ 0 - 1
xeth/types.go

@@ -60,7 +60,6 @@ func (self *Object) Storage() (storage map[string]string) {
 		rlp.Decode(bytes.NewReader(it.Value), &data)
 		storage[toHex(it.Key)] = toHex(data)
 	}
-	self.StateObject.Trie().PrintRoot()
 
 	return
 }