OSDN Git Service

fix_concurrent_sign_block
[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/bytom/vapor/config"
10         "github.com/bytom/vapor/crypto/ed25519/chainkd"
11         "github.com/bytom/vapor/errors"
12         "github.com/bytom/vapor/event"
13         "github.com/bytom/vapor/protocol/bc"
14         "github.com/bytom/vapor/protocol/bc/types"
15         "github.com/bytom/vapor/protocol/state"
16 )
17
18 const (
19         maxSignatureCacheSize = 10000
20 )
21
22 var (
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) checkDoubleSign(bh *types.BlockHeader, xPub string) error {
33         blockHashes, err := c.store.GetBlockHashesByHeight(bh.Height)
34         if err != nil {
35                 return err
36         }
37
38         for _, blockHash := range blockHashes {
39                 if *blockHash == bh.Hash() {
40                         continue
41                 }
42
43                 blockHeader, err := c.store.GetBlockHeader(blockHash)
44                 if err != nil {
45                         return err
46                 }
47
48                 consensusNode, err := c.getConsensusNode(&blockHeader.PreviousBlockHash, xPub)
49                 if err == errNotFoundConsensusNode {
50                         continue
51                 } else if err != nil {
52                         return err
53                 }
54
55                 if blockHeader.BlockWitness.Get(consensusNode.Order) != nil {
56                         return errDoubleSignBlock
57                 }
58         }
59         return nil
60 }
61
62 func (c *Chain) checkNodeSign(bh *types.BlockHeader, consensusNode *state.ConsensusNode, signature []byte) error {
63         if !consensusNode.XPub.Verify(bh.Hash().Bytes(), signature) {
64                 return errInvalidSignature
65         }
66
67         return c.checkDoubleSign(bh, consensusNode.XPub.String())
68 }
69
70 func (c *Chain) isIrreversible(blockHeader *types.BlockHeader) bool {
71         consensusNodes, err := c.getConsensusNodes(&blockHeader.PreviousBlockHash)
72         if err != nil {
73                 return false
74         }
75
76         signCount := 0
77         for i := 0; i < len(consensusNodes); i++ {
78                 if blockHeader.BlockWitness.Get(uint64(i)) != nil {
79                         signCount++
80                 }
81         }
82
83         return signCount > len(consensusNodes)*2/3
84 }
85
86 func (c *Chain) updateBlockSignature(blockHeader *types.BlockHeader, nodeOrder uint64, signature []byte) error {
87         blockHeader.Set(nodeOrder, signature)
88         if err := c.store.SaveBlockHeader(blockHeader); err != nil {
89                 return err
90         }
91
92         if !c.isIrreversible(blockHeader) || blockHeader.Height <= c.lastIrrBlockHeader.Height {
93                 return nil
94         }
95
96         if c.InMainChain(blockHeader.Hash()) {
97                 if err := c.store.SaveChainStatus(c.bestBlockHeader, blockHeader, []*types.BlockHeader{}, state.NewUtxoViewpoint(), []*state.ConsensusResult{}); err != nil {
98                         return err
99                 }
100
101                 c.lastIrrBlockHeader = blockHeader
102         } else {
103                 // block is on a forked chain
104                 log.WithFields(log.Fields{"module": logModule}).Info("majority votes received on forked chain")
105                 tail, err := c.traceLongestChainTail(blockHeader)
106                 if err != nil {
107                         return err
108                 }
109
110                 return c.reorganizeChain(tail)
111         }
112         return nil
113 }
114
115 // validateSign verify the signatures of block, and return the number of correct signature
116 // if some signature is invalid, they will be reset to nil
117 // if the block does not have the signature of blocker, it will return error
118 func (c *Chain) validateSign(block *types.Block) error {
119         consensusNodeMap, err := c.getConsensusNodes(&block.PreviousBlockHash)
120         if err != nil {
121                 return err
122         }
123
124         blocker, err := c.GetBlocker(&block.PreviousBlockHash, block.Timestamp)
125         if err != nil {
126                 return err
127         }
128
129         hasBlockerSign := false
130         blockHash := block.Hash()
131         for pubKey, node := range consensusNodeMap {
132                 if block.BlockWitness.Get(node.Order) == nil {
133                         cachekey := signCacheKey(blockHash.String(), pubKey)
134                         if signature, ok := c.signatureCache.Get(cachekey); ok {
135                                 block.Set(node.Order, signature.([]byte))
136                                 c.eventDispatcher.Post(event.BlockSignatureEvent{BlockHash: blockHash, Signature: signature.([]byte), XPub: node.XPub[:]})
137                                 c.signatureCache.Remove(cachekey)
138                         } else {
139                                 continue
140                         }
141                 }
142
143                 if err := c.checkNodeSign(&block.BlockHeader, node, block.Get(node.Order)); err == errDoubleSignBlock {
144                         log.WithFields(log.Fields{"module": logModule, "blockHash": blockHash.String(), "pubKey": pubKey}).Warn("the consensus node double sign the same height of different block")
145                         // if the blocker double sign & become the mainchain, that means
146                         // all the side chain will reject the main chain make the chain
147                         // fork. All the node will ban each other & can't roll back
148                         if blocker != pubKey {
149                                 block.BlockWitness.Delete(node.Order)
150                                 continue
151                         }
152                 } else if err != nil {
153                         return err
154                 }
155
156                 if blocker == pubKey {
157                         hasBlockerSign = true
158                 }
159         }
160
161         if !hasBlockerSign {
162                 return errors.New("the block has no signature of the blocker")
163         }
164         return nil
165 }
166
167 // ProcessBlockSignature process the received block signature messages
168 // return whether a block become irreversible, if so, the chain module must update status
169 func (c *Chain) ProcessBlockSignature(signature, xPub []byte, blockHash *bc.Hash) error {
170         xpubStr := hex.EncodeToString(xPub[:])
171         blockHeader, _ := c.store.GetBlockHeader(blockHash)
172
173         // save the signature if the block is not exist
174         if blockHeader == nil {
175                 var xPubKey chainkd.XPub
176                 copy(xPubKey[:], xPub[:])
177                 if !xPubKey.Verify(blockHash.Bytes(), signature) {
178                         return errInvalidSignature
179                 }
180
181                 cacheKey := signCacheKey(blockHash.String(), xpubStr)
182                 c.signatureCache.Add(cacheKey, signature)
183                 return nil
184         }
185
186         consensusNode, err := c.getConsensusNode(&blockHeader.PreviousBlockHash, xpubStr)
187         if err != nil {
188                 return err
189         }
190
191         if blockHeader.BlockWitness.Get(consensusNode.Order) != nil {
192                 return nil
193         }
194
195         c.cond.L.Lock()
196         defer c.cond.L.Unlock()
197         if err := c.checkNodeSign(blockHeader, consensusNode, signature); err != nil {
198                 return err
199         }
200
201         if err := c.updateBlockSignature(blockHeader, consensusNode.Order, signature); err != nil {
202                 return err
203         }
204         return c.eventDispatcher.Post(event.BlockSignatureEvent{BlockHash: *blockHash, Signature: signature, XPub: xPub})
205 }
206
207 // SignBlockHeader signing the block if current node is consensus node
208 func (c *Chain) SignBlockHeader(blockHeader *types.BlockHeader) error {
209         c.cond.L.Lock()
210         defer c.cond.L.Unlock()
211
212         _, err := c.signBlockHeader(blockHeader)
213         if err != nil {
214                 return err
215         }
216
217         return c.store.SaveBlockHeader(blockHeader)
218 }
219
220 func (c *Chain) applyBlockSign(blockHeader *types.BlockHeader) error {
221         signature, err := c.signBlockHeader(blockHeader)
222         if err != nil {
223                 return err
224         }
225
226         if len(signature) == 0 {
227                 return nil
228         }
229
230         if err := c.store.SaveBlockHeader(blockHeader); err != nil {
231                 return err
232         }
233
234         xpub := config.CommonConfig.PrivateKey().XPub()
235         return c.eventDispatcher.Post(event.BlockSignatureEvent{BlockHash: blockHeader.Hash(), Signature: signature, XPub: xpub[:]})
236 }
237
238 func (c *Chain) signBlockHeader(blockHeader *types.BlockHeader) ([]byte, error) {
239         xprv := config.CommonConfig.PrivateKey()
240         xpub := xprv.XPub()
241         node, err := c.getConsensusNode(&blockHeader.PreviousBlockHash, xpub.String())
242         blockHash := blockHeader.Hash()
243         if err == errNotFoundConsensusNode {
244                 log.WithFields(log.Fields{"module": logModule, "blockHash": blockHash.String()}).Debug("can't find consensus node of current node")
245                 return nil, nil
246         } else if err != nil {
247                 return nil, err
248         }
249
250         if len(blockHeader.Get(node.Order)) != 0 {
251                 return nil, nil
252         }
253
254         if err := c.checkDoubleSign(blockHeader, node.XPub.String()); err == errDoubleSignBlock {
255                 log.WithFields(log.Fields{"module": logModule, "blockHash": blockHash.String()}).Warn("current node has double sign the block")
256                 return nil, nil
257         } else if err != nil {
258                 return nil, err
259         }
260
261         signature := xprv.Sign(blockHeader.Hash().Bytes())
262         blockHeader.Set(node.Order, signature)
263         return signature, nil
264 }