diff --git a/.github/ISSUE_TEMPLATE/qa.md b/.github/ISSUE_TEMPLATE/qa.md index c45a80ddb757..86062e9f6c83 100644 --- a/.github/ISSUE_TEMPLATE/qa.md +++ b/.github/ISSUE_TEMPLATE/qa.md @@ -28,7 +28,6 @@ v without deliberation * [ ] Audit x/bank/v2 * [ ] Audit x/circuit * [ ] Audit x/consensus - * [ ] Audit x/crisis * [ ] Audit x/distribution * [ ] Audit x/evidence * [ ] Audit x/epochs diff --git a/.github/pr_labeler.yml b/.github/pr_labeler.yml index f42f8cc3aeec..472d84033c0d 100644 --- a/.github/pr_labeler.yml +++ b/.github/pr_labeler.yml @@ -51,8 +51,6 @@ - x/circuit/**/* "C:x/consensus": - x/consensus/**/* -"C:x/crisis": - - x/crisis/**/* "C:x/distribution": - x/distribution/**/* "C:x/evidence": diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9878ca45fb23..629b0ef6f8cf 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -283,7 +283,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: - go-version: "1.21" + go-version: "1.22" check-latest: false cache: true cache-dependency-path: depinject/go.sum @@ -312,7 +312,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: - go-version: "1.20" + go-version: "1.22" check-latest: true cache: true cache-dependency-path: errors/go.sum @@ -343,7 +343,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: - go-version: "1.20" + go-version: "1.22" check-latest: true cache: true cache-dependency-path: math/go.sum diff --git a/CHANGELOG.md b/CHANGELOG.md index 436dfc7b7c71..80acb6b96228 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,8 @@ Every module contains its own CHANGELOG.md. Please refer to the module you are i ### Bug Fixes +* (query) [23002](https://github.com/cosmos/cosmos-sdk/pull/23002) Fix collection filtered pagination. + ### API Breaking Changes * (x/params) [#22995](https://github.com/cosmos/cosmos-sdk/pull/22995) Remove `x/params`. Migrate to the new params system introduced in `v0.47` as demonstrated [here](https://github.com/cosmos/cosmos-sdk/blob/main/UPGRADING.md#xparams). diff --git a/collections/README.md b/collections/README.md index f2bca5101bc3..b8d8a62f1d93 100644 --- a/collections/README.md +++ b/collections/README.md @@ -90,7 +90,7 @@ Since a module can have multiple collections, the following is expected: We don't want a collection to write over the state of the other collection so we pass it a prefix, which defines a storage partition owned by the collection. -If you already built modules, the prefix translates to the items you were creating in your ``types/keys.go`` file, example: https://github.com/cosmos/cosmos-sdk/blob/main/x/feegrant/key.go#L27 +If you already built modules, the prefix translates to the items you were creating in your ``types/keys.go`` file, example: https://github.com/cosmos/cosmos-sdk/blob/v0.52.0-rc.1/x/feegrant/key.go#L16~L22 your old: diff --git a/depinject/go.mod b/depinject/go.mod index e1b55ecbcd53..4e4274eba481 100644 --- a/depinject/go.mod +++ b/depinject/go.mod @@ -1,6 +1,6 @@ module cosmossdk.io/depinject -go 1.21 +go 1.22 require ( github.com/cosmos/cosmos-proto v1.0.0-beta.5 diff --git a/docs/architecture/adr-069-gov-improvements.md b/docs/architecture/adr-069-gov-improvements.md index 1ef6971c713d..0e3b62ada24b 100644 --- a/docs/architecture/adr-069-gov-improvements.md +++ b/docs/architecture/adr-069-gov-improvements.md @@ -66,8 +66,8 @@ Voter can only vote NO on the proposal. If the NO threshold is reached, the opti Two governance parameters will be in added [`v1.Params`][5] to support optimistic proposals: ```protobuf -// optimistic_authorized_addreses is an optional governance parameter that limits the authorized accounts that can submit optimistic proposals -repeated string optimistic_authorized_addreses = 17 [(cosmos_proto.scalar) = "cosmos.AddressString"]; +// optimistic_authorized_addresses is an optional governance parameter that limits the authorized accounts that can submit optimistic proposals +repeated string optimistic_authorized_addresses = 17 [(cosmos_proto.scalar) = "cosmos.AddressString"]; // Optimistic rejected threshold defines at which percentage of NO votes, the optimistic proposal should fail and be converted to a standard proposal. string optimistic_rejected_threshold = 18 [(cosmos_proto.scalar) = "cosmos.Dec"]; diff --git a/errors/go.mod b/errors/go.mod index f057227f20ad..24e095e7af2b 100644 --- a/errors/go.mod +++ b/errors/go.mod @@ -2,4 +2,4 @@ module cosmossdk.io/errors/v2 // NOTE: this go.mod should have zero dependencies. -go 1.20 +go 1.22 diff --git a/log/bench_test.go b/log/bench_test.go index 0005e9c12102..fdf5fca645ee 100644 --- a/log/bench_test.go +++ b/log/bench_test.go @@ -83,7 +83,6 @@ func BenchmarkLoggers(b *testing.B) { // so that real write time is negligible. b.Run("zerolog", func(b *testing.B) { for _, bc := range benchCases { - bc := bc b.Run(bc.name, func(b *testing.B) { zl := zerolog.New(io.Discard) logger := log.NewCustomLogger(zl) @@ -99,7 +98,6 @@ func BenchmarkLoggers(b *testing.B) { // also useful as a reference for how expensive zerolog is. b.Run("specialized nop logger", func(b *testing.B) { for _, bc := range nopCases { - bc := bc b.Run(bc.name, func(b *testing.B) { logger := log.NewNopLogger() @@ -115,7 +113,6 @@ func BenchmarkLoggers(b *testing.B) { // so we offer the specialized version in the exported API. b.Run("zerolog nop logger", func(b *testing.B) { for _, bc := range nopCases { - bc := bc b.Run(bc.name, func(b *testing.B) { logger := log.NewCustomLogger(zerolog.Nop()) diff --git a/log/go.mod b/log/go.mod index 2ade9119ab2a..b96fc35696ab 100644 --- a/log/go.mod +++ b/log/go.mod @@ -1,6 +1,6 @@ module cosmossdk.io/log -go 1.21 +go 1.22 require ( github.com/bytedance/sonic v1.12.6 diff --git a/math/go.mod b/math/go.mod index 2afb0109af6d..eb114e987152 100644 --- a/math/go.mod +++ b/math/go.mod @@ -1,6 +1,6 @@ module cosmossdk.io/math -go 1.20 +go 1.22 require ( github.com/cockroachdb/apd/v3 v3.2.1 diff --git a/math/go.sum b/math/go.sum index 03e94d3c99c9..86b231d55d52 100644 --- a/math/go.sum +++ b/math/go.sum @@ -7,11 +7,13 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= +github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -29,6 +31,7 @@ golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= google.golang.org/genproto/googleapis/rpc v0.0.0-20240709173604-40e1e62336c5 h1:SbSDUWW1PAO24TNpLdeheoYPd7kllICcLU52x6eD4kQ= google.golang.org/genproto/googleapis/rpc v0.0.0-20240709173604-40e1e62336c5/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= google.golang.org/grpc v1.64.1 h1:LKtvyfbX3UGVPFcGqJ9ItpVWW6oN/2XqTxfAnwRRXiA= @@ -37,6 +40,7 @@ google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6h google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= pgregory.net/rapid v1.1.0 h1:CMa0sjHSru3puNx+J0MIAuiiEV4N0qj8/cMWGBBCsjw= diff --git a/math/legacy_dec_test.go b/math/legacy_dec_test.go index 4f3897a0867e..1f0b288a080e 100644 --- a/math/legacy_dec_test.go +++ b/math/legacy_dec_test.go @@ -754,7 +754,6 @@ func TestFormatDecNonDigits(t *testing.T) { } for _, value := range badCases { - value := value t.Run(value, func(t *testing.T) { s, err := math.FormatDec(value) if err == nil { diff --git a/scripts/build/build.mk b/scripts/build/build.mk index c715a855a4f9..e05e253ac7c2 100644 --- a/scripts/build/build.mk +++ b/scripts/build/build.mk @@ -12,9 +12,9 @@ MOCKS_DIR = $(CURDIR)/tests/mocks HTTPS_GIT := https://github.com/cosmos/cosmos-sdk.git DOCKER := $(shell which docker) PROJECT_NAME = $(shell git remote get-url origin | xargs basename -s .git) -COSMOS_BUILD_OPTIONS := v2 +COSMOS_BUILD_OPTIONS += ' v2' -rocksdb_version=v9.6.1 +rocksdb_version=v9.7.3 ifeq ($(findstring .,$(VERSION)),) VERSION := 0.0.0 diff --git a/server/v2/stf/README.md b/server/v2/stf/README.md index 2f2ff1ca749f..e3ae1b5376ff 100644 --- a/server/v2/stf/README.md +++ b/server/v2/stf/README.md @@ -1,34 +1,152 @@ -# State Transition Function (STF) +# STF (State Transition Function) Documentation -STF is a function that takes a state and an action as input and returns the next state. It does not assume the execution model of the application nor consensus. +This document outlines the main external calls in the STF package, their execution flows, and dependencies. -The state transition function receives a read only instance of state. It does not directly write to disk, instead it will return the state changes which has undergone within the application. The state transition function is deterministic, meaning that given the same input, it will always produce the same output. +## Table of Contents +- [DeliverBlock](#deliverblock) +- [Simulate](#simulate) +- [ValidateTx](#validatetx) +- [Query](#query) -## BranchDB +## DeliverBlock -BranchDB is a cache of all the reads done within a block, simulation or transaction validation. It takes a read-only instance of state and creates its own write instance using a btree. After all state transitions are done, the new change sets are returned to the caller. +DeliverBlock is the main state transition function that processes an entire block of transactions. -The BranchDB can be replaced and optimized for specific use cases. The implementation is as follows +```mermaid +sequenceDiagram +participant Caller +participant STF +participant State +participant PreBlock +participant BeginBlock +participant TxProcessor +participant EndBlock +Caller->>STF: DeliverBlock(ctx, block, state) +STF->>State: Branch(state) +STF->>State: SetHeaderInfo +STF->>PreBlock: doPreBlock(ctx, txs) +STF->>BeginBlock: doBeginBlock(ctx) +loop For each transaction +STF->>TxProcessor: deliverTx(ctx, state, tx) +TxProcessor->>TxProcessor: validateTx() +TxProcessor->>TxProcessor: execTx() +TxProcessor-->>STF: TxResult +end +STF->>EndBlock: doEndBlock(ctx) +STF->>EndBlock: validatorUpdates(ctx) +STF-->>Caller: BlockResponse, newState, error +``` + +### Dependencies +- Required Input: + - Context + - BlockRequest containing transactions + - ReadOnly state +- Required Components: + - PreBlock handler + - BeginBlock handler + - EndBlock handler + - Transaction validator + - Message router + - Gas meter + +## Simulate + +Simulate executes a transaction without committing changes to the actual state. -```go - type branchdb func(state store.ReaderMap) store.WriterMap +```mermaid +sequenceDiagram +participant Caller +participant STF +participant State +participant TxProcessor +Caller->>STF: Simulate(ctx, state, gasLimit, tx) +STF->>State: Branch(state) +STF->>State: GetHeaderInfo() +STF->>TxProcessor: deliverTx(ctx, state, tx, SimulateMode) +TxProcessor-->>Caller: TxResult, simulationState ``` -## GasMeter +### Dependencies +- Required Input: + - Context + - ReadOnly state + - Gas limit + - Transaction +- Required Components: + - Transaction processor + - Gas meter + - Message router -GasMeter is a utility that keeps track of the gas consumed by the state transition function. It is used to limit the amount of computation that can be done within a block. +## ValidateTx + +ValidateTx performs transaction validation without execution. + +```mermaid +sequenceDiagram +participant Caller +participant STF +participant State +participant Validator +Caller->>STF: ValidateTx(ctx, state, gasLimit, tx) +STF->>State: Branch(state) +STF->>Validator: validateTx(ctx, state, gasLimit, tx) +Validator-->>Caller: TxResult +``` -The GasMeter can be replaced and optimized for specific use cases. The implementation is as follows: +### Dependencies +- Required Input: + - Context + - ReadOnly state + - Gas limit + - Transaction +- Required Components: + - Transaction validator + - Gas meter -```go -type ( - // gasMeter is a function type that takes a gas limit as input and returns a gas.Meter. - // It is used to measure and limit the amount of gas consumed during the execution of a function. - gasMeter func(gasLimit uint64) gas.Meter +## Query - // wrapGasMeter is a function type that wraps a gas meter and a store writer map. - wrapGasMeter func(meter gas.Meter, store store.WriterMap) store.WriterMap -) +Query executes a read-only query against the application state. + +```mermaid +sequenceDiagram +participant Caller +participant STF +participant State +participant QueryRouter +Caller->>STF: Query(ctx, state, gasLimit, req) +STF->>State: Branch(state) +STF->>State: GetHeaderInfo() +STF->>QueryRouter: Invoke(ctx, req) +QueryRouter-->>Caller: Response, error ``` -THe wrapGasMeter is used in order to consume gas. Application developers can seamlsessly replace the gas meter with their own implementation in order to customize consumption of gas. +### Dependencies +- Required Input: + - Context + - ReadOnly state + - Gas limit + - Query request message +- Required Components: + - Query router + - Gas meter + - Message handlers + +## Error Handling + +All operations include error handling for: +- Context cancellation +- Gas limit exceeded +- Invalid transactions +- State operation failures +- Panic recovery (in transaction execution) + +## Gas Management + +Gas is tracked and limited for: +- Transaction validation +- Message execution +- State operations +- Query execution + +Each operation that consumes gas uses a gas meter to track usage and ensure limits are not exceeded. \ No newline at end of file diff --git a/store/snapshots/manager.go b/store/snapshots/manager.go index 17c318a94bec..c392cc03e771 100644 --- a/store/snapshots/manager.go +++ b/store/snapshots/manager.go @@ -67,7 +67,7 @@ const ( snapshotMaxItemSize = int(64e6) // SDK has no key/value size limit, so we set an arbitrary limit ) -var ErrOptsZeroSnapshotInterval = errors.New("snaphot-interval must not be 0") +var ErrOptsZeroSnapshotInterval = errors.New("snapshot-interval must not be 0") // NewManager creates a new manager. func NewManager(store *Store, opts types.SnapshotOptions, multistore types.Snapshotter, extensions map[string]types.ExtensionSnapshotter, logger storetypes.Logger) *Manager { diff --git a/systemtests/getting_started.md b/systemtests/getting_started.md index 7adc98f1b3e9..e9b5ad01539e 100644 --- a/systemtests/getting_started.md +++ b/systemtests/getting_started.md @@ -92,7 +92,7 @@ At the end is a tail from the server log printed. This can sometimes be handy wh When we have a json response, the [gjson](https://github.com/tidwall/gjson) lib can shine. It comes with jquery like syntax that makes it easy to navigation within the document. -For example `gjson.Get(raw, "supply").Array()` gives us all the childs to `supply` as an array. +For example `gjson.Get(raw, "supply").Array()` gives us all the children to `supply` as an array. Or `gjson.Get("supply.#(denom==stake).amount").Int()` for the amount of the stake token as int64 type. In order to test our assumptions in the system test, we modify the code to use `gjson` to fetch the data: diff --git a/tests/integration/auth/keeper/account_retriever_test.go b/tests/integration/auth/keeper/account_retriever_test.go deleted file mode 100644 index 823a2ade21a1..000000000000 --- a/tests/integration/auth/keeper/account_retriever_test.go +++ /dev/null @@ -1,87 +0,0 @@ -package keeper_test - -import ( - "context" - "testing" - - "github.com/stretchr/testify/require" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" - - "cosmossdk.io/math" - minttypes "cosmossdk.io/x/mint/types" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/codec" - srvconfig "github.com/cosmos/cosmos-sdk/server/config" - servergrpc "github.com/cosmos/cosmos-sdk/server/grpc" - simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth/keeper" - "github.com/cosmos/cosmos-sdk/x/auth/types" -) - -func TestAccountRetriever(t *testing.T) { - t.Skip() // TODO: https://github.com/cosmos/cosmos-sdk/issues/22825 - - f := initFixture(t, nil) - - grpcSrv := grpc.NewServer(grpc.ForceServerCodec(codec.NewProtoCodec(f.encodingCfg.InterfaceRegistry).GRPCCodec())) - - types.RegisterQueryServer(f.app.GRPCQueryRouter(), keeper.NewQueryServer(f.authKeeper)) - f.app.RegisterGRPCServer(grpcSrv) - - grpcCfg := srvconfig.DefaultConfig().GRPC - - go func() { - require.NoError(t, servergrpc.StartGRPCServer(context.Background(), f.app.Logger(), grpcCfg, grpcSrv)) - }() - - conn, err := grpc.NewClient( - grpcCfg.Address, - grpc.WithTransportCredentials(insecure.NewCredentials()), - grpc.WithDefaultCallOptions(grpc.ForceCodec(codec.NewProtoCodec(f.encodingCfg.InterfaceRegistry).GRPCCodec())), - ) - require.NoError(t, err) - - defer conn.Close() - - pubkeys := simtestutil.CreateTestPubKeys(1) - addr := sdk.AccAddress(pubkeys[0].Address()) - - newAcc := types.BaseAccount{ - Address: addr.String(), - PubKey: nil, - AccountNumber: 2, - Sequence: 7, - } - - updatedAcc := f.authKeeper.NewAccount(f.ctx, &newAcc) - f.authKeeper.SetAccount(f.ctx, updatedAcc) - - amount := sdk.NewCoins(sdk.NewCoin("stake", math.NewInt(10000))) - require.NoError(t, f.bankKeeper.MintCoins(f.ctx, minttypes.ModuleName, amount)) - require.NoError(t, f.bankKeeper.SendCoinsFromModuleToAccount(f.ctx, minttypes.ModuleName, addr, amount)) - - ar := types.AccountRetriever{} - - clientCtx := client.Context{}. - WithGRPCClient(conn). - WithAddressPrefix(sdk.Bech32MainPrefix) - - acc, err := ar.GetAccount(clientCtx, addr) - require.NoError(t, err) - require.NotNil(t, acc) - - acc, height, err := ar.GetAccountWithHeight(clientCtx, addr) - require.NoError(t, err) - require.NotNil(t, acc) - require.Equal(t, height, int64(2)) - - require.NoError(t, ar.EnsureExists(clientCtx, addr)) - - accNum, accSeq, err := ar.GetAccountNumberSequence(clientCtx, addr) - require.NoError(t, err) - require.Equal(t, accNum, uint64(0)) - require.Equal(t, accSeq, uint64(1)) -} diff --git a/tests/integration/auth/keeper/accounts_retro_compatibility_test.go b/tests/integration/auth/keeper/accounts_retro_compatibility_test.go deleted file mode 100644 index 1dcc67458a28..000000000000 --- a/tests/integration/auth/keeper/accounts_retro_compatibility_test.go +++ /dev/null @@ -1,157 +0,0 @@ -package keeper_test - -import ( - "context" - "testing" - - gogotypes "github.com/cosmos/gogoproto/types" - "github.com/stretchr/testify/require" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - - "cosmossdk.io/x/accounts/accountstd" - basev1 "cosmossdk.io/x/accounts/defaults/base/v1" - - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" - authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" -) - -var _ accountstd.Interface = mockRetroCompatAccount{} - -type mockRetroCompatAccount struct { - retroCompat *authtypes.QueryLegacyAccountResponse - address []byte -} - -func (m mockRetroCompatAccount) RegisterInitHandler(builder *accountstd.InitBuilder) { - accountstd.RegisterInitHandler(builder, func(ctx context.Context, req *gogotypes.Empty) (*gogotypes.Empty, error) { - return &gogotypes.Empty{}, nil - }) -} - -func (m mockRetroCompatAccount) RegisterExecuteHandlers(_ *accountstd.ExecuteBuilder) {} - -func (m mockRetroCompatAccount) RegisterQueryHandlers(builder *accountstd.QueryBuilder) { - if m.retroCompat == nil { - return - } - accountstd.RegisterQueryHandler(builder, func(ctx context.Context, req *authtypes.QueryLegacyAccount) (*authtypes.QueryLegacyAccountResponse, error) { - return m.retroCompat, nil - }) -} - -func TestAuthToAccountsGRPCCompat(t *testing.T) { - valid := &mockRetroCompatAccount{ - retroCompat: &authtypes.QueryLegacyAccountResponse{ - Account: &codectypes.Any{}, - Base: &authtypes.BaseAccount{ - Address: "test", - PubKey: nil, - AccountNumber: 10, - Sequence: 20, - }, - }, - } - - noInfo := &mockRetroCompatAccount{ - retroCompat: &authtypes.QueryLegacyAccountResponse{ - Account: &codectypes.Any{}, - }, - } - noImplement := &mockRetroCompatAccount{ - retroCompat: nil, - } - - accs := map[string]accountstd.Interface{ - "valid": valid, - "no_info": noInfo, - "no_implement": noImplement, - } - - f := initFixture(t, accs) - - // init three accounts - for n, a := range accs { - _, addr, err := f.accountsKeeper.Init(f.app.Context(), n, []byte("me"), &gogotypes.Empty{}, nil, nil) - require.NoError(t, err) - a.(*mockRetroCompatAccount).address = addr - } - - qs := authkeeper.NewQueryServer(f.authKeeper) - - t.Run("account supports info and account query", func(t *testing.T) { - infoResp, err := qs.AccountInfo(f.app.Context(), &authtypes.QueryAccountInfoRequest{ - Address: f.mustAddr(valid.address), - }) - require.NoError(t, err) - require.Equal(t, infoResp.Info, valid.retroCompat.Base) - - accountResp, err := qs.Account(f.app.Context(), &authtypes.QueryAccountRequest{ - Address: f.mustAddr(noInfo.address), - }) - require.NoError(t, err) - require.Equal(t, accountResp.Account, valid.retroCompat.Account) - }) - - t.Run("account only supports account query, not info", func(t *testing.T) { - _, err := qs.AccountInfo(f.app.Context(), &authtypes.QueryAccountInfoRequest{ - Address: f.mustAddr(noInfo.address), - }) - require.Error(t, err) - require.Equal(t, status.Code(err), codes.NotFound) - - resp, err := qs.Account(f.app.Context(), &authtypes.QueryAccountRequest{ - Address: f.mustAddr(noInfo.address), - }) - require.NoError(t, err) - require.Equal(t, resp.Account, valid.retroCompat.Account) - }) - - t.Run("account does not support any retro compat", func(t *testing.T) { - _, err := qs.AccountInfo(f.app.Context(), &authtypes.QueryAccountInfoRequest{ - Address: f.mustAddr(noImplement.address), - }) - require.Error(t, err) - require.Equal(t, status.Code(err), codes.NotFound) - - _, err = qs.Account(f.app.Context(), &authtypes.QueryAccountRequest{ - Address: f.mustAddr(noImplement.address), - }) - - require.Error(t, err) - require.Equal(t, status.Code(err), codes.NotFound) - }) -} - -func TestAccountsBaseAccountRetroCompat(t *testing.T) { - f := initFixture(t, nil) - // init a base acc - anyPk, err := codectypes.NewAnyWithValue(secp256k1.GenPrivKey().PubKey()) - require.NoError(t, err) - - // we init two accounts to have account num not be zero. - _, _, err = f.accountsKeeper.Init(f.app.Context(), "base", []byte("me"), &basev1.MsgInit{PubKey: anyPk}, nil, nil) - require.NoError(t, err) - - _, addr, err := f.accountsKeeper.Init(f.app.Context(), "base", []byte("me"), &basev1.MsgInit{PubKey: anyPk}, nil, nil) - require.NoError(t, err) - - // try to query it via auth - qs := authkeeper.NewQueryServer(f.authKeeper) - - r, err := qs.Account(f.app.Context(), &authtypes.QueryAccountRequest{ - Address: f.mustAddr(addr), - }) - require.NoError(t, err) - require.NotNil(t, r.Account) - - info, err := qs.AccountInfo(f.app.Context(), &authtypes.QueryAccountInfoRequest{ - Address: f.mustAddr(addr), - }) - require.NoError(t, err) - require.NotNil(t, info.Info) - require.Equal(t, info.Info.PubKey, anyPk) - require.Equal(t, info.Info.AccountNumber, uint64(1)) -} diff --git a/tests/integration/auth/keeper/app_config.go b/tests/integration/auth/keeper/app_config.go deleted file mode 100644 index 051fb5efeac7..000000000000 --- a/tests/integration/auth/keeper/app_config.go +++ /dev/null @@ -1,26 +0,0 @@ -package keeper - -import ( - _ "cosmossdk.io/x/accounts" // import as blank for app wiring - _ "cosmossdk.io/x/bank" // import as blank for app wiring - _ "cosmossdk.io/x/consensus" // import as blank for app wiring - _ "cosmossdk.io/x/staking" // import as blank for app wiring - - "github.com/cosmos/cosmos-sdk/testutil/configurator" - _ "github.com/cosmos/cosmos-sdk/x/auth" // import as blank for app wiring - _ "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 AppConfig = configurator.NewAppConfig( - configurator.AccountsModule(), - configurator.AuthModule(), - configurator.BankModule(), - configurator.VestingModule(), - configurator.StakingModule(), - configurator.TxModule(), - configurator.ValidateModule(), - configurator.ConsensusModule(), - configurator.GenutilModule(), -) diff --git a/tests/integration/auth/keeper/fixture_test.go b/tests/integration/auth/keeper/fixture_test.go deleted file mode 100644 index d549bae86cd8..000000000000 --- a/tests/integration/auth/keeper/fixture_test.go +++ /dev/null @@ -1,153 +0,0 @@ -package keeper_test - -import ( - "testing" - - cmtabcitypes "github.com/cometbft/cometbft/api/cometbft/abci/v1" - "github.com/stretchr/testify/require" - "gotest.tools/v3/assert" - - "cosmossdk.io/core/appmodule" - "cosmossdk.io/log" - storetypes "cosmossdk.io/store/types" - "cosmossdk.io/x/accounts" - "cosmossdk.io/x/accounts/accountstd" - baseaccount "cosmossdk.io/x/accounts/defaults/base" - accountsv1 "cosmossdk.io/x/accounts/v1" - "cosmossdk.io/x/bank" - bankkeeper "cosmossdk.io/x/bank/keeper" - banktypes "cosmossdk.io/x/bank/types" - minttypes "cosmossdk.io/x/mint/types" - "cosmossdk.io/x/tx/signing" - - "github.com/cosmos/cosmos-sdk/baseapp" - "github.com/cosmos/cosmos-sdk/codec" - addresscodec "github.com/cosmos/cosmos-sdk/codec/address" - codectestutil "github.com/cosmos/cosmos-sdk/codec/testutil" - "github.com/cosmos/cosmos-sdk/runtime" - "github.com/cosmos/cosmos-sdk/testutil/integration" - sdk "github.com/cosmos/cosmos-sdk/types" - moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" - "github.com/cosmos/cosmos-sdk/x/auth" - authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" - authsims "github.com/cosmos/cosmos-sdk/x/auth/simulation" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" -) - -type fixture struct { - app *integration.App - - cdc codec.Codec - ctx sdk.Context - encodingCfg moduletestutil.TestEncodingConfig - - authKeeper authkeeper.AccountKeeper - accountsKeeper accounts.Keeper - bankKeeper bankkeeper.Keeper -} - -func (f fixture) mustAddr(address []byte) string { - s, _ := f.authKeeper.AddressCodec().BytesToString(address) - return s -} - -func initFixture(t *testing.T, extraAccs map[string]accountstd.Interface) *fixture { - t.Helper() - keys := storetypes.NewKVStoreKeys( - authtypes.StoreKey, banktypes.StoreKey, accounts.StoreKey, - ) - encodingCfg := moduletestutil.MakeTestEncodingConfig(codectestutil.CodecOptions{}, auth.AppModule{}, bank.AppModule{}, accounts.AppModule{}) - cdc := encodingCfg.Codec - - logger := log.NewTestLogger(t) - - router := baseapp.NewMsgServiceRouter() - queryRouter := baseapp.NewGRPCQueryRouter() - - handler := directHandler{} - account := baseaccount.NewAccount("base", signing.NewHandlerMap(handler), baseaccount.WithSecp256K1PubKey()) - - var accs []accountstd.AccountCreatorFunc - for name, acc := range extraAccs { - f := accountstd.AddAccount(name, func(_ accountstd.Dependencies) (accountstd.Interface, error) { - return acc, nil - }) - accs = append(accs, f) - } - accountsKeeper, err := accounts.NewKeeper( - cdc, - runtime.NewEnvironment(runtime.NewKVStoreService(keys[accounts.StoreKey]), log.NewNopLogger(), runtime.EnvWithQueryRouterService(queryRouter), runtime.EnvWithMsgRouterService(router)), - addresscodec.NewBech32Codec("cosmos"), - cdc.InterfaceRegistry(), - nil, - append(accs, account)..., - ) - assert.NilError(t, err) - accountsv1.RegisterQueryServer(queryRouter, accounts.NewQueryServer(accountsKeeper)) - - authority := authtypes.NewModuleAddress("gov") - - authKeeper := authkeeper.NewAccountKeeper( - runtime.NewEnvironment(runtime.NewKVStoreService(keys[authtypes.StoreKey]), log.NewNopLogger()), - cdc, - authtypes.ProtoBaseAccount, - accountsKeeper, - map[string][]string{minttypes.ModuleName: {authtypes.Minter}}, - addresscodec.NewBech32Codec(sdk.Bech32MainPrefix), - sdk.Bech32MainPrefix, - authority.String(), - ) - - blockedAddresses := map[string]bool{ - authKeeper.GetAuthority(): false, - } - bankKeeper := bankkeeper.NewBaseKeeper( - runtime.NewEnvironment(runtime.NewKVStoreService(keys[banktypes.StoreKey]), log.NewNopLogger()), - cdc, - authKeeper, - blockedAddresses, - authority.String(), - ) - - accountsModule := accounts.NewAppModule(cdc, accountsKeeper) - authModule := auth.NewAppModule(cdc, authKeeper, accountsKeeper, authsims.RandomGenesisAccounts, nil) - bankModule := bank.NewAppModule(cdc, bankKeeper, authKeeper) - - integrationApp := integration.NewIntegrationApp(logger, keys, cdc, - encodingCfg.InterfaceRegistry.SigningContext().AddressCodec(), - encodingCfg.InterfaceRegistry.SigningContext().ValidatorAddressCodec(), - map[string]appmodule.AppModule{ - accounts.ModuleName: accountsModule, - authtypes.ModuleName: authModule, - banktypes.ModuleName: bankModule, - }, router, queryRouter) - - authtypes.RegisterInterfaces(cdc.InterfaceRegistry()) - banktypes.RegisterInterfaces(cdc.InterfaceRegistry()) - - authtypes.RegisterMsgServer(integrationApp.MsgServiceRouter(), authkeeper.NewMsgServerImpl(authKeeper)) - authtypes.RegisterQueryServer(integrationApp.QueryHelper(), authkeeper.NewQueryServer(authKeeper)) - - banktypes.RegisterMsgServer(router, bankkeeper.NewMsgServerImpl(bankKeeper)) - - // commit and finalize block - defer func() { - _, err := integrationApp.Commit() - if err != nil { - panic(err) - } - }() - height := integrationApp.LastBlockHeight() + 1 - _, err = integrationApp.FinalizeBlock(&cmtabcitypes.FinalizeBlockRequest{Height: height, DecidedLastCommit: cmtabcitypes.CommitInfo{Votes: []cmtabcitypes.VoteInfo{{}}}}) - require.NoError(t, err) - - return &fixture{ - app: integrationApp, - cdc: cdc, - ctx: sdk.UnwrapSDKContext(integrationApp.Context()), - accountsKeeper: accountsKeeper, - authKeeper: authKeeper, - bankKeeper: bankKeeper, - encodingCfg: encodingCfg, - } -} diff --git a/tests/integration/auth/keeper/keeper_bench_test.go b/tests/integration/auth/keeper/keeper_bench_test.go deleted file mode 100644 index 09bde3bd7e80..000000000000 --- a/tests/integration/auth/keeper/keeper_bench_test.go +++ /dev/null @@ -1,67 +0,0 @@ -package keeper_test - -import ( - "testing" - - "github.com/stretchr/testify/require" - - "cosmossdk.io/depinject" - "cosmossdk.io/log" - - authTest "github.com/cosmos/cosmos-sdk/tests/integration/auth/keeper" - simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth/keeper" -) - -func BenchmarkAccountMapperGetAccountFound(b *testing.B) { - b.ReportAllocs() - var accountKeeper keeper.AccountKeeper - app, err := simtestutil.Setup( - depinject.Configs( - depinject.Supply(log.NewNopLogger()), - authTest.AppConfig, - ), - &accountKeeper, - ) - require.NoError(b, err) - - ctx := app.BaseApp.NewContext(false) - - // assumes b.N < 2**24 - for i := 0; i < b.N; i++ { - arr := []byte{byte((i & 0xFF0000) >> 16), byte((i & 0xFF00) >> 8), byte(i & 0xFF)} - addr := sdk.AccAddress(arr) - acc := accountKeeper.NewAccountWithAddress(ctx, addr) - accountKeeper.SetAccount(ctx, acc) - } - - b.ResetTimer() - for i := 0; i < b.N; i++ { - arr := []byte{byte((i & 0xFF0000) >> 16), byte((i & 0xFF00) >> 8), byte(i & 0xFF)} - accountKeeper.GetAccount(ctx, sdk.AccAddress(arr)) - } -} - -func BenchmarkAccountMapperSetAccount(b *testing.B) { - b.ReportAllocs() - var accountKeeper keeper.AccountKeeper - app, err := simtestutil.Setup( - depinject.Configs( - depinject.Supply(log.NewNopLogger()), - authTest.AppConfig, - ), &accountKeeper) - require.NoError(b, err) - - ctx := app.BaseApp.NewContext(false) - - b.ResetTimer() - - // assumes b.N < 2**24 - for i := 0; i < b.N; i++ { - arr := []byte{byte((i & 0xFF0000) >> 16), byte((i & 0xFF00) >> 8), byte(i & 0xFF)} - addr := sdk.AccAddress(arr) - acc := accountKeeper.NewAccountWithAddress(ctx, addr) - accountKeeper.SetAccount(ctx, acc) - } -} diff --git a/tests/integration/auth/keeper/migrate_x_accounts_test.go b/tests/integration/auth/keeper/migrate_x_accounts_test.go deleted file mode 100644 index b7da225c84e6..000000000000 --- a/tests/integration/auth/keeper/migrate_x_accounts_test.go +++ /dev/null @@ -1,100 +0,0 @@ -package keeper_test - -import ( - "testing" - - "github.com/stretchr/testify/require" - - basev1 "cosmossdk.io/x/accounts/defaults/base/v1" - - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" -) - -func TestMigrateToAccounts(t *testing.T) { - f := initFixture(t, nil) - - // create a module account - modAcc := &authtypes.ModuleAccount{ - BaseAccount: &authtypes.BaseAccount{ - Address: f.mustAddr([]byte("cookies")), - PubKey: nil, - AccountNumber: 0, - Sequence: 0, - }, - Name: "cookies", - Permissions: nil, - } - updatedMod := f.authKeeper.NewAccount(f.app.Context(), modAcc) - f.authKeeper.SetAccount(f.app.Context(), updatedMod) - - // create account - msgSrv := authkeeper.NewMsgServerImpl(f.authKeeper) - privKey := secp256k1.GenPrivKey() - addr := sdk.AccAddress(privKey.PubKey().Address()) - - acc := f.authKeeper.NewAccountWithAddress(f.app.Context(), addr) - require.NoError(t, acc.SetPubKey(privKey.PubKey())) - f.authKeeper.SetAccount(f.app.Context(), acc) - - t.Run("account does not exist", func(t *testing.T) { - resp, err := msgSrv.MigrateAccount(f.app.Context(), &authtypes.MsgMigrateAccount{ - Signer: f.mustAddr([]byte("notexist")), - AccountType: "base", - AccountInitMsg: nil, - }) - require.Nil(t, resp) - require.ErrorIs(t, err, sdkerrors.ErrUnknownAddress) - }) - - t.Run("invalid account type", func(t *testing.T) { - resp, err := msgSrv.MigrateAccount(f.app.Context(), &authtypes.MsgMigrateAccount{ - Signer: f.mustAddr(updatedMod.GetAddress()), - AccountType: "base", - AccountInitMsg: nil, - }) - require.Nil(t, resp) - require.ErrorContains(t, err, "only BaseAccount can be migrated") - }) - - t.Run("success", func(t *testing.T) { - pk, err := codectypes.NewAnyWithValue(privKey.PubKey()) - require.NoError(t, err) - - migrateMsg := &basev1.MsgInit{ - PubKey: pk, - InitSequence: 100, - } - - initMsgAny, err := codectypes.NewAnyWithValue(migrateMsg) - require.NoError(t, err) - - resp, err := msgSrv.MigrateAccount(f.app.Context(), &authtypes.MsgMigrateAccount{ - Signer: f.mustAddr(addr), - AccountType: "base", - AccountInitMsg: initMsgAny, - }) - require.NoError(t, err) - - // check response semantics. - require.Equal(t, resp.InitResponse.TypeUrl, "/cosmos.accounts.defaults.base.v1.MsgInitResponse") - require.NotNil(t, resp.InitResponse.Value) - - // check the account was removed from x/auth and added to x/accounts - require.Nil(t, f.authKeeper.GetAccount(f.app.Context(), addr)) - require.True(t, f.accountsKeeper.IsAccountsModuleAccount(f.app.Context(), addr)) - - // check the init information is correctly propagated. - seq, err := f.accountsKeeper.Query(f.app.Context(), addr, &basev1.QuerySequence{}) - require.NoError(t, err) - require.Equal(t, migrateMsg.InitSequence, seq.(*basev1.QuerySequenceResponse).Sequence) - - pkResp, err := f.accountsKeeper.Query(f.app.Context(), addr, &basev1.QueryPubKey{}) - require.NoError(t, err) - require.Equal(t, migrateMsg.PubKey, pkResp.(*basev1.QueryPubKeyResponse).PubKey) - }) -} diff --git a/tests/integration/auth/keeper/module_test.go b/tests/integration/auth/keeper/module_test.go deleted file mode 100644 index 3937da28912c..000000000000 --- a/tests/integration/auth/keeper/module_test.go +++ /dev/null @@ -1,30 +0,0 @@ -package keeper_test - -import ( - "testing" - - "github.com/stretchr/testify/require" - - "cosmossdk.io/depinject" - "cosmossdk.io/log" - - authTest "github.com/cosmos/cosmos-sdk/tests/integration/auth/keeper" - simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" - "github.com/cosmos/cosmos-sdk/x/auth/keeper" - "github.com/cosmos/cosmos-sdk/x/auth/types" -) - -func TestItCreatesModuleAccountOnInitBlock(t *testing.T) { - var accountKeeper keeper.AccountKeeper - app, err := simtestutil.SetupAtGenesis( - depinject.Configs( - authTest.AppConfig, - depinject.Supply(log.NewNopLogger()), - ), - &accountKeeper) - require.NoError(t, err) - - ctx := app.BaseApp.NewContext(false) - acc := accountKeeper.GetAccount(ctx, types.NewModuleAddress(types.FeeCollectorName)) - require.NotNil(t, acc) -} diff --git a/tests/integration/auth/keeper/msg_server_test.go b/tests/integration/auth/keeper/msg_server_test.go deleted file mode 100644 index d42468c9c674..000000000000 --- a/tests/integration/auth/keeper/msg_server_test.go +++ /dev/null @@ -1,168 +0,0 @@ -package keeper_test - -import ( - "context" - "fmt" - "strings" - "testing" - - "gotest.tools/v3/assert" - - signingv1beta1 "cosmossdk.io/api/cosmos/tx/signing/v1beta1" - sdkmath "cosmossdk.io/math" - "cosmossdk.io/x/bank/testutil" - banktypes "cosmossdk.io/x/bank/types" - "cosmossdk.io/x/tx/signing" - - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/cosmos-sdk/testutil/integration" - simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" - sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" -) - -var _ signing.SignModeHandler = directHandler{} - -type directHandler struct{} - -func (s directHandler) Mode() signingv1beta1.SignMode { - return signingv1beta1.SignMode_SIGN_MODE_DIRECT -} - -func (s directHandler) GetSignBytes(_ context.Context, _ signing.SignerData, _ signing.TxData) ([]byte, error) { - panic("not implemented") -} - -func TestAsyncExec(t *testing.T) { - t.Parallel() - f := initFixture(t, nil) - - addrs := simtestutil.CreateIncrementalAccounts(2) - coins := sdk.NewCoins(sdk.NewCoin("stake", sdkmath.NewInt(10))) - - assert.NilError(t, testutil.FundAccount(f.app.Context(), f.bankKeeper, addrs[0], sdk.NewCoins(sdk.NewInt64Coin("stake", 500)))) - - msg := &banktypes.MsgSend{ - FromAddress: addrs[0].String(), - ToAddress: addrs[1].String(), - Amount: coins, - } - msg2 := &banktypes.MsgSend{ - FromAddress: addrs[1].String(), - ToAddress: addrs[0].String(), - Amount: coins, - } - failingMsg := &banktypes.MsgSend{ - FromAddress: addrs[0].String(), - ToAddress: addrs[1].String(), - Amount: sdk.NewCoins(sdk.NewCoin("stake", sdkmath.ZeroInt())), // No amount specified - } - - msgAny, err := codectypes.NewAnyWithValue(msg) - assert.NilError(t, err) - - msgAny2, err := codectypes.NewAnyWithValue(msg2) - assert.NilError(t, err) - - failingMsgAny, err := codectypes.NewAnyWithValue(failingMsg) - assert.NilError(t, err) - - testCases := []struct { - name string - req *authtypes.MsgNonAtomicExec - expectErr bool - expErrMsg string - }{ - { - name: "empty signer address", - req: &authtypes.MsgNonAtomicExec{ - Signer: "", - Msgs: []*codectypes.Any{}, - }, - expectErr: true, - expErrMsg: "empty signer address string is not allowed", - }, - { - name: "invalid signer address", - req: &authtypes.MsgNonAtomicExec{ - Signer: "invalid", - Msgs: []*codectypes.Any{}, - }, - expectErr: true, - expErrMsg: "invalid signer address", - }, - { - name: "empty msgs", - req: &authtypes.MsgNonAtomicExec{ - Signer: addrs[0].String(), - Msgs: []*codectypes.Any{}, - }, - expectErr: true, - expErrMsg: "messages cannot be empty", - }, - { - name: "valid msg", - req: &authtypes.MsgNonAtomicExec{ - Signer: addrs[0].String(), - Msgs: []*codectypes.Any{msgAny}, - }, - expectErr: false, - }, - { - name: "multiple messages being executed", - req: &authtypes.MsgNonAtomicExec{ - Signer: addrs[0].String(), - Msgs: []*codectypes.Any{msgAny, msgAny}, - }, - expectErr: false, - }, - { - name: "multiple messages with different signers", - req: &authtypes.MsgNonAtomicExec{ - Signer: addrs[0].String(), - Msgs: []*codectypes.Any{msgAny, msgAny2}, - }, - expectErr: false, - expErrMsg: "unauthorized: sender does not match expected sender", - }, - { - name: "multi msg with one failing being executed", - req: &authtypes.MsgNonAtomicExec{ - Signer: addrs[0].String(), - Msgs: []*codectypes.Any{msgAny, failingMsgAny}, - }, - expectErr: false, - expErrMsg: "invalid coins", - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - res, err := f.app.RunMsg( - tc.req, - integration.WithAutomaticFinalizeBlock(), - integration.WithAutomaticCommit(), - ) - if tc.expectErr { - assert.ErrorContains(t, err, tc.expErrMsg) - } else { - assert.NilError(t, err) - assert.Assert(t, res != nil) - - // check the result - result := authtypes.MsgNonAtomicExecResponse{} - err = f.cdc.Unmarshal(res.Value, &result) - assert.NilError(t, err) - - if tc.expErrMsg != "" { - for _, res := range result.Results { - if res.Error != "" { - assert.Assert(t, strings.Contains(res.Error, tc.expErrMsg), fmt.Sprintf("res.Error %s does not contain %s", res.Error, tc.expErrMsg)) - } - continue - } - } - } - }) - } -} diff --git a/tests/integration/bank/keeper/deterministic_test.go b/tests/integration/bank/keeper/deterministic_test.go deleted file mode 100644 index 2a7af76a866f..000000000000 --- a/tests/integration/bank/keeper/deterministic_test.go +++ /dev/null @@ -1,560 +0,0 @@ -package keeper_test - -import ( - "context" - "testing" - - "go.uber.org/mock/gomock" - "gotest.tools/v3/assert" - "pgregory.net/rapid" - - "cosmossdk.io/core/appmodule" - "cosmossdk.io/log" - "cosmossdk.io/math" - storetypes "cosmossdk.io/store/types" - "cosmossdk.io/x/bank" - "cosmossdk.io/x/bank/keeper" - banktestutil "cosmossdk.io/x/bank/testutil" - banktypes "cosmossdk.io/x/bank/types" - _ "cosmossdk.io/x/consensus" - minttypes "cosmossdk.io/x/mint/types" - _ "cosmossdk.io/x/staking" - - "github.com/cosmos/cosmos-sdk/baseapp" - addresscodec "github.com/cosmos/cosmos-sdk/codec/address" - codectestutil "github.com/cosmos/cosmos-sdk/codec/testutil" - "github.com/cosmos/cosmos-sdk/runtime" - "github.com/cosmos/cosmos-sdk/testutil/integration" - "github.com/cosmos/cosmos-sdk/testutil/testdata" - sdk "github.com/cosmos/cosmos-sdk/types" - moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" - "github.com/cosmos/cosmos-sdk/x/auth" - authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" - authsims "github.com/cosmos/cosmos-sdk/x/auth/simulation" - authtestutil "github.com/cosmos/cosmos-sdk/x/auth/testutil" - _ "github.com/cosmos/cosmos-sdk/x/auth/tx/config" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" -) - -var ( - denomRegex = `[a-zA-Z][a-zA-Z0-9/:._-]{2,127}` - addr1 = sdk.MustAccAddressFromBech32("cosmos139f7kncmglres2nf3h4hc4tade85ekfr8sulz5") - coin1 = sdk.NewCoin("denom", math.NewInt(10)) - metadataAtom = banktypes.Metadata{ - Description: "The native staking token of the Cosmos Hub.", - DenomUnits: []*banktypes.DenomUnit{ - { - Denom: "uatom", - Exponent: 0, - Aliases: []string{"microatom"}, - }, - { - Denom: "atom", - Exponent: 6, - Aliases: []string{"ATOM"}, - }, - }, - Base: "uatom", - Display: "atom", - } -) - -type deterministicFixture struct { - ctx sdk.Context - bankKeeper keeper.BaseKeeper - queryClient banktypes.QueryClient -} - -func initDeterministicFixture(t *testing.T) *deterministicFixture { - t.Helper() - keys := storetypes.NewKVStoreKeys(authtypes.StoreKey, banktypes.StoreKey) - encodingCfg := moduletestutil.MakeTestEncodingConfig(codectestutil.CodecOptions{}, auth.AppModule{}, bank.AppModule{}) - cdc := encodingCfg.Codec - - logger := log.NewTestLogger(t) - authority := authtypes.NewModuleAddress("gov") - - maccPerms := map[string][]string{ - minttypes.ModuleName: {authtypes.Minter}, - } - - // gomock initializations - ctrl := gomock.NewController(t) - acctsModKeeper := authtestutil.NewMockAccountsModKeeper(ctrl) - accNum := uint64(0) - acctsModKeeper.EXPECT().NextAccountNumber(gomock.Any()).AnyTimes().DoAndReturn(func(ctx context.Context) (uint64, error) { - currentNum := accNum - accNum++ - return currentNum, nil - }) - - accountKeeper := authkeeper.NewAccountKeeper( - runtime.NewEnvironment(runtime.NewKVStoreService(keys[authtypes.StoreKey]), log.NewNopLogger()), - cdc, - authtypes.ProtoBaseAccount, - acctsModKeeper, - maccPerms, - addresscodec.NewBech32Codec(sdk.Bech32MainPrefix), - sdk.Bech32MainPrefix, - authority.String(), - ) - - blockedAddresses := map[string]bool{ - accountKeeper.GetAuthority(): false, - } - bankKeeper := keeper.NewBaseKeeper( - runtime.NewEnvironment(runtime.NewKVStoreService(keys[banktypes.StoreKey]), log.NewNopLogger()), - cdc, - accountKeeper, - blockedAddresses, - authority.String(), - ) - - authModule := auth.NewAppModule(cdc, accountKeeper, acctsModKeeper, authsims.RandomGenesisAccounts, nil) - bankModule := bank.NewAppModule(cdc, bankKeeper, accountKeeper) - - integrationApp := integration.NewIntegrationApp(logger, keys, cdc, - encodingCfg.InterfaceRegistry.SigningContext().AddressCodec(), - encodingCfg.InterfaceRegistry.SigningContext().ValidatorAddressCodec(), - map[string]appmodule.AppModule{ - authtypes.ModuleName: authModule, - banktypes.ModuleName: bankModule, - }, - baseapp.NewMsgServiceRouter(), - baseapp.NewGRPCQueryRouter(), - ) - - sdkCtx := sdk.UnwrapSDKContext(integrationApp.Context()) - - // Register MsgServer and QueryServer - banktypes.RegisterMsgServer(integrationApp.MsgServiceRouter(), keeper.NewMsgServerImpl(bankKeeper)) - banktypes.RegisterQueryServer(integrationApp.QueryHelper(), keeper.NewQuerier(&bankKeeper)) - - qr := integrationApp.QueryHelper() - queryClient := banktypes.NewQueryClient(qr) - - f := deterministicFixture{ - ctx: sdkCtx, - bankKeeper: bankKeeper, - queryClient: queryClient, - } - - return &f -} - -func fundAccount(f *deterministicFixture, addr sdk.AccAddress, coin ...sdk.Coin) { - err := banktestutil.FundAccount(f.ctx, f.bankKeeper, addr, sdk.NewCoins(coin...)) - assert.NilError(&testing.T{}, err) -} - -func getCoin(rt *rapid.T) sdk.Coin { - return sdk.NewCoin( - rapid.StringMatching(denomRegex).Draw(rt, "denom"), - math.NewInt(rapid.Int64Min(1).Draw(rt, "amount")), - ) -} - -func TestGRPCQueryBalance(t *testing.T) { - t.Parallel() - f := initDeterministicFixture(t) - - rapid.Check(t, func(rt *rapid.T) { - addr := testdata.AddressGenerator(rt).Draw(rt, "address") - coin := getCoin(rt) - fundAccount(f, addr, coin) - - addrStr, err := codectestutil.CodecOptions{}.GetAddressCodec().BytesToString(addr) - assert.NilError(t, err) - - req := banktypes.NewQueryBalanceRequest(addrStr, coin.GetDenom()) - - testdata.DeterministicIterations(t, f.ctx, req, f.queryClient.Balance, 0, true) - }) - - addr1Str, err := codectestutil.CodecOptions{}.GetAddressCodec().BytesToString(addr1) - assert.NilError(t, err) - - fundAccount(f, addr1, coin1) - req := banktypes.NewQueryBalanceRequest(addr1Str, coin1.GetDenom()) - testdata.DeterministicIterations(t, f.ctx, req, f.queryClient.Balance, 1087, false) -} - -func TestGRPCQueryAllBalances(t *testing.T) { - t.Parallel() - f := initDeterministicFixture(t) - addressCodec := codectestutil.CodecOptions{}.GetAddressCodec() - - rapid.Check(t, func(rt *rapid.T) { - addr := testdata.AddressGenerator(rt).Draw(rt, "address") - numCoins := rapid.IntRange(1, 10).Draw(rt, "num-count") - coins := make(sdk.Coins, 0, numCoins) - - addrStr, err := addressCodec.BytesToString(addr) - assert.NilError(t, err) - - for i := 0; i < numCoins; i++ { - coin := getCoin(rt) - if exists, _ := coins.Find(coin.Denom); exists { - t.Skip("duplicate denom") - } - // NewCoins sorts the denoms - coins = sdk.NewCoins(append(coins, coin)...) - } - - fundAccount(f, addr, coins...) - - req := banktypes.NewQueryAllBalancesRequest(addrStr, testdata.PaginationGenerator(rt, uint64(numCoins)).Draw(rt, "pagination"), false) - testdata.DeterministicIterations(t, f.ctx, req, f.queryClient.AllBalances, 0, true) - }) - - coins := sdk.NewCoins( - sdk.NewCoin("stake", math.NewInt(10)), - sdk.NewCoin("denom", math.NewInt(100)), - ) - - fundAccount(f, addr1, coins...) - addr1Str, err := addressCodec.BytesToString(addr1) - assert.NilError(t, err) - - req := banktypes.NewQueryAllBalancesRequest(addr1Str, nil, false) - - testdata.DeterministicIterations(t, f.ctx, req, f.queryClient.AllBalances, 357, false) -} - -func TestGRPCQuerySpendableBalances(t *testing.T) { - t.Parallel() - f := initDeterministicFixture(t) - - rapid.Check(t, func(rt *rapid.T) { - addr := testdata.AddressGenerator(rt).Draw(rt, "address") - addrStr, err := codectestutil.CodecOptions{}.GetAddressCodec().BytesToString(addr) - assert.NilError(t, err) - - // Denoms must be unique, otherwise sdk.NewCoins will panic. - denoms := rapid.SliceOfNDistinct(rapid.StringMatching(denomRegex), 1, 10, rapid.ID[string]).Draw(rt, "denoms") - coins := make(sdk.Coins, 0, len(denoms)) - for _, denom := range denoms { - coin := sdk.NewCoin( - denom, - math.NewInt(rapid.Int64Min(1).Draw(rt, "amount")), - ) - - // NewCoins sorts the denoms - coins = sdk.NewCoins(append(coins, coin)...) - } - - err = banktestutil.FundAccount(f.ctx, f.bankKeeper, addr, coins) - assert.NilError(t, err) - - req := banktypes.NewQuerySpendableBalancesRequest(addrStr, testdata.PaginationGenerator(rt, uint64(len(denoms))).Draw(rt, "pagination")) - testdata.DeterministicIterations(t, f.ctx, req, f.queryClient.SpendableBalances, 0, true) - }) - - coins := sdk.NewCoins( - sdk.NewCoin("stake", math.NewInt(10)), - sdk.NewCoin("denom", math.NewInt(100)), - ) - - err := banktestutil.FundAccount(f.ctx, f.bankKeeper, addr1, coins) - assert.NilError(t, err) - - addr1Str, err := codectestutil.CodecOptions{}.GetAddressCodec().BytesToString(addr1) - assert.NilError(t, err) - - req := banktypes.NewQuerySpendableBalancesRequest(addr1Str, nil) - testdata.DeterministicIterations(t, f.ctx, req, f.queryClient.SpendableBalances, 1420, false) -} - -func TestGRPCQueryTotalSupply(t *testing.T) { - t.Parallel() - f := initDeterministicFixture(t) - - res, err := f.queryClient.TotalSupply(f.ctx, &banktypes.QueryTotalSupplyRequest{}) - assert.NilError(t, err) - initialSupply := res.GetSupply() - - rapid.Check(t, func(rt *rapid.T) { - numCoins := rapid.IntRange(1, 3).Draw(rt, "num-count") - coins := make(sdk.Coins, 0, numCoins) - - for i := 0; i < numCoins; i++ { - coin := sdk.NewCoin( - rapid.StringMatching(denomRegex).Draw(rt, "denom"), - math.NewInt(rapid.Int64Min(1).Draw(rt, "amount")), - ) - - coins = coins.Add(coin) - } - - assert.NilError(t, f.bankKeeper.MintCoins(f.ctx, minttypes.ModuleName, coins)) - - initialSupply = initialSupply.Add(coins...) - - req := &banktypes.QueryTotalSupplyRequest{ - Pagination: testdata.PaginationGenerator(rt, uint64(len(initialSupply))).Draw(rt, "pagination"), - } - - testdata.DeterministicIterations(t, f.ctx, req, f.queryClient.TotalSupply, 0, true) - }) - - f = initDeterministicFixture(t) // reset - - coins := sdk.NewCoins( - sdk.NewCoin("foo", math.NewInt(10)), - sdk.NewCoin("bar", math.NewInt(100)), - ) - - assert.NilError(t, f.bankKeeper.MintCoins(f.ctx, minttypes.ModuleName, coins)) - - req := &banktypes.QueryTotalSupplyRequest{} - testdata.DeterministicIterations(t, f.ctx, req, f.queryClient.TotalSupply, 150, false) -} - -func TestGRPCQueryTotalSupplyOf(t *testing.T) { - t.Parallel() - f := initDeterministicFixture(t) - - rapid.Check(t, func(rt *rapid.T) { - coin := sdk.NewCoin( - rapid.StringMatching(denomRegex).Draw(rt, "denom"), - math.NewInt(rapid.Int64Min(1).Draw(rt, "amount")), - ) - - assert.NilError(t, f.bankKeeper.MintCoins(f.ctx, minttypes.ModuleName, sdk.NewCoins(coin))) - - req := &banktypes.QuerySupplyOfRequest{Denom: coin.GetDenom()} - testdata.DeterministicIterations(t, f.ctx, req, f.queryClient.SupplyOf, 0, true) - }) - - coin := sdk.NewCoin("bar", math.NewInt(100)) - - assert.NilError(t, f.bankKeeper.MintCoins(f.ctx, minttypes.ModuleName, sdk.NewCoins(coin))) - req := &banktypes.QuerySupplyOfRequest{Denom: coin.GetDenom()} - testdata.DeterministicIterations(t, f.ctx, req, f.queryClient.SupplyOf, 1021, false) -} - -func TestGRPCQueryParams(t *testing.T) { - t.Parallel() - f := initDeterministicFixture(t) - - rapid.Check(t, func(rt *rapid.T) { - enabledStatus := banktypes.SendEnabled{ - Denom: rapid.StringMatching(denomRegex).Draw(rt, "denom"), - Enabled: rapid.Bool().Draw(rt, "status"), - } - - params := banktypes.Params{ - SendEnabled: []*banktypes.SendEnabled{&enabledStatus}, - DefaultSendEnabled: rapid.Bool().Draw(rt, "send"), - } - - err := f.bankKeeper.SetParams(f.ctx, params) - assert.NilError(t, err) - - req := &banktypes.QueryParamsRequest{} - testdata.DeterministicIterations(t, f.ctx, req, f.queryClient.Params, 0, true) - }) - - enabledStatus := banktypes.SendEnabled{ - Denom: "denom", - Enabled: true, - } - - params := banktypes.Params{ - SendEnabled: []*banktypes.SendEnabled{&enabledStatus}, - DefaultSendEnabled: false, - } - - err := f.bankKeeper.SetParams(f.ctx, params) - assert.NilError(t, err) - req := &banktypes.QueryParamsRequest{} - testdata.DeterministicIterations(t, f.ctx, req, f.queryClient.Params, 1003, false) -} - -func createAndReturnMetadatas(t *rapid.T, count int) []banktypes.Metadata { - denomsMetadata := make([]banktypes.Metadata, 0, count) - for i := 0; i < count; i++ { - - denom := rapid.StringMatching(denomRegex).Draw(t, "denom") - - aliases := rapid.SliceOf(rapid.String()).Draw(t, "aliases") - // In the GRPC server code, empty arrays are returned as nil - if len(aliases) == 0 { - aliases = nil - } - - metadata := banktypes.Metadata{ - Description: rapid.StringN(1, 100, 100).Draw(t, "desc"), - DenomUnits: []*banktypes.DenomUnit{ - { - Denom: denom, - Exponent: rapid.Uint32().Draw(t, "exponent"), - Aliases: aliases, - }, - }, - Base: denom, - Display: denom, - Name: rapid.String().Draw(t, "name"), - Symbol: rapid.String().Draw(t, "symbol"), - URI: rapid.String().Draw(t, "uri"), - URIHash: rapid.String().Draw(t, "uri-hash"), - } - - denomsMetadata = append(denomsMetadata, metadata) - } - - return denomsMetadata -} - -func TestGRPCDenomsMetadata(t *testing.T) { - t.Parallel() - f := initDeterministicFixture(t) - - rapid.Check(t, func(rt *rapid.T) { - count := rapid.IntRange(1, 3).Draw(rt, "count") - denomsMetadata := createAndReturnMetadatas(rt, count) - assert.Assert(t, len(denomsMetadata) == count) - - for i := 0; i < count; i++ { - f.bankKeeper.SetDenomMetaData(f.ctx, denomsMetadata[i]) - } - - req := &banktypes.QueryDenomsMetadataRequest{ - Pagination: testdata.PaginationGenerator(rt, uint64(count)).Draw(rt, "pagination"), - } - - testdata.DeterministicIterations(t, f.ctx, req, f.queryClient.DenomsMetadata, 0, true) - }) - - f = initDeterministicFixture(t) // reset - - f.bankKeeper.SetDenomMetaData(f.ctx, metadataAtom) - - req := &banktypes.QueryDenomsMetadataRequest{} - testdata.DeterministicIterations(t, f.ctx, req, f.queryClient.DenomsMetadata, 660, false) -} - -func TestGRPCDenomMetadata(t *testing.T) { - t.Parallel() - f := initDeterministicFixture(t) - - rapid.Check(t, func(rt *rapid.T) { - denomMetadata := createAndReturnMetadatas(rt, 1) - assert.Assert(t, len(denomMetadata) == 1) - f.bankKeeper.SetDenomMetaData(f.ctx, denomMetadata[0]) - - req := &banktypes.QueryDenomMetadataRequest{ - Denom: denomMetadata[0].Base, - } - - testdata.DeterministicIterations(t, f.ctx, req, f.queryClient.DenomMetadata, 0, true) - }) - - f.bankKeeper.SetDenomMetaData(f.ctx, metadataAtom) - - req := &banktypes.QueryDenomMetadataRequest{ - Denom: metadataAtom.Base, - } - - testdata.DeterministicIterations(t, f.ctx, req, f.queryClient.DenomMetadata, 1300, false) -} - -func TestGRPCSendEnabled(t *testing.T) { - t.Parallel() - f := initDeterministicFixture(t) - - allDenoms := []string{} - - rapid.Check(t, func(rt *rapid.T) { - count := rapid.IntRange(0, 10).Draw(rt, "count") - denoms := make([]string, 0, count) - - for i := 0; i < count; i++ { - coin := banktypes.SendEnabled{ - Denom: rapid.StringMatching(denomRegex).Draw(rt, "denom"), - Enabled: rapid.Bool().Draw(rt, "enabled-status"), - } - - f.bankKeeper.SetSendEnabled(f.ctx, coin.Denom, coin.Enabled) - denoms = append(denoms, coin.Denom) - } - - allDenoms = append(allDenoms, denoms...) - - req := &banktypes.QuerySendEnabledRequest{ - Denoms: denoms, - // Pagination is only taken into account when `denoms` is an empty array - Pagination: testdata.PaginationGenerator(rt, uint64(len(allDenoms))).Draw(rt, "pagination"), - } - testdata.DeterministicIterations(t, f.ctx, req, f.queryClient.SendEnabled, 0, true) - }) - - coin1 := banktypes.SendEnabled{ - Denom: "falsecoin", - Enabled: false, - } - coin2 := banktypes.SendEnabled{ - Denom: "truecoin", - Enabled: true, - } - - f.bankKeeper.SetSendEnabled(f.ctx, coin1.Denom, false) - f.bankKeeper.SetSendEnabled(f.ctx, coin2.Denom, true) - - req := &banktypes.QuerySendEnabledRequest{ - Denoms: []string{coin1.GetDenom(), coin2.GetDenom()}, - } - - testdata.DeterministicIterations(t, f.ctx, req, f.queryClient.SendEnabled, 4063, false) -} - -func TestGRPCDenomOwners(t *testing.T) { - t.Parallel() - f := initDeterministicFixture(t) - - rapid.Check(t, func(rt *rapid.T) { - denom := rapid.StringMatching(denomRegex).Draw(rt, "denom") - numAddr := rapid.IntRange(1, 10).Draw(rt, "number-address") - for i := 0; i < numAddr; i++ { - addr := testdata.AddressGenerator(rt).Draw(rt, "address") - - coin := sdk.NewCoin( - denom, - math.NewInt(rapid.Int64Min(1).Draw(rt, "amount")), - ) - - err := banktestutil.FundAccount(f.ctx, f.bankKeeper, addr, sdk.NewCoins(coin)) - assert.NilError(t, err) - } - - req := &banktypes.QueryDenomOwnersRequest{ - Denom: denom, - Pagination: testdata.PaginationGenerator(rt, uint64(numAddr)).Draw(rt, "pagination"), - } - testdata.DeterministicIterations(t, f.ctx, req, f.queryClient.DenomOwners, 0, true) - }) - - denomOwners := []*banktypes.DenomOwner{ - { - Address: "cosmos1qg65a9q6k2sqq7l3ycp428sqqpmqcucgzze299", - Balance: coin1, - }, - { - Address: "cosmos1qglnsqgpq48l7qqzgs8qdshr6fh3gqq9ej3qut", - Balance: coin1, - }, - } - - for i := 0; i < len(denomOwners); i++ { - addr, err := sdk.AccAddressFromBech32(denomOwners[i].Address) - assert.NilError(t, err) - - err = banktestutil.FundAccount(f.ctx, f.bankKeeper, addr, sdk.NewCoins(coin1)) - assert.NilError(t, err) - } - - req := &banktypes.QueryDenomOwnersRequest{ - Denom: coin1.GetDenom(), - } - testdata.DeterministicIterations(t, f.ctx, req, f.queryClient.DenomOwners, 2516, false) -} diff --git a/tests/integration/example/example_test.go b/tests/integration/example/example_test.go deleted file mode 100644 index 6d4d57c3f356..000000000000 --- a/tests/integration/example/example_test.go +++ /dev/null @@ -1,235 +0,0 @@ -package integration_test - -import ( - "context" - "errors" - "fmt" - "io" - "testing" - - "github.com/google/go-cmp/cmp" - "go.uber.org/mock/gomock" - - "cosmossdk.io/core/appmodule" - "cosmossdk.io/log" - storetypes "cosmossdk.io/store/types" - "cosmossdk.io/x/mint" - mintkeeper "cosmossdk.io/x/mint/keeper" - minttypes "cosmossdk.io/x/mint/types" - - "github.com/cosmos/cosmos-sdk/baseapp" - addresscodec "github.com/cosmos/cosmos-sdk/codec/address" - codectestutil "github.com/cosmos/cosmos-sdk/codec/testutil" - "github.com/cosmos/cosmos-sdk/runtime" - "github.com/cosmos/cosmos-sdk/testutil/integration" - sdk "github.com/cosmos/cosmos-sdk/types" - moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" - "github.com/cosmos/cosmos-sdk/x/auth" - authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" - authsims "github.com/cosmos/cosmos-sdk/x/auth/simulation" - authtestutil "github.com/cosmos/cosmos-sdk/x/auth/testutil" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" -) - -// Example shows how to use the integration test framework to test the integration of SDK modules. -// Panics are used in this example, but in a real test case, you should use the testing.T object and assertions. -func Example() { - // in this example we are testing the integration of the following modules: - // - mint, which directly depends on auth, bank and staking - encodingCfg := moduletestutil.MakeTestEncodingConfig(codectestutil.CodecOptions{}, auth.AppModule{}, mint.AppModule{}) - signingCtx := encodingCfg.InterfaceRegistry.SigningContext() - - keys := storetypes.NewKVStoreKeys(authtypes.StoreKey, minttypes.StoreKey) - authority := authtypes.NewModuleAddress("gov").String() - - // replace the logger by testing values in a real test case (e.g. log.NewTestLogger(t)) - logger := log.NewNopLogger() - - // gomock initializations - ctrl := gomock.NewController(&testing.T{}) - acctsModKeeper := authtestutil.NewMockAccountsModKeeper(ctrl) - accNum := uint64(0) - acctsModKeeper.EXPECT().NextAccountNumber(gomock.Any()).AnyTimes().DoAndReturn(func(ctx context.Context) (uint64, error) { - currentNum := accNum - accNum++ - return currentNum, nil - }) - - accountKeeper := authkeeper.NewAccountKeeper( - runtime.NewEnvironment(runtime.NewKVStoreService(keys[authtypes.StoreKey]), log.NewNopLogger()), - encodingCfg.Codec, - authtypes.ProtoBaseAccount, - acctsModKeeper, - map[string][]string{minttypes.ModuleName: {authtypes.Minter}}, - addresscodec.NewBech32Codec("cosmos"), - "cosmos", - authority, - ) - - // subspace is nil because we don't test params (which is legacy anyway) - authModule := auth.NewAppModule(encodingCfg.Codec, accountKeeper, acctsModKeeper, authsims.RandomGenesisAccounts, nil) - - // here bankkeeper and staking keeper is nil because we are not testing them - // subspace is nil because we don't test params (which is legacy anyway) - mintKeeper := mintkeeper.NewKeeper(encodingCfg.Codec, runtime.NewEnvironment(runtime.NewKVStoreService(keys[minttypes.StoreKey]), logger), accountKeeper, nil, authtypes.FeeCollectorName, authority) - mintModule := mint.NewAppModule(encodingCfg.Codec, mintKeeper, accountKeeper) - - // create the application and register all the modules from the previous step - integrationApp := integration.NewIntegrationApp( - logger, - keys, - encodingCfg.Codec, - signingCtx.AddressCodec(), - signingCtx.ValidatorAddressCodec(), - map[string]appmodule.AppModule{ - authtypes.ModuleName: authModule, - minttypes.ModuleName: mintModule, - }, - baseapp.NewMsgServiceRouter(), - baseapp.NewGRPCQueryRouter(), - ) - - // register the message and query servers - authtypes.RegisterMsgServer(integrationApp.MsgServiceRouter(), authkeeper.NewMsgServerImpl(accountKeeper)) - minttypes.RegisterMsgServer(integrationApp.MsgServiceRouter(), mintkeeper.NewMsgServerImpl(mintKeeper)) - minttypes.RegisterQueryServer(integrationApp.QueryHelper(), mintkeeper.NewQueryServerImpl(mintKeeper)) - - params := minttypes.DefaultParams() - params.BlocksPerYear = 10000 - - // now we can use the application to test a mint message - result, err := integrationApp.RunMsg(&minttypes.MsgUpdateParams{ - Authority: authority, - Params: params, - }) - if err != nil { - panic(err) - } - - // in this example the result is an empty response, a nil check is enough - // in other cases, it is recommended to check the result value. - if result == nil { - panic(errors.New("unexpected nil result")) - } - - // we now check the result - resp := minttypes.MsgUpdateParamsResponse{} - err = encodingCfg.Codec.Unmarshal(result.Value, &resp) - if err != nil { - panic(err) - } - - sdkCtx := sdk.UnwrapSDKContext(integrationApp.Context()) - - // we should also check the state of the application - got, err := mintKeeper.Params.Get(sdkCtx) - if err != nil { - panic(err) - } - - if diff := cmp.Diff(got, params); diff != "" { - panic(diff) - } - fmt.Println(got.BlocksPerYear) - // Output: 10000 -} - -// Example_oneModule shows how to use the integration test framework to test the integration of a single module. -// That module has no dependency on other modules. -func Example_oneModule() { - // in this example we are testing the integration of the auth module: - encodingCfg := moduletestutil.MakeTestEncodingConfig(codectestutil.CodecOptions{}, auth.AppModule{}) - keys := storetypes.NewKVStoreKeys(authtypes.StoreKey) - authority := authtypes.NewModuleAddress("gov").String() - - // replace the logger by testing values in a real test case (e.g. log.NewTestLogger(t)) - logger := log.NewLogger(io.Discard) - - // gomock initializations - ctrl := gomock.NewController(&testing.T{}) - acctsModKeeper := authtestutil.NewMockAccountsModKeeper(ctrl) - accNum := uint64(0) - acctsModKeeper.EXPECT().NextAccountNumber(gomock.Any()).AnyTimes().DoAndReturn(func(ctx context.Context) (uint64, error) { - currentNum := accNum - accNum++ - return currentNum, nil - }) - - accountKeeper := authkeeper.NewAccountKeeper( - runtime.NewEnvironment(runtime.NewKVStoreService(keys[authtypes.StoreKey]), log.NewNopLogger()), - encodingCfg.Codec, - authtypes.ProtoBaseAccount, - acctsModKeeper, - map[string][]string{minttypes.ModuleName: {authtypes.Minter}}, - addresscodec.NewBech32Codec("cosmos"), - "cosmos", - authority, - ) - - // subspace is nil because we don't test params (which is legacy anyway) - authModule := auth.NewAppModule(encodingCfg.Codec, accountKeeper, acctsModKeeper, authsims.RandomGenesisAccounts, nil) - - // create the application and register all the modules from the previous step - integrationApp := integration.NewIntegrationApp( - logger, - keys, - encodingCfg.Codec, - encodingCfg.InterfaceRegistry.SigningContext().AddressCodec(), - encodingCfg.InterfaceRegistry.SigningContext().ValidatorAddressCodec(), - map[string]appmodule.AppModule{ - authtypes.ModuleName: authModule, - }, - baseapp.NewMsgServiceRouter(), - baseapp.NewGRPCQueryRouter(), - ) - - // register the message and query servers - authtypes.RegisterMsgServer(integrationApp.MsgServiceRouter(), authkeeper.NewMsgServerImpl(accountKeeper)) - - params := authtypes.DefaultParams() - params.MaxMemoCharacters = 1000 - - // now we can use the application to test a mint message - result, err := integrationApp.RunMsg(&authtypes.MsgUpdateParams{ - Authority: authority, - Params: params, - }, - // this allows to the begin and end blocker of the module before and after the message - integration.WithAutomaticFinalizeBlock(), - // this allows to commit the state after the message - integration.WithAutomaticCommit(), - ) - if err != nil { - panic(err) - } - - // verify that the begin and end blocker were called - // NOTE: in this example, we are testing auth, which doesn't have any begin or end blocker - // so verifying the block height is enough - if integrationApp.LastBlockHeight() != 2 { - panic(fmt.Errorf("expected block height to be 2, got %d", integrationApp.LastBlockHeight())) - } - - // in this example the result is an empty response, a nil check is enough - // in other cases, it is recommended to check the result value. - if result == nil { - panic(errors.New("unexpected nil result")) - } - - // we now check the result - resp := authtypes.MsgUpdateParamsResponse{} - err = encodingCfg.Codec.Unmarshal(result.Value, &resp) - if err != nil { - panic(err) - } - - sdkCtx := sdk.UnwrapSDKContext(integrationApp.Context()) - - // we should also check the state of the application - got := accountKeeper.GetParams(sdkCtx) - if diff := cmp.Diff(got, params); diff != "" { - panic(diff) - } - fmt.Println(got.MaxMemoCharacters) - // Output: 1000 -} diff --git a/tests/integration/v2/auth/keeper_bench_test.go b/tests/integration/v2/auth/keeper_bench_test.go new file mode 100644 index 000000000000..78f1890b6ccc --- /dev/null +++ b/tests/integration/v2/auth/keeper_bench_test.go @@ -0,0 +1,116 @@ +package auth + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "cosmossdk.io/depinject" + "cosmossdk.io/log" + basedepinject "cosmossdk.io/x/accounts/defaults/base/depinject" + + "github.com/cosmos/cosmos-sdk/tests/integration/v2" + "github.com/cosmos/cosmos-sdk/testutil/configurator" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth/keeper" +) + +func BenchmarkAccountMapperGetAccountFound(b *testing.B) { + b.ReportAllocs() + + moduleConfigs := []configurator.ModuleOption{ + configurator.AccountsModule(), + configurator.AuthModule(), + configurator.BankModule(), + configurator.VestingModule(), + configurator.StakingModule(), + configurator.TxModule(), + configurator.ValidateModule(), + configurator.ConsensusModule(), + configurator.GenutilModule(), + } + + var accountKeeper keeper.AccountKeeper + startupCfg := integration.DefaultStartUpConfig(b) + + app, err := integration.NewApp( + depinject.Configs(configurator.NewAppV2Config(moduleConfigs...), depinject.Provide( + // inject desired account types: + basedepinject.ProvideAccount, + + // provide base account options + basedepinject.ProvideSecp256K1PubKey, + + // provide extra accounts + ProvideMockRetroCompatAccountValid, + ProvideMockRetroCompatAccountNoInfo, + ProvideMockRetroCompatAccountNoImplement, + ), depinject.Supply(log.NewNopLogger())), + startupCfg, + &accountKeeper) + require.NoError(b, err) + + ctx := app.StateLatestContext(b) + + // assumes b.N < 2**24 + for i := 0; i < b.N; i++ { + arr := []byte{byte((i & 0xFF0000) >> 16), byte((i & 0xFF00) >> 8), byte(i & 0xFF)} + addr := sdk.AccAddress(arr) + acc := accountKeeper.NewAccountWithAddress(ctx, addr) + accountKeeper.SetAccount(ctx, acc) + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + arr := []byte{byte((i & 0xFF0000) >> 16), byte((i & 0xFF00) >> 8), byte(i & 0xFF)} + accountKeeper.GetAccount(ctx, sdk.AccAddress(arr)) + } +} + +func BenchmarkAccountMapperSetAccount(b *testing.B) { + b.ReportAllocs() + + moduleConfigs := []configurator.ModuleOption{ + configurator.AccountsModule(), + configurator.AuthModule(), + configurator.BankModule(), + configurator.VestingModule(), + configurator.StakingModule(), + configurator.TxModule(), + configurator.ValidateModule(), + configurator.ConsensusModule(), + configurator.GenutilModule(), + } + + var accountKeeper keeper.AccountKeeper + startupCfg := integration.DefaultStartUpConfig(b) + + app, err := integration.NewApp( + depinject.Configs(configurator.NewAppV2Config(moduleConfigs...), depinject.Provide( + // inject desired account types: + basedepinject.ProvideAccount, + + // provide base account options + basedepinject.ProvideSecp256K1PubKey, + + // provide extra accounts + ProvideMockRetroCompatAccountValid, + ProvideMockRetroCompatAccountNoInfo, + ProvideMockRetroCompatAccountNoImplement, + ), depinject.Supply(log.NewNopLogger())), + startupCfg, + &accountKeeper) + require.NoError(b, err) + + ctx := app.StateLatestContext(b) + + b.ResetTimer() + + // assumes b.N < 2**24 + for i := 0; i < b.N; i++ { + arr := []byte{byte((i & 0xFF0000) >> 16), byte((i & 0xFF00) >> 8), byte(i & 0xFF)} + addr := sdk.AccAddress(arr) + acc := accountKeeper.NewAccountWithAddress(ctx, addr) + accountKeeper.SetAccount(ctx, acc) + } +} diff --git a/tests/integration/v2/auth/module_test.go b/tests/integration/v2/auth/module_test.go new file mode 100644 index 000000000000..57f527fd5c98 --- /dev/null +++ b/tests/integration/v2/auth/module_test.go @@ -0,0 +1,16 @@ +package auth + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/x/auth/types" +) + +func TestItCreatesModuleAccountOnInitBlock(t *testing.T) { + f := createTestSuite(t) + ctx := f.ctx + acc := f.authKeeper.GetAccount(ctx, types.NewModuleAddress(types.FeeCollectorName)) + require.NotNil(t, acc) +} diff --git a/tests/integration/v2/example/example_test.go b/tests/integration/v2/example/example_test.go new file mode 100644 index 000000000000..7fa4f47dd1bf --- /dev/null +++ b/tests/integration/v2/example/example_test.go @@ -0,0 +1,93 @@ +package integration_test + +import ( + "context" + "errors" + "fmt" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/stretchr/testify/require" + + "cosmossdk.io/core/transaction" + "cosmossdk.io/depinject" + "cosmossdk.io/log" + mintkeeper "cosmossdk.io/x/mint/keeper" + minttypes "cosmossdk.io/x/mint/types" + + "github.com/cosmos/cosmos-sdk/tests/integration/v2" + "github.com/cosmos/cosmos-sdk/testutil/configurator" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" +) + +// Example shows how to use the integration test framework to test the integration of SDK modules. +// Panics are used in this example, but in a real test case, you should use the testing.T object and assertions. +// nolint:govet // ignore removal of parameter here as its run as a test as well. +func Example(t *testing.T) { + t.Helper() + authority := authtypes.NewModuleAddress("gov").String() + + var mintKeeper *mintkeeper.Keeper + + moduleConfigs := []configurator.ModuleOption{ + configurator.AccountsModule(), + configurator.AuthModule(), + configurator.BankModule(), + configurator.VestingModule(), + configurator.TxModule(), + configurator.ValidateModule(), + configurator.ConsensusModule(), + configurator.GenutilModule(), + } + + var err error + startupCfg := integration.DefaultStartUpConfig(t) + + app, err := integration.NewApp( + depinject.Configs(configurator.NewAppV2Config(moduleConfigs...), depinject.Provide(), depinject.Supply(log.NewNopLogger())), + startupCfg, + mintKeeper) + require.NoError(t, err) + require.NotNil(t, mintKeeper) + + ctx := app.StateLatestContext(t) + + mintMsgServer := mintkeeper.NewMsgServerImpl(mintKeeper) + + params := minttypes.DefaultParams() + params.BlocksPerYear = 10000 + + // now we can use the application to test a mint message + result, err := app.RunMsg(t, ctx, func(ctx context.Context) (transaction.Msg, error) { + msg := &minttypes.MsgUpdateParams{ + Authority: authority, + Params: params, + } + + return mintMsgServer.UpdateParams(ctx, msg) + }) + if err != nil { + panic(err) + } + + // in this example the result is an empty response, a nil check is enough + // in other cases, it is recommended to check the result value. + if result == nil { + panic(errors.New("unexpected nil result")) + } + + _, ok := result.(*minttypes.MsgUpdateParamsResponse) + require.True(t, ok) + + // we should also check the state of the application + got, err := mintKeeper.Params.Get(ctx) + if err != nil { + panic(err) + } + + if diff := cmp.Diff(got, params); diff != "" { + panic(diff) + } + fmt.Println(got.BlocksPerYear) + // Output: 10000 +} diff --git a/testutil/integration/doc.go b/testutil/integration/doc.go deleted file mode 100644 index c1b9902d7cfe..000000000000 --- a/testutil/integration/doc.go +++ /dev/null @@ -1,3 +0,0 @@ -// Integration contains the integration test setup used for SDK modules. -// To see how to use this, check the tests/integration/example_test.go file. -package integration diff --git a/testutil/integration/helpers.go b/testutil/integration/helpers.go deleted file mode 100644 index 94bbdca35c58..000000000000 --- a/testutil/integration/helpers.go +++ /dev/null @@ -1,9 +0,0 @@ -package integration - -import ( - moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" -) - -// CreateMultiStore is a helper for setting up multiple stores for provided modules. -// Deprecated: use github.com/cosmos/cosmos-sdk/types/module/testutil.CreateMultiStore instead. -var CreateMultiStore = moduletestutil.CreateMultiStore diff --git a/testutil/integration/options.go b/testutil/integration/options.go deleted file mode 100644 index d2a6aacdb001..000000000000 --- a/testutil/integration/options.go +++ /dev/null @@ -1,25 +0,0 @@ -package integration - -// Config is the configuration for the integration app. -type Config struct { - AutomaticFinalizeBlock bool - AutomaticCommit bool -} - -// Option is a function that can be used to configure the integration app. -type Option func(*Config) - -// WithAutomaticFinalizeBlock calls ABCI finalize block. -func WithAutomaticFinalizeBlock() Option { - return func(cfg *Config) { - cfg.AutomaticFinalizeBlock = true - } -} - -// WithAutomaticCommit enables automatic commit. -// This means that the integration app will automatically commit the state after each msgs. -func WithAutomaticCommit() Option { - return func(cfg *Config) { - cfg.AutomaticCommit = true - } -} diff --git a/testutil/integration/router.go b/testutil/integration/router.go deleted file mode 100644 index a65766847f29..000000000000 --- a/testutil/integration/router.go +++ /dev/null @@ -1,237 +0,0 @@ -package integration - -import ( - "context" - "fmt" - - cmtabcitypes "github.com/cometbft/cometbft/api/cometbft/abci/v1" - cmtproto "github.com/cometbft/cometbft/api/cometbft/types/v1" - cmttypes "github.com/cometbft/cometbft/types" - - "cosmossdk.io/collections" - "cosmossdk.io/core/address" - "cosmossdk.io/core/appmodule" - corestore "cosmossdk.io/core/store" - coretesting "cosmossdk.io/core/testing" - "cosmossdk.io/log" - storetypes "cosmossdk.io/store/types" - - "github.com/cosmos/cosmos-sdk/baseapp" - "github.com/cosmos/cosmos-sdk/codec" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/cosmos-sdk/runtime" - simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/module" - authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" -) - -const ( - appName = "integration-app" - consensus = "consensus" -) - -// App is a test application that can be used to test the integration of modules. -type App struct { - *baseapp.BaseApp - - ctx sdk.Context - logger log.Logger - queryHelper *baseapp.QueryServiceTestHelper -} - -// NewIntegrationApp creates an application for testing purposes. This application -// is able to route messages to their respective handlers. -func NewIntegrationApp( - logger log.Logger, - keys map[string]*storetypes.KVStoreKey, - appCodec codec.Codec, - addressCodec address.Codec, - validatorCodec address.Codec, - modules map[string]appmodule.AppModule, - msgRouter *baseapp.MsgServiceRouter, - grpcRouter *baseapp.GRPCQueryRouter, - baseAppOptions ...func(*baseapp.BaseApp), -) *App { - db := coretesting.NewMemDB() - - interfaceRegistry := codectypes.NewInterfaceRegistry() - moduleManager := module.NewManagerFromMap(modules) - moduleManager.RegisterInterfaces(interfaceRegistry) - - txConfig := authtx.NewTxConfig(codec.NewProtoCodec(interfaceRegistry), addressCodec, validatorCodec, authtx.DefaultSignModes) - bApp := baseapp.NewBaseApp(appName, logger, db, txConfig.TxDecoder(), append(baseAppOptions, baseapp.SetChainID(appName))...) - bApp.MountKVStores(keys) - - bApp.SetInitChainer(func(sdkCtx sdk.Context, _ *cmtabcitypes.InitChainRequest) (*cmtabcitypes.InitChainResponse, error) { - for _, mod := range modules { - if m, ok := mod.(module.HasGenesis); ok { - if err := m.InitGenesis(sdkCtx, m.DefaultGenesis()); err != nil { - return nil, err - } - } else if m, ok := mod.(module.HasABCIGenesis); ok { - if _, err := m.InitGenesis(sdkCtx, m.DefaultGenesis()); err != nil { - return nil, err - } - } - } - - return &cmtabcitypes.InitChainResponse{}, nil - }) - - bApp.SetBeginBlocker(func(sdkCtx sdk.Context) (sdk.BeginBlock, error) { - return moduleManager.BeginBlock(sdkCtx) - }) - bApp.SetEndBlocker(func(sdkCtx sdk.Context) (sdk.EndBlock, error) { - return moduleManager.EndBlock(sdkCtx) - }) - - msgRouter.SetInterfaceRegistry(interfaceRegistry) - bApp.SetMsgServiceRouter(msgRouter) - grpcRouter.SetInterfaceRegistry(interfaceRegistry) - bApp.SetGRPCQueryRouter(grpcRouter) - - if consensusKey := keys[consensus]; consensusKey != nil { - _ = bApp.CommitMultiStore().LoadLatestVersion() - cps := newParamStore(runtime.NewKVStoreService(consensusKey), appCodec) - params := cmttypes.ConsensusParamsFromProto(*simtestutil.DefaultConsensusParams) // This fills up missing param sections - if err := cps.Set(sdk.NewContext(bApp.CommitMultiStore(), true, logger), params.ToProto()); err != nil { // at this point, because we haven't written state we don't have a real context - panic(fmt.Errorf("failed to set consensus params: %w", err)) - } - bApp.SetParamStore(cps) - - if err := bApp.LoadLatestVersion(); err != nil { - panic(fmt.Errorf("failed to load application version from store: %w", err)) - } - - if _, err := bApp.InitChain(&cmtabcitypes.InitChainRequest{ChainId: appName, ConsensusParams: simtestutil.DefaultConsensusParams}); err != nil { - panic(fmt.Errorf("failed to initialize application: %w", err)) - } - } else { - if err := bApp.LoadLatestVersion(); err != nil { - panic(fmt.Errorf("failed to load application version from store: %w", err)) - } - - if _, err := bApp.InitChain(&cmtabcitypes.InitChainRequest{ChainId: appName}); err != nil { - panic(fmt.Errorf("failed to initialize application: %w", err)) - } - } - - bApp.SimWriteState() // forcing state write from init genesis like in sims - _, err := bApp.Commit() - if err != nil { - panic(err) - } - - sdkCtx := bApp.NewContext(true).WithBlockHeader(cmtproto.Header{ChainID: appName}) - return &App{ - BaseApp: bApp, - logger: logger, - ctx: sdkCtx, - queryHelper: baseapp.NewQueryServerTestHelper(sdkCtx, interfaceRegistry), - } -} - -// RunMsg provides the ability to run a message and return the response. -// In order to run a message, the application must have a handler for it. -// These handlers are registered on the application message service router. -// The result of the message execution is returned as an Any type. -// That any type can be unmarshaled to the expected response type. -// If the message execution fails, an error is returned. -func (app *App) RunMsg(msg sdk.Msg, option ...Option) (*codectypes.Any, error) { - // set options - cfg := &Config{} - for _, opt := range option { - opt(cfg) - } - - if cfg.AutomaticCommit { - defer func() { - _, err := app.Commit() - if err != nil { - panic(err) - } - }() - } - - if cfg.AutomaticFinalizeBlock { - height := app.LastBlockHeight() + 1 - if _, err := app.FinalizeBlock(&cmtabcitypes.FinalizeBlockRequest{Height: height, DecidedLastCommit: cmtabcitypes.CommitInfo{Votes: []cmtabcitypes.VoteInfo{}}}); err != nil { - return nil, fmt.Errorf("failed to run finalize block: %w", err) - } - } - - app.logger.Info("Running msg", "msg", msg.String()) - - handler := app.MsgServiceRouter().Handler(msg) - if handler == nil { - return nil, fmt.Errorf("handler is nil, can't route message %s: %+v", sdk.MsgTypeURL(msg), msg) - } - - msgResult, err := handler(app.ctx, msg) - if err != nil { - return nil, fmt.Errorf("failed to execute message %s: %w", sdk.MsgTypeURL(msg), err) - } - - var response *codectypes.Any - if len(msgResult.MsgResponses) > 0 { - msgResponse := msgResult.MsgResponses[0] - if msgResponse == nil { - return nil, fmt.Errorf("got nil msg response %s in message result: %s", sdk.MsgTypeURL(msg), msgResult.String()) - } - - response = msgResponse - } - - return response, nil -} - -// NextBlock advances the chain height and returns the new height. -func (app *App) NextBlock(txsblob ...[]byte) (int64, error) { - height := app.LastBlockHeight() + 1 - if _, err := app.FinalizeBlock(&cmtabcitypes.FinalizeBlockRequest{ - Txs: txsblob, // txsBlob are raw txs to be executed in the block - Height: height, - DecidedLastCommit: cmtabcitypes.CommitInfo{Votes: []cmtabcitypes.VoteInfo{}}, - }); err != nil { - return 0, fmt.Errorf("failed to run finalize block: %w", err) - } - - _, err := app.Commit() - return height, err -} - -// Context returns the application context. It can be unwrapped to a sdk.Context, -// with the sdk.UnwrapSDKContext function. -func (app *App) Context() context.Context { - return app.ctx -} - -// QueryHelper returns the application query helper. -// It can be used when registering query services. -func (app *App) QueryHelper() *baseapp.QueryServiceTestHelper { - return app.queryHelper -} - -type paramStoreService struct { - ParamsStore collections.Item[cmtproto.ConsensusParams] -} - -func newParamStore(storeService corestore.KVStoreService, cdc codec.Codec) paramStoreService { - sb := collections.NewSchemaBuilder(storeService) - return paramStoreService{ - ParamsStore: collections.NewItem(sb, collections.NewPrefix("Consensus"), "params", codec.CollValue[cmtproto.ConsensusParams](cdc)), - } -} - -func (pss paramStoreService) Get(ctx context.Context) (cmtproto.ConsensusParams, error) { - return pss.ParamsStore.Get(ctx) -} - -func (pss paramStoreService) Has(ctx context.Context) (bool, error) { - return pss.ParamsStore.Has(ctx) -} - -func (pss paramStoreService) Set(ctx context.Context, cp cmtproto.ConsensusParams) error { - return pss.ParamsStore.Set(ctx, cp) -} diff --git a/types/query/collections_pagination.go b/types/query/collections_pagination.go index 2877df26396c..902d68b1dde3 100644 --- a/types/query/collections_pagination.go +++ b/types/query/collections_pagination.go @@ -265,53 +265,59 @@ func collFilteredPaginateByKey[K, V any, C Collection[K, V], T any]( defer iterator.Close() var ( - count uint64 - nextKey []byte + count uint64 + nextKey []byte + transformed T ) for ; iterator.Valid(); iterator.Next() { - // if we reached the specified limit - // then we get the next key, and we exit the iteration. - if count == limit { - concreteKey, err := iterator.Key() - if err != nil { - return nil, nil, err - } - - nextKey, err = encodeCollKey[K, V](coll, concreteKey) - if err != nil { - return nil, nil, err - } - break - } - kv, err := iterator.KeyValue() if err != nil { return nil, nil, err } + + include := false // if no predicate is specified then we just append the result if predicateFunc == nil { - transformed, err := transformFunc(kv.Key, kv.Value) + transformed, err = transformFunc(kv.Key, kv.Value) if err != nil { return nil, nil, err } - results = append(results, transformed) + include = true // if predicate is applied we execute the predicate function // and append only if predicateFunc yields true. } else { - include, err := predicateFunc(kv.Key, kv.Value) + include, err = predicateFunc(kv.Key, kv.Value) if err != nil { return nil, nil, err } if include { - transformed, err := transformFunc(kv.Key, kv.Value) + transformed, err = transformFunc(kv.Key, kv.Value) if err != nil { return nil, nil, err } - results = append(results, transformed) } } - count++ + + if include { + // if we reached the specified limit + // then we get the next key, and we exit the iteration. + if count == limit { + concreteKey, err := iterator.Key() + if err != nil { + return nil, nil, err + } + + nextKey, err = encodeCollKey[K, V](coll, concreteKey) + if err != nil { + return nil, nil, err + } + break + } + + results = append(results, transformed) + count++ + } } return results, &PageResponse{ diff --git a/types/query/collections_pagination_test.go b/types/query/collections_pagination_test.go index 25dc267a4481..6e4beb8c753c 100644 --- a/types/query/collections_pagination_test.go +++ b/types/query/collections_pagination_test.go @@ -127,7 +127,7 @@ func TestCollectionPagination(t *testing.T) { Limit: 3, }, expResp: &PageResponse{ - NextKey: encodeKey(5), + NextKey: encodeKey(8), }, filter: func(key, value uint64) (bool, error) { return key%2 == 0, nil @@ -135,6 +135,21 @@ func TestCollectionPagination(t *testing.T) { expResults: []collections.KeyValue[uint64, uint64]{ {Key: 2, Value: 2}, {Key: 4, Value: 4}, + {Key: 6, Value: 6}, + }, + }, + "filtered with key and empty next key in response": { + req: &PageRequest{ + Key: encodeKey(295), + }, + expResp: &PageResponse{ + NextKey: nil, + }, + filter: func(key, value uint64) (bool, error) { + return key%5 == 0, nil + }, + expResults: []collections.KeyValue[uint64, uint64]{ + {Key: 295, Value: 295}, }, }, } diff --git a/x/README.md b/x/README.md index 373527b6ef6e..e7ce22c9e697 100644 --- a/x/README.md +++ b/x/README.md @@ -6,6 +6,7 @@ sidebar_position: 0 Here are some production-grade modules that can be used in Cosmos SDK applications, along with their respective documentation: +* [Accounts](./accounts/README.md) - Tools and infrastructure for creating advanced smart accounts. * [Auth](./auth/README.md) - Authentication of accounts and transactions for Cosmos SDK applications. * [Authz](./authz/README.md) - Authorization for accounts to perform actions on behalf of other accounts. * [Bank](./bank/README.md) - Token transfer functionalities. @@ -18,6 +19,7 @@ Here are some production-grade modules that can be used in Cosmos SDK applicatio * [Feegrant](./feegrant/README.md) - Grant fee allowances for executing transactions. * [Genutil](./genutil/README.md) - Genesis utilities for the Cosmos SDK. * [Governance](./gov/README.md) - On-chain proposals and voting. +* [Group](./group/README.md) - On-chain multisig accounts creation and management. * [Mint](./mint/README.md) - Creation of new units of staking token. * [NFT](./nft/README.md) - NFT module implemented based on [ADR43](https://docs.cosmos.network/main/build/architecture/adr-043-nft-module). * [Params](./params/README.md) - Globally available parameter store. @@ -28,7 +30,7 @@ Here are some production-grade modules that can be used in Cosmos SDK applicatio * [Upgrade](./upgrade/README.md) - Software upgrades handling and coordination. * [Validate](./validate/README.md) - Global ante/post handlers and tx validator setup. -To learn more about the process of building modules, visit the [building modules reference documentation](https://docs.cosmos.network/main/building-modules/intro). +To learn more about the process of building modules, visit the [building modules reference documentation](https://docs.cosmos.network/main/build/building-modules/intro). ## IBC diff --git a/x/auth/vesting/README.md b/x/auth/vesting/README.md index 5fd33462a949..f72e8b6aff7d 100644 --- a/x/auth/vesting/README.md +++ b/x/auth/vesting/README.md @@ -46,7 +46,7 @@ For all vesting accounts, the owner of the vesting account is able to delegate a ## Note -Vesting accounts can be initialized with some vesting and non-vesting coins. The non-vesting coins would be immediately transferable. DelayedVesting ContinuousVesting, PeriodicVesting and PermenantVesting accounts can be created with normal messages after genesis. Other types of vesting accounts must be created at genesis, or as part of a manual network upgrade. The current specification only allows for _unconditional_ vesting (ie. there is no possibility of reaching `ET` and +Vesting accounts can be initialized with some vesting and non-vesting coins. The non-vesting coins would be immediately transferable. DelayedVesting ContinuousVesting, PeriodicVesting and PermanentVesting accounts can be created with normal messages after genesis. Other types of vesting accounts must be created at genesis, or as part of a manual network upgrade. The current specification only allows for _unconditional_ vesting (ie. there is no possibility of reaching `ET` and having coins fail to vest). ## Vesting Account Types diff --git a/x/staking/README.md b/x/staking/README.md index 45c204041b88..14753f82f53a 100644 --- a/x/staking/README.md +++ b/x/staking/README.md @@ -506,7 +506,7 @@ When a Validator is slashed, the following occurs: redelegation began from the validator are slashed by the `slashFactor` percentage of the initialBalance. * Each amount slashed from redelegations and unbonding delegations is subtracted from the total slash amount. -* The `remaingSlashAmount` is then slashed from the validator's tokens in the `BondedPool` or +* The `remainingSlashAmount` is then slashed from the validator's tokens in the `BondedPool` or `NonBondedPool` depending on the validator's status. This reduces the total supply of tokens. In the case of a slash due to any infraction that requires evidence to submitted (for example double-sign), the slash