diff --git a/tests/difference/core/quint_model/driver/core.go b/tests/difference/core/quint_model/driver/core.go index 18d37ecd0e..5938b540a5 100644 --- a/tests/difference/core/quint_model/driver/core.go +++ b/tests/difference/core/quint_model/driver/core.go @@ -15,94 +15,100 @@ import ( appConsumer "github.com/cosmos/interchain-security/v3/app/consumer" appProvider "github.com/cosmos/interchain-security/v3/app/provider" + simibc "github.com/cosmos/interchain-security/v3/testutil/simibc" consumerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/consumer/keeper" + providerkeeper "github.com/cosmos/interchain-security/v3/x/ccv/provider/keeper" ) +// Define a new type for ChainIds to be more explicit +// about what the string represents. type ChainId string -type Params struct { - VscTimeout time.Duration - CcvTimeout map[ChainId]time.Duration +type ModelParams struct { + VscTimeout time.Duration + CcvTimeout map[ChainId]time.Duration + UnbondingPeriodPerChain map[ChainId]time.Duration } -type CoreSuite struct { +type Driver struct { t *testing.T + coordinator *ibctesting.Coordinator + // simulate IBC network: for each consumer chain name, we have a path between consumer and provider - simibcs map[string]*simibc.RelayedPath + simibcs map[ChainId]*simibc.RelayedPath // keep around validators for easy access valAddresses []sdk.ValAddress - - // offsets: the model time and heights start at 0 - // so offsets are needed for comparisons. - offsetTimeUnix int64 - offsetHeight int64 } // ctx returns the sdk.Context for the chain -func (s *CoreSuite) ctx(chain string) sdk.Context { +func (s *Driver) ctx(chain ChainId) sdk.Context { return s.chain(chain).GetContext() } // returns the path from the given chain to the provider. -func (s *CoreSuite) path(chain string) *simibc.RelayedPath { +func (s *Driver) path(chain ChainId) *simibc.RelayedPath { return s.simibcs[chain] } -func (s *CoreSuite) chainID(chain string) string { - return map[string]string{P: ibctesting.GetChainID(0), C: ibctesting.GetChainID(1)}[chain] -} - // chain returns the TestChain for a given chain identifier -func (s *CoreSuite) chain(chain string) *ibctesting.TestChain { - return s.path(chain).Chain(chain) +func (s *Driver) chain(chain ChainId) *ibctesting.TestChain { + return s.path(chain).Chain(string(chain)) } -func (s *CoreSuite) providerChain() *ibctesting.TestChain { +func (s *Driver) providerChain() *ibctesting.TestChain { return s.chain("provider") } -func (b *CoreSuite) providerStakingKeeper() stakingkeeper.Keeper { +func (s *Driver) providerCtx() sdk.Context { + return s.providerChain().GetContext() +} + +func (s *Driver) providerKeeper() providerkeeper.Keeper { + return s.providerChain().App.(*appProvider.App).ProviderKeeper +} + +func (b *Driver) providerStakingKeeper() stakingkeeper.Keeper { return *b.providerChain().App.(*appProvider.App).StakingKeeper } -func (b *CoreSuite) providerSlashingKeeper() slashingkeeper.Keeper { +func (b *Driver) providerSlashingKeeper() slashingkeeper.Keeper { return b.providerChain().App.(*appProvider.App).SlashingKeeper } -func (b *CoreSuite) consumerKeeper(chain string) consumerkeeper.Keeper { +func (b *Driver) consumerKeeper(chain ChainId) consumerkeeper.Keeper { return b.chain(chain).App.(*appConsumer.App).ConsumerKeeper } // height returns the height of the current header of chain -func (s *CoreSuite) height(chain string) int64 { +func (s *Driver) height(chain ChainId) int64 { return s.chain(chain).CurrentHeader.GetHeight() } // time returns the time of the current header of chain -func (s *CoreSuite) time(chain string) time.Time { +func (s *Driver) time(chain ChainId) time.Time { return s.chain(chain).CurrentHeader.Time } // delegator retrieves the address for the delegator account -func (s *CoreSuite) delegator() sdk.AccAddress { +func (s *Driver) delegator() sdk.AccAddress { return s.providerChain().SenderAccount.GetAddress() } // validator returns the address for the validator with id (ix) i -func (s *CoreSuite) validator(i int64) sdk.ValAddress { +func (s *Driver) validator(i int64) sdk.ValAddress { return s.valAddresses[i] } // consAddr returns the ConsAdd for the validator with id (ix) i -func (s *CoreSuite) consAddr(i int64) sdk.ConsAddress { +func (s *Driver) consAddr(i int64) sdk.ConsAddress { return sdk.ConsAddress(s.validator(i)) } // isJailed returns the jail status of validator with id (ix) i -func (s *CoreSuite) isJailed(i int64) bool { +func (s *Driver) isJailed(i int64) bool { val, found := s.providerStakingKeeper().GetValidator(s.ctx(P), s.validator(i)) require.True(s.t, found, "GetValidator(%v) -> !found", s.validator(i)) @@ -111,7 +117,7 @@ func (s *CoreSuite) isJailed(i int64) bool { // consumerPower returns the power on the consumer chain chain for // validator with id (ix) i -func (s *CoreSuite) consumerPower(i int64, chain string) (int64, error) { +func (s *Driver) consumerPower(i int64, chain ChainId) (int64, error) { v, found := s.consumerKeeper(chain).GetCCValidator(s.ctx(C), s.validator(i)) if !found { return 0, fmt.Errorf("GetCCValidator(%v) -> !found", s.validator(i)) @@ -121,7 +127,7 @@ func (s *CoreSuite) consumerPower(i int64, chain string) (int64, error) { // delegation returns the number of delegated tokens in the delegation from // the delegator account to the validator with id (ix) i -func (s *CoreSuite) delegation(i int64) int64 { +func (s *Driver) delegation(i int64) int64 { d, found := s.providerStakingKeeper().GetDelegation(s.ctx(P), s.delegator(), s.validator(i)) require.True(s.t, found, "GetDelegation(%v) -> !found", s.validator(i)) return d.Shares.TruncateInt64() @@ -129,7 +135,7 @@ func (s *CoreSuite) delegation(i int64) int64 { // validatorStatus returns the validator status for validator with id (ix) i // on the provider chain -func (s *CoreSuite) validatorStatus(i int64) stakingtypes.BondStatus { +func (s *Driver) validatorStatus(i int64) stakingtypes.BondStatus { v, found := s.providerStakingKeeper().GetValidator(s.ctx(P), s.validator(i)) require.True(s.t, found, "GetValidator(%v) -> !found", s.validator(i)) return v.GetStatus() @@ -137,13 +143,13 @@ func (s *CoreSuite) validatorStatus(i int64) stakingtypes.BondStatus { // providerTokens returns the number of tokens that the validator with // id (ix) i has delegated to it in total on the provider chain -func (s *CoreSuite) providerTokens(i int64) int64 { +func (s *Driver) providerTokens(i int64) int64 { v, found := s.providerStakingKeeper().GetValidator(s.ctx(P), s.validator(i)) require.True(s.t, found, "GetValidator(%v) -> !found", s.validator(i)) return v.Tokens.Int64() } -func (s *CoreSuite) validatorSet(chain string) []stakingtypes.Validator { +func (s *Driver) validatorSet(chain ChainId) []stakingtypes.Validator { if chain == P { return s.providerStakingKeeper().GetLastValidators(s.ctx(P)) } else { @@ -152,14 +158,14 @@ func (s *CoreSuite) validatorSet(chain string) []stakingtypes.Validator { } // delegatorBalance returns the balance of the delegator account -func (s *CoreSuite) delegatorBalance() int64 { +func (s *Driver) delegatorBalance() int64 { d := s.delegator() bal := s.providerChain().App.(*appProvider.App).BankKeeper.GetBalance(s.ctx(P), d, sdk.DefaultBondDenom) return bal.Amount.Int64() } // delegate delegates amt tokens to validator val -func (s *CoreSuite) delegate(val, amt int64) { +func (s *Driver) delegate(val, amt int64) { providerStaking := s.providerStakingKeeper() server := stakingkeeper.NewMsgServerImpl(&providerStaking) coin := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(amt)) @@ -172,7 +178,7 @@ func (s *CoreSuite) delegate(val, amt int64) { } // undelegate undelegates amt tokens from validator val -func (s *CoreSuite) undelegate(val, amt int64) { +func (s *Driver) undelegate(val, amt int64) { providerStaking := s.providerStakingKeeper() server := stakingkeeper.NewMsgServerImpl(&providerStaking) coin := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(amt)) @@ -186,7 +192,7 @@ func (s *CoreSuite) undelegate(val, amt int64) { // consumerSlash simulates a slash event occurring on the consumer chain. // It can be for a downtime or doublesign. -func (s *CoreSuite) consumerSlash(val sdk.ConsAddress, h int64, isDowntime bool, chain string) { +func (s *Driver) consumerSlash(val sdk.ConsAddress, h int64, isDowntime bool, chain ChainId) { kind := stakingtypes.Infraction_INFRACTION_DOUBLE_SIGN if isDowntime { kind = stakingtypes.Infraction_INFRACTION_DOWNTIME @@ -198,29 +204,42 @@ func (s *CoreSuite) consumerSlash(val sdk.ConsAddress, h int64, isDowntime bool, evts := ctx.EventManager().Events() packets := simibc.ParsePacketsFromEvents(evts[before:]) if len(packets) > 0 { - s.path(chain).Outboxes.AddPacket(s.chainID(C), packets[0]) + s.path(chain).Outboxes.AddPacket(C, packets[0]) } } -func (s *CoreSuite) updateClient(chain string) { - s.path(chain).UpdateClient(s.chainID(chain)) +func (s *Driver) updateClient(chain ChainId) { + s.path(chain).UpdateClient(string(chain)) } // deliver numPackets packets from the network to chain -func (s *CoreSuite) deliver(chain string, numPackets int) { +func (s *Driver) deliver(chain ChainId, numPackets int) { // Makes sure client is updated s.updateClient(chain) // Deliver any outstanding acks - s.path(chain).DeliverAcks(s.chainID(chain), 999999) + s.path(chain).DeliverAcks(string(chain), 999999) // Consume deliverable packets from the network - s.path(chain).DeliverPackets(s.chainID(chain), numPackets) + s.path(chain).DeliverPackets(string(chain), numPackets) } -func (s *CoreSuite) endAndBeginBlock(chain string, timeAdvancement time.Duration, preCommitCallback func()) { - s.path(chain).EndAndBeginBlock(s.chainID(chain), timeAdvancement, func() { +func (s *Driver) endAndBeginBlock(chain ChainId, timeAdvancement time.Duration, preCommitCallback func()) { + s.path(chain).EndAndBeginBlock(string(chain), timeAdvancement, func() { }) } +func newDriver(t *testing.T, valAddresses []sdk.ValAddress) *Driver { + t.Log("Creating coordinator") + coordinator := ibctesting.NewCoordinator(t, 0) // start without chains, which we add later + + suite := &Driver{ + t: t, + coordinator: coordinator, + simibcs: make(map[ChainId]*simibc.RelayedPath), + valAddresses: valAddresses, + } + return suite +} + // // The state of the data returned is equivalent to the state of two chains // // after a full handshake, but the precise order of steps used to reach the // // state does not necessarily mimic the order of steps that happen in a diff --git a/tests/difference/core/quint_model/driver/mbt_test.go b/tests/difference/core/quint_model/driver/mbt_test.go index 5325a2dc45..53cb7b9a78 100644 --- a/tests/difference/core/quint_model/driver/mbt_test.go +++ b/tests/difference/core/quint_model/driver/mbt_test.go @@ -3,13 +3,12 @@ package main import ( "log" "testing" + "time" cmttypes "github.com/cometbft/cometbft/types" - icstestingutils "github.com/cosmos/interchain-security/v3/testutil/ibc_testing" + "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/interchain-security/v3/testutil/integration" "github.com/informalsystems/itf-go/itf" - - ibctesting "github.com/cosmos/ibc-go/v7/testing" ) // Given a map from node names to voting powers, create a validator set with the right voting powers. @@ -85,7 +84,25 @@ func TestItfTrace(t *testing.T) { consumers[i] = chain.Value.(string) } - t.Log("Consumer chains are: ", consumers) + chains := append(consumers, "provider") + + t.Log("Chains are: ", chains) + + // create params struct + vscTimeout := time.Duration(params["VscTimeout"].Value.(int64)) + + unbondingPeriodPerChain := make(map[ChainId]time.Duration, len(consumers)) + ccvTimeoutPerChain := make(map[ChainId]time.Duration, len(consumers)) + for _, consumer := range chains { + unbondingPeriodPerChain[ChainId(consumer)] = time.Duration(params["UnbondingPeriodPerChain"].Value.(itf.MapExprType)[consumer].Value.(int64)) + ccvTimeoutPerChain[ChainId(consumer)] = time.Duration(params["CcvTimeout"].Value.(itf.MapExprType)[consumer].Value.(int64)) + } + + modelParams := ModelParams{ + VscTimeout: vscTimeout, + CcvTimeout: ccvTimeoutPerChain, + UnbondingPeriodPerChain: unbondingPeriodPerChain, + } valExprs := params["Nodes"].Value.(itf.ListExprType) valNames := make([]string, len(valExprs)) @@ -105,21 +122,15 @@ func TestItfTrace(t *testing.T) { nodes[i] = addressMap[valName] } - t.Log("Creating coordinator") - coordinator := ibctesting.NewCoordinator(t, 0) // start without chains, which we add later - - // start provider - t.Log("Creating provider chain") - providerChain := newChain(t, coordinator, icstestingutils.ProviderAppIniter, "provider", valSet, signers, nodes) - coordinator.Chains["provider"] = providerChain - - // start consumer chains - for _, chain := range consumers { - t.Logf("Creating consumer chain %v", chain) - consumerChain := newChain(t, coordinator, icstestingutils.ConsumerAppIniter(initValUpdates), chain, valSet, signers, nodes) - coordinator.Chains[chain] = consumerChain + valAddresses := make([]types.ValAddress, len(valNames)) + for i, valNode := range nodes { + pbVal := cmttypes.TM2PB.Validator(valNode) + valAddresses[i] = pbVal.Address } + driver := newDriver(t, valAddresses) + driver.setupChains(modelParams, valSet, signers, nodes, consumers) + t.Log("Started chains") t.Log("Reading the trace...") diff --git a/tests/difference/core/quint_model/driver/setup.go b/tests/difference/core/quint_model/driver/setup.go index 4c7ca4ae6a..02341044e0 100644 --- a/tests/difference/core/quint_model/driver/setup.go +++ b/tests/difference/core/quint_model/driver/setup.go @@ -14,8 +14,14 @@ import ( cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" sdk "github.com/cosmos/cosmos-sdk/types" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" + ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" icstestingutils "github.com/cosmos/interchain-security/v3/testutil/ibc_testing" simibc "github.com/cosmos/interchain-security/v3/testutil/simibc" + "github.com/stretchr/testify/require" + + ccv "github.com/cosmos/interchain-security/v3/x/ccv/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" @@ -252,14 +258,17 @@ func newChain( SenderAccounts: senderAccounts, } - coord.CommitBlock(chain) + chain.NextBlock() return chain } // Creates a path for cross-chain validation from the consumer to the provider and configures the channel config of the endpoints -// as well as the clients -func ConfigureNewPath(consumerChain *ibctesting.TestChain, providerChain *ibctesting.TestChain) *ibctesting.Path { +// as well as the clients. +// this function stops when there is an initialized, ready-to-relay channel between the provider and consumer. +func (s *Driver) ConfigureNewPath(consumerChain *ibctesting.TestChain, providerChain *ibctesting.TestChain, params ModelParams, lastProviderHeader *ibctmtypes.Header) *ibctesting.Path { + consumerChainId := ChainId(consumerChain.ChainID) + path := ibctesting.NewPath(consumerChain, providerChain) consumerEndPoint := path.EndpointA providerEndPoint := path.EndpointB @@ -270,95 +279,115 @@ func ConfigureNewPath(consumerChain *ibctesting.TestChain, providerChain *ibctes consumerEndPoint.ChannelConfig.Order = channeltypes.ORDERED providerEndPoint.ChannelConfig.Order = channeltypes.ORDERED - // Configure and create the consumer Client + // Configure and create the client on the provider tmCfg := providerEndPoint.ClientConfig.(*ibctesting.TendermintConfig) - tmCfg.UnbondingPeriod = b.initState.UnbondingC - tmCfg.TrustingPeriod = b.initState.Trusting - err := b.providerEndpoint().CreateClient() - b.suite.Require().NoError(err) - // Create the Consumer chain ID mapping in the provider state - b.providerKeeper().SetConsumerClientId(b.providerCtx(), b.consumer().ChainID, b.providerEndpoint().ClientID) - - return path -} + tmCfg.UnbondingPeriod = params.UnbondingPeriodPerChain[ChainId(providerChain.ChainID)] + err := providerEndPoint.CreateClient() + require.NoError(s.t, err, "Error creating client on provider for chain %v", consumerChain.ChainID) -func SetupChains(t *testing.T, - s *CoreSuite, - valSet *cmttypes.ValidatorSet, // the initial validator set - signers map[string]cmttypes.PrivValidator, // a map of validator addresses to private validators (signers) - nodes []*cmttypes.Validator, // the list of nodes, even ones that have no voting power initially - consumers []string, // a list of consumer chain names -) { - initValUpdates := cmttypes.TM2PB.ValidatorUpdates(valSet) - - t.Log("Creating coordinator") - coordinator := ibctesting.NewCoordinator(t, 0) // start without chains, which we add later - - // start provider - t.Log("Creating provider chain") - providerChain := newChain(t, coordinator, icstestingutils.ProviderAppIniter, "provider", valSet, signers, nodes) - coordinator.Chains["provider"] = providerChain - - // start consumer chains - for _, chain := range consumers { - t.Logf("Creating consumer chain %v", chain) - consumerChain := newChain(t, coordinator, icstestingutils.ConsumerAppIniter(initValUpdates), chain, valSet, signers, nodes) - coordinator.Chains[chain] = consumerChain - - path := ConfigureNewPath(consumerChain, providerChain) - } + // Create the Consumer chain ID mapping in the provider state + s.providerKeeper().SetConsumerClientId(providerChain.GetContext(), consumerChain.ChainID, providerEndPoint.ClientID) - // Create a client for the provider chain to use, using ibc go testing. - b.createProvidersLocalClient() + // Configure and create the client on the consumer + tmCfg = consumerEndPoint.ClientConfig.(*ibctesting.TendermintConfig) + tmCfg.UnbondingPeriod = params.UnbondingPeriodPerChain[consumerChainId] - // Manually create a client for the consumer chain to and bootstrap - // via genesis. - clientState := b.createConsumersLocalClientGenesis() + consumerClientState := ibctmtypes.NewClientState( + providerChain.ChainID, tmCfg.TrustLevel, tmCfg.TrustingPeriod, tmCfg.UnbondingPeriod, tmCfg.MaxClockDrift, + providerChain.LastHeader.GetHeight().(clienttypes.Height), commitmenttypes.GetSDKSpecs(), + []string{"upgrade", "upgradedIBCState"}, + ) - consumerGenesis := b.createConsumerGenesis(clientState) + consumerGenesis := createConsumerGenesis(params, providerChain, consumerClientState) - b.consumerKeeper().InitGenesis(b.consumerCtx(), consumerGenesis) + s.consumerKeeper(consumerChainId).InitGenesis(s.ctx(consumerChainId), consumerGenesis) // Client ID is set in InitGenesis and we treat it as a block box. So // must query it to use it with the endpoint. - clientID, _ := b.consumerKeeper().GetProviderClientID(b.consumerCtx()) - b.consumerEndpoint().ClientID = clientID + clientID, _ := s.consumerKeeper(consumerChainId).GetProviderClientID(s.ctx(consumerChainId)) + consumerEndPoint.ClientID = clientID // Handshake - b.coordinator.CreateConnections(b.path) - b.coordinator.CreateChannels(b.path) + s.coordinator.CreateConnections(path) + s.coordinator.CreateChannels(path) // Usually the consumer sets the channel ID when it receives a first VSC packet // to the provider. For testing purposes, we can set it here. This is because // we model a blank slate: a provider and consumer that have fully established // their channel, and are ready for anything to happen. - b.consumerKeeper().SetProviderChannel(b.consumerCtx(), b.consumerEndpoint().ChannelID) + s.consumerKeeper(consumerChainId).SetProviderChannel(s.ctx(consumerChainId), consumerEndPoint.ChannelID) - // Catch up consumer height to provider height. The provider was one ahead - // from committing additional validators. - simibc.EndBlock(b.consumer(), func() {}) + // // Catch up consumer height to provider height. The provider was one ahead TODO: activate this + // // from committing additional validators. + // simibc.EndBlock(consumerChain, func() {}) - simibc.BeginBlock(b.consumer(), initState.BlockInterval) - simibc.BeginBlock(b.provider(), initState.BlockInterval) + // simibc.BeginBlock(consumerChain, initState.BlockInterval) + // simibc.BeginBlock(providerChain, initState.BlockInterval) // Commit a block on both chains, giving us two committed headers from // the same time and height. This is the starting point for all our // data driven testing. - lastProviderHeader, _ := simibc.EndBlock(b.provider(), func() {}) - lastConsumerHeader, _ := simibc.EndBlock(b.consumer(), func() {}) - - // Want the height and time of last COMMITTED block - heightLastCommitted = b.provider().CurrentHeader.Height - timeLastCommitted = b.provider().CurrentHeader.Time.Unix() + lastConsumerHeader, _ := simibc.EndBlock(consumerChain, func() {}) // Get ready to update clients. - simibc.BeginBlock(b.provider(), initState.BlockInterval) - simibc.BeginBlock(b.consumer(), initState.BlockInterval) + simibc.BeginBlock(providerChain, 0) + simibc.BeginBlock(consumerChain, 0) + + // Update clients to the latest header. + err = simibc.UpdateReceiverClient(consumerEndPoint, providerEndPoint, lastConsumerHeader) + require.NoError(s.t, err, "Error updating client on consumer for chain %v", consumerChain.ChainID) + err = simibc.UpdateReceiverClient(providerEndPoint, consumerEndPoint, lastProviderHeader) + require.NoError(s.t, err, "Error updating client on provider for chain %v", consumerChain.ChainID) - // Update clients to the latest header. Now everything is ready to go! - // Ignore errors for brevity. Everything is checked in Assuptions test. - _ = simibc.UpdateReceiverClient(b.consumerEndpoint(), b.providerEndpoint(), lastConsumerHeader) - _ = simibc.UpdateReceiverClient(b.providerEndpoint(), b.consumerEndpoint(), lastProviderHeader) + // path is ready to go + return path +} - return b.path, b.valAddresses, heightLastCommitted, timeLastCommitted +func (s *Driver) setupChains( + params ModelParams, + valSet *cmttypes.ValidatorSet, // the initial validator set + signers map[string]cmttypes.PrivValidator, // a map of validator addresses to private validators (signers) + nodes []*cmttypes.Validator, // the list of nodes, even ones that have no voting power initially + consumers []string, // a list of consumer chain names +) { + initValUpdates := cmttypes.TM2PB.ValidatorUpdates(valSet) + // start provider + s.t.Log("Creating provider chain") + providerChain := newChain(s.t, s.coordinator, icstestingutils.ProviderAppIniter, "provider", valSet, signers, nodes) + s.coordinator.Chains["provider"] = providerChain + + providerHeader, _ := simibc.EndBlock(providerChain, func() {}) + + // start consumer chains + for _, chain := range consumers { + s.t.Logf("Creating consumer chain %v", chain) + consumerChain := newChain(s.t, s.coordinator, icstestingutils.ConsumerAppIniter(initValUpdates), chain, valSet, signers, nodes) + s.coordinator.Chains[chain] = consumerChain + + path := s.ConfigureNewPath(consumerChain, providerChain, params, providerHeader) + relayedPath := simibc.MakeRelayedPath(s.t, path) + s.simibcs[ChainId(chain)] = &relayedPath + } +} + +func createConsumerGenesis(modelParams ModelParams, providerChain *ibctesting.TestChain, consumerClientState *ibctmtypes.ClientState) *consumertypes.GenesisState { + providerConsState := providerChain.LastHeader.ConsensusState() + + valUpdates := cmttypes.TM2PB.ValidatorUpdates(providerChain.Vals) + params := ccv.NewParams( + true, + 1000, // ignore distribution + "", // ignore distribution + "", // ignore distribution + ccv.DefaultCCVTimeoutPeriod, + ccv.DefaultTransferTimeoutPeriod, + ccv.DefaultConsumerRedistributeFrac, + ccv.DefaultHistoricalEntries, + consumerClientState.UnbondingPeriod, + "0", // disable soft opt-out + []string{}, + []string{}, + ccv.DefaultRetryDelayPeriod, + ) + return consumertypes.NewInitialGenesisState(consumerClientState, providerConsState, valUpdates, params) }