Skip to content

Commit

Permalink
deps: upgrade capability to sdk v0.50 and remove ibc-go dependency (#…
Browse files Browse the repository at this point in the history
…4068)

* adding testing/simapp dir for testing purposes

* upgrade to sdk v0.50.0-alpha.1 and rm dep on ibc-go simapp

* refactor and improve capability tests to use test helpers in favour of simapp

* rm simapp and go mod tidy

* update godoc

* assert the transfer capability does not exist until memstore is reinitialised
  • Loading branch information
damiannolan authored Jul 13, 2023
1 parent 7ee9a31 commit 49cdfc5
Show file tree
Hide file tree
Showing 11 changed files with 272 additions and 689 deletions.
129 changes: 76 additions & 53 deletions modules/capability/capability_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,101 +3,124 @@ package capability_test
import (
"testing"

abci "github.com/cometbft/cometbft/abci/types"
tmproto "github.com/cometbft/cometbft/proto/tendermint/types"
"github.com/stretchr/testify/suite"

"cosmossdk.io/log"
"cosmossdk.io/store"
"cosmossdk.io/store/metrics"
storetypes "cosmossdk.io/store/types"

dbm "github.com/cosmos/cosmos-db"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/stretchr/testify/suite"

"github.com/cosmos/ibc-go/v7/testing/simapp"
tmproto "github.com/cometbft/cometbft/proto/tendermint/types"

"github.com/cosmos/ibc-go/modules/capability"
"github.com/cosmos/ibc-go/modules/capability/keeper"
"github.com/cosmos/ibc-go/modules/capability/types"
)

const memStoreKey = "memory:mock"
const mockMemStoreKey = "memory:mock"

type CapabilityTestSuite struct {
suite.Suite
cdc codec.Codec
ctx sdk.Context
app *simapp.SimApp

cdc codec.Codec
ctx sdk.Context

keeper *keeper.Keeper
module module.AppModule

storeKey *storetypes.KVStoreKey
memStoreKey *storetypes.MemoryStoreKey
mockMemStoreKey *storetypes.MemoryStoreKey
}

func (suite *CapabilityTestSuite) SetupTest() {
checkTx := false
app := simapp.Setup(suite.T(), checkTx)
cdc := app.AppCodec()

// create new keeper so we can define custom scoping before init and seal
keeper := keeper.NewKeeper(cdc, app.GetKey(types.StoreKey), app.GetMemKey(types.MemStoreKey))

suite.app = app
suite.ctx = app.BaseApp.NewContext(checkTx, tmproto.Header{Height: 1})
suite.keeper = keeper
suite.cdc = cdc
suite.module = capability.NewAppModule(cdc, *keeper, false)
encodingCfg := moduletestutil.MakeTestEncodingConfig(capability.AppModuleBasic{})
suite.cdc = encodingCfg.Codec

suite.storeKey = storetypes.NewKVStoreKey(types.StoreKey)
suite.memStoreKey = storetypes.NewMemoryStoreKey(types.MemStoreKey)
suite.mockMemStoreKey = storetypes.NewMemoryStoreKey(mockMemStoreKey)

suite.ctx = suite.NewTestContext()
suite.keeper = keeper.NewKeeper(suite.cdc, suite.storeKey, suite.memStoreKey)
}

func (suite *CapabilityTestSuite) NewTestContext() sdk.Context {
db := dbm.NewMemDB()
cms := store.NewCommitMultiStore(db, log.NewNopLogger(), metrics.NewNoOpMetrics())
cms.MountStoreWithDB(suite.storeKey, storetypes.StoreTypeIAVL, db)
cms.MountStoreWithDB(suite.memStoreKey, storetypes.StoreTypeMemory, db)
cms.MountStoreWithDB(suite.mockMemStoreKey, storetypes.StoreTypeMemory, db)

err := cms.LoadLatestVersion()
suite.Require().NoError(err)

return sdk.NewContext(cms, tmproto.Header{}, false, log.NewNopLogger())
}

