OSDN Git Service

11dc0db6f20b751a3a2e190183407eca85c79277
[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                                 c.signatureCache.Remove(cachekey)
136                         } else {
137                                 continue
138                         }
139                 }
140
141                 if err := c.checkNodeSign(&block.BlockHeader, node, block.Get(node.Order)); err == errDoubleSignBlock {
142                         log.WithFields(log.Fields{"module": logModule, "blockHash": blockHash.String(), "pubKey": pubKey}).Warn("the consensus node double sign the same height of different block")
143                         block.BlockWitness.Delete(node.Order)
144                         continue
145                 } else if err != nil {
146                         return err
147                 }
148
149                 if blocker == pubKey {
150                         hasBlockerSign = true
151                 }
152         }
153
154         if !hasBlockerSign {
155                 return errors.New("the block has no signature of the blocker")
156         }
157         return nil
158 }
159
160 // ProcessBlockSignature process the received block signature messages
161 // return whether a block become irreversible, if so, the chain module must update status
162 func (c *Chain) ProcessBlockSignature(signature, xPub []byte, blockHash *bc.Hash) error {
163         xpubStr := hex.EncodeToString(xPub[:])
164         blockHeader, _ := c.store.GetBlockHeader(blockHash)
165
166         // save the signature if the block is not exist
167         if blockHeader == nil {
168                 cacheKey := signCacheKey(blockHash.String(), xpubStr)
169                 c.signatureCache.Add(cacheKey, signature)
170                 return nil
171         }
172
173         consensusNode, err := c.getConsensusNode(&blockHeader.PreviousBlockHash, xpubStr)
174         if err != nil {
175                 return err
176         }
177
178         if blockHeader.BlockWitness.Get(consensusNode.Order) != nil {
179                 return nil
180         }
181
182         c.cond.L.Lock()
183         defer c.cond.L.Unlock()
184         if err := c.checkNodeSign(blockHeader, consensusNode, signature); err != nil {
185                 return err
186         }
187
188         if err := c.updateBlockSignature(blockHeader, consensusNode.Order, signature); err != nil {
189                 return err
190         }
191         return c.eventDispatcher.Post(event.BlockSignatureEvent{BlockHash: *blockHash, Signature: signature, XPub: xPub})
192 }
193
194 // SignBlock signing the block if current node is consensus node
195 func (c *Chain) SignBlock(block *types.Block) ([]byte, error) {
196         xprv := config.CommonConfig.PrivateKey()
197         xpubStr := xprv.XPub().String()
198         node, err := c.getConsensusNode(&block.PreviousBlockHash, xpubStr)
199         if err == errNotFoundConsensusNode {
200                 return nil, nil
201         } else if err != nil {
202                 return nil, err
203         }
204
205         if err := c.checkDoubleSign(&block.BlockHeader, node.XPub.String()); err == errDoubleSignBlock {
206                 return nil, nil
207         } else if err != nil {
208                 return nil, err
209         }
210
211         signature := block.Get(node.Order)
212         if len(signature) == 0 {
213                 signature = xprv.Sign(block.Hash().Bytes())
214                 block.Set(node.Order, signature)
215         }
216         return signature, nil
217 }