OSDN Git Service

modify miner block to propose block (#92)
[bytom/vapor.git] / protocol / protocol.go
1 package protocol
2
3 import (
4         "sync"
5
6         log "github.com/sirupsen/logrus"
7
8         "github.com/vapor/config"
9         "github.com/vapor/event"
10         "github.com/vapor/protocol/bc"
11         "github.com/vapor/protocol/bc/types"
12         "github.com/vapor/protocol/state"
13 )
14
15 const maxProcessBlockChSize = 1024
16
17 // Chain provides functions for working with the Bytom block chain.
18 type Chain struct {
19         index          *state.BlockIndex
20         orphanManage   *OrphanManage
21         txPool         *TxPool
22         store          Store
23         bbft           *bbft
24         processBlockCh chan *processBlockMsg
25
26         cond                 sync.Cond
27         bestNode             *state.BlockNode
28         bestIrreversibleNode *state.BlockNode
29 }
30
31 // NewChain returns a new Chain using store as the underlying storage.
32 func NewChain(store Store, txPool *TxPool, eventDispatcher *event.Dispatcher) (*Chain, error) {
33         c := &Chain{
34                 orphanManage:   NewOrphanManage(),
35                 txPool:         txPool,
36                 store:          store,
37                 processBlockCh: make(chan *processBlockMsg, maxProcessBlockChSize),
38         }
39         c.cond.L = new(sync.Mutex)
40
41         storeStatus := store.GetStoreStatus()
42         if storeStatus == nil {
43                 if err := c.initChainStatus(); err != nil {
44                         return nil, err
45                 }
46                 storeStatus = store.GetStoreStatus()
47         }
48
49         var err error
50         if c.index, err = store.LoadBlockIndex(storeStatus.Height); err != nil {
51                 return nil, err
52         }
53
54         c.bestNode = c.index.GetNode(storeStatus.Hash)
55         c.index.SetMainChain(c.bestNode)
56         c.bbft = newBbft(store, c.index, c.orphanManage, eventDispatcher)
57         go c.blockProcesser()
58         return c, nil
59 }
60
61 func (c *Chain) initChainStatus() error {
62         genesisBlock := config.GenesisBlock()
63         txStatus := bc.NewTransactionStatus()
64         for i := range genesisBlock.Transactions {
65                 if err := txStatus.SetStatus(i, false); err != nil {
66                         return err
67                 }
68         }
69
70         if err := c.store.SaveBlock(genesisBlock, txStatus); err != nil {
71                 return err
72         }
73
74         utxoView := state.NewUtxoViewpoint()
75         bcBlock := types.MapBlock(genesisBlock)
76         if err := utxoView.ApplyBlock(bcBlock, txStatus); err != nil {
77                 return err
78         }
79
80         node, err := state.NewBlockNode(&genesisBlock.BlockHeader, nil)
81         if err != nil {
82                 return err
83         }
84         return c.store.SaveChainStatus(node, node, utxoView, map[uint64]*state.VoteResult{})
85 }
86
87 // BestBlockHeight returns the current height of the blockchain.
88 func (c *Chain) BestBlockHeight() uint64 {
89         c.cond.L.Lock()
90         defer c.cond.L.Unlock()
91         return c.bestNode.Height
92 }
93
94 // BestBlockHash return the hash of the chain tail block
95 func (c *Chain) BestBlockHash() *bc.Hash {
96         c.cond.L.Lock()
97         defer c.cond.L.Unlock()
98         return &c.bestNode.Hash
99 }
100
101 // BestBlockHeader returns the chain tail block
102 func (c *Chain) BestBlockHeader() *types.BlockHeader {
103         node := c.index.BestNode()
104         return node.BlockHeader()
105 }
106
107 // InMainChain checks wheather a block is in the main chain
108 func (c *Chain) InMainChain(hash bc.Hash) bool {
109         return c.index.InMainchain(hash)
110 }
111
112 // This function must be called with mu lock in above level
113 func (c *Chain) setState(node *state.BlockNode, irreversibleNode *state.BlockNode, view *state.UtxoViewpoint, voteMap map[uint64]*state.VoteResult) error {
114         if err := c.store.SaveChainStatus(node, irreversibleNode, view, voteMap); err != nil {
115                 return err
116         }
117
118         c.cond.L.Lock()
119         defer c.cond.L.Unlock()
120
121         if err := c.bbft.UpdateConsensusNodes(node.Height); err != nil {
122                 return err
123         }
124
125         c.index.SetMainChain(node)
126         c.bestNode = node
127         c.bestIrreversibleNode = irreversibleNode
128
129         log.WithFields(log.Fields{"module": logModule, "height": c.bestNode.Height, "hash": c.bestNode.Hash.String()}).Debug("chain best status has been update")
130         c.cond.Broadcast()
131         return nil
132 }
133
134 // BlockWaiter returns a channel that waits for the block at the given height.
135 func (c *Chain) BlockWaiter(height uint64) <-chan struct{} {
136         ch := make(chan struct{}, 1)
137         go func() {
138                 c.cond.L.Lock()
139                 defer c.cond.L.Unlock()
140                 for c.bestNode.Height < height {
141                         c.cond.Wait()
142                 }
143                 ch <- struct{}{}
144         }()
145
146         return ch
147 }
148
149 // GetTxPool return chain txpool.
150 func (c *Chain) GetTxPool() *TxPool {
151         return c.txPool
152 }
153
154 // GetBBFT return chain bbft
155 func (c *Chain) GetBBFT() *bbft {
156         return c.bbft
157 }