OSDN Git Service

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