OSDN Git Service

2d19aff41ae067eeb44a588b3f904d5c4dc27139
[bytom/vapor.git] / consensus / consensus / dpos / snapshot.go
1 package dpos
2
3 import (
4         "encoding/json"
5         "errors"
6         "math/big"
7         "sort"
8         "time"
9
10         lru "github.com/hashicorp/golang-lru"
11         "github.com/vapor/common"
12         "github.com/vapor/config"
13         "github.com/vapor/consensus"
14         "github.com/vapor/crypto"
15         "github.com/vapor/crypto/ed25519/chainkd"
16         "github.com/vapor/protocol"
17         "github.com/vapor/protocol/bc"
18         "github.com/vapor/protocol/bc/types"
19 )
20
21 const (
22         defaultFullCredit               = 1000 // no punished
23         missingPublishCredit            = 100  // punished for missing one block seal
24         signRewardCredit                = 10   // seal one block
25         autoRewardCredit                = 1    // credit auto recover for each block
26         minCalSignerQueueCredit         = 300  // when calculate the signerQueue
27         defaultOfficialMaxSignerCount   = 21   // official max signer count
28         defaultOfficialFirstLevelCount  = 10   // official first level , 100% in signer queue
29         defaultOfficialSecondLevelCount = 20   // official second level, 60% in signer queue
30         defaultOfficialThirdLevelCount  = 30   // official third level, 40% in signer queue
31         // the credit of one signer is at least minCalSignerQueueCredit
32         candidateStateNormal = 1
33         candidateMaxLen      = 500 // if candidateNeedPD is false and candidate is more than candidateMaxLen, then minimum tickets candidates will be remove in each LCRS*loop
34 )
35
36 var errIncorrectTallyCount = errors.New("incorrect tally count")
37
38 type Snapshot struct {
39         config          *config.DposConfig    // Consensus engine configuration parameters
40         sigcache        *lru.ARCCache         // Cache of recent block signatures to speed up ecrecover
41         LCRS            uint64                // Loop count to recreate signers from top tally
42         Period          uint64                `json:"period"`           // Period of seal each block
43         Number          uint64                `json:"number"`           // Block Number where the snapshot was created
44         ConfirmedNumber uint64                `json:"confirmed_number"` // Block Number confirmed when the snapshot was created
45         Hash            bc.Hash               `json:"hash"`             // Block hash where the snapshot was created
46         HistoryHash     []bc.Hash             `json:"historyHash"`      // Block hash list for two recent loop
47         Signers         []*string             `json:"signers"`          // Signers queue in current header
48         Votes           map[string]*Vote      `json:"votes"`            // All validate votes from genesis block
49         Tally           map[string]uint64     `json:"tally"`            // Stake for each candidate address
50         Voters          map[string]uint64     `json:"voters"`           // Block height for each voter address
51         Candidates      map[string]uint64     `json:"candidates"`       // Candidates for Signers (0- adding procedure 1- normal 2- removing procedure)
52         Punished        map[string]uint64     `json:"punished"`         // The signer be punished count cause of missing seal
53         Confirmations   map[uint64][]string   `json:"confirms"`         // The signer confirm given block height
54         Proposals       map[bc.Hash]*Proposal `json:"proposals"`        // The Proposals going or success (failed proposal will be removed)
55         HeaderTime      uint64                `json:"headerTime"`       // Time of the current header
56         LoopStartTime   uint64                `json:"loopStartTime"`    // Start Time of the current loop
57 }
58
59 // newSnapshot creates a new snapshot with the specified startup parameters. only ever use if for
60 // the genesis block.
61 func newSnapshot(config *config.DposConfig, sigcache *lru.ARCCache, hash bc.Hash, votes []*Vote, lcrs uint64) *Snapshot {
62
63         snap := &Snapshot{
64                 config:          config,
65                 sigcache:        sigcache,
66                 LCRS:            lcrs,
67                 Period:          config.Period,
68                 Number:          0,
69                 ConfirmedNumber: 0,
70                 Hash:            hash,
71                 HistoryHash:     []bc.Hash{},
72                 Signers:         []*string{},
73                 Votes:           make(map[string]*Vote),
74                 Tally:           make(map[string]uint64),
75                 Voters:          make(map[string]uint64),
76                 Punished:        make(map[string]uint64),
77                 Candidates:      make(map[string]uint64),
78                 Confirmations:   make(map[uint64][]string),
79                 Proposals:       make(map[bc.Hash]*Proposal),
80                 HeaderTime:      uint64(time.Now().Unix()) - 1,
81                 LoopStartTime:   config.GenesisTimestamp,
82         }
83         snap.HistoryHash = append(snap.HistoryHash, hash)
84         for _, vote := range votes {
85                 // init Votes from each vote
86                 snap.Votes[vote.Voter] = vote
87                 // init Tally
88                 _, ok := snap.Tally[vote.Candidate]
89                 if !ok {
90                         snap.Tally[vote.Candidate] = 0
91                 }
92                 snap.Tally[vote.Candidate] += vote.Stake
93                 // init Voters
94                 snap.Voters[vote.Voter] = 0 // block height is 0 , vote in genesis block
95                 // init Candidates
96                 snap.Candidates[vote.Voter] = candidateStateNormal
97         }
98
99         for i := 0; i < int(config.MaxSignerCount); i++ {
100                 snap.Signers = append(snap.Signers, &config.SelfVoteSigners[i%len(config.SelfVoteSigners)])
101         }
102
103         return snap
104 }
105
106 // loadSnapshot loads an existing snapshot from the database.
107 func loadSnapshot(config *config.DposConfig, sigcache *lru.ARCCache, store protocol.Store, hash bc.Hash) (*Snapshot, error) {
108         data, err := store.Get(&hash)
109         if err != nil {
110                 return nil, err
111         }
112         snap := new(Snapshot)
113         if err := json.Unmarshal(data, snap); err != nil {
114                 return nil, err
115         }
116         snap.config = config
117         snap.sigcache = sigcache
118         return snap, nil
119 }
120
121 // store inserts the snapshot into the database.
122 func (s *Snapshot) store(store protocol.Store) error {
123         data, err := json.Marshal(s)
124         if err != nil {
125                 return err
126         }
127         return store.Set(&s.Hash, data)
128 }
129
130 // copy creates a deep copy of the snapshot, though not the individual votes.
131 func (s *Snapshot) copy() *Snapshot {
132         cpy := &Snapshot{
133                 config:          s.config,
134                 sigcache:        s.sigcache,
135                 LCRS:            s.LCRS,
136                 Period:          s.Period,
137                 Number:          s.Number,
138                 ConfirmedNumber: s.ConfirmedNumber,
139                 Hash:            s.Hash,
140                 HistoryHash:     make([]bc.Hash, len(s.HistoryHash)),
141
142                 Signers:       make([]*string, len(s.Signers)),
143                 Votes:         make(map[string]*Vote),
144                 Tally:         make(map[string]uint64),
145                 Voters:        make(map[string]uint64),
146                 Candidates:    make(map[string]uint64),
147                 Punished:      make(map[string]uint64),
148                 Proposals:     make(map[bc.Hash]*Proposal),
149                 Confirmations: make(map[uint64][]string),
150
151                 HeaderTime:    s.HeaderTime,
152                 LoopStartTime: s.LoopStartTime,
153         }
154         copy(cpy.HistoryHash, s.HistoryHash)
155         copy(cpy.Signers, s.Signers)
156         for voter, vote := range s.Votes {
157                 cpy.Votes[voter] = &Vote{
158                         Voter:     vote.Voter,
159                         Candidate: vote.Candidate,
160                         Stake:     vote.Stake,
161                 }
162         }
163         for candidate, tally := range s.Tally {
164                 cpy.Tally[candidate] = tally
165         }
166         for voter, number := range s.Voters {
167                 cpy.Voters[voter] = number
168         }
169         for candidate, state := range s.Candidates {
170                 cpy.Candidates[candidate] = state
171         }
172         for signer, cnt := range s.Punished {
173                 cpy.Punished[signer] = cnt
174         }
175         for blockNumber, confirmers := range s.Confirmations {
176                 cpy.Confirmations[blockNumber] = make([]string, len(confirmers))
177                 copy(cpy.Confirmations[blockNumber], confirmers)
178         }
179         for txHash, proposal := range s.Proposals {
180                 cpy.Proposals[txHash] = proposal.copy()
181         }
182
183         return cpy
184 }
185
186 // apply creates a new authorization snapshot by applying the given headers to
187 // the original one.
188 func (s *Snapshot) apply(headers []*types.BlockHeader) (*Snapshot, error) {
189         // Allow passing in no headers for cleaner code
190         if len(headers) == 0 {
191                 return s, nil
192         }
193         // Sanity check that the headers can be applied
194         for i := 0; i < len(headers)-1; i++ {
195                 if headers[i+1].Height != headers[i].Height+1 {
196                         return nil, errInvalidVotingChain
197                 }
198         }
199         if headers[0].Height != s.Number+1 {
200                 return nil, errInvalidVotingChain
201         }
202         // Iterate through the headers and create a new snapshot
203         snap := s.copy()
204         for _, header := range headers {
205
206                 // Resolve the authorization key and check against signers
207                 coinbase, err := ecrecover(header, s.sigcache, nil)
208                 if err != nil {
209                         return nil, err
210                 }
211
212                 xpub := &chainkd.XPub{}
213                 xpub.UnmarshalText(header.Coinbase)
214                 derivedPK := xpub.PublicKey()
215                 pubHash := crypto.Ripemd160(derivedPK)
216                 address, err := common.NewAddressWitnessPubKeyHash(pubHash, &consensus.ActiveNetParams)
217                 if err != nil {
218                         return nil, err
219                 }
220                 if coinbase != address.EncodeAddress() {
221                         return nil, errUnauthorized
222                 }
223
224                 headerExtra := HeaderExtra{}
225                 if err := json.Unmarshal(header.Extra[extraVanity:len(header.Extra)-extraSeal], &headerExtra); err != nil {
226                         return nil, err
227                 }
228
229                 snap.HeaderTime = header.Timestamp
230                 snap.LoopStartTime = headerExtra.LoopStartTime
231                 snap.Signers = nil
232                 for i := range headerExtra.SignerQueue {
233                         snap.Signers = append(snap.Signers, &headerExtra.SignerQueue[i])
234                 }
235
236                 snap.ConfirmedNumber = headerExtra.ConfirmedBlockNumber
237
238                 if len(snap.HistoryHash) >= int(s.config.MaxSignerCount)*2 {
239                         snap.HistoryHash = snap.HistoryHash[1 : int(s.config.MaxSignerCount)*2]
240                 }
241
242                 snap.HistoryHash = append(snap.HistoryHash, header.Hash())
243
244                 // deal the new confirmation in this block
245                 snap.updateSnapshotByConfirmations(headerExtra.CurrentBlockConfirmations)
246
247                 // deal the new vote from voter
248                 snap.updateSnapshotByVotes(headerExtra.CurrentBlockVotes, header.Height)
249
250                 // deal the voter which balance modified
251                 //snap.updateSnapshotByMPVotes(headerExtra.ModifyPredecessorVotes)
252
253                 // deal the snap related with punished
254                 //snap.updateSnapshotForPunish(headerExtra.SignerMissing, header.Height, header.Coinbase)
255
256                 // deal proposals
257                 snap.updateSnapshotByProposals(headerExtra.CurrentBlockProposals, header.Height)
258
259                 // deal declares
260                 snap.updateSnapshotByDeclares(headerExtra.CurrentBlockDeclares, header.Height)
261
262                 // calculate proposal result
263                 snap.calculateProposalResult(header.Height)
264
265                 // check the len of candidate if not candidateNeedPD
266                 if !candidateNeedPD && (snap.Number+1)%(snap.config.MaxSignerCount*snap.LCRS) == 0 && len(snap.Candidates) > candidateMaxLen {
267                         snap.removeExtraCandidate()
268                 }
269
270         }
271         snap.Number += uint64(len(headers))
272         snap.Hash = headers[len(headers)-1].Hash()
273         snap.updateSnapshotForExpired()
274         err := snap.verifyTallyCnt()
275         if err != nil {
276                 return nil, err
277         }
278         return snap, nil
279 }
280
281 func (s *Snapshot) removeExtraCandidate() {
282         // remove minimum tickets tally beyond candidateMaxLen
283         tallySlice := s.buildTallySlice()
284         sort.Sort(TallySlice(tallySlice))
285         if len(tallySlice) > candidateMaxLen {
286                 removeNeedTally := tallySlice[candidateMaxLen:]
287                 for _, tallySlice := range removeNeedTally {
288                         delete(s.Candidates, tallySlice.addr)
289                 }
290         }
291 }
292
293 func (s *Snapshot) verifyTallyCnt() error {
294
295         tallyTarget := make(map[string]uint64)
296         for _, v := range s.Votes {
297                 if _, ok := tallyTarget[v.Candidate]; ok {
298                         tallyTarget[v.Candidate] = tallyTarget[v.Candidate] + v.Stake
299                 } else {
300                         tallyTarget[v.Candidate] = v.Stake
301                 }
302         }
303         for address, tally := range s.Tally {
304                 if targetTally, ok := tallyTarget[address]; ok && targetTally == tally {
305                         continue
306                 }
307         }
308
309         return nil
310 }
311
312 func (s *Snapshot) updateSnapshotByDeclares(declares []Declare, headerHeight uint64) {
313         for _, declare := range declares {
314                 if proposal, ok := s.Proposals[declare.ProposalHash]; ok {
315                         // check the proposal enable status and valid block number
316                         if proposal.ReceivedNumber+proposal.ValidationLoopCnt*s.config.MaxSignerCount < headerHeight || !s.isCandidate(declare.Declarer) {
317                                 continue
318                         }
319                         // check if this signer already declare on this proposal
320                         alreadyDeclare := false
321                         for _, v := range proposal.Declares {
322                                 if v.Declarer == declare.Declarer {
323                                         // this declarer already declare for this proposal
324                                         alreadyDeclare = true
325                                         break
326                                 }
327                         }
328                         if alreadyDeclare {
329                                 continue
330                         }
331                         // add declare to proposal
332                         s.Proposals[declare.ProposalHash].Declares = append(s.Proposals[declare.ProposalHash].Declares,
333                                 &Declare{declare.ProposalHash, declare.Declarer, declare.Decision})
334
335                 }
336         }
337 }
338
339 func (s *Snapshot) calculateProposalResult(headerHeight uint64) {
340
341         for hashKey, proposal := range s.Proposals {
342                 // the result will be calculate at receiverdNumber + vlcnt + 1
343                 if proposal.ReceivedNumber+proposal.ValidationLoopCnt*s.config.MaxSignerCount+1 == headerHeight {
344                         // calculate the current stake of this proposal
345                         judegmentStake := big.NewInt(0)
346                         for _, tally := range s.Tally {
347                                 judegmentStake.Add(judegmentStake, new(big.Int).SetUint64(tally))
348                         }
349                         judegmentStake.Mul(judegmentStake, big.NewInt(2))
350                         judegmentStake.Div(judegmentStake, big.NewInt(3))
351                         // calculate declare stake
352                         yesDeclareStake := big.NewInt(0)
353                         for _, declare := range proposal.Declares {
354                                 if declare.Decision {
355                                         if _, ok := s.Tally[declare.Declarer]; ok {
356                                                 yesDeclareStake.Add(yesDeclareStake, new(big.Int).SetUint64(s.Tally[declare.Declarer]))
357                                         }
358                                 }
359                         }
360                         if yesDeclareStake.Cmp(judegmentStake) > 0 {
361                                 // process add candidate
362                                 switch proposal.ProposalType {
363                                 case proposalTypeCandidateAdd:
364                                         if candidateNeedPD {
365                                                 s.Candidates[s.Proposals[hashKey].Candidate] = candidateStateNormal
366                                         }
367                                 case proposalTypeCandidateRemove:
368                                         if _, ok := s.Candidates[proposal.Candidate]; ok && candidateNeedPD {
369                                                 delete(s.Candidates, proposal.Candidate)
370                                         }
371                                 case proposalTypeMinerRewardDistributionModify:
372                                         minerRewardPerThousand = s.Proposals[hashKey].MinerRewardPerThousand
373
374                                 }
375                         }
376
377                 }
378
379         }
380
381 }
382
383 func (s *Snapshot) updateSnapshotByProposals(proposals []Proposal, headerHeight uint64) {
384         for _, proposal := range proposals {
385                 proposal.ReceivedNumber = headerHeight
386                 s.Proposals[proposal.Hash] = &proposal
387         }
388 }
389
390 func (s *Snapshot) updateSnapshotForExpired() {
391
392         // deal the expired vote
393         var expiredVotes []*Vote
394         for voterAddress, voteNumber := range s.Voters {
395                 if s.Number-voteNumber > s.config.Epoch {
396                         // clear the vote
397                         if expiredVote, ok := s.Votes[voterAddress]; ok {
398                                 expiredVotes = append(expiredVotes, expiredVote)
399                         }
400                 }
401         }
402         // remove expiredVotes only enough voters left
403         if uint64(len(s.Voters)-len(expiredVotes)) >= s.config.MaxSignerCount {
404                 for _, expiredVote := range expiredVotes {
405                         s.Tally[expiredVote.Candidate] -= expiredVote.Stake
406                         // TODO
407                         /*
408                                 if s.Tally[expiredVote.Candidate] == 0 {
409                                         delete(s.Tally, expiredVote.Candidate)
410                                 }
411                                 delete(s.Votes, expiredVote.Voter)
412                                 delete(s.Voters, expiredVote.Voter)
413                         */
414                 }
415         }
416
417         // deal the expired confirmation
418         for blockNumber := range s.Confirmations {
419                 if s.Number-blockNumber > s.config.MaxSignerCount {
420                         delete(s.Confirmations, blockNumber)
421                 }
422         }
423
424         // TODO
425         /*
426                 // remove 0 stake tally
427                 for address, tally := range s.Tally {
428                         if tally <= 0 {
429                                 delete(s.Tally, address)
430                         }
431                 }
432         */
433 }
434
435 func (s *Snapshot) updateSnapshotByConfirmations(confirmations []Confirmation) {
436         for _, confirmation := range confirmations {
437                 _, ok := s.Confirmations[confirmation.BlockNumber]
438                 if !ok {
439                         s.Confirmations[confirmation.BlockNumber] = []string{}
440                 }
441                 addConfirmation := true
442                 for _, address := range s.Confirmations[confirmation.BlockNumber] {
443                         if confirmation.Signer == address {
444                                 addConfirmation = false
445                                 break
446                         }
447                 }
448                 if addConfirmation == true {
449                         s.Confirmations[confirmation.BlockNumber] = append(s.Confirmations[confirmation.BlockNumber], confirmation.Signer)
450                 }
451         }
452 }
453
454 func (s *Snapshot) updateSnapshotByVotes(votes []Vote, headerHeight uint64) {
455         for _, vote := range votes {
456                 // update Votes, Tally, Voters data
457                 if lastVote, ok := s.Votes[vote.Voter]; ok {
458                         s.Tally[lastVote.Candidate] = s.Tally[lastVote.Candidate] - lastVote.Stake
459                 }
460                 if _, ok := s.Tally[vote.Candidate]; ok {
461                         s.Tally[vote.Candidate] = s.Tally[vote.Candidate] + vote.Stake
462                 } else {
463                         s.Tally[vote.Candidate] = vote.Stake
464                         if !candidateNeedPD {
465                                 s.Candidates[vote.Candidate] = candidateStateNormal
466                         }
467                 }
468                 s.Votes[vote.Voter] = &Vote{vote.Voter, vote.Candidate, vote.Stake}
469                 s.Voters[vote.Voter] = headerHeight
470         }
471 }
472
473 func (s *Snapshot) updateSnapshotByMPVotes(votes []Vote) {
474         for _, txVote := range votes {
475                 if lastVote, ok := s.Votes[txVote.Voter]; ok {
476                         s.Tally[lastVote.Candidate] = s.Tally[lastVote.Candidate] - lastVote.Stake
477                         s.Tally[lastVote.Candidate] = s.Tally[lastVote.Candidate] + txVote.Stake
478                         s.Votes[txVote.Voter] = &Vote{Voter: txVote.Voter, Candidate: lastVote.Candidate, Stake: txVote.Stake}
479                 }
480         }
481 }
482
483 func (s *Snapshot) updateSnapshotForPunish(signerMissing []string, headerNumber uint64, coinbase string) {
484         // set punished count to half of origin in Epoch
485         /*
486                 if headerNumber.Uint64()%s.config.Epoch == 0 {
487                         for bePublished := range s.Punished {
488                                 if count := s.Punished[bePublished] / 2; count > 0 {
489                                         s.Punished[bePublished] = count
490                                 } else {
491                                         delete(s.Punished, bePublished)
492                                 }
493                         }
494                 }
495         */
496         // punish the missing signer
497         for _, signerMissing := range signerMissing {
498                 if _, ok := s.Punished[signerMissing]; ok {
499                         s.Punished[signerMissing] += missingPublishCredit
500                 } else {
501                         s.Punished[signerMissing] = missingPublishCredit
502                 }
503         }
504         // reduce the punish of sign signer
505         if _, ok := s.Punished[coinbase]; ok {
506
507                 if s.Punished[coinbase] > signRewardCredit {
508                         s.Punished[coinbase] -= signRewardCredit
509                 } else {
510                         delete(s.Punished, coinbase)
511                 }
512         }
513         // reduce the punish for all punished
514         for signerEach := range s.Punished {
515                 if s.Punished[signerEach] > autoRewardCredit {
516                         s.Punished[signerEach] -= autoRewardCredit
517                 } else {
518                         delete(s.Punished, signerEach)
519                 }
520         }
521 }
522
523 // inturn returns if a signer at a given block height is in-turn or not.
524 func (s *Snapshot) inturn(signer string, headerTime uint64) bool {
525         // if all node stop more than period of one loop
526         loopIndex := int((headerTime-s.LoopStartTime)/s.config.Period) % len(s.Signers)
527         if loopIndex >= len(s.Signers) {
528                 return false
529         } else if *s.Signers[loopIndex] != signer {
530                 return false
531
532         }
533         return true
534 }
535
536 // check if address belong to voter
537 func (s *Snapshot) isVoter(address string) bool {
538         if _, ok := s.Voters[address]; ok {
539                 return true
540         }
541         return false
542 }
543
544 // check if address belong to candidate
545 func (s *Snapshot) isCandidate(address string) bool {
546         if _, ok := s.Candidates[address]; ok {
547                 return true
548         }
549         return false
550 }
551
552 // get last block number meet the confirm condition
553 func (s *Snapshot) getLastConfirmedBlockNumber(confirmations []Confirmation) *big.Int {
554
555         cpyConfirmations := make(map[uint64][]string)
556         for blockNumber, confirmers := range s.Confirmations {
557                 cpyConfirmations[blockNumber] = make([]string, len(confirmers))
558                 copy(cpyConfirmations[blockNumber], confirmers)
559         }
560         // update confirmation into snapshot
561         for _, confirmation := range confirmations {
562                 _, ok := cpyConfirmations[confirmation.BlockNumber]
563                 if !ok {
564                         cpyConfirmations[confirmation.BlockNumber] = []string{}
565                 }
566                 addConfirmation := true
567                 for _, address := range cpyConfirmations[confirmation.BlockNumber] {
568                         if confirmation.Signer == address {
569                                 addConfirmation = false
570                                 break
571                         }
572                 }
573                 if addConfirmation == true {
574
575                         cpyConfirmations[confirmation.BlockNumber] = append(cpyConfirmations[confirmation.BlockNumber], confirmation.Signer)
576                 }
577         }
578
579         i := s.Number
580         for ; i > s.Number-s.config.MaxSignerCount*2/3+1; i-- {
581                 if confirmers, ok := cpyConfirmations[i]; ok {
582                         if len(confirmers) > int(s.config.MaxSignerCount*2/3) {
583                                 return big.NewInt(int64(i))
584                         }
585                 }
586         }
587         return big.NewInt(int64(i))
588 }