OSDN Git Service

Small edit (#1990)
[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         contractView.ApplyBlock(block)
118
119         if err := c.setState(&block.BlockHeader, []*types.BlockHeader{&block.BlockHeader}, utxoView, contractView); err != nil {
120                 return err
121         }
122
123         for _, tx := range block.Transactions {
124                 c.txPool.RemoveTransaction(&tx.Tx.ID)
125         }
126         return nil
127 }
128
129 func (c *Chain) reorganizeChain(blockHeader *types.BlockHeader) error {
130         attachNodes, detachNodes, err := c.calcReorganizeChain(blockHeader, c.bestBlockHeader)
131         if err != nil {
132                 return err
133         }
134
135         utxoView := state.NewUtxoViewpoint()
136         contractView := state.NewContractViewpoint()
137
138         txsToRestore := map[bc.Hash]*types.Tx{}
139         for _, detachNode := range detachNodes {
140                 hash := detachNode.Hash()
141                 b, err := c.store.GetBlock(&hash)
142                 if err != nil {
143                         return err
144                 }
145
146                 detachBlock := types.MapBlock(b)
147                 if err := c.store.GetTransactionsUtxo(utxoView, detachBlock.Transactions); err != nil {
148                         return err
149                 }
150
151                 if err := utxoView.DetachBlock(detachBlock); err != nil {
152                         return err
153                 }
154
155                 contractView.DetachBlock(b)
156                 for _, tx := range b.Transactions {
157                         txsToRestore[tx.ID] = tx
158                 }
159                 log.WithFields(log.Fields{"module": logModule, "height": detachNode.Height, "hash": hash.String()}).Debug("detach from mainchain")
160         }
161
162         txsToRemove := map[bc.Hash]*types.Tx{}
163         for _, attachNode := range attachNodes {
164                 hash := attachNode.Hash()
165                 b, err := c.store.GetBlock(&hash)
166                 if err != nil {
167                         return err
168                 }
169
170                 attachBlock := types.MapBlock(b)
171                 if err := c.store.GetTransactionsUtxo(utxoView, attachBlock.Transactions); err != nil {
172                         return err
173                 }
174
175                 if err := utxoView.ApplyBlock(attachBlock); err != nil {
176                         return err
177                 }
178
179                 contractView.ApplyBlock(b)
180                 for _, tx := range b.Transactions {
181                         if _, ok := txsToRestore[tx.ID]; !ok {
182                                 txsToRemove[tx.ID] = tx
183                         } else {
184                                 delete(txsToRestore, tx.ID)
185                         }
186                 }
187
188                 log.WithFields(log.Fields{"module": logModule, "height": attachNode.Height, "hash": hash.String()}).Debug("attach from mainchain")
189         }
190
191         if err := c.setState(blockHeader, []*types.BlockHeader{blockHeader}, utxoView, contractView); err != nil {
192                 return err
193         }
194
195         for txHash := range txsToRemove {
196                 c.txPool.RemoveTransaction(&txHash)
197         }
198
199         for _, tx := range txsToRestore {
200                 // the number of restored Tx should be very small or most of time ZERO
201                 // Error returned from validation is ignored, tx could still be lost if validation fails.
202                 // TODO: adjust tx timestamp so that it won't starve in pool.
203                 if _, err := c.ValidateTx(tx); err != nil {
204                         log.WithFields(log.Fields{"module": logModule, "tx_id": tx.Tx.ID.String(), "error": err}).Info("restore tx fail")
205                 }
206         }
207
208         if len(txsToRestore) > 0 {
209                 log.WithFields(log.Fields{"module": logModule, "num": len(txsToRestore)}).Debug("restore txs back to pool")
210         }
211
212         return nil
213 }
214
215 func (c *Chain) broadcastVerification(v *Verification) error {
216         pubKey, err := hex.DecodeString(v.PubKey)
217         if err != nil {
218                 return err
219         }
220
221         return c.eventDispatcher.Post(event.BlockVerificationEvent{
222                 SourceHeight: v.SourceHeight,
223                 SourceHash:   v.SourceHash,
224                 TargetHeight: v.TargetHeight,
225                 TargetHash:   v.TargetHash,
226                 PubKey:       pubKey,
227                 Signature:    v.Signature,
228         })
229 }
230
231 // SaveBlock will validate and save block into storage
232 func (c *Chain) saveBlock(block *types.Block) error {
233         bcBlock := types.MapBlock(block)
234         parent, err := c.store.GetBlockHeader(&block.PreviousBlockHash)
235         if err != nil {
236                 return err
237         }
238
239         checkpoint, err := c.PrevCheckpointByPrevHash(&block.PreviousBlockHash)
240         if err != nil {
241                 return err
242         }
243
244         if err := validation.ValidateBlock(bcBlock, parent, checkpoint, c.ProgramConverter); err != nil {
245                 return errors.Sub(ErrBadBlock, err)
246         }
247
248         if err := c.store.SaveBlock(block); err != nil {
249                 return err
250         }
251
252         c.orphanManage.Delete(&bcBlock.ID)
253         return nil
254 }
255
256 func (c *Chain) saveSubBlock(block *types.Block) *types.Block {
257         blockHash := block.Hash()
258         prevOrphans, ok := c.orphanManage.GetPrevOrphans(&blockHash)
259         if !ok {
260                 return block
261         }
262
263         bestBlock := block
264         for _, prevOrphan := range prevOrphans {
265                 orphanBlock, ok := c.orphanManage.Get(prevOrphan)
266                 if !ok {
267                         log.WithFields(log.Fields{"module": logModule, "hash": prevOrphan.String()}).Warning("saveSubBlock fail to get block from orphanManage")
268                         continue
269                 }
270                 if err := c.saveBlock(orphanBlock); err != nil {
271                         log.WithFields(log.Fields{"module": logModule, "hash": prevOrphan.String(), "height": orphanBlock.Height}).Warning("saveSubBlock fail to save block")
272                         continue
273                 }
274
275                 if subBestBlock := c.saveSubBlock(orphanBlock); subBestBlock.Height > bestBlock.Height {
276                         bestBlock = subBestBlock
277                 }
278         }
279         return bestBlock
280 }
281
282 type processBlockResponse struct {
283         isOrphan bool
284         err      error
285 }
286
287 type processBlockMsg struct {
288         block *types.Block
289         reply chan processBlockResponse
290 }
291
292 // ProcessBlock is the entry for chain update
293 func (c *Chain) ProcessBlock(block *types.Block) (bool, error) {
294         reply := make(chan processBlockResponse, 1)
295         c.processBlockCh <- &processBlockMsg{block: block, reply: reply}
296         response := <-reply
297         return response.isOrphan, response.err
298 }
299
300 type rollbackMsg struct {
301         bestHash bc.Hash
302         reply    chan error
303 }
304
305 func (c *Chain) blockProcessor() {
306         for {
307                 select {
308                 case msg := <-c.processBlockCh:
309                         isOrphan, err := c.processBlock(msg.block)
310                         msg.reply <- processBlockResponse{isOrphan: isOrphan, err: err}
311                 case msg := <-c.processRollbackCh:
312                         err := c.rollback(msg.bestHash)
313                         msg.reply <- err
314                 }
315         }
316 }
317
318 // ProcessBlock is the entry for handle block insert
319 func (c *Chain) processBlock(block *types.Block) (bool, error) {
320         blockHash := block.Hash()
321         if c.BlockExist(&blockHash) {
322                 log.WithFields(log.Fields{"module": logModule, "hash": blockHash.String(), "height": block.Height}).Info("block has been processed")
323                 return c.orphanManage.BlockExist(&blockHash), nil
324         }
325
326         if _, err := c.store.GetBlockHeader(&block.PreviousBlockHash); err != nil {
327                 c.orphanManage.Add(block)
328                 return true, nil
329         }
330
331         if err := c.saveBlock(block); err != nil {
332                 return false, err
333         }
334
335         bestBlock := c.saveSubBlock(block)
336         bestBlockHeader := &bestBlock.BlockHeader
337
338         if bestBlockHeader.PreviousBlockHash == c.bestBlockHeader.Hash() {
339                 log.WithFields(log.Fields{"module": logModule}).Debug("append block to the end of mainchain")
340                 return false, c.connectBlock(bestBlock)
341         }
342
343         return false, c.applyForkChainToCasper(bestBlockHeader)
344 }
345
346 func (c *Chain) applyForkChainToCasper(beginAttach *types.BlockHeader) error {
347         attachNodes, _, err := c.calcReorganizeChain(beginAttach, c.bestBlockHeader)
348         if err != nil {
349                 return err
350         }
351
352         var reply *applyBlockReply
353         for _, node := range attachNodes {
354                 hash := node.Hash()
355                 block, err := c.store.GetBlock(&hash)
356                 if err != nil {
357                         return err
358                 }
359
360                 reply, err = c.casper.ApplyBlock(block)
361                 if err != nil {
362                         return err
363                 }
364
365                 log.WithFields(log.Fields{"module": logModule, "height": node.Height, "hash": hash.String()}).Info("apply fork node")
366
367                 if reply.verification != nil {
368                         if err := c.broadcastVerification(reply.verification); err != nil {
369                                 return err
370                         }
371                 }
372         }
373
374         if reply.bestHash != c.bestBlockHeader.Hash() {
375                 return c.rollback(reply.bestHash)
376         }
377
378         return nil
379 }
380
381 func (c *Chain) rollback(bestHash bc.Hash) error {
382         if c.bestBlockHeader.Hash() == bestHash {
383                 return nil
384         }
385
386         blockHeader, err := c.GetHeaderByHash(&bestHash)
387         if err != nil {
388                 return err
389         }
390
391         log.WithFields(log.Fields{"module": logModule, "bestHash": bestHash.String()}).Info("start to reorganize chain")
392         return c.reorganizeChain(blockHeader)
393 }