github.com/iotexproject/iotex-core@v1.14.1-rc1/action/protocol/staking/handler_candidate_endorsement.go (about) 1 package staking 2 3 import ( 4 "context" 5 6 "github.com/iotexproject/iotex-address/address" 7 "github.com/pkg/errors" 8 9 "github.com/iotexproject/iotex-core/action" 10 "github.com/iotexproject/iotex-core/action/protocol" 11 "github.com/iotexproject/iotex-core/pkg/util/byteutil" 12 ) 13 14 const ( 15 handleCandidateEndorsement = "candidateEndorsement" 16 ) 17 18 func (p *Protocol) handleCandidateEndorsement(ctx context.Context, act *action.CandidateEndorsement, csm CandidateStateManager) (*receiptLog, []*action.TransactionLog, error) { 19 actCtx := protocol.MustGetActionCtx(ctx) 20 featureCtx := protocol.MustGetFeatureCtx(ctx) 21 log := newReceiptLog(p.addr.String(), handleCandidateEndorsement, featureCtx.NewStakingReceiptFormat) 22 23 bucket, rErr := p.fetchBucket(csm, act.BucketIndex()) 24 if rErr != nil { 25 return log, nil, rErr 26 } 27 cand := csm.GetByOwner(bucket.Candidate) 28 if cand == nil { 29 return log, nil, errCandNotExist 30 } 31 log.AddTopics(byteutil.Uint64ToBytesBigEndian(bucket.Index), bucket.Candidate.Bytes(), []byte{byteutil.BoolToByte(act.IsEndorse())}) 32 33 esm := NewEndorsementStateManager(csm.SM()) 34 expireHeight := uint64(0) 35 if act.IsEndorse() { 36 // handle endorsement 37 if err := p.validateEndorsement(ctx, csm, esm, actCtx.Caller, bucket, cand); err != nil { 38 return log, nil, err 39 } 40 expireHeight = uint64(endorsementNotExpireHeight) 41 } else { 42 // handle withdrawal 43 if err := p.validateEndorsementWithdrawal(ctx, esm, actCtx.Caller, bucket); err != nil { 44 return log, nil, err 45 } 46 // expire immediately if the bucket is not self-staked 47 // otherwise, expire after withdraw waiting period 48 selfStake, err := isSelfStakeBucket(featureCtx, csm, bucket) 49 if err != nil { 50 return log, nil, err 51 } 52 expireHeight = protocol.MustGetBlockCtx(ctx).BlockHeight 53 if selfStake { 54 expireHeight += p.config.EndorsementWithdrawWaitingBlocks 55 } 56 } 57 // update endorsement state 58 if err := esm.Put(bucket.Index, &Endorsement{ 59 ExpireHeight: expireHeight, 60 }); err != nil { 61 return log, nil, errors.Wrapf(err, "failed to put endorsement with bucket index %d", bucket.Index) 62 } 63 return log, nil, nil 64 } 65 66 func (p *Protocol) validateEndorsement(ctx context.Context, csm CandidateStateManager, esm *EndorsementStateManager, caller address.Address, bucket *VoteBucket, cand *Candidate) ReceiptError { 67 featureCtx := protocol.MustGetFeatureCtx(ctx) 68 if err := validateBucketOwner(bucket, caller); err != nil { 69 return err 70 } 71 if err := validateBucketMinAmount(bucket, p.config.RegistrationConsts.MinSelfStake); err != nil { 72 return err 73 } 74 if err := validateBucketStake(bucket, true); err != nil { 75 return err 76 } 77 if err := validateBucketCandidate(bucket, cand.Owner); err != nil { 78 return err 79 } 80 if err := validateBucketSelfStake(featureCtx, csm, bucket, false); err != nil { 81 return err 82 } 83 return validateBucketWithoutEndorsement(esm, bucket, protocol.MustGetBlockCtx(ctx).BlockHeight) 84 } 85 86 func (p *Protocol) validateEndorsementWithdrawal(ctx context.Context, esm *EndorsementStateManager, caller address.Address, bucket *VoteBucket) ReceiptError { 87 if err := validateBucketOwner(bucket, caller); err != nil { 88 return err 89 } 90 return validateBucketEndorsementWithdrawal(esm, bucket, protocol.MustGetBlockCtx(ctx).BlockHeight) 91 }