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