Skip to content

Commit

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

* deps: upgrade capability to sdk v0.50 and remove ibc-go dependency (#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

(cherry picked from commit 49cdfc5)

# Conflicts:
#	modules/capability/capability_test.go
#	modules/capability/genesis_test.go
#	modules/capability/go.mod
#	modules/capability/go.sum
#	modules/capability/module.go
#	modules/capability/simulation/decoder_test.go

* addressing merge conflicts

* pin goleveldb using replace

* updating to go 1.20 in capability workflows

* just use the workflow from main.. please work

---------

Co-authored-by: Damian Nolan <damiannolan@gmail.com>
  • Loading branch information
mergify[bot] and damiannolan authored Jul 14, 2023
1 parent 3d0db02 commit 72bc817
Show file tree
Hide file tree
Showing 13 changed files with 366 additions and 777 deletions.
13 changes: 7 additions & 6 deletions .github/workflows/capability.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
name: Capability Module
# This workflow runs when a PR is opened that targets code that is part of the capability module.
on:
push:
pull_request:
pull_request:
paths:
- '.github/workflows/capability.yml'
- 'modules/capability/**'
- 'proto/capability/**'
Expand All @@ -11,12 +12,12 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
go-arch: ["amd64", "arm", "arm64"]
go-arch: ['amd64', 'arm', 'arm64']
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: 1.19
go-version: '1.20'
- name: Build capability-module
run: |
cd modules/capability
Expand All @@ -28,8 +29,8 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: 1.19
go-version: '1.20'
- name: Go Test
run: |
cd modules/capability
go test -v -mod=readonly ./...
go test -v -mod=readonly ./...
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(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
19 changes: 5 additions & 14 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,16 +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()
encCdc := simapp.MakeTestEncodingConfig()
newApp := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, simapp.DefaultNodeHome, 5, encCdc, 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 72bc817

Please sign in to comment.