Skip to content

Commit b5205d5

Browse files
committed
fix(x/epochs): di wiring
1 parent b0854ae commit b5205d5

File tree

6 files changed

+299
-11
lines changed

6 files changed

+299
-11
lines changed

simapp/app_di.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ type SimApp struct {
7676
// supplementary keepers
7777
FeeGrantKeeper feegrantkeeper.Keeper
7878
AuthzKeeper authzkeeper.Keeper
79-
EpochsKeeper epochskeeper.Keeper
79+
EpochsKeeper *epochskeeper.Keeper
8080
ProtocolPoolKeeper protocolpoolkeeper.Keeper
8181

8282
// simulation manager
@@ -232,7 +232,12 @@ func NewSimApp(
232232
// NOTE: this is not required apps that don't use the simulator for fuzz testing
233233
// transactions
234234
overrideModules := map[string]module.AppModuleSimulation{
235-
authtypes.ModuleName: auth.NewAppModule(app.appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts, nil),
235+
authtypes.ModuleName: auth.NewAppModule(
236+
app.appCodec,
237+
app.AccountKeeper,
238+
authsims.RandomGenesisAccounts,
239+
nil,
240+
),
236241
}
237242
app.sm = module.NewSimulationManagerFromAppModules(app.ModuleManager.Modules, overrideModules)
238243

x/epochs/README.md

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,174 @@ func (k MyModuleKeeper) AfterEpochEnd(ctx sdk.Context, epochIdentifier string, e
9595
}
9696
```
9797

98+
### Wiring Hooks
99+
100+
**Manual Wiring:**
101+
102+
Import the following:
103+
104+
```go
105+
import (
106+
// ...
107+
"github.com/cosmos/cosmos-sdk/x/epochs"
108+
epochskeeper "github.com/cosmos/cosmos-sdk/x/epochs/keeper"
109+
epochstypes "github.com/cosmos/cosmos-sdk/x/epochs/types"
110+
)
111+
```
112+
113+
Add the epochs keeper to your application struct:
114+
115+
```go
116+
EpochsKeeper epochskeeper.Keeper
117+
```
118+
119+
Add the store key:
120+
121+
```go
122+
keys := storetypes.NewKVStoreKeys(
123+
// ...
124+
epochstypes.StoreKey,
125+
)
126+
```
127+
128+
Instantiate the keeper:
129+
130+
```go
131+
app.EpochsKeeper = epochskeeper.NewKeeper(
132+
runtime.NewKVStoreService(keys[epochstypes.StoreKey]),
133+
appCodec,
134+
)
135+
```
136+
137+
Set up hooks for the epochs keeper:
138+
139+
```go
140+
app.EpochsKeeper.SetHooks(
141+
epochstypes.NewMultiEpochHooks(
142+
// insert epoch hooks receivers here
143+
app.SomeOtherModule
144+
),
145+
)
146+
```
147+
148+
Add the epochs module to the module manager:
149+
150+
```go
151+
app.ModuleManager = module.NewManager(
152+
// ...
153+
epochs.NewAppModule(appCodec, app.EpochsKeeper),
154+
)
155+
```
156+
157+
Add entries for SetOrderBeginBlockers and SetOrderInitGenesis:
158+
159+
```go
160+
app.ModuleManager.SetOrderBeginBlockers(
161+
// ...
162+
epochstypes.ModuleName,
163+
)
164+
```
165+
166+
```go
167+
app.ModuleManager.SetOrderInitGenesis(
168+
// ...
169+
epochstypes.ModuleName,
170+
)
171+
```
172+
173+
**DI Wiring:**
174+
175+
First, set up the keeper for the application.
176+
177+
Import the epochs keeper:
178+
179+
```go
180+
epochskeeper "github.com/cosmos/cosmos-sdk/x/epochs/keeper"
181+
```
182+
183+
Add the keeper to your application struct:
184+
185+
```go
186+
EpochsKeeper *epochskeeper.Keeper // must be a pointer for DI
187+
```
188+
189+
Add the keeper to the depinject system:
190+
191+
```go
192+
depinject.Inject(
193+
appConfig,
194+
&appBuilder,
195+
&app.appCodec,
196+
&app.legacyAmino,
197+
&app.txConfig,
198+
&app.interfaceRegistry,
199+
// ... other modules
200+
&app.EpochsKeeper, // NEW MODULE!
201+
)
202+
```
203+
204+
Next, set up configuration for the module.
205+
206+
Import the following:
207+
208+
```go
209+
import (
210+
epochsmodulev1 "cosmossdk.io/api/cosmos/epochs/module/v1"
211+
212+
_ "github.com/cosmos/cosmos-sdk/x/epochs" // import for side-effects
213+
epochstypes "github.com/cosmos/cosmos-sdk/x/epochs/types"
214+
)
215+
```
216+
217+
Add an entry for BeginBlockers and InitGenesis:
218+
219+
```go
220+
BeginBlockers: []string{
221+
// ...
222+
epochstypes.ModuleName,
223+
},
224+
```
225+
226+
```go
227+
InitGenesis: []string{
228+
// ...
229+
epochstypes.ModuleName,
230+
},
231+
```
232+
233+
Add an entry for epochs in the ModuleConfig:
234+
235+
```go
236+
{
237+
Name: epochstypes.ModuleName,
238+
Config: appconfig.WrapAny(&epochsmodulev1.Module{}),
239+
},
240+
```
241+
242+
depinject can automatically add your hooks to the epochs `Keeper`. For it do so, specify an output of your module with the type `epochtypes.EpochHooksWrapper`, ie:
243+
244+
```go
245+
type TestInputs struct {
246+
depinject.In
247+
}
248+
249+
type TestOutputs struct {
250+
depinject.Out
251+
252+
Hooks types.EpochHooksWrapper
253+
}
254+
255+
func DummyProvider(in TestInputs) TestOutputs {
256+
return TestOutputs{
257+
Hooks: types.EpochHooksWrapper{
258+
EpochHooks: testEpochHooks{},
259+
},
260+
}
261+
}
262+
```
263+
264+
for an example see [`depinject_test.go`](https://github.com/cosmos/cosmos-sdk/tree/main/x/epochs/depinject_test.go)
265+
98266
### Panic isolation
99267

100268
If a given epoch hook panics, its state update is reverted, but we keep

x/epochs/depinject.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,14 @@ type ModuleInputs struct {
3939
type ModuleOutputs struct {
4040
depinject.Out
4141

42-
EpochKeeper keeper.Keeper
42+
EpochKeeper *keeper.Keeper
4343
Module appmodule.AppModule
4444
}
4545

4646
func ProvideModule(in ModuleInputs) ModuleOutputs {
4747
k := keeper.NewKeeper(in.StoreService, in.Cdc)
48-
m := NewAppModule(k)
49-
return ModuleOutputs{EpochKeeper: k, Module: m}
48+
m := NewAppModule(&k)
49+
return ModuleOutputs{EpochKeeper: m.keeper, Module: m}
5050
}
5151

5252
func InvokeSetHooks(keeper *keeper.Keeper, hooks map[string]types.EpochHooksWrapper) error {

x/epochs/depinject_test.go

Lines changed: 106 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,41 @@ import (
66

77
"github.com/stretchr/testify/require"
88

9+
appv1alpha1 "cosmossdk.io/api/cosmos/app/v1alpha1"
10+
bankmodulev1 "cosmossdk.io/api/cosmos/bank/module/v1"
11+
"cosmossdk.io/core/appmodule"
12+
"cosmossdk.io/core/store"
13+
"cosmossdk.io/depinject"
14+
"cosmossdk.io/depinject/appconfig"
915
storetypes "cosmossdk.io/store/types"
1016

17+
modulev1 "cosmossdk.io/api/cosmos/epochs/module/v1"
18+
"github.com/cosmos/cosmos-sdk/codec"
1119
"github.com/cosmos/cosmos-sdk/runtime"
1220
"github.com/cosmos/cosmos-sdk/types/module/testutil"
21+
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
1322
"github.com/cosmos/cosmos-sdk/x/epochs"
1423
"github.com/cosmos/cosmos-sdk/x/epochs/keeper"
1524
"github.com/cosmos/cosmos-sdk/x/epochs/types"
1625
)
1726

27+
var _ types.EpochHooks = testEpochHooks{}
28+
1829
type testEpochHooks struct{}
1930

20-
func (h testEpochHooks) AfterEpochEnd(ctx context.Context, epochIdentifier string, epochNumber int64) error {
31+
func (h testEpochHooks) AfterEpochEnd(
32+
ctx context.Context,
33+
epochIdentifier string,
34+
epochNumber int64,
35+
) error {
2136
return nil
2237
}
2338

24-
func (h testEpochHooks) BeforeEpochStart(ctx context.Context, epochIdentifier string, epochNumber int64) error {
39+
func (h testEpochHooks) BeforeEpochStart(
40+
ctx context.Context,
41+
epochIdentifier string,
42+
epochNumber int64,
43+
) error {
2544
return nil
2645
}
2746

@@ -58,3 +77,88 @@ func TestInvokeSetHooks(t *testing.T) {
5877
require.Equal(t, hook1, multiHooks[0])
5978
require.Equal(t, hook2, multiHooks[1])
6079
}
80+
81+
type TestInputs struct {
82+
depinject.In
83+
}
84+
85+
type TestOutputs struct {
86+
depinject.Out
87+
88+
Hooks types.EpochHooksWrapper
89+
}
90+
91+
func DummyProvider(in TestInputs) TestOutputs {
92+
return TestOutputs{
93+
Hooks: types.EpochHooksWrapper{
94+
EpochHooks: testEpochHooks{},
95+
},
96+
}
97+
}
98+
99+
func ProvideDeps(depinject.In) struct {
100+
depinject.Out
101+
Cdc codec.Codec
102+
StoreService store.KVStoreService
103+
} {
104+
encCfg := testutil.MakeTestEncodingConfig()
105+
106+
key := storetypes.NewKVStoreKey(types.StoreKey)
107+
return struct {
108+
depinject.Out
109+
Cdc codec.Codec
110+
StoreService store.KVStoreService
111+
}{
112+
Cdc: encCfg.Codec,
113+
StoreService: runtime.NewKVStoreService(key),
114+
}
115+
}
116+
117+
func TestDepinject(t *testing.T) {
118+
/// we just need any module's proto to register the provider here, no specific reason to use bank
119+
appconfig.RegisterModule(&bankmodulev1.Module{}, appconfig.Provide(DummyProvider))
120+
var appModules map[string]appmodule.AppModule
121+
keeper := new(keeper.Keeper)
122+
require.NoError(t,
123+
depinject.Inject(
124+
depinject.Configs(
125+
appconfig.Compose(
126+
&appv1alpha1.Config{
127+
Modules: []*appv1alpha1.ModuleConfig{
128+
{
129+
Name: banktypes.ModuleName,
130+
Config: appconfig.WrapAny(&bankmodulev1.Module{}),
131+
},
132+
{
133+
Name: types.ModuleName,
134+
Config: appconfig.WrapAny(&modulev1.Module{}),
135+
},
136+
},
137+
},
138+
),
139+
depinject.Provide(ProvideDeps),
140+
),
141+
&appModules,
142+
&keeper,
143+
),
144+
)
145+
146+
require.NotNil(t, keeper, "expected keeper to not be nil after depinject")
147+
multihooks, ok := keeper.Hooks().(types.MultiEpochHooks)
148+
require.True(t, ok, "expected keeper to have MultiEpochHooks after depinject")
149+
require.Len(t, multihooks, 1, "expected MultiEpochHooks to have 1 element after depinject")
150+
require.Equal(
151+
t,
152+
types.EpochHooksWrapper{EpochHooks: testEpochHooks{}},
153+
multihooks[0],
154+
"expected the only hook in MultiEpochHooks to be the test hook",
155+
)
156+
module, ok := appModules[types.ModuleName].(epochs.AppModule)
157+
require.True(t, ok, "expected depinject to fill map with the epochs AppModule")
158+
require.Equal(
159+
t,
160+
types.MultiEpochHooks{types.EpochHooksWrapper{EpochHooks: testEpochHooks{}}},
161+
module.Keeper().Hooks(),
162+
)
163+
require.Equal(t, keeper, module.Keeper()) // pointers pointing to the same instance
164+
}

x/epochs/export_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package epochs
2+
3+
import "github.com/cosmos/cosmos-sdk/x/epochs/keeper"
4+
5+
func (am AppModule) Keeper() *keeper.Keeper {
6+
return am.keeper
7+
}

x/epochs/module.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@ const ConsensusVersion = 1
3333

3434
// AppModule implements the AppModule interface for the epochs module.
3535
type AppModule struct {
36-
keeper keeper.Keeper
36+
keeper *keeper.Keeper
3737
}
3838

3939
// NewAppModule creates a new AppModule object.
40-
func NewAppModule(keeper keeper.Keeper) AppModule {
40+
func NewAppModule(keeper *keeper.Keeper) AppModule {
4141
return AppModule{
4242
keeper: keeper,
4343
}
@@ -66,7 +66,7 @@ func (AppModule) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *gwrunt
6666

6767
// RegisterServices registers module services.
6868
func (am AppModule) RegisterServices(registrar grpc.ServiceRegistrar) error {
69-
types.RegisterQueryServer(registrar, keeper.NewQuerier(am.keeper))
69+
types.RegisterQueryServer(registrar, keeper.NewQuerier(*am.keeper))
7070
return nil
7171
}
7272

@@ -80,7 +80,11 @@ func (am AppModule) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage {
8080
}
8181

8282
// ValidateGenesis performs genesis state validation for the epochs module.
83-
func (am AppModule) ValidateGenesis(cdc codec.JSONCodec, _ client.TxEncodingConfig, bz json.RawMessage) error {
83+
func (am AppModule) ValidateGenesis(
84+
cdc codec.JSONCodec,
85+
_ client.TxEncodingConfig,
86+
bz json.RawMessage,
87+
) error {
8488
var gs types.GenesisState
8589
if err := cdc.UnmarshalJSON(bz, &gs); err != nil {
8690
return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err)

0 commit comments

Comments
 (0)