diff --git a/tests/integration/accounts/base_account_test.go b/tests/integration/accounts/base_account_test.go deleted file mode 100644 index 5f239d36c083..000000000000 --- a/tests/integration/accounts/base_account_test.go +++ /dev/null @@ -1,118 +0,0 @@ -package accounts - -import ( - "math/rand" - "testing" - - gogoproto "github.com/cosmos/gogoproto/proto" - gogoany "github.com/cosmos/gogoproto/types/any" - "github.com/stretchr/testify/require" - - "cosmossdk.io/simapp" - baseaccountv1 "cosmossdk.io/x/accounts/defaults/base/v1" - "cosmossdk.io/x/bank/testutil" - banktypes "cosmossdk.io/x/bank/types" - - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" - cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" - "github.com/cosmos/cosmos-sdk/testutil/sims" - sdk "github.com/cosmos/cosmos-sdk/types" -) - -var ( - privKey = secp256k1.GenPrivKey() - accCreator = []byte("creator") -) - -func TestBaseAccount(t *testing.T) { - app := setupApp(t) - ak := app.AccountsKeeper - ctx := sdk.NewContext(app.CommitMultiStore(), false, app.Logger()) - - _, baseAccountAddr, err := ak.Init(ctx, "base", accCreator, &baseaccountv1.MsgInit{ - PubKey: toAnyPb(t, privKey.PubKey()), - }, nil, nil) - require.NoError(t, err) - - // fund base account! this will also cause an auth base account to be created - // by the bank module. - // TODO: fixed by letting x/auth rely on x/accounts for acc existence checks. - fundAccount(t, app, ctx, baseAccountAddr, "1000000stake") - - // now we make the account send a tx, public key not present. - // so we know it will default to x/accounts calling. - msg := &banktypes.MsgSend{ - FromAddress: bechify(t, app, baseAccountAddr), - ToAddress: bechify(t, app, []byte("random-addr")), - Amount: coins(t, "100stake"), - } - sendTx(t, ctx, app, baseAccountAddr, msg) -} - -func sendTx(t *testing.T, ctx sdk.Context, app *simapp.SimApp, sender []byte, msg sdk.Msg) { - t.Helper() - tx := sign(t, ctx, app, sender, privKey, msg) - _, _, err := app.SimDeliver(app.TxEncode, tx) - require.NoError(t, err) -} - -func sign(t *testing.T, ctx sdk.Context, app *simapp.SimApp, from sdk.AccAddress, privKey cryptotypes.PrivKey, msg sdk.Msg) sdk.Tx { - t.Helper() - r := rand.New(rand.NewSource(0)) - - accNum, err := app.AccountsKeeper.AccountByNumber.Get(ctx, from) - require.NoError(t, err) - accSeq, err := app.AccountsKeeper.Query(ctx, from, &baseaccountv1.QuerySequence{}) - require.NoError(t, err) - - tx, err := sims.GenSignedMockTx( - r, - app.TxConfig(), - []sdk.Msg{msg}, - coins(t, "100stake"), - 1_000_000, - app.ChainID(), - []uint64{accNum}, - []uint64{accSeq.(*baseaccountv1.QuerySequenceResponse).Sequence}, - privKey, - ) - - require.NoError(t, err) - return tx -} - -func bechify(t *testing.T, app *simapp.SimApp, addr []byte) string { - t.Helper() - bech32, err := app.AuthKeeper.AddressCodec().BytesToString(addr) - require.NoError(t, err) - return bech32 -} - -func fundAccount(t *testing.T, app *simapp.SimApp, ctx sdk.Context, addr sdk.AccAddress, amt string) { - t.Helper() - require.NoError(t, testutil.FundAccount(ctx, app.BankKeeper, addr, coins(t, amt))) -} - -func toAnyPb(t *testing.T, pm gogoproto.Message) *codectypes.Any { - t.Helper() - if gogoproto.MessageName(pm) == gogoproto.MessageName(&gogoany.Any{}) { - t.Fatal("no") - } - pb, err := codectypes.NewAnyWithValue(pm) - require.NoError(t, err) - return pb -} - -func coins(t *testing.T, s string) sdk.Coins { - t.Helper() - coins, err := sdk.ParseCoinsNormalized(s) - require.NoError(t, err) - return coins -} - -func setupApp(t *testing.T) *simapp.SimApp { - t.Helper() - app := simapp.Setup(t, false) - return app -} diff --git a/tests/integration/accounts/fixture_test.go b/tests/integration/accounts/fixture_test.go deleted file mode 100644 index 0cf55d6d9022..000000000000 --- a/tests/integration/accounts/fixture_test.go +++ /dev/null @@ -1,203 +0,0 @@ -package accounts - -import ( - "context" - "testing" - - gogotypes "github.com/cosmos/gogoproto/types" - "github.com/stretchr/testify/require" - - "cosmossdk.io/core/appmodule" - "cosmossdk.io/log" - storetypes "cosmossdk.io/store/types" - "cosmossdk.io/x/accounts" - "cosmossdk.io/x/accounts/accountstd" - account_abstractionv1 "cosmossdk.io/x/accounts/interfaces/account_abstraction/v1" - 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" - txdecode "cosmossdk.io/x/tx/decode" - - "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" -) - -var _ accountstd.Interface = (*mockAccount)(nil) - -type mockAccount struct { - authenticate func(ctx context.Context, msg *account_abstractionv1.MsgAuthenticate) (*account_abstractionv1.MsgAuthenticateResponse, error) -} - -func (m mockAccount) RegisterInitHandler(builder *accountstd.InitBuilder) { - accountstd.RegisterInitHandler(builder, func(ctx context.Context, req *gogotypes.Empty) (*gogotypes.Empty, error) { - return &gogotypes.Empty{}, nil - }) -} - -func (m mockAccount) RegisterExecuteHandlers(builder *accountstd.ExecuteBuilder) { - if m.authenticate == nil { - return - } - - accountstd.RegisterExecuteHandler(builder, m.authenticate) -} - -func (m mockAccount) RegisterQueryHandlers(_ *accountstd.QueryBuilder) {} - -type fixture struct { - t *testing.T - - app *integration.App - cdc codec.Codec - - authKeeper authkeeper.AccountKeeper - accountsKeeper accounts.Keeper - bankKeeper bankkeeper.Keeper - - mockAccountAddress []byte - bundler string -} - -func (f fixture) mustAddr(address []byte) string { - s, _ := f.authKeeper.AddressCodec().BytesToString(address) - return s -} - -func (f fixture) runBundle(txBytes ...[]byte) *accountsv1.MsgExecuteBundleResponse { - f.t.Helper() - - msgSrv := accounts.NewMsgServer(f.accountsKeeper) - - resp, err := msgSrv.ExecuteBundle(f.app.Context(), &accountsv1.MsgExecuteBundle{ - Bundler: f.bundler, - Txs: txBytes, - }) - require.NoError(f.t, err) - return resp -} - -func (f fixture) mint(address []byte, coins ...sdk.Coin) { - f.t.Helper() - for _, coin := range coins { - err := f.bankKeeper.MintCoins(f.app.Context(), minttypes.ModuleName, sdk.NewCoins(coin)) - require.NoError(f.t, err) - err = f.bankKeeper.SendCoinsFromModuleToAccount(f.app.Context(), minttypes.ModuleName, address, sdk.NewCoins(coin)) - require.NoError(f.t, err) - } -} - -func (f fixture) balance(recipient, denom string) sdk.Coin { - f.t.Helper() - balances, err := f.bankKeeper.Balance(f.app.Context(), &banktypes.QueryBalanceRequest{ - Address: recipient, - Denom: denom, - }) - require.NoError(f.t, err) - return *balances.Balance -} - -func initFixture(t *testing.T, f func(ctx context.Context, msg *account_abstractionv1.MsgAuthenticate) (*account_abstractionv1.MsgAuthenticateResponse, error)) *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() - - txDecoder, err := txdecode.NewDecoder(txdecode.Options{ - SigningContext: encodingCfg.TxConfig.SigningContext(), - ProtoCodec: encodingCfg.Codec, - }) - require.NoError(t, err) - - 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(), - txDecoder, - accountstd.AddAccount("mock", func(deps accountstd.Dependencies) (accountstd.Interface, error) { - return mockAccount{f}, nil - }), - ) - require.NoError(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)) - - // init account - _, addr, err := accountsKeeper.Init(integrationApp.Context(), "mock", []byte("system"), &gogotypes.Empty{}, nil, nil) - require.NoError(t, err) - - fixture := &fixture{ - t: t, - app: integrationApp, - cdc: cdc, - authKeeper: authKeeper, - accountsKeeper: accountsKeeper, - bankKeeper: bankKeeper, - mockAccountAddress: addr, - bundler: "", - } - fixture.bundler = fixture.mustAddr([]byte("bundler")) - return fixture -} diff --git a/tests/integration/v2/accounts/base_account_test.go b/tests/integration/v2/accounts/base_account_test.go new file mode 100644 index 000000000000..4aa4610ce883 --- /dev/null +++ b/tests/integration/v2/accounts/base_account_test.go @@ -0,0 +1,96 @@ +package accounts + +import ( + "context" + "testing" + + gogoproto "github.com/cosmos/gogoproto/proto" + gogoany "github.com/cosmos/gogoproto/types/any" + "github.com/stretchr/testify/require" + + "cosmossdk.io/x/accounts" + baseaccountv1 "cosmossdk.io/x/accounts/defaults/base/v1" + bankkeeper "cosmossdk.io/x/bank/keeper" + "cosmossdk.io/x/bank/testutil" + banktypes "cosmossdk.io/x/bank/types" + + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + "github.com/cosmos/cosmos-sdk/tests/integration/v2" + sdk "github.com/cosmos/cosmos-sdk/types" + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" +) + +var ( + privKey = secp256k1.GenPrivKey() + accCreator = []byte("creator") +) + +func TestBaseAccount(t *testing.T) { + f := initFixture(t, nil) + app := f.app + ctx := f.ctx + + _, baseAccountAddr, err := f.accountsKeeper.Init(ctx, "base", accCreator, &baseaccountv1.MsgInit{ + PubKey: toAnyPb(t, privKey.PubKey()), + }, nil, nil) + require.NoError(t, err) + + // fund base account! this will also cause an auth base account to be created + // by the bank module. + fundAccount(t, f.bankKeeper, ctx, baseAccountAddr, "1000000stake") + + // now we make the account send a tx, public key not present. + // so we know it will default to x/accounts calling. + msg := &banktypes.MsgSend{ + FromAddress: bechify(t, f.authKeeper, baseAccountAddr), + ToAddress: bechify(t, f.authKeeper, []byte("random-addr")), + Amount: coins(t, "100stake"), + } + sendTx(t, ctx, app, f.accountsKeeper, baseAccountAddr, msg) +} + +func sendTx(t *testing.T, ctx context.Context, app *integration.App, ak accounts.Keeper, sender []byte, msg sdk.Msg) { + t.Helper() + accNum, err := ak.AccountByNumber.Get(ctx, sender) + require.NoError(t, err) + + accSeq, err := ak.Query(ctx, sender, &baseaccountv1.QuerySequence{}) + require.NoError(t, err) + + app.SignCheckDeliver( + t, ctx, []sdk.Msg{msg}, "", []uint64{accNum}, []uint64{accSeq.(*baseaccountv1.QuerySequenceResponse).Sequence}, + []cryptotypes.PrivKey{privKey}, + "", + ) +} + +func bechify(t *testing.T, ak authkeeper.AccountKeeper, addr []byte) string { + t.Helper() + bech32, err := ak.AddressCodec().BytesToString(addr) + require.NoError(t, err) + return bech32 +} + +func fundAccount(t *testing.T, bk bankkeeper.Keeper, ctx context.Context, addr sdk.AccAddress, amt string) { + t.Helper() + require.NoError(t, testutil.FundAccount(ctx, bk, addr, coins(t, amt))) +} + +func toAnyPb(t *testing.T, pm gogoproto.Message) *codectypes.Any { + t.Helper() + if gogoproto.MessageName(pm) == gogoproto.MessageName(&gogoany.Any{}) { + t.Fatal("no") + } + pb, err := codectypes.NewAnyWithValue(pm) + require.NoError(t, err) + return pb +} + +func coins(t *testing.T, s string) sdk.Coins { + t.Helper() + coins, err := sdk.ParseCoinsNormalized(s) + require.NoError(t, err) + return coins +} diff --git a/tests/integration/accounts/bundler_test.go b/tests/integration/v2/accounts/bundler_test.go similarity index 100% rename from tests/integration/accounts/bundler_test.go rename to tests/integration/v2/accounts/bundler_test.go diff --git a/tests/integration/v2/accounts/fixture_test.go b/tests/integration/v2/accounts/fixture_test.go new file mode 100644 index 000000000000..2a9a5c9aada7 --- /dev/null +++ b/tests/integration/v2/accounts/fixture_test.go @@ -0,0 +1,219 @@ +package accounts + +import ( + "context" + "testing" + + gogotypes "github.com/cosmos/gogoproto/types" + "github.com/stretchr/testify/require" + + "cosmossdk.io/core/router" + "cosmossdk.io/core/transaction" + "cosmossdk.io/depinject" + "cosmossdk.io/log" + "cosmossdk.io/runtime/v2" + "cosmossdk.io/x/accounts" + "cosmossdk.io/x/accounts/accountstd" + basedepinject "cosmossdk.io/x/accounts/defaults/base/depinject" + account_abstractionv1 "cosmossdk.io/x/accounts/interfaces/account_abstraction/v1" + counteraccount "cosmossdk.io/x/accounts/testing/counter" + accountsv1 "cosmossdk.io/x/accounts/v1" + "cosmossdk.io/x/bank" + bankkeeper "cosmossdk.io/x/bank/keeper" + banktypes "cosmossdk.io/x/bank/types" + _ "cosmossdk.io/x/consensus" // import as blank for app wiring + minttypes "cosmossdk.io/x/mint/types" + _ "cosmossdk.io/x/staking" // import as blank for app wirings + + "github.com/cosmos/cosmos-sdk/codec" + codectestutil "github.com/cosmos/cosmos-sdk/codec/testutil" + "github.com/cosmos/cosmos-sdk/tests/integration/v2" + "github.com/cosmos/cosmos-sdk/testutil/configurator" + 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" + _ "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 _ accountstd.Interface = (*mockAccount)(nil) + +type mockAccount struct { + authenticate authentiacteFunc +} + +func (m mockAccount) RegisterInitHandler(builder *accountstd.InitBuilder) { + accountstd.RegisterInitHandler(builder, func(ctx context.Context, req *gogotypes.Empty) (*gogotypes.Empty, error) { + return &gogotypes.Empty{}, nil + }) +} + +func (m mockAccount) RegisterExecuteHandlers(builder *accountstd.ExecuteBuilder) { + if m.authenticate == nil { + return + } + + accountstd.RegisterExecuteHandler(builder, m.authenticate) +} + +func (m mockAccount) RegisterQueryHandlers(_ *accountstd.QueryBuilder) {} + +func ProvideMockAccount(f authentiacteFunc) accountstd.DepinjectAccount { + return accountstd.DepinjectAccount{MakeAccount: func(_ accountstd.Dependencies) (string, accountstd.Interface, error) { + return "mock", mockAccount{f}, nil + }} +} + +type authentiacteFunc = func(ctx context.Context, msg *account_abstractionv1.MsgAuthenticate) (*account_abstractionv1.MsgAuthenticateResponse, error) + +type fixture struct { + t *testing.T + + app *integration.App + cdc codec.Codec + ctx context.Context + + authKeeper authkeeper.AccountKeeper + accountsKeeper accounts.Keeper + bankKeeper bankkeeper.Keeper + + mockAccountAddress []byte + bundler string +} + +func (f fixture) mustAddr(address []byte) string { + s, _ := f.authKeeper.AddressCodec().BytesToString(address) + return s +} + +func (f fixture) runBundle(txBytes ...[]byte) *accountsv1.MsgExecuteBundleResponse { + f.t.Helper() + + msgSrv := accounts.NewMsgServer(f.accountsKeeper) + + resp, err := msgSrv.ExecuteBundle(f.ctx, &accountsv1.MsgExecuteBundle{ + Bundler: f.bundler, + Txs: txBytes, + }) + require.NoError(f.t, err) + return resp +} + +func (f fixture) mint(address []byte, coins ...sdk.Coin) { + f.t.Helper() + for _, coin := range coins { + err := f.bankKeeper.MintCoins(f.ctx, minttypes.ModuleName, sdk.NewCoins(coin)) + require.NoError(f.t, err) + err = f.bankKeeper.SendCoinsFromModuleToAccount(f.ctx, minttypes.ModuleName, address, sdk.NewCoins(coin)) + require.NoError(f.t, err) + } +} + +func (f fixture) balance(recipient, denom string) sdk.Coin { + f.t.Helper() + balances, err := f.bankKeeper.Balance(f.ctx, &banktypes.QueryBalanceRequest{ + Address: recipient, + Denom: denom, + }) + require.NoError(f.t, err) + return *balances.Balance +} + +func initFixture(t *testing.T, f authentiacteFunc) *fixture { + t.Helper() + + fixture := &fixture{} + fixture.t = t + encodingCfg := moduletestutil.MakeTestEncodingConfig(codectestutil.CodecOptions{}, auth.AppModule{}, bank.AppModule{}, accounts.AppModule{}) + cdc := encodingCfg.Codec + + moduleConfigs := []configurator.ModuleOption{ + configurator.AccountsModule(), + configurator.AuthModule(), + configurator.BankModule(), + configurator.VestingModule(), + configurator.StakingModule(), + configurator.TxModule(), + configurator.ValidateModule(), + configurator.ConsensusModule(), + configurator.GenutilModule(), + } + + var err error + startupCfg := integration.DefaultStartUpConfig(t) + + msgRouterService := integration.NewRouterService() + fixture.registerMsgRouterService(msgRouterService) + + var routerFactory runtime.RouterServiceFactory = func(_ []byte) router.Service { + return msgRouterService + } + + queryRouterService := integration.NewRouterService() + fixture.registerQueryRouterService(queryRouterService) + + serviceBuilder := runtime.NewRouterBuilder(routerFactory, queryRouterService) + + startupCfg.BranchService = &integration.BranchService{} + startupCfg.RouterServiceBuilder = serviceBuilder + startupCfg.HeaderService = &integration.HeaderService{} + startupCfg.GasService = &integration.GasService{} + + fixture.app, err = integration.NewApp( + depinject.Configs(configurator.NewAppV2Config(moduleConfigs...), depinject.Provide( + // inject desired account types: + basedepinject.ProvideAccount, + + // provide base account options + basedepinject.ProvideSecp256K1PubKey, + + ProvideMockAccount, + counteraccount.ProvideAccount, + ), depinject.Supply(log.NewNopLogger(), f)), + startupCfg, + &fixture.bankKeeper, &fixture.accountsKeeper, &fixture.authKeeper, &fixture.cdc) + require.NoError(t, err) + + fixture.ctx = fixture.app.StateLatestContext(t) + + // init account + _, addr, err := fixture.accountsKeeper.Init(fixture.ctx, "mock", []byte("system"), &gogotypes.Empty{}, nil, nil) + require.NoError(t, err) + + fixture.cdc = cdc + fixture.mockAccountAddress = addr + fixture.bundler = fixture.mustAddr([]byte("bundler")) + return fixture +} + +func (f *fixture) registerMsgRouterService(router *integration.RouterService) { + // register custom router service + bankSendHandler := func(ctx context.Context, req transaction.Msg) (transaction.Msg, error) { + msg, ok := req.(*banktypes.MsgSend) + if !ok { + return nil, integration.ErrInvalidMsgType + } + msgServer := bankkeeper.NewMsgServerImpl(f.bankKeeper) + resp, err := msgServer.Send(ctx, msg) + return resp, err + } + + router.RegisterHandler(bankSendHandler, "cosmos.bank.v1beta1.MsgSend") +} + +func (f *fixture) registerQueryRouterService(router *integration.RouterService) { + // register custom router service + queryHandler := func(ctx context.Context, msg transaction.Msg) (transaction.Msg, error) { + req, ok := msg.(*accountsv1.AccountNumberRequest) + if !ok { + return nil, integration.ErrInvalidMsgType + } + qs := accounts.NewQueryServer(f.accountsKeeper) + resp, err := qs.AccountNumber(ctx, req) + return resp, err + } + + router.RegisterHandler(queryHandler, "cosmos.accounts.v1.AccountNumberRequest") +} diff --git a/tests/integration/accounts/wiring_test.go b/tests/integration/v2/accounts/wiring_test.go similarity index 62% rename from tests/integration/accounts/wiring_test.go rename to tests/integration/v2/accounts/wiring_test.go index 3d0a8ed0b5b4..649d990f8d05 100644 --- a/tests/integration/accounts/wiring_test.go +++ b/tests/integration/v2/accounts/wiring_test.go @@ -6,10 +6,11 @@ import ( "github.com/stretchr/testify/require" "cosmossdk.io/core/header" - storetypes "cosmossdk.io/store/types" + stfgas "cosmossdk.io/server/v2/stf/gas" counterv1 "cosmossdk.io/x/accounts/testing/counter/v1" "cosmossdk.io/x/bank/testutil" + "github.com/cosmos/cosmos-sdk/tests/integration/v2" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -21,21 +22,21 @@ import ( // - gas service // - funds func TestDependencies(t *testing.T) { - app := setupApp(t) - ak := app.AccountsKeeper - ctx := sdk.NewContext(app.CommitMultiStore(), false, app.Logger()).WithHeaderInfo(header.Info{ChainID: "chain-id"}) - ctx = ctx.WithGasMeter(storetypes.NewGasMeter(500_000)) + f := initFixture(t, nil) + ctx := f.ctx + ctx = integration.SetHeaderInfo(ctx, header.Info{ChainID: "chain-id"}) + ctx = integration.SetGasMeter(ctx, stfgas.DefaultGasMeter(500_000)) - _, counterAddr, err := ak.Init(ctx, "counter", accCreator, &counterv1.MsgInit{ + _, counterAddr, err := f.accountsKeeper.Init(ctx, "counter", accCreator, &counterv1.MsgInit{ InitialValue: 0, }, nil, nil) require.NoError(t, err) // test dependencies creatorInitFunds := sdk.NewCoins(sdk.NewInt64Coin("stake", 100_000)) - err = testutil.FundAccount(ctx, app.BankKeeper, accCreator, creatorInitFunds) + err = testutil.FundAccount(ctx, f.bankKeeper, accCreator, creatorInitFunds) require.NoError(t, err) sentFunds := sdk.NewCoins(sdk.NewInt64Coin("stake", 50_000)) - r, err := ak.Execute( + r, err := f.accountsKeeper.Execute( ctx, counterAddr, accCreator, @@ -50,18 +51,19 @@ func TestDependencies(t *testing.T) { require.NotZero(t, res.AfterGas) require.Equal(t, int(uint64(10)), int(res.AfterGas-res.BeforeGas)) + headerInfo := integration.HeaderInfoFromContext(ctx) // test header service - require.Equal(t, ctx.HeaderInfo().ChainID, res.ChainId) + require.Equal(t, headerInfo.ChainID, res.ChainId) // test address codec - wantAddr, err := app.AuthKeeper.AddressCodec().BytesToString(counterAddr) + wantAddr, err := f.authKeeper.AddressCodec().BytesToString(counterAddr) require.NoError(t, err) require.Equal(t, wantAddr, res.Address) // test funds - creatorFunds := app.BankKeeper.GetAllBalances(ctx, accCreator) + creatorFunds := f.bankKeeper.GetAllBalances(ctx, accCreator) require.Equal(t, creatorInitFunds.Sub(sentFunds...), creatorFunds) - accFunds := app.BankKeeper.GetAllBalances(ctx, counterAddr) + accFunds := f.bankKeeper.GetAllBalances(ctx, counterAddr) require.Equal(t, sentFunds, accFunds) } diff --git a/tests/integration/v2/services.go b/tests/integration/v2/services.go index f608fd65fdb0..f8c27ff12666 100644 --- a/tests/integration/v2/services.go +++ b/tests/integration/v2/services.go @@ -21,6 +21,7 @@ import ( corestore "cosmossdk.io/core/store" "cosmossdk.io/core/transaction" "cosmossdk.io/server/v2/stf" + stfbranch "cosmossdk.io/server/v2/stf/branch" stfgas "cosmossdk.io/server/v2/stf/gas" ) @@ -139,6 +140,15 @@ func GasMeterFactory(ctx context.Context) func() gas.Meter { } } +func SetGasMeter(ctx context.Context, meter gas.Meter) context.Context { + iCtx, ok := ctx.Value(contextKey).(*integrationContext) + if !ok { + return ctx + } + iCtx.gasMeter = meter + return context.WithValue(ctx, contextKey, iCtx) +} + func (s storeService) OpenKVStore(ctx context.Context) corestore.KVStore { const gasLimit = 100_000 iCtx, ok := ctx.Value(contextKey).(*integrationContext) @@ -244,15 +254,55 @@ func (bs *BranchService) ExecuteWithGasLimit( return 0, errors.New("context is not an integration context") } + originalGasMeter := iCtx.gasMeter + + iCtx.gasMeter = stfgas.DefaultGasMeter(gasLimit) + // execute branched, with predefined gas limit. - err = f(ctx) + err = bs.execute(ctx, iCtx, f) + // restore original context gasUsed = iCtx.gasMeter.Limit() - iCtx.gasMeter.Remaining() - _ = iCtx.gasMeter.Consume(gasUsed, "execute-with-gas-limit") + _ = originalGasMeter.Consume(gasUsed, "execute-with-gas-limit") + iCtx.gasMeter = stfgas.DefaultGasMeter(originalGasMeter.Remaining()) return gasUsed, err } +func (bs BranchService) execute(ctx context.Context, ictx *integrationContext, f func(ctx context.Context) error) error { + branchedState := stfbranch.DefaultNewWriterMap(ictx.state) + meteredBranchedState := stfgas.DefaultWrapWithGasMeter(ictx.gasMeter, branchedState) + + branchedCtx := &integrationContext{ + state: meteredBranchedState, + gasMeter: ictx.gasMeter, + header: ictx.header, + events: ictx.events, + } + + newCtx := context.WithValue(ctx, contextKey, branchedCtx) + + err := f(newCtx) + if err != nil { + return err + } + + err = applyStateChanges(ictx.state, branchedCtx.state) + if err != nil { + return err + } + + return nil +} + +func applyStateChanges(dst, src corestore.WriterMap) error { + changes, err := src.GetStateChanges() + if err != nil { + return err + } + return dst.ApplyStateChanges(changes) +} + // msgTypeURL returns the TypeURL of a proto message. func msgTypeURL(msg gogoproto.Message) string { return gogoproto.MessageName(msg)