diff --git a/CHANGELOG.md b/CHANGELOG.md index 3967d6d2b38..2d6ef4acbb1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -221,6 +221,8 @@ Ref: https://keepachangelog.com/en/1.0.0/ * `simulation.NewOperationMsg` is now 2-arity instead of 3-arity with the obsolete argument `codec.ProtoCodec` removed. * The field `OperationMsg.Msg` is now of type `[]byte` instead of `json.RawMessage`. * (cli) [#16209](https://github.com/cosmos/cosmos-sdk/pull/16209) Add API `StartCmdWithOptions` to create customized start command. +* (x/auth) [#16016](https://github.com/cosmos/cosmos-sdk/pull/16016) Use collections for accounts state management: + - removed: keeper `HasAccountByID`, `AccountAddressByID`, `SetParams * (x/distribution) [#16211](https://github.com/cosmos/cosmos-sdk/pull/16211) Use collections for params state management. * [#15284](https://github.com/cosmos/cosmos-sdk/pull/15284) * `sdk.Msg.GetSigners` was deprecated and is no longer supported. Use the `cosmos.msg.v1.signer` protobuf annotation instead. diff --git a/baseapp/block_gas_test.go b/baseapp/block_gas_test.go index 5e9910e4a17..7819565a2bf 100644 --- a/baseapp/block_gas_test.go +++ b/baseapp/block_gas_test.go @@ -177,7 +177,7 @@ func TestBaseApp_BlockGas(t *testing.T) { require.Equal(t, []byte("ok"), okValue) } // check block gas is always consumed - baseGas := uint64(50702) // baseGas is the gas consumed before tx msg + baseGas := uint64(57554) // baseGas is the gas consumed before tx msg expGasConsumed := addUint64Saturating(tc.gasToConsume, baseGas) if expGasConsumed > txtypes.MaxGasWanted { // capped by gasLimit diff --git a/collections/indexes/reverse_pair_test.go b/collections/indexes/reverse_pair_test.go index 55ee354f1f0..15f0b996677 100644 --- a/collections/indexes/reverse_pair_test.go +++ b/collections/indexes/reverse_pair_test.go @@ -59,4 +59,10 @@ func TestReversePair(t *testing.T) { require.NoError(t, err) require.Equal(t, "address1", pks[0].K1()) require.Equal(t, "address2", pks[1].K1()) + + // assert if we remove address1 atom balance, we can no longer find it in the index + err = indexedMap.Remove(ctx, collections.Join("address1", "atom")) + require.NoError(t, err) + _, err = indexedMap.Indexes.Denom.MatchExact(ctx, "atom") + require.ErrorIs(t, collections.ErrInvalidIterator, err) } diff --git a/tests/integration/gov/genesis_test.go b/tests/integration/gov/genesis_test.go index 4a1cd9e869e..2482c0b0c57 100644 --- a/tests/integration/gov/genesis_test.go +++ b/tests/integration/gov/genesis_test.go @@ -4,6 +4,8 @@ import ( "encoding/json" "testing" + dbm "github.com/cosmos/cosmos-db" + abci "github.com/cometbft/cometbft/abci/types" cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" "gotest.tools/v3/assert" @@ -75,9 +77,10 @@ func TestImportExportQueues(t *testing.T) { ctx := s1.app.BaseApp.NewContext(false, cmtproto.Header{}) addrs := simtestutil.AddTestAddrs(s1.BankKeeper, s1.StakingKeeper, ctx, 1, valTokens) - s1.app.FinalizeBlock(&abci.RequestFinalizeBlock{ + _, err = s1.app.FinalizeBlock(&abci.RequestFinalizeBlock{ Height: s1.app.LastBlockHeight() + 1, }) + assert.NilError(t, err) ctx = s1.app.BaseApp.NewContext(false, cmtproto.Header{}) // Create two proposals, put the second into the voting period @@ -121,29 +124,41 @@ func TestImportExportQueues(t *testing.T) { assert.NilError(t, err) s2 := suite{} + db := dbm.NewMemDB() + conf2 := simtestutil.DefaultStartUpConfig() + conf2.DB = db s2.app, err = simtestutil.SetupWithConfiguration( depinject.Configs( appConfig, depinject.Supply(log.NewNopLogger()), ), - simtestutil.DefaultStartUpConfig(), + conf2, &s2.AccountKeeper, &s2.BankKeeper, &s2.DistrKeeper, &s2.GovKeeper, &s2.StakingKeeper, &s2.cdc, &s2.appBuilder, ) assert.NilError(t, err) - s2.app.InitChain(&abci.RequestInitChain{ - Validators: []abci.ValidatorUpdate{}, - ConsensusParams: simtestutil.DefaultConsensusParams, - AppStateBytes: stateBytes, - }) + clearDB(t, db) + err = s2.app.CommitMultiStore().LoadLatestVersion() + assert.NilError(t, err) + + _, err = s2.app.InitChain( + &abci.RequestInitChain{ + Validators: []abci.ValidatorUpdate{}, + ConsensusParams: simtestutil.DefaultConsensusParams, + AppStateBytes: stateBytes, + }, + ) + assert.NilError(t, err) - s2.app.FinalizeBlock(&abci.RequestFinalizeBlock{ + _, err = s2.app.FinalizeBlock(&abci.RequestFinalizeBlock{ Height: s2.app.LastBlockHeight() + 1, }) + assert.NilError(t, err) - s2.app.FinalizeBlock(&abci.RequestFinalizeBlock{ + _, err = s2.app.FinalizeBlock(&abci.RequestFinalizeBlock{ Height: s2.app.LastBlockHeight() + 1, }) + assert.NilError(t, err) ctx2 := s2.app.BaseApp.NewContext(false, cmtproto.Header{}) @@ -174,3 +189,18 @@ func TestImportExportQueues(t *testing.T) { assert.NilError(t, err) assert.Assert(t, proposal2.Status == v1.StatusRejected) } + +func clearDB(t *testing.T, db *dbm.MemDB) { + iter, err := db.Iterator(nil, nil) + assert.NilError(t, err) + defer iter.Close() + + var keys [][]byte + for ; iter.Valid(); iter.Next() { + keys = append(keys, iter.Key()) + } + + for _, k := range keys { + assert.NilError(t, db.Delete(k)) + } +} diff --git a/x/auth/ante/ante_test.go b/x/auth/ante/ante_test.go index f5b33fe6e4e..21a6d6bcb1d 100644 --- a/x/auth/ante/ante_test.go +++ b/x/auth/ante/ante_test.go @@ -1418,7 +1418,7 @@ func TestAnteHandlerReCheck(t *testing.T) { for _, tc := range testCases { // set testcase parameters - err := suite.accountKeeper.SetParams(suite.ctx, tc.params) + err := suite.accountKeeper.Params.Set(suite.ctx, tc.params) require.NoError(t, err) _, err = suite.anteHandler(suite.ctx, tx, false) @@ -1426,7 +1426,7 @@ func TestAnteHandlerReCheck(t *testing.T) { require.NotNil(t, err, "tx does not fail on recheck with updated params in test case: %s", tc.name) // reset parameters to default values - err = suite.accountKeeper.SetParams(suite.ctx, authtypes.DefaultParams()) + err = suite.accountKeeper.Params.Set(suite.ctx, authtypes.DefaultParams()) require.NoError(t, err) } diff --git a/x/auth/ante/sigverify_test.go b/x/auth/ante/sigverify_test.go index e5538ee03e1..78dcc5802fe 100644 --- a/x/auth/ante/sigverify_test.go +++ b/x/auth/ante/sigverify_test.go @@ -44,7 +44,7 @@ func TestSetPubKey(t *testing.T) { // set accounts and create msg for each address for i, addr := range addrs { acc := suite.accountKeeper.NewAccountWithAddress(suite.ctx, addr) - require.NoError(t, acc.SetAccountNumber(uint64(i))) + require.NoError(t, acc.SetAccountNumber(uint64(i+1000))) suite.accountKeeper.SetAccount(suite.ctx, acc) msgs[i] = testdata.NewTestMsg(addr) } @@ -153,12 +153,14 @@ func TestSigVerification(t *testing.T) { addrs := []sdk.AccAddress{addr1, addr2, addr3} msgs := make([]sdk.Msg, len(addrs)) + accs := make([]sdk.AccountI, len(addrs)) // set accounts and create msg for each address for i, addr := range addrs { acc := suite.accountKeeper.NewAccountWithAddress(suite.ctx, addr) - require.NoError(t, acc.SetAccountNumber(uint64(i))) + require.NoError(t, acc.SetAccountNumber(uint64(i)+1000)) suite.accountKeeper.SetAccount(suite.ctx, acc) msgs[i] = testdata.NewTestMsg(addr) + accs[i] = acc } feeAmount := testdata.NewTestFeeAmount() @@ -190,11 +192,11 @@ func TestSigVerification(t *testing.T) { validSigs := false testCases := []testCase{ {"no signers", []cryptotypes.PrivKey{}, []uint64{}, []uint64{}, validSigs, false, true}, - {"not enough signers", []cryptotypes.PrivKey{priv1, priv2}, []uint64{0, 1}, []uint64{0, 0}, validSigs, false, true}, - {"wrong order signers", []cryptotypes.PrivKey{priv3, priv2, priv1}, []uint64{2, 1, 0}, []uint64{0, 0, 0}, validSigs, false, true}, + {"not enough signers", []cryptotypes.PrivKey{priv1, priv2}, []uint64{accs[0].GetAccountNumber(), accs[1].GetAccountNumber()}, []uint64{0, 0}, validSigs, false, true}, + {"wrong order signers", []cryptotypes.PrivKey{priv3, priv2, priv1}, []uint64{accs[2].GetAccountNumber(), accs[1].GetAccountNumber(), accs[0].GetAccountNumber()}, []uint64{0, 0, 0}, validSigs, false, true}, {"wrong accnums", []cryptotypes.PrivKey{priv1, priv2, priv3}, []uint64{7, 8, 9}, []uint64{0, 0, 0}, validSigs, false, true}, - {"wrong sequences", []cryptotypes.PrivKey{priv1, priv2, priv3}, []uint64{0, 1, 2}, []uint64{3, 4, 5}, validSigs, false, true}, - {"valid tx", []cryptotypes.PrivKey{priv1, priv2, priv3}, []uint64{0, 1, 2}, []uint64{0, 0, 0}, validSigs, false, false}, + {"wrong sequences", []cryptotypes.PrivKey{priv1, priv2, priv3}, []uint64{accs[0].GetAccountNumber(), accs[1].GetAccountNumber(), accs[2].GetAccountNumber()}, []uint64{3, 4, 5}, validSigs, false, true}, + {"valid tx", []cryptotypes.PrivKey{priv1, priv2, priv3}, []uint64{accs[0].GetAccountNumber(), accs[1].GetAccountNumber(), accs[2].GetAccountNumber()}, []uint64{0, 0, 0}, validSigs, false, false}, {"no err on recheck", []cryptotypes.PrivKey{priv1, priv2, priv3}, []uint64{0, 0, 0}, []uint64{0, 0, 0}, !validSigs, true, false}, } @@ -265,7 +267,7 @@ func runSigDecorators(t *testing.T, params types.Params, _ bool, privs ...crypto // Make block-height non-zero to include accNum in SignBytes suite.ctx = suite.ctx.WithBlockHeight(1) - err := suite.accountKeeper.SetParams(suite.ctx, params) + err := suite.accountKeeper.Params.Set(suite.ctx, params) require.NoError(t, err) msgs := make([]sdk.Msg, len(privs)) @@ -275,10 +277,10 @@ func runSigDecorators(t *testing.T, params types.Params, _ bool, privs ...crypto for i, priv := range privs { addr := sdk.AccAddress(priv.PubKey().Address()) acc := suite.accountKeeper.NewAccountWithAddress(suite.ctx, addr) - require.NoError(t, acc.SetAccountNumber(uint64(i))) + require.NoError(t, acc.SetAccountNumber(uint64(i)+1000)) suite.accountKeeper.SetAccount(suite.ctx, acc) msgs[i] = testdata.NewTestMsg(addr) - accNums[i] = uint64(i) + accNums[i] = acc.GetAccountNumber() accSeqs[i] = uint64(0) } require.NoError(t, suite.txBuilder.SetMsgs(msgs...)) diff --git a/x/auth/ante/testutil_test.go b/x/auth/ante/testutil_test.go index 5056e85b7fa..c22c4b7bd71 100644 --- a/x/auth/ante/testutil_test.go +++ b/x/auth/ante/testutil_test.go @@ -82,7 +82,7 @@ func SetupTestSuite(t *testing.T, isCheckTx bool) *AnteTestSuite { suite.encCfg.Codec, runtime.NewKVStoreService(key), types.ProtoBaseAccount, maccPerms, sdk.Bech32MainPrefix, types.NewModuleAddress("gov").String(), ) suite.accountKeeper.GetModuleAccount(suite.ctx, types.FeeCollectorName) - err := suite.accountKeeper.SetParams(suite.ctx, types.DefaultParams()) + err := suite.accountKeeper.Params.Set(suite.ctx, types.DefaultParams()) require.NoError(t, err) // We're using TestMsg encoding in some tests, so register it here. diff --git a/x/auth/keeper/account.go b/x/auth/keeper/account.go index 5336ecbec4e..62b32099fd2 100644 --- a/x/auth/keeper/account.go +++ b/x/auth/keeper/account.go @@ -2,11 +2,11 @@ package keeper import ( "context" + "errors" - storetypes "cosmossdk.io/store/types" + "cosmossdk.io/collections" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth/types" ) // NewAccountWithAddress implements AccountKeeperI. @@ -31,51 +31,17 @@ func (ak AccountKeeper) NewAccount(ctx context.Context, acc sdk.AccountI) sdk.Ac // HasAccount implements AccountKeeperI. func (ak AccountKeeper) HasAccount(ctx context.Context, addr sdk.AccAddress) bool { - store := ak.storeService.OpenKVStore(ctx) - has, err := store.Has(types.AddressStoreKey(addr)) - if err != nil { - panic(err) - } - return has -} - -// HasAccountAddressByID checks account address exists by id. -func (ak AccountKeeper) HasAccountAddressByID(ctx context.Context, id uint64) bool { - store := ak.storeService.OpenKVStore(ctx) - has, err := store.Has(types.AccountNumberStoreKey(id)) - if err != nil { - panic(err) - } + has, _ := ak.Accounts.Has(ctx, addr) return has } // GetAccount implements AccountKeeperI. func (ak AccountKeeper) GetAccount(ctx context.Context, addr sdk.AccAddress) sdk.AccountI { - store := ak.storeService.OpenKVStore(ctx) - bz, err := store.Get(types.AddressStoreKey(addr)) - if err != nil { + acc, err := ak.Accounts.Get(ctx, addr) + if err != nil && !errors.Is(err, collections.ErrNotFound) { panic(err) } - - if bz == nil { - return nil - } - - return ak.decodeAccount(bz) -} - -// GetAccountAddressById returns account address by id. -func (ak AccountKeeper) GetAccountAddressByID(ctx context.Context, id uint64) string { - store := ak.storeService.OpenKVStore(ctx) - bz, err := store.Get(types.AccountNumberStoreKey(id)) - if err != nil { - panic(err) - } - - if bz == nil { - return "" - } - return sdk.AccAddress(bz).String() + return acc } // GetAllAccounts returns all accounts in the accountKeeper. @@ -90,29 +56,16 @@ func (ak AccountKeeper) GetAllAccounts(ctx context.Context) (accounts []sdk.Acco // SetAccount implements AccountKeeperI. func (ak AccountKeeper) SetAccount(ctx context.Context, acc sdk.AccountI) { - addr := acc.GetAddress() - store := ak.storeService.OpenKVStore(ctx) - - bz, err := ak.MarshalAccount(acc) + err := ak.Accounts.Set(ctx, acc.GetAddress(), acc) if err != nil { panic(err) } - - store.Set(types.AddressStoreKey(addr), bz) - store.Set(types.AccountNumberStoreKey(acc.GetAccountNumber()), addr.Bytes()) } // RemoveAccount removes an account for the account mapper store. // NOTE: this will cause supply invariant violation if called func (ak AccountKeeper) RemoveAccount(ctx context.Context, acc sdk.AccountI) { - addr := acc.GetAddress() - store := ak.storeService.OpenKVStore(ctx) - err := store.Delete(types.AddressStoreKey(addr)) - if err != nil { - panic(err) - } - - err = store.Delete(types.AccountNumberStoreKey(acc.GetAccountNumber())) + err := ak.Accounts.Remove(ctx, acc.GetAddress()) if err != nil { panic(err) } @@ -121,18 +74,10 @@ func (ak AccountKeeper) RemoveAccount(ctx context.Context, acc sdk.AccountI) { // IterateAccounts iterates over all the stored accounts and performs a callback function. // Stops iteration when callback returns true. func (ak AccountKeeper) IterateAccounts(ctx context.Context, cb func(account sdk.AccountI) (stop bool)) { - store := ak.storeService.OpenKVStore(ctx) - iterator, err := store.Iterator(types.AddressStoreKeyPrefix, storetypes.PrefixEndBytes(types.AddressStoreKeyPrefix)) + err := ak.Accounts.Walk(ctx, nil, func(_ sdk.AccAddress, value sdk.AccountI) (bool, error) { + return cb(value), nil + }) if err != nil { panic(err) } - - defer iterator.Close() - for ; iterator.Valid(); iterator.Next() { - account := ak.decodeAccount(iterator.Value()) - - if cb(account) { - break - } - } } diff --git a/x/auth/keeper/deterministic_test.go b/x/auth/keeper/deterministic_test.go index aad05c5ef0a..d65ff8bab46 100644 --- a/x/auth/keeper/deterministic_test.go +++ b/x/auth/keeper/deterministic_test.go @@ -3,6 +3,7 @@ package keeper_test import ( "encoding/hex" "sort" + "sync/atomic" "testing" cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" @@ -27,6 +28,8 @@ import ( type DeterministicTestSuite struct { suite.Suite + accountNumberLanes uint64 + key *storetypes.KVStoreKey storeService corestore.KVStoreService ctx sdk.Context @@ -80,6 +83,7 @@ func (suite *DeterministicTestSuite) SetupTest() { suite.key = key suite.storeService = storeService suite.maccPerms = maccPerms + suite.accountNumberLanes = 1 } // createAndSetAccount creates a random account and sets to the keeper store. @@ -87,7 +91,15 @@ func (suite *DeterministicTestSuite) createAndSetAccounts(t *rapid.T, count int) accs := make([]sdk.AccountI, 0, count) // We need all generated account-numbers unique - accNums := rapid.SliceOfNDistinct(rapid.Uint64(), count, count, func(i uint64) uint64 { return i }).Draw(t, "acc-numss") + accNums := rapid.SliceOfNDistinct(rapid.Uint64(), count, count, func(i uint64) uint64 { + return i + }).Draw(t, "acc-nums") + + // then we change account numbers in such a way that there cannot be accounts with the same account number + lane := atomic.AddUint64(&suite.accountNumberLanes, 1) + for i := range accNums { + accNums[i] += lane * 1000 + } for i := 0; i < count; i++ { pub := pubkeyGenerator(t).Draw(t, "pubkey") @@ -99,14 +111,12 @@ func (suite *DeterministicTestSuite) createAndSetAccounts(t *rapid.T, count int) suite.accountKeeper.SetAccount(suite.ctx, acc1) accs = append(accs, acc1) } - return accs } func (suite *DeterministicTestSuite) TestGRPCQueryAccount() { rapid.Check(suite.T(), func(t *rapid.T) { accs := suite.createAndSetAccounts(t, 1) - req := &types.QueryAccountRequest{Address: accs[0].GetAddress().String()} testdata.DeterministicIterations(suite.ctx, suite.T(), req, suite.queryClient.Account, 0, true) }) @@ -167,16 +177,8 @@ func (suite *DeterministicTestSuite) TestGRPCQueryAccounts() { func (suite *DeterministicTestSuite) TestGRPCQueryAccountAddressByID() { rapid.Check(suite.T(), func(t *rapid.T) { - pub := pubkeyGenerator(t).Draw(t, "pubkey") - addr := sdk.AccAddress(pub.Address()) - - accNum := rapid.Uint64().Draw(t, "account-number") - seq := rapid.Uint64().Draw(t, "sequence") - - acc1 := types.NewBaseAccount(addr, &pub, accNum, seq) - suite.accountKeeper.SetAccount(suite.ctx, acc1) - - req := &types.QueryAccountAddressByIDRequest{AccountId: accNum} + accs := suite.createAndSetAccounts(t, 1) + req := &types.QueryAccountAddressByIDRequest{AccountId: accs[0].GetAccountNumber()} testdata.DeterministicIterations(suite.ctx, suite.T(), req, suite.queryClient.AccountAddressByID, 0, true) }) @@ -200,7 +202,7 @@ func (suite *DeterministicTestSuite) TestGRPCQueryParameters() { rapid.Uint64Min(1).Draw(t, "sig-verify-cost-ed25519"), rapid.Uint64Min(1).Draw(t, "sig-verify-cost-Secp256k1"), ) - err := suite.accountKeeper.SetParams(suite.ctx, params) + err := suite.accountKeeper.Params.Set(suite.ctx, params) suite.Require().NoError(err) req := &types.QueryParamsRequest{} @@ -210,7 +212,7 @@ func (suite *DeterministicTestSuite) TestGRPCQueryParameters() { // Regression test params := types.NewParams(15, 167, 100, 1, 21457) - err := suite.accountKeeper.SetParams(suite.ctx, params) + err := suite.accountKeeper.Params.Set(suite.ctx, params) suite.Require().NoError(err) req := &types.QueryParamsRequest{} diff --git a/x/auth/keeper/genesis.go b/x/auth/keeper/genesis.go index ad830ef54e2..555e9f3566d 100644 --- a/x/auth/keeper/genesis.go +++ b/x/auth/keeper/genesis.go @@ -10,7 +10,7 @@ import ( // CONTRACT: old coins from the FeeCollectionKeeper need to be transferred through // a genesis port script to the new fee collector account func (ak AccountKeeper) InitGenesis(ctx sdk.Context, data types.GenesisState) { - if err := ak.SetParams(ctx, data.Params); err != nil { + if err := ak.Params.Set(ctx, data.Params); err != nil { panic(err) } diff --git a/x/auth/keeper/grpc_query.go b/x/auth/keeper/grpc_query.go index bfcb4dfea7e..57e8b113a2c 100644 --- a/x/auth/keeper/grpc_query.go +++ b/x/auth/keeper/grpc_query.go @@ -6,9 +6,6 @@ import ( "sort" "strings" - "cosmossdk.io/store/prefix" - - "github.com/cosmos/cosmos-sdk/runtime" "github.com/cosmos/cosmos-sdk/types/query" "google.golang.org/grpc/codes" @@ -27,7 +24,7 @@ func NewQueryServer(k AccountKeeper) types.QueryServer { type queryServer struct{ k AccountKeeper } -func (s queryServer) AccountAddressByID(c context.Context, req *types.QueryAccountAddressByIDRequest) (*types.QueryAccountAddressByIDResponse, error) { +func (s queryServer) AccountAddressByID(ctx context.Context, req *types.QueryAccountAddressByIDRequest) (*types.QueryAccountAddressByIDResponse, error) { if req == nil { return nil, status.Errorf(codes.InvalidArgument, "empty request") } @@ -38,13 +35,12 @@ func (s queryServer) AccountAddressByID(c context.Context, req *types.QueryAccou accID := req.AccountId - ctx := sdk.UnwrapSDKContext(c) - address := s.k.GetAccountAddressByID(ctx, accID) - if len(address) == 0 { + address, err := s.k.Accounts.Indexes.Number.MatchExact(ctx, accID) + if err != nil { return nil, status.Errorf(codes.NotFound, "account address not found with account number %d", req.Id) } - return &types.QueryAccountAddressByIDResponse{AccountAddress: address}, nil + return &types.QueryAccountAddressByIDResponse{AccountAddress: address.String()}, nil } func (s queryServer) Accounts(ctx context.Context, req *types.QueryAccountsRequest) (*types.QueryAccountsResponse, error) { @@ -52,29 +48,21 @@ func (s queryServer) Accounts(ctx context.Context, req *types.QueryAccountsReque return nil, status.Error(codes.InvalidArgument, "empty request") } - store := s.k.storeService.OpenKVStore(ctx) - accountsStore := prefix.NewStore(runtime.KVStoreAdapter(store), types.AddressStoreKeyPrefix) - var accounts []*codectypes.Any - pageRes, err := query.Paginate(accountsStore, req.Pagination, func(key, value []byte) error { - account := s.k.decodeAccount(value) - any, err := codectypes.NewAnyWithValue(account) + _, pageRes, err := query.CollectionFilteredPaginate(ctx, s.k.Accounts, req.Pagination, func(_ sdk.AccAddress, value sdk.AccountI) (include bool, err error) { + accountAny, err := codectypes.NewAnyWithValue(value) if err != nil { - return err + return false, err } - - accounts = append(accounts, any) - return nil + accounts = append(accounts, accountAny) + return false, nil // we don't include it since we're already appending the account }) - if err != nil { - return nil, status.Errorf(codes.Internal, "paginate: %v", err) - } return &types.QueryAccountsResponse{Accounts: accounts, Pagination: pageRes}, err } // Account returns account details based on address -func (s queryServer) Account(c context.Context, req *types.QueryAccountRequest) (*types.QueryAccountResponse, error) { +func (s queryServer) Account(ctx context.Context, req *types.QueryAccountRequest) (*types.QueryAccountResponse, error) { if req == nil { return nil, status.Errorf(codes.InvalidArgument, "empty request") } @@ -83,7 +71,6 @@ func (s queryServer) Account(c context.Context, req *types.QueryAccountRequest) return nil, status.Error(codes.InvalidArgument, "Address cannot be empty") } - ctx := sdk.UnwrapSDKContext(c) addr, err := s.k.addressCodec.StringToBytes(req.Address) if err != nil { return nil, err @@ -218,7 +205,7 @@ func (s queryServer) AddressStringToBytes(ctx context.Context, req *types.Addres } // AccountInfo implements the AccountInfo query. -func (s queryServer) AccountInfo(goCtx context.Context, req *types.QueryAccountInfoRequest) (*types.QueryAccountInfoResponse, error) { +func (s queryServer) AccountInfo(ctx context.Context, req *types.QueryAccountInfoRequest) (*types.QueryAccountInfoResponse, error) { if req == nil { return nil, status.Errorf(codes.InvalidArgument, "empty request") } @@ -227,7 +214,6 @@ func (s queryServer) AccountInfo(goCtx context.Context, req *types.QueryAccountI return nil, status.Error(codes.InvalidArgument, "address cannot be empty") } - ctx := sdk.UnwrapSDKContext(goCtx) addr, err := s.k.addressCodec.StringToBytes(req.Address) if err != nil { return nil, err diff --git a/x/auth/keeper/keeper.go b/x/auth/keeper/keeper.go index 8e4766db7a9..5ef50152dda 100644 --- a/x/auth/keeper/keeper.go +++ b/x/auth/keeper/keeper.go @@ -5,6 +5,8 @@ import ( "errors" "fmt" + "cosmossdk.io/collections/indexes" + "cosmossdk.io/collections" errorsmod "cosmossdk.io/errors" @@ -59,6 +61,28 @@ type AccountKeeperI interface { AddressCodec() address.Codec } +func NewAccountIndexes(sb *collections.SchemaBuilder) AccountsIndexes { + return AccountsIndexes{ + Number: indexes.NewUnique( + sb, types.AccountNumberStoreKeyPrefix, "account_by_number", collections.Uint64Key, sdk.AccAddressKey, + func(_ sdk.AccAddress, v sdk.AccountI) (uint64, error) { + return v.GetAccountNumber(), nil + }, + ), + } +} + +type AccountsIndexes struct { + // Number is a unique index that indexes accounts by their account number. + Number *indexes.Unique[uint64, sdk.AccAddress, sdk.AccountI] +} + +func (a AccountsIndexes) IndexesList() []collections.Index[sdk.AccAddress, sdk.AccountI] { + return []collections.Index[sdk.AccAddress, sdk.AccountI]{ + a.Number, + } +} + // AccountKeeper encodes/decodes accounts using the go-amino (binary) // encoding/decoding library. type AccountKeeper struct { @@ -77,8 +101,10 @@ type AccountKeeper struct { authority string // State + Schema collections.Schema Params collections.Item[types.Params] AccountNumber collections.Sequence + Accounts *collections.IndexedMap[sdk.AccAddress, sdk.AccountI, AccountsIndexes] } var _ AccountKeeperI = &AccountKeeper{} @@ -100,7 +126,7 @@ func NewAccountKeeper( sb := collections.NewSchemaBuilder(storeService) - return AccountKeeper{ + ak := AccountKeeper{ addressCodec: authcodec.NewBech32Codec(bech32Prefix), bech32Prefix: bech32Prefix, storeService: storeService, @@ -110,7 +136,14 @@ func NewAccountKeeper( authority: authority, Params: collections.NewItem(sb, types.ParamsKey, "params", codec.CollValue[types.Params](cdc)), AccountNumber: collections.NewSequence(sb, types.GlobalAccountNumberKey, "account_number"), + Accounts: collections.NewIndexedMap(sb, types.AddressStoreKeyPrefix, "accounts", sdk.AccAddressKey, codec.CollInterfaceValue[sdk.AccountI](cdc), NewAccountIndexes(sb)), + } + schema, err := sb.Build() + if err != nil { + panic(err) } + ak.Schema = schema + return ak } // GetAuthority returns the x/auth module's authority. @@ -234,41 +267,11 @@ func (ak AccountKeeper) SetModuleAccount(ctx context.Context, macc sdk.ModuleAcc ak.SetAccount(ctx, macc) } -func (ak AccountKeeper) decodeAccount(bz []byte) sdk.AccountI { - acc, err := ak.UnmarshalAccount(bz) - if err != nil { - panic(err) - } - - return acc -} - -// MarshalAccount protobuf serializes an Account interface -func (ak AccountKeeper) MarshalAccount(accountI sdk.AccountI) ([]byte, error) { - return ak.cdc.MarshalInterface(accountI) -} - -// UnmarshalAccount returns an Account interface from raw encoded account -// bytes of a Proto-based Account type -func (ak AccountKeeper) UnmarshalAccount(bz []byte) (sdk.AccountI, error) { - var acc sdk.AccountI - return acc, ak.cdc.UnmarshalInterface(bz, &acc) -} - -// GetCodec return codec.Codec object used by the keeper -func (ak AccountKeeper) GetCodec() codec.BinaryCodec { return ak.cdc } - // add getter for bech32Prefix func (ak AccountKeeper) getBech32Prefix() (string, error) { return ak.bech32Prefix, nil } -// SetParams sets the auth module's parameters. -// CONTRACT: This method performs no validation of the parameters. -func (ak AccountKeeper) SetParams(ctx context.Context, params types.Params) error { - return ak.Params.Set(ctx, params) -} - // GetParams gets the auth module's parameters. func (ak AccountKeeper) GetParams(ctx context.Context) (params types.Params) { params, err := ak.Params.Get(ctx) diff --git a/x/auth/keeper/keeper_test.go b/x/auth/keeper/keeper_test.go index 2d0fdcbb048..2237486c032 100644 --- a/x/auth/keeper/keeper_test.go +++ b/x/auth/keeper/keeper_test.go @@ -79,80 +79,6 @@ func TestKeeperTestSuite(t *testing.T) { suite.Run(t, new(KeeperTestSuite)) } -func (suite *KeeperTestSuite) TestAccountMapperGetSet() { - ctx := suite.ctx - addr := sdk.AccAddress([]byte("some---------address")) - - // no account before its created - acc := suite.accountKeeper.GetAccount(ctx, addr) - suite.Require().Nil(acc) - - // create account and check default values - acc = suite.accountKeeper.NewAccountWithAddress(ctx, addr) - suite.Require().NotNil(acc) - suite.Require().Equal(addr, acc.GetAddress()) - suite.Require().EqualValues(nil, acc.GetPubKey()) - suite.Require().EqualValues(0, acc.GetSequence()) - - // NewAccount doesn't call Set, so it's still nil - suite.Require().Nil(suite.accountKeeper.GetAccount(ctx, addr)) - - // set some values on the account and save it - newSequence := uint64(20) - err := acc.SetSequence(newSequence) - suite.Require().NoError(err) - suite.accountKeeper.SetAccount(ctx, acc) - - // check the new values - acc = suite.accountKeeper.GetAccount(ctx, addr) - suite.Require().NotNil(acc) - suite.Require().Equal(newSequence, acc.GetSequence()) -} - -func (suite *KeeperTestSuite) TestAccountMapperRemoveAccount() { - ctx := suite.ctx - addr1 := sdk.AccAddress([]byte("addr1---------------")) - addr2 := sdk.AccAddress([]byte("addr2---------------")) - - // create accounts - acc1 := suite.accountKeeper.NewAccountWithAddress(ctx, addr1) - acc2 := suite.accountKeeper.NewAccountWithAddress(ctx, addr2) - - accSeq1 := uint64(20) - accSeq2 := uint64(40) - - err := acc1.SetSequence(accSeq1) - suite.Require().NoError(err) - err = acc2.SetSequence(accSeq2) - suite.Require().NoError(err) - suite.accountKeeper.SetAccount(ctx, acc1) - suite.accountKeeper.SetAccount(ctx, acc2) - - acc1 = suite.accountKeeper.GetAccount(ctx, addr1) - suite.Require().NotNil(acc1) - suite.Require().Equal(accSeq1, acc1.GetSequence()) - - // remove one account - suite.accountKeeper.RemoveAccount(ctx, acc1) - acc1 = suite.accountKeeper.GetAccount(ctx, addr1) - suite.Require().Nil(acc1) - - acc2 = suite.accountKeeper.GetAccount(ctx, addr2) - suite.Require().NotNil(acc2) - suite.Require().Equal(accSeq2, acc2.GetSequence()) -} - -func (suite *KeeperTestSuite) TestGetSetParams() { - ctx := suite.ctx - params := types.DefaultParams() - - err := suite.accountKeeper.SetParams(ctx, params) - suite.Require().NoError(err) - - actualParams := suite.accountKeeper.GetParams(ctx) - suite.Require().Equal(params, actualParams) -} - func (suite *KeeperTestSuite) TestSupply_ValidatePermissions() { err := suite.accountKeeper.ValidatePermissions(multiPermAcc) suite.Require().NoError(err) diff --git a/x/auth/keeper/migrations.go b/x/auth/keeper/migrations.go index 6b363dcf223..3fd7748b71f 100644 --- a/x/auth/keeper/migrations.go +++ b/x/auth/keeper/migrations.go @@ -75,10 +75,16 @@ func (m Migrator) V45SetAccount(ctx sdk.Context, acc sdk.AccountI) error { addr := acc.GetAddress() store := m.keeper.storeService.OpenKVStore(ctx) - bz, err := m.keeper.MarshalAccount(acc) + bz, err := m.keeper.Accounts.ValueCodec().Encode(acc) if err != nil { return err } - return store.Set(types.AddressStoreKey(addr), bz) + return store.Set(addressStoreKey(addr), bz) +} + +// addressStoreKey turn an address to key used to get it from the account store +// NOTE(tip): exists for legacy compatibility +func addressStoreKey(addr sdk.AccAddress) []byte { + return append(types.AddressStoreKeyPrefix, addr.Bytes()...) } diff --git a/x/auth/keeper/msg_server.go b/x/auth/keeper/msg_server.go index c309c7c127b..fbfc0f95ebe 100644 --- a/x/auth/keeper/msg_server.go +++ b/x/auth/keeper/msg_server.go @@ -33,7 +33,7 @@ func (ms msgServer) UpdateParams(goCtx context.Context, msg *types.MsgUpdatePara } ctx := sdk.UnwrapSDKContext(goCtx) - if err := ms.ak.SetParams(ctx, msg.Params); err != nil { + if err := ms.ak.Params.Set(ctx, msg.Params); err != nil { return nil, err } diff --git a/x/auth/migrations/v2/store_test.go b/x/auth/migrations/v2/store_test.go index b4508b5c3af..c8e198d7c3e 100644 --- a/x/auth/migrations/v2/store_test.go +++ b/x/auth/migrations/v2/store_test.go @@ -2,6 +2,7 @@ package v2_test import ( "fmt" + "sync/atomic" "testing" "time" @@ -74,6 +75,12 @@ func TestMigrateVestingAccounts(t *testing.T) { ctx = app.BaseApp.NewContext(false, cmtproto.Header{Time: time.Now()}) stakingKeeper.SetParams(ctx, stakingtypes.DefaultParams()) + lastAccNum := uint64(1000) + createBaseAccount := func(addr sdk.AccAddress) *authtypes.BaseAccount { + baseAccount := authtypes.NewBaseAccountWithAddress(addr) + require.NoError(t, baseAccount.SetAccountNumber(atomic.AddUint64(&lastAccNum, 1))) + return baseAccount + } testCases := []struct { name string @@ -87,13 +94,13 @@ func TestMigrateVestingAccounts(t *testing.T) { { "delayed vesting has vested, multiple delegations less than the total account balance", func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) { - baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr) + baseAccount := createBaseAccount(delegatorAddr) vestedCoins := sdk.NewCoins(sdk.NewCoin(stakingKeeper.BondDenom(ctx), sdkmath.NewInt(200))) delayedAccount := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().Unix()) ctx = ctx.WithBlockTime(ctx.BlockTime().AddDate(1, 0, 0)) - err := accountKeeper.SetParams(ctx, authtypes.DefaultParams()) + err := accountKeeper.Params.Set(ctx, authtypes.DefaultParams()) require.NoError(t, err) accountKeeper.SetAccount(ctx, delayedAccount) @@ -115,7 +122,7 @@ func TestMigrateVestingAccounts(t *testing.T) { "delayed vesting has vested, single delegations which exceed the vested amount", func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) { require.NoError(t, err) - baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr) + baseAccount := createBaseAccount(delegatorAddr) vestedCoins := sdk.NewCoins(sdk.NewCoin(stakingKeeper.BondDenom(ctx), sdkmath.NewInt(200))) delayedAccount := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().Unix()) @@ -135,7 +142,7 @@ func TestMigrateVestingAccounts(t *testing.T) { { "delayed vesting has vested, multiple delegations which exceed the vested amount", func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) { - baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr) + baseAccount := createBaseAccount(delegatorAddr) vestedCoins := sdk.NewCoins(sdk.NewCoin(stakingKeeper.BondDenom(ctx), sdkmath.NewInt(200))) delayedAccount := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().Unix()) @@ -159,7 +166,7 @@ func TestMigrateVestingAccounts(t *testing.T) { { "delayed vesting has not vested, single delegations which exceed the vested amount", func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) { - baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr) + baseAccount := createBaseAccount(delegatorAddr) vestedCoins := sdk.NewCoins(sdk.NewCoin(stakingKeeper.BondDenom(ctx), sdkmath.NewInt(200))) delayedAccount := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().AddDate(1, 0, 0).Unix()) @@ -177,7 +184,7 @@ func TestMigrateVestingAccounts(t *testing.T) { { "delayed vesting has not vested, multiple delegations which exceed the vested amount", func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) { - baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr) + baseAccount := createBaseAccount(delegatorAddr) vestedCoins := sdk.NewCoins(sdk.NewCoin(stakingKeeper.BondDenom(ctx), sdkmath.NewInt(200))) delayedAccount := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().AddDate(1, 0, 0).Unix()) @@ -199,7 +206,7 @@ func TestMigrateVestingAccounts(t *testing.T) { { "not end time", func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) { - baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr) + baseAccount := createBaseAccount(delegatorAddr) vestedCoins := sdk.NewCoins(sdk.NewCoin(stakingKeeper.BondDenom(ctx), sdkmath.NewInt(300))) delayedAccount := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().AddDate(1, 0, 0).Unix()) @@ -221,7 +228,7 @@ func TestMigrateVestingAccounts(t *testing.T) { { "delayed vesting has not vested, single delegation greater than the total account balance", func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) { - baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr) + baseAccount := createBaseAccount(delegatorAddr) vestedCoins := sdk.NewCoins(sdk.NewCoin(stakingKeeper.BondDenom(ctx), sdkmath.NewInt(300))) delayedAccount := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().AddDate(1, 0, 0).Unix()) @@ -239,7 +246,7 @@ func TestMigrateVestingAccounts(t *testing.T) { { "delayed vesting has vested, single delegation greater than the total account balance", func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) { - baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr) + baseAccount := createBaseAccount(delegatorAddr) vestedCoins := sdk.NewCoins(sdk.NewCoin(stakingKeeper.BondDenom(ctx), sdkmath.NewInt(300))) delayedAccount := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().Unix()) @@ -261,7 +268,7 @@ func TestMigrateVestingAccounts(t *testing.T) { func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) { startTime := ctx.BlockTime().AddDate(1, 0, 0).Unix() endTime := ctx.BlockTime().AddDate(2, 0, 0).Unix() - baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr) + baseAccount := createBaseAccount(delegatorAddr) vestedCoins := sdk.NewCoins(sdk.NewCoin(stakingKeeper.BondDenom(ctx), sdkmath.NewInt(300))) delayedAccount := types.NewContinuousVestingAccount(baseAccount, vestedCoins, startTime, endTime) @@ -283,7 +290,7 @@ func TestMigrateVestingAccounts(t *testing.T) { func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) { startTime := ctx.BlockTime().AddDate(-1, 0, 0).Unix() endTime := ctx.BlockTime().AddDate(2, 0, 0).Unix() - baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr) + baseAccount := createBaseAccount(delegatorAddr) vestedCoins := sdk.NewCoins(sdk.NewCoin(stakingKeeper.BondDenom(ctx), sdkmath.NewInt(300))) delayedAccount := types.NewContinuousVestingAccount(baseAccount, vestedCoins, startTime, endTime) @@ -305,7 +312,7 @@ func TestMigrateVestingAccounts(t *testing.T) { func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) { startTime := ctx.BlockTime().AddDate(-2, 0, 0).Unix() endTime := ctx.BlockTime().AddDate(-1, 0, 0).Unix() - baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr) + baseAccount := createBaseAccount(delegatorAddr) vestedCoins := sdk.NewCoins(sdk.NewCoin(stakingKeeper.BondDenom(ctx), sdkmath.NewInt(300))) delayedAccount := types.NewContinuousVestingAccount(baseAccount, vestedCoins, startTime, endTime) @@ -325,7 +332,7 @@ func TestMigrateVestingAccounts(t *testing.T) { { "periodic vesting account, yet to be vested, some rewards delegated", func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) { - baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr) + baseAccount := createBaseAccount(delegatorAddr) vestedCoins := sdk.NewCoins(sdk.NewCoin(stakingKeeper.BondDenom(ctx), sdkmath.NewInt(100))) start := ctx.BlockTime().Unix() + int64(time.Hour/time.Second) @@ -363,7 +370,7 @@ func TestMigrateVestingAccounts(t *testing.T) { - we're delegating the full original vesting */ startTime := int64(1601042400) - baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr) + baseAccount := createBaseAccount(delegatorAddr) vestedCoins := sdk.NewCoins(sdk.NewCoin(stakingKeeper.BondDenom(ctx), sdk.NewInt(3666666670000))) periods := []types.Period{ { @@ -407,7 +414,7 @@ func TestMigrateVestingAccounts(t *testing.T) { - we're delegating the full original vesting */ startTime := int64(1601042400) - baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr) + baseAccount := createBaseAccount(delegatorAddr) vestedCoins := sdk.NewCoins(sdk.NewCoin(stakingKeeper.BondDenom(ctx), sdk.NewInt(3666666670000))) periods := []types.Period{ { @@ -453,7 +460,7 @@ func TestMigrateVestingAccounts(t *testing.T) { - we're delegating the full original vesting */ startTime := int64(1601042400) - baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr) + baseAccount := createBaseAccount(delegatorAddr) vestedCoins := sdk.NewCoins(sdk.NewCoin(stakingKeeper.BondDenom(ctx), sdk.NewInt(3666666670000))) periods := []types.Period{ { @@ -499,7 +506,7 @@ func TestMigrateVestingAccounts(t *testing.T) { - we're delegating the full original vesting */ startTime := int64(1601042400) - baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr) + baseAccount := createBaseAccount(delegatorAddr) vestedCoins := sdk.NewCoins(sdk.NewCoin(stakingKeeper.BondDenom(ctx), sdk.NewInt(3666666670000))) periods := []types.Period{ { @@ -535,7 +542,7 @@ func TestMigrateVestingAccounts(t *testing.T) { { "vesting account has unbonding delegations in place", func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) { - baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr) + baseAccount := createBaseAccount(delegatorAddr) vestedCoins := sdk.NewCoins(sdk.NewCoin(stakingKeeper.BondDenom(ctx), sdk.NewInt(300))) delayedAccount := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().AddDate(10, 0, 0).Unix()) @@ -564,7 +571,7 @@ func TestMigrateVestingAccounts(t *testing.T) { { "vesting account has never delegated anything", func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) { - baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr) + baseAccount := createBaseAccount(delegatorAddr) vestedCoins := sdk.NewCoins(sdk.NewCoin(stakingKeeper.BondDenom(ctx), sdk.NewInt(300))) delayedAccount := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().AddDate(10, 0, 0).Unix()) @@ -580,7 +587,7 @@ func TestMigrateVestingAccounts(t *testing.T) { { "vesting account has no delegation but dirty DelegatedFree and DelegatedVesting fields", func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) { - baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr) + baseAccount := createBaseAccount(delegatorAddr) vestedCoins := sdk.NewCoins(sdk.NewCoin(stakingKeeper.BondDenom(ctx), sdk.NewInt(300))) delayedAccount := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().AddDate(10, 0, 0).Unix()) @@ -598,7 +605,7 @@ func TestMigrateVestingAccounts(t *testing.T) { for _, tc := range testCases { tc := tc t.Run(tc.name, func(t *testing.T) { - err := accountKeeper.SetParams(ctx, authtypes.DefaultParams()) + err := accountKeeper.Params.Set(ctx, authtypes.DefaultParams()) require.NoError(t, err) addrs := simtestutil.AddTestAddrs(bankKeeper, stakingKeeper, ctx, 1, sdk.NewInt(tc.tokenAmount)) diff --git a/x/auth/migrations/v3/store.go b/x/auth/migrations/v3/store.go index 6aee1dc1a35..62deba2e49b 100644 --- a/x/auth/migrations/v3/store.go +++ b/x/auth/migrations/v3/store.go @@ -22,7 +22,7 @@ func mapAccountAddressToAccountID(ctx sdk.Context, storeService corestore.KVStor if err := cdc.UnmarshalInterface(iterator.Value(), &acc); err != nil { return err } - store.Set(types.AccountNumberStoreKey(acc.GetAccountNumber()), acc.GetAddress().Bytes()) + store.Set(accountNumberStoreKey(acc.GetAccountNumber()), acc.GetAddress().Bytes()) } return nil @@ -34,3 +34,9 @@ func mapAccountAddressToAccountID(ctx sdk.Context, storeService corestore.KVStor func MigrateStore(ctx sdk.Context, storeService corestore.KVStoreService, cdc codec.BinaryCodec) error { return mapAccountAddressToAccountID(ctx, storeService, cdc) } + +// accountNumberStoreKey turn an account number to key used to get the account address from account store +// NOTE(tip): exists for legacy compatibility +func accountNumberStoreKey(accountNumber uint64) []byte { + return append(types.AccountNumberStoreKeyPrefix, sdk.Uint64ToBigEndian(accountNumber)...) +} diff --git a/x/auth/migrations/v3/store_test.go b/x/auth/migrations/v3/store_test.go index 39c958707d3..a431c72ebde 100644 --- a/x/auth/migrations/v3/store_test.go +++ b/x/auth/migrations/v3/store_test.go @@ -5,6 +5,8 @@ import ( "testing" "time" + "cosmossdk.io/collections" + cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" "github.com/stretchr/testify/require" @@ -99,12 +101,11 @@ func TestMigrateMapAccAddressToAccNumberKey(t *testing.T) { } // get the account address by acc id - accAddr := accountKeeper.GetAccountAddressByID(ctx, tc.accNum) - + accAddr, err := accountKeeper.Accounts.Indexes.Number.MatchExact(ctx, tc.accNum) if tc.doMigration { - require.Equal(t, accAddr, acc.Address) + require.Equal(t, accAddr.String(), acc.Address) } else { - require.Equal(t, len(accAddr), 0) + require.ErrorIs(t, err, collections.ErrNotFound) } }) } diff --git a/x/auth/module.go b/x/auth/module.go index 00667b524e1..b6319950ef8 100644 --- a/x/auth/module.go +++ b/x/auth/module.go @@ -186,7 +186,7 @@ func (AppModule) ProposalMsgs(simState module.SimulationState) []simtypes.Weight // RegisterStoreDecoder registers a decoder for auth module's types func (am AppModule) RegisterStoreDecoder(sdr simtypes.StoreDecoderRegistry) { - sdr[types.StoreKey] = simulation.NewDecodeStore(am.accountKeeper) + sdr[types.StoreKey] = simtypes.NewStoreDecoderFuncFromCollectionsSchema(am.accountKeeper.Schema) } // WeightedOperations doesn't return any auth module operation. diff --git a/x/auth/simulation/decoder.go b/x/auth/simulation/decoder.go deleted file mode 100644 index 4d32123e416..00000000000 --- a/x/auth/simulation/decoder.go +++ /dev/null @@ -1,63 +0,0 @@ -package simulation - -import ( - "bytes" - "fmt" - - gogotypes "github.com/cosmos/gogoproto/types" - - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/kv" - "github.com/cosmos/cosmos-sdk/x/auth/types" -) - -type AuthUnmarshaler interface { - UnmarshalAccount([]byte) (sdk.AccountI, error) - GetCodec() codec.BinaryCodec -} - -// NewDecodeStore returns a decoder function closure that unmarshals the KVPair's -// Value to the corresponding auth type. -func NewDecodeStore(ak AuthUnmarshaler) func(kvA, kvB kv.Pair) string { - return func(kvA, kvB kv.Pair) string { - switch { - case bytes.Equal(kvA.Key[:1], types.AddressStoreKeyPrefix): - accA, err := ak.UnmarshalAccount(kvA.Value) - if err != nil { - panic(err) - } - - accB, err := ak.UnmarshalAccount(kvB.Value) - if err != nil { - panic(err) - } - - return fmt.Sprintf("%v\n%v", accA, accB) - - case bytes.Equal(kvA.Key, types.GlobalAccountNumberKey): - var globalAccNumberA, globalAccNumberB gogotypes.UInt64Value - ak.GetCodec().MustUnmarshal(kvA.Value, &globalAccNumberA) - ak.GetCodec().MustUnmarshal(kvB.Value, &globalAccNumberB) - - return fmt.Sprintf("GlobalAccNumberA: %d\nGlobalAccNumberB: %d", globalAccNumberA, globalAccNumberB) - - case bytes.HasPrefix(kvA.Key, types.AccountNumberStoreKeyPrefix): - var accNumA, accNumB sdk.AccAddress - err := accNumA.Unmarshal(kvA.Value) - if err != nil { - panic(err) - } - - err = accNumB.Unmarshal(kvB.Value) - if err != nil { - panic(err) - } - - return fmt.Sprintf("AccNumA: %s\nAccNumB: %s", accNumA, accNumB) - - default: - panic(fmt.Sprintf("unexpected %s key %X (%s)", types.ModuleName, kvA.Key, kvA.Key)) - } - } -} diff --git a/x/auth/simulation/decoder_test.go b/x/auth/simulation/decoder_test.go deleted file mode 100644 index 17a4433561e..00000000000 --- a/x/auth/simulation/decoder_test.go +++ /dev/null @@ -1,90 +0,0 @@ -package simulation_test - -import ( - "fmt" - "testing" - - gogotypes "github.com/cosmos/gogoproto/types" - "github.com/stretchr/testify/require" - - "cosmossdk.io/depinject" - "cosmossdk.io/log" - - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/kv" - "github.com/cosmos/cosmos-sdk/x/auth/simulation" - "github.com/cosmos/cosmos-sdk/x/auth/testutil" - - authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" - - "github.com/cosmos/cosmos-sdk/x/auth/types" -) - -var ( - delPk1 = ed25519.GenPrivKey().PubKey() - delAddr1 = sdk.AccAddress(delPk1.Address()) -) - -func TestDecodeStore(t *testing.T) { - var ( - cdc codec.Codec - accountKeeper authkeeper.AccountKeeper - ) - err := depinject.Inject(depinject.Configs( - testutil.AppConfig, - depinject.Supply(log.NewNopLogger()), - ), &cdc, &accountKeeper) - require.NoError(t, err) - - acc := types.NewBaseAccountWithAddress(delAddr1) - dec := simulation.NewDecodeStore(accountKeeper) - - accBz, err := accountKeeper.MarshalAccount(acc) - require.NoError(t, err) - - globalAccNumber := gogotypes.UInt64Value{Value: 10} - - kvPairs := kv.Pairs{ - Pairs: []kv.Pair{ - { - Key: types.AddressStoreKey(delAddr1), - Value: accBz, - }, - { - Key: types.GlobalAccountNumberKey, - Value: cdc.MustMarshal(&globalAccNumber), - }, - { - Key: types.AccountNumberStoreKey(5), - Value: acc.GetAddress().Bytes(), - }, - { - Key: []byte{0x99}, - Value: []byte{0x99}, - }, - }, - } - tests := []struct { - name string - expectedLog string - }{ - {"Account", fmt.Sprintf("%v\n%v", acc, acc)}, - {"GlobalAccNumber", fmt.Sprintf("GlobalAccNumberA: %d\nGlobalAccNumberB: %d", globalAccNumber, globalAccNumber)}, - {"AccNum", fmt.Sprintf("AccNumA: %s\nAccNumB: %s", acc.GetAddress(), acc.GetAddress())}, - {"other", ""}, - } - - for i, tt := range tests { - i, tt := i, tt - t.Run(tt.name, func(t *testing.T) { - switch i { - case len(tests) - 1: - require.Panics(t, func() { dec(kvPairs.Pairs[i], kvPairs.Pairs[i]) }, tt.name) - default: - require.Equal(t, tt.expectedLog, dec(kvPairs.Pairs[i], kvPairs.Pairs[i]), tt.name) - } - }) - } -} diff --git a/x/auth/types/account_test.go b/x/auth/types/account_test.go index 8f0952f2e08..545e3beef5d 100644 --- a/x/auth/types/account_test.go +++ b/x/auth/types/account_test.go @@ -8,14 +8,9 @@ import ( "github.com/stretchr/testify/require" - "cosmossdk.io/depinject" - "cosmossdk.io/log" - "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" "github.com/cosmos/cosmos-sdk/testutil/testdata" sdk "github.com/cosmos/cosmos-sdk/types" - authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" - "github.com/cosmos/cosmos-sdk/x/auth/testutil" "github.com/cosmos/cosmos-sdk/x/auth/types" ) @@ -66,36 +61,6 @@ func TestBaseSequence(t *testing.T) { require.Equal(t, seq, acc.GetSequence()) } -func TestBaseAccountMarshal(t *testing.T) { - var accountKeeper authkeeper.AccountKeeper - err := depinject.Inject(depinject.Configs( - testutil.AppConfig, - depinject.Supply(log.NewNopLogger()), - ), &accountKeeper) - require.NoError(t, err) - - _, pub, addr := testdata.KeyTestPubAddr() - acc := types.NewBaseAccountWithAddress(addr) - seq := uint64(7) - - // set everything on the account - err = acc.SetPubKey(pub) - require.Nil(t, err) - err = acc.SetSequence(seq) - require.Nil(t, err) - - bz, err := accountKeeper.MarshalAccount(acc) - require.Nil(t, err) - - acc2, err := accountKeeper.UnmarshalAccount(bz) - require.Nil(t, err) - require.Equal(t, acc, acc2) - - // error on bad bytes - _, err = accountKeeper.UnmarshalAccount(bz[:len(bz)/2]) - require.NotNil(t, err) -} - func TestGenesisAccountValidate(t *testing.T) { pubkey := secp256k1.GenPrivKey().PubKey() addr := sdk.AccAddress(pubkey.Address()) diff --git a/x/auth/types/keys.go b/x/auth/types/keys.go index e8e9d70e01f..fb3295511f2 100644 --- a/x/auth/types/keys.go +++ b/x/auth/types/keys.go @@ -2,7 +2,6 @@ package types import ( "cosmossdk.io/collections" - sdk "github.com/cosmos/cosmos-sdk/types" ) const ( @@ -21,22 +20,12 @@ var ( ParamsKey = collections.NewPrefix(0) // AddressStoreKeyPrefix prefix for account-by-address store - AddressStoreKeyPrefix = []byte{0x01} + AddressStoreKeyPrefix = collections.NewPrefix(1) // GlobalAccountNumberKey identifies the prefix where the monotonically increasing // account number is stored. GlobalAccountNumberKey = collections.NewPrefix(2) // AccountNumberStoreKeyPrefix prefix for account-by-id store - AccountNumberStoreKeyPrefix = []byte("accountNumber") + AccountNumberStoreKeyPrefix = collections.NewPrefix("accountNumber") ) - -// AddressStoreKey turn an address to key used to get it from the account store -func AddressStoreKey(addr sdk.AccAddress) []byte { - return append(AddressStoreKeyPrefix, addr.Bytes()...) -} - -// AccountNumberStoreKey turn an account number to key used to get the account address from account store -func AccountNumberStoreKey(accountNumber uint64) []byte { - return append(AccountNumberStoreKeyPrefix, sdk.Uint64ToBigEndian(accountNumber)...) -} diff --git a/x/auth/vesting/types/vesting_account_test.go b/x/auth/vesting/types/vesting_account_test.go index 502416f6522..bec4a07d910 100644 --- a/x/auth/vesting/types/vesting_account_test.go +++ b/x/auth/vesting/types/vesting_account_test.go @@ -780,79 +780,6 @@ func TestGenesisAccountValidate(t *testing.T) { } } -func (s *VestingAccountTestSuite) TestContinuousVestingAccountMarshal() { - require := s.Require() - baseAcc, coins := initBaseAccount() - baseVesting := types.NewBaseVestingAccount(baseAcc, coins, time.Now().Unix()) - acc := types.NewContinuousVestingAccountRaw(baseVesting, baseVesting.EndTime) - - bz, err := s.accountKeeper.MarshalAccount(acc) - require.Nil(err) - - acc2, err := s.accountKeeper.UnmarshalAccount(bz) - require.Nil(err) - require.IsType(&types.ContinuousVestingAccount{}, acc2) - require.Equal(acc.String(), acc2.String()) - - // error on bad bytes - _, err = s.accountKeeper.UnmarshalAccount(bz[:len(bz)/2]) - require.NotNil(err) -} - -func (s *VestingAccountTestSuite) TestPeriodicVestingAccountMarshal() { - require := s.Require() - baseAcc, coins := initBaseAccount() - acc := types.NewPeriodicVestingAccount(baseAcc, coins, time.Now().Unix(), types.Periods{types.Period{3600, coins}}) - - bz, err := s.accountKeeper.MarshalAccount(acc) - require.Nil(err) - - acc2, err := s.accountKeeper.UnmarshalAccount(bz) - require.Nil(err) - require.IsType(&types.PeriodicVestingAccount{}, acc2) - require.Equal(acc.String(), acc2.String()) - - // error on bad bytes - _, err = s.accountKeeper.UnmarshalAccount(bz[:len(bz)/2]) - require.NotNil(err) -} - -func (s *VestingAccountTestSuite) TestDelayedVestingAccountMarshal() { - require := s.Require() - baseAcc, coins := initBaseAccount() - acc := types.NewDelayedVestingAccount(baseAcc, coins, time.Now().Unix()) - - bz, err := s.accountKeeper.MarshalAccount(acc) - require.Nil(err) - - acc2, err := s.accountKeeper.UnmarshalAccount(bz) - require.Nil(err) - require.IsType(&types.DelayedVestingAccount{}, acc2) - require.Equal(acc.String(), acc2.String()) - - // error on bad bytes - _, err = s.accountKeeper.UnmarshalAccount(bz[:len(bz)/2]) - require.NotNil(err) -} - -func (s *VestingAccountTestSuite) TestPermanentLockedAccountMarshal() { - require := s.Require() - baseAcc, coins := initBaseAccount() - acc := types.NewPermanentLockedAccount(baseAcc, coins) - - bz, err := s.accountKeeper.MarshalAccount(acc) - require.Nil(err) - - acc2, err := s.accountKeeper.UnmarshalAccount(bz) - require.Nil(err) - require.IsType(&types.PermanentLockedAccount{}, acc2) - require.Equal(acc.String(), acc2.String()) - - // error on bad bytes - _, err = s.accountKeeper.UnmarshalAccount(bz[:len(bz)/2]) - require.NotNil(err) -} - func initBaseAccount() (*authtypes.BaseAccount, sdk.Coins) { _, _, addr := testdata.KeyTestPubAddr() origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)}