9 log "github.com/sirupsen/logrus"
11 "github.com/vapor/account"
12 "github.com/vapor/consensus"
13 "github.com/vapor/crypto"
14 "github.com/vapor/crypto/ed25519/chainkd"
15 "github.com/vapor/mining"
16 "github.com/vapor/protocol"
17 "github.com/vapor/protocol/bc"
18 "github.com/vapor/protocol/bc/types"
19 "github.com/vapor/protocol/vm/vmutil"
23 maxNonce = ^uint64(0) // 2^64 - 1
28 // CPUMiner provides facilities for solving blocks (mining) using the CPU in
29 // a concurrency-safe manner.
30 type CPUMiner struct {
33 accountManager *account.Manager
34 txPool *protocol.TxPool
38 workerWg sync.WaitGroup
39 updateNumWorkers chan struct{}
41 newBlockCh chan *bc.Hash
42 Authoritys map[string]string
46 // solveBlock attempts to find some combination of a nonce, extra nonce, and
47 // current timestamp which makes the passed block hash to a value less than the
49 func (m *CPUMiner) solveBlock(block *types.Block, ticker *time.Ticker, quit chan struct{}) bool {
50 header := &block.BlockHeader
52 seed, err := m.chain.CalcNextSeed(&header.PreviousBlockHash)
57 for i := uint64(0); i <= maxNonce; i++ {
62 if m.chain.BestBlockHeight() >= header.Height {
71 func (m *CPUMiner) isSealer(height uint64) bool {
72 authority := height % uint64(len(m.Authoritys))
73 return authority == m.position
76 func (m *CPUMiner) generateProof(block types.Block) (types.Proof, error) {
78 if consensus.ActiveNetParams.Signer == "" {
79 return types.Proof{}, errors.New("Signer is empty")
81 xPrv.UnmarshalText([]byte(consensus.ActiveNetParams.Signer))
82 sign := xPrv.Sign(block.BlockCommitment.TransactionsMerkleRoot.Bytes())
83 pubHash := crypto.Ripemd160(xPrv.XPub().PublicKey())
84 control, err := vmutil.P2WPKHProgram([]byte(pubHash))
86 return types.Proof{}, err
88 return types.Proof{Sign: sign, ControlProgram: control}, nil
91 // generateBlocks is a worker that is controlled by the miningWorkerController.
92 // It is self contained in that it creates block templates and attempts to solve
93 // them while detecting when it is performing stale work and reacting
94 // accordingly by generating a new block template. When a block is solved, it
97 // It must be run as a goroutine.
98 func (m *CPUMiner) generateBlocks(quit chan struct{}) {
99 ticker := time.NewTicker(time.Second * hashUpdateSecs)
110 if m.isSealer(m.chain.BestBlockHeight()) {
111 block, err := mining.NewBlockTemplate(m.chain, m.txPool, m.accountManager)
113 log.Errorf("Mining: failed on create NewBlockTemplate: %v", err)
117 time.Sleep(3 * time.Second)
120 proof, _ := m.generateProof(*block)
122 if isOrphan, err := m.chain.ProcessBlock(block); err == nil {
123 log.WithFields(log.Fields{
124 "height": block.BlockHeader.Height,
125 "isOrphan": isOrphan,
126 "tx": len(block.Transactions),
127 }).Info("Miner processed block")
129 blockHash := block.Hash()
130 m.newBlockCh <- &blockHash
132 log.WithField("height", block.BlockHeader.Height).Errorf("Miner fail on ProcessBlock, %v", err)
135 time.Sleep(3 * time.Second)
141 // miningWorkerController launches the worker goroutines that are used to
142 // generate block templates and solve them. It also provides the ability to
143 // dynamically adjust the number of running worker goroutines.
145 // It must be run as a goroutine.
146 func (m *CPUMiner) miningWorkerController() {
147 // launchWorkers groups common code to launch a specified number of
148 // workers for generating blocks.
149 var runningWorkers []chan struct{}
150 launchWorkers := func(numWorkers uint64) {
151 for i := uint64(0); i < numWorkers; i++ {
152 quit := make(chan struct{})
153 runningWorkers = append(runningWorkers, quit)
156 go m.generateBlocks(quit)
160 // Launch the current number of workers by default.
161 runningWorkers = make([]chan struct{}, 0, m.numWorkers)
162 launchWorkers(m.numWorkers)
167 // Update the number of running workers.
168 case <-m.updateNumWorkers:
170 numRunning := uint64(len(runningWorkers))
171 if m.numWorkers == numRunning {
176 if m.numWorkers > numRunning {
177 launchWorkers(m.numWorkers - numRunning)
181 // Signal the most recently created goroutines to exit.
182 for i := numRunning - 1; i >= m.numWorkers; i-- {
183 close(runningWorkers[i])
184 runningWorkers[i] = nil
185 runningWorkers = runningWorkers[:i]
189 for _, quit := range runningWorkers {
199 // Start begins the CPU mining process as well as the speed monitor used to
200 // track hashing metrics. Calling this function when the CPU miner has
201 // already been started will have no effect.
203 // This function is safe for concurrent access.
204 func (m *CPUMiner) Start() {
208 // Nothing to do if the miner is already running
213 m.quit = make(chan struct{})
214 go m.miningWorkerController()
217 log.Infof("CPU miner started")
220 // Stop gracefully stops the mining process by signalling all workers, and the
221 // speed monitor to quit. Calling this function when the CPU miner has not
222 // already been started will have no effect.
224 // This function is safe for concurrent access.
225 func (m *CPUMiner) Stop() {
229 // Nothing to do if the miner is not currently running
236 log.Info("CPU miner stopped")
239 // IsMining returns whether or not the CPU miner has been started and is
240 // therefore currenting mining.
242 // This function is safe for concurrent access.
243 func (m *CPUMiner) IsMining() bool {
250 // SetNumWorkers sets the number of workers to create which solve blocks. Any
251 // negative values will cause a default number of workers to be used which is
252 // based on the number of processor cores in the system. A value of 0 will
253 // cause all CPU mining to be stopped.
255 // This function is safe for concurrent access.
256 func (m *CPUMiner) SetNumWorkers(numWorkers int32) {
261 // Don't lock until after the first check since Stop does its own
266 // Use default if provided value is negative.
268 m.numWorkers = defaultNumWorkers
270 m.numWorkers = uint64(numWorkers)
273 // When the miner is already running, notify the controller about the
276 m.updateNumWorkers <- struct{}{}
280 // NumWorkers returns the number of workers which are running to solve blocks.
282 // This function is safe for concurrent access.
283 func (m *CPUMiner) NumWorkers() int32 {
287 return int32(m.numWorkers)
290 // NewCPUMiner returns a new instance of a CPU miner for the provided configuration.
291 // Use Start to begin the mining process. See the documentation for CPUMiner
292 // type for more details.
293 func NewCPUMiner(c *protocol.Chain, accountManager *account.Manager, txPool *protocol.TxPool, newBlockCh chan *bc.Hash) *CPUMiner {
294 authoritys := make(map[string]string)
296 for index, xpub := range consensus.ActiveNetParams.SignBlockXPubs {
297 pubHash := crypto.Ripemd160(xpub.PublicKey())
298 control, _ := vmutil.P2WPKHProgram([]byte(pubHash))
299 key := hex.EncodeToString(control)
300 authoritys[key] = xpub.String()
301 if accountManager.IsLocalControlProgram(control) {
302 position = uint64(index)
305 c.SetAuthoritys(authoritys)
306 c.SetPosition(position)
309 accountManager: accountManager,
311 numWorkers: defaultNumWorkers,
312 updateNumWorkers: make(chan struct{}),
313 newBlockCh: newBlockCh,
314 Authoritys: authoritys,