OSDN Git Service

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