diff --git a/README.md b/README.md index cc6d7af437..b7623b137e 100644 --- a/README.md +++ b/README.md @@ -47,15 +47,15 @@ Inspect the [Makefile](./Makefile) if curious. ### Unit Tests -Unit tests are useful for simple standalone functionality, and CRUD operations. Unit tests should use golang's standard testing package, and be defined in files formatted as ```_test.go``` in the same directory as the file being tested, following standard conventions. +Unit tests are useful for simple standalone functionality, and CRUD operations. Unit tests should use golang's standard testing package, and be defined in files formatted as ```_test.go``` in the same directory as the file being tested, following standard conventions. -[Mocked external keepers](./testutil/keeper/mocks.go) (implemented with [gomock](https://github.com/golang/mock)) are available for testing more complex functionality, but still only relevant to execution within a single node. Ie. no internode or interchain communication. +[Mocked external keepers](./testutil/keeper/mocks.go) (implemented with [gomock](https://github.com/golang/mock)) are available for testing code that briefly interacts with external modules, but still only a single function/method relevant to ccv, and a single chain. Ie. do not use mocked external keepers to test the integration of the ccv module with external modules, or integration between consumer and provider. ### End to End (e2e) Tests [e2e-tests](./tests/e2e/) utilize the [IBC Testing Package](https://github.com/cosmos/ibc-go/tree/main/testing), and test functionality that is wider in scope than a unit test, but still able to be validated in-memory. Ie. code where advancing blocks would be useful, simulated handshakes, simulated packet relays, etc. -To run e2e tests against your own consumer/provider implementations, use [instance_test.go](./tests/e2e/instance_test.go) as an example. All you'll need to do is make sure your applications implement the necessary interfaces defined in [interfaces.go](./testutil/e2e/interfaces.go), then pass in an appropriate callback to the testing suites. +To run e2e tests against your own consumer/provider implementations, use [instance_test.go](./tests/e2e/instance_test.go) as an example. All you'll need to do is make sure your applications implement the necessary interfaces defined in [interfaces.go](./testutil/e2e/interfaces.go), pattern match [specific_setup.go](./testutil/ibc_testing/specific_setup.go), then pass in the appropriate types and parameters to the suite, as is done in `instance_test.go` for the dummy provider/consumer implementations. ### Differential Tests (WIP) diff --git a/app/consumer-democracy/proposals_whitelisting_test.go b/app/consumer-democracy/proposals_whitelisting_test.go index a83fb686b5..e1a4a489d9 100644 --- a/app/consumer-democracy/proposals_whitelisting_test.go +++ b/app/consumer-democracy/proposals_whitelisting_test.go @@ -5,12 +5,13 @@ import ( ibctesting "github.com/cosmos/ibc-go/v3/testing" appConsumer "github.com/cosmos/interchain-security/app/consumer-democracy" - simapp "github.com/cosmos/interchain-security/testutil/simapp" + icstestingutils "github.com/cosmos/interchain-security/testutil/ibc_testing" "github.com/stretchr/testify/require" ) func TestDemocracyGovernanceWhitelistingKeys(t *testing.T) { - chain := ibctesting.NewTestChain(t, simapp.NewBasicCoordinator(t), simapp.SetupTestingAppConsumerDemocracy, "test") + chain := ibctesting.NewTestChain(t, ibctesting.NewCoordinator(t, 0), + icstestingutils.DemocracyConsumerAppIniter, "test") paramKeeper := chain.App.(*appConsumer.App).ParamsKeeper for paramKey := range appConsumer.WhitelistedParams { ss, ok := paramKeeper.GetSubspace(paramKey.Subspace) diff --git a/proto/interchain_security/ccv/provider/v1/provider.proto b/proto/interchain_security/ccv/provider/v1/provider.proto index 753d1a28e4..a0b17af011 100644 --- a/proto/interchain_security/ccv/provider/v1/provider.proto +++ b/proto/interchain_security/ccv/provider/v1/provider.proto @@ -72,6 +72,18 @@ message Params { // to timeout VSC packets even when a consumer chain is not live. google.protobuf.Duration vsc_timeout_period = 5 [(gogoproto.nullable) = false, (gogoproto.stdduration) = true]; + + // The period for which the slash meter is replenished + google.protobuf.Duration slash_meter_replenish_period = 6 + [(gogoproto.nullable) = false, (gogoproto.stdduration) = true]; + + // The fraction of total voting power that is replenished to the slash meter every replenish period. + // This param also serves as a maximum fraction of total voting power that the slash meter can hold. + string slash_meter_replenish_fraction = 7; + + // The maximum amount of pending slash packets that can be queued for a consumer + // before the provider chain halts. + int64 max_pending_slash_packets = 8; } message HandshakeMetadata { diff --git a/tests/difference/core/driver/setup.go b/tests/difference/core/driver/setup.go index ab136122e1..b247087bc1 100644 --- a/tests/difference/core/driver/setup.go +++ b/tests/difference/core/driver/setup.go @@ -10,7 +10,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - "github.com/cosmos/interchain-security/x/ccv/types" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" abci "github.com/tendermint/tendermint/abci/types" @@ -23,7 +22,6 @@ import ( cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - simapp "github.com/cosmos/interchain-security/testutil/simapp" cryptoEd25519 "crypto/ed25519" @@ -39,6 +37,7 @@ import ( stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" appConsumer "github.com/cosmos/interchain-security/app/consumer" appProvider "github.com/cosmos/interchain-security/app/provider" + icstestingutils "github.com/cosmos/interchain-security/testutil/ibc_testing" simibc "github.com/cosmos/interchain-security/testutil/simibc" consumerkeeper "github.com/cosmos/interchain-security/x/ccv/consumer/keeper" consumertypes "github.com/cosmos/interchain-security/x/ccv/consumer/types" @@ -337,14 +336,14 @@ func (b *Builder) createValidators() (*tmtypes.ValidatorSet, map[string]tmtypes. func (b *Builder) createChains() { - coordinator := simapp.NewBasicCoordinator(b.suite.T()) + coordinator := ibctesting.NewCoordinator(b.suite.T(), 0) // Create validators validators, signers, addresses := b.createValidators() // Create provider - coordinator.Chains[ibctesting.GetChainID(0)] = b.newChain(coordinator, simapp.SetupTestingappProvider, ibctesting.GetChainID(0), validators, signers) + coordinator.Chains[ibctesting.GetChainID(0)] = b.newChain(coordinator, icstestingutils.ProviderAppIniter, ibctesting.GetChainID(0), validators, signers) // Create consumer, using the same validators. - coordinator.Chains[ibctesting.GetChainID(1)] = b.newChain(coordinator, simapp.SetupTestingAppConsumer, ibctesting.GetChainID(1), validators, signers) + coordinator.Chains[ibctesting.GetChainID(1)] = b.newChain(coordinator, icstestingutils.ConsumerAppIniter, ibctesting.GetChainID(1), validators, signers) b.coordinator = coordinator b.valAddresses = addresses @@ -540,7 +539,7 @@ func (b *Builder) sendEmptyVSCPacketToFinishHandshake() { timeout := uint64(b.chain(P).CurrentHeader.Time.Add(ccv.DefaultCCVTimeoutPeriod).UnixNano()) - pd := types.NewValidatorSetChangePacketData( + pd := ccv.NewValidatorSetChangePacketData( []abci.ValidatorUpdate{}, vscID, nil, diff --git a/tests/e2e/README.md b/tests/e2e/README.md index b8ad9d1970..62f34b59ea 100644 --- a/tests/e2e/README.md +++ b/tests/e2e/README.md @@ -14,4 +14,4 @@ E2e tests are categorized into files as follows: - `normal_operations.go` - e2e tests for _normal operations_ of ICS enabled chains - `instance_test.go` - ties the e2e test structure into golang's standard test mechanism, with appropriate definitions for concrete app types and setup callback -To run the e2e tests defined in this repo on any arbitrary consumer and provider implementation, copy the pattern exemplified in `instance_test.go` +To run the e2e tests defined in this repo on any arbitrary consumer and provider implementation, copy the pattern exemplified in `instance_test.go` and `specific_setup.go` diff --git a/tests/e2e/democracy.go b/tests/e2e/democracy.go index 8b4dfda7f9..0961a33cbf 100644 --- a/tests/e2e/democracy.go +++ b/tests/e2e/democracy.go @@ -7,15 +7,14 @@ import ( "time" sdk "github.com/cosmos/cosmos-sdk/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + icstestingutils "github.com/cosmos/interchain-security/testutil/ibc_testing" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" - "github.com/cosmos/cosmos-sdk/x/params/types/proposal" proposaltypes "github.com/cosmos/cosmos-sdk/x/params/types/proposal" - "github.com/cosmos/interchain-security/testutil/e2e" + e2eutil "github.com/cosmos/interchain-security/testutil/e2e" consumertypes "github.com/cosmos/interchain-security/x/ccv/consumer/types" "github.com/stretchr/testify/suite" ) @@ -24,15 +23,32 @@ type ConsumerDemocracyTestSuite struct { suite.Suite coordinator *ibctesting.Coordinator consumerChain *ibctesting.TestChain - consumerApp e2e.DemocConsumerApp + consumerApp e2eutil.DemocConsumerApp setupCallback DemocSetupCallback } // NewCCVTestSuite returns a new instance of ConsumerDemocracyTestSuite, // ready to be tested against using suite.Run(). -func NewConsumerDemocracyTestSuite(setupCallback DemocSetupCallback) *ConsumerDemocracyTestSuite { +func NewConsumerDemocracyTestSuite[T e2eutil.DemocConsumerApp]( + democConsumerAppIniter ibctesting.AppIniter) *ConsumerDemocracyTestSuite { + democSuite := new(ConsumerDemocracyTestSuite) - democSuite.setupCallback = setupCallback + + democSuite.setupCallback = func(t *testing.T) ( + *ibctesting.Coordinator, + *ibctesting.TestChain, + e2eutil.DemocConsumerApp, + ) { + // Instantiate the test coordinator + coordinator := ibctesting.NewCoordinator(t, 0) + + // Add single democracy consumer to coordinator, store returned test chain and app. + democConsumer, democConsumerApp := icstestingutils.AddDemocracyConsumer[T]( + coordinator, t, democConsumerAppIniter) + + // Pass variables to suite. + return coordinator, democConsumer, democConsumerApp + } return democSuite } @@ -41,7 +57,7 @@ func NewConsumerDemocracyTestSuite(setupCallback DemocSetupCallback) *ConsumerDe type DemocSetupCallback func(t *testing.T) ( coord *ibctesting.Coordinator, consumerChain *ibctesting.TestChain, - consumerApp e2e.DemocConsumerApp, + consumerApp e2eutil.DemocConsumerApp, ) // SetupTest sets up in-mem state before every test relevant to ccv with a democracy consumer @@ -138,8 +154,8 @@ func (s *ConsumerDemocracyTestSuite) TestDemocracyGovernanceWhitelisting() { mintKeeper := s.consumerApp.GetE2eMintKeeper() newAuthParamValue := uint64(128) newMintParamValue := sdk.NewDecWithPrec(1, 1) // "0.100000000000000000" - allowedChange := proposal.ParamChange{Subspace: minttypes.ModuleName, Key: "InflationMax", Value: fmt.Sprintf("\"%s\"", newMintParamValue)} - forbiddenChange := proposal.ParamChange{Subspace: authtypes.ModuleName, Key: "MaxMemoCharacters", Value: fmt.Sprintf("\"%s\"", strconv.FormatUint(newAuthParamValue, 10))} + allowedChange := proposaltypes.ParamChange{Subspace: minttypes.ModuleName, Key: "InflationMax", Value: fmt.Sprintf("\"%s\"", newMintParamValue)} + forbiddenChange := proposaltypes.ParamChange{Subspace: authtypes.ModuleName, Key: "MaxMemoCharacters", Value: fmt.Sprintf("\"%s\"", strconv.FormatUint(newAuthParamValue, 10))} votingAccounts := s.consumerChain.SenderAccounts bondDenom := stakingKeeper.BondDenom(s.consumerCtx()) depositAmount := govKeeper.GetDepositParams(s.consumerCtx()).MinDeposit @@ -203,7 +219,7 @@ func (s *ConsumerDemocracyTestSuite) TestDemocracyGovernanceWhitelisting() { s.Assert().Equal(votersOldBalances, getAccountsBalances(s.consumerCtx(), bankKeeper, bondDenom, votingAccounts)) } -func submitProposalWithDepositAndVote(govKeeper e2e.E2eGovKeeper, ctx sdk.Context, paramChange proposaltypes.ParameterChangeProposal, +func submitProposalWithDepositAndVote(govKeeper e2eutil.E2eGovKeeper, ctx sdk.Context, paramChange proposaltypes.ParameterChangeProposal, accounts []ibctesting.SenderAccount, depositAmount sdk.Coins) error { proposal, err := govKeeper.SubmitProposal(ctx, ¶mChange) if err != nil { @@ -223,7 +239,7 @@ func submitProposalWithDepositAndVote(govKeeper e2e.E2eGovKeeper, ctx sdk.Contex return nil } -func getAccountsBalances(ctx sdk.Context, bankKeeper e2e.E2eBankKeeper, bondDenom string, accounts []ibctesting.SenderAccount) map[string]sdk.Int { +func getAccountsBalances(ctx sdk.Context, bankKeeper e2eutil.E2eBankKeeper, bondDenom string, accounts []ibctesting.SenderAccount) map[string]sdk.Int { accountsBalances := map[string]sdk.Int{} for _, acc := range accounts { accountsBalances[string(acc.SenderAccount.GetAddress())] = diff --git a/tests/e2e/instance_test.go b/tests/e2e/instance_test.go index 4c6a47c39a..4dc79b0ab7 100644 --- a/tests/e2e/instance_test.go +++ b/tests/e2e/instance_test.go @@ -3,57 +3,43 @@ package e2e_test import ( "testing" - ibctesting "github.com/cosmos/ibc-go/v3/testing" appConsumer "github.com/cosmos/interchain-security/app/consumer" appConsumerDemocracy "github.com/cosmos/interchain-security/app/consumer-democracy" appProvider "github.com/cosmos/interchain-security/app/provider" "github.com/cosmos/interchain-security/tests/e2e" - e2etestutil "github.com/cosmos/interchain-security/testutil/e2e" - "github.com/cosmos/interchain-security/testutil/simapp" + icstestingutils "github.com/cosmos/interchain-security/testutil/ibc_testing" "github.com/stretchr/testify/suite" ) // This file can be used as an example e2e testing instance for any provider/consumer applications. // In the case of this repo, we're testing the dummy provider/consumer applications, -// but to test any arbitrary app, you only need to replicate this file, and pass in the -// appropriate callback to the testing suites. Note that any provider/consumer applications -// must implement the interfaces defined in /testutil/e2e/interfaces.go +// but to test any arbitrary app, one only needs to replicate this file and "specific_setup.go", +// then pass in the appropriate types and parameters to the suite. Note that provider and consumer +// applications types must implement the interfaces defined in /testutil/e2e/interfaces.go to compile. // Executes the standard group of ccv tests against a consumer and provider app.go implementation. func TestCCVTestSuite(t *testing.T) { - ccvSuite := e2e.NewCCVTestSuite( - func(t *testing.T) ( - *ibctesting.Coordinator, - *ibctesting.TestChain, - *ibctesting.TestChain, - e2etestutil.ProviderApp, - e2etestutil.ConsumerApp, - ) { - // Here we pass the concrete types that must implement the necessary interfaces - // to be ran with e2e tests. - coord, prov, cons := simapp.NewProviderConsumerCoordinator(t) - return coord, prov, cons, prov.App.(*appProvider.App), cons.App.(*appConsumer.App) - }, - ) + // Pass in concrete app types that implement the interfaces defined in /testutil/e2e/interfaces.go + ccvSuite := e2e.NewCCVTestSuite[*appProvider.App, *appConsumer.App]( + // Pass in ibctesting.AppIniters for provider and consumer. + icstestingutils.ProviderAppIniter, icstestingutils.ConsumerAppIniter) + + // Run tests suite.Run(t, ccvSuite) } // TODO: Run the gov enabled consumer against the standard suite of tests: https://github.com/cosmos/interchain-security/issues/397 -// Executes a specialized group of tests specific to a democracy consumer, against a democracy consumer app.go implementation. +// Executes a specialized group of tests specific to a democracy consumer, +// against a democracy consumer app.go implementation. func TestConsumerDemocracyTestSuite(t *testing.T) { - democSuite := e2e.NewConsumerDemocracyTestSuite( - func(t *testing.T) ( - *ibctesting.Coordinator, - *ibctesting.TestChain, - e2etestutil.DemocConsumerApp, - ) { - // Here we pass the concrete types that must implement the necessary interfaces - // to be ran with e2e tests. - coord, _, cons := simapp.NewProviderConsumerDemocracyCoordinator(t) - return coord, cons, cons.App.(*appConsumerDemocracy.App) - }, - ) + + // Pass in concrete app type that implement the interface defined in /testutil/e2e/interfaces.go + democSuite := e2e.NewConsumerDemocracyTestSuite[*appConsumerDemocracy.App]( + // Pass in ibctesting.AppIniter for democracy consumer. + icstestingutils.DemocracyConsumerAppIniter) + + // Run tests suite.Run(t, democSuite) } diff --git a/tests/e2e/setup.go b/tests/e2e/setup.go index 4aa78adfa9..8c27166d67 100644 --- a/tests/e2e/setup.go +++ b/tests/e2e/setup.go @@ -1,12 +1,12 @@ package e2e import ( - ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" - "bytes" "testing" - e2e "github.com/cosmos/interchain-security/testutil/e2e" + ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" + e2eutil "github.com/cosmos/interchain-security/testutil/e2e" + icstestingutils "github.com/cosmos/interchain-security/testutil/ibc_testing" ccv "github.com/cosmos/interchain-security/x/ccv/types" "github.com/cosmos/interchain-security/x/ccv/utils" @@ -30,28 +30,54 @@ type CCVTestSuite struct { coordinator *ibctesting.Coordinator providerChain *ibctesting.TestChain consumerChain *ibctesting.TestChain - providerApp e2e.ProviderApp - consumerApp e2e.ConsumerApp + providerApp e2eutil.ProviderApp + consumerApp e2eutil.ConsumerApp path *ibctesting.Path transferPath *ibctesting.Path setupCallback SetupCallback } // NewCCVTestSuite returns a new instance of CCVTestSuite, ready to be tested against using suite.Run(). -func NewCCVTestSuite(setupCallback SetupCallback) *CCVTestSuite { +func NewCCVTestSuite[Tp e2eutil.ProviderApp, Tc e2eutil.ConsumerApp]( + providerAppIniter ibctesting.AppIniter, consumerAppIniter ibctesting.AppIniter) *CCVTestSuite { + ccvSuite := new(CCVTestSuite) - ccvSuite.setupCallback = setupCallback + + ccvSuite.setupCallback = func(t *testing.T) ( + *ibctesting.Coordinator, + *ibctesting.TestChain, + *ibctesting.TestChain, + e2eutil.ProviderApp, + e2eutil.ConsumerApp, + ) { + // Instantiate the test coordinator. + coordinator := ibctesting.NewCoordinator(t, 0) + + // Add provider to coordinator, store returned test chain and app. + // Concrete provider app type is passed to the generic function here. + provider, providerApp := icstestingutils.AddProvider[Tp]( + coordinator, t, providerAppIniter) + + // Add specified number of consumers to coordinator, store returned test chains and apps. + // Concrete consumer app type is passed to the generic function here. + consumers, consumerApps := icstestingutils.AddConsumers[Tc]( + coordinator, t, 1, consumerAppIniter) + + // Pass variables to suite. + // TODO: accept multiple consumers here + return coordinator, provider, consumers[0], providerApp, consumerApps[0] + } return ccvSuite } -// Callback for instantiating a new coordinator, provider/consumer test chains, and provider/consumer app +// Callback for instantiating a new coordinator, provider/consumer test chains, and provider/consumer apps // before every test defined on the suite. type SetupCallback func(t *testing.T) ( coord *ibctesting.Coordinator, providerChain *ibctesting.TestChain, consumerChain *ibctesting.TestChain, - providerApp e2e.ProviderApp, - consumerApp e2e.ConsumerApp, + providerApp e2eutil.ProviderApp, + consumerApp e2eutil.ConsumerApp, ) // SetupTest sets up in-mem state before every test diff --git a/tests/e2e/slashing.go b/tests/e2e/slashing.go index f7a6736fae..40cc23e5a2 100644 --- a/tests/e2e/slashing.go +++ b/tests/e2e/slashing.go @@ -14,249 +14,177 @@ import ( clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - "github.com/cosmos/interchain-security/x/ccv/types" - abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto/ed25519" ) -// TestSendDowntimePacket tests consumer initiated slashing -func (s *CCVTestSuite) TestSendSlashPacketDowntime() { - s.SetupCCVChannel() - s.SetupTransferChannel() - validatorsPerChain := len(s.consumerChain.Vals.Validators) - - providerStakingKeeper := s.providerApp.GetE2eStakingKeeper() - providerSlashingKeeper := s.providerApp.GetE2eSlashingKeeper() - consumerKeeper := s.consumerApp.GetConsumerKeeper() - providerKeeper := s.providerApp.GetProviderKeeper() - - // get a cross-chain validator address, pubkey and balance - tmVals := s.consumerChain.Vals.Validators - tmVal := tmVals[0] - - val, err := tmVal.ToProto() - s.Require().NoError(err) - pubkey, err := cryptocodec.FromTmProtoPublicKey(val.GetPubKey()) - s.Require().Nil(err) - consAddr := sdk.GetConsAddress(pubkey) - valData, found := providerStakingKeeper.GetValidatorByConsAddr(s.providerCtx(), consAddr) - s.Require().True(found) - valOldBalance := valData.Tokens - - // create the validator's signing info record to allow jailing - valInfo := slashingtypes.NewValidatorSigningInfo(consAddr, s.providerCtx().BlockHeight(), - s.providerCtx().BlockHeight()-1, time.Time{}.UTC(), false, int64(0)) - providerSlashingKeeper.SetValidatorSigningInfo(s.providerCtx(), consAddr, valInfo) - - // get valseUpdateId for current block height - valsetUpdateId := consumerKeeper.GetHeightValsetUpdateID(s.consumerCtx(), - uint64(s.consumerCtx().BlockHeight())) - - // construct the downtime packet with the validator address and power along - // with the slashing and jailing parameters - validator := abci.Validator{ - Address: tmVal.Address, - Power: tmVal.VotingPower, - } - - oldBlockTime := s.consumerCtx().BlockTime() - slashFraction := int64(100) - packetData := types.NewSlashPacketData(validator, valsetUpdateId, stakingtypes.Downtime) - timeout := uint64(oldBlockTime.Add(ccv.DefaultCCVTimeoutPeriod).UnixNano()) - packet := channeltypes.NewPacket(packetData.GetBytes(), 1, ccv.ConsumerPortID, - s.path.EndpointA.ChannelID, ccv.ProviderPortID, s.path.EndpointB.ChannelID, - clienttypes.Height{}, timeout) - - // Send the downtime packet through CCV - err = s.path.EndpointA.SendPacket(packet) - s.Require().NoError(err) - - // Set outstanding slashing flag - consumerKeeper.SetOutstandingDowntime(s.consumerCtx(), consAddr) - - // save next VSC packet info - oldBlockTime = s.providerCtx().BlockTime() - timeout = uint64(oldBlockTime.Add(ccv.DefaultCCVTimeoutPeriod).UnixNano()) - valsetUpdateID := providerKeeper.GetValidatorSetUpdateId(s.providerCtx()) - - // receive the downtime packet on the provider chain; - // RecvPacket() calls the provider endblocker thus sends a VSC packet to the consumer - err = s.path.EndpointB.RecvPacket(packet) - s.Require().NoError(err) - - // check that the validator was removed from the provider validator set - s.Require().Len(s.providerChain.Vals.Validators, validatorsPerChain-1) - // check that the VSC ID is updated on the consumer chain - - // update consumer client on the VSC packet sent from provider - err = s.path.EndpointA.UpdateClient() - s.Require().NoError(err) +const ( + downtimeTestCase = iota + doubleSignTestCase +) - // reconstruct VSC packet - valUpdates := []abci.ValidatorUpdate{ - { - PubKey: val.GetPubKey(), - Power: int64(0), - }, +// TestRelayAndApplySlashPacket tests that slash packets can be properly relayed +// from consumer to provider, handled by provider, with a VSC and jailing/tombstoning +// eventually effective on consumer and provider. +// +// Note: This method does not test the actual slash packet sending logic for downtime +// and double-signing, see TestValidatorDowntime and TestValidatorDoubleSigning for +// those types of tests. +func (s *CCVTestSuite) TestRelayAndApplySlashPacket() { + + testCases := []int{ + downtimeTestCase, + doubleSignTestCase, } - packetData2 := ccv.NewValidatorSetChangePacketData(valUpdates, valsetUpdateID, []string{consAddr.String()}) - packet2 := channeltypes.NewPacket(packetData2.GetBytes(), 1, ccv.ProviderPortID, s.path.EndpointB.ChannelID, - ccv.ConsumerPortID, s.path.EndpointA.ChannelID, clienttypes.Height{}, timeout) - // receive VSC packet about jailing on the consumer chain - err = s.path.EndpointA.RecvPacket(packet2) - s.Require().NoError(err) - - // check that the consumer update its VSC ID for the subsequent block - s.Require().Equal(consumerKeeper.GetHeightValsetUpdateID(s.consumerCtx(), uint64(s.consumerCtx().BlockHeight())+1), valsetUpdateID) + for _, tc := range testCases { - // check that the validator was removed from the consumer validator set - s.Require().Len(s.consumerChain.Vals.Validators, validatorsPerChain-1) + s.SetupTest() + s.SetupCCVChannel() + s.SetupTransferChannel() + validatorsPerChain := len(s.consumerChain.Vals.Validators) + + providerStakingKeeper := s.providerApp.GetE2eStakingKeeper() + providerSlashingKeeper := s.providerApp.GetE2eSlashingKeeper() + providerKeeper := s.providerApp.GetProviderKeeper() + consumerKeeper := s.consumerApp.GetConsumerKeeper() + + // get a cross-chain validator address, pubkey and balance + tmVals := s.consumerChain.Vals.Validators + tmVal := tmVals[0] + + val, err := tmVal.ToProto() + s.Require().NoError(err) + pubkey, err := cryptocodec.FromTmProtoPublicKey(val.GetPubKey()) + s.Require().Nil(err) + consAddr := sdk.GetConsAddress(pubkey) + valData, found := providerStakingKeeper.GetValidatorByConsAddr(s.providerCtx(), consAddr) + s.Require().True(found) + valOldBalance := valData.Tokens + + // create the validator's signing info record to allow jailing + valInfo := slashingtypes.NewValidatorSigningInfo(consAddr, s.providerCtx().BlockHeight(), + s.providerCtx().BlockHeight()-1, time.Time{}.UTC(), false, int64(0)) + providerSlashingKeeper.SetValidatorSigningInfo(s.providerCtx(), consAddr, valInfo) + + // get valseUpdateId for current block height + valsetUpdateId := consumerKeeper.GetHeightValsetUpdateID( + s.consumerCtx(), uint64(s.consumerCtx().BlockHeight())) + + // construct the slash packet with the validator address and power + validator := abci.Validator{ + Address: tmVal.Address, + Power: tmVal.VotingPower, + } - err = s.path.EndpointB.UpdateClient() - s.Require().NoError(err) + // Construct packet data depending on the test case + var infractionType stakingtypes.InfractionType - // check that the validator is successfully jailed on provider + if tc == downtimeTestCase { + infractionType = stakingtypes.Downtime + } else if tc == doubleSignTestCase { + infractionType = stakingtypes.DoubleSign + } + packetData := ccv.NewSlashPacketData(validator, valsetUpdateId, infractionType).GetBytes() - validatorJailed, ok := s.providerApp.GetE2eStakingKeeper().GetValidatorByConsAddr(s.providerCtx(), consAddr) - s.Require().True(ok) - s.Require().True(validatorJailed.Jailed) - s.Require().Equal(validatorJailed.Status, stakingtypes.Unbonding) + oldBlockTime := s.consumerCtx().BlockTime() + timeout := uint64(oldBlockTime.Add(ccv.DefaultCCVTimeoutPeriod).UnixNano()) + packet := channeltypes.NewPacket(packetData, 1, ccv.ConsumerPortID, s.path.EndpointA.ChannelID, + ccv.ProviderPortID, s.path.EndpointB.ChannelID, clienttypes.Height{}, timeout) - // check that the validator's token was slashed - slashedAmout := sdk.NewDec(1).QuoInt64(slashFraction).Mul(valOldBalance.ToDec()) - resultingTokens := valOldBalance.Sub(slashedAmout.TruncateInt()) - s.Require().Equal(resultingTokens, validatorJailed.GetTokens()) + // Send the slash packet through CCV + err = s.path.EndpointA.SendPacket(packet) + s.Require().NoError(err) - // check that the validator's unjailing time is updated - valSignInfo, found := providerSlashingKeeper.GetValidatorSigningInfo(s.providerCtx(), consAddr) - s.Require().True(found) - s.Require().True(valSignInfo.JailedUntil.After(s.providerCtx().BlockHeader().Time)) + if tc == downtimeTestCase { + // Set outstanding slashing flag if testing a downtime slash packet + consumerKeeper.SetOutstandingDowntime(s.consumerCtx(), consAddr) + } - // check that the outstanding slashing flag is reset on the consumer - pFlag := consumerKeeper.OutstandingDowntime(s.consumerCtx(), consAddr) - s.Require().False(pFlag) + // Note: RecvPacket advances two blocks. Let's say the provider is currently at height n. + // The received slash packet will be handled during n, and the staking module will then + // register a validator update from that packet during the endblocker of n. Then the ccv + // module sends a VSC packet during the endblocker of n. The new validator set will be + // committed to in block n+1, and will be in effect for block n+2. - // check that slashing packet gets acknowledged - ack := channeltypes.NewResultAcknowledgement([]byte{byte(1)}) - err = s.path.EndpointA.AcknowledgePacket(packet, ack.Acknowledgement()) - s.Require().NoError(err) -} + valsetUpdateN := providerKeeper.GetValidatorSetUpdateId(s.providerCtx()) -func (s *CCVTestSuite) TestSendSlashPacketDoubleSign() { - s.SetupCCVChannel() - s.SetupTransferChannel() - validatorsPerChain := len(s.consumerChain.Vals.Validators) + // receive the downtime packet on the provider chain. RecvPacket() calls the provider endblocker twice + err = s.path.EndpointB.RecvPacket(packet) + s.Require().NoError(err) - providerStakingKeeper := s.providerApp.GetE2eStakingKeeper() - providerSlashingKeeper := s.providerApp.GetE2eSlashingKeeper() - providerKeeper := s.providerApp.GetProviderKeeper() - consumerKeeper := s.consumerApp.GetConsumerKeeper() + // We've now advanced two blocks. - // get a cross-chain validator address, pubkey and balance - tmVals := s.consumerChain.Vals.Validators - tmVal := tmVals[0] + // One VSC packet should have been sent during block n + expectedSentValsetUpdateId := valsetUpdateN + _, found = providerKeeper.GetVscSendTimestamp(s.providerCtx(), + s.consumerChain.ChainID, expectedSentValsetUpdateId) + s.Require().True(found) - val, err := tmVal.ToProto() - s.Require().NoError(err) - pubkey, err := cryptocodec.FromTmProtoPublicKey(val.GetPubKey()) - s.Require().Nil(err) - consAddr := sdk.GetConsAddress(pubkey) - valData, found := providerStakingKeeper.GetValidatorByConsAddr(s.providerCtx(), consAddr) - s.Require().True(found) - valOldBalance := valData.Tokens - - // create the validator's signing info record to allow jailing - valInfo := slashingtypes.NewValidatorSigningInfo(consAddr, s.providerCtx().BlockHeight(), - s.providerCtx().BlockHeight()-1, time.Time{}.UTC(), false, int64(0)) - providerSlashingKeeper.SetValidatorSigningInfo(s.providerCtx(), consAddr, valInfo) - - // get valseUpdateId for current block height - valsetUpdateId := consumerKeeper.GetHeightValsetUpdateID(s.consumerCtx(), uint64(s.consumerCtx().BlockHeight())) - - // construct the downtime packet with the validator address and power along - // with the slashing and jailing parameters - validator := abci.Validator{ - Address: tmVal.Address, - Power: tmVal.VotingPower, - } + // Confirm the valset update Id was incremented twice. + valsetUpdateNPlus2 := providerKeeper.GetValidatorSetUpdateId(s.providerCtx()) + s.Require().Equal(valsetUpdateN+2, valsetUpdateNPlus2) - oldBlockTime := s.consumerCtx().BlockTime() - packetData := types.NewSlashPacketData(validator, valsetUpdateId, stakingtypes.DoubleSign) + // check that the validator was removed from the provider validator set + s.Require().Len(s.providerChain.Vals.Validators, validatorsPerChain-1) - timeout := uint64(oldBlockTime.Add(ccv.DefaultCCVTimeoutPeriod).UnixNano()) - packet := channeltypes.NewPacket(packetData.GetBytes(), 1, ccv.ConsumerPortID, s.path.EndpointA.ChannelID, - ccv.ProviderPortID, s.path.EndpointB.ChannelID, clienttypes.Height{}, timeout) + // Relay the VSC packet to the consumer + relayAllCommittedPackets(s, s.providerChain, s.path, ccv.ProviderPortID, s.path.EndpointB.ChannelID, 1) - // Send the downtime packet through CCV - err = s.path.EndpointA.SendPacket(packet) - s.Require().NoError(err) + // check that the consumer updated its VSC ID for the subsequent block + actualValsetUpdateID := consumerKeeper.GetHeightValsetUpdateID( + s.consumerCtx(), uint64(s.consumerCtx().BlockHeight())+1) + s.Require().Equal(expectedSentValsetUpdateId, actualValsetUpdateID) - // save next VSC packet info - oldBlockTime = s.providerCtx().BlockTime() - timeout = uint64(oldBlockTime.Add(ccv.DefaultCCVTimeoutPeriod).UnixNano()) - valsetUpdateID := providerKeeper.GetValidatorSetUpdateId(s.providerCtx()) + // check that the validator was removed from the consumer validator set + s.Require().Len(s.consumerChain.Vals.Validators, validatorsPerChain-1) - // receive the downtime packet on the provider chain; - // RecvPacket() calls the provider endblocker and thus sends a VSC packet to the consumer - err = s.path.EndpointB.RecvPacket(packet) - s.Require().NoError(err) + err = s.path.EndpointB.UpdateClient() + s.Require().NoError(err) - // check that the validator was removed from the provider validator set - s.Require().Len(s.providerChain.Vals.Validators, validatorsPerChain-1) - // check that the VSC ID is updated on the consumer chain + // check that the validator is successfully jailed on provider + validatorJailed, ok := providerStakingKeeper.GetValidatorByConsAddr(s.providerCtx(), consAddr) + s.Require().True(ok) + s.Require().True(validatorJailed.Jailed) + s.Require().Equal(validatorJailed.Status, stakingtypes.Unbonding) - // update consumer client on the VSC packet sent from provider - err = s.path.EndpointA.UpdateClient() - s.Require().NoError(err) + // check that the validator's tokens were slashed + var slashFraction sdk.Dec + if tc == downtimeTestCase { + slashFraction = providerSlashingKeeper.SlashFractionDowntime(s.providerCtx()) - // reconstruct VSC packet - valUpdates := []abci.ValidatorUpdate{ - { - PubKey: val.GetPubKey(), - Power: int64(0), - }, + } else if tc == doubleSignTestCase { + slashFraction = providerSlashingKeeper.SlashFractionDoubleSign(s.providerCtx()) + } + slashedAmount := slashFraction.Mul(valOldBalance.ToDec()) + + resultingTokens := valOldBalance.Sub(slashedAmount.TruncateInt()) + s.Require().Equal(resultingTokens, validatorJailed.GetTokens()) + + // check that the validator's unjailing time is updated + valSignInfo, found := providerSlashingKeeper.GetValidatorSigningInfo(s.providerCtx(), consAddr) + s.Require().True(found) + s.Require().True(valSignInfo.JailedUntil.After(s.providerCtx().BlockHeader().Time)) + + if tc == downtimeTestCase { + // check that the outstanding slashing flag is reset on the consumer + pFlag := consumerKeeper.OutstandingDowntime(s.consumerCtx(), consAddr) + s.Require().False(pFlag) + + // check that slashing packet gets acknowledged + ack := channeltypes.NewResultAcknowledgement([]byte{byte(1)}) + err = s.path.EndpointA.AcknowledgePacket(packet, ack.Acknowledgement()) + s.Require().NoError(err) + + } else if tc == doubleSignTestCase { + // check that validator was tombstoned + s.Require().True(valSignInfo.Tombstoned) + s.Require().True(valSignInfo.JailedUntil.Equal(evidencetypes.DoubleSignJailEndTime)) + } } - packetData2 := ccv.NewValidatorSetChangePacketData(valUpdates, valsetUpdateID, []string{}) - packet2 := channeltypes.NewPacket(packetData2.GetBytes(), 1, ccv.ProviderPortID, s.path.EndpointB.ChannelID, - ccv.ConsumerPortID, s.path.EndpointA.ChannelID, clienttypes.Height{}, timeout) - - // receive VSC packet about jailing on the consumer chain - err = s.path.EndpointA.RecvPacket(packet2) - s.Require().NoError(err) - - // check that the consumer update its VSC ID for the subsequent block - s.Require().Equal(consumerKeeper.GetHeightValsetUpdateID(s.consumerCtx(), uint64(s.consumerCtx().BlockHeight())+1), valsetUpdateID) - - // check that the validator was removed from the consumer validator set - s.Require().Len(s.consumerChain.Vals.Validators, validatorsPerChain-1) - - err = s.path.EndpointB.UpdateClient() - s.Require().NoError(err) - - // check that the validator is successfully jailed on provider - validatorJailed, ok := providerStakingKeeper.GetValidatorByConsAddr(s.providerCtx(), consAddr) - s.Require().True(ok) - s.Require().True(validatorJailed.Jailed) - s.Require().Equal(validatorJailed.Status, stakingtypes.Unbonding) - - // check that the validator's token was slashed - slashedAmout := providerSlashingKeeper.SlashFractionDoubleSign(s.providerCtx()).Mul(valOldBalance.ToDec()) - resultingTokens := valOldBalance.Sub(slashedAmout.TruncateInt()) - s.Require().Equal(resultingTokens, validatorJailed.GetTokens()) - - // check that the validator's unjailing time is updated - valSignInfo, found := providerSlashingKeeper.GetValidatorSigningInfo(s.providerCtx(), consAddr) - s.Require().True(found) - s.Require().True(valSignInfo.JailedUntil.After(s.providerCtx().BlockHeader().Time)) - - // check that validator was tombstoned - s.Require().True(valSignInfo.Tombstoned) - s.Require().True(valSignInfo.JailedUntil.Equal(evidencetypes.DoubleSignJailEndTime)) } -func (s *CCVTestSuite) TestSlashPacketAcknowldgement() { +func (s *CCVTestSuite) TestSlashPacketAcknowledgement() { providerKeeper := s.providerApp.GetProviderKeeper() consumerKeeper := s.consumerApp.GetConsumerKeeper() diff --git a/tests/integration/actions.go b/tests/integration/actions.go index 9e6c334266..c9e01db6bd 100644 --- a/tests/integration/actions.go +++ b/tests/integration/actions.go @@ -368,6 +368,7 @@ func (tr TestRun) submitParamChangeProposal( `--chain-id`, string(tr.chainConfigs[action.chain].chainId), `--home`, tr.getValidatorHome(action.chain, action.from), `--node`, tr.getValidatorNode(action.chain, action.from), + `--gas`, "900000", `--keyring-backend`, `test`, `-b`, `block`, `-y`, @@ -406,6 +407,7 @@ func (tr TestRun) voteGovProposal( `--home`, tr.getValidatorHome(action.chain, val), `--node`, tr.getValidatorNode(action.chain, val), `--keyring-backend`, `test`, + `--gas`, "900000", `-b`, `block`, `-y`, ).CombinedOutput() @@ -550,7 +552,6 @@ type addIbcConnectionAction struct { chainB chainID clientA uint clientB uint - order string } func (tr TestRun) addIbcConnection( @@ -833,6 +834,7 @@ func (tr TestRun) unbondTokens( `--chain-id`, string(tr.chainConfigs[action.chain].chainId), `--home`, tr.getValidatorHome(action.chain, action.sender), `--node`, tr.getValidatorNode(action.chain, action.sender), + `--gas`, "900000", `--keyring-backend`, `test`, `-b`, `block`, `-y`, diff --git a/tests/integration/config.go b/tests/integration/config.go index c29736b17a..5bbc424959 100644 --- a/tests/integration/config.go +++ b/tests/integration/config.go @@ -87,12 +87,12 @@ func getDefaultValidators() map[validatorID]ValidatorConfig { } } -func DoubleSignTestRun() TestRun { +func DefaultTestRun() TestRun { return TestRun{ - name: "double-sign", + name: "default", containerConfig: ContainerConfig{ - containerName: "interchain-security-ds-container", - instanceName: "interchain-security-ds-instance", + containerName: "interchain-security-container", + instanceName: "interchain-security-instance", ccvVersion: "1", now: time.Now(), }, @@ -109,8 +109,7 @@ func DoubleSignTestRun() TestRun { ".app_state.slashing.params.signed_blocks_window = \"2\" | " + ".app_state.slashing.params.min_signed_per_window = \"0.500000000000000000\" | " + ".app_state.slashing.params.downtime_jail_duration = \"2s\" | " + - ".app_state.slashing.params.slash_fraction_downtime = \"0.010000000000000000\" | " + - ".app_state.slashing.params.slash_fraction_double_sign = \"0.100000000000000000\"", + ".app_state.slashing.params.slash_fraction_downtime = \"0.010000000000000000\"", }, chainID("consu"): { chainId: chainID("consu"), @@ -127,12 +126,12 @@ func DoubleSignTestRun() TestRun { } } -func DefaultTestRun() TestRun { +func DemocracyTestRun() TestRun { return TestRun{ - name: "default", + name: "democracy", containerConfig: ContainerConfig{ - containerName: "interchain-security-container", - instanceName: "interchain-security-instance", + containerName: "interchain-security-democ-container", + instanceName: "interchain-security-democ-instance", ccvVersion: "1", now: time.Now(), }, @@ -151,12 +150,13 @@ func DefaultTestRun() TestRun { ".app_state.slashing.params.downtime_jail_duration = \"2s\" | " + ".app_state.slashing.params.slash_fraction_downtime = \"0.010000000000000000\"", }, - chainID("consu"): { - chainId: chainID("consu"), - binaryName: "interchain-security-cd", - ipPrefix: "7.7.8", + chainID("democ"): { + chainId: chainID("democ"), + binaryName: "interchain-security-cdd", + ipPrefix: "7.7.9", votingWaitTime: 10, - genesisChanges: ".app_state.gov.voting_params.voting_period = \"10s\" | " + + genesisChanges: ".app_state.ccvconsumer.params.blocks_per_distribution_transmission = \"10\" | " + + ".app_state.gov.voting_params.voting_period = \"10s\" | " + ".app_state.slashing.params.signed_blocks_window = \"2\" | " + ".app_state.slashing.params.min_signed_per_window = \"0.500000000000000000\" | " + ".app_state.slashing.params.downtime_jail_duration = \"2s\" | " + @@ -166,12 +166,12 @@ func DefaultTestRun() TestRun { } } -func DemocracyTestRun() TestRun { +func MultiConsumerTestRun() TestRun { return TestRun{ - name: "democracy", + name: "multi-consumer", containerConfig: ContainerConfig{ - containerName: "interchain-security-democ-container", - instanceName: "interchain-security-democ-instance", + containerName: "interchain-security-multic-container", + instanceName: "interchain-security-multic-instance", ccvVersion: "1", now: time.Now(), }, @@ -190,13 +190,23 @@ func DemocracyTestRun() TestRun { ".app_state.slashing.params.downtime_jail_duration = \"2s\" | " + ".app_state.slashing.params.slash_fraction_downtime = \"0.010000000000000000\"", }, - chainID("democ"): { - chainId: chainID("democ"), - binaryName: "interchain-security-cdd", + chainID("consu"): { + chainId: chainID("consu"), + binaryName: "interchain-security-cd", + ipPrefix: "7.7.8", + votingWaitTime: 10, + genesisChanges: ".app_state.gov.voting_params.voting_period = \"10s\" | " + + ".app_state.slashing.params.signed_blocks_window = \"2\" | " + + ".app_state.slashing.params.min_signed_per_window = \"0.500000000000000000\" | " + + ".app_state.slashing.params.downtime_jail_duration = \"2s\" | " + + ".app_state.slashing.params.slash_fraction_downtime = \"0.010000000000000000\"", + }, + chainID("densu"): { + chainId: chainID("densu"), + binaryName: "interchain-security-cd", ipPrefix: "7.7.9", votingWaitTime: 10, - genesisChanges: ".app_state.ccvconsumer.params.blocks_per_distribution_transmission = \"10\" | " + - ".app_state.gov.voting_params.voting_period = \"10s\" | " + + genesisChanges: ".app_state.gov.voting_params.voting_period = \"10s\" | " + ".app_state.slashing.params.signed_blocks_window = \"2\" | " + ".app_state.slashing.params.min_signed_per_window = \"0.500000000000000000\" | " + ".app_state.slashing.params.downtime_jail_duration = \"2s\" | " + diff --git a/tests/integration/main.go b/tests/integration/main.go index bedf0d65b1..a07043a46b 100644 --- a/tests/integration/main.go +++ b/tests/integration/main.go @@ -37,10 +37,10 @@ func main() { dmc.ValidateStringLiterals() dmc.startDocker() - ds := DoubleSignTestRun() - ds.SetLocalSDKPath(*localSdkPath) - ds.ValidateStringLiterals() - ds.startDocker() + mul := MultiConsumerTestRun() + mul.SetLocalSDKPath(*localSdkPath) + mul.ValidateStringLiterals() + mul.startDocker() wg.Add(1) go tr.ExecuteSteps(&wg, happyPathSteps) @@ -49,7 +49,7 @@ func main() { go dmc.ExecuteSteps(&wg, democracySteps) wg.Add(1) - go ds.ExecuteSteps(&wg, doubleSignProviderSteps) + go mul.ExecuteSteps(&wg, multipleConsumers) wg.Wait() fmt.Printf("TOTAL TIME ELAPSED: %v\n", time.Since(start)) @@ -108,7 +108,8 @@ func (tr *TestRun) runStep(step Step, verbose bool) { // Check state if !reflect.DeepEqual(actualState, modelState) { - fmt.Println("action", reflect.TypeOf(step.action).Name()) + fmt.Printf("=============== %s FAILED ===============\n", tr.name) + fmt.Println("FAILED action", reflect.TypeOf(step.action).Name()) pretty.Print("actual state", actualState) pretty.Print("model state", modelState) log.Fatal(`actual state (-) not equal to model state (+): ` + pretty.Compare(actualState, modelState)) diff --git a/tests/integration/steps_delegation.go b/tests/integration/step_delegation.go similarity index 93% rename from tests/integration/steps_delegation.go rename to tests/integration/step_delegation.go index 074347161a..af969e8f08 100644 --- a/tests/integration/steps_delegation.go +++ b/tests/integration/step_delegation.go @@ -1,6 +1,6 @@ package main -// stepsDelegate tests basic delegation and resulting validator power changes. +// stepsDelegate tests basic delegation and resulting validator power changes func stepsDelegate(consumerName string) []Step { return []Step{ { @@ -80,8 +80,8 @@ func stepsDelegate(consumerName string) []Step { } } -// stepsDelegate tests validatod unbonding, redelegation and resulting validator power changes. -func stepsUnbondRedelegate(consumerName string) []Step { +// stepsDelegate tests unbonding and resulting validator power changes. +func stepsUnbond(consumerName string) []Step { return []Step{ { action: unbondTokensAction{ @@ -124,6 +124,12 @@ func stepsUnbondRedelegate(consumerName string) []Step { }, }, }, + } +} + +// stepsRedelegate tests redelegation and resulting validator power changes. +func stepsRedelegate(consumerName string) []Step { + return []Step{ { action: redelegateTokensAction{ chain: chainID("provi"), diff --git a/tests/integration/steps.go b/tests/integration/steps.go index b1c68ee008..526a036b5c 100644 --- a/tests/integration/steps.go +++ b/tests/integration/steps.go @@ -14,21 +14,28 @@ func concatSteps(steps ...[]Step) []Step { } var happyPathSteps = concatSteps( - stepsStartChains("consu", false), + stepsStartChains([]string{"consu"}, false), stepsDelegate("consu"), - stepsUnbondRedelegate("consu"), + stepsUnbond("consu"), + stepsRedelegate("consu"), stepsDowntime("consu"), stepsStopChain("consu"), ) var democracySteps = concatSteps( // democracySteps requires a transfer channel - stepsStartChains("democ", true), + stepsStartChains([]string{"democ"}, true), + // delegation needs to happen so the first VSC packet can be delivered stepsDelegate("democ"), stepsDemocracy("democ"), ) -var doubleSignProviderSteps = concatSteps( - stepsStartChains("consu", false), - stepsDoubleSign("consu", "provi", "carol"), +var multipleConsumers = concatSteps( + stepsStartChains([]string{"consu", "densu"}, false), + stepsMultiConsumerDelegate("consu", "densu"), + stepsMultiConsumerUnbond("consu", "densu"), + stepsMultiConsumerRedelegate("consu", "densu"), + stepsMultiConsumerDowntimeFromConsumer("consu", "densu"), + stepsMultiConsumerDowntimeFromProvider("consu", "densu"), + stepsDoubleSign("consu", "densu"), // double sign on one of the chains ) diff --git a/tests/integration/steps_double_sign.go b/tests/integration/steps_double_sign.go index ae7cc055a2..955b3c22d0 100644 --- a/tests/integration/steps_double_sign.go +++ b/tests/integration/steps_double_sign.go @@ -1,10 +1,11 @@ package main -// simulates double signing on provider and consumer chains -func stepsDoubleSign(consumerName, doubleSignChain, doubleSignValidator string) []Step { +// simulates double signing on provider and vsc propagation to consumer chains +// steps continue from downtime tests state +func stepsDoubleSign(consumer1, consumer2 string) []Step { return []Step{ - // provider double sign { + // provider double sign action: doublesignSlashAction{ chain: chainID("provi"), validator: validatorID("carol"), @@ -13,112 +14,204 @@ func stepsDoubleSign(consumerName, doubleSignChain, doubleSignValidator string) // slash on provider chainID("provi"): ChainState{ ValPowers: &map[validatorID]uint{ - validatorID("alice"): 500, - validatorID("bob"): 500, + validatorID("alice"): 509, + validatorID("bob"): 495, + validatorID("carol"): 0, // from 495 to 0 + }, + }, + chainID(consumer1): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 495, + validatorID("carol"): 495, // not slashed on consumer1 yet + }, + }, + chainID(consumer2): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 495, + validatorID("carol"): 495, // not slashed on consumer2 yet + }, + }, + }, + }, + { + // relay power change to consumer1 + action: relayPacketsAction{ + chain: chainID("provi"), + port: "provider", + channel: 0, // consumer1 channel + }, + state: State{ + chainID("provi"): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 495, validatorID("carol"): 0, }, }, - // not slashed on consumer yet - chainID(consumerName): ChainState{ + chainID(consumer1): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 495, + validatorID("carol"): 0, // slash visible on consumer1 + }, + }, + chainID(consumer2): ChainState{ ValPowers: &map[validatorID]uint{ - validatorID("alice"): 500, - validatorID("bob"): 500, - validatorID("carol"): 500, + validatorID("alice"): 509, + validatorID("bob"): 495, + validatorID("carol"): 495, // slash NOT YET visible on consumer2 }, }, }, }, { - // relay power change to consumer + // relay power change to consumer2 action: relayPacketsAction{ chain: chainID("provi"), port: "provider", - channel: 0, + channel: 1, // consumer2 channel }, state: State{ chainID("provi"): ChainState{ ValPowers: &map[validatorID]uint{ - validatorID("alice"): 500, - validatorID("bob"): 500, + validatorID("alice"): 509, + validatorID("bob"): 495, validatorID("carol"): 0, }, }, - chainID(consumerName): ChainState{ + chainID(consumer1): ChainState{ ValPowers: &map[validatorID]uint{ - validatorID("alice"): 500, - validatorID("bob"): 500, + validatorID("alice"): 509, + validatorID("bob"): 495, validatorID("carol"): 0, }, }, + chainID(consumer2): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 495, + validatorID("carol"): 0, // slash visible on consumer2 + }, + }, }, }, { + // consumer double sign + // no changes are visible until relayed from consumer to provider action: doublesignSlashAction{ chain: chainID("consu"), validator: validatorID("bob"), }, state: State{ - chainID(consumerName): ChainState{ + chainID("provi"): ChainState{ ValPowers: &map[validatorID]uint{ - validatorID("alice"): 500, - validatorID("bob"): 500, + validatorID("alice"): 509, + validatorID("bob"): 495, validatorID("carol"): 0, }, }, - chainID("provi"): ChainState{ + chainID(consumer1): ChainState{ ValPowers: &map[validatorID]uint{ - validatorID("alice"): 500, - validatorID("bob"): 500, + validatorID("alice"): 509, + validatorID("bob"): 495, + validatorID("carol"): 0, + }, + }, + chainID(consumer2): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 495, validatorID("carol"): 0, }, }, }, }, { + // provider learns about the infraction and slashes on provider chain action: relayPacketsAction{ chain: chainID("provi"), port: "provider", - channel: 0, + channel: 0, // consumer1 channel }, state: State{ chainID("provi"): ChainState{ ValPowers: &map[validatorID]uint{ - validatorID("alice"): 500, - validatorID("bob"): 0, + validatorID("alice"): 509, + validatorID("bob"): 0, // from 495 to 0 + validatorID("carol"): 0, + }, + }, + chainID(consumer1): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 495, // not slashed yet validatorID("carol"): 0, }, }, - chainID(consumerName): ChainState{ + chainID(consumer2): ChainState{ ValPowers: &map[validatorID]uint{ - validatorID("alice"): 500, - validatorID("bob"): 500, + validatorID("alice"): 509, + validatorID("bob"): 495, // not slashed yet validatorID("carol"): 0, }, }, }, }, { - // relay power change to consumer + // consumer1 learns about the slash and powerchanges action: relayPacketsAction{ chain: chainID("provi"), port: "provider", - channel: 0, + channel: 0, // consumer1 channel }, state: State{ chainID("provi"): ChainState{ ValPowers: &map[validatorID]uint{ - validatorID("alice"): 500, + validatorID("alice"): 509, validatorID("bob"): 0, validatorID("carol"): 0, }, }, - chainID(consumerName): ChainState{ + chainID(consumer1): ChainState{ ValPowers: &map[validatorID]uint{ - validatorID("alice"): 500, + validatorID("alice"): 509, + validatorID("bob"): 0, // from 495 to 0 + validatorID("carol"): 0, + }, + }, + chainID(consumer2): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 495, // not slashed yet + validatorID("carol"): 0, + }, + }, + }, + }, + { + // consumer2 learns about the slash and powerchanges + action: relayPacketsAction{ + chain: chainID("provi"), + port: "provider", + channel: 1, // consumer2 channel + }, + state: State{ + chainID(consumer1): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, validatorID("bob"): 0, validatorID("carol"): 0, }, }, + chainID(consumer2): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 0, // from 495 to 0 + validatorID("carol"): 0, + }, + }, }, }, } diff --git a/tests/integration/steps_multi_consumer_delegation.go b/tests/integration/steps_multi_consumer_delegation.go new file mode 100644 index 0000000000..106307629d --- /dev/null +++ b/tests/integration/steps_multi_consumer_delegation.go @@ -0,0 +1,305 @@ +package main + +// stepsDelegate tests basic delegation and resulting validator power changes. +func stepsMultiConsumerDelegate(consumer1, consumer2 string) []Step { + return []Step{ + { + // changes not visible on any consumer + action: delegateTokensAction{ + chain: chainID("provi"), + from: validatorID("alice"), + to: validatorID("alice"), + amount: 11000000, + }, + state: State{ + chainID("provi"): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 511, // this changes from 500 + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + }, + chainID(consumer1): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 500, + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + }, + chainID(consumer2): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 500, + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + }, + }, + }, + { + // relay changes to consumer1 + action: relayPacketsAction{ + chain: chainID("provi"), + port: "provider", + channel: 0, // consumer1 channel + }, + state: State{ + chainID("provi"): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 511, + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + }, + chainID(consumer1): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 511, // changed + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + }, + chainID(consumer2): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 500, // unchanged + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + }, + }, + }, + { + // relay changes to consumer2 + action: relayPacketsAction{ + chain: chainID("provi"), + port: "provider", + channel: 1, // consumer2 channel + }, + state: State{ + chainID("provi"): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 511, + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + }, + chainID(consumer1): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 511, + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + }, + chainID(consumer2): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 511, // changed + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + }, + }, + }, + } +} + +// stepsMultiConsumerUnbond tests unbonding and resulting validator power changes. +// order of operations: unbond on provider -> relay to each consumer +func stepsMultiConsumerUnbond(consumer1, consumer2 string) []Step { + return []Step{ + { + action: unbondTokensAction{ + chain: chainID("provi"), + unbondFrom: validatorID("alice"), + sender: validatorID("alice"), + amount: 1000000, + }, + state: State{ + chainID("provi"): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 510, // change from 511 + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + }, + chainID(consumer1): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 511, // no change + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + }, + chainID(consumer2): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 511, // no change + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + }, + }, + }, + { + // relay to consumer1 + action: relayPacketsAction{ + chain: chainID("provi"), + port: "provider", + channel: 0, // consumer1 channel + }, + state: State{ + chainID("provi"): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 510, + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + }, + chainID(consumer1): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 510, // change from 511 + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + }, + chainID(consumer2): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 511, // no change + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + }, + }, + }, + { + // relay to consumer2 + action: relayPacketsAction{ + chain: chainID("provi"), + port: "provider", + channel: 1, // consumer2 channel + }, + state: State{ + chainID("provi"): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 510, + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + }, + chainID(consumer1): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 510, + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + }, + chainID(consumer2): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 510, // change from 511 + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + }, + }, + }, + } +} + +// stepsMultiConsumerRedelegate tests redelegation and resulting validator power changes. +// order of operations: redelegate on provider -> relay to each consumer +func stepsMultiConsumerRedelegate(consumer1, consumer2 string) []Step { + return []Step{ + { + action: redelegateTokensAction{ + chain: chainID("provi"), + src: validatorID("alice"), + dst: validatorID("carol"), + txSender: validatorID("alice"), + // Leave alice with majority stake so non-faulty validators maintain more than + // 2/3 voting power during downtime tests below, avoiding chain halt + amount: 1000000, + }, + state: State{ + chainID("provi"): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 500, + validatorID("carol"): 501, + }, + }, + chainID(consumer1): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 510, // no change + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + }, + chainID(consumer2): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 510, // no change + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + }, + }, + }, + + { + // relay to consumer1 + action: relayPacketsAction{ + chain: chainID("provi"), + port: "provider", + channel: 0, // consumer1 channel + }, + state: State{ + chainID("provi"): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 500, + validatorID("carol"): 501, + }, + }, + chainID(consumer1): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, // change from 510 + validatorID("bob"): 500, + validatorID("carol"): 501, // change from 500 + }, + }, + chainID(consumer2): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 510, // no change + validatorID("bob"): 500, + validatorID("carol"): 500, // no change + }, + }, + }, + }, + { + // relay to consumer2 + action: relayPacketsAction{ + chain: chainID("provi"), + port: "provider", + channel: 1, // consumer1 channel + }, + state: State{ + chainID("provi"): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 500, + validatorID("carol"): 501, + }, + }, + chainID(consumer1): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 500, + validatorID("carol"): 501, + }, + }, + chainID(consumer2): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, // change from 510 + validatorID("bob"): 500, + validatorID("carol"): 501, // change from 500 + }, + }, + }, + }, + } +} diff --git a/tests/integration/steps_multi_consumer_downtime.go b/tests/integration/steps_multi_consumer_downtime.go new file mode 100644 index 0000000000..18f1f12d62 --- /dev/null +++ b/tests/integration/steps_multi_consumer_downtime.go @@ -0,0 +1,408 @@ +package main + +// stepsDowntime tests validator jailing and slashing. +func stepsMultiConsumerDowntimeFromConsumer(consumer1, consumer2 string) []Step { + return []Step{ + { + action: downtimeSlashAction{ + chain: chainID(consumer1), + validator: validatorID("bob"), + }, + state: State{ + // validator should be slashed on consumer, powers not affected on either chain yet + chainID("provi"): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 500, + validatorID("carol"): 501, + }, + }, + chainID(consumer1): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 500, + validatorID("carol"): 501, + }, + }, + chainID(consumer2): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 500, + validatorID("carol"): 501, + }, + }, + }, + }, + { + // Downtime jailing and corresponding voting power change are processed by provider + // Validator powers are unchanged on consumer chains + action: relayPacketsAction{ + chain: chainID("provi"), + port: "provider", + channel: 0, + }, + state: State{ + chainID("provi"): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 0, + validatorID("carol"): 501, + }, + }, + chainID(consumer1): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 500, + validatorID("carol"): 501, + }, + }, + chainID(consumer2): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 500, + validatorID("carol"): 501, + }, + }, + }, + }, + { + // A block is incremented each action, hence why VSC is committed on provider, + // and can now be relayed as packet to consumer + // consumer1 will now see the validator power changes - consumer2 will not (had not been relayed) + action: relayPacketsAction{ + chain: chainID("provi"), + port: "provider", + channel: 0, // consumer1 chan + }, + state: State{ + // change propagated to consumer1 + chainID(consumer1): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + // VSC now seen on consumer1 + validatorID("bob"): 0, + validatorID("carol"): 501, + }, + }, + chainID(consumer2): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + // VSC has not arrived to on consumer2 + validatorID("bob"): 500, + validatorID("carol"): 501, + }, + }, + }, + }, + { + // both consumer1 and consumer will now see the validator power changes + action: relayPacketsAction{ + chain: chainID("provi"), + port: "provider", + channel: 1, // consumer2 chan + }, + state: State{ + chainID(consumer1): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 0, // both consumers see the change + validatorID("carol"): 501, + }, + }, + chainID(consumer2): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 0, // both consumers see the change + validatorID("carol"): 501, + }, + }, + }, + }, + { + action: unjailValidatorAction{ + provider: chainID("provi"), + validator: validatorID("bob"), + }, + state: State{ + chainID("provi"): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + // 1% of bob's stake should be slashed as set in config.go + validatorID("bob"): 495, + validatorID("carol"): 501, + }, + }, + // change is not visible on consumer1 + chainID(consumer1): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 0, + validatorID("carol"): 501, + }, + }, + // change is not visible on consumer2 + chainID(consumer2): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 0, + validatorID("carol"): 501, + }, + }, + }, + }, + { + // relay to consumer 1 + action: relayPacketsAction{ + chain: chainID("provi"), + port: "provider", + channel: 0, + }, + state: State{ + chainID("provi"): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 495, + validatorID("carol"): 501, + }, + }, + chainID(consumer1): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 495, // bob was slashed and changes relayed to consumer1 + validatorID("carol"): 501, + }, + }, + chainID(consumer2): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 0, // change has not arrived to consumer2 + validatorID("carol"): 501, + }, + }, + }, + }, + { + // relay to consumer2 + action: relayPacketsAction{ + chain: chainID("provi"), + port: "provider", + channel: 1, // consumer2 chan + }, + state: State{ + chainID("provi"): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 495, + validatorID("carol"): 501, + }, + }, + chainID(consumer1): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 495, // bob was slashed and changes relayed to consumer1 + validatorID("carol"): 501, + }, + }, + chainID(consumer2): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 495, // change has arrived to consumer2 + validatorID("carol"): 501, + }, + }, + }, + }, + } +} + +// stepsMultiConsumerDowntimeFromProvider tests validator jailing and slashing. +func stepsMultiConsumerDowntimeFromProvider(consumer1, consumer2 string) []Step { + return []Step{ + // Now we test provider initiated downtime/slashing + { + action: downtimeSlashAction{ + chain: chainID("provi"), + validator: validatorID("carol"), + }, + state: State{ + chainID("provi"): ChainState{ + ValPowers: &map[validatorID]uint{ + // Non faulty validators still maintain just above 2/3 power here + validatorID("alice"): 509, + validatorID("bob"): 495, + validatorID("carol"): 0, + }, + }, + chainID(consumer1): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 495, + validatorID("carol"): 501, + }, + }, + chainID(consumer2): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 495, + validatorID("carol"): 501, + }, + }, + }, + }, + { + action: relayPacketsAction{ + chain: chainID("provi"), + port: "provider", + channel: 0, // consumer 1 channel + }, + state: State{ + chainID("provi"): ChainState{ + ValPowers: &map[validatorID]uint{ + // Non faulty validators still maintain just above 2/3 power here + validatorID("alice"): 509, + validatorID("bob"): 495, + validatorID("carol"): 0, + }, + }, + // powers now changed + chainID(consumer1): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 495, + validatorID("carol"): 0, + }, + }, + // not relayed yet - powers unchanged + chainID(consumer2): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 495, + validatorID("carol"): 501, + }, + }, + }, + }, + { + action: relayPacketsAction{ + chain: chainID("provi"), + port: "provider", + channel: 1, // consumer2 channel + }, + state: State{ + chainID("provi"): ChainState{ + ValPowers: &map[validatorID]uint{ + // Non faulty validators still maintain just above 2/3 power here + validatorID("alice"): 509, + validatorID("bob"): 495, + validatorID("carol"): 0, + }, + }, + chainID(consumer1): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 495, + validatorID("carol"): 0, + }, + }, + // powers now changed + chainID(consumer2): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 495, + validatorID("carol"): 0, + }, + }, + }, + }, + { + action: unjailValidatorAction{ + provider: chainID("provi"), + validator: validatorID("carol"), + }, + state: State{ + chainID("provi"): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 495, + validatorID("carol"): 495, + }, + }, + chainID(consumer1): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 495, + validatorID("carol"): 0, + }, + }, + chainID(consumer2): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 495, + validatorID("carol"): 0, + }, + }, + }, + }, + { + action: relayPacketsAction{ + chain: chainID("provi"), + port: "provider", + channel: 0, // consumer1 channel + }, + state: State{ + chainID("provi"): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 495, + validatorID("carol"): 495, + }, + }, + chainID(consumer1): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 495, + validatorID("carol"): 495, + }, + }, + // not relayed yet + chainID(consumer2): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 495, + validatorID("carol"): 0, + }, + }, + }, + }, + { + action: relayPacketsAction{ + chain: chainID("provi"), + port: "provider", + channel: 1, // consumer2 channel + }, + state: State{ + chainID("provi"): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 495, + validatorID("carol"): 495, + }, + }, + chainID(consumer1): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 495, + validatorID("carol"): 495, + }, + }, + chainID(consumer2): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 509, + validatorID("bob"): 495, + validatorID("carol"): 495, + }, + }, + }, + }, + } +} diff --git a/tests/integration/steps_start_chains.go b/tests/integration/steps_start_chains.go index 7356f9fe5c..c6ff985615 100644 --- a/tests/integration/steps_start_chains.go +++ b/tests/integration/steps_start_chains.go @@ -4,11 +4,8 @@ import ( clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" ) -// starts provider and single consumer chain -// * genesisParams overrides consumer genesis params -// * setupTransferChan creates a transfer channel between provider and consumer -func stepsStartChains(consumerName string, setupTransferChan bool) []Step { - s := []Step{ +func stepStartProviderChain() []Step { + return []Step{ { action: StartChainAction{ chain: chainID("provi"), @@ -17,34 +14,22 @@ func stepsStartChains(consumerName string, setupTransferChan bool) []Step { {id: validatorID("alice"), stake: 500000000, allocation: 10000000000}, {id: validatorID("carol"), stake: 500000000, allocation: 10000000000}, }, - genesisChanges: "", // No custom genesis changes for this action - skipGentx: false, }, state: State{ chainID("provi"): ChainState{ ValBalances: &map[validatorID]uint{ validatorID("alice"): 9500000000, validatorID("bob"): 9500000000, + validatorID("carol"): 9500000000, }, }, }, }, - { - action: SendTokensAction{ - chain: chainID("provi"), - from: validatorID("alice"), - to: validatorID("bob"), - amount: 2, - }, - state: State{ - chainID("provi"): ChainState{ - ValBalances: &map[validatorID]uint{ - validatorID("alice"): 9499999998, - validatorID("bob"): 9500000002, - }, - }, - }, - }, + } +} + +func stepsStartConsumerChain(consumerName string, proposalIndex, chainIndex uint, setupTransferChans bool) []Step { + s := []Step{ { action: submitConsumerAdditionProposalAction{ chain: chainID("provi"), @@ -57,11 +42,11 @@ func stepsStartChains(consumerName string, setupTransferChan bool) []Step { state: State{ chainID("provi"): ChainState{ ValBalances: &map[validatorID]uint{ - validatorID("alice"): 9489999997, - validatorID("bob"): 9500000002, + validatorID("alice"): 9489999999, + validatorID("bob"): 9500000000, }, Proposals: &map[uint]Proposal{ - 1: ConsumerAdditionProposal{ + proposalIndex: ConsumerAdditionProposal{ Deposit: 10000001, Chain: chainID(consumerName), SpawnTime: 0, @@ -77,12 +62,12 @@ func stepsStartChains(consumerName string, setupTransferChan bool) []Step { chain: chainID("provi"), from: []validatorID{validatorID("alice"), validatorID("bob"), validatorID("carol")}, vote: []string{"yes", "yes", "yes"}, - propNumber: 1, + propNumber: proposalIndex, }, state: State{ chainID("provi"): ChainState{ Proposals: &map[uint]Proposal{ - 1: ConsumerAdditionProposal{ + proposalIndex: ConsumerAdditionProposal{ Deposit: 10000001, Chain: chainID(consumerName), SpawnTime: 0, @@ -91,8 +76,8 @@ func stepsStartChains(consumerName string, setupTransferChan bool) []Step { }, }, ValBalances: &map[validatorID]uint{ - validatorID("alice"): 9499999998, - validatorID("bob"): 9500000002, + validatorID("alice"): 9500000000, + validatorID("bob"): 9500000000, }, }, }, @@ -111,8 +96,8 @@ func stepsStartChains(consumerName string, setupTransferChan bool) []Step { state: State{ chainID("provi"): ChainState{ ValBalances: &map[validatorID]uint{ - validatorID("alice"): 9499999998, - validatorID("bob"): 9500000002, + validatorID("alice"): 9500000000, + validatorID("bob"): 9500000000, }, }, chainID(consumerName): ChainState{ @@ -123,30 +108,12 @@ func stepsStartChains(consumerName string, setupTransferChan bool) []Step { }, }, }, - { - action: SendTokensAction{ - chain: chainID(consumerName), - from: validatorID("alice"), - to: validatorID("bob"), - amount: 1, - }, - state: State{ - chainID(consumerName): ChainState{ - // Tx on consumer chain should not go through before ICS channel is setup - ValBalances: &map[validatorID]uint{ - validatorID("alice"): 10000000000, - validatorID("bob"): 10000000000, - }, - }, - }, - }, { action: addIbcConnectionAction{ chainA: chainID(consumerName), chainB: chainID("provi"), clientA: 0, - clientB: 0, - order: "ordered", + clientB: chainIndex, }, state: State{}, }, @@ -164,7 +131,7 @@ func stepsStartChains(consumerName string, setupTransferChan bool) []Step { } // currently only used in democracy tests - if setupTransferChan { + if setupTransferChans { s = append(s, Step{ action: transferChannelCompleteAction{ chainA: chainID(consumerName), @@ -179,6 +146,16 @@ func stepsStartChains(consumerName string, setupTransferChan bool) []Step { state: State{}, }) } + return s +} + +// starts provider and consumer chains specified in consumerNames +// setupTransferChans will establish a channel for fee transfers between consumer and provider +func stepsStartChains(consumerNames []string, setupTransferChans bool) []Step { + s := stepStartProviderChain() + for i, consumerName := range consumerNames { + s = append(s, stepsStartConsumerChain(consumerName, uint(i+1), uint(i), setupTransferChans)...) + } return s } diff --git a/tests/integration/steps_stop_chain.go b/tests/integration/steps_stop_chain.go index c35a7f28f1..bbeb7429f5 100644 --- a/tests/integration/steps_stop_chain.go +++ b/tests/integration/steps_stop_chain.go @@ -16,7 +16,7 @@ func stepsStopChain(consumerName string) []Step { state: State{ chainID("provi"): ChainState{ ValBalances: &map[validatorID]uint{ - validatorID("bob"): 9490000001, + validatorID("bob"): 9489999999, }, Proposals: &map[uint]Proposal{ 2: ConsumerRemovalProposal{ @@ -48,7 +48,7 @@ func stepsStopChain(consumerName string) []Step { }, }, ValBalances: &map[validatorID]uint{ - validatorID("bob"): 9500000002, + validatorID("bob"): 9500000000, }, ConsumerChains: &map[chainID]bool{}, // Consumer chain is now removed }, diff --git a/testutil/crypto/crypto.go b/testutil/crypto/crypto.go index 3551a97e65..5e77e65e40 100644 --- a/testutil/crypto/crypto.go +++ b/testutil/crypto/crypto.go @@ -3,7 +3,7 @@ package crypto import ( "encoding/binary" - "github.com/cosmos/ibc-go/v3/testing/mock" + ibcmock "github.com/cosmos/ibc-go/v3/testing/mock" cryptoEd25519 "crypto/ed25519" @@ -22,12 +22,12 @@ import ( // various interfaces and types used by the SDK and Tendermint from a single // 'root' private key. type CryptoIdentity struct { - mock.PV + ibcmock.PV } func NewCryptoIdentityFromBytesSeed(seed []byte) CryptoIdentity { //lint:ignore SA1019 We don't care because this is only a test. - privKey := mock.PV{PrivKey: &sdkcryptokeys.PrivKey{Key: cryptoEd25519.NewKeyFromSeed(seed)}} + privKey := ibcmock.PV{PrivKey: &sdkcryptokeys.PrivKey{Key: cryptoEd25519.NewKeyFromSeed(seed)}} return CryptoIdentity{PV: privKey} } diff --git a/testutil/ibc_testing/generic_setup.go b/testutil/ibc_testing/generic_setup.go new file mode 100644 index 0000000000..7c3234437d --- /dev/null +++ b/testutil/ibc_testing/generic_setup.go @@ -0,0 +1,62 @@ +package ibc_testing + +import ( + "testing" + + ibctesting "github.com/cosmos/ibc-go/v3/testing" + "github.com/cosmos/interchain-security/testutil/e2e" +) + +// Contains generic setup code for running e2e tests against a provider, consumer, +// and/or democracy consumer app.go implementation. You should not need to modify or replicate this file +// to run e2e tests against your app.go implementations! + +var ( + provChainID = ibctesting.GetChainID(1) + democConsumerChainID = ibctesting.GetChainID(2) +) + +// AddProvider adds a new provider chain to the coordinator and returns the test chain and app type +func AddProvider[T e2e.ProviderApp](coordinator *ibctesting.Coordinator, t *testing.T, appIniter ibctesting.AppIniter) ( + *ibctesting.TestChain, T) { + + provider := ibctesting.NewTestChain(t, coordinator, appIniter, provChainID) + coordinator.Chains[provChainID] = provider + + return provider, provider.App.(T) +} + +// AddDemocracyConsumer adds a new democ consumer chain to the coordinator and returns the test chain and app type +func AddDemocracyConsumer[T e2e.DemocConsumerApp](coordinator *ibctesting.Coordinator, t *testing.T, + appIniter ibctesting.AppIniter) (*ibctesting.TestChain, T) { + + democConsumer := ibctesting.NewTestChain(t, coordinator, appIniter, democConsumerChainID) + coordinator.Chains[democConsumerChainID] = democConsumer + + return democConsumer, democConsumer.App.(T) +} + +// AddConsumers adds new consumer chains to the coordinator and returns the test chains and app types +// The new consumers are initialized with the valset of the existing provider chain. +// +// This method must be called after AddProvider. +func AddConsumers[T e2e.ConsumerApp](coordinator *ibctesting.Coordinator, + t *testing.T, numConsumers int, appIniter ibctesting.AppIniter) ([]*ibctesting.TestChain, []T) { + + providerChain := coordinator.GetChain(provChainID) + + // Instantiate specified number of consumers, add them to coordinator, and returned chain/app slices + consumerChains := []*ibctesting.TestChain{} + consumerApps := []T{} + for i := 0; i < numConsumers; i++ { + chainID := ibctesting.GetChainID(i + 2) + testChain := ibctesting.NewTestChainWithValSet(t, coordinator, + appIniter, chainID, providerChain.Vals, providerChain.Signers) + + coordinator.Chains[chainID] = testChain + consumerChains = append(consumerChains, testChain) + consumerApps = append(consumerApps, testChain.App.(T)) + } + + return consumerChains, consumerApps +} diff --git a/testutil/ibc_testing/specific_setup.go b/testutil/ibc_testing/specific_setup.go new file mode 100644 index 0000000000..80f847c0a5 --- /dev/null +++ b/testutil/ibc_testing/specific_setup.go @@ -0,0 +1,45 @@ +package ibc_testing + +// Contains example setup code for running e2e tests against a provider, consumer, +// and/or democracy consumer app.go implementation. This file is meant to be pattern matched +// for apps running e2e tests against their implementation. + +import ( + "encoding/json" + + "github.com/cosmos/cosmos-sdk/simapp" + + ibctesting "github.com/cosmos/ibc-go/v3/testing" + + "github.com/tendermint/spm/cosmoscmd" + "github.com/tendermint/tendermint/libs/log" + tmdb "github.com/tendermint/tm-db" + + appConsumer "github.com/cosmos/interchain-security/app/consumer" + appConsumerDemocracy "github.com/cosmos/interchain-security/app/consumer-democracy" + appProvider "github.com/cosmos/interchain-security/app/provider" +) + +// ProviderAppIniter implements ibctesting.AppIniter for a provider app +func ProviderAppIniter() (ibctesting.TestingApp, map[string]json.RawMessage) { + encoding := cosmoscmd.MakeEncodingConfig(appProvider.ModuleBasics) + testApp := appProvider.New(log.NewNopLogger(), tmdb.NewMemDB(), nil, true, map[int64]bool{}, + simapp.DefaultNodeHome, 5, encoding, simapp.EmptyAppOptions{}).(ibctesting.TestingApp) + return testApp, appProvider.NewDefaultGenesisState(encoding.Marshaler) +} + +// ConsumerAppIniter implements ibctesting.AppIniter for a consumer app +func ConsumerAppIniter() (ibctesting.TestingApp, map[string]json.RawMessage) { + encoding := cosmoscmd.MakeEncodingConfig(appConsumer.ModuleBasics) + testApp := appConsumer.New(log.NewNopLogger(), tmdb.NewMemDB(), nil, true, map[int64]bool{}, + simapp.DefaultNodeHome, 5, encoding, simapp.EmptyAppOptions{}).(ibctesting.TestingApp) + return testApp, appConsumer.NewDefaultGenesisState(encoding.Marshaler) +} + +// DemocracyConsumerAppIniter implements ibctesting.AppIniter for a democracy consumer app +func DemocracyConsumerAppIniter() (ibctesting.TestingApp, map[string]json.RawMessage) { + encoding := cosmoscmd.MakeEncodingConfig(appConsumerDemocracy.ModuleBasics) + testApp := appConsumerDemocracy.New(log.NewNopLogger(), tmdb.NewMemDB(), nil, true, map[int64]bool{}, + simapp.DefaultNodeHome, 5, encoding, simapp.EmptyAppOptions{}).(ibctesting.TestingApp) + return testApp, appConsumerDemocracy.NewDefaultGenesisState(encoding.Marshaler) +} diff --git a/testutil/sample/sample.go b/testutil/sample/sample.go deleted file mode 100644 index 98f2153ed4..0000000000 --- a/testutil/sample/sample.go +++ /dev/null @@ -1,13 +0,0 @@ -package sample - -import ( - "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// AccAddress returns a sample account address -func AccAddress() string { - pk := ed25519.GenPrivKey().PubKey() - addr := pk.Address() - return sdk.AccAddress(addr).String() -} diff --git a/testutil/simapp/simapp.go b/testutil/simapp/simapp.go deleted file mode 100644 index cd76500be6..0000000000 --- a/testutil/simapp/simapp.go +++ /dev/null @@ -1,79 +0,0 @@ -package simapp - -import ( - "encoding/json" - "testing" - - "github.com/cosmos/cosmos-sdk/simapp" - - ibctesting "github.com/cosmos/ibc-go/v3/testing" - - "github.com/tendermint/spm/cosmoscmd" - "github.com/tendermint/tendermint/libs/log" - tmdb "github.com/tendermint/tm-db" - - appConsumer "github.com/cosmos/interchain-security/app/consumer" - appConsumerDemocracy "github.com/cosmos/interchain-security/app/consumer-democracy" - appProvider "github.com/cosmos/interchain-security/app/provider" -) - -func SetupTestingappProvider() (ibctesting.TestingApp, map[string]json.RawMessage) { - db := tmdb.NewMemDB() - // encCdc := app.MakeTestEncodingConfig() - encoding := cosmoscmd.MakeEncodingConfig(appProvider.ModuleBasics) - testApp := appProvider.New(log.NewNopLogger(), db, nil, true, map[int64]bool{}, simapp.DefaultNodeHome, 5, encoding, simapp.EmptyAppOptions{}).(ibctesting.TestingApp) - return testApp, appProvider.NewDefaultGenesisState(encoding.Marshaler) -} - -func SetupTestingAppConsumerDemocracy() (ibctesting.TestingApp, map[string]json.RawMessage) { - db := tmdb.NewMemDB() - // encCdc := app.MakeTestEncodingConfig() - encoding := cosmoscmd.MakeEncodingConfig(appConsumerDemocracy.ModuleBasics) - testApp := appConsumerDemocracy.New(log.NewNopLogger(), db, nil, true, map[int64]bool{}, simapp.DefaultNodeHome, 5, encoding, simapp.EmptyAppOptions{}).(ibctesting.TestingApp) - return testApp, appConsumerDemocracy.NewDefaultGenesisState(encoding.Marshaler) -} - -func SetupTestingAppConsumer() (ibctesting.TestingApp, map[string]json.RawMessage) { - db := tmdb.NewMemDB() - // encCdc := app.MakeTestEncodingConfig() - encoding := cosmoscmd.MakeEncodingConfig(appConsumer.ModuleBasics) - testApp := appConsumer.New(log.NewNopLogger(), db, nil, true, map[int64]bool{}, simapp.DefaultNodeHome, 5, encoding, simapp.EmptyAppOptions{}).(ibctesting.TestingApp) - return testApp, appConsumer.NewDefaultGenesisState(encoding.Marshaler) -} - -// NewCoordinator initializes Coordinator with 0 TestChains -func NewBasicCoordinator(t *testing.T) *ibctesting.Coordinator { - chains := make(map[string]*ibctesting.TestChain) - coord := &ibctesting.Coordinator{ - T: t, - CurrentTime: ibctesting.GlobalStartTime, - } - coord.Chains = chains - return coord -} - -// NewCoordinator initializes Coordinator with 0 TestChains -func NewProviderConsumerCoordinator(t *testing.T) (*ibctesting.Coordinator, *ibctesting.TestChain, *ibctesting.TestChain) { - coordinator := NewBasicCoordinator(t) - chainID := ibctesting.GetChainID(1) - coordinator.Chains[chainID] = ibctesting.NewTestChain(t, coordinator, SetupTestingappProvider, chainID) - providerChain := coordinator.GetChain(chainID) - chainID = ibctesting.GetChainID(2) - coordinator.Chains[chainID] = ibctesting.NewTestChainWithValSet(t, coordinator, - SetupTestingAppConsumer, chainID, providerChain.Vals, providerChain.Signers) - consumerChain := coordinator.GetChain(chainID) - return coordinator, providerChain, consumerChain -} - -// NewCoordinator initializes Coordinator with provider and democracy consumer TestChains -func NewProviderConsumerDemocracyCoordinator(t *testing.T) (*ibctesting.Coordinator, *ibctesting.TestChain, *ibctesting.TestChain) { - coordinator := NewBasicCoordinator(t) - chainID := ibctesting.GetChainID(1) - coordinator.Chains[chainID] = ibctesting.NewTestChain(t, coordinator, SetupTestingappProvider, chainID) - providerChain := coordinator.GetChain(chainID) - chainID = ibctesting.GetChainID(2) - coordinator.Chains[chainID] = ibctesting.NewTestChainWithValSet(t, coordinator, - SetupTestingAppConsumerDemocracy, chainID, providerChain.Vals, providerChain.Signers) - consumerChain := coordinator.GetChain(chainID) - return coordinator, providerChain, consumerChain -} diff --git a/x/ccv/consumer/types/params.go b/x/ccv/consumer/types/params.go index 68d586f3c6..7a0a96832e 100644 --- a/x/ccv/consumer/types/params.go +++ b/x/ccv/consumer/types/params.go @@ -1,10 +1,8 @@ package types import ( - fmt "fmt" time "time" - sdk "github.com/cosmos/cosmos-sdk/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" ccvtypes "github.com/cosmos/interchain-security/x/ccv/types" @@ -110,7 +108,7 @@ func (p Params) Validate() error { if err := ccvtypes.ValidateDuration(p.TransferTimeoutPeriod); err != nil { return err } - if err := validateConsumerRedistributionFraction(p.ConsumerRedistributionFraction); err != nil { + if err := ccvtypes.ValidateStringFraction(p.ConsumerRedistributionFraction); err != nil { return err } if err := ccvtypes.ValidatePositiveInt64(p.HistoricalEntries); err != nil { @@ -137,7 +135,7 @@ func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { paramtypes.NewParamSetPair(KeyTransferTimeoutPeriod, p.TransferTimeoutPeriod, ccvtypes.ValidateDuration), paramtypes.NewParamSetPair(KeyConsumerRedistributionFrac, - p.ConsumerRedistributionFraction, validateConsumerRedistributionFraction), + p.ConsumerRedistributionFraction, ccvtypes.ValidateStringFraction), paramtypes.NewParamSetPair(KeyHistoricalEntries, p.HistoricalEntries, ccvtypes.ValidatePositiveInt64), paramtypes.NewParamSetPair(KeyConsumerUnbondingPeriod, @@ -162,21 +160,3 @@ func validateProviderFeePoolAddrStr(i interface{}) error { // Otherwise validate as usual for a bech32 address return ccvtypes.ValidateBech32(i) } - -func validateConsumerRedistributionFraction(i interface{}) error { - str, ok := i.(string) - if !ok { - return fmt.Errorf("invalid parameter type: %T", i) - } - dec, err := sdk.NewDecFromStr(str) - if err != nil { - return err - } - if dec.IsNegative() { - return fmt.Errorf("consumer redistribution fraction is negative") - } - if dec.Sub(sdk.NewDec(1)).IsPositive() { - return fmt.Errorf("consumer redistribution fraction cannot be above 1.0") - } - return nil -} diff --git a/x/ccv/provider/keeper/keeper.go b/x/ccv/provider/keeper/keeper.go index f831ad18f1..fed221f9f8 100644 --- a/x/ccv/provider/keeper/keeper.go +++ b/x/ccv/provider/keeper/keeper.go @@ -842,6 +842,24 @@ func (k Keeper) SetVscSendTimestamp( store.Set(types.VscSendingTimestampKey(chainID, vscID), timeBz) } +// GetVscSendTimestamp returns a VSC send timestamp by chainID and vscID +// +// Note: This method is used only for testing. +func (k Keeper) GetVscSendTimestamp(ctx sdk.Context, chainID string, vscID uint64) (time.Time, bool) { + store := ctx.KVStore(k.storeKey) + + timeBz := store.Get(types.VscSendingTimestampKey(chainID, vscID)) + if timeBz == nil { + return time.Time{}, false + } + + ts, err := sdk.ParseTimeBytes(timeBz) + if err != nil { + return time.Time{}, false + } + return ts, true +} + // DeleteVscSendTimestamp removes from the store a specific VSC send timestamp // for the given chainID and vscID. func (k Keeper) DeleteVscSendTimestamp(ctx sdk.Context, chainID string, vscID uint64) { diff --git a/x/ccv/provider/keeper/params.go b/x/ccv/provider/keeper/params.go index 9ce00d2f81..ae6d34ce9a 100644 --- a/x/ccv/provider/keeper/params.go +++ b/x/ccv/provider/keeper/params.go @@ -52,6 +52,30 @@ func (k Keeper) SetVscTimeoutPeriod(ctx sdk.Context, period time.Duration) { k.paramSpace.Set(ctx, types.KeyVscTimeoutPeriod, period) } +// GetSlashMeterReplenishPeriod returns the period for which the slash gas meter is replenished. +func (k Keeper) GetSlashMeterReplenishPeriod(ctx sdk.Context) time.Duration { + var p time.Duration + k.paramSpace.Get(ctx, types.KeySlashMeterReplenishPeriod, &p) + return p +} + +// GetSlashMeterReplenishFraction returns the string fraction of total voting power that is replenished +// to the slash meter every replenish period. This param also serves as a maximum fraction of total +// voting power that the slash meter can hold. +func (k Keeper) GetSlashMeterReplenishFraction(ctx sdk.Context) string { + var f string + k.paramSpace.Get(ctx, types.KeySlashMeterReplenishFraction, &f) + return f +} + +// GetMaxPendingSlashingPackets returns the maximum number of pending slash packets that can be queued for a consumer +// before the provider chain halts. +func (k Keeper) GetMaxPendingSlashingPackets(ctx sdk.Context) int64 { + var p int64 + k.paramSpace.Get(ctx, types.KeyMaxPendingSlashPackets, &p) + return p +} + // GetParams returns the paramset for the provider module func (k Keeper) GetParams(ctx sdk.Context) types.Params { return types.NewParams( @@ -60,6 +84,9 @@ func (k Keeper) GetParams(ctx sdk.Context) types.Params { k.GetCCVTimeoutPeriod(ctx), k.GetInitTimeoutPeriod(ctx), k.GetVscTimeoutPeriod(ctx), + k.GetSlashMeterReplenishPeriod(ctx), + k.GetSlashMeterReplenishFraction(ctx), + k.GetMaxPendingSlashingPackets(ctx), ) } diff --git a/x/ccv/provider/keeper/params_test.go b/x/ccv/provider/keeper/params_test.go index 02da2aa9de..7fbeb8760f 100644 --- a/x/ccv/provider/keeper/params_test.go +++ b/x/ccv/provider/keeper/params_test.go @@ -8,8 +8,7 @@ import ( commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" testkeeper "github.com/cosmos/interchain-security/testutil/keeper" - "github.com/cosmos/interchain-security/x/ccv/provider/types" - ccvtypes "github.com/cosmos/interchain-security/x/ccv/types" + providertypes "github.com/cosmos/interchain-security/x/ccv/provider/types" "github.com/stretchr/testify/require" ) @@ -21,14 +20,32 @@ func TestParams(t *testing.T) { providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, keeperParams) defer ctrl.Finish() - defaultParams := types.DefaultParams() + defaultParams := providertypes.DefaultParams() providerKeeper.SetParams(ctx, defaultParams) params := providerKeeper.GetParams(ctx) require.Equal(t, defaultParams, params) - newParams := types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, - time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}, true, false), - types.DefaultTrustingPeriodFraction, ccvtypes.DefaultCCVTimeoutPeriod, types.DefaultInitTimeoutPeriod, types.DefaultVscTimeoutPeriod) + newParams := providertypes.NewParams( + ibctmtypes.NewClientState( + "", + ibctmtypes.DefaultTrustLevel, + 0, + 0, + time.Second*40, + clienttypes.Height{}, + commitmenttypes.GetSDKSpecs(), + []string{"ibc", "upgradedIBCState"}, + true, + false, + ), + 4, + 7*24*time.Hour, + 5*time.Hour, + 10*time.Minute, + time.Hour, + "0.4", + 100, + ) providerKeeper.SetParams(ctx, newParams) params = providerKeeper.GetParams(ctx) require.Equal(t, newParams, params) diff --git a/x/ccv/provider/keeper/proposal_test.go b/x/ccv/provider/keeper/proposal_test.go index fbd49e724f..968c9bb51c 100644 --- a/x/ccv/provider/keeper/proposal_test.go +++ b/x/ccv/provider/keeper/proposal_test.go @@ -633,10 +633,13 @@ func TestMakeConsumerGenesis(t *testing.T) { }, // Note these are unused provider parameters for this test, and not actually asserted against // They must be populated with reasonable values to satisfy SetParams though. - TrustingPeriodFraction: providertypes.DefaultTrustingPeriodFraction, - CcvTimeoutPeriod: ccvtypes.DefaultCCVTimeoutPeriod, - InitTimeoutPeriod: types.DefaultInitTimeoutPeriod, - VscTimeoutPeriod: types.DefaultVscTimeoutPeriod, + TrustingPeriodFraction: providertypes.DefaultTrustingPeriodFraction, + CcvTimeoutPeriod: ccvtypes.DefaultCCVTimeoutPeriod, + InitTimeoutPeriod: types.DefaultInitTimeoutPeriod, + VscTimeoutPeriod: types.DefaultVscTimeoutPeriod, + SlashMeterReplenishPeriod: types.DefaultSlashMeterReplenishPeriod, + SlashMeterReplenishFraction: types.DefaultSlashMeterReplenishFraction, + MaxPendingSlashPackets: types.DefaultMaxPendingSlashPackets, } providerKeeper.SetParams(ctx, moduleParams) defer ctrl.Finish() diff --git a/x/ccv/provider/types/genesis_test.go b/x/ccv/provider/types/genesis_test.go index 87aa1f8ff5..c1613c8277 100644 --- a/x/ccv/provider/types/genesis_test.go +++ b/x/ccv/provider/types/genesis_test.go @@ -79,7 +79,7 @@ func TestValidateGenesisState(t *testing.T) { nil, types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}, true, false), - 3, time.Hour, time.Hour, time.Hour), + 3, time.Hour, time.Hour, 30*time.Minute, time.Hour, "0.1", 400), ), true, }, @@ -95,7 +95,13 @@ func TestValidateGenesisState(t *testing.T) { nil, types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, 0, clienttypes.Height{}, nil, []string{"ibc", "upgradedIBCState"}, true, false), - types.DefaultTrustingPeriodFraction, ccv.DefaultCCVTimeoutPeriod, types.DefaultInitTimeoutPeriod, types.DefaultVscTimeoutPeriod), + types.DefaultTrustingPeriodFraction, + ccv.DefaultCCVTimeoutPeriod, + types.DefaultInitTimeoutPeriod, + types.DefaultVscTimeoutPeriod, + types.DefaultSlashMeterReplenishPeriod, + types.DefaultSlashMeterReplenishFraction, + types.DefaultMaxPendingSlashPackets), ), false, }, @@ -114,7 +120,10 @@ func TestValidateGenesisState(t *testing.T) { 0, // 0 trusting period fraction here ccv.DefaultCCVTimeoutPeriod, types.DefaultInitTimeoutPeriod, - types.DefaultVscTimeoutPeriod), + types.DefaultVscTimeoutPeriod, + types.DefaultSlashMeterReplenishPeriod, + types.DefaultSlashMeterReplenishFraction, + types.DefaultMaxPendingSlashPackets), ), false, }, @@ -133,7 +142,10 @@ func TestValidateGenesisState(t *testing.T) { types.DefaultTrustingPeriodFraction, 0, // 0 ccv timeout here types.DefaultInitTimeoutPeriod, - types.DefaultVscTimeoutPeriod), + types.DefaultVscTimeoutPeriod, + types.DefaultSlashMeterReplenishPeriod, + types.DefaultSlashMeterReplenishFraction, + types.DefaultMaxPendingSlashPackets), ), false, }, @@ -152,7 +164,10 @@ func TestValidateGenesisState(t *testing.T) { types.DefaultTrustingPeriodFraction, ccv.DefaultCCVTimeoutPeriod, 0, // 0 init timeout here - types.DefaultVscTimeoutPeriod), + types.DefaultVscTimeoutPeriod, + types.DefaultSlashMeterReplenishPeriod, + types.DefaultSlashMeterReplenishFraction, + types.DefaultMaxPendingSlashPackets), ), false, }, @@ -171,7 +186,76 @@ func TestValidateGenesisState(t *testing.T) { types.DefaultTrustingPeriodFraction, ccv.DefaultCCVTimeoutPeriod, types.DefaultInitTimeoutPeriod, - 0), // 0 vsc timeout here + 0, // 0 vsc timeout here + types.DefaultSlashMeterReplenishPeriod, + types.DefaultSlashMeterReplenishFraction, + types.DefaultMaxPendingSlashPackets), + ), + false, + }, + { + "invalid params, zero slash meter replenish period", + types.NewGenesisState( + 0, + nil, + []types.ConsumerState{{ChainId: "chainid-1", ChannelId: "channelid"}}, + nil, + nil, + nil, + nil, + types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, + time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}, true, false), + types.DefaultTrustingPeriodFraction, + ccv.DefaultCCVTimeoutPeriod, + types.DefaultInitTimeoutPeriod, + types.DefaultVscTimeoutPeriod, + 0, // 0 slash meter replenish period here + types.DefaultSlashMeterReplenishFraction, + types.DefaultMaxPendingSlashPackets), + ), + false, + }, + { + "invalid params, invalid slash meter replenish fraction", + types.NewGenesisState( + 0, + nil, + []types.ConsumerState{{ChainId: "chainid-1", ChannelId: "channelid"}}, + nil, + nil, + nil, + nil, + types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, + time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}, true, false), + types.DefaultTrustingPeriodFraction, + ccv.DefaultCCVTimeoutPeriod, + types.DefaultInitTimeoutPeriod, + types.DefaultVscTimeoutPeriod, + types.DefaultSlashMeterReplenishPeriod, + "1.15", + types.DefaultMaxPendingSlashPackets), + ), + false, + }, + { + "invalid params, invalid max pending slash packets", + types.NewGenesisState( + 0, + nil, + []types.ConsumerState{{ChainId: "chainid-1", ChannelId: "channelid"}}, + nil, + nil, + nil, + nil, + types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, + time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}, true, false), + types.DefaultTrustingPeriodFraction, + ccv.DefaultCCVTimeoutPeriod, + types.DefaultInitTimeoutPeriod, + types.DefaultVscTimeoutPeriod, + types.DefaultSlashMeterReplenishPeriod, + "1.15", + -1), ), false, }, diff --git a/x/ccv/provider/types/params.go b/x/ccv/provider/types/params.go index be3281ee06..87e9773557 100644 --- a/x/ccv/provider/types/params.go +++ b/x/ccv/provider/types/params.go @@ -26,14 +26,29 @@ const ( // DefaultVscTimeoutPeriod defines the VSC timeout period DefaultVscTimeoutPeriod = 5 * 7 * 24 * time.Hour + + // DefaultSlashMeterReplenishPeriod defines the default period for which the slash gas meter is replenished + DefaultSlashMeterReplenishPeriod = time.Hour + + // DefaultSlashMeterReplenishFraction defines the default fraction of total voting power + // that is replenished to the slash meter every replenish period. This param also serves as a maximum + // fraction of total voting power that the slash meter can hold. + DefaultSlashMeterReplenishFraction = "0.05" + + // DefaultMaxPendingSlashPackets defines the default maximum amount of pending slash packets that can + // be queued for a consumer before the provider chain halts. + DefaultMaxPendingSlashPackets = 1000 ) // Reflection based keys for params subspace var ( - KeyTemplateClient = []byte("TemplateClient") - KeyTrustingPeriodFraction = []byte("TrustingPeriodFraction") - KeyInitTimeoutPeriod = []byte("InitTimeoutPeriod") - KeyVscTimeoutPeriod = []byte("VscTimeoutPeriod") + KeyTemplateClient = []byte("TemplateClient") + KeyTrustingPeriodFraction = []byte("TrustingPeriodFraction") + KeyInitTimeoutPeriod = []byte("InitTimeoutPeriod") + KeyVscTimeoutPeriod = []byte("VscTimeoutPeriod") + KeySlashMeterReplenishPeriod = []byte("SlashMeterReplenishPeriod") + KeySlashMeterReplenishFraction = []byte("SlashMeterReplenishFraction") + KeyMaxPendingSlashPackets = []byte("MaxPendingSlashPackets") ) // ParamKeyTable returns a key table with the necessary registered provider params @@ -48,13 +63,19 @@ func NewParams( ccvTimeoutPeriod time.Duration, initTimeoutPeriod time.Duration, vscTimeoutPeriod time.Duration, + slashMeterReplenishPeriod time.Duration, + slashMeterReplenishFraction string, + maxPendingSlashPackets int64, ) Params { return Params{ - TemplateClient: cs, - TrustingPeriodFraction: trustingPeriodFraction, - CcvTimeoutPeriod: ccvTimeoutPeriod, - InitTimeoutPeriod: initTimeoutPeriod, - VscTimeoutPeriod: vscTimeoutPeriod, + TemplateClient: cs, + TrustingPeriodFraction: trustingPeriodFraction, + CcvTimeoutPeriod: ccvTimeoutPeriod, + InitTimeoutPeriod: initTimeoutPeriod, + VscTimeoutPeriod: vscTimeoutPeriod, + SlashMeterReplenishPeriod: slashMeterReplenishPeriod, + SlashMeterReplenishFraction: slashMeterReplenishFraction, + MaxPendingSlashPackets: maxPendingSlashPackets, } } @@ -79,6 +100,9 @@ func DefaultParams() Params { ccvtypes.DefaultCCVTimeoutPeriod, DefaultInitTimeoutPeriod, DefaultVscTimeoutPeriod, + DefaultSlashMeterReplenishPeriod, + DefaultSlashMeterReplenishFraction, + DefaultMaxPendingSlashPackets, ) } @@ -102,6 +126,15 @@ func (p Params) Validate() error { if err := ccvtypes.ValidateDuration(p.VscTimeoutPeriod); err != nil { return fmt.Errorf("vsc timeout period is invalid: %s", err) } + if err := ccvtypes.ValidateDuration(p.SlashMeterReplenishPeriod); err != nil { + return fmt.Errorf("slash meter replenish period is invalid: %s", err) + } + if err := ccvtypes.ValidateStringFraction(p.SlashMeterReplenishFraction); err != nil { + return fmt.Errorf("slash meter replenish fraction is invalid: %s", err) + } + if err := ccvtypes.ValidatePositiveInt64(p.MaxPendingSlashPackets); err != nil { + return fmt.Errorf("max pending slash packets is invalid: %s", err) + } return nil } @@ -113,6 +146,9 @@ func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { paramtypes.NewParamSetPair(ccvtypes.KeyCCVTimeoutPeriod, p.CcvTimeoutPeriod, ccvtypes.ValidateDuration), paramtypes.NewParamSetPair(KeyInitTimeoutPeriod, p.InitTimeoutPeriod, ccvtypes.ValidateDuration), paramtypes.NewParamSetPair(KeyVscTimeoutPeriod, p.VscTimeoutPeriod, ccvtypes.ValidateDuration), + paramtypes.NewParamSetPair(KeySlashMeterReplenishPeriod, p.SlashMeterReplenishPeriod, ccvtypes.ValidateDuration), + paramtypes.NewParamSetPair(KeySlashMeterReplenishFraction, p.SlashMeterReplenishFraction, ccvtypes.ValidateStringFraction), + paramtypes.NewParamSetPair(KeyMaxPendingSlashPackets, p.MaxPendingSlashPackets, ccvtypes.ValidatePositiveInt64), } } diff --git a/x/ccv/provider/types/params_test.go b/x/ccv/provider/types/params_test.go index f4a13a7bd3..1db46449b8 100644 --- a/x/ccv/provider/types/params_test.go +++ b/x/ccv/provider/types/params_test.go @@ -22,25 +22,34 @@ func TestValidateParams(t *testing.T) { {"default params", types.DefaultParams(), true}, {"custom valid params", types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}, true, false), - 3, time.Hour, time.Hour, time.Hour), true}, + 3, time.Hour, time.Hour, time.Hour, 30*time.Minute, "0.1", 100), true}, {"custom invalid params", types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, 0, clienttypes.Height{}, nil, []string{"ibc", "upgradedIBCState"}, true, false), - 3, time.Hour, time.Hour, time.Hour), false}, + 3, time.Hour, time.Hour, time.Hour, 30*time.Minute, "0.1", 100), false}, {"blank client", types.NewParams(&ibctmtypes.ClientState{}, - 3, time.Hour, time.Hour, time.Hour), false}, - {"nil client", types.NewParams(nil, 3, time.Hour, time.Hour, time.Hour), false}, + 3, time.Hour, time.Hour, time.Hour, 30*time.Minute, "0.1", 100), false}, + {"nil client", types.NewParams(nil, 3, time.Hour, time.Hour, time.Hour, 30*time.Minute, "0.1", 100), false}, {"0 trusting period fraction (denominator)", types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}, true, false), - 0, time.Hour, time.Hour, time.Hour), false}, + 0, time.Hour, time.Hour, time.Hour, 30*time.Minute, "0.1", 100), false}, {"0 ccv timeout period", types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}, true, false), - 3, 0, time.Hour, time.Hour), false}, + 3, 0, time.Hour, time.Hour, 30*time.Minute, "0.1", 100), false}, {"0 init timeout period", types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}, true, false), - 3, time.Hour, 0, time.Hour), false}, + 3, time.Hour, 0, time.Hour, 30*time.Minute, "0.1", 100), false}, {"0 vsc timeout period", types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}, true, false), - 3, time.Hour, time.Hour, 0), false}, + 3, time.Hour, time.Hour, 0, 30*time.Minute, "0.1", 100), false}, + {"0 slash meter replenish period", types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, + time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}, true, false), + 3, time.Hour, time.Hour, 24*time.Hour, 0, "0.1", 100), false}, + {"slash meter replenish fraction over 1", types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, + time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}, true, false), + 3, time.Hour, time.Hour, 24*time.Hour, time.Hour, "1.5", 100), false}, + {"negative max pending slash packets", types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, + time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}, true, false), + 3, time.Hour, time.Hour, 24*time.Hour, time.Hour, "0.1", -100), false}, } for _, tc := range testCases { diff --git a/x/ccv/provider/types/provider.pb.go b/x/ccv/provider/types/provider.pb.go index b928cb9751..8c36024522 100644 --- a/x/ccv/provider/types/provider.pb.go +++ b/x/ccv/provider/types/provider.pb.go @@ -178,6 +178,14 @@ type Params struct { // the vsc_timeout_period is a provider-side param that enables the provider // to timeout VSC packets even when a consumer chain is not live. VscTimeoutPeriod time.Duration `protobuf:"bytes,5,opt,name=vsc_timeout_period,json=vscTimeoutPeriod,proto3,stdduration" json:"vsc_timeout_period"` + // The period for which the slash meter is replenished + SlashMeterReplenishPeriod time.Duration `protobuf:"bytes,6,opt,name=slash_meter_replenish_period,json=slashMeterReplenishPeriod,proto3,stdduration" json:"slash_meter_replenish_period"` + // The fraction of total voting power that is replenished to the slash meter every replenish period. + // This param also serves as a maximum fraction of total voting power that the slash meter can hold. + SlashMeterReplenishFraction string `protobuf:"bytes,7,opt,name=slash_meter_replenish_fraction,json=slashMeterReplenishFraction,proto3" json:"slash_meter_replenish_fraction,omitempty"` + // The maximum amount of pending slash packets that can be queued for a consumer + // before the provider chain halts. + MaxPendingSlashPackets int64 `protobuf:"varint,8,opt,name=max_pending_slash_packets,json=maxPendingSlashPackets,proto3" json:"max_pending_slash_packets,omitempty"` } func (m *Params) Reset() { *m = Params{} } @@ -248,6 +256,27 @@ func (m *Params) GetVscTimeoutPeriod() time.Duration { return 0 } +func (m *Params) GetSlashMeterReplenishPeriod() time.Duration { + if m != nil { + return m.SlashMeterReplenishPeriod + } + return 0 +} + +func (m *Params) GetSlashMeterReplenishFraction() string { + if m != nil { + return m.SlashMeterReplenishFraction + } + return "" +} + +func (m *Params) GetMaxPendingSlashPackets() int64 { + if m != nil { + return m.MaxPendingSlashPackets + } + return 0 +} + type HandshakeMetadata struct { ProviderFeePoolAddr string `protobuf:"bytes,1,opt,name=provider_fee_pool_addr,json=providerFeePoolAddr,proto3" json:"provider_fee_pool_addr,omitempty"` Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"` @@ -453,57 +482,62 @@ func init() { } var fileDescriptor_f22ec409a72b7b72 = []byte{ - // 797 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x55, 0x41, 0x6f, 0xe3, 0x44, - 0x14, 0x8e, 0x49, 0xda, 0x24, 0x93, 0x65, 0x61, 0x67, 0x57, 0xc5, 0xa9, 0x50, 0x12, 0xc2, 0x25, - 0x08, 0x61, 0x2b, 0xd9, 0x0b, 0xac, 0xe0, 0x90, 0x16, 0x2d, 0xe5, 0x80, 0xc8, 0xba, 0x05, 0x24, - 0x2e, 0xd6, 0x78, 0x66, 0x6a, 0x8f, 0x6a, 0x7b, 0xac, 0x99, 0xb1, 0xa1, 0x77, 0x0e, 0x1c, 0x57, - 0xe2, 0xb2, 0xc7, 0xfd, 0x07, 0xfc, 0x8d, 0x3d, 0xf6, 0xc8, 0x09, 0x50, 0xfb, 0x47, 0xd0, 0xcc, - 0xd8, 0x49, 0x1b, 0xa8, 0xd4, 0x1e, 0xb8, 0x79, 0xde, 0xfb, 0xbe, 0x6f, 0xde, 0x9b, 0xef, 0xcd, - 0x18, 0x2c, 0x58, 0xae, 0xa8, 0xc0, 0x09, 0x62, 0x79, 0x28, 0x29, 0x2e, 0x05, 0x53, 0xe7, 0x3e, - 0xc6, 0x95, 0x5f, 0x08, 0x5e, 0x31, 0x42, 0x85, 0x5f, 0xcd, 0xd7, 0xdf, 0x5e, 0x21, 0xb8, 0xe2, - 0xf0, 0xc3, 0xff, 0xe0, 0x78, 0x18, 0x57, 0xde, 0x1a, 0x57, 0xcd, 0xf7, 0x9f, 0xc4, 0x3c, 0xe6, - 0x06, 0xef, 0xeb, 0x2f, 0x4b, 0xdd, 0x1f, 0xc7, 0x9c, 0xc7, 0x29, 0xf5, 0xcd, 0x2a, 0x2a, 0x4f, - 0x7d, 0xc5, 0x32, 0x2a, 0x15, 0xca, 0x8a, 0x1a, 0x30, 0xda, 0x06, 0x90, 0x52, 0x20, 0xc5, 0x78, - 0xde, 0x08, 0xb0, 0x08, 0xfb, 0x98, 0x0b, 0xea, 0xe3, 0x94, 0xd1, 0x5c, 0xe9, 0xf2, 0xec, 0x57, - 0x0d, 0xf0, 0x35, 0x20, 0x65, 0x71, 0xa2, 0x6c, 0x58, 0xfa, 0x8a, 0xe6, 0x84, 0x8a, 0x8c, 0x59, - 0xf0, 0x66, 0x65, 0x09, 0xd3, 0x5f, 0xda, 0xc0, 0x3d, 0xe4, 0xb9, 0x2c, 0x33, 0x2a, 0x96, 0x84, - 0x30, 0xbd, 0xd9, 0x4a, 0xf0, 0x82, 0x4b, 0x94, 0xc2, 0x27, 0x60, 0x47, 0x31, 0x95, 0x52, 0xd7, - 0x99, 0x38, 0xb3, 0x7e, 0x60, 0x17, 0x70, 0x02, 0x06, 0x84, 0x4a, 0x2c, 0x58, 0xa1, 0xc1, 0xee, - 0x5b, 0x26, 0x77, 0x3d, 0x04, 0x87, 0xa0, 0x67, 0xcf, 0x87, 0x11, 0xb7, 0x6d, 0xd2, 0x5d, 0xb3, - 0xfe, 0x9a, 0xc0, 0xaf, 0xc0, 0x43, 0x96, 0x33, 0xc5, 0x50, 0x1a, 0x26, 0x54, 0xd7, 0xe9, 0x76, - 0x26, 0xce, 0x6c, 0xb0, 0xd8, 0xf7, 0x58, 0x84, 0x3d, 0xdd, 0x9a, 0x57, 0x37, 0x54, 0xcd, 0xbd, - 0x23, 0x83, 0x38, 0xe8, 0xbc, 0xf9, 0x73, 0xdc, 0x0a, 0xde, 0xae, 0x79, 0x36, 0x08, 0x3f, 0x00, - 0x0f, 0x62, 0x9a, 0x53, 0xc9, 0x64, 0x98, 0x20, 0x99, 0xb8, 0x3b, 0x13, 0x67, 0xf6, 0x20, 0x18, - 0xd4, 0xb1, 0x23, 0x24, 0x13, 0x38, 0x06, 0x83, 0x88, 0xe5, 0x48, 0x9c, 0x5b, 0xc4, 0xae, 0x41, - 0x00, 0x1b, 0x32, 0x80, 0x43, 0x00, 0x64, 0x81, 0x7e, 0xca, 0x43, 0xed, 0x83, 0xdb, 0xad, 0x0b, - 0xb1, 0x1e, 0x78, 0x8d, 0x07, 0xde, 0x49, 0x63, 0xd2, 0x41, 0x4f, 0x17, 0xf2, 0xf2, 0xaf, 0xb1, - 0x13, 0xf4, 0x0d, 0x4f, 0x67, 0xe0, 0x67, 0x60, 0x98, 0x72, 0x7c, 0x16, 0x96, 0x79, 0xc4, 0x73, - 0xc2, 0xf2, 0x38, 0xe4, 0x56, 0x90, 0x97, 0xca, 0xed, 0x4d, 0x9c, 0x59, 0x2f, 0xd8, 0xd3, 0x80, - 0xef, 0x9a, 0xfc, 0xb7, 0x86, 0xc7, 0x4b, 0xf5, 0xac, 0xf7, 0xeb, 0xeb, 0x71, 0xeb, 0xd5, 0xeb, - 0x71, 0x6b, 0xfa, 0xbb, 0x03, 0xde, 0x6b, 0x6c, 0x08, 0x68, 0xc6, 0x2b, 0x94, 0xfe, 0x9f, 0x2e, - 0x2c, 0x41, 0x5f, 0x2a, 0x5e, 0xd8, 0xbe, 0x3b, 0xf7, 0xe8, 0xbb, 0xa7, 0x69, 0x3a, 0x31, 0xfd, - 0xad, 0x0d, 0x76, 0x57, 0x48, 0xa0, 0x4c, 0xc2, 0x13, 0xf0, 0x8e, 0xa2, 0x59, 0x91, 0x22, 0x45, - 0x43, 0x6b, 0x9e, 0x29, 0x75, 0xb0, 0xf8, 0xd8, 0x98, 0x7a, 0x7d, 0x1c, 0xbd, 0x6b, 0x03, 0x58, - 0xcd, 0xbd, 0x43, 0x13, 0x3d, 0x56, 0x48, 0xd1, 0xe0, 0x61, 0xa3, 0x61, 0x83, 0xf0, 0x53, 0xe0, - 0x2a, 0x51, 0x4a, 0xa5, 0x4f, 0xb4, 0xa0, 0x82, 0x71, 0x12, 0x9e, 0x0a, 0x84, 0xd7, 0xdd, 0xb6, - 0x83, 0xbd, 0x26, 0xbf, 0x32, 0xe9, 0xe7, 0x75, 0x16, 0xbe, 0x00, 0x10, 0xe3, 0xaa, 0xf1, 0xa0, - 0x26, 0x9b, 0x23, 0x18, 0x2c, 0x86, 0xff, 0x6a, 0xf3, 0xcb, 0xfa, 0x8a, 0xd9, 0x2e, 0x5f, 0xe9, - 0x2e, 0xdf, 0xc5, 0xb8, 0xaa, 0x3d, 0xb2, 0xd2, 0xf0, 0x18, 0x3c, 0xd6, 0xe3, 0xb7, 0xad, 0xd9, - 0xb9, 0xbb, 0xe6, 0x23, 0xcd, 0xbf, 0x29, 0xfa, 0x02, 0xc0, 0x4a, 0xe2, 0x6d, 0xcd, 0x9d, 0x7b, - 0xd4, 0x59, 0x49, 0x7c, 0x43, 0x72, 0x1a, 0x81, 0x47, 0x47, 0x28, 0x27, 0x32, 0x41, 0x67, 0xf4, - 0x1b, 0xaa, 0x10, 0x41, 0x0a, 0xc1, 0xa7, 0x60, 0xaf, 0x79, 0x9b, 0xc2, 0x53, 0x4a, 0xc3, 0x82, - 0xf3, 0x34, 0x44, 0x84, 0x88, 0x7a, 0xa2, 0x1e, 0x37, 0xd9, 0xe7, 0x94, 0xae, 0x38, 0x4f, 0x97, - 0x84, 0x08, 0xe8, 0x82, 0x6e, 0x45, 0x85, 0xdc, 0xcc, 0x56, 0xb3, 0x9c, 0x7e, 0x04, 0xfa, 0xc7, - 0x29, 0x92, 0xc9, 0x12, 0x9f, 0x49, 0xf8, 0x3e, 0xe8, 0x6b, 0x25, 0x2a, 0x25, 0x95, 0xae, 0x33, - 0x69, 0xcf, 0xfa, 0xc1, 0x26, 0x30, 0x55, 0x60, 0x78, 0xdb, 0xe3, 0x22, 0xe1, 0x0f, 0xa0, 0x5b, - 0x50, 0x73, 0x23, 0x0c, 0x71, 0xb0, 0xf8, 0xc2, 0xbb, 0xc3, 0xd3, 0xea, 0xdd, 0x26, 0x18, 0x34, - 0x6a, 0x53, 0xb1, 0x79, 0xd2, 0xb6, 0xee, 0x92, 0x84, 0xdf, 0x6f, 0x6f, 0xfa, 0xf9, 0xbd, 0x36, - 0xdd, 0xd2, 0x5b, 0xef, 0x79, 0x70, 0xf2, 0xe6, 0x72, 0xe4, 0x5c, 0x5c, 0x8e, 0x9c, 0xbf, 0x2f, - 0x47, 0xce, 0xcb, 0xab, 0x51, 0xeb, 0xe2, 0x6a, 0xd4, 0xfa, 0xe3, 0x6a, 0xd4, 0xfa, 0xf1, 0x59, - 0xcc, 0x54, 0x52, 0x46, 0x1e, 0xe6, 0x99, 0x8f, 0xb9, 0xcc, 0xb8, 0xf4, 0x37, 0x3b, 0x7e, 0xb2, - 0xfe, 0xeb, 0xfc, 0x7c, 0xf3, 0xbf, 0xa3, 0xce, 0x0b, 0x2a, 0xa3, 0x5d, 0xe3, 0xfe, 0xd3, 0x7f, - 0x02, 0x00, 0x00, 0xff, 0xff, 0x97, 0x79, 0x3f, 0x95, 0xa8, 0x06, 0x00, 0x00, + // 872 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x55, 0xcf, 0x73, 0xdb, 0x44, + 0x14, 0xb6, 0xb0, 0x13, 0xdb, 0xeb, 0x52, 0xe8, 0xb6, 0x13, 0xe4, 0xd0, 0xb1, 0x8d, 0xb9, 0x98, + 0x61, 0x90, 0x26, 0xee, 0x85, 0x76, 0xe0, 0x90, 0x84, 0x29, 0xe1, 0xd0, 0xc1, 0x55, 0x02, 0xcc, + 0x70, 0xd1, 0xac, 0x57, 0x2f, 0xd6, 0x4e, 0x24, 0xad, 0x66, 0x77, 0x25, 0x92, 0x3b, 0x07, 0x8e, + 0x3d, 0xf6, 0xd8, 0xff, 0x80, 0x7f, 0xa3, 0xc7, 0x1e, 0x39, 0x01, 0x93, 0xfc, 0x15, 0xdc, 0x98, + 0xdd, 0x95, 0xec, 0xc4, 0x24, 0x33, 0xc9, 0x81, 0x9b, 0xf6, 0x7d, 0xdf, 0xfb, 0xde, 0x7b, 0xfa, + 0xf6, 0x07, 0x9a, 0xb2, 0x4c, 0x81, 0xa0, 0x31, 0x61, 0x59, 0x28, 0x81, 0x16, 0x82, 0xa9, 0x33, + 0x9f, 0xd2, 0xd2, 0xcf, 0x05, 0x2f, 0x59, 0x04, 0xc2, 0x2f, 0x77, 0x96, 0xdf, 0x5e, 0x2e, 0xb8, + 0xe2, 0xf8, 0xd3, 0x6b, 0x72, 0x3c, 0x4a, 0x4b, 0x6f, 0xc9, 0x2b, 0x77, 0xb6, 0x1f, 0x2d, 0xf8, + 0x82, 0x1b, 0xbe, 0xaf, 0xbf, 0x6c, 0xea, 0xf6, 0x70, 0xc1, 0xf9, 0x22, 0x01, 0xdf, 0xac, 0xe6, + 0xc5, 0xb1, 0xaf, 0x58, 0x0a, 0x52, 0x91, 0x34, 0xaf, 0x08, 0x83, 0x75, 0x42, 0x54, 0x08, 0xa2, + 0x18, 0xcf, 0x6a, 0x01, 0x36, 0xa7, 0x3e, 0xe5, 0x02, 0x7c, 0x9a, 0x30, 0xc8, 0x94, 0x6e, 0xcf, + 0x7e, 0x55, 0x04, 0x5f, 0x13, 0x12, 0xb6, 0x88, 0x95, 0x0d, 0x4b, 0x5f, 0x41, 0x16, 0x81, 0x48, + 0x99, 0x25, 0xaf, 0x56, 0x36, 0x61, 0xfc, 0x6b, 0x13, 0xb9, 0xfb, 0x3c, 0x93, 0x45, 0x0a, 0x62, + 0x37, 0x8a, 0x98, 0x2e, 0x36, 0x13, 0x3c, 0xe7, 0x92, 0x24, 0xf8, 0x11, 0xda, 0x50, 0x4c, 0x25, + 0xe0, 0x3a, 0x23, 0x67, 0xd2, 0x0d, 0xec, 0x02, 0x8f, 0x50, 0x2f, 0x02, 0x49, 0x05, 0xcb, 0x35, + 0xd9, 0x7d, 0xcf, 0x60, 0x97, 0x43, 0xb8, 0x8f, 0x3a, 0xf6, 0xff, 0xb0, 0xc8, 0x6d, 0x1a, 0xb8, + 0x6d, 0xd6, 0xdf, 0x45, 0xf8, 0x5b, 0x74, 0x9f, 0x65, 0x4c, 0x31, 0x92, 0x84, 0x31, 0xe8, 0x3e, + 0xdd, 0xd6, 0xc8, 0x99, 0xf4, 0xa6, 0xdb, 0x1e, 0x9b, 0x53, 0x4f, 0x8f, 0xe6, 0x55, 0x03, 0x95, + 0x3b, 0xde, 0x81, 0x61, 0xec, 0xb5, 0xde, 0xfe, 0x39, 0x6c, 0x04, 0xef, 0x57, 0x79, 0x36, 0x88, + 0x3f, 0x41, 0xf7, 0x16, 0x90, 0x81, 0x64, 0x32, 0x8c, 0x89, 0x8c, 0xdd, 0x8d, 0x91, 0x33, 0xb9, + 0x17, 0xf4, 0xaa, 0xd8, 0x01, 0x91, 0x31, 0x1e, 0xa2, 0xde, 0x9c, 0x65, 0x44, 0x9c, 0x59, 0xc6, + 0xa6, 0x61, 0x20, 0x1b, 0x32, 0x84, 0x7d, 0x84, 0x64, 0x4e, 0x7e, 0xc9, 0x42, 0xed, 0x83, 0xdb, + 0xae, 0x1a, 0xb1, 0x1e, 0x78, 0xb5, 0x07, 0xde, 0x51, 0x6d, 0xd2, 0x5e, 0x47, 0x37, 0xf2, 0xea, + 0xaf, 0xa1, 0x13, 0x74, 0x4d, 0x9e, 0x46, 0xf0, 0x53, 0xd4, 0x4f, 0x38, 0x3d, 0x09, 0x8b, 0x6c, + 0xce, 0xb3, 0x88, 0x65, 0x8b, 0x90, 0x5b, 0x41, 0x5e, 0x28, 0xb7, 0x33, 0x72, 0x26, 0x9d, 0x60, + 0x4b, 0x13, 0x7e, 0xa8, 0xf1, 0xef, 0x4d, 0x1e, 0x2f, 0xd4, 0xb3, 0xce, 0x6f, 0x6f, 0x86, 0x8d, + 0xd7, 0x6f, 0x86, 0x8d, 0xf1, 0xef, 0x0e, 0xfa, 0xa8, 0xb6, 0x21, 0x80, 0x94, 0x97, 0x24, 0xf9, + 0x3f, 0x5d, 0xd8, 0x45, 0x5d, 0xa9, 0x78, 0x6e, 0xe7, 0x6e, 0xdd, 0x61, 0xee, 0x8e, 0x4e, 0xd3, + 0xc0, 0xf8, 0x9f, 0x16, 0xda, 0x9c, 0x11, 0x41, 0x52, 0x89, 0x8f, 0xd0, 0x07, 0x0a, 0xd2, 0x3c, + 0x21, 0x0a, 0x42, 0x6b, 0x9e, 0x69, 0xb5, 0x37, 0xfd, 0xdc, 0x98, 0x7a, 0x79, 0x3b, 0x7a, 0x97, + 0x36, 0x60, 0xb9, 0xe3, 0xed, 0x9b, 0xe8, 0xa1, 0x22, 0x0a, 0x82, 0xfb, 0xb5, 0x86, 0x0d, 0xe2, + 0x2f, 0x91, 0xab, 0x44, 0x21, 0x95, 0xfe, 0xa3, 0x39, 0x08, 0xc6, 0xa3, 0xf0, 0x58, 0x10, 0xba, + 0x9c, 0xb6, 0x19, 0x6c, 0xd5, 0xf8, 0xcc, 0xc0, 0xcf, 0x2b, 0x14, 0xbf, 0x44, 0x98, 0xd2, 0xb2, + 0xf6, 0xa0, 0x4a, 0x36, 0xbf, 0xa0, 0x37, 0xed, 0xff, 0x67, 0xcc, 0x6f, 0xaa, 0x23, 0x66, 0xa7, + 0x7c, 0xad, 0xa7, 0xfc, 0x90, 0xd2, 0xb2, 0xf2, 0xc8, 0x4a, 0xe3, 0x43, 0xf4, 0x50, 0x6f, 0xbf, + 0x75, 0xcd, 0xd6, 0xed, 0x35, 0x1f, 0xe8, 0xfc, 0xab, 0xa2, 0x2f, 0x11, 0x2e, 0x25, 0x5d, 0xd7, + 0xdc, 0xb8, 0x43, 0x9f, 0xa5, 0xa4, 0x57, 0x25, 0x23, 0xf4, 0x58, 0x26, 0x44, 0xc6, 0x61, 0x0a, + 0x0a, 0x44, 0x28, 0x20, 0x4f, 0x20, 0x63, 0x32, 0xae, 0xc5, 0x37, 0x6f, 0x2f, 0xde, 0x37, 0x42, + 0x2f, 0xb4, 0x4e, 0x50, 0xcb, 0x54, 0x55, 0xf6, 0xd1, 0xe0, 0xfa, 0x2a, 0x4b, 0x83, 0xda, 0x66, + 0xbf, 0x7d, 0x7c, 0x8d, 0xc4, 0xd2, 0xa5, 0xa7, 0xa8, 0x9f, 0x92, 0xd3, 0x30, 0x07, 0x7b, 0x68, + 0xac, 0x60, 0x4e, 0xe8, 0x09, 0x28, 0x69, 0xce, 0x4d, 0x33, 0xd8, 0x4a, 0xc9, 0xe9, 0xcc, 0xe2, + 0x87, 0x1a, 0x9e, 0x59, 0x74, 0x3c, 0x47, 0x0f, 0x0e, 0x48, 0x16, 0xc9, 0x98, 0x9c, 0xc0, 0x0b, + 0x50, 0x24, 0x22, 0x8a, 0xe0, 0x27, 0x68, 0xab, 0xbe, 0x81, 0xc3, 0x63, 0x80, 0x30, 0xe7, 0x3c, + 0x09, 0x49, 0x14, 0x89, 0xea, 0xdc, 0x3c, 0xac, 0xd1, 0xe7, 0x00, 0x33, 0xce, 0x93, 0xdd, 0x28, + 0x12, 0xd8, 0x45, 0xed, 0x12, 0x84, 0x5c, 0x9d, 0xa0, 0x7a, 0x39, 0xfe, 0x0c, 0x75, 0x4d, 0xcd, + 0x5d, 0x7a, 0x22, 0xf1, 0x63, 0xd4, 0xd5, 0x4a, 0x20, 0x25, 0x48, 0xd7, 0x19, 0x35, 0x27, 0xdd, + 0x60, 0x15, 0x18, 0x2b, 0xd4, 0xbf, 0xe9, 0x0a, 0x95, 0xf8, 0x27, 0xd4, 0xae, 0x46, 0x34, 0x89, + 0xbd, 0xe9, 0xd7, 0xde, 0x2d, 0x1e, 0x10, 0xef, 0x26, 0xc1, 0xa0, 0x56, 0x1b, 0x8b, 0xd5, 0xc5, + 0xbd, 0x76, 0x63, 0x48, 0xfc, 0xe3, 0x7a, 0xd1, 0xaf, 0xee, 0x54, 0x74, 0x4d, 0x6f, 0x59, 0x73, + 0xef, 0xe8, 0xed, 0xf9, 0xc0, 0x79, 0x77, 0x3e, 0x70, 0xfe, 0x3e, 0x1f, 0x38, 0xaf, 0x2e, 0x06, + 0x8d, 0x77, 0x17, 0x83, 0xc6, 0x1f, 0x17, 0x83, 0xc6, 0xcf, 0xcf, 0x16, 0x4c, 0xc5, 0xc5, 0xdc, + 0xa3, 0x3c, 0xf5, 0x29, 0x97, 0x29, 0x97, 0xfe, 0xaa, 0xe2, 0x17, 0xcb, 0xb7, 0xf5, 0xf4, 0xea, + 0xeb, 0xaa, 0xce, 0x72, 0x90, 0xf3, 0x4d, 0xb3, 0x0d, 0x9f, 0xfc, 0x1b, 0x00, 0x00, 0xff, 0xff, + 0xf3, 0xd5, 0x5b, 0x4e, 0x8e, 0x07, 0x00, 0x00, } func (m *ConsumerAdditionProposal) Marshal() (dAtA []byte, err error) { @@ -664,29 +698,49 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - n4, err4 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.VscTimeoutPeriod, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.VscTimeoutPeriod):]) + if m.MaxPendingSlashPackets != 0 { + i = encodeVarintProvider(dAtA, i, uint64(m.MaxPendingSlashPackets)) + i-- + dAtA[i] = 0x40 + } + if len(m.SlashMeterReplenishFraction) > 0 { + i -= len(m.SlashMeterReplenishFraction) + copy(dAtA[i:], m.SlashMeterReplenishFraction) + i = encodeVarintProvider(dAtA, i, uint64(len(m.SlashMeterReplenishFraction))) + i-- + dAtA[i] = 0x3a + } + n4, err4 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.SlashMeterReplenishPeriod, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.SlashMeterReplenishPeriod):]) if err4 != nil { return 0, err4 } i -= n4 i = encodeVarintProvider(dAtA, i, uint64(n4)) i-- - dAtA[i] = 0x2a - n5, err5 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.InitTimeoutPeriod, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.InitTimeoutPeriod):]) + dAtA[i] = 0x32 + n5, err5 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.VscTimeoutPeriod, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.VscTimeoutPeriod):]) if err5 != nil { return 0, err5 } i -= n5 i = encodeVarintProvider(dAtA, i, uint64(n5)) i-- - dAtA[i] = 0x22 - n6, err6 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.CcvTimeoutPeriod, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.CcvTimeoutPeriod):]) + dAtA[i] = 0x2a + n6, err6 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.InitTimeoutPeriod, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.InitTimeoutPeriod):]) if err6 != nil { return 0, err6 } i -= n6 i = encodeVarintProvider(dAtA, i, uint64(n6)) i-- + dAtA[i] = 0x22 + n7, err7 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.CcvTimeoutPeriod, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.CcvTimeoutPeriod):]) + if err7 != nil { + return 0, err7 + } + i -= n7 + i = encodeVarintProvider(dAtA, i, uint64(n7)) + i-- dAtA[i] = 0x1a if m.TrustingPeriodFraction != 0 { i = encodeVarintProvider(dAtA, i, uint64(m.TrustingPeriodFraction)) @@ -940,6 +994,15 @@ func (m *Params) Size() (n int) { n += 1 + l + sovProvider(uint64(l)) l = github_com_gogo_protobuf_types.SizeOfStdDuration(m.VscTimeoutPeriod) n += 1 + l + sovProvider(uint64(l)) + l = github_com_gogo_protobuf_types.SizeOfStdDuration(m.SlashMeterReplenishPeriod) + n += 1 + l + sovProvider(uint64(l)) + l = len(m.SlashMeterReplenishFraction) + if l > 0 { + n += 1 + l + sovProvider(uint64(l)) + } + if m.MaxPendingSlashPackets != 0 { + n += 1 + sovProvider(uint64(m.MaxPendingSlashPackets)) + } return n } @@ -1673,6 +1736,90 @@ func (m *Params) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SlashMeterReplenishPeriod", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProvider + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthProvider + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthProvider + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_gogo_protobuf_types.StdDurationUnmarshal(&m.SlashMeterReplenishPeriod, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SlashMeterReplenishFraction", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProvider + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthProvider + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProvider + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SlashMeterReplenishFraction = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 8: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxPendingSlashPackets", wireType) + } + m.MaxPendingSlashPackets = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProvider + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MaxPendingSlashPackets |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipProvider(dAtA[iNdEx:]) diff --git a/x/ccv/types/shared_params.go b/x/ccv/types/shared_params.go index 15e2dd1acb..5d100eab7c 100644 --- a/x/ccv/types/shared_params.go +++ b/x/ccv/types/shared_params.go @@ -75,3 +75,21 @@ func ValidateBech32(i interface{}) error { _, err := sdktypes.AccAddressFromBech32(value) return err } + +func ValidateStringFraction(i interface{}) error { + str, ok := i.(string) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + dec, err := sdktypes.NewDecFromStr(str) + if err != nil { + return err + } + if dec.IsNegative() { + return fmt.Errorf("consumer redistribution fraction is negative") + } + if dec.Sub(sdktypes.NewDec(1)).IsPositive() { + return fmt.Errorf("consumer redistribution fraction cannot be above 1.0") + } + return nil +}