github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/consensus/dpos/epoch_context.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 12:09:33</date> 10 //</624342611368349696> 11 12 package dpos 13 14 import ( 15 "encoding/binary" 16 "errors" 17 "fmt" 18 "math/big" 19 "sort" 20 21 "github.com/ethereum/go-ethereum/common" 22 "github.com/ethereum/go-ethereum/core/state" 23 "github.com/ethereum/go-ethereum/core/types" 24 "github.com/ethereum/go-ethereum/log" 25 "github.com/ethereum/go-ethereum/trie" 26 ) 27 28 type EpochContext struct { 29 TimeStamp int64 30 DposContext *types.DposContext 31 statedb *state.StateDB 32 } 33 34 /*特赦 35 return:返回票人对应选人代表 36 “0XFDB9694B92A33663F89C1FE8FCB3BD0BF07A9E09”:18000_ 37 **/ 38 39 func (ec *EpochContext) countVotes() (votes map[common.Address]*big.Int, err error) { 40 votes = map[common.Address]*big.Int{} 41 42 //获得投票者列表、候选人列表以及用户基本信息列表 43 delegateTrie := ec.DposContext.DelegateTrie() 44 candidateTrie := ec.DposContext.CandidateTrie() 45 statedb := ec.statedb 46 47 //代理人获得候选人名单 48 iterCandidate := trie.NewIterator(candidateTrie.NodeIterator(nil)) 49 existCandidate := iterCandidate.Next() 50 if !existCandidate { 51 return votes, errors.New("no candidates") 52 } 53 //末代皇帝5.srt 54 for existCandidate { 55 candidate := iterCandidate.Value //获取每个选项--bytes 56 candidateAddr := common.BytesToAddress(candidate) //将bytes转换为地址 57 delegateIterator := trie.NewIterator(delegateTrie.PrefixIterator(candidate)) //通过候选人找到每一个候选人对应票信息列表 58 existDelegator := delegateIterator.Next() //调用代理next()判断代理 59 if !existDelegator { //如果在候选人名单中为空 60 votes[candidateAddr] = new(big.Int) //在投票者隐蔽中追踪候选人信息 61 existCandidate = iterCandidate.Next() 62 continue 63 } 64 for existDelegator { //历任候选人对应票人信息列表 65 delegator := delegateIterator.Value // 66 score, ok := votes[candidateAddr] //获得候选人投票权 67 if !ok { 68 score = new(big.Int) //当没有查到投票者信息时,将定义一个局部历史分数 69 } 70 delegatorAddr := common.BytesToAddress(delegator) //将投票者字节类型转换为address 71 //获得投票者的余款作为票号累计到投票者的票号中 72 weight := statedb.GetBalance(delegatorAddr) 73 score.Add(score, weight) 74 votes[candidateAddr] = score 75 existDelegator = delegateIterator.Next() 76 } 77 existCandidate = iterCandidate.Next() 78 } 79 return votes, nil 80 } 81 82 //除害验证人计算法 83 func (ec *EpochContext) kickoutValidator(epoch int64,genesis *types.Header) error { 84 validators, err := ec.DposContext.GetValidators() 85 86 87 //var maxvalidator大小Int64 88 //var safesize int64 89 fmt.Println("++++++++++++++++++++++++++9999++++++++++++++++++++++\n") 90 fmt.Println("kickoutValidator test") 91 maxValidatorSize := genesis.MaxValidatorSize 92 safeSize := int(maxValidatorSize*2/3+1) 93 94 if err != nil { 95 return fmt.Errorf("failed to get validator: %s", err) 96 } 97 if len(validators) == 0 { 98 return errors.New("no validator could be kickout") 99 } 100 101 epochDuration := epochInterval 102 fmt.Println("0000000000000000000",epochDuration,"00000000000000\n") 103 blockInterval := genesis.BlockInterval 104 //第一个历元的持续时间可以是历元间隔, 105 //虽然第一个街区时间并不总是与时代间隔一致, 106 //所以用第一块时间而不是年代间隔来计算第一个时期的二分之一。 107 //防止验证器被错误地踢出。 108 if ec.TimeStamp-timeOfFirstBlock < epochInterval { 109 epochDuration = ec.TimeStamp - timeOfFirstBlock 110 } 111 112 needKickoutValidators := sortableAddresses{} 113 for _, validator := range validators { 114 key := make([]byte, 8) 115 binary.BigEndian.PutUint64(key, uint64(epoch)) 116 key = append(key, validator.Bytes()...) 117 cnt := int64(0) 118 if cntBytes := ec.DposContext.MintCntTrie().Get(key); cntBytes != nil { 119 cnt = int64(binary.BigEndian.Uint64(cntBytes)) 120 } 121 122 if cnt < epochDuration/int64(blockInterval)/ int64(maxValidatorSize) /2 { 123 //非活动验证器需要启动 124 needKickoutValidators = append(needKickoutValidators, &sortableAddress{validator, big.NewInt(cnt)}) 125 } 126 } 127 //没有验证器需要启动 128 needKickoutValidatorCnt := len(needKickoutValidators) 129 if needKickoutValidatorCnt <= 0 { 130 return nil 131 } 132 sort.Sort(sort.Reverse(needKickoutValidators)) 133 134 candidateCount := 0 135 iter := trie.NewIterator(ec.DposContext.CandidateTrie().NodeIterator(nil)) 136 for iter.Next() { 137 candidateCount++ 138 if candidateCount >= needKickoutValidatorCnt+int(safeSize) { 139 break 140 } 141 } 142 143 for i, validator := range needKickoutValidators { 144 //确保候选计数大于或等于safesize 145 if candidateCount <= int(safeSize) { 146 log.Info("No more candidate can be kickout", "prevEpochID", epoch, "candidateCount", candidateCount, "needKickoutCount", len(needKickoutValidators)-i) 147 return nil 148 } 149 150 if err := ec.DposContext.KickoutCandidate(validator.address); err != nil { 151 return err 152 } 153 // 154 candidateCount-- 155 log.Info("Kickout candidate", "prevEpochID", epoch, "candidate", validator.address.String(), "mintCnt", validator.weight.String()) 156 } 157 return nil 158 } 159 160 //实时检查出块者是否是本节点 161 func (ec *EpochContext) lookupValidator(now int64, blockInterval uint64) (validator common.Address, err error) { 162 validator = common.Address{} 163 offset := now % epochInterval 164 if offset%int64(blockInterval) != 0 { //判断当前时间是否在出块周期内 165 return common.Address{}, ErrInvalidMintBlockTime 166 } 167 offset /= int64(blockInterval) 168 169 validators, err := ec.DposContext.GetValidators() 170 if err != nil { 171 return common.Address{}, err 172 } 173 validatorSize := len(validators) 174 if validatorSize == 0 { 175 return common.Address{}, errors.New("failed to lookup validator") 176 } 177 offset %= int64(validatorSize) 178 return validators[offset], nil 179 } 180 181 type sortableAddress struct { 182 address common.Address 183 weight *big.Int 184 } 185 type sortableAddresses []*sortableAddress 186 187 func (p sortableAddresses) Swap(i, j int) { p[i], p[j] = p[j], p[i] } 188 func (p sortableAddresses) Len() int { return len(p) } 189 func (p sortableAddresses) Less(i, j int) bool { 190 if p[i].weight.Cmp(p[j].weight) < 0 { 191 return false 192 } else if p[i].weight.Cmp(p[j].weight) > 0 { 193 return true 194 } else { 195 return p[i].address.String() < p[j].address.String() 196 } 197 } 198