-
Notifications
You must be signed in to change notification settings - Fork 3.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: Capability Issue on Restart, Backport to v0.42 (#9835)
* implement BeginBlock fix * add changelog * fix lint * address reviews * Update CHANGELOG.md Co-authored-by: Aleksandr Bezobchuk <alexanderbez@users.noreply.github.com> * address reviews * Apply suggestions from code review Co-authored-by: Robert Zaremba <robert@zaremba.ch> * move store check * add api breaking changelog * fix lint Co-authored-by: Aleksandr Bezobchuk <alexanderbez@users.noreply.github.com> Co-authored-by: Robert Zaremba <robert@zaremba.ch>
- Loading branch information
1 parent
81988ac
commit 7f41de9
Showing
9 changed files
with
222 additions
and
45 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
package capability_test | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/suite" | ||
abci "github.com/tendermint/tendermint/abci/types" | ||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types" | ||
|
||
"github.com/cosmos/cosmos-sdk/codec" | ||
"github.com/cosmos/cosmos-sdk/simapp" | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
"github.com/cosmos/cosmos-sdk/types/module" | ||
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" | ||
"github.com/cosmos/cosmos-sdk/x/capability" | ||
"github.com/cosmos/cosmos-sdk/x/capability/keeper" | ||
"github.com/cosmos/cosmos-sdk/x/capability/types" | ||
) | ||
|
||
type CapabilityTestSuite struct { | ||
suite.Suite | ||
|
||
cdc codec.Marshaler | ||
ctx sdk.Context | ||
app *simapp.SimApp | ||
keeper *keeper.Keeper | ||
module module.AppModule | ||
} | ||
|
||
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) | ||
} | ||
|
||
// 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. | ||
func (suite *CapabilityTestSuite) TestInitializeMemStore() { | ||
sk1 := suite.keeper.ScopeToModule(banktypes.ModuleName) | ||
|
||
cap1, err := sk1.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("testing")) | ||
newSk1 := newKeeper.ScopeToModule(banktypes.ModuleName) | ||
|
||
// Mock App startup | ||
ctx := suite.app.BaseApp.NewUncachedContext(false, tmproto.Header{}) | ||
newKeeper.InitializeAndSeal(ctx) | ||
suite.Require().False(newKeeper.IsInitialized(ctx), "memstore initialized flag set before BeginBlock") | ||
|
||
// 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)) | ||
prevGas := ctx.BlockGasMeter().GasConsumed() | ||
restartedModule := capability.NewAppModule(suite.cdc, *newKeeper) | ||
restartedModule.BeginBlock(ctx, abci.RequestBeginBlock{}) | ||
suite.Require().True(newKeeper.IsInitialized(ctx), "memstore initialized flag not set") | ||
gasUsed := ctx.BlockGasMeter().GasConsumed() | ||
|
||
suite.Require().Equal(prevGas, gasUsed, "beginblocker consumed 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() | ||
_, ok := newSk1.GetCapability(cacheCtx, "transfer") | ||
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{}) | ||
|
||
cap1, ok = newSk1.GetCapability(ctx, "transfer") | ||
suite.Require().True(ok) | ||
|
||
// 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") | ||
suite.Require().True(ok) | ||
suite.Require().Equal(cap1, recap, "capabilities got reinitialized after second BeginBlock") | ||
suite.Require().True(newKeeper.IsInitialized(ctx), "memstore initialized flag not set") | ||
} | ||
|
||
func TestCapabilityTestSuite(t *testing.T) { | ||
suite.Run(t, new(CapabilityTestSuite)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package capability_test | ||
|
||
import ( | ||
"github.com/tendermint/tendermint/libs/log" | ||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types" | ||
dbm "github.com/tendermint/tm-db" | ||
|
||
"github.com/cosmos/cosmos-sdk/simapp" | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" | ||
"github.com/cosmos/cosmos-sdk/x/capability" | ||
"github.com/cosmos/cosmos-sdk/x/capability/keeper" | ||
"github.com/cosmos/cosmos-sdk/x/capability/types" | ||
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" | ||
) | ||
|
||
func (suite *CapabilityTestSuite) TestGenesis() { | ||
sk1 := suite.keeper.ScopeToModule(banktypes.ModuleName) | ||
sk2 := suite.keeper.ScopeToModule(stakingtypes.ModuleName) | ||
|
||
cap1, err := sk1.NewCapability(suite.ctx, "transfer") | ||
suite.Require().NoError(err) | ||
suite.Require().NotNil(cap1) | ||
|
||
err = sk2.ClaimCapability(suite.ctx, cap1, "transfer") | ||
suite.Require().NoError(err) | ||
|
||
cap2, err := sk2.NewCapability(suite.ctx, "ica") | ||
suite.Require().NoError(err) | ||
suite.Require().NotNil(cap2) | ||
|
||
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, simapp.EmptyAppOptions{}) | ||
|
||
newKeeper := keeper.NewKeeper(suite.cdc, newApp.GetKey(types.StoreKey), newApp.GetMemKey(types.MemStoreKey)) | ||
newSk1 := newKeeper.ScopeToModule(banktypes.ModuleName) | ||
newSk2 := newKeeper.ScopeToModule(stakingtypes.ModuleName) | ||
deliverCtx, _ := newApp.BaseApp.NewUncachedContext(false, tmproto.Header{}).WithBlockGasMeter(sdk.NewInfiniteGasMeter()).CacheContext() | ||
|
||
capability.InitGenesis(deliverCtx, *newKeeper, *genState) | ||
|
||
// check that all previous capabilities exist in new app after InitGenesis | ||
sk1Cap1, ok := newSk1.GetCapability(deliverCtx, "transfer") | ||
suite.Require().True(ok, "could not get first capability after genesis on first ScopedKeeper") | ||
suite.Require().Equal(*cap1, *sk1Cap1, "capability values not equal on first ScopedKeeper") | ||
|
||
sk2Cap1, ok := newSk2.GetCapability(deliverCtx, "transfer") | ||
suite.Require().True(ok, "could not get first capability after genesis on first ScopedKeeper") | ||
suite.Require().Equal(*cap1, *sk2Cap1, "capability values not equal on first ScopedKeeper") | ||
|
||
sk2Cap2, ok := newSk2.GetCapability(deliverCtx, "ica") | ||
suite.Require().True(ok, "could not get second capability after genesis on second ScopedKeeper") | ||
suite.Require().Equal(*cap2, *sk2Cap2, "capability values not equal on second ScopedKeeper") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters