Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: Ensure InitGenesis returns with non-empty validator set #9697

Merged
merged 73 commits into from
Oct 5, 2021
Merged
Show file tree
Hide file tree
Changes from 71 commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
bd90b1a
add check for validator set length
aleem1314 Jul 13, 2021
be4082a
Update simapp/Setup
aleem1314 Jul 15, 2021
e152292
WIP
aleem1314 Jul 15, 2021
7a608e6
WIP
aleem1314 Jul 15, 2021
66a4ff1
refactor simapp/Setup
aleem1314 Jul 16, 2021
4718667
WIP update tests
aleem1314 Jul 19, 2021
81b74a2
WIP fixing tests
aleem1314 Jul 19, 2021
ad24e04
WIP fix simapp & server tests
aleem1314 Jul 20, 2021
8d19a32
Merge branch 'master' into aleem/8961-init-genesis
aleem1314 Jul 20, 2021
bbe36cf
WIP fixing tests
aleem1314 Jul 26, 2021
41392f9
WIP fixing tests
aleem1314 Jul 26, 2021
0e64738
WIP fixing tests
aleem1314 Jul 27, 2021
098f152
WIP fix slashing tests
aleem1314 Jul 27, 2021
b237286
remove print statements
aleem1314 Jul 27, 2021
62701db
Merge branch 'master' into aleem/8961-init-genesis
aleem1314 Jul 27, 2021
8ff0b48
fix upgrade module tests
aleem1314 Jul 27, 2021
1512793
fix distribution module keeper tests
aleem1314 Jul 28, 2021
3fc33e4
fix bank keeper tests
aleem1314 Jul 28, 2021
8631c69
fix feegrant simulation tests
aleem1314 Jul 28, 2021
aaae1e7
WIP fixing staking tests
aleem1314 Jul 29, 2021
2667fcd
cleanup
aleem1314 Jul 29, 2021
08b48fc
WIP fixing staking tests
aleem1314 Jul 29, 2021
09562f4
WIP fixing staking tests
aleem1314 Jul 29, 2021
e1a09de
cleanup
aleem1314 Jul 29, 2021
bdb1f94
WIP fixing tests
aleem1314 Jul 31, 2021
d2b394d
WIP
aleem1314 Aug 1, 2021
2333a8d
update module tests
aleem1314 Aug 2, 2021
ca91201
fix delegations test
aleem1314 Aug 2, 2021
6c6b97f
Merge branch 'master' into aleem/8961-init-genesis
aleem1314 Aug 2, 2021
768874e
Merge branch 'master' into aleem/8961-init-genesis
aleem1314 Aug 4, 2021
e13061e
WIP fixing staking tests
aleem1314 Aug 5, 2021
3a4da8f
WIP staking tests
aleem1314 Aug 5, 2021
74286c0
WIP fixing simulation tests
aleem1314 Aug 6, 2021
4b5e3d3
Merge branch 'master' into aleem/8961-init-genesis
aleem1314 Aug 6, 2021
4eb8bbb
fix validator tests
aleem1314 Aug 6, 2021
ce0ee6a
fix test
aleem1314 Aug 6, 2021
09e2d96
fix test
aleem1314 Aug 6, 2021
2c031c8
cleanup
aleem1314 Aug 6, 2021
fe96eda
fix genesis simulation
aleem1314 Aug 9, 2021
f5a63cd
fix staking simulation tests
aleem1314 Aug 9, 2021
a3dc9a6
add changelog
aleem1314 Aug 9, 2021
a4298f9
Merge branch 'master' into aleem/8961-init-genesis
aleem1314 Aug 9, 2021
daa1537
cleanup
aleem1314 Aug 9, 2021
d7b9a02
fix test
aleem1314 Aug 9, 2021
3bfa61e
Merge branch into aleem/8961-init-genesis
aleem1314 Aug 9, 2021
bafed57
Merge branch 'aleem/8961-init-genesis' of https://github.com/cosmos/c…
aleem1314 Aug 9, 2021
f9ede21
Update simapp/sim_test.go
aleem1314 Aug 9, 2021
e5a0f39
cleanup
aleem1314 Aug 10, 2021
8573d2c
Merge branch 'aleem/8961-init-genesis' of https://github.com/cosmos/c…
aleem1314 Aug 10, 2021
d59ae67
Update simapp/app_test.go
aleem1314 Aug 12, 2021
4c3cbd3
Update simapp/sim_test.go
aleem1314 Aug 12, 2021
7ce3494
Merge branch 'master' into aleem/8961-init-genesis
aleem1314 Aug 12, 2021
a3d5ba6
fix imports
aleem1314 Aug 12, 2021
7c01a45
Merge branch 'master' into aleem/8961-init-genesis
aleem1314 Aug 17, 2021
c461abf
fix: fix conflicts
aleem1314 Aug 19, 2021
1237e3d
Merge branch 'master' into aleem/8961-init-genesis
aleem1314 Aug 19, 2021
7e5f6c1
Merge branch 'master' into aleem/8961-init-genesis
aleem1314 Sep 1, 2021
0cdfcce
review changes
aleem1314 Sep 1, 2021
3a8e124
Merge branch 'master' into aleem/8961-init-genesis
aleem1314 Sep 16, 2021
884b72b
WIP: fixing tests
aleem1314 Sep 16, 2021
90519cc
fix failing tests
aleem1314 Sep 18, 2021
6c21a6e
cleanup
aleem1314 Sep 20, 2021
d055f23
fix errors
aleem1314 Sep 20, 2021
c8ff8be
cleanup
aleem1314 Sep 20, 2021
5dcbe37
Merge branch 'master' into aleem/8961-init-genesis
aleem1314 Sep 20, 2021
65530a2
Update x/staking/keeper/historical_info_test.go
aleem1314 Sep 27, 2021
ae4a8c4
Merge branch 'master' into aleem/8961-init-genesis
aleem1314 Sep 27, 2021
1c3ff1c
address review comments
aleem1314 Sep 27, 2021
807039b
chore: address review comments
aleem1314 Sep 28, 2021
a79beda
Merge branch 'master' into aleem/8961-init-genesis
aleem1314 Sep 28, 2021
6961300
Merge branch 'master' into aleem/8961-init-genesis
aleem1314 Sep 29, 2021
3122bf9
Merge branch 'master' into aleem/8961-init-genesis
aleem1314 Oct 5, 2021
d7a2684
Merge branch 'master' into aleem/8961-init-genesis
aleem1314 Oct 5, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (types) [\#10021](https://github.com/cosmos/cosmos-sdk/pull/10021) Speedup coins.AmountOf(), by removing many intermittent regex calls.
* (rosetta) [\#10001](https://github.com/cosmos/cosmos-sdk/issues/10001) Add documentation for rosetta-cli dockerfile and rename folder for the rosetta-ci dockerfile
* [\#9699](https://github.com/cosmos/cosmos-sdk/pull/9699) Add `:`, `.`, `-`, and `_` as allowed characters in the default denom regular expression.
* (genesis) [\#9697](https://github.com/cosmos/cosmos-sdk/pull/9697) Ensure `InitGenesis` returns with non-empty validator set.

### Bug Fixes
* [#10180](https://github.com/cosmos/cosmos-sdk/issues/10180) Documentation: make references to Cosmos SDK consistent
Expand Down
29 changes: 10 additions & 19 deletions server/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package server_test
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"os"
Expand All @@ -22,7 +21,6 @@ import (

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/server"
"github.com/cosmos/cosmos-sdk/server/types"
"github.com/cosmos/cosmos-sdk/simapp"
Expand Down Expand Up @@ -123,6 +121,8 @@ func TestExportCmd_Height(t *testing.T) {
}

func setupApp(t *testing.T, tempDir string) (*simapp.SimApp, context.Context, *tmtypes.GenesisDoc, *cobra.Command) {
t.Helper()

if err := createConfigFolder(tempDir); err != nil {
t.Fatalf("error creating config folder: %s", err)
}
Expand All @@ -132,11 +132,18 @@ func setupApp(t *testing.T, tempDir string) (*simapp.SimApp, context.Context, *t
encCfg := simapp.MakeTestEncodingConfig()
app := simapp.NewSimApp(logger, db, nil, true, map[int64]bool{}, tempDir, 0, encCfg, simapp.EmptyAppOptions{})

genesisState := simapp.GenesisStateWithSingleValidator(t, app)
stateBytes, err := tmjson.MarshalIndent(genesisState, "", " ")
require.NoError(t, err)

serverCtx := server.NewDefaultContext()
serverCtx.Config.RootDir = tempDir

clientCtx := client.Context{}.WithCodec(app.AppCodec())
genDoc := newDefaultGenesisDoc(encCfg.Codec)
genDoc := &tmtypes.GenesisDoc{}
genDoc.ChainID = "theChainId"
genDoc.Validators = nil
genDoc.AppState = stateBytes

require.NoError(t, saveGenesisFile(genDoc, serverCtx.Config.GenesisFile()))
app.InitChain(
Expand Down Expand Up @@ -177,22 +184,6 @@ func createConfigFolder(dir string) error {
return os.Mkdir(path.Join(dir, "config"), 0700)
}

func newDefaultGenesisDoc(cdc codec.Codec) *tmtypes.GenesisDoc {
genesisState := simapp.NewDefaultGenesisState(cdc)

stateBytes, err := json.MarshalIndent(genesisState, "", " ")
if err != nil {
panic(err)
}

genDoc := &tmtypes.GenesisDoc{}
genDoc.ChainID = "theChainId"
genDoc.Validators = nil
genDoc.AppState = stateBytes

return genDoc
}

func saveGenesisFile(genDoc *tmtypes.GenesisDoc, dir string) error {
err := genutil.ExportGenesisFile(genDoc, dir)
if err != nil {
Expand Down
13 changes: 13 additions & 0 deletions simapp/sim_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"fmt"
"math/rand"
"os"
"runtime/debug"
"strings"
"testing"

"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -152,6 +154,17 @@ func TestAppImportExport(t *testing.T) {
err = json.Unmarshal(exported.AppState, &genesisState)
require.NoError(t, err)

defer func() {
if r := recover(); r != nil {
err := fmt.Sprintf("%v", r)
if !strings.Contains(err, "validator set is empty after InitGenesis") {
panic(r)
}
logger.Info("Skipping simulation as all validators have been unbonded")
logger.Info("err", err, "stacktrace", string(debug.Stack()))
}
}()

ctxA := app.NewContext(true, tmproto.Header{Height: app.LastBlockHeight()})
ctxB := newApp.NewContext(true, tmproto.Header{Height: app.LastBlockHeight()})
newApp.mm.InitGenesis(ctxB, app.AppCodec(), genesisState)
Expand Down
86 changes: 52 additions & 34 deletions simapp/test_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,22 +121,24 @@ func NewSimappWithCustomOptions(t *testing.T, isCheckTx bool, options SetupOptio
func Setup(t *testing.T, isCheckTx bool) *SimApp {
t.Helper()

app, genesisState := setup(!isCheckTx, 5)
if !isCheckTx {
// init chain must be called to stop deliverState from being nil
stateBytes, err := json.MarshalIndent(genesisState, "", " ")
require.NoError(t, err)
privVal := mock.NewPV()
pubKey, err := privVal.GetPubKey()
require.NoError(t, err)

// Initialize the chain
app.InitChain(
abci.RequestInitChain{
Validators: []abci.ValidatorUpdate{},
ConsensusParams: DefaultConsensusParams,
AppStateBytes: stateBytes,
},
)
// create validator set with single validator
validator := tmtypes.NewValidator(pubKey, 1)
valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator})

// generate genesis account
senderPrivKey := secp256k1.GenPrivKey()
acc := authtypes.NewBaseAccount(senderPrivKey.PubKey().Address().Bytes(), senderPrivKey.PubKey(), 0, 0)
balance := banktypes.Balance{
Address: acc.GetAddress().String(),
Coins: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100000000000000))),
}

app := SetupWithGenesisValSet(t, valSet, []authtypes.GenesisAccount{acc}, balance)

return app
}

Expand Down Expand Up @@ -181,8 +183,13 @@ func genesisStateWithValSet(t *testing.T,

totalSupply := sdk.NewCoins()
for _, b := range balances {
// add genesis acc tokens and delegated tokens to total supply
totalSupply = totalSupply.Add(b.Coins.Add(sdk.NewCoin(sdk.DefaultBondDenom, bondAmt))...)
// add genesis acc tokens to total supply
totalSupply = totalSupply.Add(b.Coins...)
}

for range delegations {
// add delegated tokens to total supply
totalSupply = totalSupply.Add(sdk.NewCoin(sdk.DefaultBondDenom, bondAmt))
}

// add bonded amount to bonded pool module account
Expand Down Expand Up @@ -237,33 +244,44 @@ func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs
func SetupWithGenesisAccounts(t *testing.T, genAccs []authtypes.GenesisAccount, balances ...banktypes.Balance) *SimApp {
t.Helper()

app, genesisState := setup(true, 0)
authGenesis := authtypes.NewGenesisState(authtypes.DefaultParams(), genAccs)
genesisState[authtypes.ModuleName] = app.AppCodec().MustMarshalJSON(authGenesis)
privVal := mock.NewPV()
pubKey, err := privVal.GetPubKey()
require.NoError(t, err)

totalSupply := sdk.NewCoins()
for _, b := range balances {
totalSupply = totalSupply.Add(b.Coins...)
}
// create validator set with single validator
validator := tmtypes.NewValidator(pubKey, 1)
valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator})

bankGenesis := banktypes.NewGenesisState(banktypes.DefaultGenesisState().Params, balances, totalSupply, []banktypes.Metadata{})
genesisState[banktypes.ModuleName] = app.AppCodec().MustMarshalJSON(bankGenesis)
return SetupWithGenesisValSet(t, valSet, genAccs, balances...)
}

stateBytes, err := json.MarshalIndent(genesisState, "", " ")
// SetupWithGenesisValSet initializes GenesisState with a single validator and genesis accounts
// that also act as delegators.
func GenesisStateWithSingleValidator(t *testing.T, app *SimApp) GenesisState {
t.Helper()

privVal := mock.NewPV()
pubKey, err := privVal.GetPubKey()
require.NoError(t, err)

app.InitChain(
abci.RequestInitChain{
Validators: []abci.ValidatorUpdate{},
ConsensusParams: DefaultConsensusParams,
AppStateBytes: stateBytes,
// create validator set with single validator
validator := tmtypes.NewValidator(pubKey, 1)
valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator})

// generate genesis account
senderPrivKey := secp256k1.GenPrivKey()
acc := authtypes.NewBaseAccount(senderPrivKey.PubKey().Address().Bytes(), senderPrivKey.PubKey(), 0, 0)
balances := []banktypes.Balance{
{
Address: acc.GetAddress().String(),
Coins: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100000000000000))),
},
)
}

app.Commit()
app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: app.LastBlockHeight() + 1}})
genesisState := NewDefaultGenesisState(app.appCodec)
genesisState = genesisStateWithValSet(t, app, genesisState, valSet, []authtypes.GenesisAccount{acc}, balances...)

return app
return genesisState
}

