OSDN Git Service

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