OSDN Git Service

modify general config (#257)
[bytom/vapor.git] / protocol / bbft.go
1 package protocol
2
3 import (
4         "encoding/hex"
5         "fmt"
6
7         log "github.com/sirupsen/logrus"
8
9         "github.com/vapor/config"
10         "github.com/vapor/errors"
11         "github.com/vapor/event"
12         "github.com/vapor/protocol/bc"
13         "github.com/vapor/protocol/bc/types"
14         "github.com/vapor/protocol/state"
15 )
16
17 const (
18         maxSignatureCacheSize = 10000
19 )
20
21 var (
22         errDoubleSignBlock  = errors.New("the consensus is double sign in same height of different block")
23         errInvalidSignature = errors.New("the signature of block is invalid")
24         errSignForkChain    = errors.New("can not sign fork before the irreversible block")
25 )
26
27 func signCacheKey(blockHash, pubkey string) string {
28         return fmt.Sprintf("%s:%s", blockHash, pubkey)
29 }
30
31 func (c *Chain) checkDoubleSign(bh *types.BlockHeader, xPub string) error {
32         blockHashes, err := c.store.GetBlockHashesByHeight(bh.Height)
33         if err != nil {
34                 return err
35         }
36
37         for _, blockHash := range blockHashes {
38                 if *blockHash == bh.Hash() {
39                         continue
40                 }
41
42                 blockHeader, err := c.store.GetBlockHeader(blockHash)
43                 if err != nil {
44                         return err
45                 }
46
47                 consensusNode, err := c.getConsensusNode(&blockHeader.PreviousBlockHash, xPub)
48                 if err == errNotFoundConsensusNode {
49                         continue
50                 } else if err != nil {
51                         return err
52                 }
53
54                 if blockHeader.BlockWitness.Get(consensusNode.Order) != nil {
55                         return errDoubleSignBlock
56                 }
57         }
58         return nil
59 }
60
61 func (c *Chain) checkNodeSign(bh *types.BlockHeader, consensusNode *state.ConsensusNode, signature []byte) error {
62         if !consensusNode.XPub.Verify(bh.Hash().Bytes(), signature) {
63                 return errInvalidSignature
64         }
65
66         return c.checkDoubleSign(bh, consensusNode.XPub.String())
67 }
68
69 func (c *Chain) isIrreversible(blockHeader *types.BlockHeader) bool {
70         consensusNodes, err := c.getConsensusNodes(&blockHeader.PreviousBlockHash)
71         if err != nil {
72                 return false
73         }
74
75         signCount := 0
76         for i := 0; i < len(consensusNodes); i++ {
77                 if blockHeader.BlockWitness.Get(uint64(i)) != nil {
78                         signCount++
79                 }
80         }
81
82         return signCount > len(consensusNodes)*2/3
83 }
84
85 func (c *Chain) updateBlockSignature(blockHeader *types.BlockHeader, nodeOrder uint64, signature []byte) error {
86         blockHeader.Set(nodeOrder, signature)
87         if err := c.store.SaveBlockHeader(blockHeader); err != nil {
88                 return err
89         }
90
91         if !c.isIrreversible(blockHeader) || blockHeader.Height <= c.lastIrrBlockHeader.Height {
92                 return nil
93         }
94
95         if c.InMainChain(blockHeader.Hash()) {
96                 if err := c.store.SaveChainStatus(c.bestBlockHeader, blockHeader, []*types.BlockHeader{}, state.NewUtxoViewpoint(), []*state.ConsensusResult{}); err != nil {
97                         return err
98                 }
99
100                 c.lastIrrBlockHeader = blockHeader
101         } else {
102                 // block is on a forked chain
103                 log.WithFields(log.Fields{"module": logModule}).Info("majority votes received on forked chain")
104                 tail, err := c.traceLongestChainTail(blockHeader)
105                 if err != nil {
106                         return err
107                 }
108
109                 return c.reorganizeChain(tail)
110         }
111         return nil
112 }
113
114 // validateSign verify the signatures of block, and return the number of correct signature
115 // if some signature is invalid, they will be reset to nil
116 // if the block does not have the signature of blocker, it will return error
117 func (c *Chain) validateSign(block *types.Block) error {
118         consensusNodeMap, err := c.getConsensusNodes(&block.PreviousBlockHash)
119         if err != nil {
120                 return err
121         }
122
123         blocker, err := c.GetBlocker(&block.PreviousBlockHash, block.Timestamp)
124         if err != nil {
125                 return err
126         }
127
128         hasBlockerSign := false
129         blockHash := block.Hash()
130         for pubKey, node := range consensusNodeMap {
131                 if block.BlockWitness.Get(node.Order) == nil {
132                         cachekey := signCacheKey(blockHash.String(), pubKey)
133                         if signature, ok := c.signatureCache.Get(cachekey); ok {
134                                 block.Set(node.Order, signature.([]byte))
135                         } else {
136                                 continue
137                         }
138                 }
139
140                 if err := c.checkNodeSign(&block.BlockHeader, node, block.Get(node.Order)); err == errDoubleSignBlock {
141                         log.WithFields(log.Fields{"module": logModule, "blockHash": blockHash.String(), "pubKey": pubKey}).Warn("the consensus node double sign the same height of different block")
142                         block.BlockWitness.Delete(node.Order)
143                         continue
144                 } else if err != nil {
145                         return err
146                 }
147
148                 if blocker == pubKey {
149                         hasBlockerSign = true
150                 }
151         }
152
153         if !hasBlockerSign {
154                 return errors.New("the block has no signature of the blocker")
155         }
156         return nil
157 }
158
159 // ProcessBlockSignature process the received block signature messages
160 // return whether a block become irreversible, if so, the chain module must update status
161 func (c *Chain) ProcessBlockSignature(signature, xPub []byte, blockHash *bc.Hash) error {
162         xpubStr := hex.EncodeToString(xPub[:])
163         blockHeader, _ := c.store.GetBlockHeader(blockHash)
164
165         // save the signature if the block is not exist
166         if blockHeader == nil {
167                 cacheKey := signCacheKey(blockHash.String(), xpubStr)
168                 c.signatureCache.Add(cacheKey, signature)
169                 return nil
170         }
171
172         consensusNode, err := c.getConsensusNode(&blockHeader.PreviousBlockHash, xpubStr)
173         if err != nil {
174                 return err
175         }
176
177         if blockHeader.BlockWitness.Get(consensusNode.Order) != nil {
178                 return nil
179         }
180
181         c.cond.L.Lock()
182         defer c.cond.L.Unlock()
183         if err := c.checkNodeSign(blockHeader, consensusNode, signature); err != nil {
184                 return err
185         }
186
187         if err := c.updateBlockSignature(blockHeader, consensusNode.Order, signature); err != nil {
188                 return err
189         }
190         return c.eventDispatcher.Post(event.BlockSignatureEvent{BlockHash: *blockHash, Signature: signature, XPub: xPub})
191 }
192
193 // SignBlock signing the block if current node is consensus node
194 func (c *Chain) SignBlock(block *types.Block) ([]byte, error) {
195         xprv := config.CommonConfig.PrivateKey()
196         xpubStr := xprv.XPub().String()
197         node, err := c.getConsensusNode(&block.PreviousBlockHash, xpubStr)
198         if err == errNotFoundConsensusNode {
199                 return nil, nil
200         } else if err != nil {
201                 return nil, err
202         }
203
204         if err := c.checkDoubleSign(&block.BlockHeader, node.XPub.String()); err == errDoubleSignBlock {
205                 return nil, nil
206         } else if err != nil {
207                 return nil, err
208         }
209
210         signature := block.Get(node.Order)
211         if len(signature) == 0 {
212                 signature = xprv.Sign(block.Hash().Bytes())
213                 block.Set(node.Order, signature)
214         }
215         return signature, nil
216 }