7 "github.com/vapor/config"
9 log "github.com/sirupsen/logrus"
11 "github.com/vapor/account"
12 "github.com/vapor/common"
13 "github.com/vapor/consensus"
14 engine "github.com/vapor/consensus/consensus"
15 "github.com/vapor/mining"
16 "github.com/vapor/protocol"
17 "github.com/vapor/protocol/bc"
21 maxNonce = ^uint64(0) // 2^64 - 1
27 // Miner creates blocks and searches for proof-of-work values.
31 accountManager *account.Manager
32 txPool *protocol.TxPool
36 workerWg sync.WaitGroup
37 updateNumWorkers chan struct{}
39 newBlockCh chan *bc.Hash
43 func NewMiner(c *protocol.Chain, accountManager *account.Manager, txPool *protocol.TxPool, newBlockCh chan *bc.Hash, engine engine.Engine) *Miner {
46 accountManager: accountManager,
48 numWorkers: defaultNumWorkers,
49 updateNumWorkers: make(chan struct{}),
50 newBlockCh: newBlockCh,
55 // generateBlocks is a worker that is controlled by the miningWorkerController.
56 // It is self contained in that it creates block templates and attempts to solve
57 // them while detecting when it is performing stale work and reacting
58 // accordingly by generating a new block template. When a block is solved, it
61 // It must be run as a goroutine.
62 func (m *Miner) generateBlocks(quit chan struct{}) {
72 delegateInfo interface{}
75 address, _ := common.DecodeAddress(config.CommonConfig.Consensus.Coinbase, &consensus.ActiveNetParams)
76 if delegateInfo, err = m.engine.IsMining(address, uint64(time.Now().Unix())); err != nil {
77 time.Sleep(1 * time.Second)
81 block, err := mining.NewBlockTemplate(m.chain, m.txPool, m.accountManager, m.engine, delegateInfo)
83 log.Errorf("Mining: failed on create NewBlockTemplate: %v", err)
84 time.Sleep(1 * time.Second)
88 time.Sleep(1 * time.Second)
92 if isOrphan, err := m.chain.ProcessBlock(block); err == nil {
93 log.WithFields(log.Fields{
94 "height": block.BlockHeader.Height,
96 "tx": len(block.Transactions),
97 }).Info("Miner processed block")
99 blockHash := block.Hash()
100 m.newBlockCh <- &blockHash
102 log.WithField("height", block.BlockHeader.Height).Errorf("Miner fail on ProcessBlock, %v", err)
104 time.Sleep(time.Duration(config.CommonConfig.Consensus.Period) * time.Second)
110 // miningWorkerController launches the worker goroutines that are used to
111 // generate block templates and solve them. It also provides the ability to
112 // dynamically adjust the number of running worker goroutines.
114 // It must be run as a goroutine.
115 func (m *Miner) miningWorkerController() {
116 // launchWorkers groups common code to launch a specified number of
117 // workers for generating blocks.
118 var runningWorkers []chan struct{}
119 launchWorkers := func(numWorkers uint64) {
120 for i := uint64(0); i < numWorkers; i++ {
121 quit := make(chan struct{})
122 runningWorkers = append(runningWorkers, quit)
125 go m.generateBlocks(quit)
129 // Launch the current number of workers by default.
130 runningWorkers = make([]chan struct{}, 0, m.numWorkers)
131 launchWorkers(m.numWorkers)
136 // Update the number of running workers.
137 case <-m.updateNumWorkers:
139 numRunning := uint64(len(runningWorkers))
140 if m.numWorkers == numRunning {
145 if m.numWorkers > numRunning {
146 launchWorkers(m.numWorkers - numRunning)
150 // Signal the most recently created goroutines to exit.
151 for i := numRunning - 1; i >= m.numWorkers; i-- {
152 close(runningWorkers[i])
153 runningWorkers[i] = nil
154 runningWorkers = runningWorkers[:i]
158 for _, quit := range runningWorkers {
168 // Start begins the CPU mining process as well as the speed monitor used to
169 // track hashing metrics. Calling this function when the CPU miner has
170 // already been started will have no effect.
172 // This function is safe for concurrent access.
173 func (m *Miner) Start() {
177 // Nothing to do if the miner is already running
182 m.quit = make(chan struct{})
183 go m.miningWorkerController()
186 log.Infof("CPU miner started")
189 // Stop gracefully stops the mining process by signalling all workers, and the
190 // speed monitor to quit. Calling this function when the CPU miner has not
191 // already been started will have no effect.
193 // This function is safe for concurrent access.
194 func (m *Miner) Stop() {
198 // Nothing to do if the miner is not currently running
205 log.Info("CPU miner stopped")
208 // IsMining returns whether or not the CPU miner has been started and is
209 // therefore currenting mining.
211 // This function is safe for concurrent access.
212 func (m *Miner) IsMining() bool {
219 // SetNumWorkers sets the number of workers to create which solve blocks. Any
220 // negative values will cause a default number of workers to be used which is
221 // based on the number of processor cores in the system. A value of 0 will
222 // cause all CPU mining to be stopped.
224 // This function is safe for concurrent access.
225 func (m *Miner) SetNumWorkers(numWorkers int32) {
230 // Don't lock until after the first check since Stop does its own
235 // Use default if provided value is negative.
237 m.numWorkers = defaultNumWorkers
239 m.numWorkers = uint64(numWorkers)
242 // When the miner is already running, notify the controller about the
245 m.updateNumWorkers <- struct{}{}
249 // NumWorkers returns the number of workers which are running to solve blocks.
251 // This function is safe for concurrent access.
252 func (m *Miner) NumWorkers() int32 {
256 return int32(m.numWorkers)