OSDN Git Service

fix vote result (#94)
[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/crypto/ed25519"
11         "github.com/vapor/crypto/ed25519/chainkd"
12         "github.com/vapor/errors"
13         "github.com/vapor/event"
14         "github.com/vapor/protocol/bc"
15         "github.com/vapor/protocol/bc/types"
16         "github.com/vapor/protocol/state"
17 )
18
19 const (
20         maxSignatureCacheSize = 10000
21 )
22
23 var (
24         errVotingOperationOverFlow = errors.New("voting operation result overflow")
25         errDoubleSignBlock         = errors.New("the consensus is double sign in same height of different block")
26         errInvalidSignature        = errors.New("the signature of block is invalid")
27 )
28
29 type bbft struct {
30         consensusNodeManager *consensusNodeManager
31         orphanManage         *OrphanManage
32         signatureCache       *lru.Cache
33         eventDispatcher      *event.Dispatcher
34 }
35
36 func newBbft(store Store, blockIndex *state.BlockIndex, orphanManage *OrphanManage, eventDispatcher *event.Dispatcher) *bbft {
37         return &bbft{
38                 orphanManage:         orphanManage,
39                 consensusNodeManager: newConsensusNodeManager(store, blockIndex),
40                 signatureCache:       lru.New(maxSignatureCacheSize),
41                 eventDispatcher:      eventDispatcher,
42         }
43 }
44
45 // IsConsensusPubkey determine whether a public key is a consensus node at a specified height
46 func (b *bbft) IsConsensusPubkey(blockHash *bc.Hash, pubkey []byte) (bool, error) {
47         node, err := b.consensusNodeManager.getConsensusNode(blockHash, hex.EncodeToString(pubkey))
48         if err != nil && err != errNotFoundConsensusNode {
49                 return false, err
50         }
51         return node != nil, nil
52 }
53
54 func (b *bbft) isIrreversible(block *types.Block) bool {
55         signNum, err := b.validateSign(block)
56         if err != nil {
57                 return false
58         }
59
60         return signNum > (numOfConsensusNode * 2 / 3)
61 }
62
63 // NextLeaderTime returns the start time of the specified public key as the next leader node
64 func (b *bbft) NextLeaderTimeRange(pubkey []byte, bestBlockHash *bc.Hash) (uint64, uint64, error) {
65         return b.consensusNodeManager.nextLeaderTimeRange(pubkey, bestBlockHash)
66 }
67
68 func (b *bbft) ApplyBlock(voteResultMap map[uint64]*state.VoteResult, block *types.Block) (err error) {
69         return b.consensusNodeManager.applyBlock(voteResultMap, block)
70 }
71
72 func (b *bbft) DetachBlock(voteResultMap map[uint64]*state.VoteResult, block *types.Block) error {
73         return b.consensusNodeManager.detachBlock(voteResultMap, block)
74 }
75
76 // ProcessBlockSignature process the received block signature messages
77 // return once a block become irreversible, whether it's height greater than best block height
78 // if so, the chain module must update status
79 func (b *bbft) ProcessBlockSignature(signature, pubkey []byte, blockHeight uint64, blockHash *bc.Hash) (bool, error) {
80         consensusNode, err := b.consensusNodeManager.getConsensusNode(blockHash, hex.EncodeToString(pubkey))
81         if err != nil {
82                 return false, err
83         }
84
85         if !ed25519.Verify(ed25519.PublicKey(pubkey), blockHash.Bytes(), signature) {
86                 return false, errInvalidSignature
87         }
88
89         isDoubleSign, err := b.checkDoubleSign(consensusNode.order, blockHeight, *blockHash)
90         if err != nil {
91                 return false, err
92         }
93
94         if isDoubleSign {
95                 log.WithFields(log.Fields{"module": logModule, "blockHash": blockHash.String(), "pubkey": pubkey}).Warn("the consensus node double sign the same height of different block")
96                 return false, errDoubleSignBlock
97         }
98
99         orphanBlock, ok := b.orphanManage.Get(blockHash)
100         if ok {
101                 orphanBlock.Witness[consensusNode.order] = signature
102                 return false, nil
103         }
104
105         block, err := b.consensusNodeManager.store.GetBlock(blockHash)
106         if err != nil {
107                 // block is not exist, save the signature
108                 key := fmt.Sprintf("%s:%s", blockHash.String(), hex.EncodeToString(pubkey))
109                 b.signatureCache.Add(key, signature)
110                 return false, err
111         }
112
113         if err := b.updateBlockSignature(block, consensusNode.order, signature); err != nil {
114                 return false, err
115         }
116
117         return b.isIrreversible(block) && blockHeight > b.consensusNodeManager.blockIndex.BestNode().Height, nil
118 }
119
120 // ValidateBlock verify whether the block is valid
121 func (b *bbft) ValidateBlock(block *types.Block) error {
122         signNum, err := b.validateSign(block)
123         if err != nil {
124                 return err
125         }
126
127         if signNum == 0 {
128                 return errors.New("no valid signature")
129         }
130         return nil
131 }
132
133 // validateSign verify the signatures of block, and return the number of correct signature
134 // if some signature is invalid, they will be reset to nil
135 // if the block has not the signature of blocker, it will return error
136 func (b *bbft) validateSign(block *types.Block) (uint64, error) {
137         var correctSignNum uint64
138         blockHash := block.Hash()
139         consensusNodeMap, err := b.consensusNodeManager.getConsensusNodesByVoteResult(&blockHash)
140         if err != nil {
141                 return 0, err
142         }
143
144         hasBlockerSign := false
145         for pubkey, node := range consensusNodeMap {
146                 if len(block.Witness) <= int(node.order) {
147                         continue
148                 }
149
150                 blockHash := block.Hash()
151                 if block.Witness[node.order] == nil {
152                         key := fmt.Sprintf("%s:%s", blockHash.String(), pubkey)
153                         signature, ok := b.signatureCache.Get(key)
154                         if ok {
155                                 block.Witness[node.order] = signature.([]byte)
156                         }
157                 }
158
159                 if ed25519.Verify(ed25519.PublicKey(pubkey), 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(&blockHash, 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         var xprv chainkd.XPrv
216         xpub := [64]byte(xprv.XPub())
217         blockHash := block.Hash()
218         node, err := b.consensusNodeManager.getConsensusNode(&blockHash, hex.EncodeToString(xpub[:]))
219         if err != nil && err != errNotFoundConsensusNode {
220                 return nil, err
221         }
222
223         if node == nil {
224                 return nil, nil
225         }
226
227         signature := xprv.Sign(block.Hash().Bytes())
228         block.Witness[node.order] = signature
229         return signature, nil
230 }
231
232 func (b *bbft) updateBlockSignature(block *types.Block, nodeOrder uint64, signature []byte) error {
233         blockHash := block.Hash()
234         blockNode := b.consensusNodeManager.blockIndex.GetNode(&blockHash)
235
236         if len(signature) != 0 {
237                 if err := blockNode.BlockWitness.Set(uint32(nodeOrder)); err != nil {
238                         return err
239                 }
240         } else {
241                 if err := blockNode.BlockWitness.Clean(uint32(nodeOrder)); err != nil {
242                         return err
243                 }
244         }
245
246         block.Witness[nodeOrder] = signature
247         txStatus, err := b.consensusNodeManager.store.GetTransactionStatus(&blockHash)
248         if err != nil {
249                 return err
250         }
251
252         return b.consensusNodeManager.store.SaveBlock(block, txStatus)
253 }