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