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