github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/consensus/dpos/epoch_context.go (about) 1 package dpos 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "errors" 7 "fmt" 8 "math/big" 9 "sort" 10 11 "github.com/quickchainproject/quickchain/common" 12 "github.com/quickchainproject/quickchain/core/state" 13 "github.com/quickchainproject/quickchain/core/types" 14 "github.com/quickchainproject/quickchain/log" 15 "github.com/quickchainproject/quickchain/rlp" 16 "github.com/quickchainproject/quickchain/trie" 17 ) 18 19 type EpochContext struct { 20 TimeStamp int64 21 DposContext *types.DposContext 22 statedb *state.StateDB 23 24 Number uint64 `json:"number"` // Block number 25 Hash common.Hash `json:"hash"` // Block hash 26 Signers map[common.Address]struct{} `json:"signers"` // Set of authorized signers at this moment 27 Recents map[uint64]common.Address `json:"recents"` // Set of recent signers for spam protections 28 } 29 30 // newEpochContext creates a new EpochContext with the specified startup parameters. This 31 // method does not initialize the set of recent signers, so only ever use if for 32 // the genesis block. 33 func newEpochContext(number uint64, hash common.Hash, dposContext *types.DposContext, state *state.StateDB) (epoch *EpochContext, err error) { 34 epoch = &EpochContext{ 35 DposContext: dposContext, 36 statedb: state, 37 Number: number, 38 Hash: hash, 39 Signers: make(map[common.Address]struct{}), 40 Recents: make(map[uint64]common.Address), 41 } 42 43 // get signer list 44 validators, err := dposContext.GetValidators() 45 if err != nil { 46 return nil, err 47 } 48 49 for _, signer := range validators { 50 epoch.Signers[signer] = struct{}{} 51 } 52 53 return epoch, nil 54 } 55 56 // countVotes 57 func (ec *EpochContext) countVotes() (votes map[common.Address]*big.Int, err error) { 58 votes = map[common.Address]*big.Int{} 59 delegateTrie := ec.DposContext.DelegateTrie() 60 candidateTrie := ec.DposContext.CandidateTrie() 61 statedb := ec.statedb 62 63 iterCandidate := trie.NewIterator(candidateTrie.NodeIterator(nil)) 64 existCandidate := iterCandidate.Next() 65 if !existCandidate { 66 return votes, errors.New("no candidates") 67 } 68 for existCandidate { 69 var cc types.CandidateContext 70 candidate := iterCandidate.Value 71 rlp.DecodeBytes(candidate, &cc) 72 candidateAddr := common.BytesToAddress(cc.Addr.Bytes()) 73 //delegateIterator := trie.NewIterator(delegateTrie.PrefixIterator(candidate)) 74 delegateIterator := trie.NewIterator(delegateTrie.PrefixIterator(cc.Addr.Bytes())) 75 existDelegator := delegateIterator.Next() 76 if !existDelegator { 77 log.Info("-------!existDelegator", "candidate", candidateAddr) 78 votes[candidateAddr] = new(big.Int) 79 existCandidate = iterCandidate.Next() 80 continue 81 } 82 for existDelegator { 83 log.Info("-------existDelegator", "candidate", candidateAddr) 84 delegator := delegateIterator.Value 85 score, ok := votes[candidateAddr] 86 if !ok { 87 score = new(big.Int) 88 } 89 delegatorAddr := common.BytesToAddress(delegator) 90 weight := statedb.GetBalance(delegatorAddr) 91 score.Add(score, weight) 92 votes[candidateAddr] = score 93 existDelegator = delegateIterator.Next() 94 } 95 existCandidate = iterCandidate.Next() 96 } 97 for k, v := range votes { 98 log.Info("votes:", "k", k, "v", v) 99 } 100 return votes, nil 101 } 102 103 // CommitScores commit candidate score into candidate tree in every epoch elec process 104 func (ec *EpochContext) CommitScores(scores map[common.Address]*big.Int) error { 105 for k, v := range scores { 106 cc, err := ec.DposContext.GetCandidateContext(k) 107 if err != nil { 108 return err 109 } 110 if bytes.Compare(cc.Addr.Bytes(), k.Bytes()) == 0 { 111 cc.Score = v 112 err = ec.DposContext.SetCandidateContext(cc) 113 if err != nil { 114 return err 115 } 116 } 117 } 118 return nil 119 } 120 121 func (ec *EpochContext) kickoutValidator() error { 122 validators, err := ec.DposContext.GetValidators() 123 if err != nil { 124 return fmt.Errorf("failed to get validator: %s", err) 125 } 126 if len(validators) == 0 { 127 return errors.New("no validator could be kickout") 128 } 129 130 needKickoutValidators := types.SortableAddresses{} 131 for _, validator := range validators { 132 133 key := validator.Bytes() 134 cnt := int64(0) 135 if cntBytes := ec.DposContext.MintCntTrie().Get(key); cntBytes != nil { 136 cnt = int64(binary.BigEndian.Uint64(cntBytes)) 137 } 138 if cnt < int64(epochLength)/maxValidatorSize/2 { 139 // not active validators need kickout 140 needKickoutValidators = append(needKickoutValidators, &types.SortableAddress{Address:validator, Weight:big.NewInt(cnt)}) 141 } 142 } 143 // clear mintcnt trie 144 mintCntTrie, _ := types.NewMintCntTrie(common.Hash{}, ec.DposContext.DB()) 145 ec.DposContext.SetMintCnt(mintCntTrie) 146 147 // no validators need kickout 148 needKickoutValidatorCnt := len(needKickoutValidators) 149 if needKickoutValidatorCnt <= 0 { 150 return nil 151 } 152 sort.Sort(sort.Reverse(needKickoutValidators)) 153 154 candidateCount := 0 155 iter := trie.NewIterator(ec.DposContext.CandidateTrie().NodeIterator(nil)) 156 for iter.Next() { 157 candidateCount++ 158 if candidateCount >= needKickoutValidatorCnt+safeSize { 159 break 160 } 161 } 162 163 for i, validator := range needKickoutValidators { 164 // ensure candidate count greater than or equal to safeSize 165 if candidateCount <= safeSize { 166 log.Info("No more candidate can be kickout", "candidateCount", candidateCount, "needKickoutCount", len(needKickoutValidators)-i) 167 return nil 168 } 169 170 if err := ec.DposContext.KickoutCandidate(validator.Address); err != nil { 171 return err 172 } 173 // if kickout success, candidateCount minus 1 174 candidateCount-- 175 log.Info("Kickout candidate", "candidate", validator.Address.String(), "mintCnt", validator.Weight.String()) 176 } 177 return nil 178 } 179 180 // update counts in MintCntTrie for the miner of newBlock 181 func (ec *EpochContext) updateMintCnt(validator common.Address) { 182 currentMintCntTrie := ec.DposContext.MintCntTrie() 183 184 cnt := int64(1) 185 186 cntBytes := currentMintCntTrie.Get(validator.Bytes()) 187 188 // not the first time to mint 189 if cntBytes != nil { 190 cnt = int64(binary.BigEndian.Uint64(cntBytes)) + 1 191 } 192 193 newCntBytes := make([]byte, 8) 194 binary.BigEndian.PutUint64(newCntBytes, uint64(cnt)) 195 ec.DposContext.MintCntTrie().TryUpdate(validator.Bytes(), newCntBytes) 196 } 197 198 func (ec *EpochContext) tryElect(genesis, parent *types.Header) error { 199 200 // if prevEpoch is not genesis, kickout not active candidate 201 /*if parent.Number.Uint64() != 0 { 202 if err := ec.kickoutValidator(); err != nil { 203 return err 204 } 205 }*/ 206 207 votes, err := ec.countVotes() 208 if err != nil { 209 return err 210 } 211 212 err = ec.CommitScores(votes) 213 if err != nil { 214 return err 215 } 216 217 candidates := types.SortableAddresses{} 218 for candidate, cnt := range votes { 219 candidates = append(candidates, &types.SortableAddress{Address:candidate, Weight:cnt}) 220 } 221 if len(candidates) < safeSize { 222 return errors.New("too few candidates") 223 } 224 sort.Sort(candidates) 225 if len(candidates) > maxValidatorSize { 226 candidates = candidates[:maxValidatorSize] 227 } 228 229 sortedValidators := make([]common.Address, 0) 230 for _, candidate := range candidates { 231 sortedValidators = append(sortedValidators, candidate.Address) 232 } 233 234 epochTrie, _ := types.NewEpochTrie(common.Hash{}, ec.DposContext.DB()) 235 ec.DposContext.SetEpoch(epochTrie) 236 ec.DposContext.SetValidators(sortedValidators) 237 ec.DposContext.SetSortableAddresses(candidates) 238 239 return nil 240 } 241 242 // signers retrieves the list of authorized signers in ascending order. 243 func (s *EpochContext) signers() []common.Address { 244 signers := make([]common.Address, 0, len(s.Signers)) 245 for signer := range s.Signers { 246 signers = append(signers, signer) 247 } 248 for i := 0; i < len(signers); i++ { 249 for j := i + 1; j < len(signers); j++ { 250 if bytes.Compare(signers[i][:], signers[j][:]) > 0 { 251 signers[i], signers[j] = signers[j], signers[i] 252 } 253 } 254 } 255 return signers 256 } 257 258 // inturn returns if a signer at a given block height is in-turn or not. 259 func (s *EpochContext) inturn(number uint64, signer common.Address) bool { 260 signers, offset := s.signers(), 0 261 for offset < len(signers) && signers[offset] != signer { 262 offset++ 263 } 264 return (number % uint64(len(signers))) == uint64(offset) 265 } 266 267 // inturn returns if a signer at a given block height is in-turn or not. 268 func (s *EpochContext) signerIndex(signer common.Address) uint64 { 269 signers, offset := s.signers(), 0 270 for offset < len(signers) && signers[offset] != signer { 271 offset++ 272 } 273 return uint64(offset) 274 }