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