OSDN Git Service

f2dc01d400036df7c29b97b54dad58b625b5652b
[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         return c.index.BlockExist(hash) || 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 header by given height
35 func (c *Chain) GetBlockByHeight(height uint64) (*types.Block, error) {
36         node := c.index.NodeByHeight(height)
37         if node == nil {
38                 return nil, errors.New("can't find block in given height")
39         }
40         return c.store.GetBlock(&node.Hash)
41 }
42
43 // GetHeaderByHash return a block header by given hash
44 func (c *Chain) GetHeaderByHash(hash *bc.Hash) (*types.BlockHeader, error) {
45         node := c.index.GetNode(hash)
46         if node == nil {
47                 return nil, errors.New("can't find block header in given hash")
48         }
49         return node.BlockHeader(), nil
50 }
51
52 // GetHeaderByHeight return a block header by given height
53 func (c *Chain) GetHeaderByHeight(height uint64) (*types.BlockHeader, error) {
54         node := c.index.NodeByHeight(height)
55         if node == nil {
56                 return nil, errors.New("can't find block header in given height")
57         }
58         return node.BlockHeader(), nil
59 }
60
61 func (c *Chain) calcReorganizeNodes(node *state.BlockNode) ([]*state.BlockNode, []*state.BlockNode) {
62         var attachNodes []*state.BlockNode
63         var detachNodes []*state.BlockNode
64
65         attachNode := node
66         for c.index.NodeByHeight(attachNode.Height) != attachNode {
67                 attachNodes = append([]*state.BlockNode{attachNode}, attachNodes...)
68                 attachNode = attachNode.Parent
69         }
70
71         detachNode := c.bestNode
72         for detachNode != attachNode {
73                 detachNodes = append(detachNodes, detachNode)
74                 detachNode = detachNode.Parent
75         }
76         return attachNodes, detachNodes
77 }
78
79 func (c *Chain) connectBlock(block *types.Block) (err error) {
80         bcBlock := types.MapBlock(block)
81         utxoView := state.NewUtxoViewpoint()
82         if err := c.store.GetTransactionsUtxo(utxoView, bcBlock.Transactions); err != nil {
83                 return err
84         }
85         if err := utxoView.ApplyBlock(bcBlock); err != nil {
86                 return err
87         }
88
89         verification, checkpoint, err := c.casper.ApplyBlock(block)
90         if err != nil {
91                 return err
92         }
93
94         if verification != nil {
95                 if err := c.broadcastVerification(verification); err != nil {
96                         return err
97                 }
98         }
99
100         contractView := state.NewContractViewpoint()
101         if err := contractView.ApplyBlock(block); err != nil {
102                 return err
103         }
104
105         node := c.index.GetNode(&bcBlock.ID)
106         if err := c.setState(node, utxoView, contractView, checkpoint); err != nil {
107                 return err
108         }
109
110         for _, tx := range block.Transactions {
111                 c.txPool.RemoveTransaction(&tx.Tx.ID)
112         }
113         return nil
114 }
115
116 func (c *Chain) reorganizeChain(node *state.BlockNode) error {
117         attachNodes, detachNodes := c.calcReorganizeNodes(node)
118         utxoView := state.NewUtxoViewpoint()
119         contractView := state.NewContractViewpoint()
120
121         txsToRestore := map[bc.Hash]*types.Tx{}
122         for _, detachNode := range detachNodes {
123                 b, err := c.store.GetBlock(&detachNode.Hash)
124                 if err != nil {
125                         return err
126                 }
127
128                 detachBlock := types.MapBlock(b)
129                 if err := c.store.GetTransactionsUtxo(utxoView, detachBlock.Transactions); err != nil {
130                         return err
131                 }
132
133                 if err := utxoView.DetachBlock(detachBlock); err != nil {
134                         return err
135                 }
136
137                 if err := contractView.DetachBlock(b); err != nil {
138                         return err
139                 }
140
141                 for _, tx := range b.Transactions {
142                         txsToRestore[tx.ID] = tx
143                 }
144                 log.WithFields(log.Fields{"module": logModule, "height": node.Height, "hash": node.Hash.String()}).Debug("detach from mainchain")
145         }
146
147         txsToRemove := map[bc.Hash]*types.Tx{}
148         var affectedCheckpoints []*state.Checkpoint
149         for _, attachNode := range attachNodes {
150                 b, err := c.store.GetBlock(&attachNode.Hash)
151                 if err != nil {
152                         return err
153                 }
154
155                 attachBlock := types.MapBlock(b)
156                 if err := c.store.GetTransactionsUtxo(utxoView, attachBlock.Transactions); err != nil {
157                         return err
158                 }
159
160                 if err := utxoView.ApplyBlock(attachBlock); err != nil {
161                         return err
162                 }
163
164                 verification, checkpoint, err := c.casper.ApplyBlock(b)
165                 if err != nil {
166                         return err
167                 }
168
169                 affectedCheckpoints = append(affectedCheckpoints, checkpoint)
170
171                 if err := c.broadcastVerification(verification); err != nil {
172                         return err
173                 }
174
175                 if err := contractView.ApplyBlock(b); err != nil {
176                         return err
177                 }
178
179                 for _, tx := range b.Transactions {
180                         if _, ok := txsToRestore[tx.ID]; !ok {
181                                 txsToRemove[tx.ID] = tx
182                         } else {
183                                 delete(txsToRestore, tx.ID)
184                         }
185                 }
186
187                 log.WithFields(log.Fields{"module": logModule, "height": node.Height, "hash": node.Hash.String()}).Debug("attach from mainchain")
188         }
189
190         if err := c.setState(node, utxoView, contractView, affectedCheckpoints...); err != nil {
191                 return err
192         }
193
194         for txHash := range txsToRemove {
195                 c.txPool.RemoveTransaction(&txHash)
196         }
197
198         for _, tx := range txsToRestore {
199                 // the number of restored Tx should be very small or most of time ZERO
200                 // Error returned from validation is ignored, tx could still be lost if validation fails.
201                 // TODO: adjust tx timestamp so that it won't starve in pool.
202                 if _, err := c.ValidateTx(tx); err != nil {
203                         log.WithFields(log.Fields{"module": logModule, "tx_id": tx.Tx.ID.String(), "error": err}).Info("restore tx fail")
204                 }
205         }
206
207         if len(txsToRestore) > 0 {
208                 log.WithFields(log.Fields{"module": logModule, "num": len(txsToRestore)}).Debug("restore txs back to pool")
209         }
210
211         return nil
212 }
213
214 func (c *Chain) broadcastVerification(v *Verification) error {
215         pubKey, err := hex.DecodeString(v.PubKey)
216         if err != nil {
217                 return err
218         }
219
220         signature, err := hex.DecodeString(v.Signature)
221         if err != nil {
222                 return err
223         }
224
225         return c.eventDispatcher.Post(event.BlockVerificationEvent{
226                 SourceHeight: v.SourceHeight,
227                 SourceHash:   v.SourceHash,
228                 TargetHeight: v.TargetHeight,
229                 TargetHash:   v.TargetHash,
230                 PubKey:       pubKey,
231                 Signature:    signature,
232         })
233 }
234
235 // SaveBlock will validate and save block into storage
236 func (c *Chain) saveBlock(block *types.Block) error {
237         bcBlock := types.MapBlock(block)
238         parent := c.index.GetNode(&block.PreviousBlockHash)
239
240         if err := validation.ValidateBlock(bcBlock, parent, c.ProgramConverter); err != nil {
241                 return errors.Sub(ErrBadBlock, err)
242         }
243
244         if err := c.store.SaveBlock(block); err != nil {
245                 return err
246         }
247
248         c.orphanManage.Delete(&bcBlock.ID)
249         node, err := state.NewBlockNode(&block.BlockHeader, parent)
250         if err != nil {
251                 return err
252         }
253
254         c.index.AddNode(node)
255         return nil
256 }
257
258 func (c *Chain) saveSubBlock(block *types.Block) *types.Block {
259         blockHash := block.Hash()
260         prevOrphans, ok := c.orphanManage.GetPrevOrphans(&blockHash)
261         if !ok {
262                 return block
263         }
264
265         bestBlock := block
266         for _, prevOrphan := range prevOrphans {
267                 orphanBlock, ok := c.orphanManage.Get(prevOrphan)
268                 if !ok {
269                         log.WithFields(log.Fields{"module": logModule, "hash": prevOrphan.String()}).Warning("saveSubBlock fail to get block from orphanManage")
270                         continue
271                 }
272                 if err := c.saveBlock(orphanBlock); err != nil {
273                         log.WithFields(log.Fields{"module": logModule, "hash": prevOrphan.String(), "height": orphanBlock.Height}).Warning("saveSubBlock fail to save block")
274                         continue
275                 }
276
277                 if subBestBlock := c.saveSubBlock(orphanBlock); subBestBlock.Height > bestBlock.Height {
278                         bestBlock = subBestBlock
279                 }
280         }
281         return bestBlock
282 }
283
284 type processBlockResponse struct {
285         isOrphan bool
286         err      error
287 }
288
289 type processBlockMsg struct {
290         block *types.Block
291         reply chan processBlockResponse
292 }
293
294 // ProcessBlock is the entry for chain update
295 func (c *Chain) ProcessBlock(block *types.Block) (bool, error) {
296         reply := make(chan processBlockResponse, 1)
297         c.processBlockCh <- &processBlockMsg{block: block, reply: reply}
298         response := <-reply
299         return response.isOrphan, response.err
300 }
301
302 func (c *Chain) blockProcessor() {
303         for {
304                 select {
305                 case msg := <-c.processBlockCh:
306                         isOrphan, err := c.processBlock(msg.block)
307                         msg.reply <- processBlockResponse{isOrphan: isOrphan, err: err}
308                 case newBestHash := <-c.rollbackNotifyCh:
309                         if err := c.rollback(newBestHash); err != nil {
310                                 log.WithFields(log.Fields{"module": logModule, "err": err}).Warning("fail on rollback block")
311                         }
312                 }
313         }
314 }
315
316 // ProcessBlock is the entry for handle block insert
317 func (c *Chain) processBlock(block *types.Block) (bool, error) {
318         blockHash := block.Hash()
319         if c.BlockExist(&blockHash) {
320                 log.WithFields(log.Fields{"module": logModule, "hash": blockHash.String(), "height": block.Height}).Info("block has been processed")
321                 return c.orphanManage.BlockExist(&blockHash), nil
322         }
323
324         if parent := c.index.GetNode(&block.PreviousBlockHash); parent == nil {
325                 c.orphanManage.Add(block)
326                 return true, nil
327         }
328
329         if err := c.saveBlock(block); err != nil {
330                 return false, err
331         }
332
333         bestBlock := c.saveSubBlock(block)
334         bestBlockHash := bestBlock.Hash()
335         bestNode := c.index.GetNode(&bestBlockHash)
336
337         if bestNode.Parent == c.bestNode {
338                 log.WithFields(log.Fields{"module": logModule}).Debug("append block to the end of mainchain")
339                 return false, c.connectBlock(bestBlock)
340         }
341         return false, nil
342 }
343
344 func (c *Chain) rollback(newBestHash bc.Hash) error {
345         if c.bestNode.Hash == newBestHash {
346                 return nil
347         }
348
349         node := c.index.GetNode(&newBestHash)
350         log.WithFields(log.Fields{"module": logModule}).Debug("start to reorganize chain")
351         return c.reorganizeChain(node)
352 }