| 
									
										
										
										
											2014-03-20 11:20:29 +01:00
										 |  |  | package ethminer | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"bytes" | 
					
						
							| 
									
										
										
										
											2014-08-21 18:14:49 +02:00
										 |  |  | 	"sort" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-20 11:20:29 +01:00
										 |  |  | 	"github.com/ethereum/eth-go/ethchain" | 
					
						
							| 
									
										
										
										
											2014-06-26 18:45:57 +01:00
										 |  |  | 	"github.com/ethereum/eth-go/ethlog" | 
					
						
							| 
									
										
										
										
											2014-07-15 01:11:06 +01:00
										 |  |  | 	"github.com/ethereum/eth-go/ethreact" | 
					
						
							| 
									
										
										
										
											2014-03-20 11:20:29 +01:00
										 |  |  | 	"github.com/ethereum/eth-go/ethwire" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-23 12:54:10 +01:00
										 |  |  | var logger = ethlog.NewLogger("MINER") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-20 11:20:29 +01:00
										 |  |  | type Miner struct { | 
					
						
							| 
									
										
										
										
											2014-05-22 00:25:34 +02:00
										 |  |  | 	pow         ethchain.PoW | 
					
						
							|  |  |  | 	ethereum    ethchain.EthManager | 
					
						
							|  |  |  | 	coinbase    []byte | 
					
						
							| 
									
										
										
										
											2014-07-15 01:11:06 +01:00
										 |  |  | 	reactChan   chan ethreact.Event | 
					
						
							| 
									
										
										
										
											2014-05-28 12:06:09 +02:00
										 |  |  | 	txs         ethchain.Transactions | 
					
						
							| 
									
										
										
										
											2014-05-22 00:25:34 +02:00
										 |  |  | 	uncles      []*ethchain.Block | 
					
						
							|  |  |  | 	block       *ethchain.Block | 
					
						
							|  |  |  | 	powChan     chan []byte | 
					
						
							| 
									
										
										
										
											2014-07-15 01:11:06 +01:00
										 |  |  | 	powQuitChan chan ethreact.Event | 
					
						
							| 
									
										
										
										
											2014-07-21 13:26:29 +01:00
										 |  |  | 	quitChan    chan chan error | 
					
						
							| 
									
										
										
										
											2014-08-21 20:13:26 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	turbo bool | 
					
						
							| 
									
										
										
										
											2014-03-20 11:20:29 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-18 12:21:11 +02:00
										 |  |  | func (self *Miner) GetPow() ethchain.PoW { | 
					
						
							|  |  |  | 	return self.pow | 
					
						
							| 
									
										
										
										
											2014-07-18 12:01:08 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-18 12:21:11 +02:00
										 |  |  | func NewDefaultMiner(coinbase []byte, ethereum ethchain.EthManager) *Miner { | 
					
						
							| 
									
										
										
										
											2014-03-20 11:20:29 +01:00
										 |  |  | 	miner := Miner{ | 
					
						
							| 
									
										
										
										
											2014-07-15 01:12:45 +01:00
										 |  |  | 		pow:      ðchain.EasyPow{}, | 
					
						
							|  |  |  | 		ethereum: ethereum, | 
					
						
							|  |  |  | 		coinbase: coinbase, | 
					
						
							| 
									
										
										
										
											2014-03-20 11:20:29 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-18 12:21:11 +02:00
										 |  |  | 	return &miner | 
					
						
							| 
									
										
										
										
											2014-03-20 11:20:29 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2014-06-26 18:45:57 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-21 20:13:26 +02:00
										 |  |  | func (self *Miner) ToggleTurbo() { | 
					
						
							|  |  |  | 	self.turbo = !self.turbo | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	self.pow.Turbo(self.turbo) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-20 11:20:29 +01:00
										 |  |  | func (miner *Miner) Start() { | 
					
						
							| 
									
										
										
										
											2014-07-15 01:12:45 +01:00
										 |  |  | 	miner.reactChan = make(chan ethreact.Event, 1)   // This is the channel that receives 'updates' when ever a new transaction or block comes in | 
					
						
							|  |  |  | 	miner.powChan = make(chan []byte, 1)             // This is the channel that receives valid sha hashes for a given block | 
					
						
							|  |  |  | 	miner.powQuitChan = make(chan ethreact.Event, 1) // This is the channel that can exit the miner thread | 
					
						
							| 
									
										
										
										
											2014-07-21 13:26:29 +01:00
										 |  |  | 	miner.quitChan = make(chan chan error, 1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Insert initial TXs in our little miner 'pool' | 
					
						
							|  |  |  | 	miner.txs = miner.ethereum.TxPool().Flush() | 
					
						
							|  |  |  | 	miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase) | 
					
						
							| 
									
										
										
										
											2014-07-15 01:12:45 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-20 11:20:29 +01:00
										 |  |  | 	// Prepare inital block | 
					
						
							| 
									
										
										
										
											2014-05-17 14:07:52 +02:00
										 |  |  | 	//miner.ethereum.StateManager().Prepare(miner.block.State(), miner.block.State()) | 
					
						
							|  |  |  | 	go miner.listener() | 
					
						
							| 
									
										
										
										
											2014-07-15 01:12:45 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	reactor := miner.ethereum.Reactor() | 
					
						
							|  |  |  | 	reactor.Subscribe("newBlock", miner.reactChan) | 
					
						
							|  |  |  | 	reactor.Subscribe("newTx:pre", miner.reactChan) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// We need the quit chan to be a Reactor event. | 
					
						
							|  |  |  | 	// The POW search method is actually blocking and if we don't | 
					
						
							|  |  |  | 	// listen to the reactor events inside of the pow itself | 
					
						
							|  |  |  | 	// The miner overseer will never get the reactor events themselves | 
					
						
							|  |  |  | 	// Only after the miner will find the sha | 
					
						
							|  |  |  | 	reactor.Subscribe("newBlock", miner.powQuitChan) | 
					
						
							|  |  |  | 	reactor.Subscribe("newTx:pre", miner.powQuitChan) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-26 18:45:57 +01:00
										 |  |  | 	logger.Infoln("Started") | 
					
						
							| 
									
										
										
										
											2014-07-18 12:21:11 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-21 13:26:29 +01:00
										 |  |  | 	reactor.Post("miner:start", miner) | 
					
						
							| 
									
										
										
										
											2014-03-20 11:20:29 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2014-06-26 18:45:57 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-20 11:20:29 +01:00
										 |  |  | func (miner *Miner) listener() { | 
					
						
							|  |  |  | 	for { | 
					
						
							|  |  |  | 		select { | 
					
						
							| 
									
										
										
										
											2014-07-21 13:26:29 +01:00
										 |  |  | 		case status := <-miner.quitChan: | 
					
						
							| 
									
										
										
										
											2014-06-26 18:45:57 +01:00
										 |  |  | 			logger.Infoln("Stopped") | 
					
						
							| 
									
										
										
										
											2014-07-21 13:26:29 +01:00
										 |  |  | 			status <- nil | 
					
						
							|  |  |  | 			return | 
					
						
							| 
									
										
										
										
											2014-03-20 11:20:29 +01:00
										 |  |  | 		case chanMessage := <-miner.reactChan: | 
					
						
							| 
									
										
										
										
											2014-06-26 18:45:57 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-20 11:20:29 +01:00
										 |  |  | 			if block, ok := chanMessage.Resource.(*ethchain.Block); ok { | 
					
						
							| 
									
										
										
										
											2014-06-23 12:54:10 +01:00
										 |  |  | 				//logger.Infoln("Got new block via Reactor") | 
					
						
							| 
									
										
										
										
											2014-03-20 11:20:29 +01:00
										 |  |  | 				if bytes.Compare(miner.ethereum.BlockChain().CurrentBlock.Hash(), block.Hash()) == 0 { | 
					
						
							|  |  |  | 					// TODO: Perhaps continue mining to get some uncle rewards | 
					
						
							| 
									
										
										
										
											2014-06-23 12:54:10 +01:00
										 |  |  | 					//logger.Infoln("New top block found resetting state") | 
					
						
							| 
									
										
										
										
											2014-03-20 11:20:29 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 					// Filter out which Transactions we have that were not in this block | 
					
						
							|  |  |  | 					var newtxs []*ethchain.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 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// Setup a fresh state to mine on | 
					
						
							| 
									
										
										
										
											2014-05-22 17:35:26 +02:00
										 |  |  | 					//miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs) | 
					
						
							| 
									
										
										
										
											2014-03-20 11:20:29 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					if bytes.Compare(block.PrevHash, miner.ethereum.BlockChain().CurrentBlock.PrevHash) == 0 { | 
					
						
							| 
									
										
										
										
											2014-06-23 12:54:10 +01:00
										 |  |  | 						logger.Infoln("Adding uncle block") | 
					
						
							| 
									
										
										
										
											2014-03-20 11:20:29 +01:00
										 |  |  | 						miner.uncles = append(miner.uncles, block) | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if tx, ok := chanMessage.Resource.(*ethchain.Transaction); ok { | 
					
						
							|  |  |  | 				found := false | 
					
						
							|  |  |  | 				for _, ctx := range miner.txs { | 
					
						
							|  |  |  | 					if found = bytes.Compare(ctx.Hash(), tx.Hash()) == 0; found { | 
					
						
							|  |  |  | 						break | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				if found == false { | 
					
						
							| 
									
										
										
										
											2014-05-21 14:00:13 +02:00
										 |  |  | 					// Undo all previous commits | 
					
						
							| 
									
										
										
										
											2014-05-21 00:17:50 +02:00
										 |  |  | 					miner.block.Undo() | 
					
						
							| 
									
										
										
										
											2014-05-21 14:00:13 +02:00
										 |  |  | 					// Apply new transactions | 
					
						
							| 
									
										
										
										
											2014-03-20 11:20:29 +01:00
										 |  |  | 					miner.txs = append(miner.txs, tx) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		default: | 
					
						
							| 
									
										
										
										
											2014-05-21 14:00:13 +02:00
										 |  |  | 			miner.mineNewBlock() | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2014-05-21 13:04:40 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-15 01:12:45 +01:00
										 |  |  | func (miner *Miner) Stop() { | 
					
						
							| 
									
										
										
										
											2014-06-26 18:45:57 +01:00
										 |  |  | 	logger.Infoln("Stopping...") | 
					
						
							| 
									
										
										
										
											2014-07-21 19:12:04 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	miner.powQuitChan <- ethreact.Event{} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-21 13:26:29 +01:00
										 |  |  | 	status := make(chan error) | 
					
						
							|  |  |  | 	miner.quitChan <- status | 
					
						
							|  |  |  | 	<-status | 
					
						
							| 
									
										
										
										
											2014-07-15 01:12:45 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	reactor := miner.ethereum.Reactor() | 
					
						
							|  |  |  | 	reactor.Unsubscribe("newBlock", miner.powQuitChan) | 
					
						
							|  |  |  | 	reactor.Unsubscribe("newTx:pre", miner.powQuitChan) | 
					
						
							|  |  |  | 	reactor.Unsubscribe("newBlock", miner.reactChan) | 
					
						
							|  |  |  | 	reactor.Unsubscribe("newTx:pre", miner.reactChan) | 
					
						
							| 
									
										
										
										
											2014-07-01 11:55:50 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-21 13:26:29 +01:00
										 |  |  | 	reactor.Post("miner:stop", miner) | 
					
						
							| 
									
										
										
										
											2014-05-22 00:25:34 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-21 14:00:13 +02:00
										 |  |  | func (self *Miner) mineNewBlock() { | 
					
						
							|  |  |  | 	stateManager := self.ethereum.StateManager() | 
					
						
							| 
									
										
										
										
											2014-05-21 13:04:40 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-22 17:35:26 +02:00
										 |  |  | 	self.block = self.ethereum.BlockChain().NewBlock(self.coinbase) | 
					
						
							| 
									
										
										
										
											2014-03-20 11:20:29 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-21 14:00:13 +02:00
										 |  |  | 	// Apply uncles | 
					
						
							|  |  |  | 	if len(self.uncles) > 0 { | 
					
						
							|  |  |  | 		self.block.SetUncles(self.uncles) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-03-20 11:20:29 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-28 12:06:09 +02:00
										 |  |  | 	// Sort the transactions by nonce in case of odd network propagation | 
					
						
							|  |  |  | 	sort.Sort(ethchain.TxByNonce{self.txs}) | 
					
						
							| 
									
										
										
										
											2014-06-14 11:46:09 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-23 12:54:10 +01:00
										 |  |  | 	// Accumulate all valid transactions and apply them to the new state | 
					
						
							| 
									
										
										
										
											2014-06-14 11:46:09 +02:00
										 |  |  | 	// Error may be ignored. It's not important during mining | 
					
						
							| 
									
										
										
										
											2014-06-16 11:51:16 +02:00
										 |  |  | 	parent := self.ethereum.BlockChain().GetBlock(self.block.PrevHash) | 
					
						
							| 
									
										
										
										
											2014-06-16 11:14:01 +02:00
										 |  |  | 	coinbase := self.block.State().GetOrNewStateObject(self.block.Coinbase) | 
					
						
							| 
									
										
										
										
											2014-06-16 11:51:16 +02:00
										 |  |  | 	coinbase.SetGasPool(self.block.CalcGasLimit(parent)) | 
					
						
							| 
									
										
										
										
											2014-06-16 11:14:01 +02:00
										 |  |  | 	receipts, txs, unhandledTxs, err := stateManager.ProcessTransactions(coinbase, self.block.State(), self.block, self.block, self.txs) | 
					
						
							| 
									
										
										
										
											2014-06-14 11:46:09 +02:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2014-06-23 12:54:10 +01:00
										 |  |  | 		logger.Debugln(err) | 
					
						
							| 
									
										
										
										
											2014-06-14 11:46:09 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	self.txs = append(txs, unhandledTxs...) | 
					
						
							| 
									
										
										
										
											2014-07-21 12:21:34 +02:00
										 |  |  | 	self.block.SetTxHash(receipts) | 
					
						
							| 
									
										
										
										
											2014-06-14 11:46:09 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-21 14:00:13 +02:00
										 |  |  | 	// Set the transactions to the block so the new SHA3 can be calculated | 
					
						
							| 
									
										
										
										
											2014-05-22 17:35:26 +02:00
										 |  |  | 	self.block.SetReceipts(receipts, txs) | 
					
						
							| 
									
										
										
										
											2014-06-14 11:46:09 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-21 14:00:13 +02:00
										 |  |  | 	// Accumulate the rewards included for this block | 
					
						
							|  |  |  | 	stateManager.AccumelateRewards(self.block.State(), self.block) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-17 11:06:06 +02:00
										 |  |  | 	self.block.State().Update() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-25 18:43:35 +01:00
										 |  |  | 	logger.Infof("Mining on block. Includes %v transactions", len(self.txs)) | 
					
						
							| 
									
										
										
										
											2014-05-21 14:00:13 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Find a valid nonce | 
					
						
							| 
									
										
										
										
											2014-05-22 00:25:34 +02:00
										 |  |  | 	self.block.Nonce = self.pow.Search(self.block, self.powQuitChan) | 
					
						
							| 
									
										
										
										
											2014-05-21 14:00:13 +02:00
										 |  |  | 	if self.block.Nonce != nil { | 
					
						
							| 
									
										
										
										
											2014-05-30 16:57:58 +02:00
										 |  |  | 		err := self.ethereum.StateManager().Process(self.block, false) | 
					
						
							| 
									
										
										
										
											2014-05-21 14:00:13 +02:00
										 |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2014-06-23 12:54:10 +01:00
										 |  |  | 			logger.Infoln(err) | 
					
						
							| 
									
										
										
										
											2014-05-21 14:00:13 +02:00
										 |  |  | 		} else { | 
					
						
							|  |  |  | 			self.ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{self.block.Value().Val}) | 
					
						
							| 
									
										
										
										
											2014-06-23 12:54:10 +01:00
										 |  |  | 			logger.Infof("🔨  Mined block %x\n", self.block.Hash()) | 
					
						
							|  |  |  | 			logger.Infoln(self.block) | 
					
						
							| 
									
										
										
										
											2014-05-21 14:00:13 +02:00
										 |  |  | 			// Gather the new batch of transactions currently in the tx pool | 
					
						
							|  |  |  | 			self.txs = self.ethereum.TxPool().CurrentTransactions() | 
					
						
							| 
									
										
										
										
											2014-03-20 11:20:29 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |