github.com/cosmos/cosmos-sdk@v0.50.10/types/module/configurator.go (about)

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