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

docs: add ADR 063: core API ADR + update app wiring ADR #12972

Merged
merged 31 commits into from
Jan 27, 2023
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
19c735e
docs: add core API ADR
aaronc Aug 19, 2022
95e5281
updates
aaronc Aug 19, 2022
77d6ea1
updates
aaronc Aug 19, 2022
b4040de
updates
aaronc Aug 19, 2022
1b2a02a
updates
aaronc Aug 19, 2022
736f50a
updates
aaronc Aug 19, 2022
40f531e
Merge branch 'main' into aaronc/core-api-adr
aaronc Aug 19, 2022
45bcd8d
updates based on reviews
aaronc Aug 25, 2022
30039ff
updates based on reviews
aaronc Aug 25, 2022
d7ce68a
Merge branch 'main' into aaronc/core-api-adr
aaronc Aug 25, 2022
28c8046
updates based on reviews
aaronc Aug 25, 2022
7d1f682
typo
aaronc Aug 25, 2022
c11a992
API simplifications
aaronc Aug 29, 2022
1175337
ADR-033 updates
aaronc Aug 29, 2022
e9b24e0
update events spec
aaronc Aug 29, 2022
8da33ef
update bundle service
aaronc Aug 29, 2022
f8212ca
Update docs/architecture/adr-061-core-module-api.md
aaronc Aug 30, 2022
b13cb98
Update docs/architecture/adr-061-core-module-api.md
aaronc Aug 30, 2022
5812828
fix indentation
aaronc Aug 31, 2022
09fdad9
Merge remote-tracking branch 'origin/aaronc/core-api-adr' into aaronc…
aaronc Aug 31, 2022
64f2d11
Update docs/architecture/adr-061-core-module-api.md
aaronc Aug 31, 2022
1fb3cba
Merge branch 'main' of github.com:cosmos/cosmos-sdk into aaronc/core-…
aaronc Dec 8, 2022
83a9060
revert
aaronc Dec 8, 2022
2cbd793
update to 063
aaronc Dec 8, 2022
aaf397b
updates
aaronc Dec 8, 2022
0e9bbe1
Merge branch 'main' of github.com:cosmos/cosmos-sdk into aaronc/core-…
aaronc Jan 24, 2023
3432806
updates
aaronc Jan 24, 2023
f330fa3
updates
aaronc Jan 24, 2023
e43258d
Merge branch 'main' into aaronc/core-api-adr
aaronc Jan 24, 2023
bbb6ba8
Merge branch 'main' into aaronc/core-api-adr
aaronc Jan 26, 2023
c216753
Merge branch 'main' into aaronc/core-api-adr
tac0turtle Jan 27, 2023
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
1 change: 1 addition & 0 deletions docs/architecture/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ When writing ADRs, follow the same best practices for writing RFCs. When writing
* [ADR 046: Module Params](./adr-046-module-params.md)
* [ADR 057: App Wiring Part I](./adr-057-app-wiring-1.md)
* [ADR 059: Test Scopes](./adr-059-test-scopes.md)
* [ADR 061: Core Module API](./adr-61-core-module-api.md)

### Draft

Expand Down
94 changes: 74 additions & 20 deletions docs/architecture/adr-057-app-wiring-1.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
# ADR 057: App Wiring Part I
# ADR 057: App Wiring

## Changelog

* 2022-05-04: Initial Draft
* 2022-08-19: Updates to align with [ADR 061](./adr-061-core-module-api.md)

## Status

PROPOSED Partially Implemented
PROPOSED Implemented

## Abstract

Expand Down Expand Up @@ -54,7 +55,7 @@ features:

* dependency resolution and provision through functional constructors, ex: `func(need SomeDep) (AnotherDep, error)`
* dependency injection `In` and `Out` structs which support `optional` dependencies
* grouped-dependencies (many-per-container) through the `AutoGroupType` tag interface
* grouped-dependencies (many-per-container) through the `ManyPerContainerType` tag interface
* module-scoped dependencies via `ModuleKey`s (where each module gets a unique dependency)
* one-per-module dependencies through the `OnePerModuleType` tag interface
* sophisticated debugging information and container visualization via GraphViz
Expand All @@ -63,7 +64,7 @@ Here are some examples of how these would be used in an SDK module:

* `StoreKey` could be a module-scoped dependency which is unique per module
* a module's `AppModule` instance (or the equivalent) could be a `OnePerModuleType`
* CLI commands could be provided with `AutoGroupType`s
* CLI commands could be provided with `ManyPerContainerType`s

