Skip to content

Commit

Permalink
Merge branch 'main' into facu/refactor-rejected-prop-deposits
Browse files Browse the repository at this point in the history
  • Loading branch information
facundomedica committed May 10, 2022
2 parents f6b081a + 90272e3 commit 2b0e99b
Show file tree
Hide file tree
Showing 22 changed files with 3,295 additions and 24 deletions.
6 changes: 2 additions & 4 deletions api/cosmos/app/v1alpha1/module.pulsar.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 18 additions & 6 deletions api/cosmos/auth/v1beta1/query.pulsar.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 14 additions & 2 deletions api/cosmos/auth/v1beta1/query_grpc.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions api/cosmos/upgrade/v1beta1/query_grpc.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions core/Makefile
@@ -0,0 +1,2 @@
codegen:
(cd internal; buf generate)
11 changes: 11 additions & 0 deletions core/README.md
@@ -0,0 +1,11 @@
# Cosmos SDK Core

The [cosmossdk.io/core](https://pkg.go.dev/cosmossdk.io/core) go module defines
"core" functionality for the Cosmos SDK.

Currently functionality for registering modules using the [appmodule](https://pkg.go.dev/cosmossdk.io/core/appmodule)
package and composing apps using the [appconfig](https://pkg.go.dev/cosmossdk.io/core/appconfig)
package is provided.

In the future core functionality for building Cosmos SDK app modules will be
provided in this go module.
111 changes: 111 additions & 0 deletions core/appconfig/config.go
@@ -0,0 +1,111 @@
package appconfig

import (
"fmt"
"reflect"
"strings"

"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
"google.golang.org/protobuf/types/known/anypb"
"sigs.k8s.io/yaml"

"github.com/cosmos/cosmos-sdk/container"

appv1alpha1 "github.com/cosmos/cosmos-sdk/api/cosmos/app/v1alpha1"

"cosmossdk.io/core/internal"
)

// LoadJSON loads an app config in JSON format.
func LoadJSON(bz []byte) container.Option {
config := &appv1alpha1.Config{}
err := protojson.Unmarshal(bz, config)
if err != nil {
return container.Error(err)
}

return Compose(config)
}

// LoadYAML loads an app config in YAML format.
func LoadYAML(bz []byte) container.Option {
j, err := yaml.YAMLToJSON(bz)
if err != nil {
return container.Error(err)
}

return LoadJSON(j)
}

// Compose composes a v1alpha1 app config into a container option by resolving
// the required modules and composing their options.
func Compose(appConfig *appv1alpha1.Config) container.Option {
opts := []container.Option{
container.Supply(appConfig),
}

for _, module := range appConfig.Modules {
if module.Name == "" {
return container.Error(fmt.Errorf("module is missing name"))
}

if module.Config == nil {
return container.Error(fmt.Errorf("module %q is missing a config object", module.Name))
}

msgType, err := protoregistry.GlobalTypes.FindMessageByURL(module.Config.TypeUrl)
if err != nil {
return container.Error(err)
}

modules, err := internal.ModulesByProtoMessageName()
if err != nil {
return container.Error(err)
}

init, ok := modules[msgType.Descriptor().FullName()]
if !ok {
modDesc := proto.GetExtension(msgType.Descriptor().Options(), appv1alpha1.E_Module).(*appv1alpha1.ModuleDescriptor)
if modDesc == nil {
return container.Error(fmt.Errorf("no module registered for type URL %s and that protobuf type does not have the option %s\n\n%s",
module.Config.TypeUrl, appv1alpha1.E_Module.TypeDescriptor().FullName(), dumpRegisteredModules(modules)))
}

return container.Error(fmt.Errorf("no module registered for type URL %s, did you forget to import %s\n\n%s",
module.Config.TypeUrl, modDesc.GoImport, dumpRegisteredModules(modules)))
}

config := init.ConfigProtoMessage.ProtoReflect().Type().New().Interface()
err = anypb.UnmarshalTo(module.Config, config, proto.UnmarshalOptions{})
if err != nil {

return container.Error(err)
}

opts = append(opts, container.Provide(container.ProviderDescriptor{
Inputs: nil,
Outputs: []container.ProviderOutput{{Type: init.ConfigGoType}},
Fn: func(values []reflect.Value) ([]reflect.Value, error) {
return []reflect.Value{reflect.ValueOf(config)}, nil
},
Location: container.LocationFromCaller(0),
}))

for _, provider := range init.Providers {
opts = append(opts, container.ProvideInModule(module.Name, provider))
}
}

return container.Options(opts...)
}

func dumpRegisteredModules(modules map[protoreflect.FullName]*internal.ModuleInitializer) string {
var mods []string
for name := range modules {
mods = append(mods, " "+string(name))
}
return fmt.Sprintf("registered modules are:\n%s", strings.Join(mods, "\n"))
}
104 changes: 104 additions & 0 deletions core/appconfig/config_test.go
@@ -0,0 +1,104 @@
package appconfig_test

import (
"bytes"
"reflect"
"testing"

"gotest.tools/v3/assert"

"github.com/cosmos/cosmos-sdk/container"

"cosmossdk.io/core/appconfig"
"cosmossdk.io/core/appmodule"
"cosmossdk.io/core/internal"
"cosmossdk.io/core/internal/testpb"
_ "cosmossdk.io/core/internal/testpb"
)

func expectContainerErrorContains(t *testing.T, option container.Option, contains string) {
t.Helper()
err := container.Build(option)
assert.ErrorContains(t, err, contains)
}

func TestCompose(t *testing.T) {
opt := appconfig.LoadJSON([]byte(`{"modules":[{}]}`))
expectContainerErrorContains(t, opt, "module is missing name")

opt = appconfig.LoadJSON([]byte(`{"modules":[{"name": "a"}]}`))
expectContainerErrorContains(t, opt, `module "a" is missing a config object`)

opt = appconfig.LoadYAML([]byte(`
modules:
- name: a
config:
"@type": testpb.ModuleFoo
`))
expectContainerErrorContains(t, opt, `unable to resolve`)

opt = appconfig.LoadYAML([]byte(`
modules:
- name: a
config:
"@type": cosmos.app.v1alpha1.Config # this is not actually a module config type!
`))
expectContainerErrorContains(t, opt, "does not have the option cosmos.app.v1alpha1.module")
expectContainerErrorContains(t, opt, "registered modules are")
expectContainerErrorContains(t, opt, "testpb.TestModuleA")

opt = appconfig.LoadYAML([]byte(`
modules:
- name: a
config:
"@type": testpb.TestUnregisteredModule
`))
expectContainerErrorContains(t, opt, "did you forget to import cosmossdk.io/core/internal/testpb")
expectContainerErrorContains(t, opt, "registered modules are")
expectContainerErrorContains(t, opt, "testpb.TestModuleA")

var app testpb.App
opt = appconfig.LoadYAML([]byte(`
modules:
- name: runtime
config:
"@type": testpb.TestRuntimeModule
- name: a
config:
"@type": testpb.TestModuleA
- name: b
config:
"@type": testpb.TestModuleB
`))
assert.NilError(t, container.Build(opt, &app))
buf := &bytes.Buffer{}
app(buf)
const expected = `got store key a
got store key b
running module handler a
result: hello
running module handler b
result: goodbye
`
assert.Equal(t, expected, buf.String())

// module registration failures:
appmodule.Register(&testpb.TestNoModuleOptionModule{})
opt = appconfig.LoadYAML([]byte(`
modules:
- name: a
config:
"@type": testpb.TestNoGoImportModule
`))
expectContainerErrorContains(t, opt, "module should have the option cosmos.app.v1alpha1.module")

internal.ModuleRegistry = map[reflect.Type]*internal.ModuleInitializer{} // reset module registry
appmodule.Register(&testpb.TestNoGoImportModule{})
opt = appconfig.LoadYAML([]byte(`
modules:
- name: a
config:
"@type": testpb.TestNoGoImportModule
`))
expectContainerErrorContains(t, opt, "module should have ModuleDescriptor.go_import specified")
}
3 changes: 3 additions & 0 deletions core/appconfig/doc.go
@@ -0,0 +1,3 @@
// Package appconfig defines functionality for loading declarative Cosmos SDK
// app configurations.
package appconfig
5 changes: 5 additions & 0 deletions core/appmodule/doc.go
@@ -0,0 +1,5 @@
// Package appmodule defines the functionality for registering Cosmos SDK app
// modules that are assembled using the github.com/cosmos/cosmos-sdk/container
// dependency injection system and the declarative app configuration format
// handled by the appconfig package.
package appmodule

0 comments on commit 2b0e99b

Please sign in to comment.