OSDN Git Service

fix rollback (#543)
[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         if err = c.setState(targetBlockHeader, setIrrBlockHeader, nil, utxoView, []*state.ConsensusResult{consensusResult.Fork()}); err != nil {
228                 return err
229         }
230
231         for _, block := range deletedBlocks {
232                 hashes, err := c.store.GetBlockHashesByHeight(block.Height)
233                 if err != nil{
234                         return err
235                 }
236
237                 for _, hash := range hashes{
238                         block, err := c.store.GetBlock(hash)
239                         if err != nil{
240                                 return err
241                         }
242
243                         if err := c.store.DeleteBlock(block); err != nil{
244                                 return err
245                         }
246                 }
247         }
248
249         endSeq := state.CalcVoteSeq(targetHeight)
250         for nowSeq := startSeq; nowSeq > endSeq; nowSeq-- {
251                 if err := c.store.DeleteConsensusResult(nowSeq); err != nil {
252                         return err
253                 }
254         }
255
256         return nil
257 }
258
259 func (c *Chain) reorganizeChain(blockHeader *types.BlockHeader) error {
260         attachBlockHeaders, detachBlockHeaders, err := c.calcReorganizeChain(blockHeader, c.bestBlockHeader)
261         if err != nil {
262                 return err
263         }
264
265         utxoView := state.NewUtxoViewpoint()
266         consensusResults := []*state.ConsensusResult{}
267         consensusResult, err := c.getBestConsensusResult()
268         if err != nil {
269                 return err
270         }
271
272         if err = c.syncSubProtocols(); err != nil {
273                 return err
274         }
275
276         txsToRestore := map[bc.Hash]*types.Tx{}
277         for _, detachBlockHeader := range detachBlockHeaders {
278                 b, err := c.detachBlock(detachBlockHeader, consensusResult, utxoView)
279                 if err != nil {
280                         return err
281                 }
282
283                 for _, tx := range b.Transactions {
284                         txsToRestore[tx.ID] = tx
285                 }
286         }
287
288         txsToRemove := map[bc.Hash]*types.Tx{}
289         irrBlockHeader := c.lastIrrBlockHeader
290         for _, attachBlockHeader := range attachBlockHeaders {
291                 attachHash := attachBlockHeader.Hash()
292                 b, err := c.store.GetBlock(&attachHash)
293                 if err != nil {
294                         return err
295                 }
296
297                 attachBlock := types.MapBlock(b)
298                 if err := c.store.GetTransactionsUtxo(utxoView, attachBlock.Transactions); err != nil {
299                         return err
300                 }
301
302                 txStatus, err := c.GetTransactionStatus(&attachBlock.ID)
303                 if err != nil {
304                         return err
305                 }
306
307                 if err := utxoView.ApplyBlock(attachBlock, txStatus); err != nil {
308                         return err
309                 }
310
311                 if err := consensusResult.ApplyBlock(b); err != nil {
312                         return err
313                 }
314
315                 for _, p := range c.subProtocols {
316                         if err := p.ApplyBlock(b); err != nil {
317                                 return errors.Wrap(err, p.Name(), "sub protocol attach block")
318                         }
319                 }
320
321                 if consensusResult.IsFinalize() {
322                         consensusResults = append(consensusResults, consensusResult.Fork())
323                 }
324
325                 if err := c.applyBlockSign(attachBlockHeader); err != nil {
326                         return err
327                 }
328
329                 if c.isIrreversible(attachBlockHeader) && attachBlockHeader.Height > irrBlockHeader.Height {
330                         irrBlockHeader = attachBlockHeader
331                 }
332
333                 for _, tx := range b.Transactions {
334                         if _, ok := txsToRestore[tx.ID]; !ok {
335                                 txsToRemove[tx.ID] = tx
336                         } else {
337                                 delete(txsToRestore, tx.ID)
338                         }
339                 }
340
341                 blockHash := blockHeader.Hash()
342                 log.WithFields(log.Fields{"module": logModule, "height": blockHeader.Height, "hash": blockHash.String()}).Debug("attach from mainchain")
343         }
344
345         if len(detachBlockHeaders) > 0 && detachBlockHeaders[len(detachBlockHeaders)-1].Height <= c.lastIrrBlockHeader.Height && irrBlockHeader.Height <= c.lastIrrBlockHeader.Height {
346                 log.WithField("module", logModule).Warn("rollback block below the height of irreversible block")
347                 return nil
348         }
349
350         consensusResults = append(consensusResults, consensusResult.Fork())
351         if err := c.setState(blockHeader, irrBlockHeader, attachBlockHeaders, utxoView, consensusResults); err != nil {
352                 return err
353         }
354
355         for txHash := range txsToRemove {
356                 c.txPool.RemoveTransaction(&txHash)
357         }
358
359         for _, tx := range txsToRestore {
360                 // the number of restored Tx should be very small or most of time ZERO
361                 // Error returned from validation is ignored, tx could still be lost if validation fails.
362                 // TODO: adjust tx timestamp so that it won't starve in pool.
363                 if _, err := c.validateTx(tx, blockHeader); err != nil {
364                         log.WithFields(log.Fields{"module": logModule, "tx_id": tx.Tx.ID.String(), "error": err}).Info("restore tx fail")
365                 }
366         }
367
368         if len(txsToRestore) > 0 {
369                 log.WithFields(log.Fields{"module": logModule, "num": len(txsToRestore)}).Debug("restore txs back to pool")
370         }
371         return nil
372 }
373
374 // SaveBlock will validate and save block into storage
375 func (c *Chain) saveBlock(block *types.Block) error {
376         if err := c.validateSign(block); err != nil {
377                 return errors.Sub(ErrBadBlock, err)
378         }
379
380         parent, err := c.store.GetBlockHeader(&block.PreviousBlockHash)
381         if err != nil {
382                 return err
383         }
384
385         consensusResult, err := c.GetConsensusResultByHash(&block.PreviousBlockHash)
386         if err != nil {
387                 return err
388         }
389
390         rewards, err := consensusResult.GetCoinbaseRewards(parent.Height)
391         if err != nil {
392                 return err
393         }
394
395         bcBlock := types.MapBlock(block)
396         if err := validation.ValidateBlock(bcBlock, parent, rewards); err != nil {
397                 return errors.Sub(ErrBadBlock, err)
398         }
399
400         for _, p := range c.subProtocols {
401                 if err := p.ValidateBlock(block, bcBlock.TransactionStatus.GetVerifyStatus()); err != nil {
402                         return errors.Wrap(err, "sub protocol save block")
403                 }
404         }
405
406         if err := c.store.SaveBlock(block, bcBlock.TransactionStatus); err != nil {
407                 return err
408         }
409
410         c.orphanManage.Delete(&bcBlock.ID)
411         return nil
412 }
413
414 func (c *Chain) saveSubBlock(block *types.Block) *types.Block {
415         blockHash := block.Hash()
416         prevOrphans, ok := c.orphanManage.GetPrevOrphans(&blockHash)
417         if !ok {
418                 return block
419         }
420
421         bestBlock := block
422         for _, prevOrphan := range prevOrphans {
423                 orphanBlock, ok := c.orphanManage.Get(prevOrphan)
424                 if !ok {
425                         log.WithFields(log.Fields{"module": logModule, "hash": prevOrphan.String()}).Warning("saveSubBlock fail to get block from orphanManage")
426                         continue
427                 }
428                 if err := c.saveBlock(orphanBlock); err != nil {
429                         log.WithFields(log.Fields{"module": logModule, "hash": prevOrphan.String(), "height": orphanBlock.Height}).Warning("saveSubBlock fail to save block")
430                         continue
431                 }
432
433                 if subBestBlock := c.saveSubBlock(orphanBlock); subBestBlock.Height > bestBlock.Height {
434                         bestBlock = subBestBlock
435                 }
436         }
437         return bestBlock
438 }
439
440 type processBlockResponse struct {
441         isOrphan bool
442         err      error
443 }
444
445 type processBlockMsg struct {
446         block *types.Block
447         reply chan processBlockResponse
448 }
449
450 // ProcessBlock is the entry for chain update
451 func (c *Chain) ProcessBlock(block *types.Block) (bool, error) {
452         reply := make(chan processBlockResponse, 1)
453         c.processBlockCh <- &processBlockMsg{block: block, reply: reply}
454         response := <-reply
455         return response.isOrphan, response.err
456 }
457
458 func (c *Chain) blockProcesser() {
459         for msg := range c.processBlockCh {
460                 isOrphan, err := c.processBlock(msg.block)
461                 msg.reply <- processBlockResponse{isOrphan: isOrphan, err: err}
462         }
463 }
464
465 // ProcessBlock is the entry for handle block insert
466 func (c *Chain) processBlock(block *types.Block) (bool, error) {
467         blockHash := block.Hash()
468         if c.BlockExist(&blockHash) {
469                 log.WithFields(log.Fields{"module": logModule, "hash": blockHash.String(), "height": block.Height}).Debug("block has been processed")
470                 return c.orphanManage.BlockExist(&blockHash), nil
471         }
472
473         c.markTransactions(block.Transactions...)
474
475         if _, err := c.store.GetBlockHeader(&block.PreviousBlockHash); err != nil {
476                 c.orphanManage.Add(block)
477                 return true, nil
478         }
479
480         if err := c.saveBlock(block); err != nil {
481                 return false, err
482         }
483
484         bestBlock := c.saveSubBlock(block)
485         bestBlockHeader := &bestBlock.BlockHeader
486
487         c.cond.L.Lock()
488         defer c.cond.L.Unlock()
489         if bestBlockHeader.PreviousBlockHash == c.bestBlockHeader.Hash() {
490                 log.WithFields(log.Fields{"module": logModule}).Debug("append block to the end of mainchain")
491                 return false, c.connectBlock(bestBlock)
492         }
493
494         if bestBlockHeader.Height > c.bestBlockHeader.Height {
495                 log.WithFields(log.Fields{"module": logModule}).Debug("start to reorganize chain")
496                 return false, c.reorganizeChain(bestBlockHeader)
497         }
498         return false, nil
499 }