OSDN Git Service

Mov (#518)
[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/bytom/vapor/common"
9         "github.com/bytom/vapor/config"
10         "github.com/bytom/vapor/errors"
11         "github.com/bytom/vapor/event"
12         "github.com/bytom/vapor/protocol/bc"
13         "github.com/bytom/vapor/protocol/bc/types"
14         "github.com/bytom/vapor/protocol/state"
15 )
16
17 const (
18         maxProcessBlockChSize = 1024
19         maxKnownTxs           = 32768 // Maximum transactions hashes to keep in the known list (prevent DOS)
20 )
21
22 // Protocoler is interface for layer 2 consensus protocol
23 type Protocoler interface {
24         Name() string
25         StartHeight() uint64
26         BeforeProposalBlock(txs []*types.Tx, blockHeight uint64, gasLeft int64, isTimeout func() bool) ([]*types.Tx, error)
27         ChainStatus() (uint64, *bc.Hash, error)
28         ValidateBlock(block *types.Block, verifyResults []*bc.TxVerifyResult) error
29         ValidateTx(tx *types.Tx, verifyResult *bc.TxVerifyResult, blockHeight uint64) error
30         ApplyBlock(block *types.Block) error
31         DetachBlock(block *types.Block) error
32 }
33
34 // Chain provides functions for working with the Bytom block chain.
35 type Chain struct {
36         orphanManage   *OrphanManage
37         txPool         *TxPool
38         store          Store
39         processBlockCh chan *processBlockMsg
40         subProtocols   []Protocoler
41
42         signatureCache  *common.Cache
43         eventDispatcher *event.Dispatcher
44
45         cond               sync.Cond
46         bestBlockHeader    *types.BlockHeader // the last block on current main chain
47         lastIrrBlockHeader *types.BlockHeader // the last irreversible block
48
49         knownTxs *common.OrderedSet
50 }
51
52 // NewChain returns a new Chain using store as the underlying storage.
53 func NewChain(store Store, txPool *TxPool, subProtocols []Protocoler, eventDispatcher *event.Dispatcher) (*Chain, error) {
54         knownTxs, _ := common.NewOrderedSet(maxKnownTxs)
55         c := &Chain{
56                 orphanManage:    NewOrphanManage(),
57                 txPool:          txPool,
58                 store:           store,
59                 subProtocols:    subProtocols,
60                 signatureCache:  common.NewCache(maxSignatureCacheSize),
61                 eventDispatcher: eventDispatcher,
62                 processBlockCh:  make(chan *processBlockMsg, maxProcessBlockChSize),
63                 knownTxs:        knownTxs,
64         }
65         c.cond.L = new(sync.Mutex)
66
67         storeStatus := store.GetStoreStatus()
68         if storeStatus == nil {
69                 if err := c.initChainStatus(); err != nil {
70                         return nil, err
71                 }
72                 storeStatus = store.GetStoreStatus()
73         }
74
75         var err error
76         c.bestBlockHeader, err = c.store.GetBlockHeader(storeStatus.Hash)
77         if err != nil {
78                 return nil, err
79         }
80
81         c.lastIrrBlockHeader, err = c.store.GetBlockHeader(storeStatus.IrreversibleHash)
82         if err != nil {
83                 return nil, err
84         }
85
86         for _, p := range c.subProtocols {
87                 if err := c.syncProtocolStatus(p); err != nil {
88                         return nil, errors.Wrap(err, p.Name(), "sync sub protocol status")
89                 }
90         }
91
92         go c.blockProcesser()
93         return c, nil
94 }
95
96 func (c *Chain) initChainStatus() error {
97         genesisBlock := config.GenesisBlock()
98         txStatus := bc.NewTransactionStatus()
99         for i := range genesisBlock.Transactions {
100                 if err := txStatus.SetStatus(i, false); err != nil {
101                         return err
102                 }
103         }
104
105         if err := c.store.SaveBlock(genesisBlock, txStatus); err != nil {
106                 return err
107         }
108
109         utxoView := state.NewUtxoViewpoint()
110         bcBlock := types.MapBlock(genesisBlock)
111         if err := utxoView.ApplyBlock(bcBlock, txStatus); err != nil {
112                 return err
113         }
114
115         for _, subProtocol := range c.subProtocols {
116                 if err := subProtocol.ApplyBlock(genesisBlock); err != nil {
117                         return err
118                 }
119         }
120
121         consensusResults := []*state.ConsensusResult{{
122                 Seq:            0,
123                 NumOfVote:      make(map[string]uint64),
124                 CoinbaseReward: make(map[string]uint64),
125                 BlockHash:      genesisBlock.Hash(),
126                 BlockHeight:    0,
127         }}
128
129         genesisBlockHeader := &genesisBlock.BlockHeader
130         return c.store.SaveChainStatus(genesisBlockHeader, genesisBlockHeader, []*types.BlockHeader{genesisBlockHeader}, utxoView, consensusResults)
131 }
132
133 // BestBlockHeight returns the current height of the blockchain.
134 func (c *Chain) BestBlockHeight() uint64 {
135         c.cond.L.Lock()
136         defer c.cond.L.Unlock()
137         return c.bestBlockHeader.Height
138 }
139
140 // BestBlockHash return the hash of the main chain tail block
141 func (c *Chain) BestBlockHash() *bc.Hash {
142         c.cond.L.Lock()
143         defer c.cond.L.Unlock()
144         bestHash := c.bestBlockHeader.Hash()
145         return &bestHash
146 }
147
148 // LastIrreversibleHeader returns the chain last irreversible block header
149 func (c *Chain) LastIrreversibleHeader() *types.BlockHeader {
150         c.cond.L.Lock()
151         defer c.cond.L.Unlock()
152         return c.lastIrrBlockHeader
153 }
154
155 // BestBlockHeader returns the chain best block header
156 func (c *Chain) BestBlockHeader() *types.BlockHeader {
157         c.cond.L.Lock()
158         defer c.cond.L.Unlock()
159         return c.bestBlockHeader
160 }
161
162 // InMainChain checks wheather a block is in the main chain
163 func (c *Chain) InMainChain(hash bc.Hash) bool {
164         blockHeader, err := c.store.GetBlockHeader(&hash)
165         if err != nil {
166                 return false
167         }
168
169         blockHash, err := c.store.GetMainChainHash(blockHeader.Height)
170         if err != nil {
171                 log.WithFields(log.Fields{"module": logModule, "height": blockHeader.Height}).Debug("not contain block hash in main chain for specified height")
172                 return false
173         }
174         return *blockHash == hash
175 }
176
177 // SubProtocols return list of layer 2 consensus protocol
178 func (c *Chain) SubProtocols() []Protocoler {
179         return c.subProtocols
180 }
181
182 // trace back to the tail of the chain from the given block header
183 func (c *Chain) traceLongestChainTail(blockHeader *types.BlockHeader) (*types.BlockHeader, error) {
184         longestTail, workQueue := blockHeader, []*types.BlockHeader{blockHeader}
185
186         for ; len(workQueue) > 0; workQueue = workQueue[1:] {
187                 currentHeader := workQueue[0]
188                 currentHash := currentHeader.Hash()
189                 hashes, err := c.store.GetBlockHashesByHeight(currentHeader.Height + 1)
190                 if err != nil {
191                         return nil, err
192                 }
193
194                 for _, h := range hashes {
195                         if header, err := c.store.GetBlockHeader(h); err != nil {
196                                 return nil, err
197                         } else if header.PreviousBlockHash == currentHash {
198                                 if longestTail.Height < header.Height {
199                                         longestTail = header
200                                 }
201                                 workQueue = append(workQueue, header)
202                         }
203                 }
204         }
205         return longestTail, nil
206 }
207
208 func (c *Chain) hasSeenTx(tx *types.Tx) bool {
209         return c.knownTxs.Has(tx.ID.String())
210 }
211
212 func (c *Chain) markTransactions(txs ...*types.Tx) {
213         for _, tx := range txs {
214                 c.knownTxs.Add(tx.ID.String())
215         }
216 }
217
218 func (c *Chain) syncProtocolStatus(subProtocol Protocoler) error {
219         if c.bestBlockHeader.Height < subProtocol.StartHeight() {
220                 return nil
221         }
222
223         protocolHeight, protocolHash, err := subProtocol.ChainStatus()
224         if err != nil {
225                 return errors.Wrap(err, "failed on get sub protocol status")
226         }
227
228         if *protocolHash == c.bestBlockHeader.Hash() {
229                 return nil
230         }
231
232         for !c.InMainChain(*protocolHash) {
233                 block, err := c.GetBlockByHash(protocolHash)
234                 if err != nil {
235                         return errors.Wrap(err, subProtocol.Name(), "can't get block by hash in chain")
236                 }
237
238                 if err := subProtocol.DetachBlock(block); err != nil {
239                         return errors.Wrap(err, subProtocol.Name(), "sub protocol detach block err")
240                 }
241
242                 protocolHeight, protocolHash = block.Height-1, &block.PreviousBlockHash
243         }
244
245         for height := protocolHeight + 1; height <= c.bestBlockHeader.Height; height++ {
246                 block, err := c.GetBlockByHeight(height)
247                 if err != nil {
248                         return errors.Wrap(err, subProtocol.Name(), "can't get block by height in chain")
249                 }
250
251                 if err := subProtocol.ApplyBlock(block); err != nil {
252                         return errors.Wrap(err, subProtocol.Name(), "sub protocol apply block err")
253                 }
254
255                 blockHash := block.Hash()
256                 protocolHeight, protocolHash = block.Height, &blockHash
257         }
258
259         return nil
260 }
261
262 // This function must be called with mu lock in above level
263 func (c *Chain) setState(blockHeader, irrBlockHeader *types.BlockHeader, mainBlockHeaders []*types.BlockHeader, view *state.UtxoViewpoint, consensusResults []*state.ConsensusResult) error {
264         if err := c.store.SaveChainStatus(blockHeader, irrBlockHeader, mainBlockHeaders, view, consensusResults); err != nil {
265                 return err
266         }
267
268         c.bestBlockHeader = blockHeader
269         c.lastIrrBlockHeader = irrBlockHeader
270
271         blockHash := blockHeader.Hash()
272         log.WithFields(log.Fields{"module": logModule, "height": blockHeader.Height, "hash": blockHash.String()}).Debug("chain best status has been update")
273         c.cond.Broadcast()
274         return nil
275 }
276
277 // BlockWaiter returns a channel that waits for the block at the given height.
278 func (c *Chain) BlockWaiter(height uint64) <-chan struct{} {
279         ch := make(chan struct{}, 1)
280         go func() {
281                 c.cond.L.Lock()
282                 defer c.cond.L.Unlock()
283                 for c.bestBlockHeader.Height < height {
284                         c.cond.Wait()
285                 }
286                 ch <- struct{}{}
287         }()
288
289         return ch
290 }
291
292 // GetTxPool return chain txpool.
293 func (c *Chain) GetTxPool() *TxPool {
294         return c.txPool
295 }