OSDN Git Service

088bcc15b10bfe76fab57ff9d1050a1ce1b1bd6e
[bytom/bytom.git] / protocol / block.go
1 package protocol
2
3 import (
4         "encoding/hex"
5
6         log "github.com/sirupsen/logrus"
7
8         "github.com/bytom/bytom/errors"
9         "github.com/bytom/bytom/event"
10         "github.com/bytom/bytom/protocol/bc"
11         "github.com/bytom/bytom/protocol/bc/types"
12         "github.com/bytom/bytom/protocol/state"
13         "github.com/bytom/bytom/protocol/validation"
14 )
15
16 var (
17         // ErrBadBlock is returned when a block is invalid.
18         ErrBadBlock = errors.New("invalid block")
19         // ErrBadStateRoot is returned when the computed assets merkle root
20         // disagrees with the one declared in a block header.
21         ErrBadStateRoot = errors.New("invalid state merkle root")
22 )
23
24 // BlockExist check is a block in chain or orphan
25 func (c *Chain) BlockExist(hash *bc.Hash) bool {
26         if _, err := c.store.GetBlockHeader(hash); err == nil {
27                 return true
28         }
29
30         return c.orphanManage.BlockExist(hash)
31 }
32
33 // GetBlockByHash return a block by given hash
34 func (c *Chain) GetBlockByHash(hash *bc.Hash) (*types.Block, error) {
35         return c.store.GetBlock(hash)
36 }
37
38 // GetBlockByHeight return a block header by given height
39 func (c *Chain) GetBlockByHeight(height uint64) (*types.Block, error) {
40         hash, err := c.store.GetMainChainHash(height)
41         if err != nil {
42                 return nil, errors.Wrap(err, "can't find block in given height")
43         }
44
45         return c.store.GetBlock(hash)
46 }
47
48 // GetHeaderByHash return a block header by given hash
49 func (c *Chain) GetHeaderByHash(hash *bc.Hash) (*types.BlockHeader, error) {
50         return c.store.GetBlockHeader(hash)
51 }
52
53 // GetHeaderByHeight return a block header by given height
54 func (c *Chain) GetHeaderByHeight(height uint64) (*types.BlockHeader, error) {
55         hash, err := c.store.GetMainChainHash(height)
56         if err != nil {
57                 return nil, errors.Wrap(err, "can't find block header in given height")
58         }
59
60         return c.store.GetBlockHeader(hash)
61 }
62
63 func (c *Chain) calcReorganizeChain(beginAttach *types.BlockHeader, beginDetach *types.BlockHeader) ([]*types.BlockHeader, []*types.BlockHeader, error) {
64         var err error
65         var attachBlockHeaders []*types.BlockHeader
66         var detachBlockHeaders []*types.BlockHeader
67
68         for attachBlockHeader, detachBlockHeader := beginAttach, beginDetach; detachBlockHeader.Hash() != attachBlockHeader.Hash(); {
69                 var attachRollback, detachRollBack bool
70                 if attachRollback = attachBlockHeader.Height >= detachBlockHeader.Height; attachRollback {
71                         attachBlockHeaders = append([]*types.BlockHeader{attachBlockHeader}, attachBlockHeaders...)
72                 }
73
74                 if detachRollBack = attachBlockHeader.Height <= detachBlockHeader.Height; detachRollBack {
75                         detachBlockHeaders = append(detachBlockHeaders, detachBlockHeader)
76                 }
77
78                 if attachRollback {
79                         attachBlockHeader, err = c.store.GetBlockHeader(&attachBlockHeader.PreviousBlockHash)
80                         if err != nil {
81                                 return nil, nil, err
82                         }
83                 }
84
85                 if detachRollBack {
86                         detachBlockHeader, err = c.store.GetBlockHeader(&detachBlockHeader.PreviousBlockHash)
87                         if err != nil {
88                                 return nil, nil, err
89                         }
90                 }
91         }
92         return attachBlockHeaders, detachBlockHeaders, nil
93 }
94
95 func (c *Chain) connectBlock(block *types.Block) (err error) {
96         bcBlock := types.MapBlock(block)
97         utxoView := state.NewUtxoViewpoint()
98         if err := c.store.GetTransactionsUtxo(utxoView, bcBlock.Transactions); err != nil {
99                 return err
100         }
101         if err := utxoView.ApplyBlock(bcBlock); err != nil {
102                 return err
103         }
104
105         reply, err := c.casper.ApplyBlock(block)
106         if err != nil {
107                 return err
108         }
109
110         if reply.verification != nil {
111                 if err := c.broadcastVerification(reply.verification); err != nil {
112                         return err
113                 }
114         }
115
116         contractView := state.NewContractViewpoint()
117         if err := contractView.ApplyBlock(block); err != nil {
118                 return err
119         }
120
121         if err := c.setState(&block.BlockHeader, []*types.BlockHeader{&block.BlockHeader}, utxoView, contractView); err != nil {
122                 return err
123         }
124
125         for _, tx := range block.Transactions {
126                 c.txPool.RemoveTransaction(&tx.Tx.ID)
127         }
128         return nil
129 }
130
131 func (c *Chain) reorganizeChain(blockHeader *types.BlockHeader) error {
132         attachNodes, detachNodes, err := c.calcReorganizeChain(blockHeader, c.bestBlockHeader)
133         if err != nil {
134                 return err
135         }
136
137         utxoView := state.NewUtxoViewpoint()
138         contractView := state.NewContractViewpoint()
139
140         txsToRestore := map[bc.Hash]*types.Tx{}
141         for _, detachNode := range detachNodes {
142                 hash := detachNode.Hash()
143                 b, err := c.store.GetBlock(&hash)
144                 if err != nil {
145                         return err
146                 }
147
148                 detachBlock := types.MapBlock(b)
149                 if err := c.store.GetTransactionsUtxo(utxoView, detachBlock.Transactions); err != nil {
150                         return err
151                 }
152
153                 if err := utxoView.DetachBlock(detachBlock); err != nil {
154                         return err
155                 }
156
157                 if err := contractView.DetachBlock(b); err != nil {
158                         return err
159                 }
160
161                 for _, tx := range b.Transactions {
162                         txsToRestore[tx.ID] = tx
163                 }
164                 log.WithFields(log.Fields{"module": logModule, "height": detachNode.Height, "hash": hash.String()}).Debug("detach from mainchain")
165         }
166
167         txsToRemove := map[bc.Hash]*types.Tx{}
168         for _, attachNode := range attachNodes {
169                 hash := attachNode.Hash()
170                 b, err := c.store.GetBlock(&hash)
171                 if err != nil {
172                         return err
173                 }
174
175                 attachBlock := types.MapBlock(b)
176                 if err := c.store.GetTransactionsUtxo(utxoView, attachBlock.Transactions); err != nil {
177                         return err
178                 }
179
180                 if err := utxoView.ApplyBlock(attachBlock); err != nil {
181                         return err
182                 }
183
184                 if err := contractView.ApplyBlock(b); err != nil {
185                         return err
186                 }
187
188                 for _, tx := range b.Transactions {
189                         if _, ok := txsToRestore[tx.ID]; !ok {
190                                 txsToRemove[tx.ID] = tx
191                         } else {
192                                 delete(txsToRestore, tx.ID)
193                         }
194                 }
195
196                 log.WithFields(log.Fields{"module": logModule, "height": attachNode.Height, "hash": hash.String()}).Debug("attach from mainchain")
197         }
198
199         if err := c.setState(blockHeader, []*types.BlockHeader{blockHeader}, utxoView, contractView); err != nil {
200                 return err
201         }
202
203         for txHash := range txsToRemove {
204                 c.txPool.RemoveTransaction(&txHash)
205         }
206
207         for _, tx := range txsToRestore {
208                 // the number of restored Tx should be very small or most of time ZERO
209                 // Error returned from validation is ignored, tx could still be lost if validation fails.
210                 // TODO: adjust tx timestamp so that it won't starve in pool.
211                 if _, err := c.ValidateTx(tx); err != nil {
212                         log.WithFields(log.Fields{"module": logModule, "tx_id": tx.Tx.ID.String(), "error": err}).Info("restore tx fail")
213                 }
214         }
215
216         if len(txsToRestore) > 0 {
217                 log.WithFields(log.Fields{"module": logModule, "num": len(txsToRestore)}).Debug("restore txs back to pool")
218         }
219
220         return nil
221 }
222
223 func (c *Chain) broadcastVerification(v *Verification) error {
224         pubKey, err := hex.DecodeString(v.PubKey)
225         if err != nil {
226                 return err
227         }
228
229         signature, err := hex.DecodeString(v.Signature)
230         if err != nil {
231                 return err
232         }
233
234         return c.eventDispatcher.Post(event.BlockVerificationEvent{
235                 SourceHeight: v.SourceHeight,
236                 SourceHash:   v.SourceHash,
237                 TargetHeight: v.TargetHeight,
238                 TargetHash:   v.TargetHash,
239                 PubKey:       pubKey,
240                 Signature:    signature,
241         })
242 }
243
244 // SaveBlock will validate and save block into storage
245 func (c *Chain) saveBlock(block *types.Block) error {
246         bcBlock := types.MapBlock(block)
247         parent, err := c.store.GetBlockHeader(&block.PreviousBlockHash)
248         if err != nil {
249                 return err
250         }
251
252         checkpoint, err := c.PrevCheckpointByPrevHash(&block.PreviousBlockHash)
253         if err != nil {
254                 return err
255         }
256
257         if err := validation.ValidateBlock(bcBlock, parent, checkpoint, c.ProgramConverter); err != nil {
258                 return errors.Sub(ErrBadBlock, err)
259         }
260
261         if err := c.store.SaveBlock(block); err != nil {
262                 return err
263         }
264
265         c.orphanManage.Delete(&bcBlock.ID)
266         return nil
267 }
268
269 func (c *Chain) saveSubBlock(block *types.Block) *types.Block {
270         blockHash := block.Hash()
271         prevOrphans, ok := c.orphanManage.GetPrevOrphans(&blockHash)
272         if !ok {
273                 return block
274         }
275
276         bestBlock := block
277         for _, prevOrphan := range prevOrphans {
278                 orphanBlock, ok := c.orphanManage.Get(prevOrphan)
279                 if !ok {
280                         log.WithFields(log.Fields{"module": logModule, "hash": prevOrphan.String()}).Warning("saveSubBlock fail to get block from orphanManage")
281                         continue
282                 }
283                 if err := c.saveBlock(orphanBlock); err != nil {
284                         log.WithFields(log.Fields{"module": logModule, "hash": prevOrphan.String(), "height": orphanBlock.Height}).Warning("saveSubBlock fail to save block")
285                         continue
286                 }
287
288                 if subBestBlock := c.saveSubBlock(orphanBlock); subBestBlock.Height > bestBlock.Height {
289                         bestBlock = subBestBlock
290                 }
291         }
292         return bestBlock
293 }
294
295 type processBlockResponse struct {
296         isOrphan bool
297         err      error
298 }
299
300 type processBlockMsg struct {
301         block *types.Block
302         reply chan processBlockResponse
303 }
304
305 // ProcessBlock is the entry for chain update
306 func (c *Chain) ProcessBlock(block *types.Block) (bool, error) {
307         reply := make(chan processBlockResponse, 1)
308         c.processBlockCh <- &processBlockMsg{block: block, reply: reply}
309         response := <-reply
310         return response.isOrphan, response.err
311 }
312
313 type rollbackMsg struct {
314         bestHash bc.Hash
315         reply    chan error
316 }
317
318 func (c *Chain) blockProcessor() {
319         for {
320                 select {
321                 case msg := <-c.processBlockCh:
322                         isOrphan, err := c.processBlock(msg.block)
323                         msg.reply <- processBlockResponse{isOrphan: isOrphan, err: err}
324                 case msg := <-c.processRollbackCh:
325                         err := c.rollback(msg.bestHash)
326                         msg.reply <- err
327                 }
328         }
329 }
330
331 // ProcessBlock is the entry for handle block insert
332 func (c *Chain) processBlock(block *types.Block) (bool, error) {
333         blockHash := block.Hash()
334         if c.BlockExist(&blockHash) {
335                 log.WithFields(log.Fields{"module": logModule, "hash": blockHash.String(), "height": block.Height}).Info("block has been processed")
336                 return c.orphanManage.BlockExist(&blockHash), nil
337         }
338
339         if _, err := c.store.GetBlockHeader(&block.PreviousBlockHash); err != nil {
340                 c.orphanManage.Add(block)
341                 return true, nil
342         }
343
344         if err := c.saveBlock(block); err != nil {
345                 return false, err
346         }
347
348         bestBlock := c.saveSubBlock(block)
349         bestBlockHeader := &bestBlock.BlockHeader
350
351         if bestBlockHeader.PreviousBlockHash == c.bestBlockHeader.Hash() {
352                 log.WithFields(log.Fields{"module": logModule}).Debug("append block to the end of mainchain")
353                 return false, c.connectBlock(bestBlock)
354         }
355
356         return false, c.applyForkChainToCasper(bestBlockHeader)
357 }
358
359 func (c *Chain) applyForkChainToCasper(beginAttach *types.BlockHeader) error {
360         attachNodes, _, err := c.calcReorganizeChain(beginAttach, c.bestBlockHeader)
361         if err != nil {
362                 return err
363         }
364
365         var reply *applyBlockReply
366         for _, node := range attachNodes {
367                 hash := node.Hash()
368                 block, err := c.store.GetBlock(&hash)
369                 if err != nil {
370                         return err
371                 }
372
373                 reply, err = c.casper.ApplyBlock(block)
374                 if err != nil {
375                         return err
376                 }
377
378                 log.WithFields(log.Fields{"module": logModule, "height": node.Height, "hash": hash.String()}).Info("apply fork node")
379
380                 if reply.verification != nil {
381                         if err := c.broadcastVerification(reply.verification); err != nil {
382                                 return err
383                         }
384                 }
385         }
386
387         if reply.bestHash != c.bestBlockHeader.Hash() {
388                 return c.rollback(reply.bestHash)
389         }
390
391         return nil
392 }
393
394 func (c *Chain) rollback(bestHash bc.Hash) error {
395         if c.bestBlockHeader.Hash() == bestHash {
396                 return nil
397         }
398
399         blockHeader, err := c.GetHeaderByHash(&bestHash)
400         if err != nil {
401                 return err
402         }
403
404         log.WithFields(log.Fields{"module": logModule, "bestHash": bestHash.String()}).Info("start to reorganize chain")
405         return c.reorganizeChain(blockHeader)
406 }