OSDN Git Service

862c01ae09df694bd28b70aee81faa4add7cb9f1
[bytom/vapor.git] / protocol / block.go
1 package protocol
2
3 import (
4         log "github.com/sirupsen/logrus"
5
6         "github.com/bytom/vapor/errors"
7         "github.com/bytom/vapor/protocol/bc"
8         "github.com/bytom/vapor/protocol/bc/types"
9         "github.com/bytom/vapor/protocol/state"
10         "github.com/bytom/vapor/protocol/validation"
11 )
12
13 var (
14         // ErrBadBlock is returned when a block is invalid.
15         ErrBadBlock = errors.New("invalid block")
16         // ErrBadStateRoot is returned when the computed assets merkle root
17         // disagrees with the one declared in a block header.
18         ErrBadStateRoot = errors.New("invalid state merkle root")
19 )
20
21 // BlockExist check is a block in chain or orphan
22 func (c *Chain) BlockExist(hash *bc.Hash) bool {
23         if _, err := c.store.GetBlockHeader(hash); err == nil {
24                 return true
25         }
26         return c.orphanManage.BlockExist(hash)
27 }
28
29 // GetBlockByHash return a block by given hash
30 func (c *Chain) GetBlockByHash(hash *bc.Hash) (*types.Block, error) {
31         return c.store.GetBlock(hash)
32 }
33
34 // GetBlockByHeight return a block by given height
35 func (c *Chain) GetBlockByHeight(height uint64) (*types.Block, error) {
36         hash, err := c.store.GetMainChainHash(height)
37         if err != nil {
38                 return nil, errors.Wrap(err, "can't find block in given height")
39         }
40         return c.store.GetBlock(hash)
41 }
42
43 // GetHeaderByHash return a block header by given hash
44 func (c *Chain) GetHeaderByHash(hash *bc.Hash) (*types.BlockHeader, error) {
45         return c.store.GetBlockHeader(hash)
46 }
47
48 // GetHeaderByHeight return a block header by given height
49 func (c *Chain) GetHeaderByHeight(height uint64) (*types.BlockHeader, error) {
50         hash, err := c.store.GetMainChainHash(height)
51         if err != nil {
52                 return nil, errors.Wrap(err, "can't find block header in given height")
53         }
54         return c.store.GetBlockHeader(hash)
55 }
56
57 func (c *Chain) calcReorganizeChain(beginAttach *types.BlockHeader, beginDetach *types.BlockHeader) ([]*types.BlockHeader, []*types.BlockHeader, error) {
58         var err error
59         var attachBlockHeaders []*types.BlockHeader
60         var detachBlockHeaders []*types.BlockHeader
61
62         for attachBlockHeader, detachBlockHeader := beginAttach, beginDetach; detachBlockHeader.Hash() != attachBlockHeader.Hash(); {
63                 var attachRollback, detachRollBack bool
64                 if attachRollback = attachBlockHeader.Height >= detachBlockHeader.Height; attachRollback {
65                         attachBlockHeaders = append([]*types.BlockHeader{attachBlockHeader}, attachBlockHeaders...)
66                 }
67
68                 if detachRollBack = attachBlockHeader.Height <= detachBlockHeader.Height; detachRollBack {
69                         detachBlockHeaders = append(detachBlockHeaders, detachBlockHeader)
70                 }
71
72                 if attachRollback {
73                         attachBlockHeader, err = c.store.GetBlockHeader(&attachBlockHeader.PreviousBlockHash)
74                         if err != nil {
75                                 return nil, nil, err
76                         }
77                 }
78
79                 if detachRollBack {
80                         detachBlockHeader, err = c.store.GetBlockHeader(&detachBlockHeader.PreviousBlockHash)
81                         if err != nil {
82                                 return nil, nil, err
83                         }
84                 }
85         }
86         return attachBlockHeaders, detachBlockHeaders, nil
87 }
88
89 func (c *Chain) connectBlock(block *types.Block) (err error) {
90         bcBlock := types.MapBlock(block)
91         if bcBlock.TransactionStatus, err = c.store.GetTransactionStatus(&bcBlock.ID); err != nil {
92                 return err
93         }
94
95         utxoView := state.NewUtxoViewpoint()
96         if err := c.store.GetTransactionsUtxo(utxoView, bcBlock.Transactions); err != nil {
97                 return err
98         }
99         if err := utxoView.ApplyBlock(bcBlock, bcBlock.TransactionStatus); err != nil {
100                 return err
101         }
102
103         consensusResult, err := c.getBestConsensusResult()
104         if err != nil {
105                 return err
106         }
107
108         if err := consensusResult.ApplyBlock(block); err != nil {
109                 return err
110         }
111
112         for _, p := range c.subProtocols {
113                 if err := c.syncProtocolStatus(p); err != nil {
114                         return errors.Wrap(err, p.Name(), "sync sub protocol status")
115                 }
116
117                 if err := p.ApplyBlock(block); err != nil {
118                         return errors.Wrap(err, p.Name(), "sub protocol connect block")
119                 }
120         }
121
122         if err := c.applyBlockSign(&block.BlockHeader); err != nil {
123                 return err
124         }
125
126         irrBlockHeader := c.lastIrrBlockHeader
127         if c.isIrreversible(&block.BlockHeader) && block.Height > irrBlockHeader.Height {
128                 irrBlockHeader = &block.BlockHeader
129         }
130
131         if err := c.setState(&block.BlockHeader, irrBlockHeader, []*types.BlockHeader{&block.BlockHeader}, utxoView, []*state.ConsensusResult{consensusResult}); err != nil {
132                 return err
133         }
134
135         for _, tx := range block.Transactions {
136                 c.txPool.RemoveTransaction(&tx.Tx.ID)
137         }
138         return nil
139 }
140
141 func (c *Chain) detachBlock(detachBlockHeader *types.BlockHeader, consensusResult *state.ConsensusResult, utxoView *state.UtxoViewpoint) (*types.Block, error) {
142         detachHash := detachBlockHeader.Hash()
143         block, err := c.store.GetBlock(&detachHash)
144         if err != nil {
145                 return block, err
146         }
147
148         detachBlock := types.MapBlock(block)
149         if err := consensusResult.DetachBlock(block); err != nil {
150                 return block, err
151         }
152
153         if err := c.store.GetTransactionsUtxo(utxoView, detachBlock.Transactions); err != nil {
154                 return block, err
155         }
156
157         txStatus, err := c.GetTransactionStatus(&detachBlock.ID)
158         if err != nil {
159                 return block, err
160         }
161
162         if err := utxoView.DetachBlock(detachBlock, txStatus); err != nil {
163                 return block, err
164         }
165
166         for _, p := range c.subProtocols {
167                 if err := p.DetachBlock(block); err != nil {
168                         return block, errors.Wrap(err, p.Name(), "sub protocol detach block")
169                 }
170         }
171
172         log.WithFields(log.Fields{"module": logModule, "height": detachBlockHeader.Height, "hash": detachHash.String()}).Debug("detach from mainchain")
173         return block, nil
174 }
175
176 func (c *Chain) syncSubProtocols() error {
177         for _, p := range c.subProtocols {
178                 if err := c.syncProtocolStatus(p); err != nil {
179                         return errors.Wrap(err, p.Name(), "sync sub protocol status")
180                 }
181         }
182         return nil
183 }
184
185 // Rollback rollback the chain from one blockHeight to targetBlockHeight
186 // WARNING: we recommend to use this only in commond line
187 func (c *Chain) Rollback(targetHeight uint64) error {
188         c.cond.L.Lock()
189         defer c.cond.L.Unlock()
190
191         utxoView := state.NewUtxoViewpoint()
192         consensusResult, err := c.getBestConsensusResult()
193         if err != nil {
194                 return err
195         }
196
197         if err = c.syncSubProtocols(); err != nil {
198                 return err
199         }
200
201         targetBlockHeader, err := c.GetHeaderByHeight(targetHeight)
202         if err != nil {
203                 return err
204         }
205
206         _, deletedBlockHeaders, err := c.calcReorganizeChain(targetBlockHeader, c.bestBlockHeader)
207         if err != nil {
208                 return err
209         }
210
211         deletedBlocks := []*types.Block{}
212         for _, deletedBlockHeader := range deletedBlockHeaders {
213                 block, err := c.detachBlock(deletedBlockHeader, consensusResult, utxoView)
214                 if err != nil {
215                         return err
216                 }
217
218                 deletedBlocks = append(deletedBlocks, block)
219         }
220
221         setIrrBlockHeader := c.lastIrrBlockHeader
222         if c.lastIrrBlockHeader.Height > targetBlockHeader.Height {
223                 setIrrBlockHeader = targetBlockHeader
224         }
225
226         startSeq := state.CalcVoteSeq(c.bestBlockHeader.Height)
227
228         if err = c.setState(targetBlockHeader, setIrrBlockHeader, nil, utxoView, []*state.ConsensusResult{consensusResult.Fork()}); err != nil {
229                 return err
230         }
231
232         for _, block := range deletedBlocks {
233                 if err := c.store.DeleteBlock(block); err != nil {
234                         return err
235                 }
236         }
237
238         endSeq := state.CalcVoteSeq(targetHeight)
239         for nowSeq := startSeq; nowSeq > endSeq; nowSeq-- {
240                 if err := c.store.DeleteConsensusResult(nowSeq); err != nil {
241                         return err
242                 }
243         }
244
245         return nil
246 }
247
248 func (c *Chain) reorganizeChain(blockHeader *types.BlockHeader) error {
249         attachBlockHeaders, detachBlockHeaders, err := c.calcReorganizeChain(blockHeader, c.bestBlockHeader)
250         if err != nil {
251                 return err
252         }
253
254         utxoView := state.NewUtxoViewpoint()
255         consensusResults := []*state.ConsensusResult{}
256         consensusResult, err := c.getBestConsensusResult()
257         if err != nil {
258                 return err
259         }
260
261         if err = c.syncSubProtocols(); err != nil {
262                 return err
263         }
264
265         txsToRestore := map[bc.Hash]*types.Tx{}
266         for _, detachBlockHeader := range detachBlockHeaders {
267                 b, err := c.detachBlock(detachBlockHeader, consensusResult, utxoView)
268                 if err != nil {
269                         return err
270                 }
271
272                 for _, tx := range b.Transactions {
273                         txsToRestore[tx.ID] = tx
274                 }
275         }
276
277         txsToRemove := map[bc.Hash]*types.Tx{}
278         irrBlockHeader := c.lastIrrBlockHeader
279         for _, attachBlockHeader := range attachBlockHeaders {
280                 attachHash := attachBlockHeader.Hash()
281                 b, err := c.store.GetBlock(&attachHash)
282                 if err != nil {
283                         return err
284                 }
285
286                 attachBlock := types.MapBlock(b)
287                 if err := c.store.GetTransactionsUtxo(utxoView, attachBlock.Transactions); err != nil {
288                         return err
289                 }
290
291                 txStatus, err := c.GetTransactionStatus(&attachBlock.ID)
292                 if err != nil {
293                         return err
294                 }
295
296                 if err := utxoView.ApplyBlock(attachBlock, txStatus); err != nil {
297                         return err
298                 }
299
300                 if err := consensusResult.ApplyBlock(b); err != nil {
301                         return err
302                 }
303
304                 for _, p := range c.subProtocols {
305                         if err := p.ApplyBlock(b); err != nil {
306                                 return errors.Wrap(err, p.Name(), "sub protocol attach block")
307                         }
308                 }
309
310                 if consensusResult.IsFinalize() {
311                         consensusResults = append(consensusResults, consensusResult.Fork())
312                 }
313
314                 if err := c.applyBlockSign(attachBlockHeader); err != nil {
315                         return err
316                 }
317
318                 if c.isIrreversible(attachBlockHeader) && attachBlockHeader.Height > irrBlockHeader.Height {
319                         irrBlockHeader = attachBlockHeader
320                 }
321
322                 for _, tx := range b.Transactions {
323                         if _, ok := txsToRestore[tx.ID]; !ok {
324                                 txsToRemove[tx.ID] = tx
325                         } else {
326                                 delete(txsToRestore, tx.ID)
327                         }
328                 }
329
330                 blockHash := blockHeader.Hash()
331                 log.WithFields(log.Fields{"module": logModule, "height": blockHeader.Height, "hash": blockHash.String()}).Debug("attach from mainchain")
332         }
333
334         if len(detachBlockHeaders) > 0 && detachBlockHeaders[len(detachBlockHeaders)-1].Height <= c.lastIrrBlockHeader.Height && irrBlockHeader.Height <= c.lastIrrBlockHeader.Height {
335                 log.WithField("module", logModule).Warn("rollback block below the height of irreversible block")
336                 return nil
337         }
338
339         consensusResults = append(consensusResults, consensusResult.Fork())
340         if err := c.setState(blockHeader, irrBlockHeader, attachBlockHeaders, utxoView, consensusResults); err != nil {
341                 return err
342         }
343
344         for txHash := range txsToRemove {
345                 c.txPool.RemoveTransaction(&txHash)
346         }
347
348         for _, tx := range txsToRestore {
349                 // the number of restored Tx should be very small or most of time ZERO
350                 // Error returned from validation is ignored, tx could still be lost if validation fails.
351                 // TODO: adjust tx timestamp so that it won't starve in pool.
352                 if _, err := c.validateTx(tx, blockHeader); err != nil {
353                         log.WithFields(log.Fields{"module": logModule, "tx_id": tx.Tx.ID.String(), "error": err}).Info("restore tx fail")
354                 }
355         }
356
357         if len(txsToRestore) > 0 {
358                 log.WithFields(log.Fields{"module": logModule, "num": len(txsToRestore)}).Debug("restore txs back to pool")
359         }
360         return nil
361 }
362
363 // SaveBlock will validate and save block into storage
364 func (c *Chain) saveBlock(block *types.Block) error {
365         if err := c.validateSign(block); err != nil {
366                 return errors.Sub(ErrBadBlock, err)
367         }
368
369         parent, err := c.store.GetBlockHeader(&block.PreviousBlockHash)
370         if err != nil {
371                 return err
372         }
373
374         consensusResult, err := c.GetConsensusResultByHash(&block.PreviousBlockHash)
375         if err != nil {
376                 return err
377         }
378
379         rewards, err := consensusResult.GetCoinbaseRewards(parent.Height)
380         if err != nil {
381                 return err
382         }
383
384         bcBlock := types.MapBlock(block)
385         if err := validation.ValidateBlock(bcBlock, parent, rewards); err != nil {
386                 return errors.Sub(ErrBadBlock, err)
387         }
388
389         for _, p := range c.subProtocols {
390                 if err := p.ValidateBlock(block, bcBlock.TransactionStatus.GetVerifyStatus()); err != nil {
391                         return errors.Wrap(err, "sub protocol save block")
392                 }
393         }
394
395         if err := c.store.SaveBlock(block, bcBlock.TransactionStatus); err != nil {
396                 return err
397         }
398
399         c.orphanManage.Delete(&bcBlock.ID)
400         return nil
401 }
402
403 func (c *Chain) saveSubBlock(block *types.Block) *types.Block {
404         blockHash := block.Hash()
405         prevOrphans, ok := c.orphanManage.GetPrevOrphans(&blockHash)
406         if !ok {
407                 return block
408         }
409
410         bestBlock := block
411         for _, prevOrphan := range prevOrphans {
412                 orphanBlock, ok := c.orphanManage.Get(prevOrphan)
413                 if !ok {
414                         log.WithFields(log.Fields{"module": logModule, "hash": prevOrphan.String()}).Warning("saveSubBlock fail to get block from orphanManage")
415                         continue
416                 }
417                 if err := c.saveBlock(orphanBlock); err != nil {
418                         log.WithFields(log.Fields{"module": logModule, "hash": prevOrphan.String(), "height": orphanBlock.Height}).Warning("saveSubBlock fail to save block")
419                         continue
420                 }
421
422                 if subBestBlock := c.saveSubBlock(orphanBlock); subBestBlock.Height > bestBlock.Height {
423                         bestBlock = subBestBlock
424                 }
425         }
426         return bestBlock
427 }
428
429 type processBlockResponse struct {
430         isOrphan bool
431         err      error
432 }
433
434 type processBlockMsg struct {
435         block *types.Block
436         reply chan processBlockResponse
437 }
438
439 // ProcessBlock is the entry for chain update
440 func (c *Chain) ProcessBlock(block *types.Block) (bool, error) {
441         reply := make(chan processBlockResponse, 1)
442         c.processBlockCh <- &processBlockMsg{block: block, reply: reply}
443         response := <-reply
444         return response.isOrphan, response.err
445 }
446
447 func (c *Chain) blockProcesser() {
448         for msg := range c.processBlockCh {
449                 isOrphan, err := c.processBlock(msg.block)
450                 msg.reply <- processBlockResponse{isOrphan: isOrphan, err: err}
451         }
452 }
453
454 // ProcessBlock is the entry for handle block insert
455 func (c *Chain) processBlock(block *types.Block) (bool, error) {
456         blockHash := block.Hash()
457         if c.BlockExist(&blockHash) {
458                 log.WithFields(log.Fields{"module": logModule, "hash": blockHash.String(), "height": block.Height}).Debug("block has been processed")
459                 return c.orphanManage.BlockExist(&blockHash), nil
460         }
461
462         c.markTransactions(block.Transactions...)
463
464         if _, err := c.store.GetBlockHeader(&block.PreviousBlockHash); err != nil {
465                 c.orphanManage.Add(block)
466                 return true, nil
467         }
468
469         if err := c.saveBlock(block); err != nil {
470                 return false, err
471         }
472
473         bestBlock := c.saveSubBlock(block)
474         bestBlockHeader := &bestBlock.BlockHeader
475
476         c.cond.L.Lock()
477         defer c.cond.L.Unlock()
478         if bestBlockHeader.PreviousBlockHash == c.bestBlockHeader.Hash() {
479                 log.WithFields(log.Fields{"module": logModule}).Debug("append block to the end of mainchain")
480                 return false, c.connectBlock(bestBlock)
481         }
482
483         if bestBlockHeader.Height > c.bestBlockHeader.Height {
484                 log.WithFields(log.Fields{"module": logModule}).Debug("start to reorganize chain")
485                 return false, c.reorganizeChain(bestBlockHeader)
486         }
487         return false, nil
488 }