Skip to content

Commit

Permalink
[staking] ActiveCandidate Exclude Candidate with Expired Endorsement (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
envestcc committed Mar 11, 2024
1 parent 8f5e47f commit ef4ae12
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 9 deletions.
4 changes: 3 additions & 1 deletion action/protocol/poll/nativestakingV2.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ import (

"github.com/iotexproject/go-pkgs/hash"
"github.com/iotexproject/iotex-address/address"
"github.com/iotexproject/iotex-election/util"

"github.com/iotexproject/iotex-core/action"
"github.com/iotexproject/iotex-core/action/protocol"
"github.com/iotexproject/iotex-core/action/protocol/staking"
"github.com/iotexproject/iotex-core/state"
"github.com/iotexproject/iotex-election/util"
)

type nativeStakingV2 struct {
Expand Down Expand Up @@ -83,6 +84,7 @@ func (ns *nativeStakingV2) CalculateCandidatesByHeight(ctx context.Context, sr p
return cands, err
}
bcCtx := protocol.MustGetBlockchainCtx(ctx)
// TODO: put candidates which will expired during current or next epoch behind the active candidates
return ns.filterAndSortCandidatesByVoteScore(cands, bcCtx.Tip.Timestamp), nil
}

Expand Down
11 changes: 11 additions & 0 deletions action/protocol/staking/candidate_statemanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,13 @@ type (
DebitBucketPool(*big.Int, bool) error
Commit(context.Context) error
SM() protocol.StateManager
SR() protocol.StateReader
}

// CandidiateStateCommon is the common interface for candidate state manager and reader
CandidiateStateCommon interface {
ContainsSelfStakingBucket(uint64) bool
SR() protocol.StateReader
}

candSM struct {
Expand Down Expand Up @@ -106,6 +113,10 @@ func (csm *candSM) SM() protocol.StateManager {
return csm.StateManager
}

func (csm *candSM) SR() protocol.StateReader {
return csm.StateManager
}

// DirtyView is csm's current state, which reflects base view + applying delta saved in csm's dock
func (csm *candSM) DirtyView() *ViewData {
return &ViewData{
Expand Down
5 changes: 5 additions & 0 deletions action/protocol/staking/candidate_statereader.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ type (
AllCandidates() CandidateList
TotalStakedAmount() *big.Int
ActiveBucketsCount() uint64
ContainsSelfStakingBucket(index uint64) bool
}

candSR struct {
Expand Down Expand Up @@ -110,6 +111,10 @@ func (c *candSR) AllCandidates() CandidateList {
return c.view.candCenter.All()
}

func (c *candSR) ContainsSelfStakingBucket(index uint64) bool {
return c.view.candCenter.ContainsSelfStakingBucket(index)
}

func (c *candSR) TotalStakedAmount() *big.Int {
return c.view.bucketPool.Total()
}
Expand Down
4 changes: 2 additions & 2 deletions action/protocol/staking/handlers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2810,7 +2810,7 @@ func TestProtocol_FetchBucketAndValidate(t *testing.T) {
})
isSelfStake := true
isSelfStakeErr := error(nil)
patches.ApplyFunc(isSelfStakeBucket, func(featureCtx protocol.FeatureCtx, csm CandidateStateManager, bucket *VoteBucket) (bool, error) {
patches.ApplyFunc(isSelfStakeBucket, func(featureCtx protocol.FeatureCtx, csm CandidiateStateCommon, bucket *VoteBucket) (bool, error) {
return isSelfStake, isSelfStakeErr
})
_, err = p.fetchBucketAndValidate(protocol.FeatureCtx{}, csm, identityset.Address(1), 1, false, false)
Expand All @@ -2831,7 +2831,7 @@ func TestProtocol_FetchBucketAndValidate(t *testing.T) {
Owner: identityset.Address(1),
}, nil
})
patches.ApplyFunc(isSelfStakeBucket, func(featureCtx protocol.FeatureCtx, csm CandidateStateManager, bucket *VoteBucket) (bool, error) {
patches.ApplyFunc(isSelfStakeBucket, func(featureCtx protocol.FeatureCtx, csm CandidiateStateCommon, bucket *VoteBucket) (bool, error) {
return false, nil
})
defer patches.Reset()
Expand Down
42 changes: 36 additions & 6 deletions action/protocol/staking/protocol.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,9 @@ const (

// Errors
var (
ErrWithdrawnBucket = errors.New("the bucket is already withdrawn")
TotalBucketKey = append([]byte{_const}, []byte("totalBucket")...)
ErrWithdrawnBucket = errors.New("the bucket is already withdrawn")
ErrEndorsementNotExist = errors.New("the endorsement does not exist")
TotalBucketKey = append([]byte{_const}, []byte("totalBucket")...)
)

var (
Expand Down Expand Up @@ -472,6 +473,31 @@ func (p *Protocol) Validate(ctx context.Context, act action.Action, sr protocol.
return nil
}

func (p *Protocol) isActiveCandidate(ctx context.Context, csr CandidateStateReader, cand *Candidate) (bool, error) {
if cand.SelfStake.Cmp(p.config.RegistrationConsts.MinSelfStake) < 0 {
return false, nil
}
featureCtx := protocol.MustGetFeatureCtx(ctx)
if featureCtx.DisableDelegateEndorsement {
// before endorsement feature, candidates with enough amount must be active
return true, nil
}
bucket, err := csr.getBucket(cand.SelfStakeBucketIdx)
switch {
case errors.Cause(err) == state.ErrStateNotExist:
// endorse bucket has been withdrawn
return false, nil
case err != nil:
return false, errors.Wrapf(err, "failed to get bucket %d", cand.SelfStakeBucketIdx)
default:
}
selfStake, err := isSelfStakeBucket(featureCtx, csr, bucket)
if err != nil {
return false, errors.Wrapf(err, "failed to check self-stake bucket %d", cand.SelfStakeBucketIdx)
}
return selfStake, nil
}

// ActiveCandidates returns all active candidates in candidate center
func (p *Protocol) ActiveCandidates(ctx context.Context, sr protocol.StateReader, height uint64) (state.CandidateList, error) {
srHeight, err := sr.Height()
Expand All @@ -496,7 +522,11 @@ func (p *Protocol) ActiveCandidates(ctx context.Context, sr protocol.StateReader
}
list[i].Votes.Add(list[i].Votes, contractVotes)
}
if list[i].SelfStake.Cmp(p.config.RegistrationConsts.MinSelfStake) >= 0 {
active, err := p.isActiveCandidate(ctx, c, list[i])
if err != nil {
return nil, err
}
if active {
cand = append(cand, list[i])
}
}
Expand Down Expand Up @@ -686,9 +716,9 @@ func writeCandCenterStateToStateDB(sm protocol.StateManager, name, op, owners Ca
}

// isSelfStakeBucket returns true if the bucket is self-stake bucket and not expired
func isSelfStakeBucket(featureCtx protocol.FeatureCtx, csm CandidateStateManager, bucket *VoteBucket) (bool, error) {
func isSelfStakeBucket(featureCtx protocol.FeatureCtx, csc CandidiateStateCommon, bucket *VoteBucket) (bool, error) {
// bucket index should be settled in one of candidates
selfStake := csm.ContainsSelfStakingBucket(bucket.Index)
selfStake := csc.ContainsSelfStakingBucket(bucket.Index)
if featureCtx.DisableDelegateEndorsement || !selfStake {
return selfStake, nil
}
Expand All @@ -698,7 +728,7 @@ func isSelfStakeBucket(featureCtx protocol.FeatureCtx, csm CandidateStateManager
return !bucket.isUnstaked(), nil
}
// otherwise bucket should be an endorse bucket which is not expired
esm := NewEndorsementStateManager(csm.SM())
esm := NewEndorsementStateReader(csc.SR())
height, err := esm.Height()
if err != nil {
return false, err
Expand Down

0 comments on commit ef4ae12

Please sign in to comment.