type GenerateAccountStrategy func(int) []sdk.AccAddress
Expand Down
10 changes: 9 additions & 1 deletion types/module/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ package module

import (
"encoding/json"
"fmt"
"sort"

"github.com/gorilla/mux"
Expand Down Expand Up @@ -296,7 +297,9 @@ func (m *Manager) RegisterServices(cfg Configurator) {
}
}

// InitGenesis performs init genesis functionality for modules
// InitGenesis performs init genesis functionality for modules. Exactly one
// module must return a non-empty validator set update to correctly initialize
// the chain.
func (m *Manager) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, genesisData map[string]json.RawMessage) abci.ResponseInitChain {
var validatorUpdates []abci.ValidatorUpdate
ctx.Logger().Info("initializing blockchain state from genesis.json")
Expand All @@ -318,6 +321,11 @@ func (m *Manager) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, genesisData
}
}

// a chain must initialize with a non-empty validator set
if len(validatorUpdates) == 0 {
panic(fmt.Sprintf("validator set is empty after InitGenesis, please ensure at least one validator is initialized with a delegation greater than or equal to the DefaultPowerReduction (%d)", sdk.DefaultPowerReduction))
colin-axner marked this conversation as resolved.
Show resolved Hide resolved
}

return abci.ResponseInitChain{
Validators: validatorUpdates,
}
Expand Down
3 changes: 2 additions & 1 deletion types/module/module_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,9 @@ func TestManager_InitGenesis(t *testing.T) {
cdc := codec.NewProtoCodec(interfaceRegistry)
genesisData := map[string]json.RawMessage{"module1": json.RawMessage(`{"key": "value"}`)}

// this should panic since the validator set is empty even after init genesis
mockAppModule1.EXPECT().InitGenesis(gomock.Eq(ctx), gomock.Eq(cdc), gomock.Eq(genesisData["module1"])).Times(1).Return(nil)
require.Equal(t, abci.ResponseInitChain{Validators: []abci.ValidatorUpdate(nil)}, mm.InitGenesis(ctx, cdc, genesisData))
require.Panics(t, func() { mm.InitGenesis(ctx, cdc, genesisData) })
aleem1314 marked this conversation as resolved.
Show resolved Hide resolved

// test panic
genesisData = map[string]json.RawMessage{
Expand Down
8 changes: 4 additions & 4 deletions x/auth/keeper/grpc_query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,14 @@ func (suite *KeeperTestSuite) TestGRPCQueryAccounts() {
},
true,
func(res *types.QueryAccountsResponse) {
for _, acc := range res.Accounts {
addresses := make([]sdk.AccAddress, len(res.Accounts))
for i, acc := range res.Accounts {
var account types.AccountI
err := suite.app.InterfaceRegistry().UnpackAny(acc, &account)
suite.Require().NoError(err)

suite.Require().True(
first.Equals(account.GetAddress()) || second.Equals(account.GetAddress()))
addresses[i] = account.GetAddress()
}
suite.Subset(addresses, []sdk.AccAddress{first, second})
},
},
}
Expand Down
15 changes: 12 additions & 3 deletions x/auth/module_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,32 @@ import (

"github.com/stretchr/testify/require"
abcitypes "github.com/tendermint/tendermint/abci/types"
tmjson "github.com/tendermint/tendermint/libs/json"
"github.com/tendermint/tendermint/libs/log"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
dbm "github.com/tendermint/tm-db"

"github.com/cosmos/cosmos-sdk/simapp"
"github.com/cosmos/cosmos-sdk/x/auth/types"
)

func TestItCreatesModuleAccountOnInitBlock(t *testing.T) {
app := simapp.Setup(t, false)
ctx := app.BaseApp.NewContext(false, tmproto.Header{})
db := dbm.NewMemDB()
encCdc := simapp.MakeTestEncodingConfig()
app := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, simapp.DefaultNodeHome, 5, encCdc, simapp.EmptyAppOptions{})

genesisState := simapp.GenesisStateWithSingleValidator(t, app)
stateBytes, err := tmjson.Marshal(genesisState)
require.NoError(t, err)

app.InitChain(
abcitypes.RequestInitChain{
AppStateBytes: []byte("{}"),
AppStateBytes: stateBytes,
ChainId: "test-chain-id",
},
)

ctx := app.BaseApp.NewContext(false, tmproto.Header{})
acc := app.AccountKeeper.GetAccount(ctx, types.NewModuleAddress(types.FeeCollectorName))
require.NotNil(t, acc)
}
20 changes: 16 additions & 4 deletions x/bank/keeper/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,13 @@ func (suite *IntegrationTestSuite) TestExportGenesis() {
app, ctx := suite.app, suite.ctx

expectedMetadata := suite.getTestMetadata()
expectedBalances, totalSupply := suite.getTestBalancesAndSupply()
expectedBalances, expTotalSupply := suite.getTestBalancesAndSupply()

// Adding genesis supply to the expTotalSupply
genesisSupply, _, err := suite.app.BankKeeper.GetPaginatedTotalSupply(suite.ctx, &query.PageRequest{Limit: query.MaxLimit})
suite.Require().NoError(err)
expTotalSupply = expTotalSupply.Add(genesisSupply...)

for i := range []int{1, 2} {
app.BankKeeper.SetDenomMetaData(ctx, expectedMetadata[i])
accAddr, err1 := sdk.AccAddressFromBech32(expectedBalances[i].Address)
Expand All @@ -32,8 +38,8 @@ func (suite *IntegrationTestSuite) TestExportGenesis() {

suite.Require().Len(exportGenesis.Params.SendEnabled, 0)
suite.Require().Equal(types.DefaultParams().DefaultSendEnabled, exportGenesis.Params.DefaultSendEnabled)
suite.Require().Equal(totalSupply, exportGenesis.Supply)
suite.Require().Equal(expectedBalances, exportGenesis.Balances)
suite.Require().Equal(expTotalSupply, exportGenesis.Supply)
suite.Require().Subset(exportGenesis.Balances, expectedBalances)
suite.Require().Equal(expectedMetadata, exportGenesis.DenomMetadata)
}

Expand Down Expand Up @@ -74,6 +80,9 @@ func (suite *IntegrationTestSuite) TestTotalSupply() {
}
totalSupply := sdk.NewCoins(sdk.NewCoin("foocoin", sdk.NewInt(11)), sdk.NewCoin("barcoin", sdk.NewInt(21)))

genesisSupply, _, err := suite.app.BankKeeper.GetPaginatedTotalSupply(suite.ctx, &query.PageRequest{Limit: query.MaxLimit})
suite.Require().NoError(err)

testcases := []struct {
name string
genesis *types.GenesisState
Expand Down Expand Up @@ -107,7 +116,10 @@ func (suite *IntegrationTestSuite) TestTotalSupply() {
suite.app.BankKeeper.InitGenesis(suite.ctx, tc.genesis)
totalSupply, _, err := suite.app.BankKeeper.GetPaginatedTotalSupply(suite.ctx, &query.PageRequest{Limit: query.MaxLimit})
suite.Require().NoError(err)
suite.Require().Equal(tc.expSupply, totalSupply)

// adding genesis supply to expected supply
expected := tc.expSupply.Add(genesisSupply...)
suite.Require().Equal(expected, totalSupply)
}
})
}
Expand Down
Loading