From 0a0d95fc5644fcd136a4cf414642a765d2b2284f Mon Sep 17 00:00:00 2001 From: Philip Offtermatt Date: Tue, 23 Jul 2024 14:22:35 +0200 Subject: [PATCH] Add some docstrings and adjust formatting --- scripts/test_doc/extract_docstrings.go | 10 ++- scripts/test_doc/test_documentation.md | 37 ++++++----- tests/integration/changeover.go | 2 +- tests/integration/democracy.go | 24 ++++++- tests/integration/distribution.go | 14 ++++- tests/integration/key_assignment.go | 83 ++++++++++++++++++++++++- tests/integration/misbehaviour.go | 32 ++++++++-- tests/integration/provider_gov_hooks.go | 11 +++- tests/integration/slashing.go | 5 ++ tests/integration/throttle.go | 6 ++ testutil/keeper/unit_test_helpers.go | 2 +- 11 files changed, 197 insertions(+), 29 deletions(-) diff --git a/scripts/test_doc/extract_docstrings.go b/scripts/test_doc/extract_docstrings.go index c3c0c9db33..98287277de 100644 --- a/scripts/test_doc/extract_docstrings.go +++ b/scripts/test_doc/extract_docstrings.go @@ -101,13 +101,17 @@ func extractDocstrings(filePath string, out *os.File) []string { } // Format the description + + // avoid breaking the table format: newlines need to be replaced + // for the short description, use spaces + shortDescription = strings.ReplaceAll(shortDescription, "\n", " ") + // for the long description, use breaks + longDescription = strings.ReplaceAll(longDescription, "\n", "
") + description := shortDescription if longDescription != "" { description += fmt.Sprintf("
Details%s
", longDescription) } - // for formatting the description in markdown table, - // replace newlines with spaces - description = strings.ReplaceAll(description, "\n", " ") fmt.Fprintf(out, "| %s | %s | %s |\n", link, fn.Name.Name, description) } else { diff --git a/scripts/test_doc/test_documentation.md b/scripts/test_doc/test_documentation.md index d5030522bd..34856ad01e 100644 --- a/scripts/test_doc/test_documentation.md +++ b/scripts/test_doc/test_documentation.md @@ -2,31 +2,40 @@ | File | Function | Short Description | |------|----------|-------------------| -| [changeover.go](../../tests/integration/changeover.go#L17) | TestRecycleTransferChannel | TestRecycleTransferChannel tests that an existing transfer channel can be reused when transitioning from a standalone to a consumer chain.
DetailsThe test case: * sets up a provider chain and a standalone chain * creates a connection between the two chains * creates a transfer channel between the two chains * transitions the standalone chain to a consumer chain * confirms that no extra transfer channel is created, and instead the existing channel is reused
| +| [changeover.go](../../tests/integration/changeover.go#L17) | TestRecycleTransferChannel | TestRecycleTransferChannel tests that an existing transfer channel can be reused when transitioning from a standalone to a consumer chain.
DetailsThe test case:
* sets up a provider chain and a standalone chain
* creates a connection between the two chains
* creates a transfer channel between the two chains
* transitions the standalone chain to a consumer chain
* confirms that no extra transfer channel is created, thus only one transfer channel and one CCV channel exist.
| | [channel_init.go](../../tests/integration/channel_init.go#L4) | TestInitTimeout | TestInitTimeout tests the init timeout | +| [democracy.go](../../tests/integration/democracy.go#L79) | TestDemocracyRewardsDistribution | TestDemocracyRewardsDistribution checks that rewards to democracy representatives, community pool, and provider redistribution account are done correctly.
Details* Sets up a democracy consumer chain
* Creates a new block
* Checks that rewards to democracy representatives, community pool, and provider redistribution account are distributed in the right proportions
| +| [democracy.go](../../tests/integration/democracy.go#L195) | TestDemocracyGovernanceWhitelisting | TestDemocracyGovernanceWhitelisting checks that only whitelisted governance proposals can be executed on democracy consumer chains.
DetailsFor context, see the whitelist for proposals in app/consumer-democracy/proposals_whitelisting.go.
* Sets up a democracy consumer chain
* Submits a proposal containing changes to the auth and mint module parameters
* Checks that the proposal is not executed, since the change to the auth module is not whitelisted.
* Submits a proposal containing changes *only* to the mint module parameters
* Checks that the proposal is executed, since the change to the mint module is whitelisted.
* Submits a proposal containing changes *only* to the auth module parameters
* Checks that again, the proposal is not executed, since the change to the auth module is not whitelisted.
| +| [democracy.go](../../tests/integration/democracy.go#L295) | TestDemocracyMsgUpdateParams | TestDemocracyMsgUpdateParams checks that the consumer parameters can be updated through a governance proposal.
Details* Sets up a democracy consumer chain
* Submits a proposal containing changes to the consumer module parameters
* Checks that the proposal is executed, and the parameters are updated
| | [distribution.go](../../tests/integration/distribution.go#L24) | TestRewardsDistribution | This test is valid for minimal viable consumer chain | -| [distribution.go](../../tests/integration/distribution.go#L187) | TestSendRewardsRetries | TestSendRewardsRetries tests that failed reward transmissions are retried every BlocksPerDistributionTransmission blocks | -| [distribution.go](../../tests/integration/distribution.go#L263) | TestEndBlockRD | TestEndBlockRD tests that the last transmission block height (LTBH) is correctly updated after the expected number of block have passed. It also checks that the IBC transfer transfer states are discarded if the reward distribution to the provider has failed. Note: this method is effectively a unit test for EndBLockRD(), but is written as an integration test to avoid excessive mocking. | -| [distribution.go](../../tests/integration/distribution.go#L383) | TestSendRewardsToProvider | TestSendRewardsToProvider is effectively a unit test for SendRewardsToProvider(), but is written as an integration test to avoid excessive mocking. | -| [distribution.go](../../tests/integration/distribution.go#L525) | TestIBCTransferMiddleware | TestIBCTransferMiddleware tests the logic of the IBC transfer OnRecvPacket callback | -| [distribution.go](../../tests/integration/distribution.go#L707) | TestAllocateTokens | TestAllocateTokens is a happy-path test of the consumer rewards pool allocation to opted-in validators and the community pool | -| [distribution.go](../../tests/integration/distribution.go#L971) | TestAllocateTokensToConsumerValidatorsWithDifferentValidatorHeights | TestAllocateTokensToConsumerValidatorsWithDifferentValidatorHeights tests `AllocateTokensToConsumerValidators` with consumer validators that have different heights. Specifically, test that validators that have been consumer validators for some time receive rewards, while validators that recently became consumer validators do not receive rewards. | -| [distribution.go](../../tests/integration/distribution.go#L1079) | TestMultiConsumerRewardsDistribution | TestMultiConsumerRewardsDistribution tests the rewards distribution of multiple consumers chains | +| [distribution.go](../../tests/integration/distribution.go#L186) | TestSendRewardsRetries | TestSendRewardsRetries tests that failed reward transmissions are retried every BlocksPerDistributionTransmission blocks | +| [distribution.go](../../tests/integration/distribution.go#L262) | TestEndBlockRD | TestEndBlockRD tests that the last transmission block height (LTBH) is correctly updated after the expected number of block have passed. It also checks that the IBC transfer transfer states are discarded if the reward distribution to the provider has failed. Note: this method is effectively a unit test for EndBLockRD(), but is written as an integration test to avoid excessive mocking. | +| [distribution.go](../../tests/integration/distribution.go#L382) | TestSendRewardsToProvider | TestSendRewardsToProvider is effectively a unit test for SendRewardsToProvider(), but is written as an integration test to avoid excessive mocking. | +| [distribution.go](../../tests/integration/distribution.go#L524) | TestIBCTransferMiddleware | TestIBCTransferMiddleware tests the logic of the IBC transfer OnRecvPacket callback | +| [distribution.go](../../tests/integration/distribution.go#L706) | TestAllocateTokens | TestAllocateTokens is a happy-path test of the consumer rewards pool allocation to opted-in validators and the community pool | +| [distribution.go](../../tests/integration/distribution.go#L846) | TestAllocateTokensToConsumerValidators | TestAllocateTokensToConsumerValidators tests the allocation of tokens to consumer validators.
DetailsThe test exclusively uses the provider chain.
It sets up a current set of consumer validators, then calls the AllocateTokensToConsumerValidators
function to allocate a number of tokens to the validators.
The test then checks that the expected number of tokens were allocated to the validators.
The test covers the following scenarios:
- The tokens to be allocated are empty
- The consumer validator set is empty
- The tokens are allocated to a single validator
- The tokens are allocated to multiple validators
| +| [distribution.go](../../tests/integration/distribution.go#L981) | TestAllocateTokensToConsumerValidatorsWithDifferentValidatorHeights | TestAllocateTokensToConsumerValidatorsWithDifferentValidatorHeights tests `AllocateTokensToConsumerValidators` with consumer validators that have different heights. Specifically, test that validators that have been consumer validators for some time receive rewards, while validators that recently became consumer validators do not receive rewards. | +| [distribution.go](../../tests/integration/distribution.go#L1089) | TestMultiConsumerRewardsDistribution | TestMultiConsumerRewardsDistribution tests the rewards distribution of multiple consumers chains | | [double_vote.go](../../tests/integration/double_vote.go#L17) | TestHandleConsumerDoubleVoting | TestHandleConsumerDoubleVoting verifies that handling a double voting evidence of a consumer chain results in the expected tombstoning, jailing, and slashing of the misbehaved validator | | [double_vote.go](../../tests/integration/double_vote.go#L271) | TestHandleConsumerDoubleVotingSlashesUndelegationsAndRelegations | TestHandleConsumerDoubleVotingSlashesUndelegationsAndRelegations verifies that handling a successful double voting evidence of a consumer chain results in the expected slashing of the misbehave validator undelegations | | [expired_client.go](../../tests/integration/expired_client.go#L23) | TestVSCPacketSendExpiredClient | TestVSCPacketSendWithExpiredClient tests queueing of VSCPackets when the consumer client is expired. While the consumer client is expired (or inactive for some reason) all packets will be queued and and cleared once the consumer client is established. | | [expired_client.go](../../tests/integration/expired_client.go#L87) | TestConsumerPacketSendExpiredClient | TestConsumerPacketSendExpiredClient tests the consumer sending packets when the provider client is expired. While the provider client is expired all packets will be queued and and cleared once the provider client is upgraded. | +| [key_assignment.go](../../tests/integration/key_assignment.go#L33) | TestKeyAssignment | TestKeyAssignment tests key assignments relayed from the provider chain to the consumer chain at different times in the protocol lifecycle.
DetailsEach test scenarios sets up a provider chain and then assigns a key for a validator.
However, the assignment comes at different times in the protocol lifecycle.
The test covers the following scenarios:
* successfully assign the key before the CCV channel initialization is complete, then check that a VSCPacket is indeed queud
* successfully assign the key after the CCV channel initialization is complete
* successfully assign the key during an same epoch where the validator power changes
* get an error when assigning the same key twice in the same block by different validators
* get an error when assigning the same key twice in the same block by the same validator
* successfully assign two different keys in the same block by one validator
* get an error when assigning the same key twice in different blocks by different validators
* get an error when assigning the same key twice in different blocks by the same validator
For each scenario where the key assignment does not produce an error,
the test also checks that VSCPackets are relayed to the consumer chain and that the clients on
the provider and consumer chain can be updated.
| | [misbehaviour.go](../../tests/integration/misbehaviour.go#L19) | TestHandleConsumerMisbehaviour | TestHandleConsumerMisbehaviour tests that handling a valid misbehaviour, with conflicting headers forming an equivocation, results in the jailing of the validators | +| [misbehaviour.go](../../tests/integration/misbehaviour.go#L97) | TestGetByzantineValidators | TestGetByzantineValidators checks the GetByzantineValidators function on various instances of misbehaviour.
DetailsThe test sets up a provider and consumer chain.
It creates a header with a subset of the validators on the consumer chain,
then creates a second header (in a variety of different ways),
and checks which validators are considered Byzantine
by calling the GetByzantineValidators function.
The test scenarios are:
* when one of the headers is empty, the function should return an error
* when one of the headers has a corrupted validator set (e.g. by a validator having a different public key), the function should return an error
* when the signatures in one of the headers are corrupted, the function should return an error
* when the attack is an amnesia attack (i.e. the headers have different block IDs), no validator is considered byzantine
* for non-amnesia misbehaviour, all validators that signed both headers are considered byzantine
| +| [misbehaviour.go](../../tests/integration/misbehaviour.go#L394) | TestCheckMisbehaviour | TestCheckMisbehaviour tests that the CheckMisbehaviour function correctly checks for misbehaviour.
DetailsThe test sets up a provider and consumer chain.
It creates a valid client header and then creates a misbehaviour by creating a second header in a variety of different ways.
It then checks that the CheckMisbehaviour function correctly checks for misbehaviour by verifying that
it returns an error when the misbehaviour is invalid and no error when the misbehaviour is valid.
The test scenarios are:
* both headers are identical (returns an error)
* the misbehaviour is not for the consumer chain (returns an error)
* passing an invalid client id (returns an error)
* passing a misbehaviour with different header height (returns an error)
* passing a misbehaviour older than the min equivocation evidence height (returns an error)
* one header of the misbehaviour has insufficient voting power (returns an error)
* passing a valid misbehaviour (no error)
It does not test actually submitting the misbehaviour to the chain or or freezing the client.
| | [normal_operations.go](../../tests/integration/normal_operations.go#L13) | TestHistoricalInfo | Tests the tracking of historical info in the context of new blocks being committed | | [provider_gov_hooks.go](../../tests/integration/provider_gov_hooks.go#L18) | TestAfterPropSubmissionAndVotingPeriodEnded | tests AfterProposalSubmission and AfterProposalVotingPeriodEnded hooks hooks require adding a proposal in the gov module and registering a consumer chain with the provider module | +| [provider_gov_hooks.go](../../tests/integration/provider_gov_hooks.go#L60) | TestGetConsumerAdditionLegacyPropFromProp | TestGetConsumerAdditionLegacyPropFromProp manually calls the GetConsumerAdditionLegacyPropFromProp hook on various types of proposals to test the behavior of the hook.
DetailsThe tes case created a provider chain,
then submits a Proposal with various different types of content.
Then, it tries to get the ConsumerAdditionProposal from the proposal using the hook.
Test cases include a proposal with no messages; a proposal with a transfer message; a proposal with an unrelated legacy proposal;
a proposal with an invalid legacy proposal; and a proposal with a ConsumerAdditionProposal.
In the case of a valid ConsumerAdditionProposal, the test verifies that the proposal is found and returned by the hook.
| | [slashing.go](../../tests/integration/slashing.go#L39) | TestRelayAndApplyDowntimePacket | TestRelayAndApplyDowntimePacket tests that downtime slash packets can be properly relayed from consumer to provider, handled by provider, with a VSC and jailing 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. | | [slashing.go](../../tests/integration/slashing.go#L177) | TestRelayAndApplyDoubleSignPacket | Similar setup to TestRelayAndApplyDowntimePacket, but with a double sign slash packet. Note that double-sign slash packets should not affect the provider validator set. | -| [slashing.go](../../tests/integration/slashing.go#L302) | TestHandleSlashPacketDowntime | TestHandleSlashPacketDowntime tests the handling of a downtime related slash packet, with integration tests. Note that only downtime slash packets are processed by HandleSlashPacket. | -| [slashing.go](../../tests/integration/slashing.go#L343) | TestOnRecvSlashPacketErrors | TestOnRecvSlashPacketErrors tests errors for the OnRecvSlashPacket method in an integration testing setting | -| [slashing.go](../../tests/integration/slashing.go#L442) | TestValidatorDowntime | TestValidatorDowntime tests if a slash packet is sent and if the outstanding slashing flag is switched when a validator has downtime on the slashing module | -| [slashing.go](../../tests/integration/slashing.go#L555) | TestValidatorDoubleSigning | TestValidatorDoubleSigning tests if a slash packet is sent when a double-signing evidence is handled by the evidence module | -| [slashing.go](../../tests/integration/slashing.go#L642) | TestQueueAndSendSlashPacket | TestQueueAndSendSlashPacket tests the integration of QueueSlashPacket with SendPackets. In normal operation slash packets are queued in BeginBlock and sent in EndBlock. | -| [slashing.go](../../tests/integration/slashing.go#L722) | TestCISBeforeCCVEstablished | TestCISBeforeCCVEstablished tests that the consumer chain doesn't panic or have any undesired behavior when a slash packet is queued before the CCV channel is established. Then once the CCV channel is established, the slash packet should be sent soon after. | +| [slashing.go](../../tests/integration/slashing.go#L263) | TestSlashPacketAcknowledgement | TestSlashPacketAcknowledgement tests the handling of a slash packet acknowledgement.
DetailsIt sets up a provider and consumer chain, with channel initialization between them performed,
then sends a slash packet with randomized fields from the consumer to the provider.
The provider processes the packet
| +| [slashing.go](../../tests/integration/slashing.go#L307) | TestHandleSlashPacketDowntime | TestHandleSlashPacketDowntime tests the handling of a downtime related slash packet, with integration tests. Note that only downtime slash packets are processed by HandleSlashPacket. | +| [slashing.go](../../tests/integration/slashing.go#L348) | TestOnRecvSlashPacketErrors | TestOnRecvSlashPacketErrors tests errors for the OnRecvSlashPacket method in an integration testing setting | +| [slashing.go](../../tests/integration/slashing.go#L447) | TestValidatorDowntime | TestValidatorDowntime tests if a slash packet is sent and if the outstanding slashing flag is switched when a validator has downtime on the slashing module | +| [slashing.go](../../tests/integration/slashing.go#L560) | TestValidatorDoubleSigning | TestValidatorDoubleSigning tests if a slash packet is sent when a double-signing evidence is handled by the evidence module | +| [slashing.go](../../tests/integration/slashing.go#L647) | TestQueueAndSendSlashPacket | TestQueueAndSendSlashPacket tests the integration of QueueSlashPacket with SendPackets. In normal operation slash packets are queued in BeginBlock and sent in EndBlock. | +| [slashing.go](../../tests/integration/slashing.go#L727) | TestCISBeforeCCVEstablished | TestCISBeforeCCVEstablished tests that the consumer chain doesn't panic or have any undesired behavior when a slash packet is queued before the CCV channel is established. Then once the CCV channel is established, the slash packet should be sent soon after. | | [stop_consumer.go](../../tests/integration/stop_consumer.go#L14) | TestStopConsumerChain | Tests the functionality of stopping a consumer chain at a higher level than unit tests | | [stop_consumer.go](../../tests/integration/stop_consumer.go#L99) | TestStopConsumerOnChannelClosed | TODO Simon: implement OnChanCloseConfirm in IBC-GO testing to close the consumer chain's channel end | | [throttle.go](../../tests/integration/throttle.go#L24) | TestBasicSlashPacketThrottling | TestBasicSlashPacketThrottling tests slash packet throttling with a single consumer, two slash packets, and no VSC matured packets. The most basic scenario. | diff --git a/tests/integration/changeover.go b/tests/integration/changeover.go index b8bd1801db..b18ea38f4b 100644 --- a/tests/integration/changeover.go +++ b/tests/integration/changeover.go @@ -13,7 +13,7 @@ import ( // * creates a connection between the two chains // * creates a transfer channel between the two chains // * transitions the standalone chain to a consumer chain -// * confirms that no extra transfer channel is created, and instead the existing channel is reused +// * confirms that no extra transfer channel is created, thus only one transfer channel and one CCV channel exist. func (suite *CCVTestSuite) TestRecycleTransferChannel() { consumerKeeper := suite.consumerApp.GetConsumerKeeper() diff --git a/tests/integration/democracy.go b/tests/integration/democracy.go index 5fe7e9eb6d..baea36857b 100644 --- a/tests/integration/democracy.go +++ b/tests/integration/democracy.go @@ -71,6 +71,11 @@ func (suite *ConsumerDemocracyTestSuite) SetupTest() { suite.consumerApp = suite.setupCallback(&suite.Suite) } +// TestDemocracyRewardsDistribution checks that rewards to democracy representatives, community pool, and provider redistribution account are done correctly. +// @Long Description@ +// * Sets up a democracy consumer chain +// * Creates a new block +// * Checks that rewards to democracy representatives, community pool, and provider redistribution account are distributed in the right proportions func (s *ConsumerDemocracyTestSuite) TestDemocracyRewardsDistribution() { s.consumerChain.NextBlock() stakingKeeper := s.consumerApp.GetTestStakingKeeper() @@ -154,7 +159,7 @@ func (s *ConsumerDemocracyTestSuite) TestDemocracyRewardsDistribution() { totalFees := nextConsumerRedistributeBalance.Add(providerDifference) s.Require().Equal(totalFees.Mul(consumerRedistributionFraction), nextConsumerRedistributeBalance) - // confirm begin blocker changes: democracy module distributes the fees from c onsumer redistribute address to representatives + // confirm begin blocker changes: democracy module distributes the fees from consumer redistribute address to representatives // and community fee pool // distribution module got tokens from previous consumer redistribute balance s.Require().Equal(distrModuleDifference, previousConsumerRedistributeBalance) @@ -176,6 +181,17 @@ func (s *ConsumerDemocracyTestSuite) TestDemocracyRewardsDistribution() { } } +// TestDemocracyGovernanceWhitelisting checks that only whitelisted governance proposals +// can be executed on democracy consumer chains. +// @Long Description@ +// For context, see the whitelist for proposals in app/consumer-democracy/proposals_whitelisting.go. +// * Sets up a democracy consumer chain +// * Submits a proposal containing changes to the auth and mint module parameters +// * Checks that the proposal is not executed, since the change to the auth module is not whitelisted. +// * Submits a proposal containing changes *only* to the mint module parameters +// * Checks that the proposal is executed, since the change to the mint module is whitelisted. +// * Submits a proposal containing changes *only* to the auth module parameters +// * Checks that again, the proposal is not executed, since the change to the auth module is not whitelisted. func (s *ConsumerDemocracyTestSuite) TestDemocracyGovernanceWhitelisting() { govKeeper := s.consumerApp.GetTestGovKeeper() params, err := govKeeper.Params.Get(s.consumerCtx()) @@ -271,6 +287,11 @@ func (s *ConsumerDemocracyTestSuite) TestDemocracyGovernanceWhitelisting() { s.Assert().Equal(votersOldBalances, getAccountsBalances(s.consumerCtx(), bankKeeper, bondDenom, votingAccounts)) } +// TestDemocracyMsgUpdateParams checks that the consumer parameters can be updated through a governance proposal. +// @Long Description@ +// * Sets up a democracy consumer chain +// * Submits a proposal containing changes to the consumer module parameters +// * Checks that the proposal is executed, and the parameters are updated func (s *ConsumerDemocracyTestSuite) TestDemocracyMsgUpdateParams() { govKeeper := s.consumerApp.GetTestGovKeeper() params, err := govKeeper.Params.Get(s.consumerCtx()) @@ -316,7 +337,6 @@ func (s *ConsumerDemocracyTestSuite) TestDemocracyMsgUpdateParams() { // deposit is refunded s.Assert().Equal(votersOldBalances, getAccountsBalances(s.consumerCtx(), bankKeeper, bondDenom, votingAccounts)) - } func submitProposalWithDepositAndVote(govKeeper govkeeper.Keeper, ctx sdk.Context, msgs []sdk.Msg, diff --git a/tests/integration/distribution.go b/tests/integration/distribution.go index 2e5f2f0bbb..157a8cb205 100644 --- a/tests/integration/distribution.go +++ b/tests/integration/distribution.go @@ -138,8 +138,7 @@ func (s *CCVTestSuite) TestRewardsDistribution() { consuValsRewards := consumerValsOutstandingRewardsFunc(s.providerCtx()) // increase the block height so validators are eligible for consumer rewards (see `IsEligibleForConsumerRewards`) - numberOfBlocksToStartReceivingRewards := - providerKeeper.GetNumberOfEpochsToStartReceivingRewards(s.providerCtx()) * providerKeeper.GetBlocksPerEpoch(s.providerCtx()) + numberOfBlocksToStartReceivingRewards := providerKeeper.GetNumberOfEpochsToStartReceivingRewards(s.providerCtx()) * providerKeeper.GetBlocksPerEpoch(s.providerCtx()) for s.providerCtx().BlockHeight() <= numberOfBlocksToStartReceivingRewards { s.providerChain.NextBlock() @@ -833,6 +832,17 @@ func (s *CCVTestSuite) prepareRewardDist() { s.coordinator.CommitNBlocks(s.consumerChain, uint64(blocksToGo)) } +// TestAllocateTokensToConsumerValidators tests the allocation of tokens to consumer validators. +// @Long Description@ +// The test exclusively uses the provider chain. +// It sets up a current set of consumer validators, then calls the AllocateTokensToConsumerValidators +// function to allocate a number of tokens to the validators. +// The test then checks that the expected number of tokens were allocated to the validators. +// The test covers the following scenarios: +// - The tokens to be allocated are empty +// - The consumer validator set is empty +// - The tokens are allocated to a single validator +// - The tokens are allocated to multiple validators func (s *CCVTestSuite) TestAllocateTokensToConsumerValidators() { providerKeeper := s.providerApp.GetProviderKeeper() distributionKeeper := s.providerApp.GetTestDistributionKeeper() diff --git a/tests/integration/key_assignment.go b/tests/integration/key_assignment.go index c6478d98ba..9b31c9f9a5 100644 --- a/tests/integration/key_assignment.go +++ b/tests/integration/key_assignment.go @@ -10,9 +10,26 @@ import ( tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" providerkeeper "github.com/cosmos/interchain-security/v5/x/ccv/provider/keeper" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" ccv "github.com/cosmos/interchain-security/v5/x/ccv/types" ) +// TestKeyAssignment tests key assignments relayed from the provider chain to the consumer chain at different times in the protocol lifecycle. +// @Long Description@ +// Each test scenarios sets up a provider chain and then assigns a key for a validator. +// However, the assignment comes at different times in the protocol lifecycle. +// The test covers the following scenarios: +// * successfully assign the key before the CCV channel initialization is complete, then check that a VSCPacket is indeed queud +// * successfully assign the key after the CCV channel initialization is complete +// * successfully assign the key during an same epoch where the validator power changes +// * get an error when assigning the same key twice in the same block by different validators +// * get an error when assigning the same key twice in the same block by the same validator +// * successfully assign two different keys in the same block by one validator +// * get an error when assigning the same key twice in different blocks by different validators +// * get an error when assigning the same key twice in different blocks by the same validator +// For each scenario where the key assignment does not produce an error, +// the test also checks that VSCPackets are relayed to the consumer chain and that the clients on +// the provider and consumer chain can be updated. func (s *CCVTestSuite) TestKeyAssignment() { testCases := []struct { name string @@ -29,6 +46,9 @@ func (s *CCVTestSuite) TestKeyAssignment() { return err } + // check that the key was assigned correctly + s.CheckKeyAssignment(validator, consumerKey) + // check that a VSCPacket is queued s.nextEpoch() pendingPackets := pk.GetPendingVSCPackets(s.providerCtx(), s.consumerChain.ChainID) @@ -51,6 +71,10 @@ func (s *CCVTestSuite) TestKeyAssignment() { if err != nil { return err } + + // check that the key was assigned correctly + s.CheckKeyAssignment(validator, consumerKey) + s.nextEpoch() return nil @@ -73,6 +97,9 @@ func (s *CCVTestSuite) TestKeyAssignment() { delAddr := s.providerChain.SenderAccount.GetAddress() delegate(s, delAddr, bondAmt) + // check that the key was assigned correctly + s.CheckKeyAssignment(validator, consumerKey) + s.nextEpoch() return nil @@ -90,12 +117,25 @@ func (s *CCVTestSuite) TestKeyAssignment() { return err } + // check that the key was assigned correctly + s.CheckKeyAssignment(validator, consumerKey) + // same key assignment, but different validator validator2, _ := generateNewConsumerKey(s, 1) err = pk.AssignConsumerKey(s.providerCtx(), s.consumerChain.ChainID, validator2, consumerKey) + + // check that the key was not assigned to the second validator + valConsAddr2, getConsAddrErr := validator2.GetConsAddr() // make sure we don't override err, which we are saving for below + s.Require().NoError(getConsAddrErr) + actualConsumerKey2, found := pk.GetValidatorConsumerPubKey(s.providerCtx(), s.consumerChain.ChainID, types.NewProviderConsAddress(valConsAddr2)) + s.Require().True(found) + // the key for the second validator should *not* be the one we just assigned to the first validator + s.Require().NotEqual(consumerKey, actualConsumerKey2) + if err != nil { return err } + s.nextEpoch() return nil @@ -113,7 +153,10 @@ func (s *CCVTestSuite) TestKeyAssignment() { return err } - // same key assignment, but different validator + // check that the key was assigned correctly + s.CheckKeyAssignment(validator, consumerKey) + + // same key assignment, same validator err = pk.AssignConsumerKey(s.providerCtx(), s.consumerChain.ChainID, validator, consumerKey) if err != nil { return err @@ -135,12 +178,19 @@ func (s *CCVTestSuite) TestKeyAssignment() { return err } + // check that the key was assigned correctly + s.CheckKeyAssignment(validator, consumerKey) + // same key assignment validator, consumerKey = generateNewConsumerKey(s, 0) err = pk.AssignConsumerKey(s.providerCtx(), s.consumerChain.ChainID, validator, consumerKey) if err != nil { return err } + + // check that the second key was also assigned correctly + s.CheckKeyAssignment(validator, consumerKey) + s.nextEpoch() return nil @@ -157,6 +207,10 @@ func (s *CCVTestSuite) TestKeyAssignment() { if err != nil { return err } + + // check that the key was assigned correctly + s.CheckKeyAssignment(validator, consumerKey) + s.nextEpoch() // same key assignment @@ -165,6 +219,15 @@ func (s *CCVTestSuite) TestKeyAssignment() { if err != nil { return err } + + // check that the key was not assigned to the second validator + valConsAddr2, getConsAddrErr := validator2.GetConsAddr() // make sure we don't override err, which we are saving for below + s.Require().NoError(getConsAddrErr) + actualConsumerKey2, found := pk.GetValidatorConsumerPubKey(s.providerCtx(), s.consumerChain.ChainID, types.NewProviderConsAddress(valConsAddr2)) + s.Require().True(found) + // the key for the second validator should *not* be the one we just assigned to the first validator + s.Require().NotEqual(consumerKey, actualConsumerKey2) + s.nextEpoch() return nil @@ -181,6 +244,10 @@ func (s *CCVTestSuite) TestKeyAssignment() { if err != nil { return err } + + // check that the key was assigned correctly + s.CheckKeyAssignment(validator, consumerKey) + s.nextEpoch() // same key assignment @@ -204,6 +271,10 @@ func (s *CCVTestSuite) TestKeyAssignment() { if err != nil { return err } + + // check that the key was assigned correctly + s.CheckKeyAssignment(validator, consumerKey) + s.nextEpoch() // same key assignment @@ -212,6 +283,7 @@ func (s *CCVTestSuite) TestKeyAssignment() { if err != nil { return err } + s.nextEpoch() return nil @@ -286,6 +358,15 @@ func (s *CCVTestSuite) TestKeyAssignment() { } } +// CheckKeyAssignmentCorrectly checks if the key was assigned correctly. +func (s *CCVTestSuite) CheckKeyAssignment(validator stakingtypes.Validator, consumerKey tmprotocrypto.PublicKey) { + valConsAddr, err := validator.GetConsAddr() + s.Require().NoError(err) + actualConsumerKey, found := s.providerApp.GetProviderKeeper().GetValidatorConsumerPubKey(s.providerCtx(), s.consumerChain.ChainID, types.NewProviderConsAddress(valConsAddr)) + s.Require().True(found) + s.Require().Equal(consumerKey, actualConsumerKey) +} + // generateNewConsumerKey generate new consumer key for the validator with valIndex func generateNewConsumerKey(s *CCVTestSuite, valIndex int) (stakingtypes.Validator, tmprotocrypto.PublicKey) { // get validator diff --git a/tests/integration/misbehaviour.go b/tests/integration/misbehaviour.go index 5924c90df1..9677a52bc8 100644 --- a/tests/integration/misbehaviour.go +++ b/tests/integration/misbehaviour.go @@ -81,6 +81,19 @@ func (s *CCVTestSuite) TestHandleConsumerMisbehaviour() { } } +// TestGetByzantineValidators checks the GetByzantineValidators function on various instances of misbehaviour. +// @Long Description@ +// The test sets up a provider and consumer chain. +// It creates a header with a subset of the validators on the consumer chain, +// then creates a second header (in a variety of different ways), +// and checks which validators are considered Byzantine +// by calling the GetByzantineValidators function. +// The test scenarios are: +// * when one of the headers is empty, the function should return an error +// * when one of the headers has a corrupted validator set (e.g. by a validator having a different public key), the function should return an error +// * when the signatures in one of the headers are corrupted, the function should return an error +// * when the attack is an amnesia attack (i.e. the headers have different block IDs), no validator is considered byzantine +// * for non-amnesia misbehaviour, all validators that signed both headers are considered byzantine func (s *CCVTestSuite) TestGetByzantineValidators() { s.SetupCCVChannel(s.path) // required to have the consumer client revision height greater than 0 @@ -363,6 +376,21 @@ func (s *CCVTestSuite) TestGetByzantineValidators() { } } +// TestCheckMisbehaviour tests that the CheckMisbehaviour function correctly checks for misbehaviour. +// @Long Description@ +// The test sets up a provider and consumer chain. +// It creates a valid client header and then creates a misbehaviour by creating a second header in a variety of different ways. +// It then checks that the CheckMisbehaviour function correctly checks for misbehaviour by verifying that +// it returns an error when the misbehaviour is invalid and no error when the misbehaviour is valid. +// The test scenarios are: +// * both headers are identical (returns an error) +// * the misbehaviour is not for the consumer chain (returns an error) +// * passing an invalid client id (returns an error) +// * passing a misbehaviour with different header height (returns an error) +// * passing a misbehaviour older than the min equivocation evidence height (returns an error) +// * one header of the misbehaviour has insufficient voting power (returns an error) +// * passing a valid misbehaviour (no error) +// It does not test actually submitting the misbehaviour to the chain or or freezing the client. func (s *CCVTestSuite) TestCheckMisbehaviour() { s.SetupCCVChannel(s.path) // required to have the consumer client revision height greater than 0 @@ -548,10 +576,6 @@ func (s *CCVTestSuite) TestCheckMisbehaviour() { for _, tc := range testCases { s.Run(tc.name, func() { err := s.providerApp.GetProviderKeeper().CheckMisbehaviour(s.providerCtx(), *tc.misbehaviour) - cs, ok := s.providerApp.GetIBCKeeper().ClientKeeper.GetClientState(s.providerCtx(), s.path.EndpointA.ClientID) - s.Require().True(ok) - // verify that the client wasn't frozen - s.Require().Zero(cs.(*ibctmtypes.ClientState).FrozenHeight) if tc.expPass { s.NoError(err) } else { diff --git a/tests/integration/provider_gov_hooks.go b/tests/integration/provider_gov_hooks.go index e3f9cc8ace..8f5ba95de7 100644 --- a/tests/integration/provider_gov_hooks.go +++ b/tests/integration/provider_gov_hooks.go @@ -48,6 +48,15 @@ func (s *CCVTestSuite) TestAfterPropSubmissionAndVotingPeriodEnded() { s.Require().Empty(providerKeeper.GetProposedConsumerChain(ctx, proposal.Id)) } +// TestGetConsumerAdditionLegacyPropFromProp manually calls the GetConsumerAdditionLegacyPropFromProp hook on +// various types of proposals to test the behavior of the hook. +// @Long Description@ +// The tes case created a provider chain, +// then submits a Proposal with various different types of content. +// Then, it tries to get the ConsumerAdditionProposal from the proposal using the hook. +// Test cases include a proposal with no messages; a proposal with a transfer message; a proposal with an unrelated legacy proposal; +// a proposal with an invalid legacy proposal; and a proposal with a ConsumerAdditionProposal. +// In the case of a valid ConsumerAdditionProposal, the test verifies that the proposal is found and returned by the hook. func (s *CCVTestSuite) TestGetConsumerAdditionLegacyPropFromProp() { ctx := s.providerChain.GetContext() proposer := s.providerChain.SenderAccount @@ -121,7 +130,7 @@ func (s *CCVTestSuite) TestGetConsumerAdditionLegacyPropFromProp() { proposal, err = v1.NewProposal([]sdk.Msg{}, 1, time.Now(), time.Now().Add(1*time.Hour), "metadata", "title", "summary", proposer.GetAddress(), false) s.Require().NoError(err) } else { - // cover variolus cases where proposal has messages but only some are consumer addition proposals + // cover various cases where proposal has messages but only some are consumer addition proposals proposal, err = v1.NewProposal([]sdk.Msg{tc.propMsg}, 1, time.Now(), time.Now().Add(1*time.Hour), "metadata", "title", "summary", proposer.GetAddress(), false) s.Require().NoError(err) } diff --git a/tests/integration/slashing.go b/tests/integration/slashing.go index 2e01c99fe7..254a8467a4 100644 --- a/tests/integration/slashing.go +++ b/tests/integration/slashing.go @@ -255,6 +255,11 @@ func (s *CCVTestSuite) TestRelayAndApplyDoubleSignPacket() { s.Require().NoError(err) } +// TestSlashPacketAcknowledgement tests the handling of a slash packet acknowledgement. +// @Long Description@ +// It sets up a provider and consumer chain, with channel initialization between them performed, +// then sends a slash packet with randomized fields from the consumer to the provider. +// The provider processes the packet func (s *CCVTestSuite) TestSlashPacketAcknowledgement() { providerKeeper := s.providerApp.GetProviderKeeper() consumerKeeper := s.consumerApp.GetConsumerKeeper() diff --git a/tests/integration/throttle.go b/tests/integration/throttle.go index f56228c56f..d9bfa1ed28 100644 --- a/tests/integration/throttle.go +++ b/tests/integration/throttle.go @@ -382,6 +382,12 @@ func (s *CCVTestSuite) TestPacketSpam() { } } +// TestDoubleSignDoesNotAffectThrottling tests that a large number of double sign slash packets +// do not affect the throttling mechanism. +// @Long Description@ +// This test sets up a scenario where 3 validators are slashed for double signing, and the 4th is not. +// It then sends 500 double sign slash packets from a consumer to the provider in a single block. +// The test confirms that the slash meter is not affected by this, and that no validators are jailed. func (s *CCVTestSuite) TestDoubleSignDoesNotAffectThrottling() { // Setup ccv channels to all consumers s.SetupAllCCVChannels() diff --git a/testutil/keeper/unit_test_helpers.go b/testutil/keeper/unit_test_helpers.go index 0fd86f3c1c..d139552371 100644 --- a/testutil/keeper/unit_test_helpers.go +++ b/testutil/keeper/unit_test_helpers.go @@ -207,7 +207,7 @@ func GetNewSlashPacketData() types.SlashPacketData { Power: int64(binary.BigEndian.Uint64(b1)), }, ValsetUpdateId: binary.BigEndian.Uint64(b2), - Infraction: stakingtypes.Infraction(binary.BigEndian.Uint64(b2) % 3), + Infraction: stakingtypes.Infraction(binary.BigEndian.Uint64(b3) % 3), } }