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