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  }