OSDN Git Service

d5ef5cf7e031eff6cfd4c799d71beb802923e071
[bytom/vapor.git] / protocol / block.go
1 package protocol
2
3 import (
4         log "github.com/sirupsen/logrus"
5
6         "github.com/vapor/config"
7         "github.com/vapor/errors"
8         "github.com/vapor/event"
9         "github.com/vapor/protocol/bc"
10         "github.com/vapor/protocol/bc/types"
11         "github.com/vapor/protocol/state"
12         "github.com/vapor/protocol/validation"
13 )
14
15 var (
16         // ErrBadBlock is returned when a block is invalid.
17         ErrBadBlock = errors.New("invalid block")
18         // ErrBadStateRoot is returned when the computed assets merkle root
19         // disagrees with the one declared in a block header.
20         ErrBadStateRoot           = errors.New("invalid state merkle root")
21         errBelowIrreversibleBlock = errors.New("the height of block below the height of irreversible block")
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         node := c.index.GetNode(hash)
32         if node == nil {
33                 return nil, errors.New("can't find block in given hash")
34         }
35         return c.store.GetBlock(hash, node.Height)
36 }
37
38 // GetBlockByHeight return a block header by given height
39 func (c *Chain) GetBlockByHeight(height uint64) (*types.Block, error) {
40         node := c.index.NodeByHeight(height)
41         if node == nil {
42                 return nil, errors.New("can't find block in given height")
43         }
44         return c.store.GetBlock(&node.Hash, height)
45 }
46
47 // GetHeaderByHash return a block header by given hash
48 func (c *Chain) GetHeaderByHash(hash *bc.Hash) (*types.BlockHeader, error) {
49         node := c.index.GetNode(hash)
50         if node == nil {
51                 return nil, errors.New("can't find block header in given hash")
52         }
53         return node.BlockHeader(), nil
54 }
55
56 // GetHeaderByHeight return a block header by given height
57 func (c *Chain) GetHeaderByHeight(height uint64) (*types.BlockHeader, error) {
58         node := c.index.NodeByHeight(height)
59         if node == nil {
60                 return nil, errors.New("can't find block header in given height")
61         }
62         return node.BlockHeader(), nil
63 }
64
65 func (c *Chain) calcReorganizeNodes(node *state.BlockNode) ([]*state.BlockNode, []*state.BlockNode) {
66         var attachNodes []*state.BlockNode
67         var detachNodes []*state.BlockNode
68
69         attachNode := node
70         for c.index.NodeByHeight(attachNode.Height) != attachNode {
71                 attachNodes = append([]*state.BlockNode{attachNode}, attachNodes...)
72                 attachNode = attachNode.Parent
73         }
74
75         detachNode := c.bestNode
76         for detachNode != attachNode {
77                 detachNodes = append(detachNodes, detachNode)
78                 detachNode = detachNode.Parent
79         }
80         return attachNodes, detachNodes
81 }
82
83 func (c *Chain) connectBlock(block *types.Block) (err error) {
84         irreversibleNode := c.bestIrreversibleNode
85         bcBlock := types.MapBlock(block)
86         if bcBlock.TransactionStatus, err = c.store.GetTransactionStatus(&bcBlock.ID); err != nil {
87                 return err
88         }
89
90         utxoView := state.NewUtxoViewpoint()
91         if err := c.store.GetTransactionsUtxo(utxoView, bcBlock.Transactions); err != nil {
92                 return err
93         }
94         if err := utxoView.ApplyBlock(bcBlock, bcBlock.TransactionStatus); err != nil {
95                 return err
96         }
97
98         voteResult, err := c.consensusNodeManager.getBestVoteResult()
99         if err != nil {
100                 return err
101         }
102         if err := voteResult.ApplyBlock(block); err != nil {
103                 return err
104         }
105
106         node := c.index.GetNode(&bcBlock.ID)
107         if c.isIrreversible(node) && block.Height > irreversibleNode.Height {
108                 irreversibleNode = node
109         }
110
111         if err := c.setState(node, irreversibleNode, utxoView, []*state.VoteResult{voteResult}); err != nil {
112                 return err
113         }
114
115         for _, tx := range block.Transactions {
116                 c.txPool.RemoveTransaction(&tx.Tx.ID)
117         }
118         return nil
119 }
120
121 func (c *Chain) reorganizeChain(node *state.BlockNode) error {
122         attachNodes, detachNodes := c.calcReorganizeNodes(node)
123         utxoView := state.NewUtxoViewpoint()
124         voteResults := []*state.VoteResult{}
125         irreversibleNode := c.bestIrreversibleNode
126         voteResult, err := c.consensusNodeManager.getBestVoteResult()
127         if err != nil {
128                 return err
129         }
130
131         for _, detachNode := range detachNodes {
132                 b, err := c.store.GetBlock(&detachNode.Hash, detachNode.Height)
133                 if err != nil {
134                         return err
135                 }
136
137                 detachBlock := types.MapBlock(b)
138                 if err := c.store.GetTransactionsUtxo(utxoView, detachBlock.Transactions); err != nil {
139                         return err
140                 }
141
142                 txStatus, err := c.GetTransactionStatus(&detachBlock.ID)
143                 if err != nil {
144                         return err
145                 }
146
147                 if err := utxoView.DetachBlock(detachBlock, txStatus); err != nil {
148                         return err
149                 }
150
151                 if err := voteResult.DetachBlock(b); err != nil {
152                         return err
153                 }
154
155                 log.WithFields(log.Fields{"module": logModule, "height": node.Height, "hash": node.Hash.String()}).Debug("detach from mainchain")
156         }
157
158         for _, attachNode := range attachNodes {
159                 b, err := c.store.GetBlock(&attachNode.Hash, attachNode.Height)
160                 if err != nil {
161                         return err
162                 }
163
164                 attachBlock := types.MapBlock(b)
165                 if err := c.store.GetTransactionsUtxo(utxoView, attachBlock.Transactions); err != nil {
166                         return err
167                 }
168
169                 txStatus, err := c.GetTransactionStatus(&attachBlock.ID)
170                 if err != nil {
171                         return err
172                 }
173
174                 if err := utxoView.ApplyBlock(attachBlock, txStatus); err != nil {
175                         return err
176                 }
177
178                 if err := voteResult.ApplyBlock(b); err != nil {
179                         return err
180                 }
181
182                 if voteResult.IsFinalize() {
183                         voteResults = append(voteResults, voteResult.Fork())
184                 }
185
186                 if c.isIrreversible(attachNode) && attachNode.Height > irreversibleNode.Height {
187                         irreversibleNode = attachNode
188                 }
189
190                 log.WithFields(log.Fields{"module": logModule, "height": node.Height, "hash": node.Hash.String()}).Debug("attach from mainchain")
191         }
192
193         if detachNodes[len(detachNodes)-1].Height <= c.bestIrreversibleNode.Height && irreversibleNode.Height <= c.bestIrreversibleNode.Height {
194                 return errors.New("rollback block below the height of irreversible block")
195         }
196         voteResults = append(voteResults, voteResult.Fork())
197         return c.setState(node, irreversibleNode, utxoView, voteResults)
198 }
199
200 // SaveBlock will validate and save block into storage
201 func (c *Chain) saveBlock(block *types.Block) error {
202         if err := c.validateSign(block); err != nil {
203                 return errors.Sub(ErrBadBlock, err)
204         }
205
206         parent := c.index.GetNode(&block.PreviousBlockHash)
207         bcBlock := types.MapBlock(block)
208         if err := validation.ValidateBlock(bcBlock, parent); err != nil {
209                 return errors.Sub(ErrBadBlock, err)
210         }
211
212         signature, err := c.SignBlock(block)
213         if err != nil {
214                 return errors.Sub(ErrBadBlock, err)
215         }
216
217         if err := c.store.SaveBlock(block, bcBlock.TransactionStatus); err != nil {
218                 return err
219         }
220
221         c.orphanManage.Delete(&bcBlock.ID)
222         node, err := state.NewBlockNode(&block.BlockHeader, parent)
223         if err != nil {
224                 return err
225         }
226
227         c.index.AddNode(node)
228
229         if len(signature) != 0 {
230                 xPub := config.CommonConfig.PrivateKey().XPub()
231                 if err := c.eventDispatcher.Post(event.BlockSignatureEvent{BlockHash: block.Hash(), Signature: signature, XPub: xPub[:]}); err != nil {
232                         return err
233                 }
234         }
235         return nil
236 }
237
238 func (c *Chain) saveSubBlock(block *types.Block) *types.Block {
239         blockHash := block.Hash()
240         prevOrphans, ok := c.orphanManage.GetPrevOrphans(&blockHash)
241         if !ok {
242                 return block
243         }
244
245         bestBlock := block
246         for _, prevOrphan := range prevOrphans {
247                 orphanBlock, ok := c.orphanManage.Get(prevOrphan)
248                 if !ok {
249                         log.WithFields(log.Fields{"module": logModule, "hash": prevOrphan.String()}).Warning("saveSubBlock fail to get block from orphanManage")
250                         continue
251                 }
252                 if err := c.saveBlock(orphanBlock); err != nil {
253                         log.WithFields(log.Fields{"module": logModule, "hash": prevOrphan.String(), "height": orphanBlock.Height}).Warning("saveSubBlock fail to save block")
254                         continue
255                 }
256
257                 if subBestBlock := c.saveSubBlock(orphanBlock); subBestBlock.Height > bestBlock.Height {
258                         bestBlock = subBestBlock
259                 }
260         }
261         return bestBlock
262 }
263
264 type processBlockResponse struct {
265         isOrphan bool
266         err      error
267 }
268
269 type processBlockMsg struct {
270         block *types.Block
271         reply chan processBlockResponse
272 }
273
274 // ProcessBlock is the entry for chain update
275 func (c *Chain) ProcessBlock(block *types.Block) (bool, error) {
276         reply := make(chan processBlockResponse, 1)
277         c.processBlockCh <- &processBlockMsg{block: block, reply: reply}
278         response := <-reply
279         return response.isOrphan, response.err
280 }
281
282 func (c *Chain) blockProcesser() {
283         for msg := range c.processBlockCh {
284                 isOrphan, err := c.processBlock(msg.block)
285                 msg.reply <- processBlockResponse{isOrphan: isOrphan, err: err}
286         }
287 }
288
289 // ProcessBlock is the entry for handle block insert
290 func (c *Chain) processBlock(block *types.Block) (bool, error) {
291         blockHash := block.Hash()
292         if c.BlockExist(&blockHash) {
293                 log.WithFields(log.Fields{"module": logModule, "hash": blockHash.String(), "height": block.Height}).Info("block has been processed")
294                 return c.orphanManage.BlockExist(&blockHash), nil
295         }
296
297         if parent := c.index.GetNode(&block.PreviousBlockHash); parent == nil {
298                 c.orphanManage.Add(block)
299                 return true, nil
300         }
301
302         if err := c.saveBlock(block); err != nil {
303                 return false, err
304         }
305
306         bestBlock := c.saveSubBlock(block)
307         bestBlockHash := bestBlock.Hash()
308         bestNode := c.index.GetNode(&bestBlockHash)
309
310         c.cond.L.Lock()
311         defer c.cond.L.Unlock()
312         if bestNode.Parent == c.bestNode {
313                 log.WithFields(log.Fields{"module": logModule}).Debug("append block to the end of mainchain")
314                 return false, c.connectBlock(bestBlock)
315         }
316
317         if bestNode.Height > c.bestNode.Height {
318                 log.WithFields(log.Fields{"module": logModule}).Debug("start to reorganize chain")
319                 return false, c.reorganizeChain(bestNode)
320         }
321         return false, nil
322 }