1 // Copyright (c) 2014-2016 The btcsuite developers
2 // Use of this source code is governed by an ISC
3 // license that can be found in the LICENSE file.
11 log "github.com/sirupsen/logrus"
13 "github.com/bytom/blockchain/account"
14 "github.com/bytom/consensus/difficulty"
15 "github.com/bytom/mining"
16 "github.com/bytom/protocol"
17 "github.com/bytom/protocol/bc/types"
21 maxNonce = ^uint64(0) // 2^32 - 1
26 // CPUMiner provides facilities for solving blocks (mining) using the CPU in
27 // a concurrency-safe manner.
28 type CPUMiner struct {
31 accountManager *account.Manager
32 txPool *protocol.TxPool
37 workerWg sync.WaitGroup
38 updateNumWorkers chan struct{}
39 queryHashesPerSec chan float64
40 updateHashes chan uint64
41 speedMonitorQuit chan struct{}
45 // solveBlock attempts to find some combination of a nonce, extra nonce, and
46 // current timestamp which makes the passed block hash to a value less than the
48 func (m *CPUMiner) solveBlock(block *types.Block, ticker *time.Ticker, quit chan struct{}) bool {
49 header := &block.BlockHeader
50 seed, err := m.chain.GetSeed(header.Height, &header.PreviousBlockHash)
55 for i := uint64(0); i <= maxNonce; i++ {
60 if m.chain.Height() >= header.Height {
67 headerHash := header.Hash()
68 if difficulty.CheckProofOfWork(&headerHash, seed, header.Bits) {
75 // generateBlocks is a worker that is controlled by the miningWorkerController.
76 // It is self contained in that it creates block templates and attempts to solve
77 // them while detecting when it is performing stale work and reacting
78 // accordingly by generating a new block template. When a block is solved, it
81 // It must be run as a goroutine.
82 func (m *CPUMiner) generateBlocks(quit chan struct{}) {
83 ticker := time.NewTicker(time.Second * hashUpdateSecs)
94 block, err := mining.NewBlockTemplate(m.chain, m.txPool, m.accountManager)
96 log.Errorf("Mining: failed on create NewBlockTemplate: %v", err)
100 if m.solveBlock(block, ticker, quit) {
101 if isOrphan, err := m.chain.ProcessBlock(block); err == nil {
102 log.WithFields(log.Fields{
103 "height": block.BlockHeader.Height,
104 "isOrphan": isOrphan,
105 "tx": len(block.Transactions),
106 }).Info("Miner processed block")
108 log.WithField("height", block.BlockHeader.Height).Errorf("Miner fail on ProcessBlock %v", err)
116 // miningWorkerController launches the worker goroutines that are used to
117 // generate block templates and solve them. It also provides the ability to
118 // dynamically adjust the number of running worker goroutines.
120 // It must be run as a goroutine.
121 func (m *CPUMiner) miningWorkerController() {
122 // launchWorkers groups common code to launch a specified number of
123 // workers for generating blocks.
124 var runningWorkers []chan struct{}
125 launchWorkers := func(numWorkers uint64) {
126 for i := uint64(0); i < numWorkers; i++ {
127 quit := make(chan struct{})
128 runningWorkers = append(runningWorkers, quit)
131 go m.generateBlocks(quit)
135 // Launch the current number of workers by default.
136 runningWorkers = make([]chan struct{}, 0, m.numWorkers)
137 launchWorkers(m.numWorkers)
142 // Update the number of running workers.
143 case <-m.updateNumWorkers:
145 numRunning := uint64(len(runningWorkers))
146 if m.numWorkers == numRunning {
151 if m.numWorkers > numRunning {
152 launchWorkers(m.numWorkers - numRunning)
156 // Signal the most recently created goroutines to exit.
157 for i := numRunning - 1; i >= m.numWorkers; i-- {
158 close(runningWorkers[i])
159 runningWorkers[i] = nil
160 runningWorkers = runningWorkers[:i]
164 for _, quit := range runningWorkers {
171 // Wait until all workers shut down to stop the speed monitor since
172 // they rely on being able to send updates to it.
174 close(m.speedMonitorQuit)
178 // Start begins the CPU mining process as well as the speed monitor used to
179 // track hashing metrics. Calling this function when the CPU miner has
180 // already been started will have no effect.
182 // This function is safe for concurrent access.
183 func (m *CPUMiner) Start() {
187 // Nothing to do if the miner is already running or if running in
188 // discrete mode (using GenerateNBlocks).
189 if m.started || m.discreteMining {
193 m.quit = make(chan struct{})
194 m.speedMonitorQuit = make(chan struct{})
196 go m.miningWorkerController()
199 log.Infof("CPU miner started")
202 // Stop gracefully stops the mining process by signalling all workers, and the
203 // speed monitor to quit. Calling this function when the CPU miner has not
204 // already been started will have no effect.
206 // This function is safe for concurrent access.
207 func (m *CPUMiner) Stop() {
211 // Nothing to do if the miner is not currently running or if running in
212 // discrete mode (using GenerateNBlocks).
213 if !m.started || m.discreteMining {
220 log.Info("CPU miner stopped")
223 // IsMining returns whether or not the CPU miner has been started and is
224 // therefore currenting mining.
226 // This function is safe for concurrent access.
227 func (m *CPUMiner) IsMining() bool {
234 // SetNumWorkers sets the number of workers to create which solve blocks. Any
235 // negative values will cause a default number of workers to be used which is
236 // based on the number of processor cores in the system. A value of 0 will
237 // cause all CPU mining to be stopped.
239 // This function is safe for concurrent access.
240 func (m *CPUMiner) SetNumWorkers(numWorkers int32) {
245 // Don't lock until after the first check since Stop does its own
250 // Use default if provided value is negative.
252 m.numWorkers = defaultNumWorkers
254 m.numWorkers = uint64(numWorkers)
257 // When the miner is already running, notify the controller about the
260 m.updateNumWorkers <- struct{}{}
264 // NumWorkers returns the number of workers which are running to solve blocks.
266 // This function is safe for concurrent access.
267 func (m *CPUMiner) NumWorkers() int32 {
271 return int32(m.numWorkers)
274 // NewCPUMiner returns a new instance of a CPU miner for the provided configuration.
275 // Use Start to begin the mining process. See the documentation for CPUMiner
276 // type for more details.
277 func NewCPUMiner(c *protocol.Chain, accountManager *account.Manager, txPool *protocol.TxPool) *CPUMiner {
280 accountManager: accountManager,
282 numWorkers: defaultNumWorkers,
283 updateNumWorkers: make(chan struct{}),
284 queryHashesPerSec: make(chan float64),
285 updateHashes: make(chan uint64),