OSDN Git Service

init delete the pow related (#55)
[bytom/vapor.git] / mining / cpuminer / cpuminer.go
1 package cpuminer
2
3 import (
4         "sync"
5         "time"
6
7         log "github.com/sirupsen/logrus"
8
9         "github.com/vapor/account"
10         "github.com/vapor/event"
11         "github.com/vapor/mining"
12         "github.com/vapor/protocol"
13         "github.com/vapor/protocol/bc/types"
14 )
15
16 const (
17         maxNonce          = ^uint64(0) // 2^64 - 1
18         defaultNumWorkers = 1
19         hashUpdateSecs    = 1
20         logModule         = "cpuminer"
21 )
22
23 // CPUMiner provides facilities for solving blocks (mining) using the CPU in
24 // a concurrency-safe manner.
25 type CPUMiner struct {
26         sync.Mutex
27         chain            *protocol.Chain
28         accountManager   *account.Manager
29         txPool           *protocol.TxPool
30         numWorkers       uint64
31         started          bool
32         discreteMining   bool
33         workerWg         sync.WaitGroup
34         updateNumWorkers chan struct{}
35         quit             chan struct{}
36         eventDispatcher  *event.Dispatcher
37 }
38
39 // solveBlock attempts to find some combination of a nonce, extra nonce, and
40 // current timestamp which makes the passed block hash to a value less than the
41 // target difficulty.
42 func (m *CPUMiner) solveBlock(block *types.Block, ticker *time.Ticker, quit chan struct{}) bool {
43         header := &block.BlockHeader
44
45         for i := uint64(0); i <= maxNonce; i++ {
46                 select {
47                 case <-quit:
48                         return false
49                 case <-ticker.C:
50                         if m.chain.BestBlockHeight() >= header.Height {
51                                 return false
52                         }
53                 default:
54                 }
55
56                 //Mining logic here
57         }
58         return false
59 }
60
61 // generateBlocks is a worker that is controlled by the miningWorkerController.
62 // It is self contained in that it creates block templates and attempts to solve
63 // them while detecting when it is performing stale work and reacting
64 // accordingly by generating a new block template.  When a block is solved, it
65 // is submitted.
66 //
67 // It must be run as a goroutine.
68 func (m *CPUMiner) generateBlocks(quit chan struct{}) {
69         ticker := time.NewTicker(time.Second * hashUpdateSecs)
70         defer ticker.Stop()
71
72 out:
73         for {
74                 select {
75                 case <-quit:
76                         break out
77                 default:
78                 }
79
80                 block, err := mining.NewBlockTemplate(m.chain, m.txPool, m.accountManager)
81                 if err != nil {
82                         log.Errorf("Mining: failed on create NewBlockTemplate: %v", err)
83                         continue
84                 }
85
86                 if m.solveBlock(block, ticker, quit) {
87                         if isOrphan, err := m.chain.ProcessBlock(block); err == nil {
88                                 log.WithFields(log.Fields{
89                                         "module":   logModule,
90                                         "height":   block.BlockHeader.Height,
91                                         "isOrphan": isOrphan,
92                                         "tx":       len(block.Transactions),
93                                 }).Info("Miner processed block")
94
95                                 // Broadcast the block and announce chain insertion event
96                                 if err = m.eventDispatcher.Post(event.NewMinedBlockEvent{Block: *block}); err != nil {
97                                         log.WithFields(log.Fields{"module": logModule, "height": block.BlockHeader.Height, "error": err}).Errorf("Miner fail on post block")
98                                 }
99                         } else {
100                                 log.WithFields(log.Fields{"module": logModule, "height": block.BlockHeader.Height, "error": err}).Errorf("Miner fail on ProcessBlock")
101                         }
102                 }
103         }
104
105         m.workerWg.Done()
106 }
107
108 // miningWorkerController launches the worker goroutines that are used to
109 // generate block templates and solve them.  It also provides the ability to
110 // dynamically adjust the number of running worker goroutines.
111 //
112 // It must be run as a goroutine.
113 func (m *CPUMiner) miningWorkerController() {
114         // launchWorkers groups common code to launch a specified number of
115         // workers for generating blocks.
116         var runningWorkers []chan struct{}
117         launchWorkers := func(numWorkers uint64) {
118                 for i := uint64(0); i < numWorkers; i++ {
119                         quit := make(chan struct{})
120                         runningWorkers = append(runningWorkers, quit)
121
122                         m.workerWg.Add(1)
123                         go m.generateBlocks(quit)
124                 }
125         }
126
127         // Launch the current number of workers by default.
128         runningWorkers = make([]chan struct{}, 0, m.numWorkers)
129         launchWorkers(m.numWorkers)
130
131 out:
132         for {
133                 select {
134                 // Update the number of running workers.
135                 case <-m.updateNumWorkers:
136                         // No change.
137                         numRunning := uint64(len(runningWorkers))
138                         if m.numWorkers == numRunning {
139                                 continue
140                         }
141
142                         // Add new workers.
143                         if m.numWorkers > numRunning {
144                                 launchWorkers(m.numWorkers - numRunning)
145                                 continue
146                         }
147
148                         // Signal the most recently created goroutines to exit.
149                         for i := numRunning - 1; i >= m.numWorkers; i-- {
150                                 close(runningWorkers[i])
151                                 runningWorkers[i] = nil
152                                 runningWorkers = runningWorkers[:i]
153                         }
154
155                 case <-m.quit:
156                         for _, quit := range runningWorkers {
157                                 close(quit)
158                         }
159                         break out
160                 }
161         }
162
163         m.workerWg.Wait()
164 }
165
166 // Start begins the CPU mining process as well as the speed monitor used to
167 // track hashing metrics.  Calling this function when the CPU miner has
168 // already been started will have no effect.
169 //
170 // This function is safe for concurrent access.
171 func (m *CPUMiner) Start() {
172         m.Lock()
173         defer m.Unlock()
174
175         // Nothing to do if the miner is already running
176         if m.started {
177                 return
178         }
179
180         m.quit = make(chan struct{})
181         go m.miningWorkerController()
182
183         m.started = true
184         log.Infof("CPU miner started")
185 }
186
187 // Stop gracefully stops the mining process by signalling all workers, and the
188 // speed monitor to quit.  Calling this function when the CPU miner has not
189 // already been started will have no effect.
190 //
191 // This function is safe for concurrent access.
192 func (m *CPUMiner) Stop() {
193         m.Lock()
194         defer m.Unlock()
195
196         // Nothing to do if the miner is not currently running
197         if !m.started {
198                 return
199         }
200
201         close(m.quit)
202         m.started = false
203         log.Info("CPU miner stopped")
204 }
205
206 // IsMining returns whether or not the CPU miner has been started and is
207 // therefore currenting mining.
208 //
209 // This function is safe for concurrent access.
210 func (m *CPUMiner) IsMining() bool {
211         m.Lock()
212         defer m.Unlock()
213
214         return m.started
215 }
216
217 // SetNumWorkers sets the number of workers to create which solve blocks.  Any
218 // negative values will cause a default number of workers to be used which is
219 // based on the number of processor cores in the system.  A value of 0 will
220 // cause all CPU mining to be stopped.
221 //
222 // This function is safe for concurrent access.
223 func (m *CPUMiner) SetNumWorkers(numWorkers int32) {
224         if numWorkers == 0 {
225                 m.Stop()
226         }
227
228         // Don't lock until after the first check since Stop does its own
229         // locking.
230         m.Lock()
231         defer m.Unlock()
232
233         // Use default if provided value is negative.
234         if numWorkers < 0 {
235                 m.numWorkers = defaultNumWorkers
236         } else {
237                 m.numWorkers = uint64(numWorkers)
238         }
239
240         // When the miner is already running, notify the controller about the
241         // the change.
242         if m.started {
243                 m.updateNumWorkers <- struct{}{}
244         }
245 }
246
247 // NumWorkers returns the number of workers which are running to solve blocks.
248 //
249 // This function is safe for concurrent access.
250 func (m *CPUMiner) NumWorkers() int32 {
251         m.Lock()
252         defer m.Unlock()
253
254         return int32(m.numWorkers)
255 }
256
257 // NewCPUMiner returns a new instance of a CPU miner for the provided configuration.
258 // Use Start to begin the mining process.  See the documentation for CPUMiner
259 // type for more details.
260 func NewCPUMiner(c *protocol.Chain, accountManager *account.Manager, txPool *protocol.TxPool, dispatcher *event.Dispatcher) *CPUMiner {
261         return &CPUMiner{
262                 chain:            c,
263                 accountManager:   accountManager,
264                 txPool:           txPool,
265                 numWorkers:       defaultNumWorkers,
266                 updateNumWorkers: make(chan struct{}),
267                 eventDispatcher:  dispatcher,
268         }
269 }