Skip to content

Commit

Permalink
fix: export only active consensus validators to genesis
Browse files Browse the repository at this point in the history
When exporting a chain to a genesis file, there's a field in the genesis
called "validators" that contains the validators that'll be used
to bootstrap consensus. This is separate to the list of all validators,
bonded and otherwise, kept in the staking module's app_state. If this field
contains anything other than those validators that're actively
participating in consensus, the chain import will fail. Thus,
we shouldn't add all the validators from the staking module to this
field, but only those we want used for consensus.
  • Loading branch information
fastfadingviolets committed Jan 27, 2025
1 parent 908fec1 commit e4ce99d
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- Export only validators that are participating in consensus
([\#3445](https://github.com/cosmos/gaia/pull/3445))
13 changes: 13 additions & 0 deletions app/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package gaia

import (
"encoding/json"
"sort"

tmproto "github.com/cometbft/cometbft/proto/tendermint/types"

Expand Down Expand Up @@ -43,6 +44,18 @@ func (app *GaiaApp) ExportAppStateAndValidators(
}

validators, err := staking.WriteValidators(ctx, app.StakingKeeper)
if err != nil {
return servertypes.ExportedApp{}, err
}
sort.SliceStable(validators, func(i, j int) bool {
return validators[i].Power > validators[j].Power
})
// we have to trim this to only active consensus validators
maxVals := app.ProviderKeeper.GetMaxProviderConsensusValidators(ctx)
if len(validators) > int(maxVals) {
validators = validators[:maxVals]
}

return servertypes.ExportedApp{
AppState: appState,
Validators: validators,
Expand Down
101 changes: 101 additions & 0 deletions tests/interchain/integrator/export_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package integrator_test

import (
"fmt"
"testing"

stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/cosmos/gaia/v23/tests/interchain/chainsuite"
"github.com/strangelove-ventures/interchaintest/v8"
"github.com/strangelove-ventures/interchaintest/v8/chain/cosmos"
"github.com/strangelove-ventures/interchaintest/v8/ibc"
"github.com/stretchr/testify/suite"
)

const (
maxValidators = 5
maxConsensusValidators = 4
)

type ExportSuite struct {
*chainsuite.Suite
}

func (s *ExportSuite) TestExportAndImportValidators() {
height, err := s.Chain.Height(s.GetContext())
s.Require().NoError(err)

s.Require().NoError(s.Chain.StopAllNodes(s.GetContext()))

exported, err := s.Chain.ExportState(s.GetContext(), height)
s.Require().NoError(err)
newConfig := chainsuite.DefaultChainSpec(s.Env).ChainConfig
newConfig.ModifyGenesis = func(cc ibc.ChainConfig, b []byte) ([]byte, error) {
return []byte(exported), nil
}
newConfig.PreGenesis = func(c ibc.Chain) error {
for i, val := range s.Chain.Validators {
key, err := val.PrivValFileContent(s.GetContext())
if err != nil {
return fmt.Errorf("failed to get key for validator %d: %w", i, err)
}
cosmosChain := c.(*cosmos.CosmosChain)
err = cosmosChain.Validators[i].OverwritePrivValFile(s.GetContext(), key)
if err != nil {
return fmt.Errorf("failed to overwrite priv val file for validator %d: %w", i, err)
}
}
return nil
}
zero := 0
newSpec := &interchaintest.ChainSpec{
Name: "gaia",
Version: s.Env.NewGaiaImageVersion,
NumValidators: &chainsuite.SixValidators,
NumFullNodes: &zero,
ChainConfig: newConfig,
}
newChain, err := chainsuite.CreateChain(s.GetContext(), s.T(), newSpec)
s.Require().NoError(err)

validators := []*stakingtypes.Validator{}
// We go through the original chain's wallets because we want to make sure those validators still exist in the new chain.
for _, wallet := range s.Chain.ValidatorWallets {
validator, err := newChain.StakingQueryValidator(s.GetContext(), wallet.ValoperAddress)
s.Require().NoError(err)
validators = append(validators, validator)
}
for i := 0; i < maxValidators; i++ {
s.Require().Equal(stakingtypes.Bonded, validators[i].Status)
}
s.Require().Equal(stakingtypes.Unbonded, validators[maxValidators].Status)

vals, err := newChain.QueryJSON(s.GetContext(), "validators", "tendermint-validator-set")
s.Require().NoError(err)
s.Require().Equal(maxConsensusValidators, len(vals.Array()), vals)
for i := 0; i < maxConsensusValidators; i++ {
valCons := vals.Array()[i].Get("address").String()
s.Require().NoError(err)
s.Require().Equal(s.Chain.ValidatorWallets[i].ValConsAddress, valCons)
}
}

func TestExport(t *testing.T) {
genesis := chainsuite.DefaultGenesis()
genesis = append(genesis,
cosmos.NewGenesisKV("app_state.staking.params.max_validators", maxValidators),
cosmos.NewGenesisKV("app_state.provider.params.max_provider_consensus_validators", maxConsensusValidators),
)
s := &ExportSuite{
Suite: chainsuite.NewSuite(chainsuite.SuiteConfig{
UpgradeOnSetup: true,
ChainSpec: &interchaintest.ChainSpec{
NumValidators: &chainsuite.SixValidators,
ChainConfig: ibc.ChainConfig{
ModifyGenesis: cosmos.ModifyGenesis(genesis),
},
},
}),
}
suite.Run(t, s)
}
3 changes: 2 additions & 1 deletion tests/interchain/matrix_tool/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,11 @@ func GetSemverForBranch() (string, error) {

func GetTestList() ([]string, error) {
retval := []string{}
var stderr bytes.Buffer
cmd := exec.Command("go", "test", "-list=.", "./...")
cmd.Stderr = &stderr
out, err := cmd.Output()
if err != nil {
stderr := string(cmd.Stderr.(*bytes.Buffer).Bytes())
return nil, fmt.Errorf("go test -list failed with %w : %s\n", err, stderr)
}
lines := strings.Split(string(out), "\n")
Expand Down

0 comments on commit e4ce99d

Please sign in to comment.