1 package cpuminer
2 3 import (
4 "errors"
5 "fmt"
6 "math/rand"
7 "runtime"
8 "sync"
9 "time"
10 11 "go.uber.org/atomic"
12 13 blockchain "github.com/p9c/p9/pkg/chain"
14 "github.com/p9c/p9/pkg/chain/config/netparams"
15 "github.com/p9c/p9/pkg/chain/fork"
16 chainhash "github.com/p9c/p9/pkg/chain/hash"
17 "github.com/p9c/p9/pkg/chain/mining"
18 "github.com/p9c/p9/pkg/chain/wire"
19 log "github.com/p9c/p9/pkg/logi"
20 "github.com/p9c/p9/pkg/util"
21 )
22 23 var tn = time.Now()
24 25 // CPUMiner provides facilities for solving blocks (mining) using the CPU in a
26 // concurrency-safe manner. It consists of two main goroutines -- a speed
27 // monitor and a controller for worker goroutines which generate and solve
28 // blocks. The number of goroutines can be set via the SetMaxGoRoutines
29 // function, but the default is based on the number of processor cores in the
30 // system which is typically sufficient.
31 type CPUMiner struct {
32 sync.Mutex
33 b *blockchain.BlockChain
34 g *mining.BlkTmplGenerator
35 cfg Config
36 numWorkers uint32
37 started bool
38 discreteMining bool
39 submitBlockLock sync.Mutex
40 wg sync.WaitGroup
41 workerWg sync.WaitGroup
42 updateNumWorkers qu.C
43 queryHashesPerSec chan float64
44 updateHashes chan uint64
45 speedMonitorQuit qu.C
46 quit qu.C
47 rotator atomic.Uint64
48 }
49 50 // Config is a descriptor containing the cpu miner configuration.
51 type Config struct {
52 // Blockchain gives access for the miner to information about the chain
53 //
54 Blockchain *blockchain.BlockChain
55 // ChainParams identifies which chain parameters the cpu miner is associated
56 // with.
57 ChainParams *netparams.Params
58 // BlockTemplateGenerator identifies the instance to use in order to
59 // generate block templates that the miner will attempt to solve.
60 BlockTemplateGenerator *mining.BlkTmplGenerator
61 // MiningAddrs is a list of payment addresses to use for the generated
62 // blocks. Each generated block will randomly choose one of them.
63 MiningAddrs []util.Address
64 // ProcessBlock defines the function to call with any solved blocks. It
65 // typically must run the provided block through the same set of rules and
66 // handling as any other block coming from the network.
67 ProcessBlock func(*util.Block, blockchain.BehaviorFlags) (bool, error)
68 // ConnectedCount defines the function to use to obtain how many other peers
69 // the server is connected to. This is used by the automatic persistent
70 // mining routine to determine whether or it should attempt mining. This is
71 // useful because there is no point in mining when not connected to any
72 // peers since there would no be anyone to send any found blocks to.
73 ConnectedCount func() int32
74 // IsCurrent defines the function to use to obtain whether or not the block
75 // chain is current. This is used by the automatic persistent mining
76 // routine to determine whether or it should attempt mining. This is useful
77 // because there is no point in mining if the chain is not current since any
78 // solved blocks would be on a side chain and and up orphaned anyways.
79 IsCurrent func() bool
80 // Algo is the name of the type of PoW used for the block header.
81 Algo string
82 // NumThreads is the number of threads set in the configuration for the
83 // CPUMiner
84 NumThreads uint32
85 // Solo sets whether the miner will run when not connected
86 Solo bool
87 }
88 89 const (
90 // // maxNonce is the maximum value a nonce can be in a block header.
91 // maxNonce = 2 ^ 32 - 1
92 // maxExtraNonce is the maximum value an extra nonce used in a coinbase
93 // transaction can be.
94 maxExtraNonce = 2 ^ 64 - 1
95 // hpsUpdateSecs is the number of seconds to wait in between each update to the hashes per second monitor.
96 hpsUpdateSecs = 1
97 // hashUpdateSec is the number of seconds each worker waits in between
98 // notifying the speed monitor with how many hashes have been completed
99 // while they are actively searching for a solution. This is done to reduce
100 // the amount of syncs between the workers that must be done to keep track
101 // of the hashes per second.
102 hashUpdateSecs = 9
103 )
104 105 var (
106 // defaultNumWorkers is the default number of workers to use for mining and
107 // is based on the number of processor cores. This helps ensure the system
108 // stays reasonably responsive under heavy load.
109 defaultNumWorkers = uint32(runtime.NumCPU())
110 )
111 112 // GenerateNBlocks generates the requested number of blocks. It is self
113 // contained in that it creates block templates and attempts to solve them
114 // while detecting when it is performing stale work and reacting accordingly by
115 // generating a new block template. When a block is solved, it is submitted.
116 // The function returns a list of the hashes of generated blocks.
117 func (m *CPUMiner) GenerateNBlocks(workerNumber uint32, n uint32,
118 algo string) ([]*chainhash.Hash, error) {
119 m.Lock()
120 L.Warnf("generating %s blocks...", m.cfg.Algo)
121 // Respond with an error if server is already mining.
122 if m.started || m.discreteMining {
123 m.Unlock()
124 return nil, errors.New("server is already CPU mining; call " +
125 "`setgenerate 0` before calling discrete `generate` commands")
126 }
127 m.started = true
128 m.discreteMining = true
129 m.speedMonitorQuit = qu.Ter()
130 m.wg.Add(1)
131 go m.speedMonitor()
132 m.Unlock()
133 L.Warnf("generating %d blocks", n)
134 i := uint32(0)
135 blockHashes := make([]*chainhash.Hash, n)
136 // Start a ticker which is used to signal checks for stale work and updates to the speed monitor.
137 ticker := time.NewTicker(time.Second * hashUpdateSecs)
138 defer ticker.Stop()
139 for {
140 // Read updateNumWorkers in case someone tries a `setgenerate` while
141 // we're generating. We can ignore it as the `generate` RPC call only
142 // uses 1 worker.
143 select {
144 case <-m.updateNumWorkers:
145 default:
146 }
147 // Grab the lock used for block submission, since the current block will
148 // be changing and this would otherwise end up building a new block
149 // template on a block that is in the process of becoming stale.
150 m.submitBlockLock.Lock()
151 curHeight := m.g.BestSnapshot().Height
152 // Choose a payment address at random.
153 rand.Seed(time.Now().UnixNano())
154 payToAddr := m.cfg.MiningAddrs[rand.Intn(len(m.cfg.MiningAddrs))]
155 // Create a new block template using the available transactions in the
156 // memory pool as a source of transactions to potentially include in the
157 // block.
158 template, e := m.g.NewBlockTemplate(workerNumber, payToAddr, algo)
159 m.submitBlockLock.Unlock()
160 if e != nil {
161 L. L.Warnf("failed to create new block template:", err)
162 continue
163 }
164 // Attempt to solve the block. The function will exit early with false
165 // when conditions that trigger a stale block, so a new block template
166 // can be generated. When the return is true a solution was found, so
167 // submit the solved block.
168 if m.solveBlock(workerNumber, template.Block, curHeight+1,
169 m.cfg.ChainParams.Name == "testnet", ticker, nil) {
170 block := util.NewBlock(template.Block)
171 m.submitBlock(block)
172 blockHashes[i] = block.Hash()
173 i++
174 if i == n {
175 L.Warnf("generated %d blocks", i)
176 m.Lock()
177 close(m.speedMonitorQuit)
178 m.wg.Wait()
179 m.started = false
180 m.discreteMining = false
181 m.Unlock()
182 return blockHashes, nil
183 }
184 }
185 }
186 }
187 188 // GetAlgo returns the algorithm currently configured for the miner
189 func (m *CPUMiner) GetAlgo() (name string) {
190 return m.cfg.Algo
191 }
192 193 // HashesPerSecond returns the number of hashes per second the mining process
194 // is performing. 0 is returned if the miner is not currently running. This
195 // function is safe for concurrent access.
196 func (m *CPUMiner) HashesPerSecond() float64 {
197 m.Lock()
198 defer m.Unlock()
199 // Nothing to do if the miner is not currently running.
200 if !m.started {
201 return 0
202 }
203 return <-m.queryHashesPerSec
204 }
205 206 // IsMining returns whether or not the CPU miner has been started and is
207 // therefore currently mining. This function is safe for concurrent access.
208 func (m *CPUMiner) IsMining() bool {
209 m.Lock()
210 defer m.Unlock()
211 return m.started
212 }
213 214 // NumWorkers returns the number of workers which are running to solve blocks.
215 // This function is safe for concurrent access.
216 func (m *CPUMiner) NumWorkers() int32 {
217 m.Lock()
218 defer m.Unlock()
219 return int32(m.numWorkers)
220 }
221 222 // SetAlgo sets the algorithm for the CPU miner
223 func (m *CPUMiner) SetAlgo(
224 name string) {
225 m.cfg.Algo = name
226 }
227 228 // SetNumWorkers sets the number of workers to create which solve blocks. Any
229 // negative values will cause a default number of workers to be used which is
230 // based on the number of processor cores in the system. A value of 0 will
231 // cause all CPU mining to be stopped. This function is safe for concurrent
232 // access.
233 func (m *CPUMiner) SetNumWorkers(numWorkers int32) {
234 if numWorkers == 0 {
235 m.Stop()
236 }
237 // Don't lock until after the first check since Stop does its own locking.
238 m.Lock()
239 defer m.Unlock()
240 // Use default if provided value is negative.
241 if numWorkers < 0 {
242 m.numWorkers = defaultNumWorkers
243 } else {
244 m.numWorkers = uint32(numWorkers)
245 }
246 // When the miner is already running, notify the controller about the the change.
247 if m.started {
248 m.updateNumWorkers <- struct{}{}
249 }
250 }
251 252 // Start begins the CPU mining process as well as the speed monitor used to
253 // track hashing metrics. Calling this function when the CPU miner has already
254 // been started will have no effect.
255 // This function is safe for concurrent access.
256 func (m *CPUMiner) Start() {
257 if len(m.cfg.MiningAddrs) < 1 {
258 return
259 }
260 m.Lock()
261 defer m.Unlock()
262 L.inf.Ln("starting cpu miner")
263 // Nothing to do if the miner is already running or if running in discrete mode (using GenerateNBlocks).
264 if m.started || m.discreteMining {
265 return
266 }
267 // randomize the starting point so all network is mining different
268 m.rotator.Store(uint64(rand.Intn(
269 len(fork.List[fork.GetCurrent(m.b.BestSnapshot().Height)].Algos))))
270 m.quit = qu.Ter()
271 m.speedMonitorQuit = qu.Ter()
272 m.wg.Add(2)
273 go m.speedMonitor()
274 go m.miningWorkerController()
275 m.started = true
276 L.trc.Ln("CPU miner started mining", m.cfg.Algo, m.cfg.NumThreads)
277 }
278 279 // Stop gracefully stops the mining process by signalling all workers, and the
280 // speed monitor to quit. Calling this function when the CPU miner has not
281 // already been started will have no effect. This function is safe for
282 // concurrent access.
283 func (m *CPUMiner) Stop() {
284 m.Lock()
285 defer m.Unlock()
286 // Nothing to do if the miner is not currently running or if running in discrete mode (using GenerateNBlocks).
287 if !m.started || m.discreteMining {
288 return
289 }
290 close(m.quit)
291 m.wg.Wait()
292 m.started = false
293 L.wrn.Ln("CPU miner stopped")
294 }
295 296 // generateBlocks is a worker that is controlled by the miningWorkerController.
297 // It is self contained in that it creates block templates and attempts to
298 // solve them while detecting when it is performing stale work and reacting
299 // accordingly by generating a new block template. When a block is solved, it
300 // is submitted. It must be run as a goroutine.
301 func (m *CPUMiner) generateBlocks(workerNumber uint32, quit qu.C) {
302 // Start a ticker which is used to signal checks for stale work and updates
303 // to the speed monitor.
304 ticker := time.NewTicker(time.Second / 3) // * hashUpdateSecs)
305 defer ticker.Stop()
306 out:
307 for i := 0; ; i++ {
308 //L.trc.Ln(workerNumber, "generateBlocksLoop start")
309 // Quit when the miner is stopped.
310 select {
311 case <-quit:
312 break out
313 default:
314 // Non-blocking select to fall through
315 }
316 // Wait until there is a connection to at least one other peer since
317 // there is no way to relay a found block or receive transactions to work
318 // on when there are no connected peers.
319 if (m.cfg.ConnectedCount() == 0 || !m.cfg.IsCurrent()) &&
320 (m.cfg.ChainParams.Net == wire.MainNet && !m.cfg.Solo) {
321 log.Print(log.Composite("server has no peers, waiting...",
322 "STATUS", true), "\r")
323 time.Sleep(time.Second)
324 continue
325 }
326 select {
327 case <-quit:
328 break out
329 default:
330 // Non-blocking select to fall through
331 }
332 // No point in searching for a solution before the chain is synced. Also,
333 // grab the same lock as used for block submission, since the current
334 // block will be changing and this would otherwise end up building a new
335 // block template on a block that is in the process of becoming stale.
336 curHeight := m.g.BestSnapshot().Height
337 if curHeight != 0 && !m.cfg.IsCurrent() && !m.cfg.Solo {
338 L.Warnf("server is not current yet, waiting")
339 time.Sleep(time.Second)
340 continue
341 }
342 select {
343 case <-quit:
344 break out
345 default:
346 // Non-blocking select to fall through
347 }
348 // choose the algorithm on a rolling cycle
349 counter := m.rotator.Load()
350 //counter /= uint64(len(fork.List[fork.GetCurrent(curHeight+1)].Algos))*2
351 m.rotator.Add(1)
352 algo := "sha256d"
353 switch fork.GetCurrent(curHeight + 1) {
354 case 0:
355 if counter&1 == 1 {
356 algo = "sha256d"
357 } else {
358 algo = "scrypt"
359 }
360 case 1:
361 l9 := uint64(len(fork.P9AlgoVers))
362 mod := counter % l9
363 algo = fork.P9AlgoVers[int32(mod+5)]
364 // L.wrn.Ln("algo", algo)
365 }
366 select {
367 case <-quit:
368 break out
369 default:
370 // Non-blocking select to fall through
371 }
372 // Choose a payment address at random.
373 rand.Seed(time.Now().UnixNano())
374 payToAddr := m.cfg.MiningAddrs[rand.Intn(len(m.cfg.MiningAddrs))]
375 // Create a new block template using the available transactions in the
376 // memory pool as a source of transactions to potentially include in the
377 // block.
378 template, e := m.g.NewBlockTemplate(workerNumber, payToAddr, algo)
379 if e != nil {
380 L.wrn.Ln("failed to create new block template:", err)
381 continue
382 }
383 // Attempt to solve the block. The function will exit early with false
384 // when conditions that trigger a stale block, so a new block template
385 // can be generated. When the return is true a solution was found, so
386 // submit the solved block.
387 //L.trc.Ln("attempting to solve block")
388 select {
389 case <-quit:
390 break out
391 default:
392 // Non-blocking select to fall through
393 }
394 if m.solveBlock(workerNumber, template.Block, curHeight+1,
395 m.cfg.ChainParams.Name == "testnet", ticker, quit) {
396 block := util.NewBlock(template.Block)
397 m.submitBlock(block)
398 }
399 }
400 L.trc.Ln("cpu miner worker finished")
401 m.workerWg.Done()
402 }
403 404 // miningWorkerController launches the worker goroutines that are used to
405 // generate block templates and solve them. It also provides the ability to
406 // dynamically adjust the number of running worker goroutines. It must be run
407 // as a goroutine.
408 func (m *CPUMiner) miningWorkerController() {
409 L.trc.Ln("starting mining worker controller")
410 // launchWorkers groups common code to launch a specified number of workers
411 // for generating blocks.
412 var runningWorkers qu.Ters
413 launchWorkers := func(numWorkers uint32) {
414 for i := uint32(0); i < numWorkers; i++ {
415 quit := qu.Ter()
416 runningWorkers = append(runningWorkers, quit)
417 m.workerWg.Add(1)
418 go m.generateBlocks(i, quit)
419 }
420 }
421 L.Tracef("spawning %d worker(s)", m.numWorkers)
422 // Launch the current number of workers by default.
423 runningWorkers = make(qu.Ters, 0, m.numWorkers)
424 launchWorkers(m.numWorkers)
425 out:
426 for {
427 select {
428 // Update the number of running workers.
429 case <-m.updateNumWorkers:
430 // No change.
431 numRunning := uint32(len(runningWorkers))
432 if m.numWorkers == numRunning {
433 continue
434 }
435 // Add new workers.
436 if m.numWorkers > numRunning {
437 launchWorkers(m.numWorkers - numRunning)
438 continue
439 }
440 // Signal the most recently created goroutines to exit.
441 for i := numRunning - 1; i >= m.numWorkers; i-- {
442 close(runningWorkers[i])
443 runningWorkers[i] = nil
444 runningWorkers = runningWorkers[:i]
445 }
446 case <-m.quit:
447 for _, quit := range runningWorkers {
448 close(quit)
449 }
450 break out
451 }
452 }
453 // Wait until all workers shut down to stop the speed monitor since they rely on being able to send updates to it.
454 m.workerWg.Wait()
455 close(m.speedMonitorQuit)
456 m.wg.Done()
457 }
458 459 // solveBlock attempts to find some combination of a nonce, extra nonce, and
460 // current timestamp which makes the passed block hash to a value less than the
461 // target difficulty. The timestamp is updated periodically and the passed
462 // block is modified with all tweaks during this process. This means that when
463 // the function returns true, the block is ready for submission. This function
464 // will return early with false when conditions that trigger a stale block such
465 // as a new block showing up or periodically when there are new transactions
466 // and enough time has elapsed without finding a solution.
467 func (m *CPUMiner) solveBlock(workerNumber uint32, msgBlock *wire.MsgBlock,
468 blockHeight int32, testnet bool, ticker *time.Ticker,
469 quit qu.C) bool {
470 //L.trc.Ln("running solveBlock")
471 // algoName := fork.GetAlgoName(
472 // msgBlock.Header.Version, m.b.BestSnapshot().Height)
473 // Choose a random extra nonce offset for this block template and worker.
474 enOffset, e := wire.RandomUint64()
475 if e != nil {
476 L. L.Warnf("unexpected error while generating random extra nonce"+
477 " offset:",
478 err)
479 enOffset = 0
480 }
481 // Create some convenience variables.
482 header := &msgBlock.Header
483 targetDifficulty := fork.CompactToBig(header.Bits)
484 // Initial state.
485 lastGenerated := time.Now()
486 lastTxUpdate := m.g.GetTxSource().LastUpdated()
487 hashesCompleted := uint64(0)
488 // Note that the entire extra nonce range is iterated and the offset is
489 // added relying on the fact that overflow will wrap around 0 as provided by
490 // the Go spec.
491 eN, _ := wire.RandomUint64()
492 // now := time.Now()
493 // for extraNonce := eN; extraNonce < eN+maxExtraNonce; extraNonce++ {
494 did := false
495 extraNonce := eN
496 // we only do this once
497 for !did {
498 did = true
499 // Update the extra nonce in the block template with the new value by
500 // regenerating the coinbase script and setting the merkle root to the
501 // new value.
502 //L.trc.Ln("updating extraNonce")
503 e := m.g.UpdateExtraNonce(msgBlock, blockHeight, extraNonce+enOffset)
504 if e != nil {
505 L. }
506 // Search through the entire nonce range for a solution while
507 // periodically checking for early quit and stale block conditions along
508 // with updates to the speed monitor.
509 var shifter uint64 = 16
510 if testnet {
511 shifter = 16
512 }
513 rn, _ := wire.RandomUint64()
514 if rn > 1<<63-1<<shifter {
515 rn -= 1 << shifter
516 }
517 rn += 1 << shifter
518 rNonce := uint32(rn)
519 mn := uint32(1 << 8)
520 switch {
521 case m.cfg.NumThreads < 2:
522 mn = uint32(1 << 7)
523 case m.cfg.NumThreads < 4:
524 mn = uint32(1 << 8)
525 case m.cfg.NumThreads < 6:
526 mn = uint32(1 << 9)
527 case m.cfg.NumThreads < 8:
528 mn = uint32(1 << 10)
529 }
530 // if testnet {
531 // mn = 1 << shifter
532 // }
533 if fork.GetCurrent(blockHeight) == 0 {
534 mn = 1 << 16 * m.cfg.NumThreads
535 }
536 var i uint32
537 algo := fork.GetAlgoName(msgBlock.Header.Version,
538 blockHeight)
539 defer func() {
540 L.Tracef("wrkr %d finished %d rounds of %s", workerNumber,
541 i-rNonce, algo)
542 }()
543 L.trc.Ln("starting round from ", rNonce, algo, mn)
544 for i = rNonce; i <= rNonce+mn; i++ {
545 // if time.Now().Sub(now) > time.Second*3 {
546 // return false
547 // }
548 select {
549 case <-quit:
550 return false
551 case <-ticker.C:
552 m.updateHashes <- hashesCompleted
553 hashesCompleted = 0
554 // The current block is stale if the best block has changed.
555 best := m.g.BestSnapshot()
556 if !header.PrevBlock.IsEqual(&best.Hash) {
557 return false
558 }
559 // The current block is stale if the memory pool has been updated
560 // since the block template was generated and it has been at least
561 // one minute.
562 if lastTxUpdate != m.g.GetTxSource().LastUpdated() &&
563 time.Now().After(lastGenerated.Add(time.Minute)) {
564 return false
565 }
566 e := m.g.UpdateBlockTime(workerNumber, msgBlock)
567 if e != nil {
568 L. }
569 default:
570 }
571 var incr uint64 = 1
572 header.Nonce = i
573 hash := header.BlockHashWithAlgos(blockHeight)
574 hashesCompleted += incr
575 // The block is solved when the new block hash is less than the target
576 // difficulty. Yay!
577 bigHash := blockchain.HashToBig(&hash)
578 if bigHash.Cmp(targetDifficulty) <= 0 {
579 m.updateHashes <- hashesCompleted
580 return true
581 }
582 }
583 return false
584 }
585 return false
586 }
587 588 // speedMonitor handles tracking the number of hashes per second the mining
589 // process is performing. It must be run as a goroutine.
590 func (m *CPUMiner) speedMonitor() {
591 var hashesPerSec float64
592 var totalHashes uint64 = 1
593 ticker := time.NewTicker(time.Second * hpsUpdateSecs)
594 defer ticker.Stop()
595 out:
596 for i := 0; ; i++ {
597 select {
598 // Periodic updates from the workers with how many hashes they have
599 // performed.
600 case numHashes := <-m.updateHashes:
601 totalHashes += numHashes
602 // Time to update the hashes per second.
603 case <-ticker.C:
604 //curHashesPerSec := float64(totalHashes) / hpsUpdateSecs
605 //if hashesPerSec == 0 {
606 // hashesPerSec = curHashesPerSec
607 //}
608 //hashesPerSec = (hashesPerSec + curHashesPerSec) / 2
609 ////totalHashes = 0
610 //if hashesPerSec != 0 {
611 //since := fmt.Sprint(time.Now().Sub(log.StartupTime) / time.
612 // Second * time.Second)
613 since := uint64(time.Now().Sub(tn)/time.Second) + 1
614 log.Print(log.Composite(fmt.Sprintf(
615 "--> Hash speed: %d hash/s av since start",
616 totalHashes/since),
617 "STATUS", true),
618 "\r")
619 //}
620 // Request for the number of hashes per second.
621 case m.queryHashesPerSec <- hashesPerSec:
622 // Nothing to do.
623 case <-m.speedMonitorQuit:
624 break out
625 }
626 }
627 m.wg.Done()
628 }
629 630 // submitBlock submits the passed block to network after ensuring it passes all
631 // of the consensus validation rules.
632 func (m *CPUMiner) submitBlock(block *util.Block) bool {
633 L.trc.Ln("submitting block")
634 m.submitBlockLock.Lock()
635 defer m.submitBlockLock.Unlock()
636 // TODO: This nonsense and the workgroup are the entirely wrong way to
637 // write a cryptocurrency miner.
638 // It is not critical work so it should not use a workgroup but rather,
639 // a semaphore, which can yank all the threads to stop as soon as they
640 // select on the semaphore,
641 // whereas this stops 'when all the jobs are finished' for what purpose?
642 // This miner will be eliminated once the replacement is complete.
643 // End result of this is node waits for miners to stop,
644 // which sometimes takes 5 seconds and almost every other height it has
645 // two submissions processing on one mutex and second and others are
646 // always stale. So also, the submitlock needs to be revised,
647 // I think submitlock and waitgroup together are far better replaced by
648 // a semaphore. Miner should STOP DEAD when a solution is found and wait
649 // for more work. The kopach controller will stop all miners in the
650 // network when it receives submissions prejudicially because it is
651 // better to save power than catch one block in a thousand from an
652 // economics poinnt of view.
653 // Every cycle degrades the value and brings closer the hardware failure
654 // so don't work unless there is a very good reason to.
655 // Ensure the block is not stale since a new block could have shown up while
656 // the solution was being found. Typically that condition is detected and
657 // all work on the stale block is halted to start work on a new block, but
658 // the check only happens periodically, so it is possible a block was found
659 // and submitted in between.
660 msgBlock := block.MsgBlock()
661 if !msgBlock.Header.PrevBlock.IsEqual(&m.g.BestSnapshot().Hash) {
662 L.trc.Ln(
663 "Block submitted via CPU miner with previous block", msgBlock.Header.PrevBlock,
664 "is stale", msgBlock.Header.Version,
665 msgBlock.BlockHashWithAlgos(block.Height()))
666 return false
667 }
668 //L.trc.Ln("found block is fresh ", m.cfg.ProcessBlock)
669 // Process this block using the same rules as blocks coming from other
670 // nodes. This will in turn relay it to the network like normal.
671 isOrphan, e := m.cfg.ProcessBlock(block, blockchain.BFNone)
672 if e != nil {
673 L. // Anything other than a rule violation is an unexpected error, so log
674 // that error as an internal error.
675 if _, ok := err.(blockchain.RuleError); !ok {
676 L.Warnf(
677 "Unexpected error while processing block submitted via CPU miner:", err,
678 )
679 return false
680 }
681 L.Warnf("block submitted via CPU miner rejected:", err)
682 return false
683 }
684 if isOrphan {
685 L.wrn.Ln("block is an orphan")
686 return false
687 }
688 //L.trc.Ln("the block was accepted")
689 coinbaseTx := block.MsgBlock().Transactions[0].TxOut[0]
690 prevHeight := block.Height() - 1
691 prevBlock, _ := m.b.BlockByHeight(prevHeight)
692 prevTime := prevBlock.MsgBlock().Header.Timestamp.Unix()
693 since := block.MsgBlock().Header.Timestamp.Unix() - prevTime
694 bHash := block.MsgBlock().BlockHashWithAlgos(block.Height())
695 L.Warnf("new block height %d %08x %s%10d %08x %v %s %ds since prev",
696 block.Height(),
697 prevBlock.MsgBlock().Header.Bits,
698 bHash,
699 block.MsgBlock().Header.Timestamp.Unix(),
700 block.MsgBlock().Header.Bits,
701 util.Amount(coinbaseTx.Value),
702 fork.GetAlgoName(block.MsgBlock().Header.Version, block.Height()),
703 since)
704 return true
705 }
706 707 // New returns a new instance of a CPU miner for the provided configuration.
708 // Use Start to begin the mining process. See the documentation for CPUMiner
709 // type for more details.
710 func New(cfg *Config) *CPUMiner {
711 return &CPUMiner{
712 b: cfg.Blockchain,
713 g: cfg.BlockTemplateGenerator,
714 cfg: *cfg,
715 numWorkers: cfg.NumThreads,
716 updateNumWorkers: qu.Ter(),
717 queryHashesPerSec: make(chan float64),
718 updateHashes: make(chan uint64),
719 }
720 }
721