Skip to content

Commit

Permalink
refactor(genutil): export genesis with val set implementation (#22178)
Browse files Browse the repository at this point in the history
  • Loading branch information
kocubinski authored Oct 8, 2024
1 parent 2d40cef commit 7879361
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 73 deletions.
14 changes: 0 additions & 14 deletions runtime/v2/app.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package runtime

import (
"context"
"encoding/json"

runtimev2 "cosmossdk.io/api/cosmos/app/runtime/v2"
Expand Down Expand Up @@ -90,23 +89,10 @@ func (a *App[T]) Close() error {
return nil
}

// GetStore returns the app store.
func (a *App[T]) GetStore() Store {
return a.db
}

func (a *App[T]) GetAppManager() *appmanager.AppManager[T] {
return a.AppManager
}

func (a *App[T]) GetQueryHandlers() map[string]appmodulev2.Handler {
return a.QueryHandlers
}

func (a *App[T]) Query(ctx context.Context, gasLimit, version uint64, req transaction.Msg) (transaction.Msg, error) {
state, err := a.db.StateAt(version)
if err != nil {
return nil, err
}
return a.stf.Query(ctx, state, gasLimit, req)
}
2 changes: 1 addition & 1 deletion runtime/v2/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ func (a *AppBuilder[T]) Build(opts ...AppBuilderOption[T]) (*App[T], error) {
return nil, errors.New("cannot init genesis on non-zero state")
}
genesisCtx := services.NewGenesisContext(a.branch(zeroState))
genesisState, err := genesisCtx.Run(ctx, func(ctx context.Context) error {
genesisState, err := genesisCtx.Mutate(ctx, func(ctx context.Context) error {
err = a.app.moduleManager.InitGenesisJSON(ctx, genesisJSON, txHandler)
if err != nil {
return fmt.Errorf("failed to init genesis: %w", err)
Expand Down
10 changes: 7 additions & 3 deletions runtime/v2/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,15 +230,17 @@ func (m *MM[T]) ExportGenesisForModules(
channels[moduleName] = make(chan genesisResult)
go func(moduleI ModuleI, ch chan genesisResult) {
genesisCtx := services.NewGenesisContext(stateFactory())
_, _ = genesisCtx.Run(ctx, func(ctx context.Context) error {
err := genesisCtx.Read(ctx, func(ctx context.Context) error {
jm, err := moduleI.ExportGenesis(ctx)
if err != nil {
ch <- genesisResult{nil, err}
return err
}
ch <- genesisResult{jm, nil}
return nil
})
if err != nil {
ch <- genesisResult{nil, err}
}
}(moduleI, channels[moduleName])
}

Expand Down Expand Up @@ -783,7 +785,9 @@ func messagePassingInterceptor(msg transaction.Msg) grpc.UnaryServerInterceptor
}

// requestFullNameFromMethodDesc returns the fully-qualified name of the request message and response of the provided service's method.
func requestFullNameFromMethodDesc(sd *grpc.ServiceDesc, method grpc.MethodDesc) (protoreflect.FullName, protoreflect.FullName, error) {
func requestFullNameFromMethodDesc(sd *grpc.ServiceDesc, method grpc.MethodDesc) (
protoreflect.FullName, protoreflect.FullName, error,
) {
methodFullName := protoreflect.FullName(fmt.Sprintf("%s.%s", sd.ServiceName, method.MethodName))
desc, err := gogoproto.HybridResolver.FindDescriptorByName(methodFullName)
if err != nil {
Expand Down
51 changes: 43 additions & 8 deletions runtime/v2/services/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
var (
_ store.KVStoreService = (*GenesisKVStoreService)(nil)
_ header.Service = (*GenesisHeaderService)(nil)
_ store.KVStore = (*readonlyKVStore)(nil)
)

type genesisContextKeyType struct{}
Expand All @@ -21,28 +22,41 @@ var genesisContextKey = genesisContextKeyType{}
// it backs the store.KVStoreService and header.Service interface implementations
// defined in this file.
type genesisContext struct {
state store.WriterMap
state store.ReaderMap
}

// NewGenesisContext creates a new genesis context.
func NewGenesisContext(state store.WriterMap) genesisContext {
func NewGenesisContext(state store.ReaderMap) genesisContext {
return genesisContext{
state: state,
}
}

// Run runs the provided function within the genesis context and returns an
// Mutate runs the provided function within the genesis context and returns an
// updated store.WriterMap containing the state modifications made during InitGenesis.
func (g *genesisContext) Run(
func (g genesisContext) Mutate(
ctx context.Context,
fn func(ctx context.Context) error,
) (store.WriterMap, error) {
writerMap, ok := g.state.(store.WriterMap)
if !ok {
return nil, fmt.Errorf("mutate requires a store.WriterMap, got a %T", g.state)
}
ctx = context.WithValue(ctx, genesisContextKey, g)
err := fn(ctx)
if err != nil {
return nil, err
}
return g.state, nil
return writerMap, nil
}

// Read runs the provided function within the genesis context.
func (g genesisContext) Read(
ctx context.Context,
fn func(ctx context.Context) error,
) error {
ctx = context.WithValue(ctx, genesisContextKey, g)
return fn(ctx)
}

// GenesisKVStoreService is a store.KVStoreService implementation that is used during
Expand Down Expand Up @@ -71,15 +85,24 @@ func (g *GenesisKVStoreService) OpenKVStore(ctx context.Context) store.KVStore {
if v == nil {
return g.executionService.OpenKVStore(ctx)
}
genCtx, ok := v.(*genesisContext)
genCtx, ok := v.(genesisContext)
if !ok {
panic(fmt.Errorf("unexpected genesis context type: %T", v))
}
state, err := genCtx.state.GetWriter(g.actor)
writerMap, ok := genCtx.state.(store.WriterMap)
if ok {
state, err := writerMap.GetWriter(g.actor)
if err != nil {
panic(err)
}
return state

}
state, err := genCtx.state.GetReader(g.actor)
if err != nil {
panic(err)
}
return state
return readonlyKVStore{state}
}

// GenesisHeaderService is a header.Service implementation that is used during
Expand All @@ -105,3 +128,15 @@ func NewGenesisHeaderService(executionService header.Service) *GenesisHeaderServ
executionService: executionService,
}
}

type readonlyKVStore struct {
store.Reader
}

func (r readonlyKVStore) Set(key, value []byte) error {
panic("tried to call Set on a readonly store")
}

func (r readonlyKVStore) Delete(key []byte) error {
panic("tried to call Delete on a readonly store")
}
10 changes: 6 additions & 4 deletions simapp/v2/app_di.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"cosmossdk.io/log"
"cosmossdk.io/runtime/v2"
serverstore "cosmossdk.io/server/v2/store"
"cosmossdk.io/store/v2"
"cosmossdk.io/store/v2/root"
basedepinject "cosmossdk.io/x/accounts/defaults/base/depinject"
lockupdepinject "cosmossdk.io/x/accounts/defaults/lockup/depinject"
Expand All @@ -39,6 +40,7 @@ type SimApp[T transaction.Tx] struct {
appCodec codec.Codec
txConfig client.TxConfig
interfaceRegistry codectypes.InterfaceRegistry
store store.RootStore

// required keepers during wiring
// others keepers are all in the app
Expand Down Expand Up @@ -173,7 +175,8 @@ func NewSimApp[T transaction.Tx](
if err != nil {
panic(err)
}
_, err = storeBuilder.Build(logger, storeConfig)

app.store, err = storeBuilder.Build(logger, storeConfig)
if err != nil {
panic(err)
}
Expand Down Expand Up @@ -216,7 +219,6 @@ func (app *SimApp[T]) TxConfig() client.TxConfig {
return app.txConfig
}

// GetStore gets the app store.
func (app *SimApp[T]) GetStore() any {
return app.App.GetStore()
func (app *SimApp[T]) GetStore() store.RootStore {
return app.store
}
5 changes: 2 additions & 3 deletions simapp/v2/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import (
sdkmath "cosmossdk.io/math"
"cosmossdk.io/runtime/v2"
serverv2 "cosmossdk.io/server/v2"
comettypes "cosmossdk.io/server/v2/cometbft/types"
serverv2store "cosmossdk.io/server/v2/store"
"cosmossdk.io/store/v2/db"
banktypes "cosmossdk.io/x/bank/types"
Expand Down Expand Up @@ -75,7 +74,7 @@ func NewTestApp(t *testing.T) (*SimApp[transaction.Tx], context.Context) {
genesisBytes, err := json.Marshal(genesis)
require.NoError(t, err)

st := app.GetStore().(comettypes.Store)
st := app.GetStore()
ci, err := st.LastCommitID()
require.NoError(t, err)

Expand Down Expand Up @@ -111,7 +110,7 @@ func MoveNextBlock(t *testing.T, app *SimApp[transaction.Tx], ctx context.Contex

bz := sha256.Sum256([]byte{})

st := app.GetStore().(comettypes.Store)
st := app.GetStore()
ci, err := st.LastCommitID()
require.NoError(t, err)

Expand Down
61 changes: 21 additions & 40 deletions simapp/v2/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,64 +2,45 @@ package simapp

import (
"context"
"fmt"

stakingtypes "cosmossdk.io/x/staking/types"
"cosmossdk.io/runtime/v2/services"
"cosmossdk.io/x/staking"

cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
v2 "github.com/cosmos/cosmos-sdk/x/genutil/v2"
)

// ExportAppStateAndValidators exports the state of the application for a genesis
// file.
func (app *SimApp[T]) ExportAppStateAndValidators(jailAllowedAddrs []string) (v2.ExportedApp, error) {
// as if they could withdraw from the start of the next block
func (app *SimApp[T]) ExportAppStateAndValidators(
jailAllowedAddrs []string,
) (v2.ExportedApp, error) {
ctx := context.Background()
var exportedApp v2.ExportedApp

latestHeight, err := app.LoadLatestHeight()
if err != nil {
return v2.ExportedApp{}, err
return exportedApp, err
}

genesis, err := app.ExportGenesis(ctx, latestHeight)
if err != nil {
return v2.ExportedApp{}, err
return exportedApp, err
}

// get the current bonded validators
resp, err := app.Query(ctx, 0, latestHeight, &stakingtypes.QueryValidatorsRequest{
Status: stakingtypes.BondStatusBonded,
})

vals, ok := resp.(*stakingtypes.QueryValidatorsResponse)
if !ok {
return v2.ExportedApp{}, fmt.Errorf("invalid response, expected QueryValidatorsResponse")
readerMap, err := app.GetStore().StateAt(latestHeight)
if err != nil {
return exportedApp, err
}

// convert to genesis validator
var genesisVals []sdk.GenesisValidator
for _, val := range vals.Validators {
pk, err := val.ConsPubKey()
if err != nil {
return v2.ExportedApp{}, err
}
jsonPk, err := cryptocodec.PubKeyFromProto(pk)
if err != nil {
return v2.ExportedApp{}, err
}

genesisVals = append(genesisVals, sdk.GenesisValidator{
Address: sdk.ConsAddress(pk.Address()).Bytes(),
PubKey: jsonPk,
Power: val.GetConsensusPower(app.StakingKeeper.PowerReduction(ctx)),
Name: val.Description.Moniker,
})
genesisCtx := services.NewGenesisContext(readerMap)
err = genesisCtx.Read(ctx, func(ctx context.Context) error {
exportedApp.Validators, err = staking.WriteValidators(ctx, app.StakingKeeper)
return err
})
if err != nil {
return exportedApp, err
}

return v2.ExportedApp{
AppState: genesis,
Height: int64(latestHeight),
Validators: genesisVals,
}, err
exportedApp.AppState = genesis
exportedApp.Height = int64(latestHeight)
return exportedApp, nil
}

0 comments on commit 7879361

Please sign in to comment.