OSDN Git Service

add log (#373)
[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/crypto/ed25519/chainkd"
11         "github.com/vapor/errors"
12         "github.com/vapor/event"
13         "github.com/vapor/protocol/bc"
14         "github.com/vapor/protocol/bc/types"
15         "github.com/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                         block.BlockWitness.Delete(node.Order)
146                         continue
147                 } else if err != nil {
148                         return err
149                 }
150
151                 if blocker == pubKey {
152                         hasBlockerSign = true
153                 }
154         }
155
156         if !hasBlockerSign {
157                 return errors.New("the block has no signature of the blocker")
158         }
159         return nil
160 }
161
162 // ProcessBlockSignature process the received block signature messages
163 // return whether a block become irreversible, if so, the chain module must update status
164 func (c *Chain) ProcessBlockSignature(signature, xPub []byte, blockHash *bc.Hash) error {
165         xpubStr := hex.EncodeToString(xPub[:])
166         blockHeader, _ := c.store.GetBlockHeader(blockHash)
167
168         // save the signature if the block is not exist
169         if blockHeader == nil {
170                 var xPubKey chainkd.XPub
171                 copy(xPubKey[:], xPub[:])
172                 if !xPubKey.Verify(blockHash.Bytes(), signature) {
173                         return errInvalidSignature
174                 }
175
176                 cacheKey := signCacheKey(blockHash.String(), xpubStr)
177                 c.signatureCache.Add(cacheKey, signature)
178                 return nil
179         }
180
181         consensusNode, err := c.getConsensusNode(&blockHeader.PreviousBlockHash, xpubStr)
182         if err != nil {
183                 return err
184         }
185
186         if blockHeader.BlockWitness.Get(consensusNode.Order) != nil {
187                 return nil
188         }
189
190         c.cond.L.Lock()
191         defer c.cond.L.Unlock()
192         if err := c.checkNodeSign(blockHeader, consensusNode, signature); err != nil {
193                 return err
194         }
195
196         if err := c.updateBlockSignature(blockHeader, consensusNode.Order, signature); err != nil {
197                 return err
198         }
199         return c.eventDispatcher.Post(event.BlockSignatureEvent{BlockHash: *blockHash, Signature: signature, XPub: xPub})
200 }
201
202 // SignBlock signing the block if current node is consensus node
203 func (c *Chain) SignBlock(block *types.Block) ([]byte, error) {
204         xprv := config.CommonConfig.PrivateKey()
205         xpubStr := xprv.XPub().String()
206         node, err := c.getConsensusNode(&block.PreviousBlockHash, xpubStr)
207         if err == errNotFoundConsensusNode {
208                 return nil, nil
209         } else if err != nil {
210                 return nil, err
211         }
212
213         if err := c.checkDoubleSign(&block.BlockHeader, node.XPub.String()); err == errDoubleSignBlock {
214                 return nil, nil
215         } else if err != nil {
216                 return nil, err
217         }
218
219         signature := block.Get(node.Order)
220         if len(signature) == 0 {
221                 signature = xprv.Sign(block.Hash().Bytes())
222                 block.Set(node.Order, signature)
223         }
224         return signature, nil
225 }