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

fix(runtime/v2): return genesis val updates #22729

Merged
merged 7 commits into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
16 changes: 9 additions & 7 deletions runtime/v2/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,35 +128,37 @@ func (a *AppBuilder[T]) Build(opts ...AppBuilderOption[T]) (*App[T], error) {
}

// initGenesis returns the app initialization genesis for modules
func (a *AppBuilder[T]) initGenesis(ctx context.Context, src io.Reader, txHandler func(json.RawMessage) error) (store.WriterMap, error) {
func (a *AppBuilder[T]) initGenesis(ctx context.Context, src io.Reader, txHandler func(json.RawMessage) error) (store.WriterMap, []appmodule.ValidatorUpdate, error) {
// this implementation assumes that the state is a JSON object
bz, err := io.ReadAll(src)
if err != nil {
return nil, fmt.Errorf("failed to read import state: %w", err)
return nil, nil, fmt.Errorf("failed to read import state: %w", err)
}

var genesisJSON map[string]json.RawMessage
if err = json.Unmarshal(bz, &genesisJSON); err != nil {
return nil, err
return nil, nil, err
}

v, zeroState, err := a.app.db.StateLatest()
if err != nil {
return nil, fmt.Errorf("unable to get latest state: %w", err)
return nil, nil, fmt.Errorf("unable to get latest state: %w", err)
}
if v != 0 { // TODO: genesis state may be > 0, we need to set version on store
return nil, errors.New("cannot init genesis on non-zero state")
return nil, nil, errors.New("cannot init genesis on non-zero state")
}
genesisCtx := services.NewGenesisContext(a.branch(zeroState))
var valUpdates []appmodulev2.ValidatorUpdate
genesisState, err := genesisCtx.Mutate(ctx, func(ctx context.Context) error {
err = a.app.moduleManager.InitGenesisJSON(ctx, genesisJSON, txHandler)
valUpdates, err = a.app.moduleManager.InitGenesisJSON(ctx, genesisJSON, txHandler)
if err != nil {
return fmt.Errorf("failed to init genesis: %w", err)
}

return nil
})

return genesisState, err
return genesisState, valUpdates, err
}

// exportGenesis returns the app export genesis logic for modules
Expand Down
26 changes: 14 additions & 12 deletions runtime/v2/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,10 @@ func (m *MM[T]) InitGenesisJSON(
ctx context.Context,
genesisData map[string]json.RawMessage,
txHandler func(json.RawMessage) error,
) error {
) ([]appmodulev2.ValidatorUpdate, error) {
m.logger.Info("initializing blockchain state from genesis.json", "order", m.config.InitGenesis)
var seenValUpdates bool

var validatorUpdates []appmodulev2.ValidatorUpdate
for _, moduleName := range m.config.InitGenesis {
if genesisData[moduleName] == nil {
continue
Expand All @@ -158,38 +159,39 @@ func (m *MM[T]) InitGenesisJSON(
case appmodulev2.GenesisDecoder: // GenesisDecoder needs to supersede HasGenesis and HasABCIGenesis.
genTxs, err := module.DecodeGenesisJSON(genesisData[moduleName])
if err != nil {
return err
return nil, err
}
for _, jsonTx := range genTxs {
if err := txHandler(jsonTx); err != nil {
return fmt.Errorf("failed to handle genesis transaction: %w", err)
return nil, fmt.Errorf("failed to handle genesis transaction: %w", err)
}
}
case appmodulev2.HasGenesis:
m.logger.Debug("running initialization for module", "module", moduleName)
if err := module.InitGenesis(ctx, genesisData[moduleName]); err != nil {
return fmt.Errorf("init module %s: %w", moduleName, err)
return nil, fmt.Errorf("init module %s: %w", moduleName, err)
}
case appmodulev2.HasABCIGenesis:
m.logger.Debug("running initialization for module", "module", moduleName)
var err error
moduleValUpdates, err := module.InitGenesis(ctx, genesisData[moduleName])
if err != nil {
return err
return nil, err
}

// use these validator updates if provided, the module manager assumes
// only one module will update the validator set
if len(moduleValUpdates) > 0 {
if seenValUpdates {
return fmt.Errorf("validator InitGenesis updates already set by a previous module: current module %s", moduleName)
} else {
seenValUpdates = true
if len(validatorUpdates) > 0 {
return nil, fmt.Errorf("validator InitGenesis updates already set by a previous module: current module %s", moduleName)
}

validatorUpdates = append(validatorUpdates, moduleValUpdates...)
}
}

}
return nil

return validatorUpdates, nil
}

// ExportGenesisForModules performs export genesis functionality for modules
Expand Down
14 changes: 13 additions & 1 deletion server/v2/appmanager/appmanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ func (a appManager[T]) InitGenesis(
txDecoder transaction.Codec[T],
) (*server.BlockResponse, corestore.WriterMap, error) {
var genTxs []T
genesisState, err := a.initGenesis(
genesisState, valUpdates, err := a.initGenesis(
ctx,
bytes.NewBuffer(initGenesisJSON),
func(jsonTx json.RawMessage) error {
Expand All @@ -122,6 +122,7 @@ func (a appManager[T]) InitGenesis(
if err != nil {
return nil, nil, fmt.Errorf("failed to import genesis state: %w", err)
}

// run block
blockRequest.Txs = genTxs

Expand All @@ -141,6 +142,17 @@ func (a appManager[T]) InitGenesis(
return nil, nil, fmt.Errorf("failed to apply block zero state changes to genesis state: %w", err)
}

// override validator updates with the ones from the init genesis state
// this triggers only when x/staking or another module that returns validator updates in InitGenesis
// otherwise, genutil validator updates takes precedence (returned from executing the genesis txs (as it implements appmodule.GenesisDecoder) in the end block)
if len(valUpdates) > 0 && len(blockResponse.ValidatorUpdates) > 0 {
return nil, nil, errors.New("validator updates returned from InitGenesis and genesis transactions, only one can be used")
}

if len(valUpdates) > 0 {
blockResponse.ValidatorUpdates = valUpdates
}
julienrbrt marked this conversation as resolved.
Show resolved Hide resolved

return blockResponse, genesisState, err
}

Expand Down
3 changes: 2 additions & 1 deletion server/v2/appmanager/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/json"
"io"

appmodulev2 "cosmossdk.io/core/appmodule/v2"
"cosmossdk.io/core/store"
)

Expand All @@ -21,7 +22,7 @@ type (
ctx context.Context,
src io.Reader,
txHandler func(json.RawMessage) error,
) (store.WriterMap, error)
) (store.WriterMap, []appmodulev2.ValidatorUpdate, error)

// ExportGenesis is a function type that represents the export of the genesis state.
ExportGenesis func(ctx context.Context, version uint64) ([]byte, error)
Expand Down
4 changes: 2 additions & 2 deletions server/v2/cometbft/abci_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -701,10 +701,10 @@ func setUpConsensus(t *testing.T, gasLimit uint64, mempool mempool.Mempool[mock.
},
mockStore,
s,
func(ctx context.Context, src io.Reader, txHandler func(json.RawMessage) error) (store.WriterMap, error) {
func(ctx context.Context, src io.Reader, txHandler func(json.RawMessage) error) (store.WriterMap, []appmodulev2.ValidatorUpdate, error) {
_, st, err := mockStore.StateLatest()
require.NoError(t, err)
return branch.DefaultNewWriterMap(st), nil
return branch.DefaultNewWriterMap(st), nil, nil
julienrbrt marked this conversation as resolved.
Show resolved Hide resolved
julienrbrt marked this conversation as resolved.
Show resolved Hide resolved
},
nil,
)
Expand Down
1 change: 1 addition & 0 deletions x/genutil/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ var (

_ appmodule.AppModule = AppModule{}
_ appmodulev2.GenesisDecoder = AppModule{}
_ appmodulev2.HasABCIGenesis = AppModule{}
)

// AppModule implements an application module for the genutil module.
Expand Down
Loading