Skip to content

Ensure InitGenesis returns with non-empty validator set #8961

Closed
@colin-axner

Description

Summary

ref: #8909 #8908

Currently, the SDK allows InitGenesis to return with an empty validator set. In practice, the error for an empty validator set gets thrown in tendermint. This error is very common and is unhelpful in figuring out the root of the issue (usually an undelgated validator). The SDK should consider an empty validator set after InitGenesis to be invalid, as a chain cannot produce a block without a validator set and should then panic.

Problem Definition

Simapp relies on an empty validator set

Proposal

I would like to add this fix in types/module/module.go:

// 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.JSONMarshaler, genesisData map[string]json.RawMessage) abci.ResponseInitChain {
        var validatorUpdates []abci.ValidatorUpdate
        for _, moduleName := range m.OrderInitGenesis {
@@ -315,6 +318,11 @@ func (m *Manager) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, genesisD
                }
        }
 
+       // 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 PowerReduction (%d)", sdk.PowerReduction))
+       }
+
        return abci.ResponseInitChain{
                Validators: validatorUpdates,
        }

But this breaks simapp. Specifically the default simapp runs without a validator set and it uses InitGenesis. I'd like simapp to use a single validator by default. I did a lot of the heavy lifting several months ago by adding SetupWithGenesisValSet function.

We would need to add this into the Setup function of simapp:

// generate validator private/public key
	privVal := mock.NewPV()
	pubKey, err := privVal.GetPubKey()
	require.NoError(t, err)

	// 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)

NOTE: mock is a package in ibc-go which mocks a simple tendermint validator. It is very straightforward and we could port it over to the SDK

I did a quick check locally to see how troublesome this change is, and several tests either:

  • rely on empty validator set (looks like grpc query functions)
  • attempt to do their own initialize (not via Setup)

After fixing Setup, all other tests doing their on simapp setup should be switched to use the Setup function unless they have a very good reason for not using it

There are arguments to be made that we should keep simapp as simple as possible since most of these tests are for unit tests


For Admin Use

  • Not duplicate issue
  • Appropriate labels applied
  • Appropriate contributors tagged
  • Contributor assigned/self-assigned

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions