From ebb3b3f2c861e60daf19dac42068e590d03ff613 Mon Sep 17 00:00:00 2001 From: sontrinh16 Date: Tue, 17 Dec 2024 15:28:57 +0700 Subject: [PATCH 1/4] add lockup and multisig tests --- .../lockup/continous_lockup_test_suite.go | 199 +++++++++++++ .../lockup/delayed_lockup_test_suite.go | 170 +++++++++++ .../v2/accounts/lockup/lockup_account_test.go | 11 + .../lockup/periodic_lockup_test_suite.go | 217 ++++++++++++++ .../lockup/permanent_lockup_test_suite.go | 132 +++++++++ tests/integration/v2/accounts/lockup/utils.go | 217 ++++++++++++++ .../v2/accounts/multisig/account_test.go | 268 ++++++++++++++++++ .../v2/accounts/multisig/test_suite.go | 227 +++++++++++++++ tests/integration/v2/services.go | 14 + 9 files changed, 1455 insertions(+) create mode 100644 tests/integration/v2/accounts/lockup/continous_lockup_test_suite.go create mode 100644 tests/integration/v2/accounts/lockup/delayed_lockup_test_suite.go create mode 100644 tests/integration/v2/accounts/lockup/lockup_account_test.go create mode 100644 tests/integration/v2/accounts/lockup/periodic_lockup_test_suite.go create mode 100644 tests/integration/v2/accounts/lockup/permanent_lockup_test_suite.go create mode 100644 tests/integration/v2/accounts/lockup/utils.go create mode 100644 tests/integration/v2/accounts/multisig/account_test.go create mode 100644 tests/integration/v2/accounts/multisig/test_suite.go diff --git a/tests/integration/v2/accounts/lockup/continous_lockup_test_suite.go b/tests/integration/v2/accounts/lockup/continous_lockup_test_suite.go new file mode 100644 index 000000000000..eea37234e543 --- /dev/null +++ b/tests/integration/v2/accounts/lockup/continous_lockup_test_suite.go @@ -0,0 +1,199 @@ +package lockup + +import ( + "testing" + "time" + + "github.com/stretchr/testify/require" + + "cosmossdk.io/collections" + "cosmossdk.io/core/header" + "cosmossdk.io/math" + lockupaccount "cosmossdk.io/x/accounts/defaults/lockup" + types "cosmossdk.io/x/accounts/defaults/lockup/v1" + + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + "github.com/cosmos/cosmos-sdk/tests/integration/v2" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func (s *IntegrationTestSuite) TestContinuousLockingAccount() { + t := s.T() + currentTime := time.Now() + ctx := s.ctx + ctx = integration.SetHeaderInfo(ctx, header.Info{Time: currentTime}) + + ownerAddrStr, err := s.authKeeper.AddressCodec().BytesToString(accOwner) + require.NoError(t, err) + s.fundAccount(s.bankKeeper, ctx, accOwner, sdk.Coins{sdk.NewCoin("stake", math.NewInt(1000000))}) + randAcc := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) + withdrawAcc := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) + + _, accountAddr, err := s.accountsKeeper.Init(ctx, lockupaccount.CONTINUOUS_LOCKING_ACCOUNT, accOwner, &types.MsgInitLockupAccount{ + Owner: ownerAddrStr, + StartTime: currentTime, + // end time in 1 minutes + EndTime: currentTime.Add(time.Minute), + }, sdk.Coins{sdk.NewCoin("stake", math.NewInt(1000))}, nil) + require.NoError(t, err) + + addr, err := s.authKeeper.AddressCodec().BytesToString(randAcc) + require.NoError(t, err) + + vals, err := s.stakingKeeper.GetAllValidators(ctx) + require.NoError(t, err) + val := vals[0] + + t.Run("error - execute message, wrong sender", func(t *testing.T) { + msg := &types.MsgSend{ + Sender: addr, + ToAddress: addr, + Amount: sdk.Coins{sdk.NewCoin("stake", math.NewInt(100))}, + } + err := s.executeTx(ctx, msg, s.accountsKeeper, accountAddr, accOwner) + require.NotNil(t, err) + }) + t.Run("error - execute send message, insufficient fund", func(t *testing.T) { + msg := &types.MsgSend{ + Sender: ownerAddrStr, + ToAddress: addr, + Amount: sdk.Coins{sdk.NewCoin("stake", math.NewInt(100))}, + } + err := s.executeTx(ctx, msg, s.accountsKeeper, accountAddr, accOwner) + require.NotNil(t, err) + }) + t.Run("error - execute withdraw message, no withdrawable token", func(t *testing.T) { + ownerAddr, err := s.authKeeper.AddressCodec().BytesToString(accOwner) + require.NoError(t, err) + withdrawAddr, err := s.authKeeper.AddressCodec().BytesToString(withdrawAcc) + require.NoError(t, err) + msg := &types.MsgWithdraw{ + Withdrawer: ownerAddr, + ToAddress: withdrawAddr, + Denoms: []string{"stake"}, + } + err = s.executeTx(ctx, msg, s.accountsKeeper, accountAddr, accOwner) + require.NotNil(t, err) + }) + + // Update context time + // 12 sec = 1/5 of a minute so 200stake should be released + ctx = integration.SetHeaderInfo(ctx, header.Info{Time: currentTime.Add(time.Second * 12)}) + + // Check if token is sendable + t.Run("ok - execute send message", func(t *testing.T) { + msg := &types.MsgSend{ + Sender: ownerAddrStr, + ToAddress: addr, + Amount: sdk.Coins{sdk.NewCoin("stake", math.NewInt(100))}, + } + err := s.executeTx(ctx, msg, s.accountsKeeper, accountAddr, accOwner) + require.NoError(t, err) + + balance := s.bankKeeper.GetBalance(ctx, randAcc, "stake") + require.True(t, balance.Amount.Equal(math.NewInt(100))) + }) + t.Run("ok - execute withdraw message", func(t *testing.T) { + ownerAddr, err := s.authKeeper.AddressCodec().BytesToString(accOwner) + require.NoError(t, err) + withdrawAddr, err := s.authKeeper.AddressCodec().BytesToString(withdrawAcc) + require.NoError(t, err) + msg := &types.MsgWithdraw{ + Withdrawer: ownerAddr, + ToAddress: withdrawAddr, + Denoms: []string{"stake"}, + } + err = s.executeTx(ctx, msg, s.accountsKeeper, accountAddr, accOwner) + require.NoError(t, err) + + // withdrawable amount should be 200 - 100 = 100stake + balance := s.bankKeeper.GetBalance(ctx, withdrawAcc, "stake") + require.True(t, balance.Amount.Equal(math.NewInt(100))) + }) + t.Run("ok - execute delegate message", func(t *testing.T) { + msg := &types.MsgDelegate{ + Sender: ownerAddrStr, + ValidatorAddress: val.OperatorAddress, + Amount: sdk.NewCoin("stake", math.NewInt(100)), + } + err = s.executeTx(ctx, msg, s.accountsKeeper, accountAddr, accOwner) + require.NoError(t, err) + + valbz, err := s.stakingKeeper.ValidatorAddressCodec().StringToBytes(val.OperatorAddress) + require.NoError(t, err) + + del, err := s.stakingKeeper.Delegations.Get( + ctx, collections.Join(sdk.AccAddress(accountAddr), sdk.ValAddress(valbz)), + ) + require.NoError(t, err) + require.NotNil(t, del) + + // check if tracking is updated accordingly + lockupAccountInfoResponse := s.queryLockupAccInfo(ctx, s.accountsKeeper, accountAddr) + delLocking := lockupAccountInfoResponse.DelegatedLocking + require.True(t, delLocking.AmountOf("stake").Equal(math.NewInt(100))) + }) + t.Run("ok - execute withdraw reward message", func(t *testing.T) { + msg := &types.MsgWithdrawReward{ + Sender: ownerAddrStr, + ValidatorAddress: val.OperatorAddress, + } + err = s.executeTx(ctx, msg, s.accountsKeeper, accountAddr, accOwner) + require.NoError(t, err) + }) + t.Run("ok - execute undelegate message", func(t *testing.T) { + vals, err := s.stakingKeeper.GetAllValidators(ctx) + require.NoError(t, err) + val := vals[0] + msg := &types.MsgUndelegate{ + Sender: ownerAddrStr, + ValidatorAddress: val.OperatorAddress, + Amount: sdk.NewCoin("stake", math.NewInt(100)), + } + err = s.executeTx(ctx, msg, s.accountsKeeper, accountAddr, accOwner) + require.NoError(t, err) + valbz, err := s.stakingKeeper.ValidatorAddressCodec().StringToBytes(val.OperatorAddress) + require.NoError(t, err) + + ubd, err := s.stakingKeeper.GetUnbondingDelegation( + ctx, sdk.AccAddress(accountAddr), sdk.ValAddress(valbz), + ) + require.NoError(t, err) + require.Equal(t, len(ubd.Entries), 1) + + // check if tracking is updated accordingly + lockupAccountInfoResponse := s.queryLockupAccInfo(ctx, s.accountsKeeper, accountAddr) + delLocking := lockupAccountInfoResponse.DelegatedLocking + require.True(t, delLocking.AmountOf("stake").Equal(math.ZeroInt())) + }) + + // Update context time to end time + ctx = integration.SetHeaderInfo(ctx, header.Info{Time: currentTime.Add(time.Minute)}) + + // test if tracking delegate work perfectly + t.Run("ok - execute delegate message", func(t *testing.T) { + msg := &types.MsgDelegate{ + Sender: ownerAddrStr, + ValidatorAddress: val.OperatorAddress, + Amount: sdk.NewCoin("stake", math.NewInt(100)), + } + err = s.executeTx(ctx, msg, s.accountsKeeper, accountAddr, accOwner) + require.NoError(t, err) + + valbz, err := s.stakingKeeper.ValidatorAddressCodec().StringToBytes(val.OperatorAddress) + require.NoError(t, err) + + del, err := s.stakingKeeper.Delegations.Get( + ctx, collections.Join(sdk.AccAddress(accountAddr), sdk.ValAddress(valbz)), + ) + require.NoError(t, err) + require.NotNil(t, del) + + // check if tracking is updated accordingly + lockupAccountInfoResponse := s.queryLockupAccInfo(ctx, s.accountsKeeper, accountAddr) + delLocking := lockupAccountInfoResponse.DelegatedLocking + require.True(t, delLocking.AmountOf("stake").Equal(math.ZeroInt())) + delFree := lockupAccountInfoResponse.DelegatedFree + require.True(t, delFree.AmountOf("stake").Equal(math.NewInt(100))) + }) +} diff --git a/tests/integration/v2/accounts/lockup/delayed_lockup_test_suite.go b/tests/integration/v2/accounts/lockup/delayed_lockup_test_suite.go new file mode 100644 index 000000000000..e46cc17d73e3 --- /dev/null +++ b/tests/integration/v2/accounts/lockup/delayed_lockup_test_suite.go @@ -0,0 +1,170 @@ +package lockup + +import ( + "testing" + "time" + + "github.com/stretchr/testify/require" + + "cosmossdk.io/collections" + "cosmossdk.io/core/header" + "cosmossdk.io/math" + lockupaccount "cosmossdk.io/x/accounts/defaults/lockup" + types "cosmossdk.io/x/accounts/defaults/lockup/v1" + + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + "github.com/cosmos/cosmos-sdk/tests/integration/v2" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func (s *IntegrationTestSuite) TestDelayedLockingAccount() { + t := s.T() + currentTime := time.Now() + ctx := s.ctx + ctx = integration.SetHeaderInfo(ctx, header.Info{Time: currentTime}) + + ownerAddrStr, err := s.authKeeper.AddressCodec().BytesToString(accOwner) + require.NoError(t, err) + s.fundAccount(s.bankKeeper, ctx, accOwner, sdk.Coins{sdk.NewCoin("stake", math.NewInt(1000000))}) + randAcc := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) + withdrawAcc := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) + + _, accountAddr, err := s.accountsKeeper.Init(ctx, lockupaccount.DELAYED_LOCKING_ACCOUNT, accOwner, &types.MsgInitLockupAccount{ + Owner: ownerAddrStr, + // end time in 1 minutes + EndTime: currentTime.Add(time.Minute), + }, sdk.Coins{sdk.NewCoin("stake", math.NewInt(1000))}, nil) + require.NoError(t, err) + + addr, err := s.authKeeper.AddressCodec().BytesToString(randAcc) + require.NoError(t, err) + + vals, err := s.stakingKeeper.GetAllValidators(ctx) + require.NoError(t, err) + val := vals[0] + + t.Run("error - execute message, wrong sender", func(t *testing.T) { + msg := &types.MsgSend{ + Sender: addr, + ToAddress: addr, + Amount: sdk.Coins{sdk.NewCoin("stake", math.NewInt(100))}, + } + err := s.executeTx(ctx, msg, s.accountsKeeper, accountAddr, accOwner) + require.NotNil(t, err) + }) + t.Run("error - execute send message, insufficient fund", func(t *testing.T) { + msg := &types.MsgSend{ + Sender: ownerAddrStr, + ToAddress: addr, + Amount: sdk.Coins{sdk.NewCoin("stake", math.NewInt(100))}, + } + err := s.executeTx(ctx, msg, s.accountsKeeper, accountAddr, accOwner) + require.NotNil(t, err) + }) + t.Run("error - execute withdraw message, no withdrawable token", func(t *testing.T) { + ownerAddr, err := s.authKeeper.AddressCodec().BytesToString(accOwner) + require.NoError(t, err) + withdrawAddr, err := s.authKeeper.AddressCodec().BytesToString(withdrawAcc) + require.NoError(t, err) + msg := &types.MsgWithdraw{ + Withdrawer: ownerAddr, + ToAddress: withdrawAddr, + Denoms: []string{"stake"}, + } + err = s.executeTx(ctx, msg, s.accountsKeeper, accountAddr, accOwner) + require.NotNil(t, err) + }) + t.Run("ok - execute delegate message", func(t *testing.T) { + msg := &types.MsgDelegate{ + Sender: ownerAddrStr, + ValidatorAddress: val.OperatorAddress, + Amount: sdk.NewCoin("stake", math.NewInt(100)), + } + err = s.executeTx(ctx, msg, s.accountsKeeper, accountAddr, accOwner) + require.NoError(t, err) + + valbz, err := s.stakingKeeper.ValidatorAddressCodec().StringToBytes(val.OperatorAddress) + require.NoError(t, err) + + del, err := s.stakingKeeper.Delegations.Get( + ctx, collections.Join(sdk.AccAddress(accountAddr), sdk.ValAddress(valbz)), + ) + require.NoError(t, err) + require.NotNil(t, del) + + // check if tracking is updated accordingly + lockupAccountInfoResponse := s.queryLockupAccInfo(ctx, s.accountsKeeper, accountAddr) + delLocking := lockupAccountInfoResponse.DelegatedLocking + require.True(t, delLocking.AmountOf("stake").Equal(math.NewInt(100))) + }) + t.Run("ok - execute withdraw reward message", func(t *testing.T) { + msg := &types.MsgWithdrawReward{ + Sender: ownerAddrStr, + ValidatorAddress: val.OperatorAddress, + } + err = s.executeTx(ctx, msg, s.accountsKeeper, accountAddr, accOwner) + require.NoError(t, err) + }) + t.Run("ok - execute undelegate message", func(t *testing.T) { + vals, err := s.stakingKeeper.GetAllValidators(ctx) + require.NoError(t, err) + val := vals[0] + msg := &types.MsgUndelegate{ + Sender: ownerAddrStr, + ValidatorAddress: val.OperatorAddress, + Amount: sdk.NewCoin("stake", math.NewInt(100)), + } + err = s.executeTx(ctx, msg, s.accountsKeeper, accountAddr, accOwner) + require.NoError(t, err) + valbz, err := s.stakingKeeper.ValidatorAddressCodec().StringToBytes(val.OperatorAddress) + require.NoError(t, err) + + ubd, err := s.stakingKeeper.GetUnbondingDelegation( + ctx, sdk.AccAddress(accountAddr), sdk.ValAddress(valbz), + ) + require.NoError(t, err) + require.Equal(t, len(ubd.Entries), 1) + + // check if tracking is updated accordingly + lockupAccountInfoResponse := s.queryLockupAccInfo(ctx, s.accountsKeeper, accountAddr) + delLocking := lockupAccountInfoResponse.DelegatedLocking + require.True(t, delLocking.AmountOf("stake").Equal(math.ZeroInt())) + }) + + // Update context time + // After endtime fund should be unlock + ctx = integration.SetHeaderInfo(ctx, header.Info{Time: currentTime.Add(time.Second * 61)}) + + // Check if token is sendable after unlock + t.Run("ok - execute send message", func(t *testing.T) { + msg := &types.MsgSend{ + Sender: ownerAddrStr, + ToAddress: addr, + Amount: sdk.Coins{sdk.NewCoin("stake", math.NewInt(100))}, + } + err := s.executeTx(ctx, msg, s.accountsKeeper, accountAddr, accOwner) + require.NoError(t, err) + + balance := s.bankKeeper.GetBalance(ctx, randAcc, "stake") + require.True(t, balance.Amount.Equal(math.NewInt(100))) + }) + // Test to withdraw all the remain funds to an account of choice + t.Run("ok - execute withdraw message", func(t *testing.T) { + ownerAddr, err := s.authKeeper.AddressCodec().BytesToString(accOwner) + require.NoError(t, err) + withdrawAddr, err := s.authKeeper.AddressCodec().BytesToString(withdrawAcc) + require.NoError(t, err) + msg := &types.MsgWithdraw{ + Withdrawer: ownerAddr, + ToAddress: withdrawAddr, + Denoms: []string{"stake"}, + } + err = s.executeTx(ctx, msg, s.accountsKeeper, accountAddr, accOwner) + require.NoError(t, err) + + // withdrawable amount should be + // 1000stake - 100stake( above sent amt ) - 100stake(above delegate amt) = 800stake + balance := s.bankKeeper.GetBalance(ctx, withdrawAcc, "stake") + require.True(t, balance.Amount.Equal(math.NewInt(800))) + }) +} diff --git a/tests/integration/v2/accounts/lockup/lockup_account_test.go b/tests/integration/v2/accounts/lockup/lockup_account_test.go new file mode 100644 index 000000000000..c8f409d7985e --- /dev/null +++ b/tests/integration/v2/accounts/lockup/lockup_account_test.go @@ -0,0 +1,11 @@ +package lockup + +import ( + "testing" + + "github.com/stretchr/testify/suite" +) + +func TestIntegrationTestSuite(t *testing.T) { + suite.Run(t, NewIntegrationTestSuite()) +} diff --git a/tests/integration/v2/accounts/lockup/periodic_lockup_test_suite.go b/tests/integration/v2/accounts/lockup/periodic_lockup_test_suite.go new file mode 100644 index 000000000000..f0f81cc19e2c --- /dev/null +++ b/tests/integration/v2/accounts/lockup/periodic_lockup_test_suite.go @@ -0,0 +1,217 @@ +package lockup + +import ( + "testing" + "time" + + "github.com/stretchr/testify/require" + + "cosmossdk.io/collections" + "cosmossdk.io/core/header" + "cosmossdk.io/math" + lockupaccount "cosmossdk.io/x/accounts/defaults/lockup" + types "cosmossdk.io/x/accounts/defaults/lockup/v1" + + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + "github.com/cosmos/cosmos-sdk/tests/integration/v2" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func (s *IntegrationTestSuite) TestPeriodicLockingAccount() { + t := s.T() + currentTime := time.Now() + ctx := s.ctx + ctx = integration.SetHeaderInfo(ctx, header.Info{Time: currentTime}) + + ownerAddrStr, err := s.authKeeper.AddressCodec().BytesToString(accOwner) + require.NoError(t, err) + s.fundAccount(s.bankKeeper, ctx, accOwner, sdk.Coins{sdk.NewCoin("stake", math.NewInt(1000000))}) + randAcc := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) + withdrawAcc := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) + + _, accountAddr, err := s.accountsKeeper.Init(ctx, lockupaccount.PERIODIC_LOCKING_ACCOUNT, accOwner, &types.MsgInitPeriodicLockingAccount{ + Owner: ownerAddrStr, + StartTime: currentTime, + LockingPeriods: []types.Period{ + { + Amount: sdk.NewCoins(sdk.NewCoin("stake", math.NewInt(500))), + Length: time.Minute, + }, + { + Amount: sdk.NewCoins(sdk.NewCoin("stake", math.NewInt(500))), + Length: time.Minute, + }, + { + Amount: sdk.NewCoins(sdk.NewCoin("stake", math.NewInt(500))), + Length: time.Minute, + }, + }, + }, sdk.Coins{sdk.NewCoin("stake", math.NewInt(1500))}, nil) + require.NoError(t, err) + + addr, err := s.authKeeper.AddressCodec().BytesToString(randAcc) + require.NoError(t, err) + + vals, err := s.stakingKeeper.GetAllValidators(ctx) + require.NoError(t, err) + val := vals[0] + + t.Run("error - execute message, wrong sender", func(t *testing.T) { + msg := &types.MsgSend{ + Sender: addr, + ToAddress: addr, + Amount: sdk.Coins{sdk.NewCoin("stake", math.NewInt(100))}, + } + err := s.executeTx(ctx, msg, s.accountsKeeper, accountAddr, accOwner) + require.NotNil(t, err) + }) + // No token being unlocked yet + t.Run("error - execute send message, insufficient fund", func(t *testing.T) { + msg := &types.MsgSend{ + Sender: ownerAddrStr, + ToAddress: addr, + Amount: sdk.Coins{sdk.NewCoin("stake", math.NewInt(100))}, + } + err := s.executeTx(ctx, msg, s.accountsKeeper, accountAddr, accOwner) + require.NotNil(t, err) + }) + t.Run("error - execute withdraw message, no withdrawable token", func(t *testing.T) { + ownerAddr, err := s.authKeeper.AddressCodec().BytesToString(accOwner) + require.NoError(t, err) + withdrawAddr, err := s.authKeeper.AddressCodec().BytesToString(withdrawAcc) + require.NoError(t, err) + msg := &types.MsgWithdraw{ + Withdrawer: ownerAddr, + ToAddress: withdrawAddr, + Denoms: []string{"stake"}, + } + err = s.executeTx(ctx, msg, s.accountsKeeper, accountAddr, accOwner) + require.NotNil(t, err) + }) + + // Update context time + // After first period 500stake should be unlock + ctx = integration.SetHeaderInfo(ctx, header.Info{Time: currentTime.Add(time.Minute)}) + + // Check if 500 stake is sendable now + t.Run("ok - execute send message", func(t *testing.T) { + msg := &types.MsgSend{ + Sender: ownerAddrStr, + ToAddress: addr, + Amount: sdk.Coins{sdk.NewCoin("stake", math.NewInt(500))}, + } + err := s.executeTx(ctx, msg, s.accountsKeeper, accountAddr, accOwner) + require.NoError(t, err) + + balance := s.bankKeeper.GetBalance(ctx, randAcc, "stake") + require.True(t, balance.Amount.Equal(math.NewInt(500))) + }) + + // Update context time + // After second period 1000stake should be unlock + ctx = integration.SetHeaderInfo(ctx, header.Info{Time: currentTime.Add(time.Minute * 2)}) + + t.Run("oke - execute withdraw message", func(t *testing.T) { + ownerAddr, err := s.authKeeper.AddressCodec().BytesToString(accOwner) + require.NoError(t, err) + withdrawAddr, err := s.authKeeper.AddressCodec().BytesToString(withdrawAcc) + require.NoError(t, err) + msg := &types.MsgWithdraw{ + Withdrawer: ownerAddr, + ToAddress: withdrawAddr, + Denoms: []string{"stake"}, + } + err = s.executeTx(ctx, msg, s.accountsKeeper, accountAddr, accOwner) + require.NoError(t, err) + + // withdrawable amount should be + // 1000stake - 500stake( above sent amt ) = 500stake + balance := s.bankKeeper.GetBalance(ctx, withdrawAcc, "stake") + require.True(t, balance.Amount.Equal(math.NewInt(500))) + }) + + t.Run("ok - execute delegate message", func(t *testing.T) { + msg := &types.MsgDelegate{ + Sender: ownerAddrStr, + ValidatorAddress: val.OperatorAddress, + Amount: sdk.NewCoin("stake", math.NewInt(100)), + } + err = s.executeTx(ctx, msg, s.accountsKeeper, accountAddr, accOwner) + require.NoError(t, err) + + valbz, err := s.stakingKeeper.ValidatorAddressCodec().StringToBytes(val.OperatorAddress) + require.NoError(t, err) + + del, err := s.stakingKeeper.Delegations.Get( + ctx, collections.Join(sdk.AccAddress(accountAddr), sdk.ValAddress(valbz)), + ) + require.NoError(t, err) + require.NotNil(t, del) + + // check if tracking is updated accordingly + lockupAccountInfoResponse := s.queryLockupAccInfo(ctx, s.accountsKeeper, accountAddr) + delLocking := lockupAccountInfoResponse.DelegatedLocking + require.True(t, delLocking.AmountOf("stake").Equal(math.NewInt(100))) + }) + t.Run("ok - execute withdraw reward message", func(t *testing.T) { + msg := &types.MsgWithdrawReward{ + Sender: ownerAddrStr, + ValidatorAddress: val.OperatorAddress, + } + err = s.executeTx(ctx, msg, s.accountsKeeper, accountAddr, accOwner) + require.NoError(t, err) + }) + t.Run("ok - execute undelegate message", func(t *testing.T) { + vals, err := s.stakingKeeper.GetAllValidators(ctx) + require.NoError(t, err) + val := vals[0] + msg := &types.MsgUndelegate{ + Sender: ownerAddrStr, + ValidatorAddress: val.OperatorAddress, + Amount: sdk.NewCoin("stake", math.NewInt(100)), + } + err = s.executeTx(ctx, msg, s.accountsKeeper, accountAddr, accOwner) + require.NoError(t, err) + valbz, err := s.stakingKeeper.ValidatorAddressCodec().StringToBytes(val.OperatorAddress) + require.NoError(t, err) + + ubd, err := s.stakingKeeper.GetUnbondingDelegation( + ctx, sdk.AccAddress(accountAddr), sdk.ValAddress(valbz), + ) + require.NoError(t, err) + require.Equal(t, len(ubd.Entries), 1) + + // check if tracking is updated accordingly + lockupAccountInfoResponse := s.queryLockupAccInfo(ctx, s.accountsKeeper, accountAddr) + delLocking := lockupAccountInfoResponse.DelegatedLocking + require.True(t, delLocking.AmountOf("stake").Equal(math.ZeroInt())) + }) + + // Update context time + // After third period 1500stake should be unlock + ctx = integration.SetHeaderInfo(ctx, header.Info{Time: currentTime.Add(time.Minute * 3)}) + + t.Run("ok - execute delegate message", func(t *testing.T) { + msg := &types.MsgDelegate{ + Sender: ownerAddrStr, + ValidatorAddress: val.OperatorAddress, + Amount: sdk.NewCoin("stake", math.NewInt(100)), + } + err = s.executeTx(ctx, msg, s.accountsKeeper, accountAddr, accOwner) + require.NoError(t, err) + + valbz, err := s.stakingKeeper.ValidatorAddressCodec().StringToBytes(val.OperatorAddress) + require.NoError(t, err) + + del, err := s.stakingKeeper.Delegations.Get( + ctx, collections.Join(sdk.AccAddress(accountAddr), sdk.ValAddress(valbz)), + ) + require.NoError(t, err) + require.NotNil(t, del) + + // check if tracking is updated accordingly + lockupAccountInfoResponse := s.queryLockupAccInfo(ctx, s.accountsKeeper, accountAddr) + delFree := lockupAccountInfoResponse.DelegatedFree + require.True(t, delFree.AmountOf("stake").Equal(math.NewInt(100))) + }) +} diff --git a/tests/integration/v2/accounts/lockup/permanent_lockup_test_suite.go b/tests/integration/v2/accounts/lockup/permanent_lockup_test_suite.go new file mode 100644 index 000000000000..feee0f4c3c9e --- /dev/null +++ b/tests/integration/v2/accounts/lockup/permanent_lockup_test_suite.go @@ -0,0 +1,132 @@ +package lockup + +import ( + "testing" + "time" + + "github.com/stretchr/testify/require" + + "cosmossdk.io/collections" + "cosmossdk.io/core/header" + "cosmossdk.io/math" + lockupaccount "cosmossdk.io/x/accounts/defaults/lockup" + types "cosmossdk.io/x/accounts/defaults/lockup/v1" + + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + "github.com/cosmos/cosmos-sdk/tests/integration/v2" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func (s *IntegrationTestSuite) TestPermanentLockingAccount() { + t := s.T() + currentTime := time.Now() + ctx := s.ctx + ctx = integration.SetHeaderInfo(ctx, header.Info{Time: currentTime}) + + ownerAddrStr, err := s.authKeeper.AddressCodec().BytesToString(accOwner) + require.NoError(t, err) + s.fundAccount(s.bankKeeper, ctx, accOwner, sdk.Coins{sdk.NewCoin("stake", math.NewInt(1000000))}) + randAcc := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) + + _, accountAddr, err := s.accountsKeeper.Init(ctx, lockupaccount.PERMANENT_LOCKING_ACCOUNT, accOwner, &types.MsgInitLockupAccount{ + Owner: ownerAddrStr, + }, sdk.Coins{sdk.NewCoin("stake", math.NewInt(1000))}, nil) + require.NoError(t, err) + + addr, err := s.authKeeper.AddressCodec().BytesToString(randAcc) + require.NoError(t, err) + + vals, err := s.stakingKeeper.GetAllValidators(ctx) + require.NoError(t, err) + val := vals[0] + + t.Run("error - execute message, wrong sender", func(t *testing.T) { + msg := &types.MsgSend{ + Sender: addr, + ToAddress: addr, + Amount: sdk.Coins{sdk.NewCoin("stake", math.NewInt(100))}, + } + err := s.executeTx(ctx, msg, s.accountsKeeper, accountAddr, accOwner) + require.NotNil(t, err) + }) + t.Run("error - execute send message, insufficient fund", func(t *testing.T) { + msg := &types.MsgSend{ + Sender: ownerAddrStr, + ToAddress: addr, + Amount: sdk.Coins{sdk.NewCoin("stake", math.NewInt(100))}, + } + err := s.executeTx(ctx, msg, s.accountsKeeper, accountAddr, accOwner) + require.NotNil(t, err) + }) + t.Run("ok - execute delegate message", func(t *testing.T) { + msg := &types.MsgDelegate{ + Sender: ownerAddrStr, + ValidatorAddress: val.OperatorAddress, + Amount: sdk.NewCoin("stake", math.NewInt(100)), + } + err = s.executeTx(ctx, msg, s.accountsKeeper, accountAddr, accOwner) + require.NoError(t, err) + + valbz, err := s.stakingKeeper.ValidatorAddressCodec().StringToBytes(val.OperatorAddress) + require.NoError(t, err) + + del, err := s.stakingKeeper.Delegations.Get( + ctx, collections.Join(sdk.AccAddress(accountAddr), sdk.ValAddress(valbz)), + ) + require.NoError(t, err) + require.NotNil(t, del) + + // check if tracking is updated accordingly + lockupAccountInfoResponse := s.queryLockupAccInfo(ctx, s.accountsKeeper, accountAddr) + delLocking := lockupAccountInfoResponse.DelegatedLocking + require.True(t, delLocking.AmountOf("stake").Equal(math.NewInt(100))) + }) + t.Run("ok - execute withdraw reward message", func(t *testing.T) { + msg := &types.MsgWithdrawReward{ + Sender: ownerAddrStr, + ValidatorAddress: val.OperatorAddress, + } + err = s.executeTx(ctx, msg, s.accountsKeeper, accountAddr, accOwner) + require.NoError(t, err) + }) + t.Run("ok - execute undelegate message", func(t *testing.T) { + vals, err := s.stakingKeeper.GetAllValidators(ctx) + require.NoError(t, err) + val := vals[0] + msg := &types.MsgUndelegate{ + Sender: ownerAddrStr, + ValidatorAddress: val.OperatorAddress, + Amount: sdk.NewCoin("stake", math.NewInt(100)), + } + err = s.executeTx(ctx, msg, s.accountsKeeper, accountAddr, accOwner) + require.NoError(t, err) + valbz, err := s.stakingKeeper.ValidatorAddressCodec().StringToBytes(val.OperatorAddress) + require.NoError(t, err) + + ubd, err := s.stakingKeeper.GetUnbondingDelegation( + ctx, sdk.AccAddress(accountAddr), sdk.ValAddress(valbz), + ) + require.NoError(t, err) + require.Equal(t, len(ubd.Entries), 1) + + // check if tracking is updated accordingly + lockupAccountInfoResponse := s.queryLockupAccInfo(ctx, s.accountsKeeper, accountAddr) + delLocking := lockupAccountInfoResponse.DelegatedLocking + require.True(t, delLocking.AmountOf("stake").Equal(math.ZeroInt())) + }) + + s.fundAccount(s.bankKeeper, ctx, accountAddr, sdk.Coins{sdk.NewCoin("stake", math.NewInt(1000))}) + + t.Run("ok - execute send message", func(t *testing.T) { + msg := &types.MsgSend{ + Sender: ownerAddrStr, + ToAddress: addr, + Amount: sdk.Coins{sdk.NewCoin("stake", math.NewInt(100))}, + } + err := s.executeTx(ctx, msg, s.accountsKeeper, accountAddr, accOwner) + require.NoError(t, err) + + balance := s.bankKeeper.GetBalance(ctx, randAcc, "stake") + require.True(t, balance.Amount.Equal(math.NewInt(100))) + }) +} diff --git a/tests/integration/v2/accounts/lockup/utils.go b/tests/integration/v2/accounts/lockup/utils.go new file mode 100644 index 000000000000..01220d5be38a --- /dev/null +++ b/tests/integration/v2/accounts/lockup/utils.go @@ -0,0 +1,217 @@ +package lockup + +import ( + "context" + + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + + "cosmossdk.io/core/router" + "cosmossdk.io/core/transaction" + "cosmossdk.io/depinject" + "cosmossdk.io/log" + "cosmossdk.io/runtime/v2" + "cosmossdk.io/x/accounts" + basedepinject "cosmossdk.io/x/accounts/defaults/base/depinject" + lockupdepinject "cosmossdk.io/x/accounts/defaults/lockup/depinject" + types "cosmossdk.io/x/accounts/defaults/lockup/v1" + _ "cosmossdk.io/x/bank" // import as blank for app wiring + bankkeeper "cosmossdk.io/x/bank/keeper" + "cosmossdk.io/x/bank/testutil" + banktypes "cosmossdk.io/x/bank/types" + _ "cosmossdk.io/x/consensus" + _ "cosmossdk.io/x/distribution" // import as blank for app wiring + distrkeeper "cosmossdk.io/x/distribution/keeper" + distrtypes "cosmossdk.io/x/distribution/types" + _ "cosmossdk.io/x/staking" // import as blank for app wiring + stakingkeeper "cosmossdk.io/x/staking/keeper" + stakingtypes "cosmossdk.io/x/staking/types" + + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + "github.com/cosmos/cosmos-sdk/tests/integration/v2" + "github.com/cosmos/cosmos-sdk/testutil/configurator" + sdk "github.com/cosmos/cosmos-sdk/types" + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + _ "github.com/cosmos/cosmos-sdk/x/auth/tx/config" // import as blank for app wiring`` + _ "github.com/cosmos/cosmos-sdk/x/auth/vesting" // import as blank for app wiring + _ "github.com/cosmos/cosmos-sdk/x/genutil" // import as blank for app wiring +) + +var ( + ownerAddr = secp256k1.GenPrivKey().PubKey().Address() + accOwner = sdk.AccAddress(ownerAddr) +) + +type IntegrationTestSuite struct { + suite.Suite + + app *integration.App + ctx context.Context + + authKeeper authkeeper.AccountKeeper + accountsKeeper accounts.Keeper + bankKeeper bankkeeper.BaseKeeper + stakingKeeper *stakingkeeper.Keeper + distrKeeper distrkeeper.Keeper +} + +func NewIntegrationTestSuite() *IntegrationTestSuite { + return &IntegrationTestSuite{} +} + +func (s *IntegrationTestSuite) SetupSuite() { + s.T().Log("setting up integration test suite") + moduleConfigs := []configurator.ModuleOption{ + configurator.AccountsModule(), + configurator.AuthModule(), + configurator.BankModule(), + configurator.VestingModule(), + configurator.StakingModule(), + configurator.TxModule(), + configurator.ValidateModule(), + configurator.ConsensusModule(), + configurator.GenutilModule(), + configurator.DistributionModule(), + } + + var err error + startupCfg := integration.DefaultStartUpConfig(s.T()) + + msgRouterService := integration.NewRouterService() + s.registerMsgRouterService(msgRouterService) + + var routerFactory runtime.RouterServiceFactory = func(_ []byte) router.Service { + return msgRouterService + } + + queryRouterService := integration.NewRouterService() + s.registerQueryRouterService(queryRouterService) + + serviceBuilder := runtime.NewRouterBuilder(routerFactory, queryRouterService) + + startupCfg.BranchService = &integration.BranchService{} + startupCfg.RouterServiceBuilder = serviceBuilder + startupCfg.HeaderService = &integration.HeaderService{} + startupCfg.GasService = &integration.GasService{} + + s.app, err = integration.NewApp( + depinject.Configs(configurator.NewAppV2Config(moduleConfigs...), depinject.Provide( + // inject desired account types: + basedepinject.ProvideAccount, + + // provide base account options + basedepinject.ProvideSecp256K1PubKey, + + // inject desired account types: + lockupdepinject.ProvideAllLockupAccounts, + ), depinject.Supply(log.NewNopLogger())), + startupCfg, + &s.bankKeeper, &s.accountsKeeper, &s.authKeeper, &s.stakingKeeper, &s.distrKeeper) + require.NoError(s.T(), err) + + s.ctx = s.app.StateLatestContext(s.T()) +} + +func (s *IntegrationTestSuite) registerMsgRouterService(router *integration.RouterService) { + // register custom router service + bankSendHandler := func(ctx context.Context, req transaction.Msg) (transaction.Msg, error) { + msg, ok := req.(*banktypes.MsgSend) + if !ok { + return nil, integration.ErrInvalidMsgType + } + msgServer := bankkeeper.NewMsgServerImpl(s.bankKeeper) + resp, err := msgServer.Send(ctx, msg) + return resp, err + } + + stakingDelegateHandler := func(ctx context.Context, req transaction.Msg) (transaction.Msg, error) { + msg, ok := req.(*stakingtypes.MsgDelegate) + if !ok { + return nil, integration.ErrInvalidMsgType + } + msgServer := stakingkeeper.NewMsgServerImpl(s.stakingKeeper) + resp, err := msgServer.Delegate(ctx, msg) + return resp, err + } + + stakingUndelegateHandler := func(ctx context.Context, req transaction.Msg) (transaction.Msg, error) { + msg, ok := req.(*stakingtypes.MsgUndelegate) + if !ok { + return nil, integration.ErrInvalidMsgType + } + msgServer := stakingkeeper.NewMsgServerImpl(s.stakingKeeper) + resp, err := msgServer.Undelegate(ctx, msg) + return resp, err + } + + distrWithdrawRewardHandler := func(ctx context.Context, req transaction.Msg) (transaction.Msg, error) { + msg, ok := req.(*distrtypes.MsgWithdrawDelegatorReward) + if !ok { + return nil, integration.ErrInvalidMsgType + } + msgServer := distrkeeper.NewMsgServerImpl(s.distrKeeper) + resp, err := msgServer.WithdrawDelegatorReward(ctx, msg) + return resp, err + } + + router.RegisterHandler(bankSendHandler, "cosmos.bank.v1beta1.MsgSend") + router.RegisterHandler(stakingDelegateHandler, "cosmos.staking.v1beta1.MsgDelegate") + router.RegisterHandler(stakingUndelegateHandler, "cosmos.staking.v1beta1.MsgUndelegate") + router.RegisterHandler(distrWithdrawRewardHandler, "cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward") +} + +func (s *IntegrationTestSuite) registerQueryRouterService(router *integration.RouterService) { + // register custom router service + stakingParamsQueryHandler := func(ctx context.Context, msg transaction.Msg) (transaction.Msg, error) { + req, ok := msg.(*stakingtypes.QueryParamsRequest) + if !ok { + return nil, integration.ErrInvalidMsgType + } + qs := stakingkeeper.NewQuerier(s.stakingKeeper) + resp, err := qs.Params(ctx, req) + return resp, err + } + + bankBalanceQueryHandler := func(ctx context.Context, msg transaction.Msg) (transaction.Msg, error) { + req, ok := msg.(*banktypes.QueryBalanceRequest) + if !ok { + return nil, integration.ErrInvalidMsgType + } + qs := bankkeeper.NewQuerier(&s.bankKeeper) + resp, err := qs.Balance(ctx, req) + return resp, err + } + + router.RegisterHandler(stakingParamsQueryHandler, "cosmos.staking.v1beta1.QueryParamsRequest") + router.RegisterHandler(bankBalanceQueryHandler, "cosmos.bank.v1beta1.QueryBalanceRequest") +} + +func (s *IntegrationTestSuite) TearDownSuite() { + s.T().Log("tearing down integration test suite") +} + +func (s *IntegrationTestSuite) executeTx(ctx context.Context, msg sdk.Msg, ak accounts.Keeper, accAddr, sender []byte) error { + _, err := ak.Execute(ctx, accAddr, sender, msg, nil) + return err +} + +func (s *IntegrationTestSuite) queryAcc(ctx context.Context, req sdk.Msg, ak accounts.Keeper, accAddr []byte) (transaction.Msg, error) { + resp, err := ak.Query(ctx, accAddr, req) + return resp, err +} + +func (s *IntegrationTestSuite) fundAccount(bk bankkeeper.Keeper, ctx context.Context, addr sdk.AccAddress, amt sdk.Coins) { + require.NoError(s.T(), testutil.FundAccount(ctx, bk, addr, amt)) +} + +func (s *IntegrationTestSuite) queryLockupAccInfo(ctx context.Context, ak accounts.Keeper, accAddr []byte) *types.QueryLockupAccountInfoResponse { + req := &types.QueryLockupAccountInfoRequest{} + resp, err := s.queryAcc(ctx, req, ak, accAddr) + require.NoError(s.T(), err) + require.NotNil(s.T(), resp) + + lockupAccountInfoResponse, ok := resp.(*types.QueryLockupAccountInfoResponse) + require.True(s.T(), ok) + + return lockupAccountInfoResponse +} diff --git a/tests/integration/v2/accounts/multisig/account_test.go b/tests/integration/v2/accounts/multisig/account_test.go new file mode 100644 index 000000000000..ba23e30ef11e --- /dev/null +++ b/tests/integration/v2/accounts/multisig/account_test.go @@ -0,0 +1,268 @@ +package multisig + +import ( + "testing" + "time" + + "github.com/stretchr/testify/suite" + + bankv1beta1 "cosmossdk.io/api/cosmos/bank/v1beta1" + basev1beta1 "cosmossdk.io/api/cosmos/base/v1beta1" + "cosmossdk.io/core/header" + "cosmossdk.io/math" + v1 "cosmossdk.io/x/accounts/defaults/multisig/v1" + accountsv1 "cosmossdk.io/x/accounts/v1" + + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + "github.com/cosmos/cosmos-sdk/tests/integration/v2" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func TestIntegrationTestSuite(t *testing.T) { + suite.Run(t, NewIntegrationTestSuite()) +} + +// TestSimpleSendProposal creates a multisig account with 1 member, sends a tx, votes and executes it. +func (s *IntegrationTestSuite) TestSimpleSendProposal() { + ctx := s.ctx + ctx = integration.SetHeaderInfo(ctx, header.Info{Time: time.Now()}) + + randAcc := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) + addr, err := s.authKeeper.AddressCodec().BytesToString(randAcc) + s.NoError(err) + + initialMembers := map[string]uint64{ + s.membersAddr[0]: 100, + } + accountAddr, accAddrStr := s.initAccount(ctx, s.members[0], initialMembers) + + balance := s.bankKeeper.GetBalance(ctx, randAcc, "stake") + s.Equal(math.NewInt(0), balance.Amount) + + // do a simple bank send + msg := &bankv1beta1.MsgSend{ + FromAddress: accAddrStr, + ToAddress: addr, + Amount: []*basev1beta1.Coin{ + { + Denom: "stake", + Amount: "100", + }, + }, + } + anyMsg, err := codectypes.NewAnyWithValue(msg) + s.NoError(err) + + s.createProposal(ctx, accountAddr, s.members[0], anyMsg) + + // now we vote for it + voteReq := &v1.MsgVote{ + ProposalId: 0, + Vote: v1.VoteOption_VOTE_OPTION_YES, + } + + err = s.executeTx(ctx, voteReq, accountAddr, s.members[0]) + s.NoError(err) + + // now we execute it + err = s.executeProposal(ctx, accountAddr, s.members[0], 0) + s.NoError(err) + + foundPropResult := false + events := integration.EventsFromContext(ctx) + foundPropResult = true + for _, e := range events { + if e.Type == "proposal_tally" { + attr, found := integration.GetAttribute(e, "status") + s.True(found) + s.Equal(v1.ProposalStatus_PROPOSAL_STATUS_PASSED.String(), attr.Value) + + yesVotes, found := integration.GetAttribute(e, "yes_votes") + s.True(found) + s.Equal("100", yesVotes.Value) + + noVotes, found := integration.GetAttribute(e, "no_votes") + s.True(found) + s.Equal("0", noVotes.Value) + + propID, found := integration.GetAttribute(e, "proposal_id") + s.True(found) + s.Equal("0", propID.Value) + + execErr, found := integration.GetAttribute(e, "exec_err") + s.True(found) + s.Equal("", execErr.Value) + + rejectErr, found := integration.GetAttribute(e, "reject_err") + s.True(found) + s.Equal("", rejectErr.Value) + + } + } + s.True(foundPropResult) + + balance = s.bankKeeper.GetBalance(ctx, randAcc, "stake") + s.Equal(int64(100), balance.Amount.Int64()) + + // try to execute again, should fail + err = s.executeProposal(ctx, accountAddr, s.members[0], 0) + s.Error(err) +} + +// TestConfigUpdate creates a multisig with 1 member, adds 2 more members and +// changes the config to require 2/3 majority (also through a proposal). +func (s *IntegrationTestSuite) TestConfigUpdate() { + ctx := s.ctx + ctx = integration.SetHeaderInfo(ctx, header.Info{Time: time.Now()}) + + initialMembers := map[string]uint64{ + s.membersAddr[0]: 100, + } + accountAddr, accAddrStr := s.initAccount(ctx, s.members[0], initialMembers) + + // Add 2 members and pass the proposal + // create proposal + updateMsg := &v1.MsgUpdateConfig{ + UpdateMembers: []*v1.Member{ + { + Address: s.membersAddr[1], + Weight: 100, + }, + { + Address: s.membersAddr[2], + Weight: 100, + }, + }, + Config: &v1.Config{ + Threshold: 200, // 3 members with 100 power each, 2/3 majority + Quorum: 200, + VotingPeriod: 120, + Revote: false, + EarlyExecution: false, + }, + } + + msgExec := &accountsv1.MsgExecute{ + Sender: accAddrStr, + Target: accAddrStr, + Message: codectypes.UnsafePackAny(updateMsg), + Funds: []sdk.Coin{}, + } + + s.createProposal(ctx, accountAddr, s.members[0], codectypes.UnsafePackAny(msgExec)) + + // vote + voteReq := &v1.MsgVote{ + ProposalId: 0, + Vote: v1.VoteOption_VOTE_OPTION_YES, + } + + err := s.executeTx(ctx, voteReq, accountAddr, s.members[0]) + s.NoError(err) + + err = s.executeProposal(ctx, accountAddr, s.members[0], 0) + s.NoError(err) + + // get members + res, err := s.queryAcc(ctx, &v1.QueryConfig{}, accountAddr) + s.NoError(err) + resp := res.(*v1.QueryConfigResponse) + s.Len(resp.Members, 3) + s.Equal(int64(200), resp.Config.Threshold) + + // Try to remove a member, but it doesn't reach passing threshold + // create proposal + msgExec = &accountsv1.MsgExecute{ + Sender: accAddrStr, + Target: accAddrStr, + Message: codectypes.UnsafePackAny(&v1.MsgUpdateConfig{ + UpdateMembers: []*v1.Member{ + { + Address: s.membersAddr[1], + Weight: 0, + }, + }, + Config: &v1.Config{ + Threshold: 200, // 3 members with 100 power each, 2/3 majority + Quorum: 200, + VotingPeriod: 120, + Revote: false, + EarlyExecution: false, + }, + }), + Funds: []sdk.Coin{}, + } + + s.createProposal(ctx, accountAddr, s.members[0], codectypes.UnsafePackAny(msgExec)) + + // vote + voteReq = &v1.MsgVote{ + ProposalId: 1, + Vote: v1.VoteOption_VOTE_OPTION_NO, + } + + err = s.executeTx(ctx, voteReq, accountAddr, s.members[0]) + s.NoError(err) + + // need to wait until voting period is over because we disabled early execution on the last + // config update + err = s.executeProposal(ctx, accountAddr, s.members[0], 0) + s.ErrorContains(err, "voting period has not ended yet, and early execution is not enabled") + + // vote with member 1 + voteReq = &v1.MsgVote{ + ProposalId: 1, + Vote: v1.VoteOption_VOTE_OPTION_NO, + } + + err = s.executeTx(ctx, voteReq, accountAddr, s.members[1]) + s.NoError(err) + + // need to wait until voting period is over because we disabled early execution on the last + // config update + err = s.executeProposal(ctx, accountAddr, s.members[0], 1) + s.ErrorContains(err, "voting period has not ended yet, and early execution is not enabled") + + headerInfo := integration.HeaderInfoFromContext(ctx) + headerInfo.Time = headerInfo.Time.Add(time.Second * 121) + ctx = integration.SetHeaderInfo(ctx, headerInfo) + + // now it should work, but the proposal will fail + err = s.executeProposal(ctx, accountAddr, s.members[0], 1) + s.NoError(err) + + foundPropResult := false + events := integration.EventsFromContext(ctx) + for _, e := range events { + if e.Type == "proposal_tally" { + propID, found := integration.GetAttribute(e, "proposal_id") + s.True(found) + + if propID.Value == "1" { + foundPropResult = true + status, found := integration.GetAttribute(e, "status") + s.True(found) + s.Equal(v1.ProposalStatus_PROPOSAL_STATUS_REJECTED.String(), status.Value) + + // exec_err is nil because the proposal didn't execute + execErr, found := integration.GetAttribute(e, "exec_err") + s.True(found) + s.Equal("", execErr.Value) + + rejectErr, found := integration.GetAttribute(e, "reject_err") + s.True(found) + s.Equal("threshold not reached", rejectErr.Value) + } + + } + } + s.True(foundPropResult) + + // get members + res, err = s.queryAcc(ctx, &v1.QueryConfig{}, accountAddr) + s.NoError(err) + resp = res.(*v1.QueryConfigResponse) + s.Len(resp.Members, 3) + s.Equal(int64(200), resp.Config.Threshold) +} diff --git a/tests/integration/v2/accounts/multisig/test_suite.go b/tests/integration/v2/accounts/multisig/test_suite.go new file mode 100644 index 000000000000..838e3a519678 --- /dev/null +++ b/tests/integration/v2/accounts/multisig/test_suite.go @@ -0,0 +1,227 @@ +package multisig + +import ( + "context" + + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + + "cosmossdk.io/core/router" + "cosmossdk.io/core/transaction" + "cosmossdk.io/depinject" + "cosmossdk.io/log" + "cosmossdk.io/math" + "cosmossdk.io/runtime/v2" + "cosmossdk.io/x/accounts" + basedepinject "cosmossdk.io/x/accounts/defaults/base/depinject" + multisigdepinject "cosmossdk.io/x/accounts/defaults/multisig/depinject" + v1 "cosmossdk.io/x/accounts/defaults/multisig/v1" + accountsv1 "cosmossdk.io/x/accounts/v1" + _ "cosmossdk.io/x/bank" // import as blank for app wiring + bankkeeper "cosmossdk.io/x/bank/keeper" + "cosmossdk.io/x/bank/testutil" + banktypes "cosmossdk.io/x/bank/types" + _ "cosmossdk.io/x/consensus" + _ "cosmossdk.io/x/distribution" // import as blank for app wiring + distrkeeper "cosmossdk.io/x/distribution/keeper" + _ "cosmossdk.io/x/staking" // import as blank for app wiring + stakingkeeper "cosmossdk.io/x/staking/keeper" + + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + "github.com/cosmos/cosmos-sdk/tests/integration/v2" + "github.com/cosmos/cosmos-sdk/testutil/configurator" + sdk "github.com/cosmos/cosmos-sdk/types" + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + _ "github.com/cosmos/cosmos-sdk/x/auth/tx/config" // import as blank for app wiring`` + _ "github.com/cosmos/cosmos-sdk/x/auth/vesting" // import as blank for app wiring + _ "github.com/cosmos/cosmos-sdk/x/genutil" // import as blank for app wiring +) + +type IntegrationTestSuite struct { + suite.Suite + + app *integration.App + ctx context.Context + + members []sdk.AccAddress + membersAddr []string + + authKeeper authkeeper.AccountKeeper + accountsKeeper accounts.Keeper + bankKeeper bankkeeper.BaseKeeper + stakingKeeper *stakingkeeper.Keeper + distrKeeper distrkeeper.Keeper +} + +func NewIntegrationTestSuite() *IntegrationTestSuite { + return &IntegrationTestSuite{} +} + +func (s *IntegrationTestSuite) SetupSuite() { + moduleConfigs := []configurator.ModuleOption{ + configurator.AccountsModule(), + configurator.AuthModule(), + configurator.BankModule(), + configurator.VestingModule(), + configurator.StakingModule(), + configurator.TxModule(), + configurator.ValidateModule(), + configurator.ConsensusModule(), + configurator.GenutilModule(), + configurator.DistributionModule(), + } + + var err error + startupCfg := integration.DefaultStartUpConfig(s.T()) + + msgRouterService := integration.NewRouterService() + s.registerMsgRouterService(msgRouterService) + + var routerFactory runtime.RouterServiceFactory = func(_ []byte) router.Service { + return msgRouterService + } + + queryRouterService := integration.NewRouterService() + s.registerQueryRouterService(queryRouterService) + + serviceBuilder := runtime.NewRouterBuilder(routerFactory, queryRouterService) + + startupCfg.BranchService = &integration.BranchService{} + startupCfg.RouterServiceBuilder = serviceBuilder + startupCfg.HeaderService = &integration.HeaderService{} + startupCfg.GasService = &integration.GasService{} + + s.app, err = integration.NewApp( + depinject.Configs(configurator.NewAppV2Config(moduleConfigs...), depinject.Provide( + // inject desired account types: + basedepinject.ProvideAccount, + + // provide base account options + basedepinject.ProvideSecp256K1PubKey, + + // inject desired account types: + multisigdepinject.ProvideAccount, + ), depinject.Supply(log.NewNopLogger())), + startupCfg, + &s.bankKeeper, &s.accountsKeeper, &s.authKeeper, &s.stakingKeeper, &s.distrKeeper) + require.NoError(s.T(), err) + + s.ctx = s.app.StateLatestContext(s.T()) + + s.members = []sdk.AccAddress{} + for i := 0; i < 10; i++ { + addr := secp256k1.GenPrivKey().PubKey().Address() + addrStr, err := s.authKeeper.AddressCodec().BytesToString(addr) + require.NoError(s.T(), err) + s.membersAddr = append(s.membersAddr, addrStr) + s.members = append(s.members, sdk.AccAddress(addr)) + } +} + +func (s *IntegrationTestSuite) registerMsgRouterService(router *integration.RouterService) { + // register custom router service + bankSendHandler := func(ctx context.Context, req transaction.Msg) (transaction.Msg, error) { + msg, ok := req.(*banktypes.MsgSend) + if !ok { + return nil, integration.ErrInvalidMsgType + } + msgServer := bankkeeper.NewMsgServerImpl(s.bankKeeper) + resp, err := msgServer.Send(ctx, msg) + return resp, err + } + + // register custom router service + accountsExeccHandler := func(ctx context.Context, req transaction.Msg) (transaction.Msg, error) { + msg, ok := req.(*accountsv1.MsgExecute) + if !ok { + return nil, integration.ErrInvalidMsgType + } + msgServer := accounts.NewMsgServer(s.accountsKeeper) + resp, err := msgServer.Execute(ctx, msg) + return resp, err + } + + router.RegisterHandler(bankSendHandler, "cosmos.bank.v1beta1.MsgSend") + router.RegisterHandler(accountsExeccHandler, "cosmos.accounts.v1.MsgExecute") +} + +func (s *IntegrationTestSuite) registerQueryRouterService(router *integration.RouterService) { + // register custom router service + bankBalanceQueryHandler := func(ctx context.Context, msg transaction.Msg) (transaction.Msg, error) { + req, ok := msg.(*banktypes.QueryBalanceRequest) + if !ok { + return nil, integration.ErrInvalidMsgType + } + qs := bankkeeper.NewQuerier(&s.bankKeeper) + resp, err := qs.Balance(ctx, req) + return resp, err + } + + router.RegisterHandler(bankBalanceQueryHandler, "cosmos.bank.v1beta1.QueryBalanceRequest") +} + +func (s *IntegrationTestSuite) TearDownSuite() {} + +func (s *IntegrationTestSuite) executeTx(ctx context.Context, msg sdk.Msg, accAddr, sender []byte) error { + _, err := s.accountsKeeper.Execute(ctx, accAddr, sender, msg, nil) + return err +} + +func (s *IntegrationTestSuite) queryAcc(ctx context.Context, req sdk.Msg, accAddr []byte) (transaction.Msg, error) { + resp, err := s.accountsKeeper.Query(ctx, accAddr, req) + return resp, err +} + +func (s *IntegrationTestSuite) fundAccount(ctx context.Context, addr sdk.AccAddress, amt sdk.Coins) { + require.NoError(s.T(), testutil.FundAccount(ctx, s.bankKeeper, addr, amt)) +} + +// initAccount initializes a multisig account with the given members and powers +// and returns the account address +func (s *IntegrationTestSuite) initAccount(ctx context.Context, sender []byte, membersPowers map[string]uint64) ([]byte, string) { + s.fundAccount(ctx, sender, sdk.Coins{sdk.NewCoin("stake", math.NewInt(1000000))}) + + members := []*v1.Member{} + for addrStr, power := range membersPowers { + members = append(members, &v1.Member{Address: addrStr, Weight: power}) + } + + _, accountAddr, err := s.accountsKeeper.Init(ctx, "multisig", sender, + &v1.MsgInit{ + Members: members, + Config: &v1.Config{ + Threshold: 100, + Quorum: 100, + VotingPeriod: 120, + Revote: false, + EarlyExecution: true, + }, + }, sdk.Coins{sdk.NewCoin("stake", math.NewInt(1000))}, nil) + s.NoError(err) + + accountAddrStr, err := s.authKeeper.AddressCodec().BytesToString(accountAddr) + s.NoError(err) + + return accountAddr, accountAddrStr +} + +// createProposal +func (s *IntegrationTestSuite) createProposal(ctx context.Context, accAddr, sender []byte, msgs ...*codectypes.Any) { + propReq := &v1.MsgCreateProposal{ + Proposal: &v1.Proposal{ + Title: "test", + Summary: "test", + Messages: msgs, + }, + } + err := s.executeTx(ctx, propReq, accAddr, sender) + s.NoError(err) +} + +func (s *IntegrationTestSuite) executeProposal(ctx context.Context, accAddr, sender []byte, proposalID uint64) error { + execReq := &v1.MsgExecuteProposal{ + ProposalId: proposalID, + } + return s.executeTx(ctx, execReq, accAddr, sender) +} diff --git a/tests/integration/v2/services.go b/tests/integration/v2/services.go index f8c27ff12666..a4e193f2d5e8 100644 --- a/tests/integration/v2/services.go +++ b/tests/integration/v2/services.go @@ -126,6 +126,20 @@ func GetAttributes(e []event.Event, key string) ([]event.Attribute, bool) { return attrs, len(attrs) > 0 } +func GetAttribute(e event.Event, key string) (event.Attribute, bool) { + attributes, err := e.Attributes() + if err != nil { + return event.Attribute{}, false + } + for _, attr := range attributes { + if attr.Key == key { + return attr, true + } + } + + return event.Attribute{}, false +} + func GasMeterFromContext(ctx context.Context) gas.Meter { iCtx, ok := ctx.Value(contextKey).(*integrationContext) if !ok { From b8a64bc47a6ab1af3f5454d4e1b9787b4e2dcfa5 Mon Sep 17 00:00:00 2001 From: sontrinh16 Date: Tue, 17 Dec 2024 15:29:43 +0700 Subject: [PATCH 2/4] remove v1 tests --- .../lockup/continous_lockup_test_suite.go | 203 -------------- .../lockup/delayed_lockup_test_suite.go | 172 ------------ .../accounts/lockup/lockup_account_test.go | 11 - .../lockup/periodic_lockup_test_suite.go | 223 --------------- .../lockup/permanent_lockup_test_suite.go | 132 --------- tests/integration/accounts/lockup/utils.go | 72 ----- .../accounts/multisig/account_test.go | 265 ------------------ .../accounts/multisig/test_suite.go | 115 -------- 8 files changed, 1193 deletions(-) delete mode 100644 tests/integration/accounts/lockup/continous_lockup_test_suite.go delete mode 100644 tests/integration/accounts/lockup/delayed_lockup_test_suite.go delete mode 100644 tests/integration/accounts/lockup/lockup_account_test.go delete mode 100644 tests/integration/accounts/lockup/periodic_lockup_test_suite.go delete mode 100644 tests/integration/accounts/lockup/permanent_lockup_test_suite.go delete mode 100644 tests/integration/accounts/lockup/utils.go delete mode 100644 tests/integration/accounts/multisig/account_test.go delete mode 100644 tests/integration/accounts/multisig/test_suite.go diff --git a/tests/integration/accounts/lockup/continous_lockup_test_suite.go b/tests/integration/accounts/lockup/continous_lockup_test_suite.go deleted file mode 100644 index 2fbc794edee9..000000000000 --- a/tests/integration/accounts/lockup/continous_lockup_test_suite.go +++ /dev/null @@ -1,203 +0,0 @@ -package lockup - -import ( - "testing" - "time" - - "github.com/stretchr/testify/require" - - "cosmossdk.io/collections" - "cosmossdk.io/core/header" - "cosmossdk.io/math" - lockupaccount "cosmossdk.io/x/accounts/defaults/lockup" - types "cosmossdk.io/x/accounts/defaults/lockup/v1" - - "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" - sdk "github.com/cosmos/cosmos-sdk/types" -) - -func (s *IntegrationTestSuite) TestContinuousLockingAccount() { - t := s.T() - app := setupApp(t) - currentTime := time.Now() - ctx := sdk.NewContext(app.CommitMultiStore(), false, app.Logger()).WithHeaderInfo(header.Info{ - Time: currentTime, - }) - ownerAddrStr, err := app.AuthKeeper.AddressCodec().BytesToString(accOwner) - require.NoError(t, err) - s.fundAccount(app, ctx, accOwner, sdk.Coins{sdk.NewCoin("stake", math.NewInt(1000000))}) - randAcc := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) - withdrawAcc := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) - - _, accountAddr, err := app.AccountsKeeper.Init(ctx, lockupaccount.CONTINUOUS_LOCKING_ACCOUNT, accOwner, &types.MsgInitLockupAccount{ - Owner: ownerAddrStr, - StartTime: currentTime, - // end time in 1 minutes - EndTime: currentTime.Add(time.Minute), - }, sdk.Coins{sdk.NewCoin("stake", math.NewInt(1000))}, nil) - require.NoError(t, err) - - addr, err := app.AuthKeeper.AddressCodec().BytesToString(randAcc) - require.NoError(t, err) - - vals, err := app.StakingKeeper.GetAllValidators(ctx) - require.NoError(t, err) - val := vals[0] - - t.Run("error - execute message, wrong sender", func(t *testing.T) { - msg := &types.MsgSend{ - Sender: addr, - ToAddress: addr, - Amount: sdk.Coins{sdk.NewCoin("stake", math.NewInt(100))}, - } - err := s.executeTx(ctx, msg, app, accountAddr, accOwner) - require.NotNil(t, err) - }) - t.Run("error - execute send message, insufficient fund", func(t *testing.T) { - msg := &types.MsgSend{ - Sender: ownerAddrStr, - ToAddress: addr, - Amount: sdk.Coins{sdk.NewCoin("stake", math.NewInt(100))}, - } - err := s.executeTx(ctx, msg, app, accountAddr, accOwner) - require.NotNil(t, err) - }) - t.Run("error - execute withdraw message, no withdrawable token", func(t *testing.T) { - ownerAddr, err := app.AuthKeeper.AddressCodec().BytesToString(accOwner) - require.NoError(t, err) - withdrawAddr, err := app.AuthKeeper.AddressCodec().BytesToString(withdrawAcc) - require.NoError(t, err) - msg := &types.MsgWithdraw{ - Withdrawer: ownerAddr, - ToAddress: withdrawAddr, - Denoms: []string{"stake"}, - } - err = s.executeTx(ctx, msg, app, accountAddr, accOwner) - require.NotNil(t, err) - }) - - // Update context time - // 12 sec = 1/5 of a minute so 200stake should be released - ctx = ctx.WithHeaderInfo(header.Info{ - Time: currentTime.Add(time.Second * 12), - }) - - // Check if token is sendable - t.Run("ok - execute send message", func(t *testing.T) { - msg := &types.MsgSend{ - Sender: ownerAddrStr, - ToAddress: addr, - Amount: sdk.Coins{sdk.NewCoin("stake", math.NewInt(100))}, - } - err := s.executeTx(ctx, msg, app, accountAddr, accOwner) - require.NoError(t, err) - - balance := app.BankKeeper.GetBalance(ctx, randAcc, "stake") - require.True(t, balance.Amount.Equal(math.NewInt(100))) - }) - t.Run("ok - execute withdraw message", func(t *testing.T) { - ownerAddr, err := app.AuthKeeper.AddressCodec().BytesToString(accOwner) - require.NoError(t, err) - withdrawAddr, err := app.AuthKeeper.AddressCodec().BytesToString(withdrawAcc) - require.NoError(t, err) - msg := &types.MsgWithdraw{ - Withdrawer: ownerAddr, - ToAddress: withdrawAddr, - Denoms: []string{"stake"}, - } - err = s.executeTx(ctx, msg, app, accountAddr, accOwner) - require.NoError(t, err) - - // withdrawable amount should be 200 - 100 = 100stake - balance := app.BankKeeper.GetBalance(ctx, withdrawAcc, "stake") - require.True(t, balance.Amount.Equal(math.NewInt(100))) - }) - t.Run("ok - execute delegate message", func(t *testing.T) { - msg := &types.MsgDelegate{ - Sender: ownerAddrStr, - ValidatorAddress: val.OperatorAddress, - Amount: sdk.NewCoin("stake", math.NewInt(100)), - } - err = s.executeTx(ctx, msg, app, accountAddr, accOwner) - require.NoError(t, err) - - valbz, err := app.StakingKeeper.ValidatorAddressCodec().StringToBytes(val.OperatorAddress) - require.NoError(t, err) - - del, err := app.StakingKeeper.Delegations.Get( - ctx, collections.Join(sdk.AccAddress(accountAddr), sdk.ValAddress(valbz)), - ) - require.NoError(t, err) - require.NotNil(t, del) - - // check if tracking is updated accordingly - lockupAccountInfoResponse := s.queryLockupAccInfo(ctx, app, accountAddr) - delLocking := lockupAccountInfoResponse.DelegatedLocking - require.True(t, delLocking.AmountOf("stake").Equal(math.NewInt(100))) - }) - t.Run("ok - execute withdraw reward message", func(t *testing.T) { - msg := &types.MsgWithdrawReward{ - Sender: ownerAddrStr, - ValidatorAddress: val.OperatorAddress, - } - err = s.executeTx(ctx, msg, app, accountAddr, accOwner) - require.NoError(t, err) - }) - t.Run("ok - execute undelegate message", func(t *testing.T) { - vals, err := app.StakingKeeper.GetAllValidators(ctx) - require.NoError(t, err) - val := vals[0] - msg := &types.MsgUndelegate{ - Sender: ownerAddrStr, - ValidatorAddress: val.OperatorAddress, - Amount: sdk.NewCoin("stake", math.NewInt(100)), - } - err = s.executeTx(ctx, msg, app, accountAddr, accOwner) - require.NoError(t, err) - valbz, err := app.StakingKeeper.ValidatorAddressCodec().StringToBytes(val.OperatorAddress) - require.NoError(t, err) - - ubd, err := app.StakingKeeper.GetUnbondingDelegation( - ctx, sdk.AccAddress(accountAddr), sdk.ValAddress(valbz), - ) - require.NoError(t, err) - require.Equal(t, len(ubd.Entries), 1) - - // check if tracking is updated accordingly - lockupAccountInfoResponse := s.queryLockupAccInfo(ctx, app, accountAddr) - delLocking := lockupAccountInfoResponse.DelegatedLocking - require.True(t, delLocking.AmountOf("stake").Equal(math.ZeroInt())) - }) - - // Update context time to end time - ctx = ctx.WithHeaderInfo(header.Info{ - Time: currentTime.Add(time.Minute), - }) - - // test if tracking delegate work perfectly - t.Run("ok - execute delegate message", func(t *testing.T) { - msg := &types.MsgDelegate{ - Sender: ownerAddrStr, - ValidatorAddress: val.OperatorAddress, - Amount: sdk.NewCoin("stake", math.NewInt(100)), - } - err = s.executeTx(ctx, msg, app, accountAddr, accOwner) - require.NoError(t, err) - - valbz, err := app.StakingKeeper.ValidatorAddressCodec().StringToBytes(val.OperatorAddress) - require.NoError(t, err) - - del, err := app.StakingKeeper.Delegations.Get( - ctx, collections.Join(sdk.AccAddress(accountAddr), sdk.ValAddress(valbz)), - ) - require.NoError(t, err) - require.NotNil(t, del) - - // check if tracking is updated accordingly - lockupAccountInfoResponse := s.queryLockupAccInfo(ctx, app, accountAddr) - delLocking := lockupAccountInfoResponse.DelegatedLocking - require.True(t, delLocking.AmountOf("stake").Equal(math.ZeroInt())) - delFree := lockupAccountInfoResponse.DelegatedFree - require.True(t, delFree.AmountOf("stake").Equal(math.NewInt(100))) - }) -} diff --git a/tests/integration/accounts/lockup/delayed_lockup_test_suite.go b/tests/integration/accounts/lockup/delayed_lockup_test_suite.go deleted file mode 100644 index ff1131403fb8..000000000000 --- a/tests/integration/accounts/lockup/delayed_lockup_test_suite.go +++ /dev/null @@ -1,172 +0,0 @@ -package lockup - -import ( - "testing" - "time" - - "github.com/stretchr/testify/require" - - "cosmossdk.io/collections" - "cosmossdk.io/core/header" - "cosmossdk.io/math" - lockupaccount "cosmossdk.io/x/accounts/defaults/lockup" - types "cosmossdk.io/x/accounts/defaults/lockup/v1" - - "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" - sdk "github.com/cosmos/cosmos-sdk/types" -) - -func (s *IntegrationTestSuite) TestDelayedLockingAccount() { - t := s.T() - app := setupApp(t) - currentTime := time.Now() - ctx := sdk.NewContext(app.CommitMultiStore(), false, app.Logger()).WithHeaderInfo(header.Info{ - Time: currentTime, - }) - ownerAddrStr, err := app.AuthKeeper.AddressCodec().BytesToString(accOwner) - require.NoError(t, err) - s.fundAccount(app, ctx, accOwner, sdk.Coins{sdk.NewCoin("stake", math.NewInt(1000000))}) - randAcc := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) - withdrawAcc := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) - - _, accountAddr, err := app.AccountsKeeper.Init(ctx, lockupaccount.DELAYED_LOCKING_ACCOUNT, accOwner, &types.MsgInitLockupAccount{ - Owner: ownerAddrStr, - // end time in 1 minutes - EndTime: currentTime.Add(time.Minute), - }, sdk.Coins{sdk.NewCoin("stake", math.NewInt(1000))}, nil) - require.NoError(t, err) - - addr, err := app.AuthKeeper.AddressCodec().BytesToString(randAcc) - require.NoError(t, err) - - vals, err := app.StakingKeeper.GetAllValidators(ctx) - require.NoError(t, err) - val := vals[0] - - t.Run("error - execute message, wrong sender", func(t *testing.T) { - msg := &types.MsgSend{ - Sender: addr, - ToAddress: addr, - Amount: sdk.Coins{sdk.NewCoin("stake", math.NewInt(100))}, - } - err := s.executeTx(ctx, msg, app, accountAddr, accOwner) - require.NotNil(t, err) - }) - t.Run("error - execute send message, insufficient fund", func(t *testing.T) { - msg := &types.MsgSend{ - Sender: ownerAddrStr, - ToAddress: addr, - Amount: sdk.Coins{sdk.NewCoin("stake", math.NewInt(100))}, - } - err := s.executeTx(ctx, msg, app, accountAddr, accOwner) - require.NotNil(t, err) - }) - t.Run("error - execute withdraw message, no withdrawable token", func(t *testing.T) { - ownerAddr, err := app.AuthKeeper.AddressCodec().BytesToString(accOwner) - require.NoError(t, err) - withdrawAddr, err := app.AuthKeeper.AddressCodec().BytesToString(withdrawAcc) - require.NoError(t, err) - msg := &types.MsgWithdraw{ - Withdrawer: ownerAddr, - ToAddress: withdrawAddr, - Denoms: []string{"stake"}, - } - err = s.executeTx(ctx, msg, app, accountAddr, accOwner) - require.NotNil(t, err) - }) - t.Run("ok - execute delegate message", func(t *testing.T) { - msg := &types.MsgDelegate{ - Sender: ownerAddrStr, - ValidatorAddress: val.OperatorAddress, - Amount: sdk.NewCoin("stake", math.NewInt(100)), - } - err = s.executeTx(ctx, msg, app, accountAddr, accOwner) - require.NoError(t, err) - - valbz, err := app.StakingKeeper.ValidatorAddressCodec().StringToBytes(val.OperatorAddress) - require.NoError(t, err) - - del, err := app.StakingKeeper.Delegations.Get( - ctx, collections.Join(sdk.AccAddress(accountAddr), sdk.ValAddress(valbz)), - ) - require.NoError(t, err) - require.NotNil(t, del) - - // check if tracking is updated accordingly - lockupAccountInfoResponse := s.queryLockupAccInfo(ctx, app, accountAddr) - delLocking := lockupAccountInfoResponse.DelegatedLocking - require.True(t, delLocking.AmountOf("stake").Equal(math.NewInt(100))) - }) - t.Run("ok - execute withdraw reward message", func(t *testing.T) { - msg := &types.MsgWithdrawReward{ - Sender: ownerAddrStr, - ValidatorAddress: val.OperatorAddress, - } - err = s.executeTx(ctx, msg, app, accountAddr, accOwner) - require.NoError(t, err) - }) - t.Run("ok - execute undelegate message", func(t *testing.T) { - vals, err := app.StakingKeeper.GetAllValidators(ctx) - require.NoError(t, err) - val := vals[0] - msg := &types.MsgUndelegate{ - Sender: ownerAddrStr, - ValidatorAddress: val.OperatorAddress, - Amount: sdk.NewCoin("stake", math.NewInt(100)), - } - err = s.executeTx(ctx, msg, app, accountAddr, accOwner) - require.NoError(t, err) - valbz, err := app.StakingKeeper.ValidatorAddressCodec().StringToBytes(val.OperatorAddress) - require.NoError(t, err) - - ubd, err := app.StakingKeeper.GetUnbondingDelegation( - ctx, sdk.AccAddress(accountAddr), sdk.ValAddress(valbz), - ) - require.NoError(t, err) - require.Equal(t, len(ubd.Entries), 1) - - // check if tracking is updated accordingly - lockupAccountInfoResponse := s.queryLockupAccInfo(ctx, app, accountAddr) - delLocking := lockupAccountInfoResponse.DelegatedLocking - require.True(t, delLocking.AmountOf("stake").Equal(math.ZeroInt())) - }) - - // Update context time - // After endtime fund should be unlock - ctx = ctx.WithHeaderInfo(header.Info{ - Time: currentTime.Add(time.Second * 61), - }) - - // Check if token is sendable after unlock - t.Run("ok - execute send message", func(t *testing.T) { - msg := &types.MsgSend{ - Sender: ownerAddrStr, - ToAddress: addr, - Amount: sdk.Coins{sdk.NewCoin("stake", math.NewInt(100))}, - } - err := s.executeTx(ctx, msg, app, accountAddr, accOwner) - require.NoError(t, err) - - balance := app.BankKeeper.GetBalance(ctx, randAcc, "stake") - require.True(t, balance.Amount.Equal(math.NewInt(100))) - }) - // Test to withdraw all the remain funds to an account of choice - t.Run("ok - execute withdraw message", func(t *testing.T) { - ownerAddr, err := app.AuthKeeper.AddressCodec().BytesToString(accOwner) - require.NoError(t, err) - withdrawAddr, err := app.AuthKeeper.AddressCodec().BytesToString(withdrawAcc) - require.NoError(t, err) - msg := &types.MsgWithdraw{ - Withdrawer: ownerAddr, - ToAddress: withdrawAddr, - Denoms: []string{"stake"}, - } - err = s.executeTx(ctx, msg, app, accountAddr, accOwner) - require.NoError(t, err) - - // withdrawable amount should be - // 1000stake - 100stake( above sent amt ) - 100stake(above delegate amt) = 800stake - balance := app.BankKeeper.GetBalance(ctx, withdrawAcc, "stake") - require.True(t, balance.Amount.Equal(math.NewInt(800))) - }) -} diff --git a/tests/integration/accounts/lockup/lockup_account_test.go b/tests/integration/accounts/lockup/lockup_account_test.go deleted file mode 100644 index c8f409d7985e..000000000000 --- a/tests/integration/accounts/lockup/lockup_account_test.go +++ /dev/null @@ -1,11 +0,0 @@ -package lockup - -import ( - "testing" - - "github.com/stretchr/testify/suite" -) - -func TestIntegrationTestSuite(t *testing.T) { - suite.Run(t, NewIntegrationTestSuite()) -} diff --git a/tests/integration/accounts/lockup/periodic_lockup_test_suite.go b/tests/integration/accounts/lockup/periodic_lockup_test_suite.go deleted file mode 100644 index 3924012d52d6..000000000000 --- a/tests/integration/accounts/lockup/periodic_lockup_test_suite.go +++ /dev/null @@ -1,223 +0,0 @@ -package lockup - -import ( - "testing" - "time" - - "github.com/stretchr/testify/require" - - "cosmossdk.io/collections" - "cosmossdk.io/core/header" - "cosmossdk.io/math" - lockupaccount "cosmossdk.io/x/accounts/defaults/lockup" - types "cosmossdk.io/x/accounts/defaults/lockup/v1" - - "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" - sdk "github.com/cosmos/cosmos-sdk/types" -) - -func (s *IntegrationTestSuite) TestPeriodicLockingAccount() { - t := s.T() - app := setupApp(t) - currentTime := time.Now() - ctx := sdk.NewContext(app.CommitMultiStore(), false, app.Logger()).WithHeaderInfo(header.Info{ - Time: currentTime, - }) - ownerAddrStr, err := app.AuthKeeper.AddressCodec().BytesToString(accOwner) - require.NoError(t, err) - s.fundAccount(app, ctx, accOwner, sdk.Coins{sdk.NewCoin("stake", math.NewInt(1000000))}) - randAcc := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) - withdrawAcc := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) - - _, accountAddr, err := app.AccountsKeeper.Init(ctx, lockupaccount.PERIODIC_LOCKING_ACCOUNT, accOwner, &types.MsgInitPeriodicLockingAccount{ - Owner: ownerAddrStr, - StartTime: currentTime, - LockingPeriods: []types.Period{ - { - Amount: sdk.NewCoins(sdk.NewCoin("stake", math.NewInt(500))), - Length: time.Minute, - }, - { - Amount: sdk.NewCoins(sdk.NewCoin("stake", math.NewInt(500))), - Length: time.Minute, - }, - { - Amount: sdk.NewCoins(sdk.NewCoin("stake", math.NewInt(500))), - Length: time.Minute, - }, - }, - }, sdk.Coins{sdk.NewCoin("stake", math.NewInt(1500))}, nil) - require.NoError(t, err) - - addr, err := app.AuthKeeper.AddressCodec().BytesToString(randAcc) - require.NoError(t, err) - - vals, err := app.StakingKeeper.GetAllValidators(ctx) - require.NoError(t, err) - val := vals[0] - - t.Run("error - execute message, wrong sender", func(t *testing.T) { - msg := &types.MsgSend{ - Sender: addr, - ToAddress: addr, - Amount: sdk.Coins{sdk.NewCoin("stake", math.NewInt(100))}, - } - err := s.executeTx(ctx, msg, app, accountAddr, accOwner) - require.NotNil(t, err) - }) - // No token being unlocked yet - t.Run("error - execute send message, insufficient fund", func(t *testing.T) { - msg := &types.MsgSend{ - Sender: ownerAddrStr, - ToAddress: addr, - Amount: sdk.Coins{sdk.NewCoin("stake", math.NewInt(100))}, - } - err := s.executeTx(ctx, msg, app, accountAddr, accOwner) - require.NotNil(t, err) - }) - t.Run("error - execute withdraw message, no withdrawable token", func(t *testing.T) { - ownerAddr, err := app.AuthKeeper.AddressCodec().BytesToString(accOwner) - require.NoError(t, err) - withdrawAddr, err := app.AuthKeeper.AddressCodec().BytesToString(withdrawAcc) - require.NoError(t, err) - msg := &types.MsgWithdraw{ - Withdrawer: ownerAddr, - ToAddress: withdrawAddr, - Denoms: []string{"stake"}, - } - err = s.executeTx(ctx, msg, app, accountAddr, accOwner) - require.NotNil(t, err) - }) - - // Update context time - // After first period 500stake should be unlock - ctx = ctx.WithHeaderInfo(header.Info{ - Time: currentTime.Add(time.Minute), - }) - - // Check if 500 stake is sendable now - t.Run("ok - execute send message", func(t *testing.T) { - msg := &types.MsgSend{ - Sender: ownerAddrStr, - ToAddress: addr, - Amount: sdk.Coins{sdk.NewCoin("stake", math.NewInt(500))}, - } - err := s.executeTx(ctx, msg, app, accountAddr, accOwner) - require.NoError(t, err) - - balance := app.BankKeeper.GetBalance(ctx, randAcc, "stake") - require.True(t, balance.Amount.Equal(math.NewInt(500))) - }) - - // Update context time - // After second period 1000stake should be unlock - ctx = ctx.WithHeaderInfo(header.Info{ - Time: currentTime.Add(time.Minute * 2), - }) - - t.Run("oke - execute withdraw message", func(t *testing.T) { - ownerAddr, err := app.AuthKeeper.AddressCodec().BytesToString(accOwner) - require.NoError(t, err) - withdrawAddr, err := app.AuthKeeper.AddressCodec().BytesToString(withdrawAcc) - require.NoError(t, err) - msg := &types.MsgWithdraw{ - Withdrawer: ownerAddr, - ToAddress: withdrawAddr, - Denoms: []string{"stake"}, - } - err = s.executeTx(ctx, msg, app, accountAddr, accOwner) - require.NoError(t, err) - - // withdrawable amount should be - // 1000stake - 500stake( above sent amt ) = 500stake - balance := app.BankKeeper.GetBalance(ctx, withdrawAcc, "stake") - require.True(t, balance.Amount.Equal(math.NewInt(500))) - }) - - t.Run("ok - execute delegate message", func(t *testing.T) { - msg := &types.MsgDelegate{ - Sender: ownerAddrStr, - ValidatorAddress: val.OperatorAddress, - Amount: sdk.NewCoin("stake", math.NewInt(100)), - } - err = s.executeTx(ctx, msg, app, accountAddr, accOwner) - require.NoError(t, err) - - valbz, err := app.StakingKeeper.ValidatorAddressCodec().StringToBytes(val.OperatorAddress) - require.NoError(t, err) - - del, err := app.StakingKeeper.Delegations.Get( - ctx, collections.Join(sdk.AccAddress(accountAddr), sdk.ValAddress(valbz)), - ) - require.NoError(t, err) - require.NotNil(t, del) - - // check if tracking is updated accordingly - lockupAccountInfoResponse := s.queryLockupAccInfo(ctx, app, accountAddr) - delLocking := lockupAccountInfoResponse.DelegatedLocking - require.True(t, delLocking.AmountOf("stake").Equal(math.NewInt(100))) - }) - t.Run("ok - execute withdraw reward message", func(t *testing.T) { - msg := &types.MsgWithdrawReward{ - Sender: ownerAddrStr, - ValidatorAddress: val.OperatorAddress, - } - err = s.executeTx(ctx, msg, app, accountAddr, accOwner) - require.NoError(t, err) - }) - t.Run("ok - execute undelegate message", func(t *testing.T) { - vals, err := app.StakingKeeper.GetAllValidators(ctx) - require.NoError(t, err) - val := vals[0] - msg := &types.MsgUndelegate{ - Sender: ownerAddrStr, - ValidatorAddress: val.OperatorAddress, - Amount: sdk.NewCoin("stake", math.NewInt(100)), - } - err = s.executeTx(ctx, msg, app, accountAddr, accOwner) - require.NoError(t, err) - valbz, err := app.StakingKeeper.ValidatorAddressCodec().StringToBytes(val.OperatorAddress) - require.NoError(t, err) - - ubd, err := app.StakingKeeper.GetUnbondingDelegation( - ctx, sdk.AccAddress(accountAddr), sdk.ValAddress(valbz), - ) - require.NoError(t, err) - require.Equal(t, len(ubd.Entries), 1) - - // check if tracking is updated accordingly - lockupAccountInfoResponse := s.queryLockupAccInfo(ctx, app, accountAddr) - delLocking := lockupAccountInfoResponse.DelegatedLocking - require.True(t, delLocking.AmountOf("stake").Equal(math.ZeroInt())) - }) - - // Update context time - // After third period 1500stake should be unlock - ctx = ctx.WithHeaderInfo(header.Info{ - Time: currentTime.Add(time.Minute * 3), - }) - - t.Run("ok - execute delegate message", func(t *testing.T) { - msg := &types.MsgDelegate{ - Sender: ownerAddrStr, - ValidatorAddress: val.OperatorAddress, - Amount: sdk.NewCoin("stake", math.NewInt(100)), - } - err = s.executeTx(ctx, msg, app, accountAddr, accOwner) - require.NoError(t, err) - - valbz, err := app.StakingKeeper.ValidatorAddressCodec().StringToBytes(val.OperatorAddress) - require.NoError(t, err) - - del, err := app.StakingKeeper.Delegations.Get( - ctx, collections.Join(sdk.AccAddress(accountAddr), sdk.ValAddress(valbz)), - ) - require.NoError(t, err) - require.NotNil(t, del) - - // check if tracking is updated accordingly - lockupAccountInfoResponse := s.queryLockupAccInfo(ctx, app, accountAddr) - delFree := lockupAccountInfoResponse.DelegatedFree - require.True(t, delFree.AmountOf("stake").Equal(math.NewInt(100))) - }) -} diff --git a/tests/integration/accounts/lockup/permanent_lockup_test_suite.go b/tests/integration/accounts/lockup/permanent_lockup_test_suite.go deleted file mode 100644 index 1505dbac0c17..000000000000 --- a/tests/integration/accounts/lockup/permanent_lockup_test_suite.go +++ /dev/null @@ -1,132 +0,0 @@ -package lockup - -import ( - "testing" - "time" - - "github.com/stretchr/testify/require" - - "cosmossdk.io/collections" - "cosmossdk.io/core/header" - "cosmossdk.io/math" - lockupaccount "cosmossdk.io/x/accounts/defaults/lockup" - types "cosmossdk.io/x/accounts/defaults/lockup/v1" - - "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" - sdk "github.com/cosmos/cosmos-sdk/types" -) - -func (s *IntegrationTestSuite) TestPermanentLockingAccount() { - t := s.T() - app := setupApp(t) - currentTime := time.Now() - ctx := sdk.NewContext(app.CommitMultiStore(), false, app.Logger()).WithHeaderInfo(header.Info{ - Time: currentTime, - }) - ownerAddrStr, err := app.AuthKeeper.AddressCodec().BytesToString(accOwner) - require.NoError(t, err) - s.fundAccount(app, ctx, accOwner, sdk.Coins{sdk.NewCoin("stake", math.NewInt(1000000))}) - randAcc := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) - - _, accountAddr, err := app.AccountsKeeper.Init(ctx, lockupaccount.PERMANENT_LOCKING_ACCOUNT, accOwner, &types.MsgInitLockupAccount{ - Owner: ownerAddrStr, - }, sdk.Coins{sdk.NewCoin("stake", math.NewInt(1000))}, nil) - require.NoError(t, err) - - addr, err := app.AuthKeeper.AddressCodec().BytesToString(randAcc) - require.NoError(t, err) - - vals, err := app.StakingKeeper.GetAllValidators(ctx) - require.NoError(t, err) - val := vals[0] - - t.Run("error - execute message, wrong sender", func(t *testing.T) { - msg := &types.MsgSend{ - Sender: addr, - ToAddress: addr, - Amount: sdk.Coins{sdk.NewCoin("stake", math.NewInt(100))}, - } - err := s.executeTx(ctx, msg, app, accountAddr, accOwner) - require.NotNil(t, err) - }) - t.Run("error - execute send message, insufficient fund", func(t *testing.T) { - msg := &types.MsgSend{ - Sender: ownerAddrStr, - ToAddress: addr, - Amount: sdk.Coins{sdk.NewCoin("stake", math.NewInt(100))}, - } - err := s.executeTx(ctx, msg, app, accountAddr, accOwner) - require.NotNil(t, err) - }) - t.Run("ok - execute delegate message", func(t *testing.T) { - msg := &types.MsgDelegate{ - Sender: ownerAddrStr, - ValidatorAddress: val.OperatorAddress, - Amount: sdk.NewCoin("stake", math.NewInt(100)), - } - err = s.executeTx(ctx, msg, app, accountAddr, accOwner) - require.NoError(t, err) - - valbz, err := app.StakingKeeper.ValidatorAddressCodec().StringToBytes(val.OperatorAddress) - require.NoError(t, err) - - del, err := app.StakingKeeper.Delegations.Get( - ctx, collections.Join(sdk.AccAddress(accountAddr), sdk.ValAddress(valbz)), - ) - require.NoError(t, err) - require.NotNil(t, del) - - // check if tracking is updated accordingly - lockupAccountInfoResponse := s.queryLockupAccInfo(ctx, app, accountAddr) - delLocking := lockupAccountInfoResponse.DelegatedLocking - require.True(t, delLocking.AmountOf("stake").Equal(math.NewInt(100))) - }) - t.Run("ok - execute withdraw reward message", func(t *testing.T) { - msg := &types.MsgWithdrawReward{ - Sender: ownerAddrStr, - ValidatorAddress: val.OperatorAddress, - } - err = s.executeTx(ctx, msg, app, accountAddr, accOwner) - require.NoError(t, err) - }) - t.Run("ok - execute undelegate message", func(t *testing.T) { - vals, err := app.StakingKeeper.GetAllValidators(ctx) - require.NoError(t, err) - val := vals[0] - msg := &types.MsgUndelegate{ - Sender: ownerAddrStr, - ValidatorAddress: val.OperatorAddress, - Amount: sdk.NewCoin("stake", math.NewInt(100)), - } - err = s.executeTx(ctx, msg, app, accountAddr, accOwner) - require.NoError(t, err) - valbz, err := app.StakingKeeper.ValidatorAddressCodec().StringToBytes(val.OperatorAddress) - require.NoError(t, err) - - ubd, err := app.StakingKeeper.GetUnbondingDelegation( - ctx, sdk.AccAddress(accountAddr), sdk.ValAddress(valbz), - ) - require.NoError(t, err) - require.Equal(t, len(ubd.Entries), 1) - - // check if tracking is updated accordingly - lockupAccountInfoResponse := s.queryLockupAccInfo(ctx, app, accountAddr) - delLocking := lockupAccountInfoResponse.DelegatedLocking - require.True(t, delLocking.AmountOf("stake").Equal(math.ZeroInt())) - }) - - s.fundAccount(app, ctx, accountAddr, sdk.Coins{sdk.NewCoin("stake", math.NewInt(1000))}) - - t.Run("ok - execute send message", func(t *testing.T) { - msg := &types.MsgSend{ - Sender: ownerAddrStr, - ToAddress: addr, - Amount: sdk.Coins{sdk.NewCoin("stake", math.NewInt(100))}, - } - err := s.executeTx(ctx, msg, app, accountAddr, accOwner) - require.NoError(t, err) - - balance := app.BankKeeper.GetBalance(ctx, randAcc, "stake") - require.True(t, balance.Amount.Equal(math.NewInt(100))) - }) -} diff --git a/tests/integration/accounts/lockup/utils.go b/tests/integration/accounts/lockup/utils.go deleted file mode 100644 index a0ce8f4e0c23..000000000000 --- a/tests/integration/accounts/lockup/utils.go +++ /dev/null @@ -1,72 +0,0 @@ -package lockup - -import ( - "testing" - - "github.com/stretchr/testify/require" - "github.com/stretchr/testify/suite" - - "cosmossdk.io/core/transaction" - "cosmossdk.io/simapp" - types "cosmossdk.io/x/accounts/defaults/lockup/v1" - "cosmossdk.io/x/bank/testutil" - - "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" - sdk "github.com/cosmos/cosmos-sdk/types" -) - -var ( - ownerAddr = secp256k1.GenPrivKey().PubKey().Address() - accOwner = sdk.AccAddress(ownerAddr) -) - -type IntegrationTestSuite struct { - suite.Suite - - app *simapp.SimApp -} - -func NewIntegrationTestSuite() *IntegrationTestSuite { - return &IntegrationTestSuite{} -} - -func (s *IntegrationTestSuite) SetupSuite() { - s.T().Log("setting up integration test suite") - s.app = setupApp(s.T()) -} - -func (s *IntegrationTestSuite) TearDownSuite() { - s.T().Log("tearing down integration test suite") -} - -func setupApp(t *testing.T) *simapp.SimApp { - t.Helper() - app := simapp.Setup(t, false) - return app -} - -func (s *IntegrationTestSuite) executeTx(ctx sdk.Context, msg sdk.Msg, app *simapp.SimApp, accAddr, sender []byte) error { - _, err := app.AccountsKeeper.Execute(ctx, accAddr, sender, msg, nil) - return err -} - -func (s *IntegrationTestSuite) queryAcc(ctx sdk.Context, req sdk.Msg, app *simapp.SimApp, accAddr []byte) (transaction.Msg, error) { - resp, err := app.AccountsKeeper.Query(ctx, accAddr, req) - return resp, err -} - -func (s *IntegrationTestSuite) fundAccount(app *simapp.SimApp, ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) { - require.NoError(s.T(), testutil.FundAccount(ctx, app.BankKeeper, addr, amt)) -} - -func (s *IntegrationTestSuite) queryLockupAccInfo(ctx sdk.Context, app *simapp.SimApp, accAddr []byte) *types.QueryLockupAccountInfoResponse { - req := &types.QueryLockupAccountInfoRequest{} - resp, err := s.queryAcc(ctx, req, app, accAddr) - require.NoError(s.T(), err) - require.NotNil(s.T(), resp) - - lockupAccountInfoResponse, ok := resp.(*types.QueryLockupAccountInfoResponse) - require.True(s.T(), ok) - - return lockupAccountInfoResponse -} diff --git a/tests/integration/accounts/multisig/account_test.go b/tests/integration/accounts/multisig/account_test.go deleted file mode 100644 index 8e03674ec480..000000000000 --- a/tests/integration/accounts/multisig/account_test.go +++ /dev/null @@ -1,265 +0,0 @@ -package multisig - -import ( - "testing" - "time" - - "github.com/stretchr/testify/suite" - - bankv1beta1 "cosmossdk.io/api/cosmos/bank/v1beta1" - basev1beta1 "cosmossdk.io/api/cosmos/base/v1beta1" - "cosmossdk.io/core/header" - "cosmossdk.io/math" - v1 "cosmossdk.io/x/accounts/defaults/multisig/v1" - accountsv1 "cosmossdk.io/x/accounts/v1" - - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" - sdk "github.com/cosmos/cosmos-sdk/types" -) - -func TestIntegrationTestSuite(t *testing.T) { - suite.Run(t, NewIntegrationTestSuite()) -} - -// TestSimpleSendProposal creates a multisig account with 1 member, sends a tx, votes and executes it. -func (s *IntegrationTestSuite) TestSimpleSendProposal() { - ctx := sdk.NewContext(s.app.CommitMultiStore(), false, s.app.Logger()).WithHeaderInfo(header.Info{ - Time: time.Now(), - }) - - randAcc := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) - addr, err := s.app.AuthKeeper.AddressCodec().BytesToString(randAcc) - s.NoError(err) - - initialMembers := map[string]uint64{ - s.membersAddr[0]: 100, - } - accountAddr, accAddrStr := s.initAccount(ctx, s.members[0], initialMembers) - - balance := s.app.BankKeeper.GetBalance(ctx, randAcc, "stake") - s.Equal(math.NewInt(0), balance.Amount) - - // do a simple bank send - msg := &bankv1beta1.MsgSend{ - FromAddress: accAddrStr, - ToAddress: addr, - Amount: []*basev1beta1.Coin{ - { - Denom: "stake", - Amount: "100", - }, - }, - } - anyMsg, err := codectypes.NewAnyWithValue(msg) - s.NoError(err) - - s.createProposal(ctx, accountAddr, s.members[0], anyMsg) - - // now we vote for it - voteReq := &v1.MsgVote{ - ProposalId: 0, - Vote: v1.VoteOption_VOTE_OPTION_YES, - } - - err = s.executeTx(ctx, voteReq, accountAddr, s.members[0]) - s.NoError(err) - - // now we execute it - err = s.executeProposal(ctx, accountAddr, s.members[0], 0) - s.NoError(err) - - foundPropResult := false - for _, v := range ctx.EventManager().Events() { - if v.Type == "proposal_tally" { - foundPropResult = true - status, found := v.GetAttribute("status") - s.True(found) - s.Equal(v1.ProposalStatus_PROPOSAL_STATUS_PASSED.String(), status.Value) - - yesVotes, found := v.GetAttribute("yes_votes") - s.True(found) - s.Equal("100", yesVotes.Value) - - noVotes, found := v.GetAttribute("no_votes") - s.True(found) - s.Equal("0", noVotes.Value) - - propID, found := v.GetAttribute("proposal_id") - s.True(found) - s.Equal("0", propID.Value) - - execErr, found := v.GetAttribute("exec_err") - s.True(found) - s.Equal("", execErr.Value) - - rejectErr, found := v.GetAttribute("reject_err") - s.True(found) - s.Equal("", rejectErr.Value) - } - } - s.True(foundPropResult) - - balance = s.app.BankKeeper.GetBalance(ctx, randAcc, "stake") - s.Equal(int64(100), balance.Amount.Int64()) - - // try to execute again, should fail - err = s.executeProposal(ctx, accountAddr, s.members[0], 0) - s.Error(err) -} - -// TestConfigUpdate creates a multisig with 1 member, adds 2 more members and -// changes the config to require 2/3 majority (also through a proposal). -func (s *IntegrationTestSuite) TestConfigUpdate() { - ctx := sdk.NewContext(s.app.CommitMultiStore(), false, s.app.Logger()).WithHeaderInfo(header.Info{ - Time: time.Now(), - }) - - initialMembers := map[string]uint64{ - s.membersAddr[0]: 100, - } - accountAddr, accAddrStr := s.initAccount(ctx, s.members[0], initialMembers) - - // Add 2 members and pass the proposal - // create proposal - updateMsg := &v1.MsgUpdateConfig{ - UpdateMembers: []*v1.Member{ - { - Address: s.membersAddr[1], - Weight: 100, - }, - { - Address: s.membersAddr[2], - Weight: 100, - }, - }, - Config: &v1.Config{ - Threshold: 200, // 3 members with 100 power each, 2/3 majority - Quorum: 200, - VotingPeriod: 120, - Revote: false, - EarlyExecution: false, - }, - } - - msgExec := &accountsv1.MsgExecute{ - Sender: accAddrStr, - Target: accAddrStr, - Message: codectypes.UnsafePackAny(updateMsg), - Funds: []sdk.Coin{}, - } - - s.createProposal(ctx, accountAddr, s.members[0], codectypes.UnsafePackAny(msgExec)) - - // vote - voteReq := &v1.MsgVote{ - ProposalId: 0, - Vote: v1.VoteOption_VOTE_OPTION_YES, - } - - err := s.executeTx(ctx, voteReq, accountAddr, s.members[0]) - s.NoError(err) - - err = s.executeProposal(ctx, accountAddr, s.members[0], 0) - s.NoError(err) - - // get members - res, err := s.queryAcc(ctx, &v1.QueryConfig{}, accountAddr) - s.NoError(err) - resp := res.(*v1.QueryConfigResponse) - s.Len(resp.Members, 3) - s.Equal(int64(200), resp.Config.Threshold) - - // Try to remove a member, but it doesn't reach passing threshold - // create proposal - msgExec = &accountsv1.MsgExecute{ - Sender: accAddrStr, - Target: accAddrStr, - Message: codectypes.UnsafePackAny(&v1.MsgUpdateConfig{ - UpdateMembers: []*v1.Member{ - { - Address: s.membersAddr[1], - Weight: 0, - }, - }, - Config: &v1.Config{ - Threshold: 200, // 3 members with 100 power each, 2/3 majority - Quorum: 200, - VotingPeriod: 120, - Revote: false, - EarlyExecution: false, - }, - }), - Funds: []sdk.Coin{}, - } - - s.createProposal(ctx, accountAddr, s.members[0], codectypes.UnsafePackAny(msgExec)) - - // vote - voteReq = &v1.MsgVote{ - ProposalId: 1, - Vote: v1.VoteOption_VOTE_OPTION_NO, - } - - err = s.executeTx(ctx, voteReq, accountAddr, s.members[0]) - s.NoError(err) - - // need to wait until voting period is over because we disabled early execution on the last - // config update - err = s.executeProposal(ctx, accountAddr, s.members[0], 0) - s.ErrorContains(err, "voting period has not ended yet, and early execution is not enabled") - - // vote with member 1 - voteReq = &v1.MsgVote{ - ProposalId: 1, - Vote: v1.VoteOption_VOTE_OPTION_NO, - } - - err = s.executeTx(ctx, voteReq, accountAddr, s.members[1]) - s.NoError(err) - - // need to wait until voting period is over because we disabled early execution on the last - // config update - err = s.executeProposal(ctx, accountAddr, s.members[0], 1) - s.ErrorContains(err, "voting period has not ended yet, and early execution is not enabled") - - headerInfo := ctx.HeaderInfo() - headerInfo.Time = headerInfo.Time.Add(time.Second * 121) - ctx = ctx.WithHeaderInfo(headerInfo) - - // now it should work, but the proposal will fail - err = s.executeProposal(ctx, accountAddr, s.members[0], 1) - s.NoError(err) - - foundPropResult := false - for _, v := range ctx.EventManager().Events() { - if v.Type == "proposal_tally" { - propID, found := v.GetAttribute("proposal_id") - s.True(found) - - if propID.Value == "1" { - foundPropResult = true - status, found := v.GetAttribute("status") - s.True(found) - s.Equal(v1.ProposalStatus_PROPOSAL_STATUS_REJECTED.String(), status.Value) - - // exec_err is nil because the proposal didn't execute - execErr, found := v.GetAttribute("exec_err") - s.True(found) - s.Equal("", execErr.Value) - - rejectErr, found := v.GetAttribute("reject_err") - s.True(found) - s.Equal("threshold not reached", rejectErr.Value) - } - } - } - s.True(foundPropResult) - - // get members - res, err = s.queryAcc(ctx, &v1.QueryConfig{}, accountAddr) - s.NoError(err) - resp = res.(*v1.QueryConfigResponse) - s.Len(resp.Members, 3) - s.Equal(int64(200), resp.Config.Threshold) -} diff --git a/tests/integration/accounts/multisig/test_suite.go b/tests/integration/accounts/multisig/test_suite.go deleted file mode 100644 index 631ddb58ab4c..000000000000 --- a/tests/integration/accounts/multisig/test_suite.go +++ /dev/null @@ -1,115 +0,0 @@ -package multisig - -import ( - "context" - "testing" - - "github.com/stretchr/testify/require" - "github.com/stretchr/testify/suite" - - "cosmossdk.io/core/transaction" - "cosmossdk.io/math" - "cosmossdk.io/simapp" - v1 "cosmossdk.io/x/accounts/defaults/multisig/v1" - "cosmossdk.io/x/bank/testutil" - - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" - sdk "github.com/cosmos/cosmos-sdk/types" -) - -type IntegrationTestSuite struct { - suite.Suite - - app *simapp.SimApp - members []sdk.AccAddress - membersAddr []string -} - -func NewIntegrationTestSuite() *IntegrationTestSuite { - return &IntegrationTestSuite{} -} - -func (s *IntegrationTestSuite) SetupSuite() { - s.app = setupApp(s.T()) - - s.members = []sdk.AccAddress{} - for i := 0; i < 10; i++ { - addr := secp256k1.GenPrivKey().PubKey().Address() - addrStr, err := s.app.AuthKeeper.AddressCodec().BytesToString(addr) - require.NoError(s.T(), err) - s.membersAddr = append(s.membersAddr, addrStr) - s.members = append(s.members, sdk.AccAddress(addr)) - } -} - -func (s *IntegrationTestSuite) TearDownSuite() {} - -func setupApp(t *testing.T) *simapp.SimApp { - t.Helper() - app := simapp.Setup(t, false) - return app -} - -func (s *IntegrationTestSuite) executeTx(ctx context.Context, msg sdk.Msg, accAddr, sender []byte) error { - _, err := s.app.AccountsKeeper.Execute(ctx, accAddr, sender, msg, nil) - return err -} - -func (s *IntegrationTestSuite) queryAcc(ctx context.Context, req sdk.Msg, accAddr []byte) (transaction.Msg, error) { - resp, err := s.app.AccountsKeeper.Query(ctx, accAddr, req) - return resp, err -} - -func (s *IntegrationTestSuite) fundAccount(ctx context.Context, addr sdk.AccAddress, amt sdk.Coins) { - require.NoError(s.T(), testutil.FundAccount(ctx, s.app.BankKeeper, addr, amt)) -} - -// initAccount initializes a multisig account with the given members and powers -// and returns the account address -func (s *IntegrationTestSuite) initAccount(ctx context.Context, sender []byte, membersPowers map[string]uint64) ([]byte, string) { - s.fundAccount(ctx, sender, sdk.Coins{sdk.NewCoin("stake", math.NewInt(1000000))}) - - members := []*v1.Member{} - for addrStr, power := range membersPowers { - members = append(members, &v1.Member{Address: addrStr, Weight: power}) - } - - _, accountAddr, err := s.app.AccountsKeeper.Init(ctx, "multisig", sender, - &v1.MsgInit{ - Members: members, - Config: &v1.Config{ - Threshold: 100, - Quorum: 100, - VotingPeriod: 120, - Revote: false, - EarlyExecution: true, - }, - }, sdk.Coins{sdk.NewCoin("stake", math.NewInt(1000))}, nil) - s.NoError(err) - - accountAddrStr, err := s.app.AuthKeeper.AddressCodec().BytesToString(accountAddr) - s.NoError(err) - - return accountAddr, accountAddrStr -} - -// createProposal -func (s *IntegrationTestSuite) createProposal(ctx context.Context, accAddr, sender []byte, msgs ...*codectypes.Any) { - propReq := &v1.MsgCreateProposal{ - Proposal: &v1.Proposal{ - Title: "test", - Summary: "test", - Messages: msgs, - }, - } - err := s.executeTx(ctx, propReq, accAddr, sender) - s.NoError(err) -} - -func (s *IntegrationTestSuite) executeProposal(ctx context.Context, accAddr, sender []byte, proposalID uint64) error { - execReq := &v1.MsgExecuteProposal{ - ProposalId: proposalID, - } - return s.executeTx(ctx, execReq, accAddr, sender) -} From 9dff64f0e1dc7473db209560ea50b39e6cb7aa82 Mon Sep 17 00:00:00 2001 From: sontrinh16 Date: Tue, 17 Dec 2024 22:38:55 +0700 Subject: [PATCH 3/4] minor --- tests/integration/v2/accounts/multisig/account_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/v2/accounts/multisig/account_test.go b/tests/integration/v2/accounts/multisig/account_test.go index ba23e30ef11e..a50a1f32dd6a 100644 --- a/tests/integration/v2/accounts/multisig/account_test.go +++ b/tests/integration/v2/accounts/multisig/account_test.go @@ -71,9 +71,9 @@ func (s *IntegrationTestSuite) TestSimpleSendProposal() { foundPropResult := false events := integration.EventsFromContext(ctx) - foundPropResult = true for _, e := range events { if e.Type == "proposal_tally" { + foundPropResult = true attr, found := integration.GetAttribute(e, "status") s.True(found) s.Equal(v1.ProposalStatus_PROPOSAL_STATUS_PASSED.String(), attr.Value) From c9a9d7078c52900f1488306c7fde34a42bdaa331 Mon Sep 17 00:00:00 2001 From: sontrinh16 Date: Thu, 19 Dec 2024 16:06:29 +0700 Subject: [PATCH 4/4] fix tests --- tests/integration/v2/accounts/multisig/account_test.go | 6 ++++-- tests/integration/v2/accounts/multisig/test_suite.go | 10 +++------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/tests/integration/v2/accounts/multisig/account_test.go b/tests/integration/v2/accounts/multisig/account_test.go index a50a1f32dd6a..7cd17cb7a5c2 100644 --- a/tests/integration/v2/accounts/multisig/account_test.go +++ b/tests/integration/v2/accounts/multisig/account_test.go @@ -25,7 +25,8 @@ func TestIntegrationTestSuite(t *testing.T) { // TestSimpleSendProposal creates a multisig account with 1 member, sends a tx, votes and executes it. func (s *IntegrationTestSuite) TestSimpleSendProposal() { - ctx := s.ctx + ctx := s.app.StateLatestContext(s.T()) + ctx = integration.SetHeaderInfo(ctx, header.Info{Time: time.Now()}) randAcc := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) @@ -113,7 +114,8 @@ func (s *IntegrationTestSuite) TestSimpleSendProposal() { // TestConfigUpdate creates a multisig with 1 member, adds 2 more members and // changes the config to require 2/3 majority (also through a proposal). func (s *IntegrationTestSuite) TestConfigUpdate() { - ctx := s.ctx + ctx := s.app.StateLatestContext(s.T()) + ctx = integration.SetHeaderInfo(ctx, header.Info{Time: time.Now()}) initialMembers := map[string]uint64{ diff --git a/tests/integration/v2/accounts/multisig/test_suite.go b/tests/integration/v2/accounts/multisig/test_suite.go index 838e3a519678..e71c432f7495 100644 --- a/tests/integration/v2/accounts/multisig/test_suite.go +++ b/tests/integration/v2/accounts/multisig/test_suite.go @@ -3,7 +3,6 @@ package multisig import ( "context" - "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" "cosmossdk.io/core/router" @@ -42,7 +41,6 @@ type IntegrationTestSuite struct { suite.Suite app *integration.App - ctx context.Context members []sdk.AccAddress membersAddr []string @@ -105,15 +103,13 @@ func (s *IntegrationTestSuite) SetupSuite() { ), depinject.Supply(log.NewNopLogger())), startupCfg, &s.bankKeeper, &s.accountsKeeper, &s.authKeeper, &s.stakingKeeper, &s.distrKeeper) - require.NoError(s.T(), err) - - s.ctx = s.app.StateLatestContext(s.T()) + s.NoError(err) s.members = []sdk.AccAddress{} for i := 0; i < 10; i++ { addr := secp256k1.GenPrivKey().PubKey().Address() addrStr, err := s.authKeeper.AddressCodec().BytesToString(addr) - require.NoError(s.T(), err) + s.NoError(err) s.membersAddr = append(s.membersAddr, addrStr) s.members = append(s.members, sdk.AccAddress(addr)) } @@ -174,7 +170,7 @@ func (s *IntegrationTestSuite) queryAcc(ctx context.Context, req sdk.Msg, accAdd } func (s *IntegrationTestSuite) fundAccount(ctx context.Context, addr sdk.AccAddress, amt sdk.Coins) { - require.NoError(s.T(), testutil.FundAccount(ctx, s.bankKeeper, addr, amt)) + s.NoError(testutil.FundAccount(ctx, s.bankKeeper, addr, amt)) } // initAccount initializes a multisig account with the given members and powers