diff --git a/CHANGELOG.md b/CHANGELOG.md index c21c2124b..6c5bf787d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [2.0.1] + +### API Breaking Changes + +* (IRISHub) [\#2845](https://github.com/irisnet/irishub/pull/2831) Fix query account api incompatibility + ## 2.0.0 ### State Machine Breaking diff --git a/app/app.go b/app/app.go index b5bb349e6..30639045f 100644 --- a/app/app.go +++ b/app/app.go @@ -118,6 +118,7 @@ import ( guardiantypes "github.com/irisnet/irishub/modules/guardian/types" mintkeeper "github.com/irisnet/irishub/modules/mint/keeper" minttypes "github.com/irisnet/irishub/modules/mint/types" + "github.com/irisnet/irishub/rpc" iristypes "github.com/irisnet/irishub/types" ) @@ -586,7 +587,7 @@ func NewIrisApp( app.configurator = module.NewConfigurator(appCodec, app.MsgServiceRouter(), app.GRPCQueryRouter()) app.mm.RegisterInvariants(&app.CrisisKeeper) app.mm.RegisterRoutes(app.Router(), app.QueryRouter(), encodingConfig.Amino) - app.mm.RegisterServices(app.configurator) + app.RegisterServices() // create the simulation manager and define the order of the modules for deterministic simulations // @@ -775,6 +776,18 @@ func (app *IrisApp) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APICo } } +// RegisterServices implements the Application.RegisterTxService method. +func (app *IrisApp) RegisterServices() { + for _, module := range app.mm.Modules { + if module.Name() == authtypes.ModuleName { + rpc.RegisterAuthServer(app.configurator, + app.GetKey(authtypes.StoreKey), app.AccountKeeper) + } else { + module.RegisterServices(app.configurator) + } + } +} + // RegisterTxService implements the Application.RegisterTxService method. func (app *IrisApp) RegisterTxService(clientCtx client.Context) { authtx.RegisterTxService(app.BaseApp.GRPCQueryRouter(), clientCtx, app.BaseApp.Simulate, app.interfaceRegistry) diff --git a/rpc/auth.go b/rpc/auth.go new file mode 100644 index 000000000..167a97ad7 --- /dev/null +++ b/rpc/auth.go @@ -0,0 +1,162 @@ +package rpc + +import ( + "context" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/store/prefix" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + "github.com/cosmos/cosmos-sdk/types/query" + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + "github.com/cosmos/cosmos-sdk/x/auth/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + + ethermint "github.com/evmos/ethermint/types" +) + +var _ authtypes.QueryServer = authServer{} + +type authServer struct { + key storetypes.StoreKey + k authkeeper.AccountKeeper +} + +func RegisterAuthServer(cfg module.Configurator, key storetypes.StoreKey, k authkeeper.AccountKeeper) { + authtypes.RegisterQueryServer(cfg.QueryServer(), authServer{key, k}) + m := authkeeper.NewMigrator(k, cfg.QueryServer()) + err := cfg.RegisterMigration(authtypes.ModuleName, 1, m.Migrate1to2) + if err != nil { + panic(err) + } + + err = cfg.RegisterMigration(authtypes.ModuleName, 2, m.Migrate2to3) + if err != nil { + panic(err) + } +} + +// Since: cosmos-sdk 0.43 +// Accounts returns all the existing accounts +func (a authServer) Accounts(c context.Context, req *types.QueryAccountsRequest) (*types.QueryAccountsResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + + ctx := sdk.UnwrapSDKContext(c) + store := ctx.KVStore(a.key) + accountsStore := prefix.NewStore(store, types.AddressStoreKeyPrefix) + + var accounts []*codectypes.Any + pageRes, err := query.Paginate(accountsStore, req.Pagination, func(key, value []byte) error { + account := a.decodeAccount(value) + any, err := codectypes.NewAnyWithValue(account) + if err != nil { + return err + } + + accounts = append(accounts, any) + return nil + }) + if err != nil { + return nil, status.Errorf(codes.Internal, "paginate: %v", err) + } + + return &types.QueryAccountsResponse{Accounts: accounts, Pagination: pageRes}, err +} + +// Account returns account details based on address. +func (a authServer) Account(c context.Context, req *types.QueryAccountRequest) (*types.QueryAccountResponse, error) { + if req == nil { + return nil, status.Errorf(codes.InvalidArgument, "empty request") + } + + if req.Address == "" { + return nil, status.Error(codes.InvalidArgument, "Address cannot be empty") + } + + ctx := sdk.UnwrapSDKContext(c) + addr, err := sdk.AccAddressFromBech32(req.Address) + if err != nil { + return nil, err + } + + account := a.k.GetAccount(ctx, addr) + if account == nil { + return nil, status.Errorf(codes.NotFound, "account %s not found", req.Address) + } + + ethAcc, ok := account.(*ethermint.EthAccount) + if ok { + account = ethAcc.BaseAccount + } + + any, err := codectypes.NewAnyWithValue(account) + if err != nil { + return nil, status.Errorf(codes.Internal, err.Error()) + } + + return &types.QueryAccountResponse{Account: any}, nil +} + +// AccountAddressByID returns account address based on account number. +// +// Since: cosmos-sdk 0.46.2 +func (a authServer) AccountAddressByID(c context.Context, req *types.QueryAccountAddressByIDRequest) (*types.QueryAccountAddressByIDResponse, error) { + return a.k.AccountAddressByID(c, req) +} + +// Params queries all parameters. +func (a authServer) Params(ctx context.Context, req *types.QueryParamsRequest) (*types.QueryParamsResponse, error) { + return a.k.Params(ctx, req) +} + +// ModuleAccounts returns all the existing module accounts. +// +// Since: cosmos-sdk 0.46 +func (a authServer) ModuleAccounts(ctx context.Context, req *types.QueryModuleAccountsRequest) (*types.QueryModuleAccountsResponse, error) { + return a.k.ModuleAccounts(ctx, req) +} + +// ModuleAccountByName returns the module account info by module name +func (a authServer) ModuleAccountByName(ctx context.Context, req *types.QueryModuleAccountByNameRequest) (*types.QueryModuleAccountByNameResponse, error) { + return a.k.ModuleAccountByName(ctx, req) +} + +// Bech32Prefix queries bech32Prefix +// +// Since: cosmos-sdk 0.46 +func (a authServer) Bech32Prefix(ctx context.Context, req *types.Bech32PrefixRequest) (*types.Bech32PrefixResponse, error) { + return a.k.Bech32Prefix(ctx, req) +} + +// AddressBytesToString converts Account Address bytes to string +// +// Since: cosmos-sdk 0.46 +func (a authServer) AddressBytesToString(ctx context.Context, req *types.AddressBytesToStringRequest) (*types.AddressBytesToStringResponse, error) { + return a.k.AddressBytesToString(ctx, req) +} + +// AddressStringToBytes converts Address string to bytes +// +// Since: cosmos-sdk 0.46 +func (a authServer) AddressStringToBytes(ctx context.Context, req *types.AddressStringToBytesRequest) (*types.AddressStringToBytesResponse, error) { + return a.k.AddressStringToBytes(ctx, req) +} + +func (a authServer) decodeAccount(bz []byte) types.AccountI { + acc, err := a.k.UnmarshalAccount(bz) + if err != nil { + panic(err) + } + + ethAcc, ok := acc.(*ethermint.EthAccount) + if ok { + return ethAcc.BaseAccount + } + return acc +}