OSDN Git Service

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