8 "github.com/vapor/blockchain/pseudohsm"
10 "github.com/vapor/blockchain/txbuilder"
11 "github.com/vapor/config"
13 log "github.com/sirupsen/logrus"
15 "github.com/vapor/account"
16 "github.com/vapor/common"
17 "github.com/vapor/consensus"
18 engine "github.com/vapor/consensus/consensus"
19 "github.com/vapor/consensus/consensus/dpos"
20 "github.com/vapor/crypto"
21 "github.com/vapor/crypto/ed25519/chainkd"
22 "github.com/vapor/mining"
23 "github.com/vapor/protocol"
24 "github.com/vapor/protocol/bc"
25 "github.com/vapor/protocol/bc/types"
26 "github.com/vapor/protocol/vm/vmutil"
30 maxNonce = ^uint64(0) // 2^64 - 1
36 var ConsensusEngine engine.Engine
38 // Miner creates blocks and searches for proof-of-work values.
42 accountManager *account.Manager
43 txPool *protocol.TxPool
47 workerWg sync.WaitGroup
48 updateNumWorkers chan struct{}
50 newBlockCh chan *bc.Hash
54 func NewMiner(c *protocol.Chain, accountManager *account.Manager, txPool *protocol.TxPool, newBlockCh chan *bc.Hash, engine engine.Engine) *Miner {
55 dpos, ok := engine.(*dpos.Dpos)
57 log.Error("Only the dpos engine was allowed")
60 dpos.Authorize(config.CommonConfig.Consensus.Dpos.Coinbase)
61 c.SetConsensusEngine(dpos)
62 ConsensusEngine = dpos
65 accountManager: accountManager,
67 numWorkers: defaultNumWorkers,
68 updateNumWorkers: make(chan struct{}),
69 newBlockCh: newBlockCh,
74 func (m *Miner) generateProof(block types.Block) (types.Proof, error) {
76 if consensus.ActiveNetParams.Signer == "" {
77 return types.Proof{}, errors.New("Signer is empty")
79 xPrv.UnmarshalText([]byte(consensus.ActiveNetParams.Signer))
80 sign := xPrv.Sign(block.BlockCommitment.TransactionsMerkleRoot.Bytes())
81 pubHash := crypto.Ripemd160(xPrv.XPub().PublicKey())
83 address, _ := common.NewPeginAddressWitnessScriptHash(pubHash, &consensus.ActiveNetParams)
84 control, err := vmutil.P2WPKHProgram([]byte(pubHash))
86 return types.Proof{}, err
88 return types.Proof{Sign: sign, ControlProgram: control, Address: address.ScriptAddress()}, 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 *Miner) generateBlocks(quit chan struct{}) {
108 block, err := mining.NewBlockTemplate(m.chain, m.txPool, m.accountManager, m.engine)
110 log.Errorf("Mining: failed on create NewBlockTemplate: %v", err)
111 time.Sleep(1 * time.Second)
115 time.Sleep(1 * time.Second)
118 block, err = m.engine.Seal(m.chain, block)
120 log.Errorf("Seal, %v", err)
123 m.chain.SetConsensusEngine(m.engine)
124 if isOrphan, err := m.chain.ProcessBlock(block); err == nil {
125 log.WithFields(log.Fields{
126 "height": block.BlockHeader.Height,
127 "isOrphan": isOrphan,
128 "tx": len(block.Transactions),
129 }).Info("Miner processed block")
131 blockHash := block.Hash()
132 m.newBlockCh <- &blockHash
134 log.WithField("height", block.BlockHeader.Height).Errorf("Miner fail on ProcessBlock, %v", err)
137 m.sendConfirmTx(block.Height - 1)
138 time.Sleep(time.Duration(config.CommonConfig.Consensus.Dpos.Period) * time.Second)
144 func (m *Miner) sendConfirmTx(height uint64) error {
146 var assetID bc.AssetID
147 assetID.UnmarshalText([]byte("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"))
149 dpos := account.DopsAction{
150 Accounts: m.accountManager,
151 From: config.CommonConfig.Consensus.Dpos.Coinbase,
156 dpos.AssetId = &assetID
157 builder := txbuilder.NewBuilder(time.Now())
158 if err := dpos.Build(nil, builder); err != nil {
162 tmpl, _, err := builder.Build()
167 var xprv chainkd.XPrv
168 xprv.UnmarshalText([]byte(config.CommonConfig.Consensus.Dpos.XPrv))
169 if err := pseudohsm.SignWithKey(tmpl, xprv); err != nil {
173 if err := txbuilder.FinalizeTx(nil, m.chain, tmpl.Transaction); err != nil {
180 // miningWorkerController launches the worker goroutines that are used to
181 // generate block templates and solve them. It also provides the ability to
182 // dynamically adjust the number of running worker goroutines.
184 // It must be run as a goroutine.
185 func (m *Miner) miningWorkerController() {
186 // launchWorkers groups common code to launch a specified number of
187 // workers for generating blocks.
188 var runningWorkers []chan struct{}
189 launchWorkers := func(numWorkers uint64) {
190 for i := uint64(0); i < numWorkers; i++ {
191 quit := make(chan struct{})
192 runningWorkers = append(runningWorkers, quit)
195 go m.generateBlocks(quit)
199 // Launch the current number of workers by default.
200 runningWorkers = make([]chan struct{}, 0, m.numWorkers)
201 launchWorkers(m.numWorkers)
206 // Update the number of running workers.
207 case <-m.updateNumWorkers:
209 numRunning := uint64(len(runningWorkers))
210 if m.numWorkers == numRunning {
215 if m.numWorkers > numRunning {
216 launchWorkers(m.numWorkers - numRunning)
220 // Signal the most recently created goroutines to exit.
221 for i := numRunning - 1; i >= m.numWorkers; i-- {
222 close(runningWorkers[i])
223 runningWorkers[i] = nil
224 runningWorkers = runningWorkers[:i]
228 for _, quit := range runningWorkers {
238 // Start begins the CPU mining process as well as the speed monitor used to
239 // track hashing metrics. Calling this function when the CPU miner has
240 // already been started will have no effect.
242 // This function is safe for concurrent access.
243 func (m *Miner) Start() {
247 // Nothing to do if the miner is already running
252 m.quit = make(chan struct{})
253 go m.miningWorkerController()
256 log.Infof("CPU miner started")
259 // Stop gracefully stops the mining process by signalling all workers, and the
260 // speed monitor to quit. Calling this function when the CPU miner has not
261 // already been started will have no effect.
263 // This function is safe for concurrent access.
264 func (m *Miner) Stop() {
268 // Nothing to do if the miner is not currently running
275 log.Info("CPU miner stopped")
278 // IsMining returns whether or not the CPU miner has been started and is
279 // therefore currenting mining.
281 // This function is safe for concurrent access.
282 func (m *Miner) IsMining() bool {
289 // SetNumWorkers sets the number of workers to create which solve blocks. Any
290 // negative values will cause a default number of workers to be used which is
291 // based on the number of processor cores in the system. A value of 0 will
292 // cause all CPU mining to be stopped.
294 // This function is safe for concurrent access.
295 func (m *Miner) SetNumWorkers(numWorkers int32) {
300 // Don't lock until after the first check since Stop does its own
305 // Use default if provided value is negative.
307 m.numWorkers = defaultNumWorkers
309 m.numWorkers = uint64(numWorkers)
312 // When the miner is already running, notify the controller about the
315 m.updateNumWorkers <- struct{}{}
319 // NumWorkers returns the number of workers which are running to solve blocks.
321 // This function is safe for concurrent access.
322 func (m *Miner) NumWorkers() int32 {
326 return int32(m.numWorkers)