OSDN Git Service

add mac function, modify nextBlockTime (#122)
[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 )
22
23 // BlockExist check is a block in chain or orphan
24 func (c *Chain) BlockExist(hash *bc.Hash) bool {
25         return c.index.BlockExist(hash) || c.orphanManage.BlockExist(hash)
26 }
27
28 // GetBlockByHash return a block by given hash
29 func (c *Chain) GetBlockByHash(hash *bc.Hash) (*types.Block, error) {
30         return c.store.GetBlock(hash)
31 }
32
33 // GetBlockByHeight return a block header by given height
34 func (c *Chain) GetBlockByHeight(height uint64) (*types.Block, error) {
35         node := c.index.NodeByHeight(height)
36         if node == nil {
37                 return nil, errors.New("can't find block in given height")
38         }
39         return c.store.GetBlock(&node.Hash)
40 }
41
42 // GetHeaderByHash return a block header by given hash
43 func (c *Chain) GetHeaderByHash(hash *bc.Hash) (*types.BlockHeader, error) {
44         node := c.index.GetNode(hash)
45         if node == nil {
46                 return nil, errors.New("can't find block header in given hash")
47         }
48         return node.BlockHeader(), nil
49 }
50
51 // GetHeaderByHeight return a block header by given height
52 func (c *Chain) GetHeaderByHeight(height uint64) (*types.BlockHeader, error) {
53         node := c.index.NodeByHeight(height)
54         if node == nil {
55                 return nil, errors.New("can't find block header in given height")
56         }
57         return node.BlockHeader(), nil
58 }
59
60 func (c *Chain) calcReorganizeNodes(node *state.BlockNode) ([]*state.BlockNode, []*state.BlockNode) {
61         var attachNodes []*state.BlockNode
62         var detachNodes []*state.BlockNode
63
64         attachNode := node
65         for c.index.NodeByHeight(attachNode.Height) != attachNode {
66                 attachNodes = append([]*state.BlockNode{attachNode}, attachNodes...)
67                 attachNode = attachNode.Parent
68         }
69
70         detachNode := c.bestNode
71         for detachNode != attachNode {
72                 detachNodes = append(detachNodes, detachNode)
73                 detachNode = detachNode.Parent
74         }
75         return attachNodes, detachNodes
76 }
77
78 func (c *Chain) connectBlock(block *types.Block) (err error) {
79         irreversibleNode := c.bestIrreversibleNode
80         bcBlock := types.MapBlock(block)
81         if bcBlock.TransactionStatus, err = c.store.GetTransactionStatus(&bcBlock.ID); err != nil {
82                 return err
83         }
84
85         utxoView := state.NewUtxoViewpoint()
86         if err := c.store.GetTransactionsUtxo(utxoView, bcBlock.Transactions); err != nil {
87                 return err
88         }
89         if err := utxoView.ApplyBlock(bcBlock, bcBlock.TransactionStatus); err != nil {
90                 return err
91         }
92
93         voteResult, err := c.consensusNodeManager.getBestVoteResult()
94         if err != nil {
95                 return err
96         }
97         if err := voteResult.ApplyBlock(block); err != nil {
98                 return err
99         }
100
101         node := c.index.GetNode(&bcBlock.ID)
102         if c.isIrreversible(node) && block.Height > irreversibleNode.Height {
103                 irreversibleNode = node
104         }
105
106         if err := c.setState(node, irreversibleNode, utxoView, []*state.VoteResult{voteResult}); 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         voteResults := []*state.VoteResult{}
120         irreversibleNode := c.bestIrreversibleNode
121         voteResult, err := c.consensusNodeManager.getBestVoteResult()
122         if err != nil {
123                 return err
124         }
125
126         for _, detachNode := range detachNodes {
127                 b, err := c.store.GetBlock(&detachNode.Hash)
128                 if err != nil {
129                         return err
130                 }
131
132                 if b.Height <= irreversibleNode.Height {
133                         return errors.New("the height of rollback block below the height of irreversible block")
134                 }
135
136                 detachBlock := types.MapBlock(b)
137                 if err := c.store.GetTransactionsUtxo(utxoView, detachBlock.Transactions); err != nil {
138                         return err
139                 }
140
141                 txStatus, err := c.GetTransactionStatus(&detachBlock.ID)
142                 if err != nil {
143                         return err
144                 }
145
146                 if err := utxoView.DetachBlock(detachBlock, txStatus); err != nil {
147                         return err
148                 }
149
150                 if err := voteResult.DetachBlock(b); err != nil {
151                         return err
152                 }
153
154                 log.WithFields(log.Fields{"module": logModule, "height": node.Height, "hash": node.Hash.String()}).Debug("detach from mainchain")
155         }
156
157         for _, attachNode := range attachNodes {
158                 b, err := c.store.GetBlock(&attachNode.Hash)
159                 if err != nil {
160                         return err
161                 }
162
163                 attachBlock := types.MapBlock(b)
164                 if err := c.store.GetTransactionsUtxo(utxoView, attachBlock.Transactions); err != nil {
165                         return err
166                 }
167
168                 txStatus, err := c.GetTransactionStatus(&attachBlock.ID)
169                 if err != nil {
170                         return err
171                 }
172
173                 if err := utxoView.ApplyBlock(attachBlock, txStatus); err != nil {
174                         return err
175                 }
176
177                 if err := voteResult.ApplyBlock(b); err != nil {
178                         return err
179                 }
180
181                 if voteResult.IsFinalize() {
182                         voteResults = append(voteResults, voteResult.Fork())
183                 }
184
185                 if c.isIrreversible(attachNode) && b.Height > irreversibleNode.Height {
186                         irreversibleNode = attachNode
187                 }
188
189                 log.WithFields(log.Fields{"module": logModule, "height": node.Height, "hash": node.Hash.String()}).Debug("attach from mainchain")
190         }
191
192         voteResults = append(voteResults, voteResult.Fork())
193         return c.setState(node, irreversibleNode, utxoView, voteResults)
194 }
195
196 // SaveBlock will validate and save block into storage
197 func (c *Chain) saveBlock(block *types.Block) error {
198         if _, err := c.validateSign(block); err != nil {
199                 return errors.Sub(ErrBadBlock, err)
200         }
201
202         parent := c.index.GetNode(&block.PreviousBlockHash)
203         bcBlock := types.MapBlock(block)
204         if err := validation.ValidateBlock(bcBlock, parent); err != nil {
205                 return errors.Sub(ErrBadBlock, err)
206         }
207
208         signature, err := c.SignBlock(block)
209         if err != nil {
210                 return errors.Sub(ErrBadBlock, err)
211         }
212
213         if err := c.store.SaveBlock(block, bcBlock.TransactionStatus); err != nil {
214                 return err
215         }
216
217         c.orphanManage.Delete(&bcBlock.ID)
218         node, err := state.NewBlockNode(&block.BlockHeader, parent)
219         if err != nil {
220                 return err
221         }
222
223         c.index.AddNode(node)
224
225         if len(signature) != 0 {
226                 xPub := config.CommonConfig.PrivateKey().XPub()
227                 if err := c.eventDispatcher.Post(event.BlockSignatureEvent{BlockHash: block.Hash(), Signature: signature, XPub: xPub}); err != nil {
228                         return err
229                 }
230         }
231         return nil
232 }
233
234 func (c *Chain) saveSubBlock(block *types.Block) *types.Block {
235         blockHash := block.Hash()
236         prevOrphans, ok := c.orphanManage.GetPrevOrphans(&blockHash)
237         if !ok {
238                 return block
239         }
240
241         bestBlock := block
242         for _, prevOrphan := range prevOrphans {
243                 orphanBlock, ok := c.orphanManage.Get(prevOrphan)
244                 if !ok {
245                         log.WithFields(log.Fields{"module": logModule, "hash": prevOrphan.String()}).Warning("saveSubBlock fail to get block from orphanManage")
246                         continue
247                 }
248                 if err := c.saveBlock(orphanBlock); err != nil {
249                         log.WithFields(log.Fields{"module": logModule, "hash": prevOrphan.String(), "height": orphanBlock.Height}).Warning("saveSubBlock fail to save block")
250                         continue
251                 }
252
253                 if subBestBlock := c.saveSubBlock(orphanBlock); subBestBlock.Height > bestBlock.Height {
254                         bestBlock = subBestBlock
255                 }
256         }
257         return bestBlock
258 }
259
260 type processBlockResponse struct {
261         isOrphan bool
262         err      error
263 }
264
265 type processBlockMsg struct {
266         block *types.Block
267         reply chan processBlockResponse
268 }
269
270 // ProcessBlock is the entry for chain update
271 func (c *Chain) ProcessBlock(block *types.Block) (bool, error) {
272         reply := make(chan processBlockResponse, 1)
273         c.processBlockCh <- &processBlockMsg{block: block, reply: reply}
274         response := <-reply
275         return response.isOrphan, response.err
276 }
277
278 func (c *Chain) blockProcesser() {
279         for msg := range c.processBlockCh {
280                 isOrphan, err := c.processBlock(msg.block)
281                 msg.reply <- processBlockResponse{isOrphan: isOrphan, err: err}
282         }
283 }
284
285 // ProcessBlock is the entry for handle block insert
286 func (c *Chain) processBlock(block *types.Block) (bool, error) {
287         if block.Height <= c.bestIrreversibleNode.Height {
288                 return false, errors.New("the height of block below the height of irreversible block")
289         }
290
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         if bestNode.Parent == c.bestNode {
311                 log.WithFields(log.Fields{"module": logModule}).Debug("append block to the end of mainchain")
312                 return false, c.connectBlock(bestBlock)
313         }
314
315         if bestNode.Height > c.bestNode.Height {
316                 log.WithFields(log.Fields{"module": logModule}).Debug("start to reorganize chain")
317                 return false, c.reorganizeChain(bestNode)
318         }
319         return false, nil
320 }