OSDN Git Service

Hulk did something
[bytom/vapor.git] / protocol / block.go
1 package protocol
2
3 import (
4         log "github.com/sirupsen/logrus"
5
6         "github.com/vapor/errors"
7         "github.com/vapor/protocol/bc"
8         "github.com/vapor/protocol/bc/types"
9         "github.com/vapor/protocol/state"
10         "github.com/vapor/protocol/validation"
11 )
12
13 var (
14         // ErrBadBlock is returned when a block is invalid.
15         ErrBadBlock = errors.New("invalid block")
16         // ErrBadStateRoot is returned when the computed assets merkle root
17         // disagrees with the one declared in a block header.
18         ErrBadStateRoot = errors.New("invalid state merkle root")
19 )
20
21 // BlockExist check is a block in chain or orphan
22 func (c *Chain) BlockExist(hash *bc.Hash) bool {
23         return c.index.BlockExist(hash) || c.orphanManage.BlockExist(hash)
24 }
25
26 // GetBlockByHash return a block by given hash
27 func (c *Chain) GetBlockByHash(hash *bc.Hash) (*types.Block, error) {
28         return c.store.GetBlock(hash)
29 }
30
31 // GetBlockByHeight return a block header by given height
32 func (c *Chain) GetBlockByHeight(height uint64) (*types.Block, error) {
33         node := c.index.NodeByHeight(height)
34         if node == nil {
35                 return nil, errors.New("can't find block in given height")
36         }
37         return c.store.GetBlock(&node.Hash)
38 }
39
40 // GetHeaderByHash return a block header by given hash
41 func (c *Chain) GetHeaderByHash(hash *bc.Hash) (*types.BlockHeader, error) {
42         node := c.index.GetNode(hash)
43         if node == nil {
44                 return nil, errors.New("can't find block header in given hash")
45         }
46         return node.BlockHeader(), nil
47 }
48
49 // GetHeaderByHeight return a block header by given height
50 func (c *Chain) GetHeaderByHeight(height uint64) (*types.BlockHeader, error) {
51         node := c.index.NodeByHeight(height)
52         if node == nil {
53                 return nil, errors.New("can't find block header in given height")
54         }
55         return node.BlockHeader(), nil
56 }
57
58 func (c *Chain) calcReorganizeNodes(node *state.BlockNode) ([]*state.BlockNode, []*state.BlockNode) {
59         var attachNodes []*state.BlockNode
60         var detachNodes []*state.BlockNode
61
62         attachNode := node
63         for c.index.NodeByHeight(attachNode.Height) != attachNode {
64                 attachNodes = append([]*state.BlockNode{attachNode}, attachNodes...)
65                 attachNode = attachNode.Parent
66         }
67
68         detachNode := c.bestNode
69         for detachNode != attachNode {
70                 detachNodes = append(detachNodes, detachNode)
71                 detachNode = detachNode.Parent
72         }
73         return attachNodes, detachNodes
74 }
75
76 func (c *Chain) connectBlock(block *types.Block) (err error) {
77         bcBlock := types.MapBlock(block)
78         if bcBlock.TransactionStatus, err = c.store.GetTransactionStatus(&bcBlock.ID); err != nil {
79                 return err
80         }
81
82         utxoView := state.NewUtxoViewpoint()
83         if err := c.store.GetTransactionsUtxo(utxoView, bcBlock.Transactions); err != nil {
84                 return err
85         }
86         if err := utxoView.ApplyBlock(bcBlock, bcBlock.TransactionStatus); err != nil {
87                 return err
88         }
89
90         node := c.index.GetNode(&bcBlock.ID)
91         if err := c.setState(node, utxoView); err != nil {
92                 return err
93         }
94
95         for _, tx := range block.Transactions {
96                 c.txPool.RemoveTransaction(&tx.Tx.ID)
97         }
98         return nil
99 }
100
101 func (c *Chain) reorganizeChain(node *state.BlockNode) error {
102         attachNodes, detachNodes := c.calcReorganizeNodes(node)
103         utxoView := state.NewUtxoViewpoint()
104
105         for _, detachNode := range detachNodes {
106                 b, err := c.store.GetBlock(&detachNode.Hash)
107                 if err != nil {
108                         return err
109                 }
110
111                 detachBlock := types.MapBlock(b)
112                 if err := c.store.GetTransactionsUtxo(utxoView, detachBlock.Transactions); err != nil {
113                         return err
114                 }
115                 txStatus, err := c.GetTransactionStatus(&detachBlock.ID)
116                 if err != nil {
117                         return err
118                 }
119                 if err := utxoView.DetachBlock(detachBlock, txStatus); err != nil {
120                         return err
121                 }
122
123                 log.WithFields(log.Fields{"module": logModule, "height": node.Height, "hash": node.Hash.String()}).Debug("detach from mainchain")
124         }
125
126         for _, attachNode := range attachNodes {
127                 b, err := c.store.GetBlock(&attachNode.Hash)
128                 if err != nil {
129                         return err
130                 }
131
132                 attachBlock := types.MapBlock(b)
133                 if err := c.store.GetTransactionsUtxo(utxoView, attachBlock.Transactions); err != nil {
134                         return err
135                 }
136                 txStatus, err := c.GetTransactionStatus(&attachBlock.ID)
137                 if err != nil {
138                         return err
139                 }
140                 if err := utxoView.ApplyBlock(attachBlock, txStatus); err != nil {
141                         return err
142                 }
143
144                 log.WithFields(log.Fields{"module": logModule, "height": node.Height, "hash": node.Hash.String()}).Debug("attach from mainchain")
145         }
146
147         return c.setState(node, utxoView)
148 }
149
150 // SaveBlock will validate and save block into storage
151 func (c *Chain) saveBlock(block *types.Block) error {
152         bcBlock := types.MapBlock(block)
153         parent := c.index.GetNode(&block.PreviousBlockHash)
154
155         if err := validation.ValidateBlock(bcBlock, parent); err != nil {
156                 return errors.Sub(ErrBadBlock, err)
157         }
158         if err := c.store.SaveBlock(block, bcBlock.TransactionStatus); err != nil {
159                 return err
160         }
161
162         c.orphanManage.Delete(&bcBlock.ID)
163         node, err := state.NewBlockNode(&block.BlockHeader, parent)
164         if err != nil {
165                 return err
166         }
167
168         c.index.AddNode(node)
169         return nil
170 }
171
172 func (c *Chain) saveSubBlock(block *types.Block) *types.Block {
173         blockHash := block.Hash()
174         prevOrphans, ok := c.orphanManage.GetPrevOrphans(&blockHash)
175         if !ok {
176                 return block
177         }
178
179         bestBlock := block
180         for _, prevOrphan := range prevOrphans {
181                 orphanBlock, ok := c.orphanManage.Get(prevOrphan)
182                 if !ok {
183                         log.WithFields(log.Fields{"module": logModule, "hash": prevOrphan.String()}).Warning("saveSubBlock fail to get block from orphanManage")
184                         continue
185                 }
186                 if err := c.saveBlock(orphanBlock); err != nil {
187                         log.WithFields(log.Fields{"module": logModule, "hash": prevOrphan.String(), "height": orphanBlock.Height}).Warning("saveSubBlock fail to save block")
188                         continue
189                 }
190
191                 if subBestBlock := c.saveSubBlock(orphanBlock); subBestBlock.Height > bestBlock.Height {
192                         bestBlock = subBestBlock
193                 }
194         }
195         return bestBlock
196 }
197
198 type processBlockResponse struct {
199         isOrphan bool
200         err      error
201 }
202
203 type processBlockMsg struct {
204         block *types.Block
205         reply chan processBlockResponse
206 }
207
208 // ProcessBlock is the entry for chain update
209 func (c *Chain) ProcessBlock(block *types.Block) (bool, error) {
210         reply := make(chan processBlockResponse, 1)
211         c.processBlockCh <- &processBlockMsg{block: block, reply: reply}
212         response := <-reply
213         return response.isOrphan, response.err
214 }
215
216 func (c *Chain) blockProcesser() {
217         for msg := range c.processBlockCh {
218                 isOrphan, err := c.processBlock(msg.block)
219                 msg.reply <- processBlockResponse{isOrphan: isOrphan, err: err}
220         }
221 }
222
223 // ProcessBlock is the entry for handle block insert
224 func (c *Chain) processBlock(block *types.Block) (bool, error) {
225         blockHash := block.Hash()
226         if c.BlockExist(&blockHash) {
227                 log.WithFields(log.Fields{"module": logModule, "hash": blockHash.String(), "height": block.Height}).Info("block has been processed")
228                 return c.orphanManage.BlockExist(&blockHash), nil
229         }
230
231         if parent := c.index.GetNode(&block.PreviousBlockHash); parent == nil {
232                 c.orphanManage.Add(block)
233                 return true, nil
234         }
235
236         if err := c.saveBlock(block); err != nil {
237                 return false, err
238         }
239
240         bestBlock := c.saveSubBlock(block)
241         bestBlockHash := bestBlock.Hash()
242         bestNode := c.index.GetNode(&bestBlockHash)
243
244         if bestNode.Parent == c.bestNode {
245                 log.WithFields(log.Fields{"module": logModule}).Debug("append block to the end of mainchain")
246                 return false, c.connectBlock(bestBlock)
247         }
248
249         if bestNode.Height > c.bestNode.Height && bestNode.WorkSum.Cmp(c.bestNode.WorkSum) >= 0 {
250                 log.WithFields(log.Fields{"module": logModule}).Debug("start to reorganize chain")
251                 return false, c.reorganizeChain(bestNode)
252         }
253         return false, nil
254 }