OSDN Git Service

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