/
handler_candidate_selfstake.go
95 lines (83 loc) · 3 KB
/
handler_candidate_selfstake.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
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
)
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)
bucket, rErr := p.fetchBucket(csm, act.BucketID())
if rErr != nil {
return log, nil, rErr
}
// caller must be the owner of a candidate
cand := csm.GetByOwner(actCtx.Caller)
if cand == nil {
return log, nil, errCandNotExist
}
if err := p.validateBucketSelfStake(ctx, csm, NewEndorsementStateManager(csm.SM()), bucket, cand); err != nil {
return log, nil, err
}
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)
if err != nil {
return log, nil, err
}
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)
featureCtx := protocol.MustGetFeatureCtx(ctx)
if err := validateBucketMinAmount(bucket, p.config.RegistrationConsts.MinSelfStake); err != nil {
return err
}
if err := validateBucketStake(bucket, true); err != nil {
return err
}
if err := validateBucketSelfStake(featureCtx, csm, bucket, false); err != nil {
return err
}
if err := validateBucketCandidate(bucket, cand.Owner); err != nil {
return err
}
if validateBucketOwner(bucket, cand.Owner) != nil &&
validateBucketWithEndorsement(esm, bucket, blkCtx.BlockHeight) != nil {
return &handleError{
err: errors.New("bucket is not a self-owned or endorsed bucket"),
failureStatus: iotextypes.ReceiptStatus_ErrUnauthorizedOperator,
}
}
return nil
}