Skip to content

Commit 3a20261

Browse files
authored
refactor(runtime/v2): use StoreBuilder (#21989)
1 parent 73ee336 commit 3a20261

File tree

5 files changed

+112
-65
lines changed

5 files changed

+112
-65
lines changed

runtime/v2/builder.go

Lines changed: 5 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -6,28 +6,22 @@ import (
66
"errors"
77
"fmt"
88
"io"
9-
"path/filepath"
109

1110
"cosmossdk.io/core/appmodule"
1211
appmodulev2 "cosmossdk.io/core/appmodule/v2"
13-
"cosmossdk.io/core/server"
1412
"cosmossdk.io/core/store"
1513
"cosmossdk.io/core/transaction"
1614
"cosmossdk.io/runtime/v2/services"
1715
"cosmossdk.io/server/v2/appmanager"
1816
"cosmossdk.io/server/v2/stf"
1917
"cosmossdk.io/server/v2/stf/branch"
20-
"cosmossdk.io/store/v2/db"
21-
rootstore "cosmossdk.io/store/v2/root"
2218
)
2319

2420
// AppBuilder is a type that is injected into a container by the runtime/v2 module
2521
// (as *AppBuilder) which can be used to create an app which is compatible with
2622
// the existing app.go initialization conventions.
2723
type AppBuilder[T transaction.Tx] struct {
28-
app *App[T]
29-
config server.DynamicConfig
30-
storeOptions *rootstore.Options
24+
app *App[T]
3125

3226
// the following fields are used to overwrite the default
3327
branch func(state store.ReaderMap) store.WriterMap
@@ -99,6 +93,10 @@ func (a *AppBuilder[T]) Build(opts ...AppBuilderOption[T]) (*App[T], error) {
9993
}
10094
}
10195

96+
if a.app.db == nil {
97+
return nil, fmt.Errorf("app.db is not set, it is required to build the app")
98+
}
99+
102100
if err := a.app.moduleManager.RegisterServices(a.app); err != nil {
103101
return nil, err
104102
}
@@ -122,37 +120,6 @@ func (a *AppBuilder[T]) Build(opts ...AppBuilderOption[T]) (*App[T], error) {
122120
}
123121
a.app.stf = stf
124122

125-
home := a.config.GetString(FlagHome)
126-
scRawDb, err := db.NewDB(
127-
db.DBType(a.config.GetString("store.app-db-backend")),
128-
"application",
129-
filepath.Join(home, "data"),
130-
nil,
131-
)
132-
if err != nil {
133-
panic(err)
134-
}
135-
136-
var storeOptions rootstore.Options
137-
if a.storeOptions != nil {
138-
storeOptions = *a.storeOptions
139-
} else {
140-
storeOptions = rootstore.DefaultStoreOptions()
141-
}
142-
factoryOptions := &rootstore.FactoryOptions{
143-
Logger: a.app.logger,
144-
RootDir: home,
145-
Options: storeOptions,
146-
StoreKeys: append(a.app.storeKeys, "stf"),
147-
SCRawDB: scRawDb,
148-
}
149-
150-
rs, err := rootstore.CreateRootStore(factoryOptions)
151-
if err != nil {
152-
return nil, fmt.Errorf("failed to create root store: %w", err)
153-
}
154-
a.app.db = rs
155-
156123
appManagerBuilder := appmanager.Builder[T]{
157124
STF: a.app.stf,
158125
DB: a.app.db,
@@ -251,9 +218,3 @@ func AppBuilderWithPostTxExec[T transaction.Tx](postTxExec func(ctx context.Cont
251218
a.postTxExec = postTxExec
252219
}
253220
}
254-
255-
func AppBuilderWithStoreOptions[T transaction.Tx](opts *rootstore.Options) AppBuilderOption[T] {
256-
return func(a *AppBuilder[T]) {
257-
a.storeOptions = opts
258-
}
259-
}

runtime/v2/module.go

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1"
1717
appmodulev2 "cosmossdk.io/core/appmodule/v2"
1818
"cosmossdk.io/core/comet"
19+
"cosmossdk.io/core/event"
1920
"cosmossdk.io/core/header"
2021
"cosmossdk.io/core/registry"
2122
"cosmossdk.io/core/server"
@@ -26,6 +27,7 @@ import (
2627
"cosmossdk.io/log"
2728
"cosmossdk.io/runtime/v2/services"
2829
"cosmossdk.io/server/v2/stf"
30+
rootstore "cosmossdk.io/store/v2/root"
2931
)
3032

3133
var (
@@ -40,19 +42,19 @@ type appModule[T transaction.Tx] struct {
4042
func (m appModule[T]) IsOnePerModuleType() {}
4143
func (m appModule[T]) IsAppModule() {}
4244

43-
func (m appModule[T]) RegisterServices(registar grpc.ServiceRegistrar) error {
45+
func (m appModule[T]) RegisterServices(registrar grpc.ServiceRegistrar) error {
4446
autoCliQueryService, err := services.NewAutoCLIQueryService(m.app.moduleManager.modules)
4547
if err != nil {
4648
return err
4749
}
4850

49-
autocliv1.RegisterQueryServer(registar, autoCliQueryService)
51+
autocliv1.RegisterQueryServer(registrar, autoCliQueryService)
5052

5153
reflectionSvc, err := services.NewReflectionService()
5254
if err != nil {
5355
return err
5456
}
55-
reflectionv1.RegisterReflectionServiceServer(registar, reflectionSvc)
57+
reflectionv1.RegisterReflectionServiceServer(registrar, reflectionSvc)
5658

5759
return nil
5860
}
@@ -97,6 +99,7 @@ func init() {
9799
ProvideAppBuilder[transaction.Tx],
98100
ProvideEnvironment[transaction.Tx],
99101
ProvideModuleManager[transaction.Tx],
102+
ProvideStoreBuilder,
100103
),
101104
appconfig.Invoke(SetupAppBuilder),
102105
)
@@ -146,7 +149,12 @@ type AppInputs struct {
146149
InterfaceRegistrar registry.InterfaceRegistrar
147150
LegacyAmino registry.AminoRegistrar
148151
Logger log.Logger
149-
DynamicConfig server.DynamicConfig `optional:"true"` // can be nil in client wiring
152+
// StoreBuilder is a builder for a store/v2 RootStore satisfying the Store interface
153+
StoreBuilder *StoreBuilder
154+
// StoreOptions are required as input for the StoreBuilder. If not provided, the default options are used.
155+
StoreOptions *rootstore.Options `optional:"true"`
156+
// DynamicConfig can be nil in client wiring, but is required in server wiring.
157+
DynamicConfig server.DynamicConfig `optional:"true"`
150158
}
151159

152160
func SetupAppBuilder(inputs AppInputs) {
@@ -157,8 +165,22 @@ func SetupAppBuilder(inputs AppInputs) {
157165
app.moduleManager.RegisterInterfaces(inputs.InterfaceRegistrar)
158166
app.moduleManager.RegisterLegacyAminoCodec(inputs.LegacyAmino)
159167

160-
if inputs.DynamicConfig != nil {
161-
inputs.AppBuilder.config = inputs.DynamicConfig
168+
if inputs.DynamicConfig == nil {
169+
return
170+
}
171+
storeOptions := rootstore.DefaultStoreOptions()
172+
if inputs.StoreOptions != nil {
173+
storeOptions = *inputs.StoreOptions
174+
}
175+
var err error
176+
app.db, err = inputs.StoreBuilder.Build(
177+
inputs.Logger,
178+
app.storeKeys,
179+
inputs.DynamicConfig,
180+
storeOptions,
181+
)
182+
if err != nil {
183+
panic(err)
162184
}
163185
}
164186

@@ -178,6 +200,7 @@ func ProvideEnvironment[T transaction.Tx](
178200
appBuilder *AppBuilder[T],
179201
kvFactory store.KVStoreServiceFactory,
180202
headerService header.Service,
203+
eventService event.Service,
181204
) (
182205
appmodulev2.Environment,
183206
store.KVStoreService,
@@ -209,7 +232,7 @@ func ProvideEnvironment[T transaction.Tx](
209232
env := appmodulev2.Environment{
210233
Logger: logger,
211234
BranchService: stf.BranchService{},
212-
EventService: stf.NewEventService(),
235+
EventService: eventService,
213236
GasService: stf.NewGasMeterService(),
214237
HeaderService: headerService,
215238
QueryRouterService: stf.NewQueryRouterService(),
@@ -254,10 +277,12 @@ func DefaultServiceBindings() depinject.Config {
254277
}
255278
headerService header.Service = services.NewGenesisHeaderService(stf.HeaderService{})
256279
cometService comet.Service = &services.ContextAwareCometInfoService{}
280+
eventService = stf.NewEventService()
257281
)
258282
return depinject.Supply(
259283
kvServiceFactory,
260284
headerService,
261285
cometService,
286+
eventService,
262287
)
263288
}

runtime/v2/store.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,16 @@ package runtime
33
import (
44
"errors"
55
"fmt"
6+
"path/filepath"
67

8+
"cosmossdk.io/core/server"
79
"cosmossdk.io/core/store"
10+
"cosmossdk.io/log"
811
"cosmossdk.io/server/v2/stf"
912
storev2 "cosmossdk.io/store/v2"
13+
"cosmossdk.io/store/v2/db"
1014
"cosmossdk.io/store/v2/proof"
15+
"cosmossdk.io/store/v2/root"
1116
)
1217

1318
// NewKVStoreService creates a new KVStoreService.
@@ -59,6 +64,58 @@ type Store interface {
5964
LastCommitID() (proof.CommitID, error)
6065
}
6166

67+
// StoreBuilder is a builder for a store/v2 RootStore satisfying the Store interface.
68+
type StoreBuilder struct {
69+
store Store
70+
}
71+
72+
// Build creates a new store/v2 RootStore.
73+
func (sb *StoreBuilder) Build(
74+
logger log.Logger,
75+
storeKeys []string,
76+
config server.DynamicConfig,
77+
options root.Options,
78+
) (Store, error) {
79+
if sb.store != nil {
80+
return sb.store, nil
81+
}
82+
home := config.GetString(flagHome)
83+
scRawDb, err := db.NewDB(
84+
db.DBType(config.GetString("store.app-db-backend")),
85+
"application",
86+
filepath.Join(home, "data"),
87+
nil,
88+
)
89+
if err != nil {
90+
return nil, fmt.Errorf("failed to create SCRawDB: %w", err)
91+
}
92+
93+
factoryOptions := &root.FactoryOptions{
94+
Logger: logger,
95+
RootDir: home,
96+
Options: options,
97+
// STF needs to store a bit of state
98+
StoreKeys: append(storeKeys, "stf"),
99+
SCRawDB: scRawDb,
100+
}
101+
102+
rs, err := root.CreateRootStore(factoryOptions)
103+
if err != nil {
104+
return nil, fmt.Errorf("failed to create root store: %w", err)
105+
}
106+
sb.store = rs
107+
return sb.store, nil
108+
}
109+
110+
// Get returns the Store. Build must be called before calling Get or the result will be nil.
111+
func (sb *StoreBuilder) Get() Store {
112+
return sb.store
113+
}
114+
115+
func ProvideStoreBuilder() *StoreBuilder {
116+
return &StoreBuilder{}
117+
}
118+
62119
// StoreLoader allows for custom loading of the store, this is useful when upgrading the store from a previous version
63120
type StoreLoader func(store Store) error
64121

runtime/v2/types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import (
1414

1515
const (
1616
ModuleName = "runtime"
17-
FlagHome = "home"
17+
flagHome = "home"
1818
)
1919

2020
// validateProtoAnnotations validates that the proto annotations are correct.

simapp/v2/app_di.go

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,9 @@ func NewSimApp[T transaction.Tx](
6464
viper *viper.Viper,
6565
) *SimApp[T] {
6666
var (
67-
app = &SimApp[T]{}
68-
appBuilder *runtime.AppBuilder[T]
69-
err error
70-
storeOptions = &root.Options{}
67+
app = &SimApp[T]{}
68+
appBuilder *runtime.AppBuilder[T]
69+
err error
7170

7271
// merge the AppConfig and other configuration in one config
7372
appConfig = depinject.Configs(
@@ -149,6 +148,19 @@ func NewSimApp[T transaction.Tx](
149148
)
150149
)
151150

151+
// the subsection of config that contains the store options (in app.toml [store.options] header)
152+
// is unmarshaled into a store.Options struct and passed to the store builder.
153+
// future work may move this specification and retrieval into store/v2.
154+
// If these options are not specified then default values will be used.
155+
if sub := viper.Sub("store.options"); sub != nil {
156+
storeOptions := &root.Options{}
157+
err := sub.Unmarshal(storeOptions)
158+
if err != nil {
159+
panic(err)
160+
}
161+
appConfig = depinject.Configs(appConfig, depinject.Supply(storeOptions))
162+
}
163+
152164
if err := depinject.Inject(appConfig,
153165
&appBuilder,
154166
&app.appCodec,
@@ -160,15 +172,7 @@ func NewSimApp[T transaction.Tx](
160172
panic(err)
161173
}
162174

163-
var builderOpts []runtime.AppBuilderOption[T]
164-
if sub := viper.Sub("store.options"); sub != nil {
165-
err = sub.Unmarshal(storeOptions)
166-
if err != nil {
167-
panic(err)
168-
}
169-
builderOpts = append(builderOpts, runtime.AppBuilderWithStoreOptions[T](storeOptions))
170-
}
171-
app.App, err = appBuilder.Build(builderOpts...)
175+
app.App, err = appBuilder.Build()
172176
if err != nil {
173177
panic(err)
174178
}

0 commit comments

Comments
 (0)