8 "github.com/vapor/config"
10 log "github.com/sirupsen/logrus"
12 "github.com/vapor/account"
13 "github.com/vapor/common"
14 "github.com/vapor/consensus"
15 engine "github.com/vapor/consensus/consensus"
16 "github.com/vapor/consensus/consensus/dpos"
17 "github.com/vapor/crypto"
18 "github.com/vapor/crypto/ed25519/chainkd"
19 "github.com/vapor/mining"
20 "github.com/vapor/protocol"
21 "github.com/vapor/protocol/bc"
22 "github.com/vapor/protocol/bc/types"
23 "github.com/vapor/protocol/vm/vmutil"
27 maxNonce = ^uint64(0) // 2^64 - 1
33 var ConsensusEngine engine.Engine
35 // Miner creates blocks and searches for proof-of-work values.
39 accountManager *account.Manager
40 txPool *protocol.TxPool
44 workerWg sync.WaitGroup
45 updateNumWorkers chan struct{}
47 newBlockCh chan *bc.Hash
48 Authoritys map[string]string
53 func NewMiner(c *protocol.Chain, accountManager *account.Manager, txPool *protocol.TxPool, newBlockCh chan *bc.Hash, engine engine.Engine) *Miner {
54 authoritys := make(map[string]string)
56 dpos, ok := engine.(*dpos.Dpos)
58 log.Error("Only the dpos engine was allowed")
61 dpos.Authorize(config.CommonConfig.Consensus.Dpos.Coinbase)
63 for index, xpub := range consensus.ActiveNetParams.SignBlockXPubs {
64 pubHash := crypto.Ripemd160(xpub.PublicKey())
65 address, _ := common.NewPeginAddressWitnessScriptHash(pubHash, &consensus.ActiveNetParams)
66 control, _ := vmutil.P2WPKHProgram([]byte(pubHash))
67 //key := hex.EncodeToString(control)
68 //authoritys[key] = xpub.String()
69 authoritys[address.EncodeAddress()] = xpub.String()
70 if accountManager.IsLocalControlProgram(control) {
71 position = uint64(index)
72 dpos.Authorize(address.EncodeAddress())
76 //c.SetAuthoritys(authoritys)
77 //c.SetPosition(position)
78 c.SetConsensusEngine(dpos)
79 ConsensusEngine = dpos
82 accountManager: accountManager,
84 numWorkers: defaultNumWorkers,
85 updateNumWorkers: make(chan struct{}),
86 newBlockCh: newBlockCh,
87 Authoritys: authoritys,
93 func (m *Miner) generateProof(block types.Block) (types.Proof, error) {
95 if consensus.ActiveNetParams.Signer == "" {
96 return types.Proof{}, errors.New("Signer is empty")
98 xPrv.UnmarshalText([]byte(consensus.ActiveNetParams.Signer))
99 sign := xPrv.Sign(block.BlockCommitment.TransactionsMerkleRoot.Bytes())
100 pubHash := crypto.Ripemd160(xPrv.XPub().PublicKey())
102 address, _ := common.NewPeginAddressWitnessScriptHash(pubHash, &consensus.ActiveNetParams)
103 control, err := vmutil.P2WPKHProgram([]byte(pubHash))
105 return types.Proof{}, err
107 return types.Proof{Sign: sign, ControlProgram: control, Address: address.ScriptAddress()}, nil
110 // generateBlocks is a worker that is controlled by the miningWorkerController.
111 // It is self contained in that it creates block templates and attempts to solve
112 // them while detecting when it is performing stale work and reacting
113 // accordingly by generating a new block template. When a block is solved, it
116 // It must be run as a goroutine.
117 func (m *Miner) generateBlocks(quit chan struct{}) {
118 ticker := time.NewTicker(time.Second * hashUpdateSecs)
129 engine, ok := m.engine.(*dpos.Dpos)
131 log.Error("Only the dpos engine was allowed")
135 header := m.chain.BestBlockHeader()
136 isSeal, err := engine.IsSealer(m.chain, header.Hash(), header, uint64(time.Now().Unix()))
138 log.WithFields(log.Fields{"module": module, "error": err}).Error("Determine whether seal is wrong")
144 block, err := mining.NewBlockTemplate1(m.chain, m.txPool, m.accountManager, m.engine)
146 log.Errorf("Mining: failed on create NewBlockTemplate: %v", err)
147 time.Sleep(3 * time.Second)
151 time.Sleep(3 * time.Second)
154 block, err = m.engine.Seal(m.chain, block)
156 log.Errorf("Seal, %v", err)
159 m.chain.SetConsensusEngine(m.engine)
160 if isOrphan, err := m.chain.ProcessBlock(block); err == nil {
161 log.WithFields(log.Fields{
162 "height": block.BlockHeader.Height,
163 "isOrphan": isOrphan,
164 "tx": len(block.Transactions),
165 }).Info("Miner processed block")
167 blockHash := block.Hash()
168 m.newBlockCh <- &blockHash
170 log.WithField("height", block.BlockHeader.Height).Errorf("Miner fail on ProcessBlock, %v", err)
173 time.Sleep(3 * time.Second)
179 // miningWorkerController launches the worker goroutines that are used to
180 // generate block templates and solve them. It also provides the ability to
181 // dynamically adjust the number of running worker goroutines.
183 // It must be run as a goroutine.
184 func (m *Miner) miningWorkerController() {
185 // launchWorkers groups common code to launch a specified number of
186 // workers for generating blocks.
187 var runningWorkers []chan struct{}
188 launchWorkers := func(numWorkers uint64) {
189 for i := uint64(0); i < numWorkers; i++ {
190 quit := make(chan struct{})
191 runningWorkers = append(runningWorkers, quit)
194 go m.generateBlocks(quit)
198 // Launch the current number of workers by default.
199 runningWorkers = make([]chan struct{}, 0, m.numWorkers)
200 launchWorkers(m.numWorkers)
205 // Update the number of running workers.
206 case <-m.updateNumWorkers:
208 numRunning := uint64(len(runningWorkers))
209 if m.numWorkers == numRunning {
214 if m.numWorkers > numRunning {
215 launchWorkers(m.numWorkers - numRunning)
219 // Signal the most recently created goroutines to exit.
220 for i := numRunning - 1; i >= m.numWorkers; i-- {
221 close(runningWorkers[i])
222 runningWorkers[i] = nil
223 runningWorkers = runningWorkers[:i]
227 for _, quit := range runningWorkers {
237 // Start begins the CPU mining process as well as the speed monitor used to
238 // track hashing metrics. Calling this function when the CPU miner has
239 // already been started will have no effect.
241 // This function is safe for concurrent access.
242 func (m *Miner) Start() {
246 // Nothing to do if the miner is already running
251 m.quit = make(chan struct{})
252 go m.miningWorkerController()
255 log.Infof("CPU miner started")
258 // Stop gracefully stops the mining process by signalling all workers, and the
259 // speed monitor to quit. Calling this function when the CPU miner has not
260 // already been started will have no effect.
262 // This function is safe for concurrent access.
263 func (m *Miner) Stop() {
267 // Nothing to do if the miner is not currently running
274 log.Info("CPU miner stopped")
277 // IsMining returns whether or not the CPU miner has been started and is
278 // therefore currenting mining.
280 // This function is safe for concurrent access.
281 func (m *Miner) IsMining() bool {
288 // SetNumWorkers sets the number of workers to create which solve blocks. Any
289 // negative values will cause a default number of workers to be used which is
290 // based on the number of processor cores in the system. A value of 0 will
291 // cause all CPU mining to be stopped.
293 // This function is safe for concurrent access.
294 func (m *Miner) SetNumWorkers(numWorkers int32) {
299 // Don't lock until after the first check since Stop does its own
304 // Use default if provided value is negative.
306 m.numWorkers = defaultNumWorkers
308 m.numWorkers = uint64(numWorkers)
311 // When the miner is already running, notify the controller about the
314 m.updateNumWorkers <- struct{}{}
318 // NumWorkers returns the number of workers which are running to solve blocks.
320 // This function is safe for concurrent access.
321 func (m *Miner) NumWorkers() int32 {
325 return int32(m.numWorkers)