Note that even though dependency resolution is dynamic and based on reflection, which could be considered a pitfall
of this approach, the entire dependency graph should be resolved immediately on app startup and only gets resolved
Expand Down Expand Up @@ -94,7 +95,9 @@ message ModuleConfig {
The configuration for every module is itself a protobuf message and modules will be identified and loaded based
on the protobuf type URL of their config object (ex. `cosmos.bank.module.v1.Module`). Modules are given a unique short `name`
to share resources across different versions of the same module which might have a different protobuf package
versions (ex. `cosmos.bank.module.v2.Module`).
versions (ex. `cosmos.bank.module.v2.Module`). All module config objects should define the `cosmos.app.v1alpha1.module`
descriptor option which will provide additional useful metadata for the framework and which can also be indexed
in module registries.

An example app config in YAML might look like this:

Expand Down Expand Up @@ -178,39 +181,43 @@ Ex:

```go
func init() {
module.Register("cosmos.bank.module.v1.Module",
module.Types(
appmodule.Register("cosmos.bank.module.v1.Module",
appmodule.Types(
types.Types_tx_proto,
types.Types_query_proto,
types.Types_types_proto,
),
module.Provide(
appmodule.Provide(
provideBankModule,
)
)
}

type inputs struct {
type Inputs struct {
container.In

AuthKeeper auth.Keeper
DB ormdb.ModuleDB
}

type outputs struct {
type Outputs struct {
Keeper bank.Keeper
Handler app.Handler // app.Handler is a hypothetical type which replaces the current AppModule
Handler *appmodule.Handler
}

func provideBankModule(config types.Module, inputs) (outputs, error) { ... }
func ProvideBankModule(config *bankmodulev1.Module, Inputs) (Outputs, error) { ... }
```

Note that in this module, a module configuration object *cannot* register different dependency providers based on the
configuration. This is intentional because it allows us to know globally which modules provide which dependencies. This
Note that in this module, a module configuration object *cannot* register different dependency providers at runtime
based on the configuration. This is intentional because it allows us to know globally which modules provide which
dependencies, and it will also allow us to do code generation of the whole app initialization. This
can help us figure out issues with missing dependencies in an app config if the needed modules are loaded at runtime.
In cases where required modules are not loaded at runtime, it may be possible to guide users to the correct module if
through a global Cosmos SDK module registry.

The `*appmodule.Handler` type referenced above is a replacement for the legacy `AppModule` framework, and
described in [ADR 061: Core Module API](./adr-061-core-module-api.md).

### New `app.go`

With this setup, `app.go` might now look something like this:
Expand Down Expand Up @@ -238,11 +245,57 @@ func main() {
### Application to existing SDK modules

So far we have described a system which is largely agnostic to the specifics of the SDK such as store keys, `AppModule`,
`BaseApp`, etc. A second app wiring ADR will be created which outlines the details of how this app wiring system will
be applied to the existing SDK in a way that:
`BaseApp`, etc. Improvements to these parts of the framework that integrate with the general app wiring framework
defined here are described in [ADR 061: Core Module API](./adr-061-core-module-api.md).

### Registration of Inter-Module Hooks

Some modules define a hooks interface (ex. `StakingHooks`) which allows one module to call back into another module
when certain events happen.

With the app wiring framework, these hooks interfaces can be defined as a `OnePerModuleType`s and then the module
which consumes these hooks can collect these hooks as a map of module name to hook type (ex. `map[string]FooHooks`). Ex:
```go
func init() {
appmodule.Register(
&foomodulev1.Module{},
appmodule.Invoke(InvokeSetFooHooks),
...
)
}
func InvokeSetFooHooks(
keeper *keeper.Keeper,
fooHooks map[string]FooHooks,
) error {
for k in sort.Strings(maps.Keys(fooHooks)) {
keeper.AddFooHooks(fooHooks[k])
}
}
```

Optionally, the module consuming hooks can allow app's to define an order for calling these hooks based on module name
in its config object.

An alternative way for registering hooks via reflection was considered where all keeper types are inspected to see if
they implement the hook interface by the modules exposing hooks. This has the downsides of:
* needing to expose all the keepers of all modules to the module providing hooks,
* not allowing for encapsulating hooks on a different type which doesn't expose all keeper methods,
* harder to know statically which module expose hooks or are checking for them.

With the approach proposed here, hooks registration will be obviously observable in `app.go` if `depinject` codegen
(described below) is used.

Note that event listeners, described in [ADR 061: Core Module API](./adr-061-core-module-api.md), are a more
standardized alternative to hooks with both a simpler declaration and registration system.

### Code Generation

The `depinject` framework will optionally allow the app configuration and dependency injection wiring to be code
generated. This will allow:
* dependency injection wiring to be inspected as regular go code just like the existing `app.go`,
* dependency injection to be opt-in with manual wiring 100% still possible.

1. is as easy to apply to existing modules as possible,
2. while also making it possible to improve existing APIs and minimize long-term technical debt
Code generation requires that all providers and invokers and their parameters are exported and in non-internal packages.

## Consequences

Expand Down Expand Up @@ -272,8 +325,8 @@ registration paradigms. These two methods can live side-by-side for as long as i

## Further Discussions

As mentioned above, a second app wiring ADR will be created to describe more specifics than there is space to go
into here. Further discussions will also happen within the Cosmos SDK Framework Working Group and in https://github.com/cosmos/cosmos-sdk/discussions/10582.
The protobuf type registration system described in this ADR has not been implemented and may need to be reconsidered in
light of code generation. It may be better to do this type registration with a DI provider.

## References

Expand All @@ -283,3 +336,4 @@ into here. Further discussions will also happen within the Cosmos SDK Framework
* https://github.com/google/wire
* https://pkg.go.dev/github.com/cosmos/cosmos-sdk/container
* https://github.com/cosmos/cosmos-sdk/pull/11802
* [ADR 061](./adr-061-core-module-api.md)
Loading