Skip to content

Commit

Permalink
refactor(appconfig)!: simplify app config (#19040)
Browse files Browse the repository at this point in the history
  • Loading branch information
julienrbrt authored Jan 13, 2024
1 parent af41599 commit 7d9dc39
Show file tree
Hide file tree
Showing 76 changed files with 1,769 additions and 1,611 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ Every Module contains its own CHANGELOG.md. Please refer to the module you are i
* (types) [#18695](https://github.com/cosmos/cosmos-sdk/pull/18695) Removed global configuration for txEncoder.
* (server) [#18909](https://github.com/cosmos/cosmos-sdk/pull/18909) Remove configuration endpoint on grpc reflection endpoint in favour of auth module bech32prefix endpoint already exposed.

### Client Breaking Changes

* (runtime) [#19040](https://github.com/cosmos/cosmos-sdk/pull/19040) Simplify app config implementation and deprecate `/cosmos/app/v1alpha1/config` query.

### CLI Breaking Changes

* (server) [#18303](https://github.com/cosmos/cosmos-sdk/pull/18303) `appd export` has moved with other genesis commands, use `appd genesis export` instead.
Expand Down
9 changes: 7 additions & 2 deletions UPGRADING.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ for more details.

### Params

* Params Migrations were removed. It is required to migrate to 0.50 prior to upgrading to .51.
* Params migrations were removed. It is required to migrate to 0.50 prior to upgrading to v0.51.

### SimApp

Expand Down Expand Up @@ -112,13 +112,18 @@ clientCtx = clientCtx.

Refer to SimApp `root_v2.go` and `root.go` for an example with an app v2 and a legacy app.

#### Dependency Injection

<!-- explain app_config.go changes -->

### Modules

#### `**all**`

##### Dependency Injection

Previously `cosmossdk.io/core` held functions `Invoke`, `Provide` and `Register` were moved to `cosmossdk.io/depinject/appmodule`. All modules using dependency injection must update their imports.
Previously `cosmossdk.io/core` held functions `Invoke`, `Provide` and `Register` were moved to `cosmossdk.io/depinject/appconfig`.
All modules using dependency injection must update their imports.

##### Genesis Interface

Expand Down
32 changes: 16 additions & 16 deletions api/cosmos/app/v1alpha1/query.pulsar.go

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

3 changes: 3 additions & 0 deletions api/cosmos/app/v1alpha1/query_grpc.pb.go

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

3 changes: 1 addition & 2 deletions core/appmodule/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,4 @@

This package defines what is needed for an module to be used in the Cosmos SDK.


If you are looking at integrating Dependency injection into your module please see [depinject appmodule documentation](../../depinject/appmodule/README.md)
If you are looking at integrating Dependency injection into your module please see [depinject appconfig documentation](../../depinject/appconfig/README.md)
102 changes: 51 additions & 51 deletions depinject/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ sidebar_position: 1

`depinject` is particularly useful for developing blockchain applications:

* With multiple interdependent components, modules, or services. Helping manage their dependencies effectively.
* That require decoupling of these components, making it easier to test, modify, or replace individual parts without affecting the entire system.
* That are wanting to simplify the setup and initialisation of modules and their dependencies by reducing boilerplate code and automating dependency management.
* With multiple interdependent components, modules, or services. Helping manage their dependencies effectively.
* That require decoupling of these components, making it easier to test, modify, or replace individual parts without affecting the entire system.
* That are wanting to simplify the setup and initialisation of modules and their dependencies by reducing boilerplate code and automating dependency management.

By using `depinject`, developers can achieve:

* Cleaner and more organised code.
* Improved modularity and maintainability.
* A more maintainable and modular structure for their blockchain applications, ultimately enhancing development velocity and code quality.
* Cleaner and more organised code.
* Improved modularity and maintainability.
* A more maintainable and modular structure for their blockchain applications, ultimately enhancing development velocity and code quality.

* [Go Doc](https://pkg.go.dev/cosmossdk.io/depinject)

Expand All @@ -38,9 +38,9 @@ Example:
package main

import (
"fmt"
"fmt"

"cosmossdk.io/depinject"
"cosmossdk.io/depinject"
)

type AnotherInt int
Expand All @@ -49,21 +49,21 @@ func GetInt() int { return 1 }
func GetAnotherInt() AnotherInt { return 2 }

func main() {
var (
x int
y AnotherInt
)

fmt.Printf("Before (%v, %v)\n", x, y)
depinject.Inject(
depinject.Provide(
GetInt,
GetAnotherInt,
),
&x,
&y,
)
fmt.Printf("After (%v, %v)\n", x, y)
var (
x int
y AnotherInt
)

fmt.Printf("Before (%v, %v)\n", x, y)
depinject.Inject(
depinject.Provide(
GetInt,
GetAnotherInt,
),
&x,
&y,
)
fmt.Printf("After (%v, %v)\n", x, y)
}
```

Expand All @@ -83,11 +83,11 @@ Consider the following example:
package duck

type Duck interface {
quack()
quack()
}

type AlsoDuck interface {
quack()
quack()
}

type Mallard struct{}
Expand All @@ -97,23 +97,23 @@ func (duck Mallard) quack() {}
func (duck Canvasback) quack() {}

type Pond struct {
Duck AlsoDuck
Duck AlsoDuck
}
```

And the following provider functions:

```go
func GetMallard() duck.Mallard {
return Mallard{}
return Mallard{}
}

func GetPond(duck Duck) Pond {
return Pond{Duck: duck}
return Pond{Duck: duck}
}

func GetCanvasback() Canvasback {
return Canvasback{}
return Canvasback{}
}
```

Expand All @@ -124,9 +124,9 @@ var pond Pond

depinject.Inject(
depinject.Provide(
GetMallard,
GetPond,
),
GetMallard,
GetPond,
),
&pond)
```

Expand All @@ -138,12 +138,12 @@ However, if there are multiple implementations of the `Duck` interface, as in th
var pond Pond

depinject.Inject(
depinject.Provide(
GetMallard,
GetCanvasback,
GetPond,
),
&pond)
depinject.Provide(
GetMallard,
GetCanvasback,
GetPond,
),
&pond)
```

A specific binding preference for `Duck` is required.
Expand All @@ -154,21 +154,21 @@ In the above situation registering a binding for a given interface binding may l

```go
depinject.Inject(
depinject.Configs(
depinject.BindInterface(
"duck/duck.Duck",
"duck/duck.Mallard",
),
depinject.Provide(
GetMallard,
GetCanvasback,
GetPond,
),
),
&pond)
depinject.Configs(
depinject.BindInterface(
"duck/duck.Duck",
"duck/duck.Mallard",
),
depinject.Provide(
GetMallard,
GetCanvasback,
GetPond,
),
),
&pond)
```

Now `depinject` has enough information to provide `Mallard` as an input to `APond`.
Now `depinject` has enough information to provide `Mallard` as an input to `APond`.

### Full example in real app

Expand Down
26 changes: 13 additions & 13 deletions depinject/appmodule/README.md → depinject/appconfig/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@ message Module {

Once we have a module config object, we need to register depinject providers and invokers for the module using the `cosmossdk.io/core/appmodule` package.

At the most basic level, we must define an `init` function in the package listed as the `go_import` in the module descriptor. This `init` function must call `appmodule.Register` with an empty instance of the config object and some options for initializing the module, ex:
At the most basic level, we must define an `init` function in the package listed as the `go_import` in the module descriptor. This `init` function must call `appconfig.RegisterModule` with an empty instance of the config object and some options for initializing the module, ex:

```go
func init() {
appmodule.Register(&modulev1.Module{},
appconfig.RegisterModule(&modulev1.Module{},
// options
)
}
Expand All @@ -53,14 +53,14 @@ A `depinject` "provider" is a function which takes dependencies from other modul
other modules to use as dependencies. A `depinject` "invoker" is function which takes optional dependencies as inputs,
returns no outputs, and is run at the end of initializing the dependency graph. Providers are much more common than
invokers and should be the preferred method of wiring up modules when possible. Providers and invokers can be registered
for modules by using `appmodule.Provide` and `appmodule.Invoke` to create options which get passed
to `appmodule.Register` in the module `init` function, ex:
for modules by using `appconfig.Provide` and `appconfig.Invoke` to create options which get passed
to `appconfig.RegisterModule` in the module `init` function, ex:

```go
func init() {
appmodule.Register(&modulev1.Module{},
appmodule.Provide(provideSomething, provideSomethingElse),
appmodule.Invoke(invokeSomething),
appconfig.RegisterModule(&modulev1.Module{},
appconfig.Provide(provideSomething, provideSomethingElse),
appconfig.Invoke(invokeSomething),
)
}
```
Expand All @@ -79,7 +79,7 @@ func init() {
#### Regular Golang Types

Regular golang types (besides the special cases described above) can be provided as both input and output parameters
to providers and invokers. For `depinject` to match an output parameter of one provider to an input parameter of
to providers and invokers. For `depinject` to match an output parameter of one provider to an input parameter of
another, there must be an exact match for the type unless the input parameter is an input type. For instance, if
a provider defines a dependency on `Foo` and some module provides `*Foo`, these two types will not match and there
will be an error.
Expand Down Expand Up @@ -133,7 +133,7 @@ bet.
If `depinject.ModuleKey` is used as input parameter for a provider, the provider function will be treated as a
"module-scoped provider" which means that the provider function will be called exactly once every time
one of its outputs is needed by a module so that the provider can provide a unique instance of the dependency to
each module.
each module.

Module-scoped dependencies should be used to provide dependencies which are private and unique to each module. Examples
of these are store keys and param subspaces.
Expand Down Expand Up @@ -177,7 +177,7 @@ when ordering *really* doesn't matter (which is rare).

### Resolving Circular Dependencies

Circular dependencies are inevitable to crop up and there are ways to avoid them. While `depinject` cannot handle
Circular dependencies are inevitable to crop up and there are ways to avoid them. While `depinject` cannot handle
circular dependency graphs of providers, many of the above tools are designed to enable satisfying circular dependencies
between modules.

Expand All @@ -193,7 +193,7 @@ the staking module can define an invoker which depends on `map[string]StakingHoo
satisfy this dependency graph which allows staking and slashing to depend on each other in this order:

* provide staking keeper -> slashing keeper
* provide slashing keeper wrapped as `StakingHooksWrapper`
* provide slashing keeper wrapped as `StakingHooksWrapper`
* get `map[string]StakingHooksWrapper` and the staking keeper and wire them together

## 3. Testing and Debugging The Module
Expand All @@ -212,8 +212,8 @@ var appConfig []byte
var AppConfig = appconfig.LoadYAML(appConfig)

func TestModule(t *testing.T) {
var keeper Keeper
assert.NilError(t, depinject.Inject(AppConfig, &keeper))
var keeper Keeper
assert.NilError(t, depinject.Inject(AppConfig, &keeper))
}
```

Expand Down
Loading

0 comments on commit 7d9dc39

Please sign in to comment.