Skip to content

Commit

Permalink
Fix Compatibility Tests using govv1beta1 GenesisStates (#3052)
Browse files Browse the repository at this point in the history
  • Loading branch information
chatton authored Feb 2, 2023
1 parent 6c008ea commit 65f7038
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 45 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"chain-a": ["release-v4.3.x"],
"chain-b": ["release-v4.3.x", "v6.1.0", "v5.2.0", "4.2.0", "v4.1.1", "v3.4.0", "v3.3.1", "v2.5.0", "v2.4.2"],
"chain-b": ["release-v4.3.x", "v6.1.0", "v5.2.0", "v4.2.0", "v4.1.1", "v3.4.0", "v3.3.1", "v2.5.0", "v2.4.2"],
"entrypoint": ["TestTransferTestSuite"],
"test": [
"TestMsgTransfer_Succeeds_Nonincentivized",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"chain-a": ["release-v4.3.x", "v6.1.0", "v5.2.0", "4.2.0", "v4.1.1", "v3.4.0", "v3.3.1", "v2.5.0", "v2.4.2"],
"chain-a": ["release-v4.3.x", "v6.1.0", "v5.2.0", "v4.2.0", "v4.1.1", "v3.4.0", "v3.3.1", "v2.5.0", "v2.4.2"],
"chain-b": ["release-v4.3.x"],
"entrypoint": ["TestTransferTestSuite"],
"test": [
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"chain-a": ["release-v7.0.x"],
"chain-b": ["release-v7.0.x", "v6.1.0", "v5.2.0", "v4.2.0", "v4.1.1", "v3.4.0", "v3.3.1", "v2.5.0", "v2.4.2"],
"entrypoint": ["TestTransferTestSuite"],
"test": [
"TestMsgTransfer_Succeeds_Nonincentivized",
"TestMsgTransfer_Fails_InvalidAddress",
"TestMsgTransfer_Timeout_Nonincentivized",
"TestMsgTransfer_WithMemo",
"TestSendEnabledParam",
"TestReceiveEnabledParam"
],
"chain-binary": ["simd"],
"chain-image": ["ghcr.io/cosmos/ibc-go-simd"]
}
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,4 @@ jobs:
push: true
tags: ${{ steps.meta.outputs.tags }}
build-args: |
IBC_GO_VERSION="${{ github.ref_name }}"
IBC_GO_VERSION=${{ github.ref_name }}
13 changes: 13 additions & 0 deletions e2e/semverutil/semver.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package semverutil

import (
"strings"

"golang.org/x/mod/semver"
)

Expand All @@ -16,6 +18,17 @@ type FeatureReleases struct {
// This is true if the version is greater than or equal to the major version it was released in
// or is greater than or equal to the list of minor releases it was included in.
func (fr FeatureReleases) IsSupported(versionStr string) bool {

// in our compatibility tests, our images are in the format of "release-v1.0.x". We want to actually look at
// the "1.0.x" part but we also need this to be a valid version. We can change it to "1.0.0"
// TODO: change the way we provide the ibc-go version. This should be done in a more flexible way such
// as docker labels/metadata instead of the tag, as this will only work for our versioning scheme.
const releasePrefix = "release-"
if strings.HasPrefix(versionStr, releasePrefix) {
versionStr = versionStr[len(releasePrefix):]
versionStr = strings.ReplaceAll(versionStr, "x", "0")
}

// assume any non-semantic version formatted version supports the feature
// this will be useful during development of the e2e test with the new feature
if !semver.IsValid(versionStr) {
Expand Down
129 changes: 87 additions & 42 deletions e2e/testconfig/testconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ import (
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module/testutil"
genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
gogoproto "github.com/cosmos/gogoproto/proto"
"github.com/strangelove-ventures/interchaintest/v7/ibc"
tmjson "github.com/tendermint/tendermint/libs/json"
tmtypes "github.com/tendermint/tendermint/types"

"github.com/cosmos/ibc-go/e2e/semverutil"
"github.com/cosmos/ibc-go/e2e/testvalues"
Expand Down Expand Up @@ -165,6 +167,7 @@ func DefaultChainOptions() ChainOptions {

// newDefaultSimappConfig creates an ibc configuration for simd.
func newDefaultSimappConfig(cc ChainConfig, name, chainID, denom string) ibc.ChainConfig {

return ibc.ChainConfig{
Type: "cosmos",
Name: name,
Expand All @@ -183,33 +186,66 @@ func newDefaultSimappConfig(cc ChainConfig, name, chainID, denom string) ibc.Cha
GasAdjustment: 1.3,
TrustingPeriod: "508h",
NoHostMount: false,
ModifyGenesis: defaultModifyGenesis(),
ModifyGenesis: getGenesisModificationFunction(cc),
}
}

// getGenesisModificationFunction returns a genesis modification function that handles the GenesisState type
// correctly depending on if the govv1beta1 gov module is used or if govv1 is being used.
func getGenesisModificationFunction(cc ChainConfig) func(ibc.ChainConfig, []byte) ([]byte, error) {
version := cc.Tag

if govGenesisFeatureReleases.IsSupported(version) {
return defaultGovv1ModifyGenesis()
}

return defaultGovv1Beta1ModifyGenesis()
}

// govGenesisFeatureReleases represents the releases the governance module genesis
// was upgraded from v1beta1 to v1.
var govGenesisFeatureReleases = semverutil.FeatureReleases{
MajorVersion: "v7",
}

// defaultModifyGenesis will only modify governance params to ensure the voting period and minimum deposit
// defaultGovv1ModifyGenesis will only modify governance params to ensure the voting period and minimum deposit
// are functional for e2e testing purposes.
// Note: this function intentionally does not use the type defined here https://github.com/tendermint/tendermint/blob/v0.37.0-rc2/types/genesis.go#L38-L46
// and uses a map[string]interface{} instead.
// This approach prevents the field block.TimeIotaMs from being lost which happened when using the GenesisDoc type from tendermint version v0.37.0.
// ibctest performs the following steps when creating the genesis.json file for chains.
// - 1. Let the chain binary create its own genesis file.
// - 2. Apply any provided functions to modify the bytes of the file.
// - 3. Overwrite the file with the new contents.
// This is a problem because when the tendermint types change, marshalling into the type will cause us to lose
// values if the types have changed in between the version of the chain in the test and the version of tendermint
// imported by the e2e tests.
// By using a raw map[string]interface{} we preserve the values unknown to the e2e tests and can still change
// the values we care about.
// TODO: handle these genesis modifications in a way which is type safe and does not require us to rely on
// map[string]interface{}
func defaultModifyGenesis() func(ibc.ChainConfig, []byte) ([]byte, error) {
func defaultGovv1ModifyGenesis() func(ibc.ChainConfig, []byte) ([]byte, error) {
return func(chainConfig ibc.ChainConfig, genbz []byte) ([]byte, error) {
genDoc, err := tmtypes.GenesisDocFromJSON(genbz)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal genesis bytes into genesis doc: %w", err)
}

var appState genutiltypes.AppMap
if err := json.Unmarshal(genDoc.AppState, &appState); err != nil {
return nil, fmt.Errorf("failed to unmarshal genesis bytes into app state: %w", err)
}

govGenBz, err := modifyGovAppState(chainConfig, appState[govtypes.ModuleName])
if err != nil {
return nil, err
}

appState[govtypes.ModuleName] = govGenBz

genDoc.AppState, err = json.Marshal(appState)
if err != nil {
return nil, err
}

bz, err := tmjson.MarshalIndent(genDoc, "", " ")
if err != nil {
return nil, err
}

return bz, nil
}
}

// defaultGovv1Beta1ModifyGenesis will only modify governance params to ensure the voting period and minimum deposit
// // are functional for e2e testing purposes.
func defaultGovv1Beta1ModifyGenesis() func(ibc.ChainConfig, []byte) ([]byte, error) {
const appStateKey = "app_state"
return func(chainConfig ibc.ChainConfig, genbz []byte) ([]byte, error) {
genesisDocMap := map[string]interface{}{}
Expand All @@ -228,7 +264,7 @@ func defaultModifyGenesis() func(ibc.ChainConfig, []byte) ([]byte, error) {
return nil, fmt.Errorf("failed to extract gov genesis bytes: %s", err)
}

govModuleGenesisBytes, err := modifyGovAppState(chainConfig, govModuleBytes)
govModuleGenesisBytes, err := modifyGovv1Beta1AppState(chainConfig, govModuleBytes)
if err != nil {
return nil, err
}
Expand All @@ -251,41 +287,50 @@ func defaultModifyGenesis() func(ibc.ChainConfig, []byte) ([]byte, error) {
}
}

// modifyGovAppState takes the existing gov app state and marshals it to either a govv1 GenesisState
// or a govv1beta1 GenesisState depending on the simapp version.
// modifyGovAppState takes the existing gov app state and marshals it to a govv1 GenesisState.
func modifyGovAppState(chainConfig ibc.ChainConfig, govAppState []byte) ([]byte, error) {
cfg := testutil.MakeTestEncodingConfig()

cdc := codec.NewProtoCodec(cfg.InterfaceRegistry)
govv1.RegisterInterfaces(cfg.InterfaceRegistry)
govv1beta1.RegisterInterfaces(cfg.InterfaceRegistry)

shouldUseGovV1 := govGenesisFeatureReleases.IsSupported(chainConfig.Images[0].Version)

var govGenesisState gogoproto.Message
if shouldUseGovV1 {
govGenesisState = &govv1.GenesisState{}
} else {
govGenesisState = &govv1beta1.GenesisState{}
}
govGenesisState := &govv1.GenesisState{}

if err := cdc.UnmarshalJSON(govAppState, govGenesisState); err != nil {
return nil, fmt.Errorf("failed to unmarshal genesis bytes into gov genesis state: %w", err)
}

switch v := govGenesisState.(type) {
case *govv1.GenesisState:
if v.Params == nil {
v.Params = &govv1.Params{}
}
// set correct minimum deposit using configured denom
v.Params.MinDeposit = sdk.NewCoins(sdk.NewCoin(chainConfig.Denom, govv1beta1.DefaultMinDepositTokens))
vp := testvalues.VotingPeriod
v.Params.VotingPeriod = &vp
case *govv1beta1.GenesisState:
v.DepositParams.MinDeposit = sdk.NewCoins(sdk.NewCoin(chainConfig.Denom, govv1beta1.DefaultMinDepositTokens))
v.VotingParams.VotingPeriod = testvalues.VotingPeriod
if govGenesisState.Params == nil {
govGenesisState.Params = &govv1.Params{}
}

govGenesisState.Params.MinDeposit = sdk.NewCoins(sdk.NewCoin(chainConfig.Denom, govv1beta1.DefaultMinDepositTokens))
vp := testvalues.VotingPeriod
govGenesisState.Params.VotingPeriod = &vp

govGenBz, err := cdc.MarshalJSON(govGenesisState)
if err != nil {
return nil, fmt.Errorf("failed to marshal gov genesis state: %w", err)
}

return govGenBz, nil
}

// modifyGovv1Beta1AppState takes the existing gov app state and marshals it to a govv1beta1 GenesisState.
func modifyGovv1Beta1AppState(chainConfig ibc.ChainConfig, govAppState []byte) ([]byte, error) {
cfg := testutil.MakeTestEncodingConfig()

cdc := codec.NewProtoCodec(cfg.InterfaceRegistry)
govv1beta1.RegisterInterfaces(cfg.InterfaceRegistry)

govGenesisState := &govv1beta1.GenesisState{}
if err := cdc.UnmarshalJSON(govAppState, govGenesisState); err != nil {
return nil, fmt.Errorf("failed to unmarshal genesis bytes into govv1beta1 genesis state: %w", err)
}

govGenesisState.DepositParams.MinDeposit = sdk.NewCoins(sdk.NewCoin(chainConfig.Denom, govv1beta1.DefaultMinDepositTokens))
govGenesisState.VotingParams.VotingPeriod = testvalues.VotingPeriod

govGenBz, err := cdc.MarshalJSON(govGenesisState)
if err != nil {
return nil, fmt.Errorf("failed to marshal gov genesis state: %w", err)
Expand Down
11 changes: 11 additions & 0 deletions e2e/testsuite/testsuite.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"

"github.com/cosmos/ibc-go/e2e/semverutil"
"github.com/cosmos/ibc-go/e2e/testconfig"
"github.com/cosmos/ibc-go/e2e/testvalues"
controllertypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/controller/types"
Expand Down Expand Up @@ -496,6 +497,11 @@ func (s *E2ETestSuite) ExecuteGovProposal(ctx context.Context, chain *cosmos.Cos
s.Require().Equal(govtypesv1beta1.StatusPassed, proposal.Status)
}

// govv1ProposalTitleAndSummary represents the releases that support the new title and summary fields.
var govv1ProposalTitleAndSummary = semverutil.FeatureReleases{
MajorVersion: "v7",
}

// ExecuteGovProposalV1 submits a governance proposal using the provided user and message and uses all validators
// to vote yes on the proposal. It ensures the proposal successfully passes.
func (s *E2ETestSuite) ExecuteGovProposalV1(ctx context.Context, msg sdk.Msg, chain *cosmos.CosmosChain, user ibc.Wallet, proposalID uint64) {
Expand All @@ -506,6 +512,11 @@ func (s *E2ETestSuite) ExecuteGovProposalV1(ctx context.Context, msg sdk.Msg, ch
msgSubmitProposal, err := govtypesv1.NewMsgSubmitProposal(msgs, sdk.NewCoins(sdk.NewCoin(chain.Config().Denom, govtypesv1.DefaultMinDepositTokens)), sender.String(), "", fmt.Sprintf("e2e gov proposal: %d", proposalID), fmt.Sprintf("executing gov proposal %d", proposalID))
s.Require().NoError(err)

if !govv1ProposalTitleAndSummary.IsSupported(chain.Nodes()[0].Image.Version) {
msgSubmitProposal.Title = ""
msgSubmitProposal.Summary = ""
}

resp, err := s.BroadcastMessages(ctx, chain, user, msgSubmitProposal)
s.AssertValidTxResponse(resp)
s.Require().NoError(err)
Expand Down

0 comments on commit 65f7038

Please sign in to comment.