OSDN Git Service

fix bug
[bytom/vapor.git] / protocol / block.go
1 package protocol
2
3 import (
4         "encoding/json"
5
6         "github.com/vapor/protocol/vm"
7
8         log "github.com/sirupsen/logrus"
9
10         "github.com/vapor/common"
11         "github.com/vapor/consensus"
12         engine "github.com/vapor/consensus/consensus"
13         dpos "github.com/vapor/consensus/consensus/dpos"
14         "github.com/vapor/errors"
15         "github.com/vapor/protocol/bc"
16         "github.com/vapor/protocol/bc/types"
17         "github.com/vapor/protocol/state"
18         "github.com/vapor/protocol/validation"
19 )
20
21 var (
22         // ErrBadBlock is returned when a block is invalid.
23         ErrBadBlock = errors.New("invalid block")
24         // ErrBadStateRoot is returned when the computed assets merkle root
25         // disagrees with the one declared in a block header.
26         ErrBadStateRoot = errors.New("invalid state merkle root")
27 )
28
29 // BlockExist check is a block in chain or orphan
30 func (c *Chain) BlockExist(hash *bc.Hash) bool {
31         return c.index.BlockExist(hash) || c.orphanManage.BlockExist(hash)
32 }
33
34 // GetBlockByHash return a block by given hash
35 func (c *Chain) GetBlockByHash(hash *bc.Hash) (*types.Block, error) {
36         return c.store.GetBlock(hash)
37 }
38
39 // GetBlockByHeight return a block header by given height
40 func (c *Chain) GetBlockByHeight(height uint64) (*types.Block, error) {
41         node := c.index.NodeByHeight(height)
42         if node == nil {
43                 return nil, errors.New("can't find block in given height")
44         }
45         return c.store.GetBlock(&node.Hash)
46 }
47
48 // GetHeaderByHash return a block header by given hash
49 func (c *Chain) GetHeaderByHash(hash *bc.Hash) (*types.BlockHeader, error) {
50         node := c.index.GetNode(hash)
51         if node == nil {
52                 return nil, errors.New("can't find block header in given hash")
53         }
54         return node.BlockHeader(), nil
55 }
56
57 // GetHeaderByHeight return a block header by given height
58 func (c *Chain) GetHeaderByHeight(height uint64) (*types.BlockHeader, error) {
59         node := c.index.NodeByHeight(height)
60         if node == nil {
61                 return nil, errors.New("can't find block header in given height")
62         }
63         return node.BlockHeader(), nil
64 }
65
66 func (c *Chain) calcReorganizeNodes(node *state.BlockNode) ([]*state.BlockNode, []*state.BlockNode) {
67         var attachNodes []*state.BlockNode
68         var detachNodes []*state.BlockNode
69
70         attachNode := node
71         for c.index.NodeByHeight(attachNode.Height) != attachNode {
72                 attachNodes = append([]*state.BlockNode{attachNode}, attachNodes...)
73                 attachNode = attachNode.Parent
74         }
75
76         detachNode := c.bestNode
77         for detachNode != attachNode {
78                 detachNodes = append(detachNodes, detachNode)
79                 detachNode = detachNode.Parent
80         }
81         return attachNodes, detachNodes
82 }
83
84 func (c *Chain) connectBlock(block *types.Block) (err error) {
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         node := c.index.GetNode(&bcBlock.ID)
98         if err := c.setState(node, utxoView); err != nil {
99                 return err
100         }
101         for _, tx := range block.Transactions {
102                 for key, value := range tx.Entries {
103                         switch value.(type) {
104                         case *bc.Claim:
105                                 c.store.SetWithdrawSpent(&key)
106                         default:
107                                 continue
108                         }
109                 }
110                 c.txPool.RemoveTransaction(&tx.Tx.ID)
111         }
112         return nil
113 }
114
115 func (c *Chain) reorganizeChain(node *state.BlockNode) error {
116         attachNodes, detachNodes := c.calcReorganizeNodes(node)
117         utxoView := state.NewUtxoViewpoint()
118
119         for _, detachNode := range detachNodes {
120                 b, err := c.store.GetBlock(&detachNode.Hash)
121                 if err != nil {
122                         return err
123                 }
124
125                 detachBlock := types.MapBlock(b)
126                 if err := c.store.GetTransactionsUtxo(utxoView, detachBlock.Transactions); err != nil {
127                         return err
128                 }
129                 txStatus, err := c.GetTransactionStatus(&detachBlock.ID)
130                 if err != nil {
131                         return err
132                 }
133                 if err := utxoView.DetachBlock(detachBlock, txStatus); err != nil {
134                         return err
135                 }
136
137                 log.WithFields(log.Fields{"height": node.Height, "hash": node.Hash.String()}).Debug("detach from mainchain")
138         }
139
140         for _, attachNode := range attachNodes {
141                 b, err := c.store.GetBlock(&attachNode.Hash)
142                 if err != nil {
143                         return err
144                 }
145
146                 attachBlock := types.MapBlock(b)
147                 if err := c.store.GetTransactionsUtxo(utxoView, attachBlock.Transactions); err != nil {
148                         return err
149                 }
150                 txStatus, err := c.GetTransactionStatus(&attachBlock.ID)
151                 if err != nil {
152                         return err
153                 }
154                 if err := utxoView.ApplyBlock(attachBlock, txStatus); err != nil {
155                         return err
156                 }
157
158                 log.WithFields(log.Fields{"height": node.Height, "hash": node.Hash.String()}).Debug("attach from mainchain")
159         }
160
161         return c.setState(node, utxoView)
162 }
163
164 func (c *Chain) consensusCheck(block *types.Block) error {
165         if err := dpos.GDpos.CheckBlockHeader(block.BlockHeader); err != nil {
166                 return err
167         }
168
169         if err := dpos.GDpos.IsValidBlockCheckIrreversibleBlock(block.Height, block.Hash()); err != nil {
170                 return err
171         }
172
173         if err := dpos.GDpos.CheckBlock(*block, true); err != nil {
174                 return err
175         }
176         return nil
177 }
178
179 // SaveBlock will validate and save block into storage
180 func (c *Chain) saveBlock(block *types.Block) error {
181         bcBlock := types.MapBlock(block)
182         parent := c.index.GetNode(&block.PreviousBlockHash)
183
184         if err := c.consensusCheck(block); err != nil {
185                 return err
186         }
187
188         if err := validation.ValidateBlock(bcBlock, parent, block); err != nil {
189                 return errors.Sub(ErrBadBlock, err)
190         }
191
192         if err := c.ProcessDPoSConnectBlock(block); err != nil {
193                 return err
194         }
195
196         if err := c.store.SaveBlock(block, bcBlock.TransactionStatus); err != nil {
197                 return err
198         }
199
200         c.orphanManage.Delete(&bcBlock.ID)
201         node, err := state.NewBlockNode(&block.BlockHeader, parent)
202         if err != nil {
203                 return err
204         }
205
206         c.index.AddNode(node)
207         return nil
208 }
209
210 func (c *Chain) saveSubBlock(block *types.Block) *types.Block {
211         blockHash := block.Hash()
212         prevOrphans, ok := c.orphanManage.GetPrevOrphans(&blockHash)
213         if !ok {
214                 return block
215         }
216
217         bestBlock := block
218         for _, prevOrphan := range prevOrphans {
219                 orphanBlock, ok := c.orphanManage.Get(prevOrphan)
220                 if !ok {
221                         log.WithFields(log.Fields{"hash": prevOrphan.String()}).Warning("saveSubBlock fail to get block from orphanManage")
222                         continue
223                 }
224                 if err := c.saveBlock(orphanBlock); err != nil {
225                         log.WithFields(log.Fields{"hash": prevOrphan.String(), "height": orphanBlock.Height}).Warning("saveSubBlock fail to save block")
226                         continue
227                 }
228
229                 if subBestBlock := c.saveSubBlock(orphanBlock); subBestBlock.Height > bestBlock.Height {
230                         bestBlock = subBestBlock
231                 }
232         }
233         return bestBlock
234 }
235
236 type processBlockResponse struct {
237         isOrphan bool
238         err      error
239 }
240
241 type processBlockMsg struct {
242         block *types.Block
243         reply chan processBlockResponse
244 }
245
246 // ProcessBlock is the entry for chain update
247 func (c *Chain) ProcessBlock(block *types.Block) (bool, error) {
248         reply := make(chan processBlockResponse, 1)
249         c.processBlockCh <- &processBlockMsg{block: block, reply: reply}
250         response := <-reply
251         return response.isOrphan, response.err
252 }
253
254 func (c *Chain) blockProcesser() {
255         for msg := range c.processBlockCh {
256                 isOrphan, err := c.processBlock(msg.block)
257                 msg.reply <- processBlockResponse{isOrphan: isOrphan, err: err}
258         }
259 }
260
261 // ProcessBlock is the entry for handle block insert
262 func (c *Chain) processBlock(block *types.Block) (bool, error) {
263         blockHash := block.Hash()
264         if c.BlockExist(&blockHash) {
265                 log.WithFields(log.Fields{"hash": blockHash.String(), "height": block.Height}).Info("block has been processed")
266                 return c.orphanManage.BlockExist(&blockHash), nil
267         }
268
269         if parent := c.index.GetNode(&block.PreviousBlockHash); parent == nil {
270                 c.orphanManage.Add(block)
271                 return true, nil
272         }
273
274         if err := c.saveBlock(block); err != nil {
275                 return false, err
276         }
277
278         bestBlock := c.saveSubBlock(block)
279         bestBlockHash := bestBlock.Hash()
280         bestNode := c.index.GetNode(&bestBlockHash)
281
282         if bestNode.Parent == c.bestNode {
283                 log.Debug("append block to the end of mainchain")
284                 return false, c.connectBlock(bestBlock)
285         }
286
287         if bestNode.Height > c.bestNode.Height {
288                 log.Debug("start to reorganize chain")
289                 return false, c.reorganizeChain(bestNode)
290         }
291         return false, nil
292 }
293
294 func (c *Chain) ProcessDPoSConnectBlock(block *types.Block) error {
295         mapTxFee := c.CalculateBalance(block, true)
296         if err := c.DoVoting(block, mapTxFee); err != nil {
297                 return err
298         }
299         return nil
300 }
301
302 func (c *Chain) DoVoting(block *types.Block, mapTxFee map[bc.Hash]uint64) error {
303         for _, tx := range block.Transactions {
304                 to := tx.Outputs[0]
305                 msg := &dpos.DposMsg{}
306
307                 if err := json.Unmarshal(tx.TxData.ReferenceData, &msg); err != nil {
308                         continue
309                 }
310                 var (
311                         address common.Address
312                         err     error
313                 )
314                 address, err = common.NewAddressWitnessPubKeyHash(to.ControlProgram[2:], &consensus.ActiveNetParams)
315                 if err != nil {
316                         address, err = common.NewAddressWitnessScriptHash(to.ControlProgram[2:], &consensus.ActiveNetParams)
317                         if err != nil {
318                                 return errors.New("ControlProgram cannot be converted to address")
319                         }
320                 }
321                 hash := block.Hash()
322                 height := block.Height
323                 switch msg.Type {
324                 case vm.OP_DELEGATE:
325                         continue
326                 case vm.OP_REGISTE:
327                         if mapTxFee[tx.Tx.ID] >= consensus.RegisrerForgerFee {
328                                 data := &dpos.RegisterForgerData{}
329                                 if err := json.Unmarshal(msg.Data, data); err != nil {
330                                         return err
331                                 }
332                                 c.Engine.ProcessRegister(address.EncodeAddress(), data.Name, hash, height)
333                         }
334                 case vm.OP_VOTE:
335                         if mapTxFee[tx.Tx.ID] >= consensus.VoteForgerFee {
336                                 data := &dpos.VoteForgerData{}
337                                 if err := json.Unmarshal(msg.Data, data); err != nil {
338                                         return err
339                                 }
340                                 c.Engine.ProcessVote(address.EncodeAddress(), data.Forgers, hash, height)
341                         }
342                 case vm.OP_REVOKE:
343                         if mapTxFee[tx.Tx.ID] >= consensus.CancelVoteForgerFee {
344                                 data := &dpos.CancelVoteForgerData{}
345                                 if err := json.Unmarshal(msg.Data, data); err != nil {
346                                         return err
347                                 }
348                                 c.Engine.ProcessCancelVote(address.EncodeAddress(), data.Forgers, hash, height)
349                         }
350                 }
351         }
352         return nil
353 }
354
355 func (c *Chain) CalculateBalance(block *types.Block, fIsAdd bool) map[bc.Hash]uint64 {
356
357         addressBalances := []engine.AddressBalance{}
358         mapTxFee := make(map[bc.Hash]uint64)
359         var (
360                 address common.Address
361                 err     error
362         )
363
364         for _, tx := range block.Transactions {
365                 fee := uint64(0)
366                 for _, input := range tx.Inputs {
367
368                         if len(tx.TxData.Inputs) == 1 &&
369                                 (tx.TxData.Inputs[0].InputType() == types.CoinbaseInputType ||
370                                         tx.TxData.Inputs[0].InputType() == types.ClainPeginInputType) {
371                                 continue
372                         }
373
374                         fee += input.Amount()
375                         value := int64(input.Amount())
376                         address, err = common.NewAddressWitnessPubKeyHash(input.ControlProgram()[2:], &consensus.ActiveNetParams)
377                         if err != nil {
378                                 address, err = common.NewAddressWitnessScriptHash(input.ControlProgram()[2:], &consensus.ActiveNetParams)
379                                 if err != nil {
380                                         continue
381                                 }
382                         }
383                         if fIsAdd {
384                                 value = 0 - value
385                         }
386                         addressBalances = append(addressBalances, engine.AddressBalance{address.EncodeAddress(), value})
387                 }
388                 for _, output := range tx.Outputs {
389                         fee -= output.Amount
390                         value := int64(output.Amount)
391                         address, err = common.NewAddressWitnessPubKeyHash(output.ControlProgram[2:], &consensus.ActiveNetParams)
392                         if err != nil {
393                                 address, err = common.NewAddressWitnessScriptHash(output.ControlProgram[2:], &consensus.ActiveNetParams)
394                                 if err != nil {
395                                         continue
396                                 }
397                         }
398                         if !fIsAdd {
399                                 value = 0 - value
400                         }
401                         addressBalances = append(addressBalances, engine.AddressBalance{address.EncodeAddress(), value})
402                 }
403                 mapTxFee[tx.Tx.ID] = fee
404         }
405
406         c.Engine.UpdateAddressBalance(addressBalances)
407         return mapTxFee
408 }
409
410 func (c *Chain) RepairDPoSData(oldBlockHeight uint64, oldBlockHash bc.Hash) error {
411         block, err := c.GetBlockByHash(&oldBlockHash)
412         if err != nil {
413                 return err
414         }
415         if block.Height != oldBlockHeight {
416                 return errors.New("The module vote records data with a problem")
417         }
418         for i := block.Height + 1; i < c.bestNode.Height; i++ {
419                 b, err := c.GetBlockByHeight(i)
420                 if err != nil {
421                         return err
422                 }
423                 if err := c.ProcessDPoSConnectBlock(b); err != nil {
424                         return err
425                 }
426
427         }
428         return nil
429 }