OSDN Git Service

fix rollback (#543)
[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 represent the consensus is double sign in same height of different block
24         ErrDoubleSignBlock  = errors.New("the consensus is double sign in same height of different block")
25         errInvalidSignature = errors.New("the signature of block is invalid")
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
153                         return err
154                 } else if err != nil {
155                         return err
156                 }
157
158                 if blocker == pubKey {
159                         hasBlockerSign = true
160                 }
161         }
162
163         if !hasBlockerSign {
164                 return errors.New("the block has no signature of the blocker")
165         }
166         return nil
167 }
168
169 // ProcessBlockSignature process the received block signature messages
170 // return whether a block become irreversible, if so, the chain module must update status
171 func (c *Chain) ProcessBlockSignature(signature, xPub []byte, blockHash *bc.Hash) error {
172         xpubStr := hex.EncodeToString(xPub[:])
173         blockHeader, _ := c.store.GetBlockHeader(blockHash)
174
175         // save the signature if the block is not exist
176         if blockHeader == nil {
177                 var xPubKey chainkd.XPub
178                 copy(xPubKey[:], xPub[:])
179                 if !xPubKey.Verify(blockHash.Bytes(), signature) {
180                         return errInvalidSignature
181                 }
182
183                 cacheKey := signCacheKey(blockHash.String(), xpubStr)
184                 c.signatureCache.Add(cacheKey, signature)
185                 return nil
186         }
187
188         consensusNode, err := c.getConsensusNode(&blockHeader.PreviousBlockHash, xpubStr)
189         if err != nil {
190                 return err
191         }
192
193         if blockHeader.BlockWitness.Get(consensusNode.Order) != nil {
194                 return nil
195         }
196
197         c.cond.L.Lock()
198         defer c.cond.L.Unlock()
199         if err := c.checkNodeSign(blockHeader, consensusNode, signature); err != nil {
200                 return err
201         }
202
203         if err := c.updateBlockSignature(blockHeader, consensusNode.Order, signature); err != nil {
204                 return err
205         }
206         return c.eventDispatcher.Post(event.BlockSignatureEvent{BlockHash: *blockHash, Signature: signature, XPub: xPub})
207 }
208
209 // SignBlockHeader signing the block if current node is consensus node
210 func (c *Chain) SignBlockHeader(blockHeader *types.BlockHeader) error {
211         c.cond.L.Lock()
212         _, err := c.signBlockHeader(blockHeader)
213         c.cond.L.Unlock()
214         return err
215 }
216
217 func (c *Chain) applyBlockSign(blockHeader *types.BlockHeader) error {
218         signature, err := c.signBlockHeader(blockHeader)
219         if err != nil {
220                 return err
221         }
222
223         if len(signature) == 0 {
224                 return nil
225         }
226
227         if err := c.store.SaveBlockHeader(blockHeader); err != nil {
228                 return err
229         }
230
231         xpub := config.CommonConfig.PrivateKey().XPub()
232         return c.eventDispatcher.Post(event.BlockSignatureEvent{BlockHash: blockHeader.Hash(), Signature: signature, XPub: xpub[:]})
233 }
234
235 func (c *Chain) signBlockHeader(blockHeader *types.BlockHeader) ([]byte, error) {
236         xprv := config.CommonConfig.PrivateKey()
237         xpub := xprv.XPub()
238         node, err := c.getConsensusNode(&blockHeader.PreviousBlockHash, xpub.String())
239         blockHash := blockHeader.Hash()
240         if err == errNotFoundConsensusNode {
241                 log.WithFields(log.Fields{"module": logModule, "blockHash": blockHash.String()}).Debug("can't find consensus node of current node")
242                 return nil, nil
243         } else if err != nil {
244                 return nil, err
245         }
246
247         if len(blockHeader.Get(node.Order)) != 0 {
248                 return nil, nil
249         }
250
251         if err := c.checkDoubleSign(blockHeader, node.XPub.String()); err == ErrDoubleSignBlock {
252                 log.WithFields(log.Fields{"module": logModule, "blockHash": blockHash.String()}).Warn("current node has double sign the block")
253                 return nil, nil
254         } else if err != nil {
255                 return nil, err
256         }
257
258         signature := xprv.Sign(blockHeader.Hash().Bytes())
259         blockHeader.Set(node.Order, signature)
260         return signature, nil
261 }