// The following test case mocks a specific bug discovered in https://github.com/cosmos/cosmos-sdk/issues/9800
// and ensures that the current code successfully fixes the issue.
// This test emulates statesync by firstly populating persisted state by creating a new scoped keeper and capability.
// In-memory storage is then discarded by creating a new capability keeper and app module using a mock memstore key.
// BeginBlock is then called to populate the new in-memory store using the persisted state.
func (suite *CapabilityTestSuite) TestInitializeMemStore() {
sk1 := suite.keeper.ScopeToModule(banktypes.ModuleName)
// create a scoped keeper and instantiate a new capability to populate state
scopedKeeper := suite.keeper.ScopeToModule(banktypes.ModuleName)

cap1, err := sk1.NewCapability(suite.ctx, "transfer")
cap1, err := scopedKeeper.NewCapability(suite.ctx, "transfer")
suite.Require().NoError(err)
suite.Require().NotNil(cap1)

// mock statesync by creating new keeper that shares persistent state but loses in-memory map
newKeeper := keeper.NewKeeper(suite.cdc, suite.app.GetKey(types.StoreKey), suite.app.GetMemKey(memStoreKey))
newSk1 := newKeeper.ScopeToModule(banktypes.ModuleName)
// mock statesync by creating a new keeper and module that shares persisted state
// but discards in-memory map by using a mock memstore key
newKeeper := keeper.NewKeeper(suite.cdc, suite.storeKey, suite.mockMemStoreKey)
newModule := capability.NewAppModule(suite.cdc, *newKeeper, true)

// Mock App startup
ctx := suite.app.BaseApp.NewUncachedContext(false, tmproto.Header{})
// reassign the scoped keeper, this will inherit the the mock memstore key used above
scopedKeeper = newKeeper.ScopeToModule(banktypes.ModuleName)

// seal the new keeper and ensure the in-memory store is not initialized
newKeeper.Seal()
suite.Require().False(newKeeper.IsInitialized(ctx), "memstore initialized flag set before BeginBlock")
suite.Require().False(newKeeper.IsInitialized(suite.ctx), "memstore initialized flag set before BeginBlock")

cap1, ok := scopedKeeper.GetCapability(suite.ctx, "transfer")
suite.Require().False(ok)
suite.Require().Nil(cap1)

// Mock app beginblock and ensure that no gas has been consumed and memstore is initialized
ctx = suite.app.BaseApp.NewContext(false, tmproto.Header{}).WithBlockGasMeter(sdk.NewGasMeter(50))
// add a new block gas meter to the context
ctx := suite.ctx.WithBlockGasMeter(storetypes.NewGasMeter(50))

prevGas := ctx.GasMeter().GasConsumed()
prevBlockGas := ctx.BlockGasMeter().GasConsumed()
prevGas := ctx.BlockGasMeter().GasConsumed()

restartedModule := capability.NewAppModule(suite.cdc, *newKeeper, true)
restartedModule.BeginBlock(ctx, abci.RequestBeginBlock{})
gasUsed := ctx.GasMeter().GasConsumed()
// call app module BeginBlock and ensure that no gas has been consumed
newModule.BeginBlock(ctx)

suite.Require().True(newKeeper.IsInitialized(ctx), "memstore initialized flag not set")
gasUsed := ctx.GasMeter().GasConsumed()
blockGasUsed := ctx.BlockGasMeter().GasConsumed()

suite.Require().Equal(prevBlockGas, blockGasUsed, "ensure beginblocker consumed no block gas during execution")
suite.Require().Equal(prevGas, gasUsed, "ensure beginblocker consumed no gas during execution")

// Mock the first transaction getting capability and subsequently failing
// by using a cached context and discarding all cached writes.
cacheCtx, _ := ctx.CacheContext()
capability, ok := newSk1.GetCapability(cacheCtx, "transfer")
suite.Require().NotNil(capability)
suite.Require().True(ok)

// Ensure that the second transaction can still receive capability even if first tx fails.
ctx = suite.app.BaseApp.NewContext(false, tmproto.Header{})
// assert that the in-memory store is now initialized
suite.Require().True(newKeeper.IsInitialized(ctx), "memstore initialized flag not set")

cap1, ok = newSk1.GetCapability(ctx, "transfer")
// ensure that BeginBlock has populated the new in-memory store (using the mock memstore key) and initialized capabilities
cap1, ok = scopedKeeper.GetCapability(ctx, "transfer")
suite.Require().True(ok)
suite.Require().NotNil(cap1)

// Ensure the capabilities don't get reinitialized on next BeginBlock
// by testing to see if capability returns same pointer
// also check that initialized flag is still set
restartedModule.BeginBlock(ctx, abci.RequestBeginBlock{})
recap, ok := newSk1.GetCapability(ctx, "transfer")
// ensure capabilities do not get reinitialized on next BeginBlock by comparing capability pointers
// and assert that the in-memory store is still initialized
newModule.BeginBlock(ctx)
refreshedCap, ok := scopedKeeper.GetCapability(ctx, "transfer")
suite.Require().True(ok)
suite.Require().Equal(cap1, recap, "capabilities got reinitialized after second BeginBlock")
suite.Require().Equal(cap1, refreshedCap, "capabilities got reinitialized after second BeginBlock")
suite.Require().True(newKeeper.IsInitialized(ctx), "memstore initialized flag not set")
}

Expand Down
18 changes: 5 additions & 13 deletions modules/capability/genesis_test.go
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
package capability_test

import (
dbm "github.com/cometbft/cometbft-db"
"github.com/cometbft/cometbft/libs/log"
tmproto "github.com/cometbft/cometbft/proto/tendermint/types"
simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
sdk "github.com/cosmos/cosmos-sdk/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/cosmos/ibc-go/v7/testing/simapp"

"github.com/cosmos/ibc-go/modules/capability"
"github.com/cosmos/ibc-go/modules/capability/keeper"
"github.com/cosmos/ibc-go/modules/capability/types"
)

func (suite *CapabilityTestSuite) TestGenesis() {
// InitGenesis must be called in order to set the intial index to 1.
capability.InitGenesis(suite.ctx, *suite.keeper, *types.DefaultGenesis())

sk1 := suite.keeper.ScopeToModule(banktypes.ModuleName)
sk2 := suite.keeper.ScopeToModule(stakingtypes.ModuleName)

Expand All @@ -32,15 +29,10 @@ func (suite *CapabilityTestSuite) TestGenesis() {

genState := capability.ExportGenesis(suite.ctx, *suite.keeper)

// create new app that does not share persistent or in-memory state
// and initialize app from exported genesis state above.
db := dbm.NewMemDB()
newApp := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, simtestutil.EmptyAppOptions{})

newKeeper := keeper.NewKeeper(suite.cdc, newApp.GetKey(types.StoreKey), newApp.GetMemKey(types.MemStoreKey))
newKeeper := keeper.NewKeeper(suite.cdc, suite.storeKey, suite.memStoreKey)
newSk1 := newKeeper.ScopeToModule(banktypes.ModuleName)
newSk2 := newKeeper.ScopeToModule(stakingtypes.ModuleName)
deliverCtx, _ := newApp.BaseApp.NewUncachedContext(false, tmproto.Header{}).WithBlockGasMeter(sdk.NewInfiniteGasMeter()).CacheContext()
deliverCtx := suite.NewTestContext()

capability.InitGenesis(deliverCtx, *newKeeper, *genState)

Expand Down
Loading

0 comments on commit 49cdfc5

Please sign in to comment.