7 "github.com/vapor/protocol/bc"
10 type TallyItem struct {
15 type TallySlice []TallyItem
17 func (s TallySlice) Len() int { return len(s) }
18 func (s TallySlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
19 func (s TallySlice) Less(i, j int) bool {
20 //we need sort reverse, so ...
21 if s[i].stake > s[j].stake {
24 } else if s[i].stake < s[j].stake {
28 //return bytes.Compare(s[i].addr.ScriptAddress(), s[j].addr.ScriptAddress()) > 0
29 return s[i].addr > s[j].addr
32 type SignerItem struct {
37 type SignerSlice []SignerItem
39 func (s SignerSlice) Len() int { return len(s) }
40 func (s SignerSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
41 func (s SignerSlice) Less(i, j int) bool {
42 return bytes.Compare(s[i].hash.Bytes(), s[j].hash.Bytes()) > 0
45 // verify the SignerQueue base on block hash
46 func (s *Snapshot) verifySignerQueue(signerQueue []string) error {
48 if len(signerQueue) > int(s.config.MaxSignerCount) {
49 return errInvalidSignerQueue
51 sq, err := s.createSignerQueue()
55 if len(sq) == 0 || len(sq) != len(signerQueue) {
56 return errInvalidSignerQueue
58 for i, signer := range signerQueue {
60 return errInvalidSignerQueue
67 func (s *Snapshot) buildTallySlice() TallySlice {
68 var tallySlice TallySlice
69 for address, stake := range s.Tally {
70 if !candidateNeedPD || s.isCandidate(address) {
71 if _, ok := s.Punished[address]; ok {
72 var creditWeight uint64
73 if s.Punished[address] > defaultFullCredit-minCalSignerQueueCredit {
74 creditWeight = minCalSignerQueueCredit
76 creditWeight = defaultFullCredit - s.Punished[address]
78 tallySlice = append(tallySlice, TallyItem{address, stake * creditWeight})
80 tallySlice = append(tallySlice, TallyItem{address, stake * defaultFullCredit})
87 func (s *Snapshot) createSignerQueue() ([]string, error) {
89 if (s.Number+1)%s.config.MaxSignerCount != 0 || s.Hash != s.HistoryHash[len(s.HistoryHash)-1] {
90 return nil, errCreateSignerQueueNotAllowed
93 var signerSlice SignerSlice
94 var topStakeAddress []string
95 if (s.Number+1)%(s.config.MaxSignerCount*s.LCRS) == 0 {
96 // before recalculate the signers, clear the candidate is not in snap.Candidates
98 // only recalculate signers from to tally per 10 loop,
99 // other loop end just reset the order of signers by block hash (nearly random)
100 tallySlice := s.buildTallySlice()
101 sort.Sort(TallySlice(tallySlice))
102 queueLength := int(s.config.MaxSignerCount)
103 if queueLength > len(tallySlice) {
104 queueLength = len(tallySlice)
106 if queueLength == defaultOfficialMaxSignerCount && len(tallySlice) > defaultOfficialThirdLevelCount {
107 for i, tallyItem := range tallySlice[:defaultOfficialFirstLevelCount] {
108 signerSlice = append(signerSlice, SignerItem{tallyItem.addr, s.HistoryHash[len(s.HistoryHash)-1-i]})
110 var signerSecondLevelSlice, signerThirdLevelSlice, signerLastLevelSlice SignerSlice
112 for i, tallyItem := range tallySlice[defaultOfficialFirstLevelCount:defaultOfficialSecondLevelCount] {
113 signerSecondLevelSlice = append(signerSecondLevelSlice, SignerItem{tallyItem.addr, s.HistoryHash[len(s.HistoryHash)-1-i]})
115 sort.Sort(SignerSlice(signerSecondLevelSlice))
116 signerSlice = append(signerSlice, signerSecondLevelSlice[:6]...)
118 for i, tallyItem := range tallySlice[defaultOfficialSecondLevelCount:defaultOfficialThirdLevelCount] {
119 signerThirdLevelSlice = append(signerThirdLevelSlice, SignerItem{tallyItem.addr, s.HistoryHash[len(s.HistoryHash)-1-i]})
121 sort.Sort(SignerSlice(signerThirdLevelSlice))
122 signerSlice = append(signerSlice, signerThirdLevelSlice[:4]...)
123 // choose 1 from last
124 for i, tallyItem := range tallySlice[defaultOfficialThirdLevelCount:] {
125 signerLastLevelSlice = append(signerLastLevelSlice, SignerItem{tallyItem.addr, s.HistoryHash[len(s.HistoryHash)-1-i]})
127 sort.Sort(SignerSlice(signerLastLevelSlice))
128 signerSlice = append(signerSlice, signerLastLevelSlice[0])
131 for i, tallyItem := range tallySlice[:queueLength] {
132 signerSlice = append(signerSlice, SignerItem{tallyItem.addr, s.HistoryHash[len(s.HistoryHash)-1-i]})
138 for i, signer := range s.Signers {
139 signerSlice = append(signerSlice, SignerItem{*signer, s.HistoryHash[len(s.HistoryHash)-1-i]})
143 sort.Sort(SignerSlice(signerSlice))
144 // Set the top candidates in random order base on block hash
145 if len(signerSlice) == 0 {
146 return nil, errSignerQueueEmpty
148 for i := 0; i < int(s.config.MaxSignerCount); i++ {
149 topStakeAddress = append(topStakeAddress, signerSlice[i%len(signerSlice)].addr)
152 return topStakeAddress, nil