cpuminer: Refactor code to its own package.

This does the minimum work necessary to refactor the CPU miner code into
its own package.  The idea is that separating this code into its own
package will improve its testability and ultimately be useful to other
parts of the codebase such as the various tests which currently
effectively have their own stripped-down versions of this code.

The API will certainly need some additional cleanup and changes to make
it more usable outside of the specific circumstances it was originally
designed to support (namely the generate RPC), however it is better to
do that in future commits in order to keep the changeset as small as
possible during this refactor.

Overview of the major changes:

- Create the new package
- Move cpuminer.go -> cpuminer/cpuminer.go
- Update mining logging to use the new cpuminer package logger
- Rename cpuminerConfig to Config (so it's now cpuminer.Config)
- Rename newCPUMiner to New (so it's now cpuminer.New)
- Update all references to the cpuminer to use the package
- Add a skeleton README.md
This commit is contained in:
Dave Collins 2016-10-28 11:06:11 -05:00
parent a755305a2e
commit 1a69eb0617
No known key found for this signature in database
GPG key ID: B8904D9D9C93D1F2
5 changed files with 117 additions and 31 deletions

2
log.go
View file

@ -15,6 +15,7 @@ import (
"github.com/btcsuite/btcd/database" "github.com/btcsuite/btcd/database"
"github.com/btcsuite/btcd/mempool" "github.com/btcsuite/btcd/mempool"
"github.com/btcsuite/btcd/mining" "github.com/btcsuite/btcd/mining"
"github.com/btcsuite/btcd/mining/cpuminer"
"github.com/btcsuite/btcd/peer" "github.com/btcsuite/btcd/peer"
"github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btclog" "github.com/btcsuite/btclog"
@ -129,6 +130,7 @@ func useLogger(subsystemID string, logger btclog.Logger) {
case "MINR": case "MINR":
minrLog = logger minrLog = logger
mining.UseLogger(logger) mining.UseLogger(logger)
cpuminer.UseLogger(logger)
case "PEER": case "PEER":
peerLog = logger peerLog = logger

26
mining/cpuminer/README.md Normal file
View file

@ -0,0 +1,26 @@
cpuminer
========
[![Build Status](http://img.shields.io/travis/btcsuite/btcd.svg)]
(https://travis-ci.org/btcsuite/btcd) [![ISC License]
(http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)]
(http://godoc.org/github.com/btcsuite/btcd/mining/cpuminer)
## Overview
This package is currently a work in progress. It works without issue since it
is used in several of the integration tests, but the API is not really ready for
public consumption as it has simply been refactored out of the main codebase for
now.
## Installation and Updating
```bash
$ go get -u github.com/btcsuite/btcd/mining/cpuminer
```
## License
Package cpuminer is licensed under the [copyfree](http://copyfree.org) ISC
License.

View file

@ -2,7 +2,7 @@
// Use of this source code is governed by an ISC // Use of this source code is governed by an ISC
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package main package cpuminer
import ( import (
"errors" "errors"
@ -47,8 +47,8 @@ var (
defaultNumWorkers = uint32(runtime.NumCPU()) defaultNumWorkers = uint32(runtime.NumCPU())
) )
// cpuminerConfig is a descriptor containing the cpu miner configuration. // Config is a descriptor containing the cpu miner configuration.
type cpuminerConfig struct { type Config struct {
// ChainParams identifies which chain parameters the cpu miner is // ChainParams identifies which chain parameters the cpu miner is
// associated with. // associated with.
ChainParams *chaincfg.Params ChainParams *chaincfg.Params
@ -92,7 +92,7 @@ type cpuminerConfig struct {
type CPUMiner struct { type CPUMiner struct {
sync.Mutex sync.Mutex
g *mining.BlkTmplGenerator g *mining.BlkTmplGenerator
cfg cpuminerConfig cfg Config
numWorkers uint32 numWorkers uint32
started bool started bool
discreteMining bool discreteMining bool
@ -109,7 +109,7 @@ type CPUMiner struct {
// speedMonitor handles tracking the number of hashes per second the mining // speedMonitor handles tracking the number of hashes per second the mining
// process is performing. It must be run as a goroutine. // process is performing. It must be run as a goroutine.
func (m *CPUMiner) speedMonitor() { func (m *CPUMiner) speedMonitor() {
minrLog.Tracef("CPU miner speed monitor started") log.Tracef("CPU miner speed monitor started")
var hashesPerSec float64 var hashesPerSec float64
var totalHashes uint64 var totalHashes uint64
@ -133,7 +133,7 @@ out:
hashesPerSec = (hashesPerSec + curHashesPerSec) / 2 hashesPerSec = (hashesPerSec + curHashesPerSec) / 2
totalHashes = 0 totalHashes = 0
if hashesPerSec != 0 { if hashesPerSec != 0 {
minrLog.Debugf("Hash speed: %6.0f kilohashes/s", log.Debugf("Hash speed: %6.0f kilohashes/s",
hashesPerSec/1000) hashesPerSec/1000)
} }
@ -147,7 +147,7 @@ out:
} }
m.wg.Done() m.wg.Done()
minrLog.Tracef("CPU miner speed monitor done") log.Tracef("CPU miner speed monitor done")
} }
// submitBlock submits the passed block to network after ensuring it passes all // submitBlock submits the passed block to network after ensuring it passes all
@ -161,10 +161,9 @@ func (m *CPUMiner) submitBlock(block *btcutil.Block) bool {
// detected and all work on the stale block is halted to start work on // detected and all work on the stale block is halted to start work on
// a new block, but the check only happens periodically, so it is // a new block, but the check only happens periodically, so it is
// possible a block was found and submitted in between. // possible a block was found and submitted in between.
latestHash := m.g.BestSnapshot().Hash
msgBlock := block.MsgBlock() msgBlock := block.MsgBlock()
if !msgBlock.Header.PrevBlock.IsEqual(latestHash) { if !msgBlock.Header.PrevBlock.IsEqual(m.g.BestSnapshot().Hash) {
minrLog.Debugf("Block submitted via CPU miner with previous "+ log.Debugf("Block submitted via CPU miner with previous "+
"block %s is stale", msgBlock.Header.PrevBlock) "block %s is stale", msgBlock.Header.PrevBlock)
return false return false
} }
@ -176,22 +175,22 @@ func (m *CPUMiner) submitBlock(block *btcutil.Block) bool {
// Anything other than a rule violation is an unexpected error, // Anything other than a rule violation is an unexpected error,
// so log that error as an internal error. // so log that error as an internal error.
if _, ok := err.(blockchain.RuleError); !ok { if _, ok := err.(blockchain.RuleError); !ok {
minrLog.Errorf("Unexpected error while processing "+ log.Errorf("Unexpected error while processing "+
"block submitted via CPU miner: %v", err) "block submitted via CPU miner: %v", err)
return false return false
} }
minrLog.Debugf("Block submitted via CPU miner rejected: %v", err) log.Debugf("Block submitted via CPU miner rejected: %v", err)
return false return false
} }
if isOrphan { if isOrphan {
minrLog.Debugf("Block submitted via CPU miner is an orphan") log.Debugf("Block submitted via CPU miner is an orphan")
return false return false
} }
// The block was accepted. // The block was accepted.
coinbaseTx := block.MsgBlock().Transactions[0].TxOut[0] coinbaseTx := block.MsgBlock().Transactions[0].TxOut[0]
minrLog.Infof("Block submitted via CPU miner accepted (hash %s, "+ log.Infof("Block submitted via CPU miner accepted (hash %s, "+
"amount %v)", block.Hash(), btcutil.Amount(coinbaseTx.Value)) "amount %v)", block.Hash(), btcutil.Amount(coinbaseTx.Value))
return true return true
} }
@ -212,12 +211,12 @@ func (m *CPUMiner) solveBlock(msgBlock *wire.MsgBlock, blockHeight int32,
// worker. // worker.
enOffset, err := wire.RandomUint64() enOffset, err := wire.RandomUint64()
if err != nil { if err != nil {
minrLog.Errorf("Unexpected error while generating random "+ log.Errorf("Unexpected error while generating random "+
"extra nonce offset: %v", err) "extra nonce offset: %v", err)
enOffset = 0 enOffset = 0
} }
// Create a couple of convenience variables. // Create some convenience variables.
header := &msgBlock.Header header := &msgBlock.Header
targetDifficulty := blockchain.CompactToBig(header.Bits) targetDifficulty := blockchain.CompactToBig(header.Bits)
@ -232,7 +231,7 @@ func (m *CPUMiner) solveBlock(msgBlock *wire.MsgBlock, blockHeight int32,
for extraNonce := uint64(0); extraNonce < maxExtraNonce; extraNonce++ { for extraNonce := uint64(0); extraNonce < maxExtraNonce; extraNonce++ {
// Update the extra nonce in the block template with the // Update the extra nonce in the block template with the
// new value by regenerating the coinbase script and // new value by regenerating the coinbase script and
// setting the merkle root to the new value. The // setting the merkle root to the new value.
m.g.UpdateExtraNonce(msgBlock, blockHeight, extraNonce+enOffset) m.g.UpdateExtraNonce(msgBlock, blockHeight, extraNonce+enOffset)
// Search through the entire nonce range for a solution while // Search through the entire nonce range for a solution while
@ -298,7 +297,7 @@ func (m *CPUMiner) solveBlock(msgBlock *wire.MsgBlock, blockHeight int32,
// //
// It must be run as a goroutine. // It must be run as a goroutine.
func (m *CPUMiner) generateBlocks(quit chan struct{}) { func (m *CPUMiner) generateBlocks(quit chan struct{}) {
minrLog.Tracef("Starting generate blocks worker") log.Tracef("Starting generate blocks worker")
// Start a ticker which is used to signal checks for stale work and // Start a ticker which is used to signal checks for stale work and
// updates to the speed monitor. // updates to the speed monitor.
@ -347,7 +346,7 @@ out:
if err != nil { if err != nil {
errStr := fmt.Sprintf("Failed to create new block "+ errStr := fmt.Sprintf("Failed to create new block "+
"template: %v", err) "template: %v", err)
minrLog.Errorf(errStr) log.Errorf(errStr)
continue continue
} }
@ -362,7 +361,7 @@ out:
} }
m.workerWg.Done() m.workerWg.Done()
minrLog.Tracef("Generate blocks worker done") log.Tracef("Generate blocks worker done")
} }
// miningWorkerController launches the worker goroutines that are used to // miningWorkerController launches the worker goroutines that are used to
@ -436,8 +435,8 @@ func (m *CPUMiner) Start() {
m.Lock() m.Lock()
defer m.Unlock() defer m.Unlock()
// Nothing to do if the miner is already running or if running in discrete // Nothing to do if the miner is already running or if running in
// mode (using GenerateNBlocks). // discrete mode (using GenerateNBlocks).
if m.started || m.discreteMining { if m.started || m.discreteMining {
return return
} }
@ -449,7 +448,7 @@ func (m *CPUMiner) Start() {
go m.miningWorkerController() go m.miningWorkerController()
m.started = true m.started = true
minrLog.Infof("CPU miner started") log.Infof("CPU miner started")
} }
// Stop gracefully stops the mining process by signalling all workers, and the // Stop gracefully stops the mining process by signalling all workers, and the
@ -470,7 +469,7 @@ func (m *CPUMiner) Stop() {
close(m.quit) close(m.quit)
m.wg.Wait() m.wg.Wait()
m.started = false m.started = false
minrLog.Infof("CPU miner stopped") log.Infof("CPU miner stopped")
} }
// IsMining returns whether or not the CPU miner has been started and is // IsMining returns whether or not the CPU miner has been started and is
@ -564,7 +563,7 @@ func (m *CPUMiner) GenerateNBlocks(n uint32) ([]*chainhash.Hash, error) {
m.Unlock() m.Unlock()
minrLog.Tracef("Generating %d blocks", n) log.Tracef("Generating %d blocks", n)
i := uint32(0) i := uint32(0)
blockHashes := make([]*chainhash.Hash, n, n) blockHashes := make([]*chainhash.Hash, n, n)
@ -601,7 +600,7 @@ func (m *CPUMiner) GenerateNBlocks(n uint32) ([]*chainhash.Hash, error) {
if err != nil { if err != nil {
errStr := fmt.Sprintf("Failed to create new block "+ errStr := fmt.Sprintf("Failed to create new block "+
"template: %v", err) "template: %v", err)
minrLog.Errorf(errStr) log.Errorf(errStr)
continue continue
} }
@ -615,7 +614,7 @@ func (m *CPUMiner) GenerateNBlocks(n uint32) ([]*chainhash.Hash, error) {
blockHashes[i] = block.Hash() blockHashes[i] = block.Hash()
i++ i++
if i == n { if i == n {
minrLog.Tracef("Generated %d blocks", i) log.Tracef("Generated %d blocks", i)
m.Lock() m.Lock()
close(m.speedMonitorQuit) close(m.speedMonitorQuit)
m.wg.Wait() m.wg.Wait()
@ -628,10 +627,10 @@ func (m *CPUMiner) GenerateNBlocks(n uint32) ([]*chainhash.Hash, error) {
} }
} }
// newCPUMiner returns a new instance of a CPU miner for the provided server. // New returns a new instance of a CPU miner for the provided configuration.
// Use Start to begin the mining process. See the documentation for CPUMiner // Use Start to begin the mining process. See the documentation for CPUMiner
// type for more details. // type for more details.
func newCPUMiner(cfg *cpuminerConfig) *CPUMiner { func New(cfg *Config) *CPUMiner {
return &CPUMiner{ return &CPUMiner{
g: cfg.BlockTemplateGenerator, g: cfg.BlockTemplateGenerator,
cfg: *cfg, cfg: *cfg,

58
mining/cpuminer/log.go Normal file
View file

@ -0,0 +1,58 @@
// Copyright (c) 2016 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package cpuminer
import (
"errors"
"io"
"github.com/btcsuite/btclog"
)
// log is a logger that is initialized with no output filters. This
// means the package will not perform any logging by default until the caller
// requests it.
var log btclog.Logger
// The default amount of logging is none.
func init() {
DisableLog()
}
// DisableLog disables all library log output. Logging output is disabled
// by default until either UseLogger or SetLogWriter are called.
func DisableLog() {
log = btclog.Disabled
}
// UseLogger uses a specified Logger to output package logging info.
// This should be used in preference to SetLogWriter if the caller is also
// using btclog.
func UseLogger(logger btclog.Logger) {
log = logger
}
// SetLogWriter uses a specified io.Writer to output package logging info.
// This allows a caller to direct package logging output without needing a
// dependency on seelog. If the caller is also using btclog, UseLogger should
// be used instead.
func SetLogWriter(w io.Writer, level string) error {
if w == nil {
return errors.New("nil writer")
}
lvl, ok := btclog.LogLevelFromString(level)
if !ok {
return errors.New("invalid log level")
}
l, err := btclog.NewLoggerFromWriter(w, lvl)
if err != nil {
return err
}
UseLogger(l)
return nil
}

View file

@ -28,6 +28,7 @@ import (
"github.com/btcsuite/btcd/database" "github.com/btcsuite/btcd/database"
"github.com/btcsuite/btcd/mempool" "github.com/btcsuite/btcd/mempool"
"github.com/btcsuite/btcd/mining" "github.com/btcsuite/btcd/mining"
"github.com/btcsuite/btcd/mining/cpuminer"
"github.com/btcsuite/btcd/peer" "github.com/btcsuite/btcd/peer"
"github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcd/wire"
@ -153,7 +154,7 @@ type server struct {
rpcServer *rpcServer rpcServer *rpcServer
blockManager *blockManager blockManager *blockManager
txMemPool *mempool.TxPool txMemPool *mempool.TxPool
cpuMiner *CPUMiner cpuMiner *cpuminer.CPUMiner
modifyRebroadcastInv chan interface{} modifyRebroadcastInv chan interface{}
newPeers chan *serverPeer newPeers chan *serverPeer
donePeers chan *serverPeer donePeers chan *serverPeer
@ -2378,7 +2379,7 @@ func newServer(listenAddrs []string, db database.DB, chainParams *chaincfg.Param
blockTemplateGenerator := mining.NewBlkTmplGenerator(&policy, blockTemplateGenerator := mining.NewBlkTmplGenerator(&policy,
s.chainParams, s.txMemPool, s.blockManager.chain, s.timeSource, s.chainParams, s.txMemPool, s.blockManager.chain, s.timeSource,
s.sigCache) s.sigCache)
s.cpuMiner = newCPUMiner(&cpuminerConfig{ s.cpuMiner = cpuminer.New(&cpuminer.Config{
ChainParams: chainParams, ChainParams: chainParams,
BlockTemplateGenerator: blockTemplateGenerator, BlockTemplateGenerator: blockTemplateGenerator,
MiningAddrs: cfg.miningAddrs, MiningAddrs: cfg.miningAddrs,