forked from cosmos/cosmos-sdk
-
Notifications
You must be signed in to change notification settings - Fork 0
/
configurator.go
156 lines (127 loc) · 5.15 KB
/
configurator.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
package module
import (
"fmt"
"github.com/cosmos/gogoproto/grpc"
"github.com/cosmos/gogoproto/proto"
cosmosmsg "github.com/verzth/cosmos-sdk/api/cosmos/msg/v1"
errorsmod "github.com/verzth/cosmos-sdk/errors"
googlegrpc "google.golang.org/grpc"
protobuf "google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
"github.com/verzth/cosmos-sdk/codec"
sdk "github.com/verzth/cosmos-sdk/types"
sdkerrors "github.com/verzth/cosmos-sdk/types/errors"
)
// Configurator provides the hooks to allow modules to configure and register
// their services in the RegisterServices method. It is designed to eventually
// support module object capabilities isolation as described in
// https://github.com/verzth/cosmos-sdk/issues/7093
type Configurator interface {
grpc.Server
// Error returns the last error encountered during RegisterService.
Error() error
// MsgServer returns a grpc.Server instance which allows registering services
// that will handle TxBody.messages in transactions. These Msg's WILL NOT
// be exposed as gRPC services.
MsgServer() grpc.Server
// QueryServer returns a grpc.Server instance which allows registering services
// that will be exposed as gRPC services as well as ABCI query handlers.
QueryServer() grpc.Server
// RegisterMigration registers an in-place store migration for a module. The
// handler is a migration script to perform in-place migrations from version
// `fromVersion` to version `fromVersion+1`.
//
// EACH TIME a module's ConsensusVersion increments, a new migration MUST
// be registered using this function. If a migration handler is missing for
// a particular function, the upgrade logic (see RunMigrations function)
// will panic. If the ConsensusVersion bump does not introduce any store
// changes, then a no-op function must be registered here.
RegisterMigration(moduleName string, fromVersion uint64, handler MigrationHandler) error
}
type configurator struct {
cdc codec.Codec
msgServer grpc.Server
queryServer grpc.Server
// migrations is a map of moduleName -> fromVersion -> migration script handler
migrations map[string]map[uint64]MigrationHandler
registryCache *protoregistry.Files
err error
}
// RegisterService implements the grpc.Server interface.
func (c *configurator) RegisterService(sd *googlegrpc.ServiceDesc, ss interface{}) {
if c.registryCache == nil {
c.registryCache, c.err = proto.MergedRegistry()
}
desc, err := c.registryCache.FindDescriptorByName(protoreflect.FullName(sd.ServiceName))
if err != nil {
c.err = err
return
}
if protobuf.HasExtension(desc.Options(), cosmosmsg.E_Service) {
c.msgServer.RegisterService(sd, ss)
} else {
c.queryServer.RegisterService(sd, ss)
}
}
// Error returns the last error encountered during RegisterService.
func (c *configurator) Error() error {
return c.err
}
// NewConfigurator returns a new Configurator instance
func NewConfigurator(cdc codec.Codec, msgServer grpc.Server, queryServer grpc.Server) Configurator {
return &configurator{
cdc: cdc,
msgServer: msgServer,
queryServer: queryServer,
migrations: map[string]map[uint64]MigrationHandler{},
}
}
var _ Configurator = &configurator{}
// MsgServer implements the Configurator.MsgServer method
func (c *configurator) MsgServer() grpc.Server {
return c.msgServer
}
// QueryServer implements the Configurator.QueryServer method
func (c *configurator) QueryServer() grpc.Server {
return c.queryServer
}
// RegisterMigration implements the Configurator.RegisterMigration method
func (c *configurator) RegisterMigration(moduleName string, fromVersion uint64, handler MigrationHandler) error {
if fromVersion == 0 {
return errorsmod.Wrap(sdkerrors.ErrInvalidVersion, "module migration versions should start at 1")
}
if c.migrations[moduleName] == nil {
c.migrations[moduleName] = map[uint64]MigrationHandler{}
}
if c.migrations[moduleName][fromVersion] != nil {
return errorsmod.Wrapf(sdkerrors.ErrLogic, "another migration for module %s and version %d already exists", moduleName, fromVersion)
}
c.migrations[moduleName][fromVersion] = handler
return nil
}
// runModuleMigrations runs all in-place store migrations for one given module from a
// version to another version.
func (c *configurator) runModuleMigrations(ctx sdk.Context, moduleName string, fromVersion, toVersion uint64) error {
// No-op if toVersion is the initial version or if the version is unchanged.
if toVersion <= 1 || fromVersion == toVersion {
return nil
}
moduleMigrationsMap, found := c.migrations[moduleName]
if !found {
return errorsmod.Wrapf(sdkerrors.ErrNotFound, "no migrations found for module %s", moduleName)
}
// Run in-place migrations for the module sequentially until toVersion.
for i := fromVersion; i < toVersion; i++ {
migrateFn, found := moduleMigrationsMap[i]
if !found {
return errorsmod.Wrapf(sdkerrors.ErrNotFound, "no migration found for module %s from version %d to version %d", moduleName, i, i+1)
}
ctx.Logger().Info(fmt.Sprintf("migrating module %s from version %d to version %d", moduleName, i, i+1))
err := migrateFn(ctx)
if err != nil {
return err
}
}
return nil
}