_cpuminer.go raw

   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