OSDN Git Service

03337a2efad27bbb944399c3e4c07a74df10676b
[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) isIrreversible(blockHeader *types.BlockHeader) bool {
32         consensusNodes, err := c.getConsensusNodes(&blockHeader.PreviousBlockHash)
33         if err != nil {
34                 return false
35         }
36
37         signCount := 0
38         for i := 0; i < len(consensusNodes); i++ {
39                 if blockHeader.BlockWitness.Get(uint64(i)) != nil {
40                         signCount++
41                 }
42         }
43
44         return signCount > len(consensusNodes)*2/3
45 }
46
47 // GetConsensusResultByHash return vote result by block hash
48 func (c *Chain) GetConsensusResultByHash(blockHash *bc.Hash) (*state.ConsensusResult, error) {
49         blockHeader, err := c.store.GetBlockHeader(blockHash)
50         if err != nil {
51                 return nil, err
52         }
53         return c.getConsensusResult(state.CalcVoteSeq(blockHeader.Height), blockHeader)
54 }
55
56 // IsBlocker returns whether the consensus node is a blocker at the specified time
57 func (c *Chain) IsBlocker(prevBlockHash *bc.Hash, pubKey string, timeStamp uint64) (bool, error) {
58         xPub, err := c.GetBlocker(prevBlockHash, timeStamp)
59         if err != nil {
60                 return false, err
61         }
62         return xPub == pubKey, nil
63 }
64
65 // ProcessBlockSignature process the received block signature messages
66 // return whether a block become irreversible, if so, the chain module must update status
67 func (c *Chain) ProcessBlockSignature(signature, xPub []byte, blockHash *bc.Hash) error {
68         xpubStr := hex.EncodeToString(xPub[:])
69         blockHeader, _ := c.store.GetBlockHeader(blockHash)
70
71         // save the signature if the block is not exist
72         if blockHeader == nil {
73                 cacheKey := signCacheKey(blockHash.String(), xpubStr)
74                 c.signatureCache.Add(cacheKey, signature)
75                 return nil
76         }
77
78         consensusNode, err := c.getConsensusNode(&blockHeader.PreviousBlockHash, xpubStr)
79         if err != nil {
80                 return err
81         }
82
83         if blockHeader.BlockWitness.Get(consensusNode.Order) != nil {
84                 return nil
85         }
86
87         c.cond.L.Lock()
88         defer c.cond.L.Unlock()
89         if err := c.checkNodeSign(blockHeader, consensusNode, signature); err != nil {
90                 return err
91         }
92
93         if err := c.updateBlockSignature(blockHeader, consensusNode.Order, signature); err != nil {
94                 return err
95         }
96         return c.eventDispatcher.Post(event.BlockSignatureEvent{BlockHash: *blockHash, Signature: signature, XPub: xPub})
97 }
98
99 // validateSign verify the signatures of block, and return the number of correct signature
100 // if some signature is invalid, they will be reset to nil
101 // if the block has not the signature of blocker, it will return error
102 func (c *Chain) validateSign(block *types.Block) error {
103         consensusNodeMap, err := c.getConsensusNodes(&block.PreviousBlockHash)
104         if err != nil {
105                 return err
106         }
107
108         hasBlockerSign := false
109         blockHash := block.Hash()
110         for pubKey, node := range consensusNodeMap {
111                 if len(block.Witness) <= int(node.Order) {
112                         continue
113                 }
114
115                 if block.Get(node.Order) == nil {
116                         cachekey := signCacheKey(blockHash.String(), pubKey)
117                         if signature, ok := c.signatureCache.Get(cachekey); ok {
118                                 block.Set(node.Order, signature.([]byte))
119                         } else {
120                                 continue
121                         }
122                 }
123
124                 if err := c.checkNodeSign(&block.BlockHeader, node, block.Get(node.Order)); err == errDoubleSignBlock {
125                         log.WithFields(log.Fields{"module": logModule, "blockHash": blockHash.String(), "pubKey": pubKey}).Warn("the consensus node double sign the same height of different block")
126                         block.Delete(node.Order)
127                         continue
128                 } else if err != nil {
129                         return err
130                 }
131
132                 isBlocker, err := c.IsBlocker(&block.PreviousBlockHash, pubKey, block.Timestamp)
133                 if err != nil {
134                         return err
135                 }
136
137                 if isBlocker {
138                         hasBlockerSign = true
139                 }
140
141         }
142
143         if !hasBlockerSign {
144                 return errors.New("the block has no signature of the blocker")
145         }
146         return nil
147 }
148
149 func (c *Chain) checkNodeSign(bh *types.BlockHeader, consensusNode *state.ConsensusNode, signature []byte) error {
150         if !consensusNode.XPub.Verify(bh.Hash().Bytes(), signature) {
151                 return errInvalidSignature
152         }
153
154         blockHashes, err := c.store.GetBlockHashesByHeight(bh.Height)
155         if err != nil {
156                 return err
157         }
158
159         for _, blockHash := range blockHashes {
160                 if *blockHash == bh.Hash() {
161                         continue
162                 }
163
164                 blockHeader, err := c.store.GetBlockHeader(blockHash)
165                 if err != nil {
166                         return err
167                 }
168
169                 consensusNode, err := c.getConsensusNode(&blockHeader.PreviousBlockHash, consensusNode.XPub.String())
170                 if err != nil && err != errNotFoundConsensusNode {
171                         return err
172                 }
173
174                 if err == errNotFoundConsensusNode {
175                         continue
176                 }
177
178                 if blockHeader.BlockWitness.Get(consensusNode.Order) != nil {
179                         return errDoubleSignBlock
180                 }
181         }
182         return nil
183 }
184
185 // SignBlock signing the block if current node is consensus node
186 func (c *Chain) SignBlock(block *types.Block) ([]byte, error) {
187         xprv := config.CommonConfig.PrivateKey()
188         xpubStr := xprv.XPub().String()
189         node, err := c.getConsensusNode(&block.PreviousBlockHash, xpubStr)
190         if err == errNotFoundConsensusNode {
191                 return nil, nil
192         } else if err != nil {
193                 return nil, err
194         }
195
196         //check double sign in same block height
197         blockHashes, err := c.store.GetBlockHashesByHeight(block.Height)
198         if err != nil {
199                 return nil, err
200         }
201
202         for _, hash := range blockHashes {
203                 blockHeader, err := c.store.GetBlockHeader(hash)
204                 if err != nil {
205                         return nil, err
206                 }
207
208                 // Has already signed the same height block
209                 if blockHeader.BlockWitness.Get(node.Order) != nil {
210                         return nil, nil
211                 }
212         }
213
214         signature := block.Get(node.Order)
215         if len(signature) == 0 {
216                 signature = xprv.Sign(block.Hash().Bytes())
217                 block.Set(node.Order, signature)
218         }
219         return signature, nil
220 }
221
222 func (c *Chain) updateBlockSignature(blockHeader *types.BlockHeader, nodeOrder uint64, signature []byte) error {
223         blockHeader.Set(nodeOrder, signature)
224         if err := c.store.SaveBlockHeader(blockHeader); err != nil {
225                 return err
226         }
227
228         if c.isIrreversible(blockHeader) && blockHeader.Height > c.bestIrrBlockHeader.Height {
229                 if err := c.store.SaveChainStatus(c.bestBlockHeader, blockHeader, []*types.BlockHeader{}, state.NewUtxoViewpoint(), []*state.ConsensusResult{}); err != nil {
230                         return err
231                 }
232                 c.bestIrrBlockHeader = blockHeader
233         }
234         return nil
235 }