github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/consensus/dpos/api.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:32</date>
    10  //</624342611083137024>
    11  
    12  
    13  package dpos
    14  
    15  import (
    16  	"encoding/binary"
    17  	"errors"
    18  	"github.com/ethereum/go-ethereum/common"
    19  	"github.com/ethereum/go-ethereum/consensus"
    20  	"github.com/ethereum/go-ethereum/core/types"
    21  	"github.com/ethereum/go-ethereum/crypto"
    22  	"github.com/ethereum/go-ethereum/log"
    23  	"github.com/ethereum/go-ethereum/rpc"
    24  	"github.com/ethereum/go-ethereum/trie"
    25  	"math/rand"
    26  	"sort"
    27  	"fmt"
    28  
    29  	"math/big"
    30  )
    31  
    32  //API是面向用户的RPC API,允许控制委托和投票
    33  //委托股权证明机制
    34  type API struct {
    35  	chain consensus.ChainReader
    36  	dpos  *Dpos
    37  }
    38  
    39  //getvalidators检索指定块上的验证程序列表
    40  func (api *API) GetValidators(number *rpc.BlockNumber) ([]common.Address, error) {
    41  	var header *types.Header
    42  	if number == nil || *number == rpc.LatestBlockNumber {
    43  		header = api.chain.CurrentHeader()
    44  	} else {
    45  		header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
    46  	}
    47  	if header == nil {
    48  		return nil, errUnknownBlock
    49  	}
    50  
    51  	trieDB := trie.NewDatabase(api.dpos.db)
    52  	epochTrie, err := types.NewEpochTrie(header.DposContext.EpochHash, trieDB)
    53  
    54  	if err != nil {
    55  		return nil, err
    56  	}
    57  	dposContext := types.DposContext{}
    58  	dposContext.SetEpoch(epochTrie)
    59  	validators, err := dposContext.GetValidators()
    60  	if err != nil {
    61  		return nil, err
    62  	}
    63  	return validators, nil
    64  }
    65  
    66  //getconfirmedBlockNumber检索最新的不可逆块
    67  func (api *API) GetConfirmedBlockNumber() (*big.Int, error) {
    68  	var err error
    69  	header := api.dpos.confirmedBlockHeader
    70  	if header == nil {
    71  		header, err = api.dpos.loadConfirmedBlockHeader(api.chain)
    72  		if err != nil {
    73  			return nil, err
    74  		}
    75  	}
    76  	return header.Number, nil
    77  }
    78  func (ec *EpochContext) tryElect(genesis, parent *types.Header) error {
    79  
    80  genesisEpoch := genesis.Time.Int64() / epochInterval   //GenesEpoch为0
    81  	prevEpoch := parent.Time.Int64() / epochInterval
    82  	currentEpoch := ec.TimeStamp / epochInterval
    83  
    84  prevEpochIsGenesis := prevEpoch == genesisEpoch  		//布尔类型
    85  	if prevEpochIsGenesis && prevEpoch < currentEpoch {
    86  		prevEpoch = currentEpoch - 1
    87  	}
    88  
    89  	prevEpochBytes := make([]byte, 8)
    90  	binary.BigEndian.PutUint64(prevEpochBytes, uint64(prevEpoch))
    91  	iter := trie.NewIterator(ec.DposContext.MintCntTrie().PrefixIterator(prevEpochBytes))
    92  	from_genesis_maxsize :=  genesis.MaxValidatorSize
    93  	fmt.Print("+++++++++++++++++++6666666666666666666++++++++++++++++++++++++++++\n")
    94  	fmt.Print(from_genesis_maxsize)
    95  //根据当前块和上一块的时间计算当前块和上一块是否属于同一个周期,
    96  //如果是同一个周期,意味着当前块不是周期的第一块,不需要联系选举
    97  //如果不是同一个周期,说明当前块是该周期的第一块,则联系投票
    98  	fmt.Print("+++++++++++++++++++8888888++++++++++++++++++++++++++++\n")
    99  	fmt.Print("Genesis init get maxvalidatorsize to kickoutValidator")
   100  	for i := prevEpoch; i < currentEpoch; i++ {
   101  //如果前一个世纪不是创世记,则启动非活动候选
   102  //如果前一个周期不是创世周期,接触发奖金候选人规则
   103  //出局规则主要是看上一周是否存在选人出局块少于规定值(50%),如果存在则出局
   104  		if !prevEpochIsGenesis && iter.Next() {
   105  			if err := ec.kickoutValidator(prevEpoch,genesis); err != nil {
   106  				return err
   107  			}
   108  		}
   109  //对候选人进行计票后按票数由高到低排序,选出前n个
   110  //这里需要注意的是目前对于成为候选人没有门槛限制很容易被恶意攻击
   111  		votes, err := ec.countVotes()
   112  		if err != nil {
   113  			return err
   114  		}
   115  //添加
   116  		maxValidatorSize := int(genesis.MaxValidatorSize)
   117  		safeSize := maxValidatorSize*2/3+1
   118  		candidates := sortableAddresses{}
   119  		for candidate, cnt := range votes {
   120  			candidates = append(candidates, &sortableAddress{candidate, cnt})
   121  		}
   122  		if len(candidates) < safeSize {
   123  //fmt.打印(“whteaaa!!!!!安全保险
   124  			return errors.New("too few candidates")
   125  		}
   126  		sort.Sort(candidates)
   127  		if len(candidates) > maxValidatorSize {
   128  			candidates = candidates[:maxValidatorSize]
   129  		}
   130  
   131  //洗牌候选人
   132  //乱验证人列表,由于使用seed是由父块的hash以及当前周编号组成,
   133  //所以每个节点计算出来的验证人员列表也会一致
   134  		seed := int64(binary.LittleEndian.Uint32(crypto.Keccak512(parent.Hash().Bytes()))) + i
   135  		r := rand.New(rand.NewSource(seed))
   136  		for i := len(candidates) - 1; i > 0; i-- {
   137  			j := int(r.Int31n(int32(i + 1)))
   138  			candidates[i], candidates[j] = candidates[j], candidates[i]
   139  		}
   140  		sortedValidators := make([]common.Address, 0)
   141  		for _, candidate := range candidates {
   142  			sortedValidators = append(sortedValidators, candidate.address)
   143  		}
   144  
   145  		epochTrie, _ := types.NewEpochTrie(common.Hash{}, ec.DposContext.DB())
   146  		ec.DposContext.SetEpoch(epochTrie)
   147  		ec.DposContext.SetValidators(sortedValidators)
   148  		log.Info("Come to new epoch", "prevEpoch", i, "nextEpoch", i+1)
   149  	}
   150  	return nil
   151  }
   152  
   153  
   154  
   155  
   156