Skip to content

Commit

Permalink
add qualified interface and fix some bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
yoomee1313 committed Dec 19, 2024
1 parent 4bdf8f9 commit e304532
Show file tree
Hide file tree
Showing 10 changed files with 108 additions and 224 deletions.
32 changes: 31 additions & 1 deletion kaiax/valset/addressList.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,24 @@ func (sc *AddressList) Pop(idx int) {
*sc = append((*sc)[:idx], (*sc)[idx+1:]...)
}

func (sc *AddressList) Remove(addr common.Address) bool {
for idx, val := range *sc {
if val == addr {
sc.Pop(idx)
return true
}
}
return false
}

func (sc AddressList) Copy() AddressList {
var copied AddressList
for _, val := range sc {
copied = append(copied, val)
}
return copied
}

func (sc AddressList) AddressStringList() []string {
stringAddrs := make([]string, len(sc))
for _, val := range sc {
Expand Down Expand Up @@ -61,14 +79,26 @@ func (sc AddressList) GetIdxByAddress(addr common.Address) int {
return -1
}

func (sc AddressList) Subtract(addrs AddressList) AddressList {
res := make(AddressList, 0)
for _, v := range sc {
if addrs.GetIdxByAddress(v) == -1 { // if cannot find in addrs,
res = append(res, v) // add it to res
}
}
return res
}

// BytesCmpSortedList retrieves the sorted address list of ValidatorSet in "ascending order" unlike the sort.Sort() is "descending order".
// sort.Sort(AddressList): descending order - strings.Compare(ValidatorSet[i].String(), ValidatorSet[j].String()) < 0)
// - sort it using strings.Compare. It's used for internal consensus purpose, especially for the source of committee.
// - e.g. snap read/store/apply except defaultSet snap store, vrank log
// AddressList.BytesCmpSortedList(): ascending order - bytes.Compare(ValidatorSet[i][:], ValidatorSet[j][:]) > 0
// - sort it using bytes.Compare. It's for public purpose.
// - e.g. getValidators/getDemotedValidators, defaultSet snap store, prepareExtra.validators
// TODO-kaia: unify sorting. do this task with istanbul.Validator rpc refactoring
// TODO-kaia: bytes.Compare is only used when calling Get(Demoted)Validators api or PrepareExtra.
//
// Deprecate it since it is already sorted by strings.Compare.
func (sc AddressList) BytesCmpSortedList() []common.Address {
copiedSlice := make(AddressList, len(sc))
copy(copiedSlice, sc)
Expand Down
140 changes: 0 additions & 140 deletions kaiax/valset/impl/api.go

This file was deleted.

29 changes: 19 additions & 10 deletions kaiax/valset/impl/committee.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,17 @@ func newCommitteeContext(v *ValsetModule, num uint64) (*committeeContext, error)
return nil, errNilHeader
}

qualified, err := v.getQualifiedValidators(num)
qualified, err := v.GetQualifiedValidators(num)
if err != nil {
return nil, err
}

prevAuthor, err := v.chain.Engine().Author(prevHeader)
if err != nil {
return nil, err
prevAuthor := qualified[0]
if num-1 > 0 {
prevAuthor, err = v.chain.Engine().Author(prevHeader)
if err != nil {
return nil, err
}
}

var (
Expand All @@ -65,9 +68,14 @@ func newCommitteeContext(v *ValsetModule, num uint64) (*committeeContext, error)

if proposerPolicy.IsWeightedRandom() && !rules.IsRandao {
pUpdateBlock = calcProposerBlockNumber(num, pSet.ProposerUpdateInterval)
proposers, err = v.getLegacyProposersList(pUpdateBlock)
if err != nil {
return nil, err
if pUpdateBlock == 0 {
proposers = make([]common.Address, len(qualified))
copy(proposers, qualified)
} else {
proposers, err = v.getLegacyProposersList(pUpdateBlock)
if err != nil {
return nil, err
}
}
}

Expand Down Expand Up @@ -184,14 +192,15 @@ func (c *committeeContext) selectRandomCommittee(round uint64, proposer, nextDis
// shuffled = shuffle_validators_KIP146(validators, seed)
// return shuffled[:min(committee_size, len(validators))]
func (c *committeeContext) selectRandaoCommittee() ([]common.Address, error) {
if c.prevHeader.MixHash == nil {
return nil, errNilMixHash
prevMixHash := c.prevHeader.MixHash
if prevMixHash == nil {
prevMixHash = params.ZeroMixHash
}

copied := make(valset.AddressList, len(c.qualified))
copy(copied, c.qualified)

seed := int64(binary.BigEndian.Uint64(c.prevHeader.MixHash[:8]))
seed := int64(binary.BigEndian.Uint64(prevMixHash[:8]))
rand.New(rand.NewSource(seed)).Shuffle(len(copied), copied.Swap)
return copied[:c.committeeSize], nil
}
Expand Down
6 changes: 0 additions & 6 deletions kaiax/valset/impl/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,8 @@ var (
errInitUnexpectedNil = errors.New("unexpected nil during module init")
errExtractIstanbulExtra = errors.New("extract Istanbul Extra from block header of the given block number")
errNilHeader = errors.New("nil block header")
errNilBlock = errors.New("nil block")
errNilMixHash = errors.New("nil mixHash on block header")
errInvalidCommitteeSize = errors.New("invalid committee size")
errInvalidProposersType = errors.New("invalid proposers type")
errEmptyVoteBlock = errors.New("failed to read vote blocks from db")

// rpc related errors
errPendingNotAllowed = errors.New("pending is not allowed")
errUnknownBlock = errors.New("unknown block")
errUnknownProposer = errors.New("unknown proposer")
)
58 changes: 18 additions & 40 deletions kaiax/valset/impl/getter.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,6 @@ func (v *ValsetModule) GetCommittee(num uint64, round uint64) (valset.AddressLis
// - if the policy is weightedrandom and before Randao hf, the proposer is picked from the proposers
// - if the pilicy is weightedrandom and after Randao hf, the proposer is picked from the committee
func (v *ValsetModule) GetProposer(num uint64, round uint64) (common.Address, error) {
// if the block exists, derive the author from header
header := v.chain.GetHeaderByNumber(num)
if header != nil && header.Number.Uint64() == num && uint64(header.Round()) == round {
return v.chain.Engine().Author(header)
}

// if the block number is genesis, directly return proposer as the first element of genesisCouncil.
if num == 0 {
genesisCouncil, err := v.GetCouncil(0)
Expand All @@ -94,6 +88,12 @@ func (v *ValsetModule) GetProposer(num uint64, round uint64) (common.Address, er
return genesisCouncil[0], nil
}

// if the block exists, derive the author from header
header := v.chain.GetHeaderByNumber(num)
if header != nil && header.Number.Uint64() == num && uint64(header.Round()) == round {
return v.chain.Engine().Author(header)
}

committeeCtx, err := newCommitteeContext(v, num)
if err != nil {
return common.Address{}, err
Expand All @@ -102,33 +102,15 @@ func (v *ValsetModule) GetProposer(num uint64, round uint64) (common.Address, er
return committeeCtx.getProposer(round)
}

// getQualifiedValidators returns a list of validators who are qualified to be a member of the committee or proposer
func (v *ValsetModule) getQualifiedValidators(num uint64) (valset.AddressList, error) {
// GetQualifiedValidators returns a list of validators who are qualified to be a member of the committee or proposer
func (v *ValsetModule) GetQualifiedValidators(num uint64) (valset.AddressList, error) {
council, err := v.GetCouncil(num)
if err != nil {
return nil, err
}

demoted, err := v.getDemotedValidators(num)
if err != nil {
return nil, err
}

qualified := make(valset.AddressList, 0)
for _, v := range council {
if demoted.GetIdxByAddress(v) == -1 { // if cannot find in demoted,
qualified = append(qualified, v) // add it to qualified
}
}

sort.Sort(qualified)
return qualified, nil
}

// getDemotedValidators are subtract of qualified from council(N)
func (v *ValsetModule) getDemotedValidators(num uint64) (valset.AddressList, error) {
if num == 0 {
return valset.AddressList{}, nil
return council, nil
}

pSet, proposerPolicy, err := v.getPSetWithProposerPolicy(num)
Expand All @@ -146,12 +128,7 @@ func (v *ValsetModule) getDemotedValidators(num uint64) (valset.AddressList, err
// either proposer-policy is not weighted random or before istanbul HF,
// do not filter out the demoted validators
if !proposerPolicy.IsWeightedRandom() || !rules.IsIstanbul {
return valset.AddressList{}, nil
}

council, err := v.GetCouncil(num)
if err != nil {
return nil, err
return council, nil
}

// Split the council(N) into qualified and demoted.
Expand All @@ -163,26 +140,27 @@ func (v *ValsetModule) getDemotedValidators(num uint64) (valset.AddressList, err
return nil, err
}

demoted := make(valset.AddressList, 0)
qualified := make(valset.AddressList, 0)
for _, addr := range council {
staking, ok := stakingAmounts[addr]
if !ok {
return nil, fmt.Errorf("cannot find staking amount for %s", addr)
}
if staking < minStaking && !(isSingleMode && addr == govNode) {
demoted = append(demoted, addr)
if staking >= minStaking || (isSingleMode && addr == govNode) {
qualified = append(qualified, addr)
}
}

// include all council members if case1 or case2
// case1. not a single mode && no qualified
// case2. single mode && len(qualified) is 1 && govNode is not qualified
if len(demoted) == len(council) || (isSingleMode && len(demoted) == len(council)-1 && stakingAmounts[govNode] < minStaking) {
return valset.AddressList{}, nil
if len(qualified) == 0 || (isSingleMode && len(qualified) == 1 && stakingAmounts[govNode] < minStaking) {
qualified = make(valset.AddressList, len(council))
copy(qualified, council)
}

sort.Sort(demoted)
return demoted, nil
sort.Sort(qualified)
return qualified, nil
}

// getPSetWithProposerPolicy returns the govParam & proposer policy after processing block num - 1
Expand Down
Loading

0 comments on commit e304532

Please sign in to comment.