Skip to content

Instantly share code, notes, and snippets.

@sainoe
Last active March 2, 2022 14:58
Show Gist options
  • Save sainoe/cf0ebdf6358c0ebb25ab1263c759ee77 to your computer and use it in GitHub Desktop.
Save sainoe/cf0ebdf6358c0ebb25ab1263c759ee77 to your computer and use it in GitHub Desktop.
TestChain validator set update issue
package ibc_testing_test
import (
"bytes"
"testing"
sdk "github.com/cosmos/cosmos-sdk/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
abci "github.com/tendermint/tendermint/abci/types"
ibctesting "github.com/cosmos/ibc-go/v3/testing"
"github.com/stretchr/testify/suite"
)
// KeeperTestSuite is a testing suite to test keeper functions.
type KeeperTestSuite struct {
suite.Suite
coordinator *ibctesting.Coordinator
// testing chains used for convenience and readability
chainA *ibctesting.TestChain
chainB *ibctesting.TestChain
ctx sdk.Context
}
// TestKeeperTestSuite runs all the tests within this package.
func TestKeeperTestSuite(t *testing.T) {
suite.Run(t, new(KeeperTestSuite))
}
// SetupTest creates a coordinator with 2 test chains.
func (s *KeeperTestSuite) SetupTest() {
s.coordinator = ibctesting.NewCoordinator(s.T(), 2) // initializes 2 test chains
s.chainA = s.coordinator.GetChain(ibctesting.GetChainID(1)) // convenience and readability
s.chainB = s.coordinator.GetChain(ibctesting.GetChainID(2)) // convenience and readability
s.ctx = s.chainA.GetContext()
}
func (s *KeeperTestSuite) TestUpdateValset() {
path := ibctesting.NewPath(s.chainA, s.chainB) // clientID, connectionID, channelID empty
s.coordinator.Setup(path) // clientID, connectionID, channelID filled
s.Require().Equal("07-tendermint-0", path.EndpointA.ClientID)
s.Require().Equal("connection-0", path.EndpointA.ConnectionID)
s.Require().Equal("channel-0", path.EndpointA.ChannelID)
chainAStakingKeeper := s.chainA.App.GetStakingKeeper()
// Choose a validator, and get its address and data structure into the correct types
tmValidator := s.chainA.Vals.Validators[0]
valAddr, err := sdk.ValAddressFromHex(tmValidator.Address.String())
s.Require().NoError(err)
// jail validator to zero its power in the validator set
chainAStakingKeeper.Jail(s.ctx, sdk.ConsAddress(tmValidator.Address))
// check that validator was jailed
val, ok := chainAStakingKeeper.GetValidatorByConsAddr(s.ctx, sdk.ConsAddress(valAddr))
s.Require().True(ok)
s.Require().True(val.Jailed)
// check that validator updates are seen by the staking module endblock callback
valUpdates := chainAStakingKeeper.BlockValidatorUpdates(s.ctx)
s.Require().Len(valUpdates, 1)
// check that chain endblock callback returns validator updates
valUpdatesEnblock := s.chainA.App.EndBlock(abci.RequestEndBlock{})
s.T().Log(len(valUpdatesEnblock.ValidatorUpdates) == 1)
// Update the second client chain -
// chainA block is ended and committed
err = path.EndpointB.UpdateClient()
s.Require().NoError(err)
// Check the validator states are updated
vals, ok := s.chainA.GetValsAtHeight(s.chainA.CurrentHeader.Height)
s.Require().True(ok)
s.T().Log(vals.Validators[0].VotingPower == int64(2))
// Check the chain validator hash is updated
s.T().Log(!bytes.Equal(s.chainA.CurrentHeader.GetNextValidatorsHash(), s.chainA.CurrentHeader.GetValidatorsHash()))
// Check the validator set is updated in chain A
s.T().Log(s.chainA.Vals.Validators[0].VotingPower == int64(2))
// Update the second client chain;
err = path.EndpointB.UpdateClient()
s.Require().NoError(err)
}
func (s *KeeperTestSuite) TestUpdateValset2() {
path := ibctesting.NewPath(s.chainA, s.chainB) // clientID, connectionID, channelID empty
s.coordinator.Setup(path) // clientID, connectionID, channelID filled
chainAStakingKeeper := s.chainA.App.GetStakingKeeper()
bondAmt := sdk.NewInt(1000000)
delAddr := s.chainA.SenderAccount.GetAddress()
tmValidator := s.chainA.Vals.Validators[0]
valAddr, err := sdk.ValAddressFromHex(tmValidator.Address.String())
s.Require().NoError(err)
validator, found := chainAStakingKeeper.GetValidator(s.ctx, valAddr)
s.Require().True(found)
_, err = chainAStakingKeeper.Delegate(s.ctx, delAddr, bondAmt, stakingtypes.Unbonded, stakingtypes.Validator(validator), true)
s.Require().NoError(err)
// check that validator updates are seen by the staking module endblock callback
valUpdates := chainAStakingKeeper.BlockValidatorUpdates(s.ctx)
s.Require().Len(valUpdates, 1)
err = path.EndpointB.UpdateClient()
s.Require().NoError(err)
// Check the chain validator hash is updated
s.T().Log(!bytes.Equal(s.chainA.CurrentHeader.GetNextValidatorsHash(), s.chainA.CurrentHeader.GetValidatorsHash()))
// Check the validator power was updated
s.T().Log(s.chainA.Vals.Validators[0].VotingPower == int64(2))
// Undelegate both shares
_, err = chainAStakingKeeper.Undelegate(s.ctx, delAddr, valAddr, sdk.NewDec(2))
s.Require().NoError(err)
// check that validator updates are seen by the staking module endblock callback
valUpdates = chainAStakingKeeper.BlockValidatorUpdates(s.ctx)
s.Require().Len(valUpdates, 1)
err = path.EndpointB.UpdateClient()
s.Require().NoError(err)
ubd, found := chainAStakingKeeper.GetUnbondingDelegation(s.ctx, delAddr, valAddr)
s.Require().True(found)
s.Require().Len(ubd.Entries, 1)
vals, ok := s.chainA.GetValsAtHeight(s.chainA.CurrentHeader.Height)
s.Require().True(ok)
// Check the validator set is updated in chain A
s.T().Log(vals.Validators[0].VotingPower == int64(0))
// Check the chain validator hash is updated
s.T().Log(!bytes.Equal(s.chainA.CurrentHeader.GetNextValidatorsHash(), s.chainA.CurrentHeader.GetValidatorsHash()))
// Check the validator set is updated in chain A
s.T().Log(s.chainA.Vals.Validators[0].VotingPower == int64(0))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment