Skip to content

Commit 605a78b

Browse files
committed
feat: limit the number of allocations for a subscription
1 parent 4b901a1 commit 605a78b

File tree

7 files changed

+123
-35
lines changed

7 files changed

+123
-35
lines changed

proto/sentinel/subscription/v3/params.proto

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,12 @@ option (gogoproto.equal_all) = false;
99
option (gogoproto.goproto_getters_all) = false;
1010

1111
message Params {
12-
string staking_share = 1 [
12+
int64 max_allocations = 1;
13+
string staking_share = 2 [
1314
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",
1415
(gogoproto.nullable) = false
1516
];
16-
google.protobuf.Duration status_timeout = 2 [
17+
google.protobuf.Duration status_timeout = 3 [
1718
(gogoproto.nullable) = false,
1819
(gogoproto.stdduration) = true
1920
];

x/subscription/keeper/msg_handler.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,11 @@ func (k *Keeper) HandleMsgShareSubscription(ctx sdk.Context, msg *v3.MsgShareSub
209209
return nil, types.NewErrorUnauthorized(msg.From)
210210
}
211211

212+
// Check if the subscription has reached maximum allocations
213+
if k.IsMaxAllocationsReached(ctx, subscription.ID) {
214+
return nil, types.NewErrorMaxAllocationsReached(subscription.ID)
215+
}
216+
212217
// Load allocation from sender and parse both account addresses
213218
fromAddr, err := sdk.AccAddressFromBech32(msg.From)
214219
if err != nil {

x/subscription/keeper/params.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
sdk "github.com/cosmos/cosmos-sdk/types"
88

99
"github.com/sentinel-official/sentinelhub/v12/x/subscription/types"
10+
"github.com/sentinel-official/sentinelhub/v12/x/subscription/types/v2"
1011
"github.com/sentinel-official/sentinelhub/v12/x/subscription/types/v3"
1112
)
1213

@@ -30,6 +31,11 @@ func (k *Keeper) GetParams(ctx sdk.Context) (v v3.Params) {
3031
return v
3132
}
3233

34+
// MaxAllocations retrieves the max allocations parameter from the module's parameters.
35+
func (k *Keeper) MaxAllocations(ctx sdk.Context) int64 {
36+
return k.GetParams(ctx).MaxAllocations
37+
}
38+
3339
// StakingShare retrieves the staking share parameter from the module's parameters.
3440
func (k *Keeper) StakingShare(ctx sdk.Context) sdkmath.LegacyDec {
3541
return k.GetParams(ctx).StakingShare
@@ -46,3 +52,21 @@ func (k *Keeper) GetInactiveAt(ctx sdk.Context) time.Time {
4652

4753
return ctx.BlockTime().Add(d)
4854
}
55+
56+
// IsMaxAllocationsReached checks if the maximum number of allocations for a given subscription has been reached.
57+
func (k *Keeper) IsMaxAllocationsReached(ctx sdk.Context, id uint64) bool {
58+
maxAllocations := k.MaxAllocations(ctx)
59+
60+
var count int64
61+
62+
k.IterateAllocationsForSubscription(ctx, id, func(_ int, _ v2.Allocation) bool {
63+
count++
64+
if count >= maxAllocations {
65+
return true // Stop iterating when maxAllocations is reached
66+
}
67+
68+
return false
69+
})
70+
71+
return count >= maxAllocations
72+
}

x/subscription/migrations/migrator.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,9 @@ func (k *Migrator) deleteKeys(ctx sdk.Context, keyPrefix []byte) (keys [][]byte)
7676

7777
func (k *Migrator) setParams(ctx sdk.Context) {
7878
params := v3.Params{
79-
StakingShare: sdkmath.LegacyMustNewDecFromStr("0.2"),
80-
StatusTimeout: 4 * time.Hour,
79+
MaxAllocations: 8,
80+
StakingShare: sdkmath.LegacyMustNewDecFromStr("0.2"),
81+
StatusTimeout: 4 * time.Hour,
8182
}
8283

8384
k.subscription.SetParams(ctx, params)

x/subscription/types/errors.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const (
2020
ErrCodeInvalidRenewalPolicy
2121
ErrCodeInvalidSessionStatus
2222
ErrCodeInvalidSubscriptionStatus
23+
ErrCodeMaxAllocationsReached
2324
ErrCodeNodeForPlanNotFound
2425
ErrCodeNodeNotFound
2526
ErrCodePlanNotFound
@@ -39,6 +40,7 @@ var (
3940
ErrInvalidRenewalPolicy = sdkerrors.Register(ModuleName, ErrCodeInvalidRenewalPolicy, "invalid renewal policy")
4041
ErrInvalidSessionStatus = sdkerrors.Register(ModuleName, ErrCodeInvalidSessionStatus, "invalid session status")
4142
ErrInvalidSubscriptionStatus = sdkerrors.Register(ModuleName, ErrCodeInvalidSubscriptionStatus, "invalid subscription status")
43+
ErrMaxAllocationsReached = sdkerrors.Register(ModuleName, ErrCodeMaxAllocationsReached, "max allocations reached")
4244
ErrNodeForPlanNotFound = sdkerrors.Register(ModuleName, ErrCodeNodeForPlanNotFound, "node for plan not found")
4345
ErrNodeNotFound = sdkerrors.Register(ModuleName, ErrCodeNodeNotFound, "node not found")
4446
ErrPlanNotFound = sdkerrors.Register(ModuleName, ErrCodePlanNotFound, "plan not found")
@@ -88,6 +90,11 @@ func NewErrorInvalidSubscriptionStatus(id uint64, status v1base.Status) error {
8890
return sdkerrors.Wrapf(ErrInvalidSubscriptionStatus, "invalid status %s for subscription %d", status, id)
8991
}
9092

93+
// NewErrorMaxAllocationsReached returns an error indicating that the specified subscription has reached maximum allocations.
94+
func NewErrorMaxAllocationsReached(id uint64) error {
95+
return sdkerrors.Wrapf(ErrNodeForPlanNotFound, "subscription %d has reached maximum allocations", id)
96+
}
97+
9198
// NewErrorNodeForPlanNotFound returns an error indicating that the specified node does not exist for the plan.
9299
func NewErrorNodeForPlanNotFound(id uint64, addr base.NodeAddress) error {
93100
return sdkerrors.Wrapf(ErrNodeForPlanNotFound, "node %s for plan %d does not exist", addr, id)

x/subscription/types/v3/params.go

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,17 @@ import (
1010

1111
// Default parameter values for the Params struct.
1212
var (
13-
DefaultStakingShare = sdkmath.LegacyMustNewDecFromStr("0.1") // Default staking share: 0.1
14-
DefaultStatusTimeout = 2 * time.Minute // Default timeout for status change
13+
DefaultMaxAllocations int64 = 8 // Default max allocations per subscription
14+
DefaultStakingShare = sdkmath.LegacyMustNewDecFromStr("0.1") // Default staking share: 0.1
15+
DefaultStatusTimeout = 2 * time.Minute // Default timeout for status change
1516
)
1617

1718
// Validate checks whether the Params fields are valid according to defined rules.
1819
func (m *Params) Validate() error {
20+
if err := validateMaxAllocations(m.MaxAllocations); err != nil {
21+
return fmt.Errorf("invalid max_allocations: %w", err)
22+
}
23+
1924
if err := validateStakingShare(m.StakingShare); err != nil {
2025
return fmt.Errorf("invalid staking_share: %w", err)
2126
}
@@ -28,21 +33,36 @@ func (m *Params) Validate() error {
2833
}
2934

3035
// NewParams creates a new Params instance with custom values.
31-
func NewParams(stakingShare sdkmath.LegacyDec, statusTimeout time.Duration) Params {
36+
func NewParams(maxAllocations int64, stakingShare sdkmath.LegacyDec, statusTimeout time.Duration) Params {
3237
return Params{
33-
StakingShare: stakingShare,
34-
StatusTimeout: statusTimeout,
38+
MaxAllocations: maxAllocations,
39+
StakingShare: stakingShare,
40+
StatusTimeout: statusTimeout,
3541
}
3642
}
3743

3844
// DefaultParams returns a Params struct initialized with default values.
3945
func DefaultParams() Params {
4046
return NewParams(
47+
DefaultMaxAllocations,
4148
DefaultStakingShare,
4249
DefaultStatusTimeout,
4350
)
4451
}
4552

53+
// validateMaxAllocations checks that maxAllocations is positive.
54+
func validateMaxAllocations(v int64) error {
55+
if v == 0 {
56+
return errors.New("value cannot be zero")
57+
}
58+
59+
if v < 0 {
60+
return errors.New("value cannot be negative")
61+
}
62+
63+
return nil
64+
}
65+
4666
// validateStakingShare ensures that the staking share is:
4767
// - Not nil
4868
// - Not negative

x/subscription/types/v3/params.pb.go

Lines changed: 56 additions & 26 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)