Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[staking] Handling CandidateSelfStake Action #4011

Merged
merged 6 commits into from
Jan 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 94 additions & 0 deletions action/protocol/staking/handler_candidate_selfstake.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package staking

import (
"context"
"math"

"github.com/iotexproject/iotex-proto/golang/iotextypes"
"github.com/pkg/errors"

"github.com/iotexproject/iotex-core/action"
"github.com/iotexproject/iotex-core/action/protocol"
"github.com/iotexproject/iotex-core/pkg/util/byteutil"
)

const (
handleCandidateActivate = "candidateActivate"

candidateNoSelfStakeBucketIndex = math.MaxUint64
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove since it's only used in test, and why is it needed in test?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will be used when register candidate without stake

)

func (p *Protocol) handleCandidateActivate(ctx context.Context, act *action.CandidateActivate, csm CandidateStateManager,
) (*receiptLog, []*action.TransactionLog, error) {
actCtx := protocol.MustGetActionCtx(ctx)
featureCtx := protocol.MustGetFeatureCtx(ctx)
log := newReceiptLog(p.addr.String(), handleCandidateActivate, featureCtx.NewStakingReceiptFormat)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add a new line?


bucket, rErr := p.fetchBucket(csm, act.BucketID())
if rErr != nil {
return log, nil, rErr

Check warning on line 29 in action/protocol/staking/handler_candidate_selfstake.go

View check run for this annotation

Codecov / codecov/patch

action/protocol/staking/handler_candidate_selfstake.go#L29

Added line #L29 was not covered by tests
}
// caller must be the owner of a candidate
cand := csm.GetByOwner(actCtx.Caller)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move this to after get and validate bucket, to be consistent with other handlers

if cand == nil {
return log, nil, errCandNotExist

Check warning on line 34 in action/protocol/staking/handler_candidate_selfstake.go

View check run for this annotation

Codecov / codecov/patch

action/protocol/staking/handler_candidate_selfstake.go#L34

Added line #L34 was not covered by tests
}

if err := p.validateBucketSelfStake(ctx, csm, NewEndorsementStateManager(csm.SM()), bucket, cand); err != nil {
return log, nil, err
}
dustinxie marked this conversation as resolved.
Show resolved Hide resolved

log.AddTopics(byteutil.Uint64ToBytesBigEndian(bucket.Index), bucket.Candidate.Bytes())
// convert previous self-stake bucket to vote bucket
if cand.SelfStake.Sign() > 0 {
prevBucket, err := p.fetchBucket(csm, cand.SelfStakeBucketIdx)
dustinxie marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return log, nil, err

Check warning on line 46 in action/protocol/staking/handler_candidate_selfstake.go

View check run for this annotation

Codecov / codecov/patch

action/protocol/staking/handler_candidate_selfstake.go#L46

Added line #L46 was not covered by tests
}
if err := cand.SubVote(p.calculateVoteWeight(prevBucket, true)); err != nil {
return log, nil, err
}
if err := cand.AddVote(p.calculateVoteWeight(prevBucket, false)); err != nil {
return log, nil, err
}
}

// convert vote bucket to self-stake bucket
cand.SelfStakeBucketIdx = bucket.Index
cand.SelfStake.SetBytes(bucket.StakedAmount.Bytes())
if err := cand.SubVote(p.calculateVoteWeight(bucket, false)); err != nil {
return log, nil, err
}
if err := cand.AddVote(p.calculateVoteWeight(bucket, true)); err != nil {
return log, nil, err
}

if err := csm.Upsert(cand); err != nil {
return log, nil, csmErrorToHandleError(cand.Owner.String(), err)
}
return log, nil, nil
}

func (p *Protocol) validateBucketSelfStake(ctx context.Context, csm CandidateStateManager, esm *EndorsementStateManager, bucket *VoteBucket, cand *Candidate) ReceiptError {
blkCtx := protocol.MustGetBlockCtx(ctx)
if err := validateBucketMinAmount(bucket, p.config.RegistrationConsts.MinSelfStake); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe better

validateFn = []func()error
for _,fn := range validateFn {
  if err := fn(); err != nil {
    return err
}
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Their parameters are different, i think no need to enforce using same interface.

return err
}
if err := validateBucketStake(bucket, true); err != nil {
return err
}
if err := validateBucketSelfStake(csm, bucket, false); err != nil {
return err
}
if err := validateBucketCandidate(bucket, cand.Owner); err != nil {
return err
}
if validateBucketOwner(bucket, cand.Owner) != nil &&
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

&& or ||?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be &&, it means only owned or endorsed bucket can be used to activate candidate self

validateBucketEndorsement(esm, bucket, true, blkCtx.BlockHeight) != nil {
return &handleError{
err: errors.New("bucket is not a self-owned or endorsed bucket"),
failureStatus: iotextypes.ReceiptStatus_ErrUnauthorizedOperator,
}
}
return nil
}
Loading
Loading