diff --git a/action/protocol/context.go b/action/protocol/context.go index af82d81bdb..804f730eeb 100644 --- a/action/protocol/context.go +++ b/action/protocol/context.go @@ -149,6 +149,7 @@ type ( EnableNewTxTypes bool VerifyNotContainerBeforeRun bool ValidateActionWithState bool + CheckStakingDurationUpperLimit bool } // FeatureWithHeightCtx provides feature check functions. @@ -311,6 +312,7 @@ func WithFeatureCtx(ctx context.Context) context.Context { EnableNewTxTypes: g.IsVanuatu(height), VerifyNotContainerBeforeRun: g.IsVanuatu(height), ValidateActionWithState: g.IsVanuatu(height), + CheckStakingDurationUpperLimit: g.IsVanuatu(height), }, ) } diff --git a/action/protocol/staking/handlers_test.go b/action/protocol/staking/handlers_test.go index 54c0217ab9..4548f2d431 100644 --- a/action/protocol/staking/handlers_test.go +++ b/action/protocol/staking/handlers_test.go @@ -106,7 +106,9 @@ func TestProtocol_HandleCreateStake(t *testing.T) { require.NoError(csm.putCandidate(candidate)) candidateName := candidate.Name candidateAddr := candidate.Owner - ctx := genesis.WithGenesisContext(context.Background(), genesis.Default) + g := genesis.Default + g.VanuatuBlockHeight = 1 + ctx := genesis.WithGenesisContext(context.Background(), g) ctx = protocol.WithFeatureWithHeightCtx(ctx) v, err := p.Start(ctx, sm) require.NoError(err) @@ -174,6 +176,20 @@ func TestProtocol_HandleCreateStake(t *testing.T) { action.ErrInvalidAmount, iotextypes.ReceiptStatus_Failure, }, + { + 101, + candidateName, + "100000000000000000000", + 1051, + false, + 10000, + 2, + 1, + time.Now(), + 10000, + ErrDurationTooHigh, + iotextypes.ReceiptStatus_Failure, + }, { 101, candidateName, @@ -203,9 +219,9 @@ func TestProtocol_HandleCreateStake(t *testing.T) { BlockTimeStamp: test.blkTimestamp, GasLimit: test.blkGasLimit, }) - ctx = protocol.WithBlockchainCtx(ctx, protocol.BlockchainCtx{Tip: protocol.TipInfo{ + ctx = protocol.WithFeatureCtx(protocol.WithBlockchainCtx(ctx, protocol.BlockchainCtx{Tip: protocol.TipInfo{ Height: test.blkHeight - 1, - }}) + }})) act, err := action.NewCreateStake(test.candName, test.amount, test.duration, test.autoStake, nil) require.NoError(err) elp := builder.SetNonce(test.nonce).SetGasLimit(test.gasLimit). @@ -215,7 +231,6 @@ func TestProtocol_HandleCreateStake(t *testing.T) { require.EqualError(test.err, errors.Cause(err).Error()) continue } - ctx = protocol.WithFeatureCtx(ctx) r, err := p.Handle(ctx, elp, sm) require.NoError(err) require.Equal(uint64(test.status), r.Status) diff --git a/action/protocol/staking/validations.go b/action/protocol/staking/validations.go index ef3eb4c8ef..7d5a5475b5 100644 --- a/action/protocol/staking/validations.go +++ b/action/protocol/staking/validations.go @@ -14,6 +14,10 @@ import ( "github.com/iotexproject/iotex-core/v2/action/protocol" ) +const ( + _stakeDurationLimit = 1050 +) + // Errors var ( ErrInvalidOwner = errors.New("invalid owner address") @@ -22,6 +26,7 @@ var ( ErrInvalidSelfStkIndex = errors.New("invalid self-staking bucket index") ErrMissingField = errors.New("missing data field") ErrTypeAssertion = errors.New("failed type assertion") + ErrDurationTooHigh = errors.New("stake duration cannot exceed 1050 days") ) func (p *Protocol) validateCreateStake(ctx context.Context, act *action.CreateStake) error { @@ -31,6 +36,9 @@ func (p *Protocol) validateCreateStake(ctx context.Context, act *action.CreateSt if act.Amount().Cmp(p.config.MinStakeAmount) == -1 { return errors.Wrap(action.ErrInvalidAmount, "stake amount is less than the minimum requirement") } + if protocol.MustGetFeatureCtx(ctx).CheckStakingDurationUpperLimit && act.Duration() > _stakeDurationLimit { + return ErrDurationTooHigh + } return nil } @@ -58,6 +66,9 @@ func (p *Protocol) validateDepositToStake(ctx context.Context, act *action.Depos } func (p *Protocol) validateRestake(ctx context.Context, act *action.Restake) error { + if protocol.MustGetFeatureCtx(ctx).CheckStakingDurationUpperLimit && act.Duration() > _stakeDurationLimit { + return ErrDurationTooHigh + } return nil } @@ -73,6 +84,9 @@ func (p *Protocol) validateCandidateRegister(ctx context.Context, act *action.Ca } return errors.Wrap(action.ErrInvalidAmount, "self staking amount is not valid") } + if protocol.MustGetFeatureCtx(ctx).CheckStakingDurationUpperLimit && act.Duration() > _stakeDurationLimit { + return ErrDurationTooHigh + } return nil }