OSDN Git Service

edit api for get-work and submit work (#507)
[bytom/bytom.git] / mining / miningpool / minepool.go
1 package miningpool
2
3 import (
4         "errors"
5         "sync"
6         "time"
7
8         log "github.com/sirupsen/logrus"
9
10         "github.com/bytom/account"
11         "github.com/bytom/mining"
12         "github.com/bytom/protocol"
13         "github.com/bytom/protocol/bc"
14         "github.com/bytom/protocol/bc/types"
15 )
16
17 const blockUpdateMS = 1000
18
19 // MiningPool is the support struct for p2p mine pool
20 type MiningPool struct {
21         mutex sync.RWMutex
22         block *types.Block
23
24         chain          *protocol.Chain
25         accountManager *account.Manager
26         txPool         *protocol.TxPool
27         newBlockCh     chan *bc.Hash
28 }
29
30 // NewMiningPool will create a new MiningPool
31 func NewMiningPool(c *protocol.Chain, accountManager *account.Manager, txPool *protocol.TxPool, newBlockCh chan *bc.Hash) *MiningPool {
32         m := &MiningPool{
33                 chain:          c,
34                 accountManager: accountManager,
35                 txPool:         txPool,
36                 newBlockCh:     newBlockCh,
37         }
38         go m.blockUpdater()
39         return m
40 }
41
42 // blockUpdater is the goroutine for keep update mining block
43 func (m *MiningPool) blockUpdater() {
44         ticker := time.NewTicker(time.Millisecond * blockUpdateMS)
45         for _ = range ticker.C {
46                 m.generateBlock()
47         }
48 }
49
50 func (m *MiningPool) generateBlock() {
51         m.mutex.Lock()
52         defer m.mutex.Unlock()
53         if m.block != nil && *m.chain.BestBlockHash() == m.block.PreviousBlockHash {
54                 m.block.Timestamp = uint64(time.Now().Unix())
55                 return
56         }
57
58         block, err := mining.NewBlockTemplate(m.chain, m.txPool, m.accountManager)
59         if err != nil {
60                 log.Errorf("miningpool: failed on create NewBlockTemplate: %v", err)
61                 return
62         }
63
64         m.block = block
65 }
66
67 // GetWork will return a block header for p2p mining
68 func (m *MiningPool) GetWork() (*types.BlockHeader, error) {
69         if m.block != nil {
70                 m.mutex.RLock()
71                 defer m.mutex.RUnlock()
72                 bh := m.block.BlockHeader
73                 return &bh, nil
74         }
75         return nil, errors.New("no block is ready for mining")
76 }
77
78 // SubmitWork will try to submit the result to the blockchain
79 func (m *MiningPool) SubmitWork(bh *types.BlockHeader) error {
80         m.mutex.Lock()
81         defer m.mutex.Unlock()
82
83         if m.block == nil || bh.PreviousBlockHash != m.block.PreviousBlockHash {
84                 return errors.New("pending mining block has been changed")
85         }
86
87         m.block.Nonce = bh.Nonce
88         m.block.Timestamp = bh.Timestamp
89         isOrphan, err := m.chain.ProcessBlock(m.block)
90         if err != nil {
91                 return err
92         }
93
94         if isOrphan {
95                 log.Warning("SubmitWork is orphan")
96         }
97
98         blockHash := bh.Hash()
99         m.newBlockCh <- &blockHash
100         return nil
101 }