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  }