refactor(tests/integration): Port x/accounts integration tests to server v2 (#22881)

This commit is contained in:
son trinh 2024-12-16 23:29:18 +07:00 committed by GitHub
parent 4e81d17254
commit f22d2a84a1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 381 additions and 335 deletions

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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")
}

View File

@ -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)
}

View File

@ -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)