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  }