| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // Copyright 2015 The go-ethereum Authors | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // This file is part of the go-ethereum library. | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // | 
					
						
							| 
									
										
										
										
											2015-07-23 18:35:11 +02:00
										 |  |  | // The go-ethereum library is free software: you can redistribute it and/or modify | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // 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. | 
					
						
							|  |  |  | // | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // The go-ethereum library is distributed in the hope that it will be useful, | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // GNU Lesser General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU Lesser General Public License | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-23 11:21:41 +01:00
										 |  |  | package miner | 
					
						
							| 
									
										
										
										
											2015-03-23 09:35:42 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2015-08-26 12:46:50 +02:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2015-04-20 00:41:50 +02:00
										 |  |  | 	"math/big" | 
					
						
							| 
									
										
										
										
											2015-07-11 20:45:59 +02:00
										 |  |  | 	"sync" | 
					
						
							| 
									
										
										
										
											2015-10-31 02:18:41 +01:00
										 |  |  | 	"sync/atomic" | 
					
						
							| 
									
										
										
										
											2015-07-11 20:45:59 +02:00
										 |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2015-04-19 17:42:21 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-23 09:35:42 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/common" | 
					
						
							| 
									
										
										
										
											2017-04-05 01:16:29 +03:00
										 |  |  | 	"github.com/ethereum/go-ethereum/consensus" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/consensus/ethash" | 
					
						
							| 
									
										
										
										
											2017-01-13 00:37:23 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/core/types" | 
					
						
							| 
									
										
										
										
											2017-02-22 14:10:07 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/log" | 
					
						
							| 
									
										
										
										
											2015-03-23 09:35:42 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-06 11:58:14 +02:00
										 |  |  | type hashrate struct { | 
					
						
							|  |  |  | 	ping time.Time | 
					
						
							|  |  |  | 	rate uint64 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-23 11:14:42 +01:00
										 |  |  | type RemoteAgent struct { | 
					
						
							| 
									
										
										
										
											2015-07-11 20:45:59 +02:00
										 |  |  | 	mu sync.Mutex | 
					
						
							| 
									
										
										
										
											2015-03-23 09:35:42 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-13 13:42:33 +02:00
										 |  |  | 	quitCh   chan struct{} | 
					
						
							| 
									
										
										
										
											2015-07-11 20:45:59 +02:00
										 |  |  | 	workCh   chan *Work | 
					
						
							|  |  |  | 	returnCh chan<- *Result | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-05 01:16:29 +03:00
										 |  |  | 	chain       consensus.ChainReader | 
					
						
							|  |  |  | 	engine      consensus.Engine | 
					
						
							| 
									
										
										
										
											2015-07-11 20:45:59 +02:00
										 |  |  | 	currentWork *Work | 
					
						
							|  |  |  | 	work        map[common.Hash]*Work | 
					
						
							| 
									
										
										
										
											2015-08-06 11:58:14 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	hashrateMu sync.RWMutex | 
					
						
							|  |  |  | 	hashrate   map[common.Hash]hashrate | 
					
						
							| 
									
										
										
										
											2015-10-31 02:18:41 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	running int32 // running indicates whether the agent is active. Call atomically | 
					
						
							| 
									
										
										
										
											2015-03-23 09:35:42 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-05 01:16:29 +03:00
										 |  |  | func NewRemoteAgent(chain consensus.ChainReader, engine consensus.Engine) *RemoteAgent { | 
					
						
							| 
									
										
										
										
											2015-10-29 13:28:00 +01:00
										 |  |  | 	return &RemoteAgent{ | 
					
						
							| 
									
										
										
										
											2017-04-05 01:16:29 +03:00
										 |  |  | 		chain:    chain, | 
					
						
							|  |  |  | 		engine:   engine, | 
					
						
							| 
									
										
										
										
											2015-10-29 13:28:00 +01:00
										 |  |  | 		work:     make(map[common.Hash]*Work), | 
					
						
							|  |  |  | 		hashrate: make(map[common.Hash]hashrate), | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-03-23 09:35:42 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-06 11:58:14 +02:00
										 |  |  | func (a *RemoteAgent) SubmitHashrate(id common.Hash, rate uint64) { | 
					
						
							|  |  |  | 	a.hashrateMu.Lock() | 
					
						
							|  |  |  | 	defer a.hashrateMu.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	a.hashrate[id] = hashrate{time.Now(), rate} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-11 20:45:59 +02:00
										 |  |  | func (a *RemoteAgent) Work() chan<- *Work { | 
					
						
							| 
									
										
										
										
											2015-03-23 09:35:42 +01:00
										 |  |  | 	return a.workCh | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-11 20:45:59 +02:00
										 |  |  | func (a *RemoteAgent) SetReturnCh(returnCh chan<- *Result) { | 
					
						
							| 
									
										
										
										
											2015-03-23 09:35:42 +01:00
										 |  |  | 	a.returnCh = returnCh | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-23 11:14:42 +01:00
										 |  |  | func (a *RemoteAgent) Start() { | 
					
						
							| 
									
										
										
										
											2015-10-31 02:18:41 +01:00
										 |  |  | 	if !atomic.CompareAndSwapInt32(&a.running, 0, 1) { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-12-13 13:42:33 +02:00
										 |  |  | 	a.quitCh = make(chan struct{}) | 
					
						
							| 
									
										
										
										
											2015-07-11 20:45:59 +02:00
										 |  |  | 	a.workCh = make(chan *Work, 1) | 
					
						
							| 
									
										
										
										
											2016-12-13 13:42:33 +02:00
										 |  |  | 	go a.loop(a.workCh, a.quitCh) | 
					
						
							| 
									
										
										
										
											2015-03-23 09:35:42 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-23 11:14:42 +01:00
										 |  |  | func (a *RemoteAgent) Stop() { | 
					
						
							| 
									
										
										
										
											2015-10-31 02:18:41 +01:00
										 |  |  | 	if !atomic.CompareAndSwapInt32(&a.running, 1, 0) { | 
					
						
							|  |  |  | 		return | 
					
						
							| 
									
										
										
										
											2015-10-29 13:28:00 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-12-13 13:42:33 +02:00
										 |  |  | 	close(a.quitCh) | 
					
						
							| 
									
										
										
										
											2015-10-31 02:18:41 +01:00
										 |  |  | 	close(a.workCh) | 
					
						
							| 
									
										
										
										
											2015-03-23 09:35:42 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-06 11:58:14 +02:00
										 |  |  | // GetHashRate returns the accumulated hashrate of all identifier combined | 
					
						
							|  |  |  | func (a *RemoteAgent) GetHashRate() (tot int64) { | 
					
						
							|  |  |  | 	a.hashrateMu.RLock() | 
					
						
							|  |  |  | 	defer a.hashrateMu.RUnlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// this could overflow | 
					
						
							|  |  |  | 	for _, hashrate := range a.hashrate { | 
					
						
							|  |  |  | 		tot += int64(hashrate.rate) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-03-23 09:35:42 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-26 12:46:50 +02:00
										 |  |  | func (a *RemoteAgent) GetWork() ([3]string, error) { | 
					
						
							| 
									
										
										
										
											2015-07-11 20:45:59 +02:00
										 |  |  | 	a.mu.Lock() | 
					
						
							|  |  |  | 	defer a.mu.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-23 09:35:42 +01:00
										 |  |  | 	var res [3]string | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-11 20:45:59 +02:00
										 |  |  | 	if a.currentWork != nil { | 
					
						
							|  |  |  | 		block := a.currentWork.Block | 
					
						
							| 
									
										
										
										
											2015-04-19 21:58:58 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-11 20:45:59 +02:00
										 |  |  | 		res[0] = block.HashNoNonce().Hex() | 
					
						
							| 
									
										
										
										
											2017-04-05 01:16:29 +03:00
										 |  |  | 		seedHash := ethash.SeedHash(block.NumberU64()) | 
					
						
							| 
									
										
										
										
											2015-05-11 10:11:33 -04:00
										 |  |  | 		res[1] = common.BytesToHash(seedHash).Hex() | 
					
						
							| 
									
										
										
										
											2015-04-20 00:41:50 +02:00
										 |  |  | 		// Calculate the "target" to be returned to the external miner | 
					
						
							|  |  |  | 		n := big.NewInt(1) | 
					
						
							|  |  |  | 		n.Lsh(n, 255) | 
					
						
							| 
									
										
										
										
											2015-07-11 20:45:59 +02:00
										 |  |  | 		n.Div(n, block.Difficulty()) | 
					
						
							| 
									
										
										
										
											2015-04-20 00:41:50 +02:00
										 |  |  | 		n.Lsh(n, 1) | 
					
						
							| 
									
										
										
										
											2015-05-11 10:11:33 -04:00
										 |  |  | 		res[2] = common.BytesToHash(n.Bytes()).Hex() | 
					
						
							| 
									
										
										
										
											2015-07-11 20:45:59 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		a.work[block.HashNoNonce()] = a.currentWork | 
					
						
							| 
									
										
										
										
											2015-08-26 12:46:50 +02:00
										 |  |  | 		return res, nil | 
					
						
							| 
									
										
										
										
											2015-03-23 09:35:42 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-08-28 03:42:01 +02:00
										 |  |  | 	return res, errors.New("No work available yet, don't panic.") | 
					
						
							| 
									
										
										
										
											2015-03-23 09:35:42 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-05 01:16:29 +03:00
										 |  |  | // SubmitWork tries to inject a pow solution into the remote agent, returning | 
					
						
							|  |  |  | // whether the solution was accepted or not (not can be both a bad pow as well as | 
					
						
							| 
									
										
										
										
											2016-12-20 03:14:36 +02:00
										 |  |  | // any other error, like no work pending). | 
					
						
							| 
									
										
										
										
											2017-01-13 00:37:23 +01:00
										 |  |  | func (a *RemoteAgent) SubmitWork(nonce types.BlockNonce, mixDigest, hash common.Hash) bool { | 
					
						
							| 
									
										
										
										
											2015-07-11 20:45:59 +02:00
										 |  |  | 	a.mu.Lock() | 
					
						
							|  |  |  | 	defer a.mu.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Make sure the work submitted is present | 
					
						
							| 
									
										
										
										
											2016-12-20 03:14:36 +02:00
										 |  |  | 	work := a.work[hash] | 
					
						
							|  |  |  | 	if work == nil { | 
					
						
							| 
									
										
										
										
											2017-04-05 01:16:29 +03:00
										 |  |  | 		log.Info("Work submitted but none pending", "hash", hash) | 
					
						
							| 
									
										
										
										
											2016-12-20 03:14:36 +02:00
										 |  |  | 		return false | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-04-05 01:16:29 +03:00
										 |  |  | 	// Make sure the Engine solutions is indeed valid | 
					
						
							|  |  |  | 	result := work.Block.Header() | 
					
						
							|  |  |  | 	result.Nonce = nonce | 
					
						
							|  |  |  | 	result.MixDigest = mixDigest | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err := a.engine.VerifySeal(a.chain, result); err != nil { | 
					
						
							|  |  |  | 		log.Warn("Invalid proof-of-work submitted", "hash", hash, "err", err) | 
					
						
							| 
									
										
										
										
											2016-12-20 03:14:36 +02:00
										 |  |  | 		return false | 
					
						
							| 
									
										
										
										
											2015-03-23 09:35:42 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-04-05 01:16:29 +03:00
										 |  |  | 	block := work.Block.WithSeal(result) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-20 03:14:36 +02:00
										 |  |  | 	// Solutions seems to be valid, return to the miner and notify acceptance | 
					
						
							|  |  |  | 	a.returnCh <- &Result{work, block} | 
					
						
							|  |  |  | 	delete(a.work, hash) | 
					
						
							| 
									
										
										
										
											2015-03-23 09:35:42 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-20 03:14:36 +02:00
										 |  |  | 	return true | 
					
						
							| 
									
										
										
										
											2015-03-23 09:35:42 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-07-11 20:45:59 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-13 13:42:33 +02:00
										 |  |  | // loop monitors mining events on the work and quit channels, updating the internal | 
					
						
							| 
									
										
										
										
											2017-10-12 10:19:23 +08:00
										 |  |  | // state of the remote miner until a termination is requested. | 
					
						
							| 
									
										
										
										
											2016-12-13 13:42:33 +02:00
										 |  |  | // | 
					
						
							|  |  |  | // Note, the reason the work and quit channels are passed as parameters is because | 
					
						
							|  |  |  | // RemoteAgent.Start() constantly recreates these channels, so the loop code cannot | 
					
						
							|  |  |  | // assume data stability in these member fields. | 
					
						
							|  |  |  | func (a *RemoteAgent) loop(workCh chan *Work, quitCh chan struct{}) { | 
					
						
							| 
									
										
										
										
											2017-08-06 19:40:34 +03:00
										 |  |  | 	ticker := time.NewTicker(5 * time.Second) | 
					
						
							|  |  |  | 	defer ticker.Stop() | 
					
						
							| 
									
										
										
										
											2015-07-11 20:45:59 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for { | 
					
						
							|  |  |  | 		select { | 
					
						
							| 
									
										
										
										
											2016-12-13 13:42:33 +02:00
										 |  |  | 		case <-quitCh: | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		case work := <-workCh: | 
					
						
							| 
									
										
										
										
											2015-07-11 20:45:59 +02:00
										 |  |  | 			a.mu.Lock() | 
					
						
							|  |  |  | 			a.currentWork = work | 
					
						
							|  |  |  | 			a.mu.Unlock() | 
					
						
							| 
									
										
										
										
											2017-08-06 19:40:34 +03:00
										 |  |  | 		case <-ticker.C: | 
					
						
							| 
									
										
										
										
											2015-07-11 20:45:59 +02:00
										 |  |  | 			// cleanup | 
					
						
							|  |  |  | 			a.mu.Lock() | 
					
						
							|  |  |  | 			for hash, work := range a.work { | 
					
						
							|  |  |  | 				if time.Since(work.createdAt) > 7*(12*time.Second) { | 
					
						
							|  |  |  | 					delete(a.work, hash) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			a.mu.Unlock() | 
					
						
							| 
									
										
										
										
											2015-08-06 11:58:14 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			a.hashrateMu.Lock() | 
					
						
							|  |  |  | 			for id, hashrate := range a.hashrate { | 
					
						
							|  |  |  | 				if time.Since(hashrate.ping) > 10*time.Second { | 
					
						
							|  |  |  | 					delete(a.hashrate, id) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			a.hashrateMu.Unlock() | 
					
						
							| 
									
										
										
										
											2015-07-11 20:45:59 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |