Co-authored-by: Alex | Interchain Labs <alex@interchainlabs.io> Co-authored-by: Tyler <48813565+technicallyty@users.noreply.github.com>
322 lines
9.9 KiB
Go
322 lines
9.9 KiB
Go
package runtime
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"slices"
|
|
|
|
"github.com/cosmos/gogoproto/proto"
|
|
"google.golang.org/protobuf/reflect/protodesc"
|
|
"google.golang.org/protobuf/reflect/protoregistry"
|
|
|
|
runtimev1alpha1 "cosmossdk.io/api/cosmos/app/runtime/v1alpha1"
|
|
appv1alpha1 "cosmossdk.io/api/cosmos/app/v1alpha1"
|
|
authmodulev1 "cosmossdk.io/api/cosmos/auth/module/v1"
|
|
stakingmodulev1 "cosmossdk.io/api/cosmos/staking/module/v1"
|
|
"cosmossdk.io/core/address"
|
|
"cosmossdk.io/core/appmodule"
|
|
"cosmossdk.io/core/comet"
|
|
"cosmossdk.io/core/event"
|
|
"cosmossdk.io/core/genesis"
|
|
"cosmossdk.io/core/header"
|
|
"cosmossdk.io/core/store"
|
|
"cosmossdk.io/depinject"
|
|
"cosmossdk.io/log"
|
|
storetypes "cosmossdk.io/store/types"
|
|
"cosmossdk.io/x/tx/signing"
|
|
|
|
"github.com/cosmos/cosmos-sdk/baseapp"
|
|
"github.com/cosmos/cosmos-sdk/codec"
|
|
addresscodec "github.com/cosmos/cosmos-sdk/codec/address"
|
|
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
|
"github.com/cosmos/cosmos-sdk/std"
|
|
"github.com/cosmos/cosmos-sdk/types/module"
|
|
"github.com/cosmos/cosmos-sdk/types/msgservice"
|
|
)
|
|
|
|
type appModule struct {
|
|
app *App
|
|
}
|
|
|
|
func (m appModule) RegisterServices(configurator module.Configurator) {
|
|
err := m.app.registerRuntimeServices(configurator)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
func (m appModule) IsOnePerModuleType() {}
|
|
func (m appModule) IsAppModule() {}
|
|
|
|
var (
|
|
_ appmodule.AppModule = appModule{}
|
|
_ module.HasServices = appModule{}
|
|
)
|
|
|
|
// BaseAppOption is a depinject.AutoGroupType which can be used to pass
|
|
// BaseApp options into the depinject. It should be used carefully.
|
|
type BaseAppOption func(*baseapp.BaseApp)
|
|
|
|
// IsManyPerContainerType indicates that this is a depinject.ManyPerContainerType.
|
|
func (b BaseAppOption) IsManyPerContainerType() {}
|
|
|
|
func init() {
|
|
appmodule.Register(&runtimev1alpha1.Module{},
|
|
appmodule.Provide(
|
|
ProvideApp,
|
|
ProvideInterfaceRegistry,
|
|
ProvideKVStoreKey,
|
|
ProvideTransientStoreKey,
|
|
ProvideMemoryStoreKey,
|
|
ProvideGenesisTxHandler,
|
|
ProvideKVStoreService,
|
|
ProvideMemoryStoreService,
|
|
ProvideTransientStoreService,
|
|
ProvideEventService,
|
|
ProvideHeaderInfoService,
|
|
ProvideCometInfoService,
|
|
ProvideBasicManager,
|
|
ProvideAddressCodec,
|
|
),
|
|
appmodule.Invoke(SetupAppBuilder),
|
|
)
|
|
}
|
|
|
|
func ProvideApp(interfaceRegistry codectypes.InterfaceRegistry) (
|
|
codec.Codec,
|
|
*codec.LegacyAmino,
|
|
*AppBuilder,
|
|
*baseapp.MsgServiceRouter,
|
|
*baseapp.GRPCQueryRouter,
|
|
appmodule.AppModule,
|
|
protodesc.Resolver,
|
|
protoregistry.MessageTypeResolver,
|
|
error,
|
|
) {
|
|
protoFiles := proto.HybridResolver
|
|
protoTypes := protoregistry.GlobalTypes
|
|
|
|
// At startup, check that all proto annotations are correct.
|
|
if err := msgservice.ValidateProtoAnnotations(protoFiles); err != nil {
|
|
// Once we switch to using protoreflect-based ante handlers, we might
|
|
// want to panic here instead of logging a warning.
|
|
_, _ = fmt.Fprintln(os.Stderr, err.Error())
|
|
}
|
|
|
|
amino := codec.NewLegacyAmino()
|
|
|
|
std.RegisterInterfaces(interfaceRegistry)
|
|
std.RegisterLegacyAminoCodec(amino)
|
|
|
|
cdc := codec.NewProtoCodec(interfaceRegistry)
|
|
msgServiceRouter := baseapp.NewMsgServiceRouter()
|
|
grpcQueryRouter := baseapp.NewGRPCQueryRouter()
|
|
app := &App{
|
|
storeKeys: nil,
|
|
interfaceRegistry: interfaceRegistry,
|
|
cdc: cdc,
|
|
amino: amino,
|
|
basicManager: module.BasicManager{},
|
|
msgServiceRouter: msgServiceRouter,
|
|
grpcQueryRouter: grpcQueryRouter,
|
|
}
|
|
appBuilder := &AppBuilder{app}
|
|
|
|
return cdc, amino, appBuilder, msgServiceRouter, grpcQueryRouter, appModule{app}, protoFiles, protoTypes, nil
|
|
}
|
|
|
|
type AppInputs struct {
|
|
depinject.In
|
|
|
|
AppConfig *appv1alpha1.Config `optional:"true"`
|
|
Config *runtimev1alpha1.Module
|
|
AppBuilder *AppBuilder
|
|
Modules map[string]appmodule.AppModule
|
|
CustomModuleBasics map[string]module.AppModuleBasic `optional:"true"`
|
|
BaseAppOptions []BaseAppOption
|
|
InterfaceRegistry codectypes.InterfaceRegistry
|
|
LegacyAmino *codec.LegacyAmino
|
|
Logger log.Logger
|
|
}
|
|
|
|
func SetupAppBuilder(inputs AppInputs) {
|
|
app := inputs.AppBuilder.app
|
|
app.baseAppOptions = inputs.BaseAppOptions
|
|
app.config = inputs.Config
|
|
app.appConfig = inputs.AppConfig
|
|
app.logger = inputs.Logger
|
|
app.ModuleManager = module.NewManagerFromMap(inputs.Modules)
|
|
|
|
for name, mod := range inputs.Modules {
|
|
if customBasicMod, ok := inputs.CustomModuleBasics[name]; ok {
|
|
app.basicManager[name] = customBasicMod
|
|
customBasicMod.RegisterInterfaces(inputs.InterfaceRegistry)
|
|
customBasicMod.RegisterLegacyAminoCodec(inputs.LegacyAmino)
|
|
continue
|
|
}
|
|
|
|
coreAppModuleBasic := module.CoreAppModuleBasicAdaptor(name, mod)
|
|
app.basicManager[name] = coreAppModuleBasic
|
|
coreAppModuleBasic.RegisterInterfaces(inputs.InterfaceRegistry)
|
|
coreAppModuleBasic.RegisterLegacyAminoCodec(inputs.LegacyAmino)
|
|
}
|
|
}
|
|
|
|
func ProvideInterfaceRegistry(addressCodec address.Codec, validatorAddressCodec ValidatorAddressCodec, customGetSigners []signing.CustomGetSigner) (codectypes.InterfaceRegistry, error) {
|
|
signingOptions := signing.Options{
|
|
AddressCodec: addressCodec,
|
|
ValidatorAddressCodec: validatorAddressCodec,
|
|
}
|
|
for _, signer := range customGetSigners {
|
|
signingOptions.DefineCustomGetSigners(signer.MsgType, signer.Fn)
|
|
}
|
|
|
|
interfaceRegistry, err := codectypes.NewInterfaceRegistryWithOptions(codectypes.InterfaceRegistryOptions{
|
|
ProtoFiles: proto.HybridResolver,
|
|
SigningOptions: signingOptions,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err := interfaceRegistry.SigningContext().Validate(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return interfaceRegistry, nil
|
|
}
|
|
|
|
func registerStoreKey(wrapper *AppBuilder, key storetypes.StoreKey) {
|
|
wrapper.app.storeKeys = append(wrapper.app.storeKeys, key)
|
|
}
|
|
|
|
func storeKeyOverride(config *runtimev1alpha1.Module, moduleName string) *runtimev1alpha1.StoreKeyConfig {
|
|
for _, cfg := range config.OverrideStoreKeys {
|
|
if cfg.ModuleName == moduleName {
|
|
return cfg
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func ProvideKVStoreKey(config *runtimev1alpha1.Module, key depinject.ModuleKey, app *AppBuilder) *storetypes.KVStoreKey {
|
|
if slices.Contains(config.SkipStoreKeys, key.Name()) {
|
|
return nil
|
|
}
|
|
|
|
override := storeKeyOverride(config, key.Name())
|
|
|
|
var storeKeyName string
|
|
if override != nil {
|
|
storeKeyName = override.KvStoreKey
|
|
} else {
|
|
storeKeyName = key.Name()
|
|
}
|
|
|
|
storeKey := storetypes.NewKVStoreKey(storeKeyName)
|
|
registerStoreKey(app, storeKey)
|
|
return storeKey
|
|
}
|
|
|
|
func ProvideTransientStoreKey(config *runtimev1alpha1.Module, key depinject.ModuleKey, app *AppBuilder) *storetypes.TransientStoreKey {
|
|
if slices.Contains(config.SkipStoreKeys, key.Name()) {
|
|
return nil
|
|
}
|
|
|
|
storeKey := storetypes.NewTransientStoreKey(fmt.Sprintf("transient:%s", key.Name()))
|
|
registerStoreKey(app, storeKey)
|
|
return storeKey
|
|
}
|
|
|
|
func ProvideMemoryStoreKey(config *runtimev1alpha1.Module, key depinject.ModuleKey, app *AppBuilder) *storetypes.MemoryStoreKey {
|
|
if slices.Contains(config.SkipStoreKeys, key.Name()) {
|
|
return nil
|
|
}
|
|
|
|
storeKey := storetypes.NewMemoryStoreKey(fmt.Sprintf("memory:%s", key.Name()))
|
|
registerStoreKey(app, storeKey)
|
|
return storeKey
|
|
}
|
|
|
|
func ProvideGenesisTxHandler(appBuilder *AppBuilder) genesis.TxHandler {
|
|
return appBuilder.app
|
|
}
|
|
|
|
func ProvideKVStoreService(config *runtimev1alpha1.Module, key depinject.ModuleKey, app *AppBuilder) store.KVStoreService {
|
|
storeKey := ProvideKVStoreKey(config, key, app)
|
|
return kvStoreService{key: storeKey}
|
|
}
|
|
|
|
func ProvideMemoryStoreService(config *runtimev1alpha1.Module, key depinject.ModuleKey, app *AppBuilder) store.MemoryStoreService {
|
|
storeKey := ProvideMemoryStoreKey(config, key, app)
|
|
return memStoreService{key: storeKey}
|
|
}
|
|
|
|
func ProvideTransientStoreService(config *runtimev1alpha1.Module, key depinject.ModuleKey, app *AppBuilder) store.TransientStoreService {
|
|
storeKey := ProvideTransientStoreKey(config, key, app)
|
|
return transientStoreService{key: storeKey}
|
|
}
|
|
|
|
func ProvideEventService() event.Service {
|
|
return EventService{}
|
|
}
|
|
|
|
func ProvideCometInfoService() comet.BlockInfoService {
|
|
return cometInfoService{}
|
|
}
|
|
|
|
func ProvideHeaderInfoService(app *AppBuilder) header.Service {
|
|
return headerInfoService{}
|
|
}
|
|
|
|
func ProvideBasicManager(app *AppBuilder) module.BasicManager {
|
|
return app.app.basicManager
|
|
}
|
|
|
|
type (
|
|
// ValidatorAddressCodec is an alias for address.Codec for validator addresses.
|
|
ValidatorAddressCodec address.Codec
|
|
|
|
// ConsensusAddressCodec is an alias for address.Codec for validator consensus addresses.
|
|
ConsensusAddressCodec address.Codec
|
|
)
|
|
|
|
type AddressCodecInputs struct {
|
|
depinject.In
|
|
|
|
AuthConfig *authmodulev1.Module `optional:"true"`
|
|
StakingConfig *stakingmodulev1.Module `optional:"true"`
|
|
|
|
AddressCodecFactory func() address.Codec `optional:"true"`
|
|
ValidatorAddressCodecFactory func() ValidatorAddressCodec `optional:"true"`
|
|
ConsensusAddressCodecFactory func() ConsensusAddressCodec `optional:"true"`
|
|
}
|
|
|
|
// ProvideAddressCodec provides an address.Codec to the container for any
|
|
// modules that want to do address string <> bytes conversion.
|
|
func ProvideAddressCodec(in AddressCodecInputs) (address.Codec, ValidatorAddressCodec, ConsensusAddressCodec) {
|
|
if in.AddressCodecFactory != nil && in.ValidatorAddressCodecFactory != nil && in.ConsensusAddressCodecFactory != nil {
|
|
return in.AddressCodecFactory(), in.ValidatorAddressCodecFactory(), in.ConsensusAddressCodecFactory()
|
|
}
|
|
|
|
if in.AuthConfig == nil || in.AuthConfig.Bech32Prefix == "" {
|
|
panic("auth config bech32 prefix cannot be empty if no custom address codec is provided")
|
|
}
|
|
|
|
if in.StakingConfig == nil {
|
|
in.StakingConfig = &stakingmodulev1.Module{}
|
|
}
|
|
|
|
if in.StakingConfig.Bech32PrefixValidator == "" {
|
|
in.StakingConfig.Bech32PrefixValidator = fmt.Sprintf("%svaloper", in.AuthConfig.Bech32Prefix)
|
|
}
|
|
|
|
if in.StakingConfig.Bech32PrefixConsensus == "" {
|
|
in.StakingConfig.Bech32PrefixConsensus = fmt.Sprintf("%svalcons", in.AuthConfig.Bech32Prefix)
|
|
}
|
|
|
|
return addresscodec.NewBech32Codec(in.AuthConfig.Bech32Prefix),
|
|
addresscodec.NewBech32Codec(in.StakingConfig.Bech32PrefixValidator),
|
|
addresscodec.NewBech32Codec(in.StakingConfig.Bech32PrefixConsensus)
|
|
}
|