OSDN Git Service

Fix vote (#106)
[bytom/vapor.git] / protocol / bbft.go
1 package protocol
2
3 import (
4         "encoding/hex"
5         "fmt"
6
7         "github.com/golang/groupcache/lru"
8         log "github.com/sirupsen/logrus"
9
10         "github.com/vapor/config"
11         "github.com/vapor/crypto/ed25519"
12         "github.com/vapor/crypto/ed25519/chainkd"
13         "github.com/vapor/errors"
14         "github.com/vapor/event"
15         "github.com/vapor/protocol/bc"
16         "github.com/vapor/protocol/bc/types"
17         "github.com/vapor/protocol/state"
18 )
19
20 const (
21         maxSignatureCacheSize = 10000
22 )
23
24 var (
25         errVotingOperationOverFlow = errors.New("voting operation result overflow")
26         errDoubleSignBlock         = errors.New("the consensus is double sign in same height of different block")
27         errInvalidSignature        = errors.New("the signature of block is invalid")
28 )
29
30 type bbft struct {
31         consensusNodeManager *consensusNodeManager
32         orphanManage         *OrphanManage
33         signatureCache       *lru.Cache
34         eventDispatcher      *event.Dispatcher
35 }
36
37 func newBbft(store Store, blockIndex *state.BlockIndex, orphanManage *OrphanManage, eventDispatcher *event.Dispatcher) *bbft {
38         return &bbft{
39                 orphanManage:         orphanManage,
40                 consensusNodeManager: newConsensusNodeManager(store, blockIndex),
41                 signatureCache:       lru.New(maxSignatureCacheSize),
42                 eventDispatcher:      eventDispatcher,
43         }
44 }
45
46 func (b *bbft) isIrreversible(block *types.Block) bool {
47         consensusNodes, err := b.consensusNodeManager.getConsensusNodesByVoteResult(&block.PreviousBlockHash)
48         if err != nil {
49                 return false
50         }
51
52         signNum, err := b.validateSign(block)
53         if err != nil {
54                 return false
55         }
56
57         return signNum > (uint64(len(consensusNodes)) * 2 / 3)
58 }
59
60 // NextLeaderTime returns the start time of the specified public key as the next leader node
61 func (b *bbft) NextLeaderTimeRange(pubkey []byte, prevBlockHash *bc.Hash) (uint64, uint64, error) {
62         return b.consensusNodeManager.nextLeaderTimeRange(pubkey, prevBlockHash)
63 }
64
65 func (b *bbft) ApplyBlock(voteResultMap map[uint64]*state.VoteResult, block *types.Block) (err error) {
66         return b.consensusNodeManager.applyBlock(voteResultMap, block)
67 }
68
69 func (b *bbft) DetachBlock(voteResultMap map[uint64]*state.VoteResult, block *types.Block) error {
70         return b.consensusNodeManager.detachBlock(voteResultMap, block)
71 }
72
73 // ProcessBlockSignature process the received block signature messages
74 // return whether a block become irreversible, if so, the chain module must update status
75 func (b *bbft) ProcessBlockSignature(signature []byte, xPub [64]byte, blockHeight uint64, blockHash *bc.Hash) (bool, error) {
76         block, err := b.consensusNodeManager.store.GetBlock(blockHash)
77         if err != nil {
78                 // block is not exist, save the signature
79                 key := fmt.Sprintf("%s:%s", blockHash.String(), hex.EncodeToString(xPub[:]))
80                 b.signatureCache.Add(key, signature)
81                 return false, err
82         }
83
84         consensusNode, err := b.consensusNodeManager.getConsensusNode(&block.PreviousBlockHash, hex.EncodeToString(xPub[:]))
85         if err != nil {
86                 return false, err
87         }
88
89         if chainkd.XPub(xPub).Verify(blockHash.Bytes(), signature) {
90                 return false, errInvalidSignature
91         }
92
93         isDoubleSign, err := b.checkDoubleSign(consensusNode.order, blockHeight, *blockHash)
94         if err != nil {
95                 return false, err
96         }
97
98         if isDoubleSign {
99                 log.WithFields(log.Fields{"module": logModule, "blockHash": blockHash.String(), "xPub": hex.EncodeToString(xPub[:])}).Warn("the consensus node double sign the same height of different block")
100                 return false, errDoubleSignBlock
101         }
102
103         orphanBlock, ok := b.orphanManage.Get(blockHash)
104         if ok {
105                 orphanBlock.Witness[consensusNode.order] = signature
106                 return false, nil
107         }
108
109         if err := b.updateBlockSignature(block, consensusNode.order, signature); err != nil {
110                 return false, err
111         }
112
113         return b.isIrreversible(block), nil
114 }
115
116 // ValidateBlock verify whether the block is valid
117 func (b *bbft) ValidateBlock(block *types.Block) error {
118         signNum, err := b.validateSign(block)
119         if err != nil {
120                 return err
121         }
122
123         if signNum == 0 {
124                 return errors.New("no valid signature")
125         }
126         return nil
127 }
128
129 // validateSign verify the signatures of block, and return the number of correct signature
130 // if some signature is invalid, they will be reset to nil
131 // if the block has not the signature of blocker, it will return error
132 func (b *bbft) validateSign(block *types.Block) (uint64, error) {
133         var correctSignNum uint64
134         consensusNodeMap, err := b.consensusNodeManager.getConsensusNodesByVoteResult(&block.PreviousBlockHash)
135         if err != nil {
136                 return 0, err
137         }
138
139         hasBlockerSign := false
140         for pubKey, node := range consensusNodeMap {
141                 if len(block.Witness) <= int(node.order) {
142                         continue
143                 }
144
145                 blockHash := block.Hash()
146                 if block.Witness[node.order] == nil {
147                         key := fmt.Sprintf("%s:%s", blockHash.String(), pubKey)
148                         signature, ok := b.signatureCache.Get(key)
149                         if ok {
150                                 block.Witness[node.order] = signature.([]byte)
151                         }
152                 }
153
154                 pubKeyBytes, err := hex.DecodeString(pubKey)
155                 if err != nil {
156                         return 0, err
157                 }
158
159                 if ed25519.Verify(ed25519.PublicKey(pubKeyBytes[:32]), blockHash.Bytes(), block.Witness[node.order]) {
160                         isDoubleSign, err := b.checkDoubleSign(node.order, block.Height, block.Hash())
161                         if err != nil {
162                                 return 0, err
163                         }
164
165                         if isDoubleSign {
166                                 log.WithFields(log.Fields{"module": logModule, "blockHash": blockHash.String(), "pubKey": pubKey}).Warn("the consensus node double sign the same height of different block")
167                                 // Consensus node is signed twice with the same block height, discard the signature
168                                 block.Witness[node.order] = nil
169                         } else {
170                                 correctSignNum++
171                                 isBlocker, err := b.consensusNodeManager.isBlocker(block, pubKey)
172                                 if err != nil {
173                                         return 0, err
174                                 }
175                                 if isBlocker {
176                                         hasBlockerSign = true
177                                 }
178                         }
179                 } else {
180                         // discard the invalid signature
181                         block.Witness[node.order] = nil
182                 }
183         }
184         if !hasBlockerSign {
185                 return 0, errors.New("the block has no signature of the blocker")
186         }
187         return correctSignNum, nil
188 }
189
190 func (b *bbft) checkDoubleSign(nodeOrder, blockHeight uint64, blockHash bc.Hash) (bool, error) {
191         blockNodes := b.consensusNodeManager.blockIndex.NodesByHeight(blockHeight)
192         for _, blockNode := range blockNodes {
193                 if blockNode.Hash == blockHash {
194                         continue
195                 }
196                 if ok, err := blockNode.BlockWitness.Test(uint32(nodeOrder)); err != nil && ok {
197                         block, err := b.consensusNodeManager.store.GetBlock(&blockHash)
198                         if err != nil {
199                                 return false, err
200                         }
201
202                         // reset nil to discard signature
203                         if err := b.updateBlockSignature(block, nodeOrder, nil); err != nil {
204                                 return false, err
205                         }
206
207                         return true, nil
208                 }
209         }
210         return false, nil
211 }
212
213 // SignBlock signing the block if current node is consensus node
214 func (b *bbft) SignBlock(block *types.Block) ([]byte, error) {
215         xprv := config.CommonConfig.PrivateKey()
216         xpub := [64]byte(xprv.XPub())
217         node, err := b.consensusNodeManager.getConsensusNode(&block.PreviousBlockHash, hex.EncodeToString(xpub[:]))
218         if err != nil && err != errNotFoundConsensusNode {
219                 return nil, err
220         }
221
222         if node == nil {
223                 return nil, nil
224         }
225
226         signature := block.Witness[node.order]
227         if len(signature) == 0 {
228                 signature = xprv.Sign(block.Hash().Bytes())
229                 block.Witness[node.order] = signature
230         }
231         return signature, nil
232 }
233
234 func (b *bbft) updateBlockSignature(block *types.Block, nodeOrder uint64, signature []byte) error {
235         blockHash := block.Hash()
236         blockNode := b.consensusNodeManager.blockIndex.GetNode(&blockHash)
237
238         if len(signature) != 0 {
239                 if err := blockNode.BlockWitness.Set(uint32(nodeOrder)); err != nil {
240                         return err
241                 }
242         } else {
243                 if err := blockNode.BlockWitness.Clean(uint32(nodeOrder)); err != nil {
244                         return err
245                 }
246         }
247
248         block.Witness[nodeOrder] = signature
249         txStatus, err := b.consensusNodeManager.store.GetTransactionStatus(&blockHash)
250         if err != nil {
251                 return err
252         }
253
254         return b.consensusNodeManager.store.SaveBlock(block, txStatus)
255 }
256
257 // SetBlockIndex set the block index field
258 func (b *bbft) SetBlockIndex(blockIndex *state.BlockIndex) {
259         b.consensusNodeManager.blockIndex = blockIndex
260 }