From 869a03ea2637f7233399fef7c2d09956d04c36cf Mon Sep 17 00:00:00 2001 From: Marc Puig Date: Fri, 19 Jan 2024 16:25:01 +0100 Subject: [PATCH] fix: Set limit to LSM deposit filtering (#731) * set limit to LSM deposit filtering * changelog --- CHANGELOG.md | 1 + x/liquidstakeibc/keeper/ibc.go | 2 +- x/liquidstakeibc/keeper/lsm_deposit.go | 29 +++++- x/liquidstakeibc/keeper/lsm_deposit_test.go | 100 ++++++++++++++++++-- x/liquidstakeibc/types/keys.go | 2 + 5 files changed, 120 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5c125723..28850a842 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Bug Fixes +- [731](https://github.com/persistenceOne/pstake-native/pull/731) Set limit to LSM deposit filtering. - [730](https://github.com/persistenceOne/pstake-native/pull/730) Fix deposit validate. - [728](https://github.com/persistenceOne/pstake-native/pull/728) Fix prevent users from liquid-staking funds by removing the Deposit entry. diff --git a/x/liquidstakeibc/keeper/ibc.go b/x/liquidstakeibc/keeper/ibc.go index 0db6951c1..0eb13843c 100644 --- a/x/liquidstakeibc/keeper/ibc.go +++ b/x/liquidstakeibc/keeper/ibc.go @@ -385,7 +385,7 @@ func (k *Keeper) handleUnsuccessfulAck( ) } case sdk.MsgTypeURL(&stakingtypes.MsgRedeemTokensForShares{}): - deposits := k.FilterLSMDeposits( + deposits := k.FilterLSMDepositsWithLimit( ctx, func(d types.LSMDeposit) bool { return d.IbcSequenceId == k.GetTransactionSequenceID(channel, sequence) diff --git a/x/liquidstakeibc/keeper/lsm_deposit.go b/x/liquidstakeibc/keeper/lsm_deposit.go index eb2d03a59..26b1cd4aa 100644 --- a/x/liquidstakeibc/keeper/lsm_deposit.go +++ b/x/liquidstakeibc/keeper/lsm_deposit.go @@ -36,7 +36,7 @@ func (k *Keeper) GetLSMDepositsFromIbcDenom(ctx sdk.Context, ibcDenom string) [] } func (k *Keeper) GetLSMDepositsFromIbcSequenceID(ctx sdk.Context, ibcSequenceID string) []*liquidstakeibctypes.LSMDeposit { - return k.FilterLSMDeposits( + return k.FilterLSMDepositsWithLimit( ctx, func(d liquidstakeibctypes.LSMDeposit) bool { return d.IbcSequenceId == ibcSequenceID @@ -45,7 +45,7 @@ func (k *Keeper) GetLSMDepositsFromIbcSequenceID(ctx sdk.Context, ibcSequenceID } func (k *Keeper) GetTransferableLSMDeposits(ctx sdk.Context, chainID string) []*liquidstakeibctypes.LSMDeposit { - return k.FilterLSMDeposits( + return k.FilterLSMDepositsWithLimit( ctx, func(d liquidstakeibctypes.LSMDeposit) bool { return d.ChainId == chainID && d.State == liquidstakeibctypes.LSMDeposit_DEPOSIT_PENDING @@ -54,7 +54,7 @@ func (k *Keeper) GetTransferableLSMDeposits(ctx sdk.Context, chainID string) []* } func (k *Keeper) GetRedeemableLSMDeposits(ctx sdk.Context, chainID string) []*liquidstakeibctypes.LSMDeposit { - return k.FilterLSMDeposits( + return k.FilterLSMDepositsWithLimit( ctx, func(d liquidstakeibctypes.LSMDeposit) bool { return d.ChainId == chainID && d.State == liquidstakeibctypes.LSMDeposit_DEPOSIT_RECEIVED @@ -112,6 +112,29 @@ func (k *Keeper) FilterLSMDeposits( return deposits } +func (k *Keeper) FilterLSMDepositsWithLimit( + ctx sdk.Context, + filter func(d liquidstakeibctypes.LSMDeposit) bool, +) []*liquidstakeibctypes.LSMDeposit { + store := prefix.NewStore(ctx.KVStore(k.storeKey), liquidstakeibctypes.LSMDepositKey) + iterator := sdk.KVStorePrefixIterator(store, nil) + defer iterator.Close() + + deposits := make([]*liquidstakeibctypes.LSMDeposit, 0) + for ; iterator.Valid(); iterator.Next() { + deposit := liquidstakeibctypes.LSMDeposit{} + k.cdc.MustUnmarshal(iterator.Value(), &deposit) + if filter(deposit) { + deposits = append(deposits, &deposit) + } + if len(deposits) == liquidstakeibctypes.LSMDepositFilterLimit { + return deposits + } + } + + return deposits +} + func (k *Keeper) GetLSMDepositAmountUntokenized(ctx sdk.Context, chainID string) math.Int { amount := sdk.ZeroInt() diff --git a/x/liquidstakeibc/keeper/lsm_deposit_test.go b/x/liquidstakeibc/keeper/lsm_deposit_test.go index 483f6660e..98ebf1a36 100644 --- a/x/liquidstakeibc/keeper/lsm_deposit_test.go +++ b/x/liquidstakeibc/keeper/lsm_deposit_test.go @@ -1,14 +1,18 @@ package keeper_test import ( + "strconv" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/persistenceOne/pstake-native/v2/x/liquidstakeibc/types" ) const ( - TestDelegatorAddress = "persistence1234" - TestLSMDenom = "cosmosvaloper1234/1" + TestDelegatorAddress = "persistence1234" + TestLSMDenom = "cosmosvaloper1234/1" + TestLSMDenomIncomplete = "cosmosvaloper1234/" + LSMDepositsTestAmount = 15000 ) func (suite *IntegrationTestSuite) TestGetSetLSMDeposit() { @@ -140,6 +144,18 @@ func (suite *IntegrationTestSuite) TestGetLSMDepositsFromIbcSequenceID() { }, ) + for i := 2; i < LSMDepositsTestAmount; i++ { + suite.app.LiquidStakeIBCKeeper.SetLSMDeposit( + suite.ctx, + &types.LSMDeposit{ + ChainId: suite.chainB.ChainID, + DelegatorAddress: TestDelegatorAddress, + Denom: TestLSMDenomIncomplete + strconv.Itoa(i), + IbcSequenceId: "2", + }, + ) + } + tc := []struct { name string ibcSequence string @@ -147,14 +163,20 @@ func (suite *IntegrationTestSuite) TestGetLSMDepositsFromIbcSequenceID() { found bool }{ { - name: "Success", + name: "Success Limit Not Hit", ibcSequence: "1", expectedLen: 1, found: true, }, { - name: "NotFound", + name: "Success Limit Hit", ibcSequence: "2", + expectedLen: types.LSMDepositFilterLimit, + found: true, + }, + { + name: "NotFound", + ibcSequence: "3", expectedLen: 0, found: false, }, @@ -187,6 +209,18 @@ func (suite *IntegrationTestSuite) TestGetTransferableLSMDeposits() { }, ) + for i := 2; i < LSMDepositsTestAmount; i++ { + suite.app.LiquidStakeIBCKeeper.SetLSMDeposit( + suite.ctx, + &types.LSMDeposit{ + ChainId: suite.chainA.ChainID, + DelegatorAddress: TestDelegatorAddress, + Denom: TestLSMDenomIncomplete + strconv.Itoa(i), + State: types.LSMDeposit_DEPOSIT_PENDING, + }, + ) + } + tc := []struct { name string chainID string @@ -194,14 +228,20 @@ func (suite *IntegrationTestSuite) TestGetTransferableLSMDeposits() { found bool }{ { - name: "Success", + name: "Success Limit Not Hit", chainID: suite.chainB.ChainID, expectedLen: 1, found: true, }, { - name: "NotFound", + name: "Success Limit Not Hit", chainID: suite.chainA.ChainID, + expectedLen: types.LSMDepositFilterLimit, + found: true, + }, + { + name: "NotFound", + chainID: "non-valid-chain-id", expectedLen: 0, found: false, }, @@ -214,7 +254,7 @@ func (suite *IntegrationTestSuite) TestGetTransferableLSMDeposits() { suite.Require().Equal(t.expectedLen, len(deposits)) if t.found { suite.Require().Equal( - suite.chainB.ChainID, deposits[0].ChainId, + t.chainID, deposits[0].ChainId, TestDelegatorAddress, deposits[0].DelegatorAddress, TestLSMDenom, deposits[0].Denom, ) @@ -234,6 +274,18 @@ func (suite *IntegrationTestSuite) TestGetRedeemableLSMDeposits() { }, ) + for i := 2; i < LSMDepositsTestAmount; i++ { + suite.app.LiquidStakeIBCKeeper.SetLSMDeposit( + suite.ctx, + &types.LSMDeposit{ + ChainId: suite.chainA.ChainID, + DelegatorAddress: TestDelegatorAddress, + Denom: TestLSMDenomIncomplete + strconv.Itoa(i), + State: types.LSMDeposit_DEPOSIT_RECEIVED, + }, + ) + } + tc := []struct { name string chainID string @@ -241,14 +293,20 @@ func (suite *IntegrationTestSuite) TestGetRedeemableLSMDeposits() { found bool }{ { - name: "Success", + name: "Success Limit Not Hit", chainID: suite.chainB.ChainID, expectedLen: 1, found: true, }, { - name: "NotFound", + name: "Success Limit Hit", chainID: suite.chainA.ChainID, + expectedLen: types.LSMDepositFilterLimit, + found: true, + }, + { + name: "NotFound", + chainID: "non-valid-chain-id", expectedLen: 0, found: false, }, @@ -261,7 +319,7 @@ func (suite *IntegrationTestSuite) TestGetRedeemableLSMDeposits() { suite.Require().Equal(t.expectedLen, len(deposits)) if t.found { suite.Require().Equal( - suite.chainB.ChainID, deposits[0].ChainId, + t.chainID, deposits[0].ChainId, TestDelegatorAddress, deposits[0].DelegatorAddress, TestLSMDenom, deposits[0].Denom, ) @@ -396,6 +454,28 @@ func (suite *IntegrationTestSuite) TestFilterLSMDeposits() { suite.Require().Equal("cosmosvaloper1234/1", deposits[0].Denom) } +func (suite *IntegrationTestSuite) TestFilterLSMDepositsWithLimit() { + for i := 2; i < LSMDepositsTestAmount; i++ { + suite.app.LiquidStakeIBCKeeper.SetLSMDeposit( + suite.ctx, + &types.LSMDeposit{ + ChainId: suite.chainB.ChainID, + DelegatorAddress: TestDelegatorAddress, + Denom: TestLSMDenomIncomplete + strconv.Itoa(i), + }, + ) + } + + deposits := suite.app.LiquidStakeIBCKeeper.FilterLSMDepositsWithLimit( + suite.ctx, + func(d types.LSMDeposit) bool { + return d.ChainId == suite.chainB.ChainID + }, + ) + + suite.Require().Equal(types.LSMDepositFilterLimit, len(deposits)) +} + func (suite *IntegrationTestSuite) TestGetLSMDepositAmountUntokenized() { deposits := []*types.LSMDeposit{ { diff --git a/x/liquidstakeibc/types/keys.go b/x/liquidstakeibc/types/keys.go index 746b0b516..eed50f491 100644 --- a/x/liquidstakeibc/types/keys.go +++ b/x/liquidstakeibc/types/keys.go @@ -53,6 +53,8 @@ const ( IBCPrefix = transfertypes.DenomPrefix + "/" UnbondingStateEpochLimit = 4 + + LSMDepositFilterLimit = 10000 ) // Consts for KV updates, update host chain