OSDN Git Service

Mov (#518)
[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 &&
335                 detachBlockHeaders[len(detachBlockHeaders)-1].Height <= c.lastIrrBlockHeader.Height &&
336                 irrBlockHeader.Height <= c.lastIrrBlockHeader.Height {
337                 return errors.New("rollback block below the height of irreversible block")
338         }
339
340         consensusResults = append(consensusResults, consensusResult.Fork())
341         if err := c.setState(blockHeader, irrBlockHeader, attachBlockHeaders, utxoView, consensusResults); err != nil {
342                 return err
343         }
344
345         for txHash := range txsToRemove {
346                 c.txPool.RemoveTransaction(&txHash)
347         }
348
349         for _, tx := range txsToRestore {
350                 // the number of restored Tx should be very small or most of time ZERO
351                 // Error returned from validation is ignored, tx could still be lost if validation fails.
352                 // TODO: adjust tx timestamp so that it won't starve in pool.
353                 if _, err := c.validateTx(tx, blockHeader); err != nil {
354                         log.WithFields(log.Fields{"module": logModule, "tx_id": tx.Tx.ID.String(), "error": err}).Info("restore tx fail")
355                 }
356         }
357
358         if len(txsToRestore) > 0 {
359                 log.WithFields(log.Fields{"module": logModule, "num": len(txsToRestore)}).Debug("restore txs back to pool")
360         }
361         return nil
362 }
363
364 // SaveBlock will validate and save block into storage
365 func (c *Chain) saveBlock(block *types.Block) error {
366         if err := c.validateSign(block); err != nil {
367                 return errors.Sub(ErrBadBlock, err)
368         }
369
370         parent, err := c.store.GetBlockHeader(&block.PreviousBlockHash)
371         if err != nil {
372                 return err
373         }
374
375         consensusResult, err := c.GetConsensusResultByHash(&block.PreviousBlockHash)
376         if err != nil {
377                 return err
378         }
379
380         rewards, err := consensusResult.GetCoinbaseRewards(parent.Height)
381         if err != nil {
382                 return err
383         }
384
385         bcBlock := types.MapBlock(block)
386         if err := validation.ValidateBlock(bcBlock, parent, rewards); err != nil {
387                 return errors.Sub(ErrBadBlock, err)
388         }
389
390         for _, p := range c.subProtocols {
391                 if err := p.ValidateBlock(block, bcBlock.TransactionStatus.GetVerifyStatus()); err != nil {
392                         return errors.Wrap(err, "sub protocol save block")
393                 }
394         }
395
396         if err := c.store.SaveBlock(block, bcBlock.TransactionStatus); err != nil {
397                 return err
398         }
399
400         c.orphanManage.Delete(&bcBlock.ID)
401         return nil
402 }
403
404 func (c *Chain) saveSubBlock(block *types.Block) *types.Block {
405         blockHash := block.Hash()
406         prevOrphans, ok := c.orphanManage.GetPrevOrphans(&blockHash)
407         if !ok {
408                 return block
409         }
410
411         bestBlock := block
412         for _, prevOrphan := range prevOrphans {
413                 orphanBlock, ok := c.orphanManage.Get(prevOrphan)
414                 if !ok {
415                         log.WithFields(log.Fields{"module": logModule, "hash": prevOrphan.String()}).Warning("saveSubBlock fail to get block from orphanManage")
416                         continue
417                 }
418                 if err := c.saveBlock(orphanBlock); err != nil {
419                         log.WithFields(log.Fields{"module": logModule, "hash": prevOrphan.String(), "height": orphanBlock.Height}).Warning("saveSubBlock fail to save block")
420                         continue
421                 }
422
423                 if subBestBlock := c.saveSubBlock(orphanBlock); subBestBlock.Height > bestBlock.Height {
424                         bestBlock = subBestBlock
425                 }
426         }
427         return bestBlock
428 }
429
430 type processBlockResponse struct {
431         isOrphan bool
432         err      error
433 }
434
435 type processBlockMsg struct {
436         block *types.Block
437         reply chan processBlockResponse
438 }
439
440 // ProcessBlock is the entry for chain update
441 func (c *Chain) ProcessBlock(block *types.Block) (bool, error) {
442         reply := make(chan processBlockResponse, 1)
443         c.processBlockCh <- &processBlockMsg{block: block, reply: reply}
444         response := <-reply
445         return response.isOrphan, response.err
446 }
447
448 func (c *Chain) blockProcesser() {
449         for msg := range c.processBlockCh {
450                 isOrphan, err := c.processBlock(msg.block)
451                 msg.reply <- processBlockResponse{isOrphan: isOrphan, err: err}
452         }
453 }
454
455 // ProcessBlock is the entry for handle block insert
456 func (c *Chain) processBlock(block *types.Block) (bool, error) {
457         blockHash := block.Hash()
458         if c.BlockExist(&blockHash) {
459                 log.WithFields(log.Fields{"module": logModule, "hash": blockHash.String(), "height": block.Height}).Debug("block has been processed")
460                 return c.orphanManage.BlockExist(&blockHash), nil
461         }
462
463         c.markTransactions(block.Transactions...)
464
465         if _, err := c.store.GetBlockHeader(&block.PreviousBlockHash); err != nil {
466                 c.orphanManage.Add(block)
467                 return true, nil
468         }
469
470         if err := c.saveBlock(block); err != nil {
471                 return false, err
472         }
473
474         bestBlock := c.saveSubBlock(block)
475         bestBlockHeader := &bestBlock.BlockHeader
476
477         c.cond.L.Lock()
478         defer c.cond.L.Unlock()
479         if bestBlockHeader.PreviousBlockHash == c.bestBlockHeader.Hash() {
480                 log.WithFields(log.Fields{"module": logModule}).Debug("append block to the end of mainchain")
481                 return false, c.connectBlock(bestBlock)
482         }
483
484         if bestBlockHeader.Height > c.bestBlockHeader.Height {
485                 log.WithFields(log.Fields{"module": logModule}).Debug("start to reorganize chain")
486                 return false, c.reorganizeChain(bestBlockHeader)
487         }
488         return false, nil
489 }