refactor(core,stf,x)!: remove InvokeTyped from router (#21224)

This commit is contained in:
Julien Robert 2024-08-23 21:38:06 +00:00 committed by GitHub
parent fc87374ff7
commit a554a21a0e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
55 changed files with 424 additions and 585 deletions

View File

@ -11,8 +11,6 @@ import (
type Service interface {
// CanInvoke returns an error if the given request cannot be invoked.
CanInvoke(ctx context.Context, typeURL string) error
// InvokeTyped execute a message or query. It should be used when the called knows the type of the response.
InvokeTyped(ctx context.Context, req, res transaction.Msg) error
// InvokeUntyped execute a Msg or query. It should be used when the called doesn't know the type of the response.
InvokeUntyped(ctx context.Context, req transaction.Msg) (res transaction.Msg, err error)
// Invoke execute a message or query. The response should be type casted by the caller to the expected response.
Invoke(ctx context.Context, req transaction.Msg) (res transaction.Msg, err error)
}

View File

@ -79,11 +79,11 @@ import (
type PreMsgHandlerRouter interface {
// RegisterGlobalPreMsgHandler will register a pre msg handler that hooks before any message executes.
// Handler will be called before ANY message executes.
RegisterGlobalPreMsgHandler(handler func(ctx context.Context, msg protoiface.MessageV1) error)
RegisterGlobalPreMsgHandler(handler func(ctx context.Context, msg transaction.Msg) error)
// RegisterPreMsgHandler will register a pre msg handler that hooks before the provided message
// with the given message name executes. Handler will be called before the message is executed
// by the module.
RegisterPreMsgHandler(msgName string, handler func(ctx context.Context, msg protoiface.MessageV1) error)
RegisterPreMsgHandler(msgName string, handler func(ctx context.Context, msg transaction.Msg) error)
}
type HasPreMsgHandler interface {
@ -105,11 +105,11 @@ import (
type PostMsgHandlerRouter interface {
// RegisterGlobalPostMsgHandler will register a post msg handler that hooks after any message executes.
// Handler will be called after ANY message executes, alongside the response.
RegisterGlobalPostMsgHandler(handler func(ctx context.Context, msg, msgResp protoiface.MessageV1) error)
RegisterGlobalPostMsgHandler(handler func(ctx context.Context, msg, msgResp transaction.Msg) error)
// RegisterPostMsgHandler will register a pre msg handler that hooks after the provided message
// with the given message name executes. Handler will be called after the message is executed
// by the module, alongside the response returned by the module.
RegisterPostMsgHandler(msgName string, handler func(ctx context.Context, msg, msgResp protoiface.MessageV1) error)
RegisterPostMsgHandler(msgName string, handler func(ctx context.Context, msg, msgResp transaction.Msg) error)
}
type HasPostMsgHandler interface {
@ -142,7 +142,7 @@ import (
)
type MsgHandlerRouter interface {
RegisterMsgHandler(msgName string, handler func(ctx context.Context, msg protoiface.MessageV1) (msgResp protoiface.MessageV1, err error))
RegisterMsgHandler(msgName string, handler func(ctx context.Context, msg transaction.Msg) (msgResp transaction.Msg, err error))
}
type HasMsgHandler interface {
@ -150,7 +150,7 @@ type HasMsgHandler interface {
}
// RegisterMsgHandler is a helper function to retain type safety when creating handlers, so we do not need to cast messages.
func RegisterMsgHandler[Req, Resp protoiface.MessageV1](router MsgHandlerRouter, handler func(ctx context.Context, req Req) (resp Resp, err error)) {
func RegisterMsgHandler[Req, Resp transaction.Msg](router MsgHandlerRouter, handler func(ctx context.Context, req Req) (resp Resp, err error)) {
// impl detail
}
```
@ -186,7 +186,7 @@ import (
)
type QueryHandlerRouter interface {
RegisterQueryHandler(msgName string, handler func(ctx context.Context, req protoiface.MessageV1) (resp protoiface.MessageV1, err error))
RegisterQueryHandler(msgName string, handler func(ctx context.Context, req transaction.Msg) (resp transaction.Msg, err error))
}
type HasQueryHandler interface {
@ -194,7 +194,7 @@ type HasQueryHandler interface {
}
// RegisterQueryHandler is a helper function to retain type safety when creating handlers, so we do not need to cast messages.
func RegisterQueryHandler[Req, Resp protoiface.MessageV1](router QueryHandlerRouter, handler func(ctx context.Context, req Req) (resp Resp, err error)) {
func RegisterQueryHandler[Req, Resp transaction.Msg](router QueryHandlerRouter, handler func(ctx context.Context, req Req) (resp Resp, err error)) {
// impl detail
}

View File

@ -45,21 +45,8 @@ func (m *msgRouterService) CanInvoke(ctx context.Context, typeURL string) error
return nil
}
// InvokeTyped execute a message and fill-in a response.
// The response must be known and passed as a parameter.
// Use InvokeUntyped if the response type is not known.
func (m *msgRouterService) InvokeTyped(ctx context.Context, msg, resp gogoproto.Message) error {
messageName := msgTypeURL(msg)
handler := m.router.HybridHandlerByMsgName(messageName)
if handler == nil {
return fmt.Errorf("unknown message: %s", messageName)
}
return handler(ctx, msg, resp)
}
// InvokeUntyped execute a message and returns a response.
func (m *msgRouterService) InvokeUntyped(ctx context.Context, msg gogoproto.Message) (gogoproto.Message, error) {
// Invoke execute a message and returns a response.
func (m *msgRouterService) Invoke(ctx context.Context, msg gogoproto.Message) (gogoproto.Message, error) {
messageName := msgTypeURL(msg)
respName := m.router.ResponseNameByMsgName(messageName)
if respName == "" {
@ -76,7 +63,16 @@ func (m *msgRouterService) InvokeUntyped(ctx context.Context, msg gogoproto.Mess
return nil, fmt.Errorf("could not create response message %s", respName)
}
return msgResp, m.InvokeTyped(ctx, msg, msgResp)
handler := m.router.HybridHandlerByMsgName(messageName)
if handler == nil {
return nil, fmt.Errorf("unknown message: %s", messageName)
}
if err := handler(ctx, msg, msgResp); err != nil {
return nil, err
}
return msgResp, nil
}
// NewQueryRouterService implements router.Service.
@ -110,27 +106,12 @@ func (m *queryRouterService) CanInvoke(ctx context.Context, typeURL string) erro
return nil
}
// InvokeTyped execute a message and fill-in a response.
// The response must be known and passed as a parameter.
// Use InvokeUntyped if the response type is not known.
func (m *queryRouterService) InvokeTyped(ctx context.Context, req, resp gogoproto.Message) error {
reqName := msgTypeURL(req)
handlers := m.router.HybridHandlerByRequestName(reqName)
if len(handlers) == 0 {
return fmt.Errorf("unknown request: %s", reqName)
} else if len(handlers) > 1 {
return fmt.Errorf("ambiguous request, query have multiple handlers: %s", reqName)
}
return handlers[0](ctx, req, resp)
}
// InvokeUntyped execute a message and returns a response.
func (m *queryRouterService) InvokeUntyped(ctx context.Context, req gogoproto.Message) (gogoproto.Message, error) {
// Invoke execute a message and returns a response.
func (m *queryRouterService) Invoke(ctx context.Context, req gogoproto.Message) (gogoproto.Message, error) {
reqName := msgTypeURL(req)
respName := m.router.ResponseNameByRequestName(reqName)
if respName == "" {
return nil, fmt.Errorf("could not find response type for request %s (%T)", reqName, req)
return nil, fmt.Errorf("unknown request: could not find response type for request %s (%T)", reqName, req)
}
// get response type
@ -143,7 +124,18 @@ func (m *queryRouterService) InvokeUntyped(ctx context.Context, req gogoproto.Me
return nil, fmt.Errorf("could not create response request %s", respName)
}
return reqResp, m.InvokeTyped(ctx, req, reqResp)
handlers := m.router.HybridHandlerByRequestName(reqName)
if len(handlers) == 0 {
return nil, fmt.Errorf("unknown request: %s", reqName)
} else if len(handlers) > 1 {
return nil, fmt.Errorf("ambiguous request, query have multiple handlers: %s", reqName)
}
if err := handlers[0](ctx, req, reqResp); err != nil {
return nil, err
}
return reqResp, nil
}
// msgTypeURL returns the TypeURL of a proto message.

View File

@ -6,7 +6,6 @@ import (
"github.com/stretchr/testify/require"
bankv1beta1 "cosmossdk.io/api/cosmos/bank/v1beta1"
counterv1 "cosmossdk.io/api/cosmos/counter/v1"
coretesting "cosmossdk.io/core/testing"
storetypes "cosmossdk.io/store/types"
@ -38,12 +37,12 @@ func TestRouterService(t *testing.T) {
// Messages
t.Run("invalid msg", func(t *testing.T) {
_, err := messageRouterService.InvokeUntyped(testCtx.Ctx, &bankv1beta1.MsgSend{})
_, err := messageRouterService.Invoke(testCtx.Ctx, &bankv1beta1.MsgSend{})
require.ErrorContains(t, err, "could not find response type for message cosmos.bank.v1beta1.MsgSend")
})
t.Run("invoke untyped: valid msg (proto v1)", func(t *testing.T) {
resp, err := messageRouterService.InvokeUntyped(testCtx.Ctx, &countertypes.MsgIncreaseCounter{
t.Run("invoke: valid msg (proto v1)", func(t *testing.T) {
resp, err := messageRouterService.Invoke(testCtx.Ctx, &countertypes.MsgIncreaseCounter{
Signer: "cosmos1",
Count: 42,
})
@ -51,57 +50,17 @@ func TestRouterService(t *testing.T) {
require.NotNil(t, resp)
})
t.Run("invoke typed: valid msg (proto v1)", func(t *testing.T) {
resp := &countertypes.MsgIncreaseCountResponse{}
err := messageRouterService.InvokeTyped(testCtx.Ctx, &countertypes.MsgIncreaseCounter{
Signer: "cosmos1",
Count: 42,
}, resp)
require.NoError(t, err)
require.NotNil(t, resp)
})
t.Run("invoke typed: valid msg (proto v2)", func(t *testing.T) {
resp := &counterv1.MsgIncreaseCountResponse{}
err := messageRouterService.InvokeTyped(testCtx.Ctx, &counterv1.MsgIncreaseCounter{
Signer: "cosmos1",
Count: 42,
}, resp)
require.NoError(t, err)
require.NotNil(t, resp)
})
// Queries
t.Run("invalid query", func(t *testing.T) {
err := queryRouterService.InvokeTyped(testCtx.Ctx, &bankv1beta1.QueryBalanceRequest{}, &bankv1beta1.QueryBalanceResponse{})
require.ErrorContains(t, err, "unknown request: cosmos.bank.v1beta1.QueryBalanceRequest")
_, err := queryRouterService.Invoke(testCtx.Ctx, &bankv1beta1.QueryBalanceRequest{})
require.ErrorContains(t, err, "could not find response type for request cosmos.bank.v1beta1.QueryBalanceRequest")
})
t.Run("invoke typed: valid query (proto v1)", func(t *testing.T) {
t.Run("invoke: valid query (proto v1)", func(t *testing.T) {
_ = counterKeeper.CountStore.Set(testCtx.Ctx, 42)
resp := &countertypes.QueryGetCountResponse{}
err := queryRouterService.InvokeTyped(testCtx.Ctx, &countertypes.QueryGetCountRequest{}, resp)
require.NoError(t, err)
require.NotNil(t, resp)
require.Equal(t, int64(42), resp.TotalCount)
})
t.Run("invoke typed: valid query (proto v2)", func(t *testing.T) {
_ = counterKeeper.CountStore.Set(testCtx.Ctx, 42)
resp := &counterv1.QueryGetCountResponse{}
err := queryRouterService.InvokeTyped(testCtx.Ctx, &counterv1.QueryGetCountRequest{}, resp)
require.NoError(t, err)
require.NotNil(t, resp)
require.Equal(t, int64(42), resp.TotalCount)
})
t.Run("invoke untyped: valid query (proto v1)", func(t *testing.T) {
_ = counterKeeper.CountStore.Set(testCtx.Ctx, 42)
resp, err := queryRouterService.InvokeUntyped(testCtx.Ctx, &countertypes.QueryGetCountRequest{})
resp, err := queryRouterService.Invoke(testCtx.Ctx, &countertypes.QueryGetCountRequest{})
require.NoError(t, err)
require.NotNil(t, resp)
respVal, ok := resp.(*countertypes.QueryGetCountResponse)

View File

@ -28,7 +28,7 @@ var testBatch = PacketBatch{
}
func batchListener() (Listener, *PacketBatch) {
var got = new(PacketBatch)
got := new(PacketBatch)
l := Listener{
InitializeModuleData: func(m ModuleInitializationData) error {
*got = append(*got, m)

View File

@ -290,7 +290,8 @@ func TestCompareModuleSchemas(t *testing.T) {
{
Name: "foo",
KeyFields: []schema.Field{{Name: "key1", Kind: schema.EnumKind, EnumType: schema.EnumType{Name: "bar", Values: []string{"a"}}}},
}},
},
},
AddedObjectTypes: []schema.ObjectType{
{
Name: "bar",

View File

@ -13,7 +13,7 @@ $mockgen_cmd -source=x/nft/expected_keepers.go -package testutil -destination x/
$mockgen_cmd -source=x/feegrant/expected_keepers.go -package testutil -destination x/feegrant/testutil/expected_keepers_mocks.go
$mockgen_cmd -source=x/mint/types/expected_keepers.go -package testutil -destination x/mint/testutil/expected_keepers_mocks.go
$mockgen_cmd -source=x/auth/tx/config/expected_keepers.go -package testutil -destination x/auth/tx/testutil/expected_keepers_mocks.go
$mockgen_cmd -source=x/auth/types/expected_keepers.go -package testutil -destination x/auth/testutil/expected_keepers_mocks.go
# $mockgen_cmd -source=x/auth/types/expected_keepers.go -package testutil -destination x/auth/testutil/expected_keepers_mocks.go
$mockgen_cmd -source=x/auth/ante/expected_keepers.go -package testutil -destination x/auth/ante/testutil/expected_keepers_mocks.go
$mockgen_cmd -source=x/authz/expected_keepers.go -package testutil -destination x/authz/testutil/expected_keepers_mocks.go
$mockgen_cmd -source=x/bank/types/expected_keepers.go -package testutil -destination x/bank/testutil/expected_keepers_mocks.go
@ -24,5 +24,5 @@ $mockgen_cmd -source=x/slashing/types/expected_keepers.go -package testutil -des
$mockgen_cmd -source=x/genutil/types/expected_keepers.go -package testutil -destination x/genutil/testutil/expected_keepers_mocks.go
$mockgen_cmd -source=x/gov/testutil/expected_keepers.go -package testutil -destination x/gov/testutil/expected_keepers_mocks.go
$mockgen_cmd -source=x/staking/types/expected_keepers.go -package testutil -destination x/staking/testutil/expected_keepers_mocks.go
$mockgen_cmd -source=x/auth/vesting/types/expected_keepers.go -package testutil -destination x/auth/vesting/testutil/expected_keepers_mocks.go
# $mockgen_cmd -source=x/auth/vesting/types/expected_keepers.go -package testutil -destination x/auth/vesting/testutil/expected_keepers_mocks.go
$mockgen_cmd -source=x/protocolpool/types/expected_keepers.go -package testutil -destination x/protocolpool/testutil/expected_keepers_mocks.go

View File

@ -31,26 +31,14 @@ func (m msgRouterService) CanInvoke(ctx context.Context, typeURL string) error {
return exCtx.msgRouter.CanInvoke(ctx, typeURL)
}
// InvokeTyped execute a message and fill-in a response.
// The response must be known and passed as a parameter.
// Use InvokeUntyped if the response type is not known.
func (m msgRouterService) InvokeTyped(ctx context.Context, msg, resp transaction.Msg) error {
exCtx, err := getExecutionCtxFromContext(ctx)
if err != nil {
return err
}
return exCtx.msgRouter.InvokeTyped(ctx, msg, resp)
}
// InvokeUntyped execute a message and returns a response.
func (m msgRouterService) InvokeUntyped(ctx context.Context, msg transaction.Msg) (transaction.Msg, error) {
// Invoke execute a message and returns a response.
func (m msgRouterService) Invoke(ctx context.Context, msg transaction.Msg) (transaction.Msg, error) {
exCtx, err := getExecutionCtxFromContext(ctx)
if err != nil {
return nil, err
}
return exCtx.msgRouter.InvokeUntyped(ctx, msg)
return exCtx.msgRouter.Invoke(ctx, msg)
}
// NewQueryRouterService implements router.Service.
@ -72,23 +60,8 @@ func (m queryRouterService) CanInvoke(ctx context.Context, typeURL string) error
return exCtx.queryRouter.CanInvoke(ctx, typeURL)
}
// InvokeTyped execute a message and fill-in a response.
// The response must be known and passed as a parameter.
// Use InvokeUntyped if the response type is not known.
func (m queryRouterService) InvokeTyped(
ctx context.Context,
req, resp transaction.Msg,
) error {
exCtx, err := getExecutionCtxFromContext(ctx)
if err != nil {
return err
}
return exCtx.queryRouter.InvokeTyped(ctx, req, resp)
}
// InvokeUntyped execute a message and returns a response.
func (m queryRouterService) InvokeUntyped(
func (m queryRouterService) Invoke(
ctx context.Context,
req transaction.Msg,
) (transaction.Msg, error) {
@ -97,5 +70,5 @@ func (m queryRouterService) InvokeUntyped(
return nil, err
}
return exCtx.queryRouter.InvokeUntyped(ctx, req)
return exCtx.queryRouter.Invoke(ctx, req)
}

View File

@ -321,7 +321,7 @@ func (s STF[T]) runTxMsgs(
execCtx.setGasLimit(gasLimit)
for i, msg := range msgs {
execCtx.sender = txSenders[i]
resp, err := s.msgRouter.InvokeUntyped(execCtx, msg)
resp, err := s.msgRouter.Invoke(execCtx, msg)
if err != nil {
return nil, 0, nil, fmt.Errorf("message execution at index %d failed: %w", i, err)
}
@ -457,7 +457,7 @@ func (s STF[T]) Query(
queryCtx := s.makeContext(ctx, nil, queryState, internal.ExecModeSimulate)
queryCtx.setHeaderInfo(hi)
queryCtx.setGasLimit(gasLimit)
return s.queryRouter.InvokeUntyped(queryCtx, req)
return s.queryRouter.Invoke(queryCtx, req)
}
// RunWithCtx is made to support genesis, if genesis was just the execution of messages instead

View File

@ -4,7 +4,6 @@ import (
"context"
"errors"
"fmt"
"reflect"
"strings"
gogoproto "github.com/cosmos/gogoproto/proto"
@ -160,54 +159,12 @@ func (r coreRouterImpl) CanInvoke(_ context.Context, typeURL string) error {
return nil
}
func (r coreRouterImpl) InvokeTyped(ctx context.Context, req, resp transaction.Msg) error {
handlerResp, err := r.InvokeUntyped(ctx, req)
if err != nil {
return err
}
return merge(handlerResp, resp)
}
func (r coreRouterImpl) InvokeUntyped(ctx context.Context, req transaction.Msg) (res transaction.Msg, err error) {
func (r coreRouterImpl) Invoke(ctx context.Context, req transaction.Msg) (res transaction.Msg, err error) {
typeName := msgTypeURL(req)
handler, exists := r.handlers[typeName]
if !exists {
return nil, fmt.Errorf("%w: %s", ErrNoHandler, typeName)
}
return handler(ctx, req)
}
// merge merges together two protobuf messages by setting the pointer
// to src in dst. Used internally.
func merge(src, dst gogoproto.Message) error {
if src == nil {
return fmt.Errorf("source message is nil")
}
if dst == nil {
return fmt.Errorf("destination message is nil")
}
srcVal := reflect.ValueOf(src)
dstVal := reflect.ValueOf(dst)
if srcVal.Kind() == reflect.Interface {
srcVal = srcVal.Elem()
}
if dstVal.Kind() == reflect.Interface {
dstVal = dstVal.Elem()
}
if srcVal.Kind() != reflect.Ptr || dstVal.Kind() != reflect.Ptr {
return fmt.Errorf("both source and destination must be pointers")
}
srcElem := srcVal.Elem()
dstElem := dstVal.Elem()
if !srcElem.Type().AssignableTo(dstElem.Type()) {
return fmt.Errorf("incompatible types: cannot merge %v into %v", srcElem.Type(), dstElem.Type())
}
dstElem.Set(srcElem)
return nil
}

View File

@ -6,7 +6,6 @@ import (
gogoproto "github.com/cosmos/gogoproto/proto"
gogotypes "github.com/cosmos/gogoproto/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"cosmossdk.io/core/appmodule/v2"
@ -41,68 +40,9 @@ func TestRouter(t *testing.T) {
require.Error(t, err)
})
t.Run("invoke untyped", func(t *testing.T) {
gotResp, err := router.InvokeUntyped(context.Background(), expectedMsg)
require.NoError(t, err)
require.Equal(t, expectedResp, gotResp)
})
t.Run("invoked typed", func(t *testing.T) {
gotResp := new(gogotypes.StringValue)
err := router.InvokeTyped(context.Background(), expectedMsg, gotResp)
t.Run("invoke", func(t *testing.T) {
gotResp, err := router.Invoke(context.Background(), expectedMsg)
require.NoError(t, err)
require.Equal(t, expectedResp, gotResp)
})
}
func TestMerge(t *testing.T) {
tests := []struct {
name string
src transaction.Msg
dst transaction.Msg
expected transaction.Msg
wantErr bool
}{
{
name: "success",
src: &gogotypes.BoolValue{Value: true},
dst: &gogotypes.BoolValue{},
expected: &gogotypes.BoolValue{Value: true},
wantErr: false,
},
{
name: "nil src",
src: nil,
dst: &gogotypes.StringValue{},
expected: &gogotypes.StringValue{},
wantErr: true,
},
{
name: "nil dst",
src: &gogotypes.StringValue{Value: "hello"},
dst: nil,
expected: nil,
wantErr: true,
},
{
name: "incompatible types",
src: &gogotypes.StringValue{Value: "hello"},
dst: &gogotypes.BoolValue{},
expected: &gogotypes.BoolValue{},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := merge(tt.src, tt.dst)
if tt.wantErr {
assert.Error(t, err)
} else {
assert.NoError(t, err)
assert.Equal(t, tt.expected, tt.dst)
}
})
}
}

View File

@ -3,6 +3,7 @@ package simapp
import (
"context"
"encoding/binary"
"fmt"
"cosmossdk.io/core/appmodule"
"cosmossdk.io/core/event"
@ -29,29 +30,43 @@ func ProvideExampleMintFn(bankKeeper MintBankKeeper) minttypes.MintFn {
return nil
}
var stakingParams stakingtypes.QueryParamsResponse
err := env.QueryRouterService.InvokeTyped(ctx, &stakingtypes.QueryParamsRequest{}, &stakingParams)
resp, err := env.QueryRouterService.Invoke(ctx, &stakingtypes.QueryParamsRequest{})
if err != nil {
return err
}
stakingParams, ok := resp.(*stakingtypes.QueryParamsResponse)
if !ok {
return fmt.Errorf("unexpected response type: %T", resp)
}
var bankSupply banktypes.QuerySupplyOfResponse
err = env.QueryRouterService.InvokeTyped(ctx, &banktypes.QuerySupplyOfRequest{Denom: stakingParams.Params.BondDenom}, &bankSupply)
resp, err = env.QueryRouterService.Invoke(ctx, &banktypes.QuerySupplyOfRequest{Denom: stakingParams.Params.BondDenom})
if err != nil {
return err
}
bankSupply, ok := resp.(*banktypes.QuerySupplyOfResponse)
if !ok {
return fmt.Errorf("unexpected response type: %T", resp)
}
stakingTokenSupply := bankSupply.Amount
var mintParams minttypes.QueryParamsResponse
err = env.QueryRouterService.InvokeTyped(ctx, &minttypes.QueryParamsRequest{}, &mintParams)
resp, err = env.QueryRouterService.Invoke(ctx, &minttypes.QueryParamsRequest{})
if err != nil {
return err
}
mintParams, ok := resp.(*minttypes.QueryParamsResponse)
if !ok {
return fmt.Errorf("unexpected response type: %T", resp)
}
resp, err = env.QueryRouterService.Invoke(ctx, &stakingtypes.QueryPoolRequest{})
if err != nil {
return err
}
var stakingPool stakingtypes.QueryPoolResponse
err = env.QueryRouterService.InvokeTyped(ctx, &stakingtypes.QueryPoolRequest{}, &stakingPool)
if err != nil {
return err
stakingPool, ok := resp.(*stakingtypes.QueryPoolResponse)
if !ok {
return fmt.Errorf("unexpected response type: %T", resp)
}
// bondedRatio

View File

@ -5,8 +5,8 @@ import (
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"google.golang.org/protobuf/runtime/protoiface"
"cosmossdk.io/core/transaction"
"cosmossdk.io/simapp"
"cosmossdk.io/x/accounts/defaults/lockup/types"
"cosmossdk.io/x/bank/testutil"
@ -15,8 +15,6 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
)
type ProtoMsg = protoiface.MessageV1
var (
ownerAddr = secp256k1.GenPrivKey().PubKey().Address()
accOwner = sdk.AccAddress(ownerAddr)
@ -52,7 +50,7 @@ func (s *E2ETestSuite) executeTx(ctx sdk.Context, msg sdk.Msg, app *simapp.SimAp
return err
}
func (s *E2ETestSuite) queryAcc(ctx sdk.Context, req sdk.Msg, app *simapp.SimApp, accAddr []byte) (ProtoMsg, error) {
func (s *E2ETestSuite) queryAcc(ctx sdk.Context, req sdk.Msg, app *simapp.SimApp, accAddr []byte) (transaction.Msg, error) {
resp, err := app.AccountsKeeper.Query(ctx, accAddr, req)
return resp, err
}

View File

@ -6,8 +6,8 @@ import (
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"google.golang.org/protobuf/runtime/protoiface"
"cosmossdk.io/core/transaction"
"cosmossdk.io/math"
"cosmossdk.io/simapp"
multisigaccount "cosmossdk.io/x/accounts/defaults/multisig"
@ -19,8 +19,6 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
)
type ProtoMsg = protoiface.MessageV1
type E2ETestSuite struct {
suite.Suite
@ -59,7 +57,7 @@ func (s *E2ETestSuite) executeTx(ctx context.Context, msg sdk.Msg, accAddr, send
return err
}
func (s *E2ETestSuite) queryAcc(ctx context.Context, req sdk.Msg, accAddr []byte) (ProtoMsg, error) {
func (s *E2ETestSuite) queryAcc(ctx context.Context, req sdk.Msg, accAddr []byte) (transaction.Msg, error) {
resp, err := s.app.AccountsKeeper.Query(ctx, accAddr, req)
return resp, err
}

View File

@ -14,6 +14,7 @@ import (
module "github.com/cosmos/cosmos-sdk/types/module"
gomock "github.com/golang/mock/gomock"
runtime "github.com/grpc-ecosystem/grpc-gateway/runtime"
grpc "google.golang.org/grpc"
)
// MockAppModuleBasic is a mock of AppModuleBasic interface.
@ -264,6 +265,67 @@ func (mr *MockHasServicesMockRecorder) RegisterServices(arg0 interface{}) *gomoc
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterServices", reflect.TypeOf((*MockHasServices)(nil).RegisterServices), arg0)
}
// MockhasServicesV1 is a mock of hasServicesV1 interface.
type MockhasServicesV1 struct {
ctrl *gomock.Controller
recorder *MockhasServicesV1MockRecorder
}
// MockhasServicesV1MockRecorder is the mock recorder for MockhasServicesV1.
type MockhasServicesV1MockRecorder struct {
mock *MockhasServicesV1
}
// NewMockhasServicesV1 creates a new mock instance.
func NewMockhasServicesV1(ctrl *gomock.Controller) *MockhasServicesV1 {
mock := &MockhasServicesV1{ctrl: ctrl}
mock.recorder = &MockhasServicesV1MockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockhasServicesV1) EXPECT() *MockhasServicesV1MockRecorder {
return m.recorder
}
// IsAppModule mocks base method.
func (m *MockhasServicesV1) IsAppModule() {
m.ctrl.T.Helper()
m.ctrl.Call(m, "IsAppModule")
}
// IsAppModule indicates an expected call of IsAppModule.
func (mr *MockhasServicesV1MockRecorder) IsAppModule() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsAppModule", reflect.TypeOf((*MockhasServicesV1)(nil).IsAppModule))
}
// IsOnePerModuleType mocks base method.
func (m *MockhasServicesV1) IsOnePerModuleType() {
m.ctrl.T.Helper()
m.ctrl.Call(m, "IsOnePerModuleType")
}
// IsOnePerModuleType indicates an expected call of IsOnePerModuleType.
func (mr *MockhasServicesV1MockRecorder) IsOnePerModuleType() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsOnePerModuleType", reflect.TypeOf((*MockhasServicesV1)(nil).IsOnePerModuleType))
}
// RegisterServices mocks base method.
func (m *MockhasServicesV1) RegisterServices(arg0 grpc.ServiceRegistrar) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "RegisterServices", arg0)
ret0, _ := ret[0].(error)
return ret0
}
// RegisterServices indicates an expected call of RegisterServices.
func (mr *MockhasServicesV1MockRecorder) RegisterServices(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterServices", reflect.TypeOf((*MockhasServicesV1)(nil).RegisterServices), arg0)
}
// MockHasABCIEndBlock is a mock of HasABCIEndBlock interface.
type MockHasABCIEndBlock struct {
ctrl *gomock.Controller

View File

@ -20,7 +20,7 @@ func TestVersionCommand_Error(t *testing.T) {
rootCmd.SetOut(out)
rootCmd.SetErr(out)
ctx := context.WithValue(context.Background(), log.ContextKey, logger) //nolint:staticcheck // SA1029: temporary issue in dependency
ctx := context.WithValue(context.Background(), log.ContextKey, logger)
require.Error(t, rootCmd.ExecuteContext(ctx))
require.Contains(t, out.String(), "DAEMON_NAME is not set")

View File

@ -97,7 +97,7 @@ type HasServices interface {
// hasServicesV1 is the interface for registering service in baseapp Cosmos SDK.
// This API is part of core/appmodule but commented out for dependencies.
type hasServicesV1 interface {
appmodule.AppModule
appmodulev2.AppModule
RegisterServices(grpc.ServiceRegistrar) error
}

View File

@ -2,15 +2,18 @@ package accounts
import (
"context"
"fmt"
"strconv"
"github.com/cosmos/gogoproto/types"
bankv1beta1 "cosmossdk.io/api/cosmos/bank/v1beta1"
basev1beta1 "cosmossdk.io/api/cosmos/base/v1beta1"
"cosmossdk.io/collections"
"cosmossdk.io/math"
"cosmossdk.io/x/accounts/accountstd"
"cosmossdk.io/x/accounts/internal/implementation"
banktypes "cosmossdk.io/x/bank/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)
var _ implementation.Account = (*TestAccount)(nil)
@ -28,7 +31,7 @@ type TestAccount struct {
func (t TestAccount) RegisterInitHandler(builder *implementation.InitBuilder) {
implementation.RegisterInitHandler(builder, func(ctx context.Context, _ *types.Empty) (*types.Empty, error) {
// we also force a module call here to test things work as expected.
_, err := implementation.QueryModule[bankv1beta1.QueryBalanceResponse](ctx, &bankv1beta1.QueryBalanceRequest{
_, err := implementation.QueryModule(ctx, &banktypes.QueryBalanceRequest{
Address: string(implementation.Whoami(ctx)),
Denom: "atom",
})
@ -52,15 +55,10 @@ func (t TestAccount) RegisterExecuteHandlers(builder *implementation.ExecuteBuil
// this is for intermodule comms testing, we simulate a bank send
implementation.RegisterExecuteHandler(builder, func(ctx context.Context, req *types.Int64Value) (*types.Empty, error) {
resp, err := implementation.ExecModule[bankv1beta1.MsgSendResponse](ctx, &bankv1beta1.MsgSend{
resp, err := implementation.ExecModule(ctx, &banktypes.MsgSend{
FromAddress: string(implementation.Whoami(ctx)),
ToAddress: "recipient",
Amount: []*basev1beta1.Coin{
{
Denom: "test",
Amount: strconv.FormatInt(req.Value, 10),
},
},
Amount: sdk.NewCoins(sdk.NewCoin("test", math.NewInt(req.Value))),
})
if err != nil {
return nil, err
@ -90,7 +88,7 @@ func (t TestAccount) RegisterQueryHandlers(builder *implementation.QueryBuilder)
// test intermodule comms, we simulate someone is sending the account a request for the accounts balance
// of a given denom.
implementation.RegisterQueryHandler(builder, func(ctx context.Context, req *types.StringValue) (*types.Int64Value, error) {
resp, err := implementation.QueryModule[bankv1beta1.QueryBalanceResponse](ctx, &bankv1beta1.QueryBalanceRequest{
resp, err := implementation.QueryModule(ctx, &banktypes.QueryBalanceRequest{
Address: string(implementation.Whoami(ctx)),
Denom: req.Value,
})
@ -98,11 +96,12 @@ func (t TestAccount) RegisterQueryHandlers(builder *implementation.QueryBuilder)
return nil, err
}
amt, err := strconv.ParseInt(resp.Balance.Amount, 10, 64)
if err != nil {
return nil, err
r, ok := resp.(*banktypes.QueryBalanceResponse)
if !ok {
panic(fmt.Sprintf("unexpected response type: %T", resp))
}
return &types.Int64Value{Value: amt}, nil
return &types.Int64Value{Value: r.Balance.Amount.Int64()}, nil
})
// genesis testing; DoubleValue does not make sense as a request type for this query, but empty is already taken

View File

@ -6,6 +6,7 @@ import (
"context"
"fmt"
"cosmossdk.io/core/transaction"
"cosmossdk.io/x/accounts/internal/implementation"
sdk "github.com/cosmos/cosmos-sdk/types"
@ -90,18 +91,13 @@ func SenderIsAccountsModule(ctx context.Context) bool {
// returns nil.
func Funds(ctx context.Context) sdk.Coins { return implementation.Funds(ctx) }
// ExecModule can be used to execute a message towards a module.
func ExecModule[Resp any, RespProto implementation.ProtoMsgG[Resp], Req any, ReqProto implementation.ProtoMsgG[Req]](ctx context.Context, msg ReqProto) (RespProto, error) {
return implementation.ExecModule[Resp, RespProto, Req, ReqProto](ctx, msg)
}
func ExecModuleUntyped(ctx context.Context, msg implementation.ProtoMsg) (implementation.ProtoMsg, error) {
return implementation.ExecModuleUntyped(ctx, msg)
func ExecModule(ctx context.Context, msg transaction.Msg) (transaction.Msg, error) {
return implementation.ExecModule(ctx, msg)
}
// QueryModule can be used by an account to execute a module query.
func QueryModule[Resp any, RespProto implementation.ProtoMsgG[Resp], Req any, ReqProto implementation.ProtoMsgG[Req]](ctx context.Context, req ReqProto) (RespProto, error) {
return implementation.QueryModule[Resp, RespProto, Req, ReqProto](ctx, req)
func QueryModule(ctx context.Context, req transaction.Msg) (transaction.Msg, error) {
return implementation.QueryModule(ctx, req)
}
// UnpackAny unpacks a protobuf Any message generically.
@ -110,7 +106,7 @@ func UnpackAny[Msg any, ProtoMsg implementation.ProtoMsgG[Msg]](any *implementat
}
// PackAny packs a protobuf Any message generically.
func PackAny(msg implementation.ProtoMsg) (*implementation.Any, error) {
func PackAny(msg transaction.Msg) (*implementation.Any, error) {
return implementation.PackAny(msg)
}
@ -124,7 +120,7 @@ func ExecModuleAnys(ctx context.Context, msgs []*implementation.Any) ([]*impleme
if err != nil {
return nil, fmt.Errorf("error unpacking message %d: %w", i, err)
}
resp, err := ExecModuleUntyped(ctx, concreteMessage)
resp, err := ExecModule(ctx, concreteMessage)
if err != nil {
return nil, fmt.Errorf("error executing message %d: %w", i, err)
}

View File

@ -4,7 +4,7 @@ import (
"context"
"cosmossdk.io/core/store"
"cosmossdk.io/core/testing"
coretesting "cosmossdk.io/core/testing"
"cosmossdk.io/x/accounts/internal/implementation"
sdk "github.com/cosmos/cosmos-sdk/types"
@ -16,14 +16,13 @@ func NewMockContext(
sender []byte,
funds sdk.Coins,
moduleExec implementation.ModuleExecFunc,
moduleExecUntyped implementation.ModuleExecUntypedFunc,
moduleQuery implementation.ModuleQueryFunc,
) (context.Context, store.KVStoreService) {
ctx := coretesting.Context()
ss := coretesting.KVStoreService(ctx, "test")
return implementation.MakeAccountContext(
ctx, ss, accNumber, accountAddr, sender, funds, moduleExec, moduleExecUntyped, moduleQuery,
ctx, ss, accNumber, accountAddr, sender, funds, moduleExec, moduleQuery,
), ss
}

View File

@ -1,12 +1,9 @@
package accounts
import (
"google.golang.org/protobuf/proto"
bankv1beta1 "cosmossdk.io/api/cosmos/bank/v1beta1"
v1beta1 "cosmossdk.io/api/cosmos/base/v1beta1"
"cosmossdk.io/core/address"
"cosmossdk.io/x/accounts/internal/implementation"
"cosmossdk.io/core/transaction"
banktypes "cosmossdk.io/x/bank/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)
@ -14,49 +11,22 @@ import (
// coinsTransferMsgFunc defines a function that creates a message to send coins from one
// address to the other, and also a message that parses such response.
// This in most cases will be implemented as a bank.MsgSend creator, but we keep x/accounts independent of bank.
type coinsTransferMsgFunc = func(from, to []byte, coins sdk.Coins) (implementation.ProtoMsg, implementation.ProtoMsg, error)
type gogoProtoPlusV2 interface {
proto.Message
implementation.ProtoMsg
}
// protoV2GogoWrapper is a wrapper of a protov2 message into a gogo message.
// this is exceptionally allowed to enable accounts to be decoupled from
// the SDK, since x/accounts can support only protov1 in its APIs.
// But in order to keep it decoupled from the SDK we need to use the API module.
// This is a hack to make an API module type work in x/accounts. Once the SDK
// has protov2 support, we can migrate internal/implementation/encoding.go to
// work with protov2.
type protoV2GogoWrapper struct {
gogoProtoPlusV2
}
func (h protoV2GogoWrapper) XXX_MessageName() string {
return string(proto.MessageName(h.gogoProtoPlusV2))
}
type coinsTransferMsgFunc = func(from, to []byte, coins sdk.Coins) (transaction.Msg, error)
func defaultCoinsTransferMsgFunc(addrCdc address.Codec) coinsTransferMsgFunc {
return func(from, to []byte, coins sdk.Coins) (implementation.ProtoMsg, implementation.ProtoMsg, error) {
return func(from, to []byte, coins sdk.Coins) (transaction.Msg, error) {
fromAddr, err := addrCdc.BytesToString(from)
if err != nil {
return nil, nil, err
return nil, err
}
toAddr, err := addrCdc.BytesToString(to)
if err != nil {
return nil, nil, err
return nil, err
}
v2Coins := make([]*v1beta1.Coin, len(coins))
for i, coin := range coins {
v2Coins[i] = &v1beta1.Coin{
Denom: coin.Denom,
Amount: coin.Amount.String(),
}
}
return protoV2GogoWrapper{&bankv1beta1.MsgSend{
return &banktypes.MsgSend{
FromAddress: fromAddr,
ToAddress: toAddr,
Amount: v2Coins,
}}, new(bankv1beta1.MsgSendResponse), nil
Amount: coins,
}, nil
}
}

View File

@ -163,12 +163,17 @@ func (a Account) computeSignerData(ctx context.Context) (secp256k1.PubKey, signi
}
func (a Account) getNumber(ctx context.Context, addrStr string) (uint64, error) {
accNum, err := accountstd.QueryModule[accountsv1.AccountNumberResponse](ctx, &accountsv1.AccountNumberRequest{Address: addrStr})
accNum, err := accountstd.QueryModule(ctx, &accountsv1.AccountNumberRequest{Address: addrStr})
if err != nil {
return 0, err
}
return accNum.Number, nil
resp, ok := accNum.(*accountsv1.AccountNumberResponse)
if !ok {
return 0, fmt.Errorf("unexpected response type: %T", accNum)
}
return resp.Number, nil
}
func (a Account) getTxData(msg *aa_interface_v1.MsgAuthenticate) (signing.TxData, error) {

View File

@ -5,8 +5,6 @@ import (
"testing"
gogoproto "github.com/cosmos/gogoproto/proto"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/runtime/protoiface"
signingv1beta1 "cosmossdk.io/api/cosmos/tx/signing/v1beta1"
"cosmossdk.io/collections"
@ -14,6 +12,7 @@ import (
"cosmossdk.io/core/event"
"cosmossdk.io/core/header"
"cosmossdk.io/core/store"
"cosmossdk.io/core/transaction"
"cosmossdk.io/x/accounts/accountstd"
accountsv1 "cosmossdk.io/x/accounts/v1"
"cosmossdk.io/x/tx/signing"
@ -24,8 +23,6 @@ import (
"github.com/cosmos/cosmos-sdk/types/tx"
)
type ProtoMsg = protoiface.MessageV1
// mock statecodec
type mockStateCodec struct {
codec.Codec
@ -58,17 +55,13 @@ func (a addressCodec) BytesToString(bz []byte) (string, error) { return string
func newMockContext(t *testing.T) (context.Context, store.KVStoreService) {
t.Helper()
return accountstd.NewMockContext(
0, []byte("mock_base_account"), []byte("sender"), nil, func(ctx context.Context, sender []byte, msg, msgResp ProtoMsg) error {
return nil
}, func(ctx context.Context, sender []byte, msg ProtoMsg) (ProtoMsg, error) {
0, []byte("mock_base_account"), []byte("sender"), nil,
func(ctx context.Context, sender []byte, msg transaction.Msg) (transaction.Msg, error) {
return nil, nil
}, func(ctx context.Context, req, resp ProtoMsg) error {
_, ok := req.(*accountsv1.AccountNumberRequest)
require.True(t, ok)
gogoproto.Merge(resp.(gogoproto.Message), &accountsv1.AccountNumberResponse{
}, func(ctx context.Context, req transaction.Msg) (transaction.Msg, error) {
return &accountsv1.AccountNumberResponse{
Number: 1,
})
return nil
}, nil
},
)
}

View File

@ -13,30 +13,20 @@ require (
github.com/cosmos/gogoproto v1.7.0
)
require cosmossdk.io/x/consensus v0.0.0-00010101000000-000000000000 // indirect
require github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
require (
buf.build/gen/go/cometbft/cometbft/protocolbuffers/go v1.34.2-20240701160653-fedbb9acfd2f.2 // indirect
cosmossdk.io/core/testing v0.0.0-00010101000000-000000000000 // indirect
cosmossdk.io/depinject v1.0.0 // indirect
github.com/cometbft/cometbft/api v1.0.0-rc.1 // indirect
github.com/cosmos/crypto v0.1.2 // indirect
github.com/dgraph-io/badger/v4 v4.2.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/google/flatbuffers v2.0.8+incompatible // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/supranational/blst v0.3.12 // indirect
go.opencensus.io v0.24.0 // indirect
)
require (
buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.34.2-20240130113600-88ef6483f90f.2 // indirect
cosmossdk.io/api v0.7.5 // indirect
cosmossdk.io/core/testing v0.0.0-00010101000000-000000000000 // indirect
cosmossdk.io/depinject v1.0.0 // indirect
cosmossdk.io/errors v1.0.1
cosmossdk.io/log v1.4.1
cosmossdk.io/math v1.3.0
cosmossdk.io/store v1.1.1-0.20240418092142-896cdf1971bc // indirect
cosmossdk.io/x/auth v0.0.0-00010101000000-000000000000 // indirect
cosmossdk.io/x/consensus v0.0.0-00010101000000-000000000000 // indirect
cosmossdk.io/x/tx v0.13.3 // indirect
filippo.io/edwards25519 v1.1.0 // indirect
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect
@ -53,9 +43,11 @@ require (
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect
github.com/cometbft/cometbft v1.0.0-rc1 // indirect
github.com/cometbft/cometbft-db v0.12.0 // indirect
github.com/cometbft/cometbft/api v1.0.0-rc.1 // indirect
github.com/cosmos/btcutil v1.0.5 // indirect
github.com/cosmos/cosmos-db v1.0.2 // indirect
github.com/cosmos/cosmos-proto v1.0.0-beta.5
github.com/cosmos/crypto v0.1.2 // indirect
github.com/cosmos/go-bip39 v1.0.0 // indirect
github.com/cosmos/iavl v1.2.1-0.20240725141113-7adc688cf179 // indirect
github.com/cosmos/ics23/go v0.10.0 // indirect
@ -63,6 +55,7 @@ require (
github.com/danieljoos/wincred v1.2.1 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect
github.com/dgraph-io/badger/v4 v4.2.0 // indirect
github.com/dgraph-io/ristretto v0.1.1 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/dvsekhvalnov/jose2go v1.6.0 // indirect
@ -75,9 +68,10 @@ require (
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/glog v1.2.1 // indirect
github.com/golang/protobuf v1.5.4
github.com/golang/protobuf v1.5.4 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/btree v1.1.2 // indirect
github.com/google/flatbuffers v2.0.8+incompatible // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/gorilla/websocket v1.5.3 // indirect
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
@ -100,6 +94,7 @@ require (
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mtibben/percent v0.2.1 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/petermattis/goid v0.0.0-20240327183114-c42a807a84ba // indirect
@ -123,6 +118,7 @@ require (
github.com/spf13/viper v1.19.0 // indirect
github.com/stretchr/testify v1.9.0
github.com/subosito/gotenv v1.6.0 // indirect
github.com/supranational/blst v0.3.12 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect
github.com/tendermint/go-amino v0.16.0 // indirect
github.com/tidwall/btree v1.7.0 // indirect
@ -131,6 +127,7 @@ require (
gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b // indirect
gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 // indirect
go.etcd.io/bbolt v1.4.0-alpha.0.0.20240404170359-43604f3112c5 // indirect
go.opencensus.io v0.24.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/crypto v0.26.0 // indirect
golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc // indirect

View File

@ -4,6 +4,7 @@ import (
"bytes"
"context"
"errors"
"fmt"
"time"
"github.com/cosmos/gogoproto/proto"
@ -386,7 +387,7 @@ func (bva *BaseLockup) checkSender(ctx context.Context, sender string) error {
}
func sendMessage(ctx context.Context, msg proto.Message) ([]*codectypes.Any, error) {
response, err := accountstd.ExecModuleUntyped(ctx, msg)
response, err := accountstd.ExecModule(ctx, msg)
if err != nil {
return nil, err
}
@ -401,13 +402,16 @@ func sendMessage(ctx context.Context, msg proto.Message) ([]*codectypes.Any, err
func getStakingDenom(ctx context.Context) (string, error) {
// Query account balance for the sent denom
paramsQueryReq := &stakingtypes.QueryParamsRequest{}
resp, err := accountstd.QueryModule[stakingtypes.QueryParamsResponse](ctx, paramsQueryReq)
resp, err := accountstd.QueryModule(ctx, &stakingtypes.QueryParamsRequest{})
if err != nil {
return "", err
}
res, ok := resp.(*stakingtypes.QueryParamsResponse)
if !ok {
return "", fmt.Errorf("unexpected response type: %T", resp)
}
return resp.Params.BondDenom, nil
return res.Params.BondDenom, nil
}
// TrackDelegation tracks a delegation amount for any given lockup account type
@ -532,13 +536,17 @@ func (bva *BaseLockup) TrackUndelegation(ctx context.Context, amount sdk.Coins)
func (bva BaseLockup) getBalance(ctx context.Context, sender, denom string) (*sdk.Coin, error) {
// Query account balance for the sent denom
balanceQueryReq := &banktypes.QueryBalanceRequest{Address: sender, Denom: denom}
resp, err := accountstd.QueryModule[banktypes.QueryBalanceResponse](ctx, balanceQueryReq)
resp, err := accountstd.QueryModule(ctx, &banktypes.QueryBalanceRequest{Address: sender, Denom: denom})
if err != nil {
return nil, err
}
return resp.Balance, nil
res, ok := resp.(*banktypes.QueryBalanceResponse)
if !ok {
return nil, fmt.Errorf("unexpected response type: %T", resp)
}
return res.Balance, nil
}
func (bva BaseLockup) checkTokensSendable(ctx context.Context, sender string, amount, lockedCoins sdk.Coins) error {

View File

@ -6,14 +6,13 @@ import (
"testing"
gogoproto "github.com/cosmos/gogoproto/proto"
"github.com/golang/protobuf/proto" // nolint: staticcheck // needed because gogoproto.Merge does not work consistently. See NOTE: comments.
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/runtime/protoiface"
"cosmossdk.io/collections"
"cosmossdk.io/core/appmodule/v2"
"cosmossdk.io/core/header"
"cosmossdk.io/core/store"
"cosmossdk.io/core/transaction"
"cosmossdk.io/math"
"cosmossdk.io/x/accounts/accountstd"
banktypes "cosmossdk.io/x/bank/types"
@ -24,8 +23,6 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
)
type ProtoMsg = protoiface.MessageV1
var TestFunds = sdk.NewCoins(sdk.NewCoin("test", math.NewInt(10)))
// mock statecodec
@ -52,9 +49,9 @@ func (c mockStateCodec) Unmarshal(bz []byte, ptr gogoproto.Message) error {
}
type (
ModuleExecUntypedFunc = func(ctx context.Context, sender []byte, msg ProtoMsg) (ProtoMsg, error)
ModuleExecFunc = func(ctx context.Context, sender []byte, msg, msgResp ProtoMsg) error
ModuleQueryFunc = func(ctx context.Context, queryReq, queryResp ProtoMsg) error
ModuleExecUntypedFunc = func(ctx context.Context, sender []byte, msg transaction.Msg) (transaction.Msg, error)
ModuleExecFunc = func(ctx context.Context, sender []byte, msg, msgResp transaction.Msg) error
ModuleQueryFunc = func(ctx context.Context, queryReq, queryResp transaction.Msg) error
)
// mock address codec
@ -73,9 +70,8 @@ func (h headerService) HeaderInfo(ctx context.Context) header.Info {
func newMockContext(t *testing.T) (context.Context, store.KVStoreService) {
t.Helper()
return accountstd.NewMockContext(
0, []byte("lockup_account"), []byte("sender"), TestFunds, func(ctx context.Context, sender []byte, msg, msgResp ProtoMsg) error {
return nil
}, func(ctx context.Context, sender []byte, msg ProtoMsg) (ProtoMsg, error) {
0, []byte("lockup_account"), []byte("sender"), TestFunds,
func(ctx context.Context, sender []byte, msg transaction.Msg) (transaction.Msg, error) {
typeUrl := sdk.MsgTypeURL(msg)
switch typeUrl {
case "/cosmos.staking.v1beta1.MsgDelegate":
@ -89,28 +85,24 @@ func newMockContext(t *testing.T) (context.Context, store.KVStoreService) {
default:
return nil, errors.New("unrecognized request type")
}
}, func(ctx context.Context, req, resp ProtoMsg) error {
}, func(ctx context.Context, req transaction.Msg) (transaction.Msg, error) {
_, ok := req.(*banktypes.QueryBalanceRequest)
if !ok {
_, ok = req.(*stakingtypes.QueryParamsRequest)
require.True(t, ok)
gogoproto.Merge(resp.(gogoproto.Message), &stakingtypes.QueryParamsResponse{
return &stakingtypes.QueryParamsResponse{
Params: stakingtypes.Params{
BondDenom: "test",
},
})
} else {
// NOTE: using gogoproto.Merge will fail for some reason unknown to me, but
// using proto.Merge with gogo messages seems to work fine.
proto.Merge(resp.(gogoproto.Message), &banktypes.QueryBalanceResponse{
Balance: &(sdk.Coin{
Denom: "test",
Amount: TestFunds.AmountOf("test"),
}),
})
}, nil
}
return nil
return &banktypes.QueryBalanceResponse{
Balance: &(sdk.Coin{
Denom: "test",
Amount: TestFunds.AmountOf("test"),
}),
}, nil
},
)
}

View File

@ -10,12 +10,13 @@ import (
"github.com/stretchr/testify/require"
"cosmossdk.io/core/store"
"cosmossdk.io/core/transaction"
"cosmossdk.io/x/accounts/accountstd"
v1 "cosmossdk.io/x/accounts/defaults/multisig/v1"
accountsv1 "cosmossdk.io/x/accounts/v1"
)
func setup(t *testing.T, ctx context.Context, ss store.KVStoreService, timefn func() time.Time) *Account {
func setup(t *testing.T, _ context.Context, ss store.KVStoreService, timefn func() time.Time) *Account {
t.Helper()
deps := makeMockDependencies(ss, timefn)
@ -442,15 +443,13 @@ func TestProposal_NotPassing(t *testing.T) {
}
ctx, ss := accountstd.NewMockContext(
0, []byte("multisig_acc"), []byte("addr1"), TestFunds, func(ctx context.Context, sender []byte, msg, msgResp ProtoMsg) error {
return nil
}, func(ctx context.Context, sender []byte, msg ProtoMsg) (ProtoMsg, error) {
0, []byte("multisig_acc"), []byte("addr1"), TestFunds, func(ctx context.Context, sender []byte, msg transaction.Msg) (transaction.Msg, error) {
if _, ok := msg.(*v1.MsgUpdateConfig); ok {
return &v1.MsgUpdateConfigResponse{}, nil
}
return nil, nil
}, func(ctx context.Context, req, resp ProtoMsg) error {
return nil
}, func(ctx context.Context, req transaction.Msg) (transaction.Msg, error) {
return nil, nil
},
)
@ -565,9 +564,8 @@ func TestProposalPassing(t *testing.T) {
var ctx context.Context
var ss store.KVStoreService
ctx, ss = accountstd.NewMockContext(
0, []byte("multisig_acc"), []byte("addr1"), TestFunds, func(ctx context.Context, sender []byte, msg, msgResp ProtoMsg) error {
return nil
}, func(ictx context.Context, sender []byte, msg ProtoMsg) (ProtoMsg, error) {
0, []byte("multisig_acc"), []byte("addr1"), TestFunds,
func(ictx context.Context, sender []byte, msg transaction.Msg) (transaction.Msg, error) {
if execmsg, ok := msg.(*accountsv1.MsgExecute); ok {
updateCfg, err := accountstd.UnpackAny[v1.MsgUpdateConfig](execmsg.GetMessage())
if err != nil {
@ -578,8 +576,8 @@ func TestProposalPassing(t *testing.T) {
return acc.UpdateConfig(ctx, updateCfg)
}
return nil, nil
}, func(ctx context.Context, req, resp ProtoMsg) error {
return nil
}, func(ctx context.Context, req transaction.Msg) (transaction.Msg, error) {
return nil, nil
},
)

View File

@ -9,13 +9,13 @@ import (
types "github.com/cosmos/gogoproto/types/any"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/runtime/protoiface"
"cosmossdk.io/collections"
"cosmossdk.io/core/appmodule/v2"
"cosmossdk.io/core/event"
"cosmossdk.io/core/header"
"cosmossdk.io/core/store"
"cosmossdk.io/core/transaction"
"cosmossdk.io/math"
"cosmossdk.io/x/accounts/accountstd"
banktypes "cosmossdk.io/x/bank/types"
@ -26,8 +26,6 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
)
type ProtoMsg = protoiface.MessageV1
var TestFunds = sdk.NewCoins(sdk.NewCoin("test", math.NewInt(10)))
// mock statecodec
@ -149,9 +147,9 @@ func (c mockStateCodec) Unmarshal(bz []byte, ptr gogoproto.Message) error {
}
type (
ModuleExecUntypedFunc = func(ctx context.Context, sender []byte, msg ProtoMsg) (ProtoMsg, error)
ModuleExecFunc = func(ctx context.Context, sender []byte, msg, msgResp ProtoMsg) error
ModuleQueryFunc = func(ctx context.Context, queryReq, queryResp ProtoMsg) error
ModuleExecUntypedFunc = func(ctx context.Context, sender []byte, msg transaction.Msg) (transaction.Msg, error)
ModuleExecFunc = func(ctx context.Context, sender []byte, msg, msgResp transaction.Msg) error
ModuleQueryFunc = func(ctx context.Context, queryReq, queryResp transaction.Msg) error
)
// mock address codec
@ -163,20 +161,19 @@ func (a addressCodec) BytesToString(bz []byte) (string, error) { return string
func newMockContext(t *testing.T) (context.Context, store.KVStoreService) {
t.Helper()
return accountstd.NewMockContext(
0, []byte("mock_multisig_account"), []byte("sender"), TestFunds, func(ctx context.Context, sender []byte, msg, msgResp ProtoMsg) error {
return nil
}, func(ctx context.Context, sender []byte, msg ProtoMsg) (ProtoMsg, error) {
0, []byte("mock_multisig_account"), []byte("sender"), TestFunds, func(ctx context.Context, sender []byte, msg transaction.Msg) (transaction.Msg, error) {
return nil, nil
}, func(ctx context.Context, req, resp ProtoMsg) error {
}, func(ctx context.Context, req transaction.Msg) (transaction.Msg, error) {
var resp transaction.Msg
_, ok := req.(*banktypes.QueryBalanceRequest)
require.True(t, ok)
gogoproto.Merge(resp.(gogoproto.Message), &banktypes.QueryBalanceResponse{
gogoproto.Merge(resp, &banktypes.QueryBalanceResponse{
Balance: &sdk.Coin{
Denom: "test",
Amount: math.NewInt(5),
},
})
return nil
return resp, nil
},
)
}

View File

@ -20,23 +20,18 @@ require (
google.golang.org/protobuf v1.34.2
)
require github.com/golang/mock v1.6.0 // indirect
require (
cosmossdk.io/schema v0.1.1 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
)
require (
buf.build/gen/go/cometbft/cometbft/protocolbuffers/go v1.34.2-20240701160653-fedbb9acfd2f.2 // indirect
buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.34.2-20240130113600-88ef6483f90f.2 // indirect
cosmossdk.io/errors v1.0.1 // indirect
cosmossdk.io/log v1.4.1 // indirect
cosmossdk.io/math v1.3.0
cosmossdk.io/schema v0.1.1 // indirect
cosmossdk.io/store v1.1.1-0.20240418092142-896cdf1971bc // indirect
cosmossdk.io/x/accounts/defaults/lockup v0.0.0-20240417181816-5e7aae0db1f5
cosmossdk.io/x/auth v0.0.0-00010101000000-000000000000 // indirect
cosmossdk.io/x/consensus v0.0.0-00010101000000-000000000000 // indirect
cosmossdk.io/x/distribution v0.0.0-00010101000000-000000000000 // indirect
cosmossdk.io/x/staking v0.0.0-00010101000000-000000000000 // indirect
filippo.io/edwards25519 v1.1.0 // indirect
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect
@ -85,6 +80,7 @@ require (
github.com/gogo/protobuf v1.3.2
github.com/golang/glog v1.2.1 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/btree v1.1.2 // indirect
@ -123,6 +119,7 @@ require (
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mtibben/percent v0.2.1 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a // indirect
github.com/oklog/run v1.1.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
@ -184,6 +181,7 @@ replace (
cosmossdk.io/collections => ../../collections
cosmossdk.io/core => ../../core
cosmossdk.io/core/testing => ../../core/testing
cosmossdk.io/x/accounts/defaults/lockup => ./defaults/lockup
cosmossdk.io/x/accounts/defaults/multisig => ./defaults/multisig
cosmossdk.io/x/auth => ../auth
cosmossdk.io/x/bank => ../bank

View File

@ -16,8 +16,6 @@ cosmossdk.io/schema v0.1.1 h1:I0M6pgI7R10nq+/HCQfbO6BsGBZA8sQy+duR1Y3aKcA=
cosmossdk.io/schema v0.1.1/go.mod h1:RDAhxIeNB4bYqAlF4NBJwRrgtnciMcyyg0DOKnhNZQQ=
cosmossdk.io/store v1.1.1-0.20240418092142-896cdf1971bc h1:R9O9d75e0qZYUsVV0zzi+D7cNLnX2JrUOQNoIPaF0Bg=
cosmossdk.io/store v1.1.1-0.20240418092142-896cdf1971bc/go.mod h1:amTTatOUV3u1PsKmNb87z6/galCxrRbz9kRdJkL0DyU=
cosmossdk.io/x/accounts/defaults/lockup v0.0.0-20240417181816-5e7aae0db1f5 h1:eb0kcGyaYHSS0do7+MIWg7UKlskSH01biRNENbm/zDA=
cosmossdk.io/x/accounts/defaults/lockup v0.0.0-20240417181816-5e7aae0db1f5/go.mod h1:drzY4oVisyWvSgpsM7ccQ7IX3efMuVIvd9Eij1Gm/6o=
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs=

View File

@ -4,6 +4,8 @@ import (
"context"
"errors"
"fmt"
"cosmossdk.io/core/transaction"
)
var (
@ -22,7 +24,7 @@ type InitBuilder struct {
// handler is the handler function that will be called when the smart account is initialized.
// Although the function here is defined to take an any, the smart account will work
// with a typed version of it.
handler func(ctx context.Context, initRequest ProtoMsg) (initResponse ProtoMsg, err error)
handler func(ctx context.Context, initRequest transaction.Msg) (initResponse transaction.Msg, err error)
// schema is the schema of the message that will be passed to the handler function.
schema HandlerSchema
@ -30,7 +32,7 @@ type InitBuilder struct {
// makeHandler returns the handler function that will be called when the smart account is initialized.
// It returns an error if no handler was registered.
func (i *InitBuilder) makeHandler() (func(ctx context.Context, initRequest ProtoMsg) (initResponse ProtoMsg, err error), error) {
func (i *InitBuilder) makeHandler() (func(ctx context.Context, initRequest transaction.Msg) (initResponse transaction.Msg, err error), error) {
if i.handler == nil {
return nil, errNoInitHandler
}
@ -40,7 +42,7 @@ func (i *InitBuilder) makeHandler() (func(ctx context.Context, initRequest Proto
// NewExecuteBuilder creates a new ExecuteBuilder instance.
func NewExecuteBuilder() *ExecuteBuilder {
return &ExecuteBuilder{
handlers: make(map[string]func(ctx context.Context, executeRequest ProtoMsg) (executeResponse ProtoMsg, err error)),
handlers: make(map[string]func(ctx context.Context, executeRequest transaction.Msg) (executeResponse transaction.Msg, err error)),
handlersSchema: make(map[string]HandlerSchema),
}
}
@ -49,7 +51,7 @@ func NewExecuteBuilder() *ExecuteBuilder {
// to a handler function for a specific account.
type ExecuteBuilder struct {
// handlers is a map of handler functions that will be called when the smart account is executed.
handlers map[string]func(ctx context.Context, executeRequest ProtoMsg) (executeResponse ProtoMsg, err error)
handlers map[string]func(ctx context.Context, executeRequest transaction.Msg) (executeResponse transaction.Msg, err error)
// handlersSchema is a map of schemas for the messages that will be passed to the handler functions
// and the messages that will be returned by the handler functions.
@ -59,10 +61,10 @@ type ExecuteBuilder struct {
err error
}
func (r *ExecuteBuilder) makeHandler() (func(ctx context.Context, executeRequest ProtoMsg) (executeResponse ProtoMsg, err error), error) {
func (r *ExecuteBuilder) makeHandler() (func(ctx context.Context, executeRequest transaction.Msg) (executeResponse transaction.Msg, err error), error) {
// if no handler is registered it's fine, it means the account will not be accepting execution or query messages.
if len(r.handlers) == 0 {
return func(ctx context.Context, _ ProtoMsg) (_ ProtoMsg, err error) {
return func(ctx context.Context, _ transaction.Msg) (_ transaction.Msg, err error) {
return nil, errNoExecuteHandler
}, nil
}
@ -72,7 +74,7 @@ func (r *ExecuteBuilder) makeHandler() (func(ctx context.Context, executeRequest
}
// build the real execution handler
return func(ctx context.Context, executeRequest ProtoMsg) (executeResponse ProtoMsg, err error) {
return func(ctx context.Context, executeRequest transaction.Msg) (executeResponse transaction.Msg, err error) {
messageName := MessageName(executeRequest)
handler, ok := r.handlers[messageName]
if !ok {
@ -96,7 +98,7 @@ type QueryBuilder struct {
er *ExecuteBuilder
}
func (r *QueryBuilder) makeHandler() (func(ctx context.Context, queryRequest ProtoMsg) (queryResponse ProtoMsg, err error), error) {
func (r *QueryBuilder) makeHandler() (func(ctx context.Context, queryRequest transaction.Msg) (queryResponse transaction.Msg, err error), error) {
return r.er.makeHandler()
}

View File

@ -6,6 +6,7 @@ import (
"cosmossdk.io/collections"
"cosmossdk.io/core/store"
"cosmossdk.io/core/transaction"
"cosmossdk.io/x/accounts/internal/prefixstore"
sdk "github.com/cosmos/cosmos-sdk/types"
@ -14,22 +15,20 @@ import (
var AccountStatePrefix = collections.NewPrefix(255)
type (
ModuleExecUntypedFunc = func(ctx context.Context, sender []byte, msg ProtoMsg) (ProtoMsg, error)
ModuleExecFunc = func(ctx context.Context, sender []byte, msg, msgResp ProtoMsg) error
ModuleQueryFunc = func(ctx context.Context, queryReq, queryResp ProtoMsg) error
ModuleExecFunc = func(ctx context.Context, sender []byte, msg transaction.Msg) (transaction.Msg, error)
ModuleQueryFunc = func(ctx context.Context, queryReq transaction.Msg) (transaction.Msg, error)
)
type contextKey struct{}
type contextValue struct {
store store.KVStore // store is the prefixed store for the account.
sender []byte // sender is the address of the entity invoking the account action.
whoami []byte // whoami is the address of the account being invoked.
funds sdk.Coins // funds reports the coins sent alongside the request.
parentContext context.Context // parentContext that was used to build the account context.
moduleExec ModuleExecFunc // moduleExec is a function that executes a module message, when the resp type is known.
moduleExecUntyped ModuleExecUntypedFunc // moduleExecUntyped is a function that executes a module message, when the resp type is unknown.
moduleQuery ModuleQueryFunc // moduleQuery is a function that queries a module.
store store.KVStore // store is the prefixed store for the account.
sender []byte // sender is the address of the entity invoking the account action.
whoami []byte // whoami is the address of the account being invoked.
funds sdk.Coins // funds reports the coins sent alongside the request.
parentContext context.Context // parentContext that was used to build the account context.
moduleExec ModuleExecFunc // moduleExec is a function that executes a module message, when the resp type is unknown.
moduleQuery ModuleQueryFunc // moduleQuery is a function that queries a module.
}
func addCtx(ctx context.Context, value contextValue) context.Context {
@ -55,18 +54,16 @@ func MakeAccountContext(
sender []byte,
funds sdk.Coins,
moduleExec ModuleExecFunc,
moduleExecUntyped ModuleExecUntypedFunc,
moduleQuery ModuleQueryFunc,
) context.Context {
return addCtx(ctx, contextValue{
store: makeAccountStore(ctx, storeSvc, accNumber),
sender: sender,
whoami: accountAddr,
funds: funds,
parentContext: ctx,
moduleExec: moduleExec,
moduleExecUntyped: moduleExecUntyped,
moduleQuery: moduleQuery,
store: makeAccountStore(ctx, storeSvc, accNumber),
sender: sender,
whoami: accountAddr,
funds: funds,
parentContext: ctx,
moduleExec: moduleExec,
moduleQuery: moduleQuery,
})
}
@ -85,27 +82,12 @@ func makeAccountStore(ctx context.Context, storeSvc store.KVStoreService, accNum
return prefixstore.New(storeSvc.OpenKVStore(ctx), append(AccountStatePrefix, prefix...))
}
// ExecModuleUntyped can be used to execute a message towards a module, when the response type is unknown.
func ExecModuleUntyped(ctx context.Context, msg ProtoMsg) (ProtoMsg, error) {
// ExecModule can be used to execute a message towards a module, when the response type is unknown.
func ExecModule(ctx context.Context, msg transaction.Msg) (transaction.Msg, error) {
// get sender
v := getCtx(ctx)
resp, err := v.moduleExecUntyped(v.parentContext, v.whoami, msg)
if err != nil {
return nil, err
}
return resp, nil
}
// ExecModule can be used to execute a message towards a module.
func ExecModule[Resp any, RespProto ProtoMsgG[Resp], Req any, ReqProto ProtoMsgG[Req]](ctx context.Context, msg ReqProto) (RespProto, error) {
// get sender
v := getCtx(ctx)
// execute module, unwrapping the original context.
resp := RespProto(new(Resp))
err := v.moduleExec(v.parentContext, v.whoami, msg, resp)
resp, err := v.moduleExec(v.parentContext, v.whoami, msg)
if err != nil {
return nil, err
}
@ -114,12 +96,11 @@ func ExecModule[Resp any, RespProto ProtoMsgG[Resp], Req any, ReqProto ProtoMsgG
}
// QueryModule can be used by an account to execute a module query.
func QueryModule[Resp any, RespProto ProtoMsgG[Resp], Req any, ReqProto ProtoMsgG[Req]](ctx context.Context, req ReqProto) (RespProto, error) {
func QueryModule(ctx context.Context, req transaction.Msg) (transaction.Msg, error) {
// we do not need to check the sender in a query because it is not a state transition.
// we also unwrap the original context.
v := getCtx(ctx)
resp := RespProto(new(Resp))
err := v.moduleQuery(v.parentContext, req, resp)
resp, err := v.moduleQuery(v.parentContext, req)
if err != nil {
return nil, err
}

View File

@ -9,7 +9,8 @@ import (
"github.com/stretchr/testify/require"
"cosmossdk.io/collections"
"cosmossdk.io/core/testing"
coretesting "cosmossdk.io/core/testing"
"cosmossdk.io/core/transaction"
)
func TestMakeAccountContext(t *testing.T) {
@ -19,7 +20,7 @@ func TestMakeAccountContext(t *testing.T) {
sender := []byte("sender")
sb := collections.NewSchemaBuilderFromAccessor(openKVStore)
accountCtx := MakeAccountContext(originalContext, storeService, 1, accountAddr, sender, nil, nil, nil, nil)
accountCtx := MakeAccountContext(originalContext, storeService, 1, accountAddr, sender, nil, nil, nil)
// ensure whoami
require.Equal(t, accountAddr, Whoami(accountCtx))
@ -43,38 +44,24 @@ func TestMakeAccountContext(t *testing.T) {
value, err := store.Get(append(AccountStatePrefix, append(binary.BigEndian.AppendUint64(nil, 1), itemPrefix...)...))
require.NoError(t, err)
require.Equal(t, []byte{0, 0, 0, 0, 0, 0, 3, 232}, value)
// ensure calling ExecModule works
accountCtx = MakeAccountContext(originalContext, storeService, 1, []byte("legit-exec-module"), []byte("invoker"), nil, func(ctx context.Context, sender []byte, msg, msgResp ProtoMsg) error {
// ensure we unwrapped the context when invoking a module call
require.Equal(t, originalContext, ctx)
Merge(msgResp, &types.StringValue{Value: "module exec was called"})
return nil
}, nil, nil)
resp, err := ExecModule[types.StringValue](accountCtx, &types.UInt64Value{Value: 1000})
require.NoError(t, err)
require.True(t, Equal(&types.StringValue{Value: "module exec was called"}, resp))
// ensure calling ExecModuleUntyped works
accountCtx = MakeAccountContext(originalContext, storeService, 1, []byte("legit-exec-module-untyped"), []byte("invoker"), nil, nil, func(ctx context.Context, sender []byte, msg ProtoMsg) (ProtoMsg, error) {
accountCtx = MakeAccountContext(originalContext, storeService, 1, []byte("legit-exec-module-untyped"), []byte("invoker"), nil, func(ctx context.Context, sender []byte, msg transaction.Msg) (transaction.Msg, error) {
require.Equal(t, originalContext, ctx)
return &types.StringValue{Value: "module exec untyped was called"}, nil
}, nil)
respUntyped, err := ExecModuleUntyped(accountCtx, &types.UInt64Value{Value: 1000})
respUntyped, err := ExecModule(accountCtx, &types.UInt64Value{Value: 1000})
require.NoError(t, err)
require.True(t, Equal(&types.StringValue{Value: "module exec untyped was called"}, respUntyped))
// ensure calling QueryModule works, also by setting everything else communication related to nil
// we can guarantee that exec paths do not impact query paths.
accountCtx = MakeAccountContext(originalContext, storeService, 1, nil, nil, nil, nil, nil, func(ctx context.Context, req, resp ProtoMsg) error {
accountCtx = MakeAccountContext(originalContext, storeService, 1, nil, nil, nil, nil, func(ctx context.Context, req transaction.Msg) (transaction.Msg, error) {
require.Equal(t, originalContext, ctx)
Merge(resp, &types.StringValue{Value: "module query was called"})
return nil
return &types.StringValue{Value: "module query was called"}, nil
})
resp, err = QueryModule[types.StringValue](accountCtx, &types.UInt64Value{Value: 1000})
resp, err := QueryModule(accountCtx, &types.UInt64Value{Value: 1000})
require.NoError(t, err)
require.True(t, Equal(&types.StringValue{Value: "module query was called"}, resp))
}

View File

@ -6,35 +6,34 @@ import (
"strings"
"github.com/cosmos/gogoproto/proto"
"google.golang.org/protobuf/runtime/protoiface"
"cosmossdk.io/core/transaction"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
)
type ProtoMsg = protoiface.MessageV1
// ProtoMsgG is a generic interface for protobuf messages.
type ProtoMsgG[T any] interface {
*T
protoiface.MessageV1
transaction.Msg
}
type Any = codectypes.Any
func FindMessageByName(name string) (ProtoMsg, error) {
func FindMessageByName(name string) (transaction.Msg, error) {
typ := proto.MessageType(name)
if typ == nil {
return nil, fmt.Errorf("no message type found for %s", name)
}
return reflect.New(typ.Elem()).Interface().(ProtoMsg), nil
return reflect.New(typ.Elem()).Interface().(transaction.Msg), nil
}
func MessageName(msg ProtoMsg) string {
func MessageName(msg transaction.Msg) string {
return proto.MessageName(msg)
}
// PackAny packs a proto message into an anypb.Any.
func PackAny(msg ProtoMsg) (*Any, error) {
func PackAny(msg transaction.Msg) (*Any, error) {
return codectypes.NewAnyWithValue(msg)
}
@ -44,7 +43,7 @@ func UnpackAny[T any, PT ProtoMsgG[T]](anyPB *Any) (PT, error) {
return to, UnpackAnyTo(anyPB, PT(to))
}
func UnpackAnyTo(anyPB *Any, to ProtoMsg) error {
func UnpackAnyTo(anyPB *Any, to transaction.Msg) error {
return proto.Unmarshal(anyPB.Value, to)
}
@ -59,10 +58,10 @@ func UnpackAnyRaw(anyPB *Any) (proto.Message, error) {
return to, UnpackAnyTo(anyPB, to)
}
func Merge(a, b ProtoMsg) {
func Merge(a, b transaction.Msg) {
proto.Merge(a, b)
}
func Equal(a, b ProtoMsg) bool {
func Equal(a, b transaction.Msg) bool {
return proto.Equal(a, b)
}

View File

@ -9,6 +9,7 @@ import (
"cosmossdk.io/collections"
"cosmossdk.io/core/address"
"cosmossdk.io/core/appmodule"
"cosmossdk.io/core/transaction"
"github.com/cosmos/cosmos-sdk/codec"
)
@ -107,11 +108,11 @@ func newImplementation(schemaBuilder *collections.SchemaBuilder, account Account
// and non-generic implementation usable by the x/accounts module.
type Implementation struct {
// Init defines the initialisation handler for the smart account.
Init func(ctx context.Context, msg ProtoMsg) (resp ProtoMsg, err error)
Init func(ctx context.Context, msg transaction.Msg) (resp transaction.Msg, err error)
// Execute defines the execution handler for the smart account.
Execute func(ctx context.Context, msg ProtoMsg) (resp ProtoMsg, err error)
Execute func(ctx context.Context, msg transaction.Msg) (resp transaction.Msg, err error)
// Query defines the query handler for the smart account.
Query func(ctx context.Context, msg ProtoMsg) (resp ProtoMsg, err error)
Query func(ctx context.Context, msg transaction.Msg) (resp transaction.Msg, err error)
// CollectionsSchema represents the state schema.
CollectionsSchema collections.Schema
// InitHandlerSchema represents the init handler schema.
@ -123,19 +124,19 @@ type Implementation struct {
}
// HasExec returns true if the account can execute the given msg.
func (i Implementation) HasExec(m ProtoMsg) bool {
func (i Implementation) HasExec(m transaction.Msg) bool {
_, ok := i.ExecuteHandlersSchema[MessageName(m)]
return ok
}
// HasQuery returns true if the account can execute the given request.
func (i Implementation) HasQuery(m ProtoMsg) bool {
func (i Implementation) HasQuery(m transaction.Msg) bool {
_, ok := i.QueryHandlersSchema[MessageName(m)]
return ok
}
// HasInit returns true if the account uses the provided init message.
func (i Implementation) HasInit(m ProtoMsg) bool {
func (i Implementation) HasInit(m transaction.Msg) bool {
return i.InitHandlerSchema.RequestSchema.Name == MessageName(m)
}
@ -145,7 +146,7 @@ type MessageSchema struct {
// Name identifies the message name, this must be queryable from some reflection service.
Name string
// New is used to create a new message instance for the schema.
New func() ProtoMsg
New func() transaction.Msg
}
// HandlerSchema defines the schema of a handler.

View File

@ -5,6 +5,8 @@ import (
"fmt"
"google.golang.org/protobuf/proto"
"cosmossdk.io/core/transaction"
)
// RegisterInitHandler registers an initialisation handler for a smart account that uses protobuf.
@ -14,7 +16,7 @@ func RegisterInitHandler[
) {
reqName := MessageName(ProtoReq(new(Req)))
router.handler = func(ctx context.Context, initRequest ProtoMsg) (initResponse ProtoMsg, err error) {
router.handler = func(ctx context.Context, initRequest transaction.Msg) (initResponse transaction.Msg, err error) {
concrete, ok := initRequest.(ProtoReq)
if !ok {
return nil, fmt.Errorf("%w: wanted %s, got %T", errInvalidMessage, reqName, initRequest)
@ -40,7 +42,7 @@ func RegisterExecuteHandler[
return
}
router.handlers[reqName] = func(ctx context.Context, executeRequest ProtoMsg) (executeResponse ProtoMsg, err error) {
router.handlers[reqName] = func(ctx context.Context, executeRequest transaction.Msg) (executeResponse transaction.Msg, err error) {
concrete, ok := executeRequest.(ProtoReq)
if !ok {
return nil, fmt.Errorf("%w: wanted %s, got %T", errInvalidMessage, reqName, executeRequest)
@ -69,7 +71,7 @@ func NewProtoMessageSchema[T any, PT ProtoMsgG[T]]() *MessageSchema {
}
return &MessageSchema{
Name: MessageName(msg),
New: func() ProtoMsg {
New: func() transaction.Msg {
return PT(new(T))
},
}

View File

@ -13,6 +13,7 @@ import (
"cosmossdk.io/collections"
"cosmossdk.io/core/address"
"cosmossdk.io/core/appmodule"
"cosmossdk.io/core/transaction"
"cosmossdk.io/x/accounts/accountstd"
"cosmossdk.io/x/accounts/internal/implementation"
v1 "cosmossdk.io/x/accounts/v1"
@ -137,9 +138,9 @@ func (k Keeper) Init(
ctx context.Context,
accountType string,
creator []byte,
initRequest implementation.ProtoMsg,
initRequest transaction.Msg,
funds sdk.Coins,
) (implementation.ProtoMsg, []byte, error) {
) (transaction.Msg, []byte, error) {
// get the next account number
num, err := k.AccountNumber.Next(ctx)
if err != nil {
@ -158,7 +159,7 @@ func (k Keeper) Init(
}
// initFromMsg is a helper which inits an account given a v1.MsgInit.
func (k Keeper) initFromMsg(ctx context.Context, initMsg *v1.MsgInit) (implementation.ProtoMsg, []byte, error) {
func (k Keeper) initFromMsg(ctx context.Context, initMsg *v1.MsgInit) (transaction.Msg, []byte, error) {
creator, err := k.addressCodec.StringToBytes(initMsg.Sender)
if err != nil {
return nil, nil, err
@ -182,9 +183,9 @@ func (k Keeper) init(
creator []byte,
accountNum uint64,
accountAddr []byte,
initRequest implementation.ProtoMsg,
initRequest transaction.Msg,
funds sdk.Coins,
) (implementation.ProtoMsg, error) {
) (transaction.Msg, error) {
impl, ok := k.accounts[accountType]
if !ok {
return nil, fmt.Errorf("%w: not found %s", errAccountTypeNotFound, accountType)
@ -223,8 +224,8 @@ func (k Keeper) MigrateLegacyAccount(
addr []byte, // The current address of the account
accNum uint64, // The current account number
accType string, // The account type to migrate to
msg implementation.ProtoMsg, // The init msg of the account type we're migrating to
) (implementation.ProtoMsg, error) {
msg transaction.Msg, // The init msg of the account type we're migrating to
) (transaction.Msg, error) {
return k.init(ctx, accType, addr, accNum, addr, msg, nil)
}
@ -233,9 +234,9 @@ func (k Keeper) Execute(
ctx context.Context,
accountAddr []byte,
sender []byte,
execRequest implementation.ProtoMsg,
execRequest transaction.Msg,
funds sdk.Coins,
) (implementation.ProtoMsg, error) {
) (transaction.Msg, error) {
// get account implementation
impl, err := k.getImplementation(ctx, accountAddr)
if err != nil {
@ -265,8 +266,8 @@ func (k Keeper) Execute(
func (k Keeper) Query(
ctx context.Context,
accountAddr []byte,
queryRequest implementation.ProtoMsg,
) (implementation.ProtoMsg, error) {
queryRequest transaction.Msg,
) (transaction.Msg, error) {
// get account implementation
impl, err := k.getImplementation(ctx, accountAddr)
if err != nil {
@ -315,8 +316,7 @@ func (k Keeper) makeAccountContext(ctx context.Context, accountNumber uint64, ac
accountAddr,
sender,
funds,
k.sendModuleMessage,
k.SendModuleMessageUntyped,
k.SendModuleMessage,
k.queryModule,
)
}
@ -330,10 +330,7 @@ func (k Keeper) makeAccountContext(ctx context.Context, accountNumber uint64, ac
accountAddr,
nil,
nil,
func(ctx context.Context, sender []byte, msg, msgResp implementation.ProtoMsg) error {
return errors.New("cannot execute in query context")
},
func(ctx context.Context, sender []byte, msg implementation.ProtoMsg) (implementation.ProtoMsg, error) {
func(ctx context.Context, sender []byte, msg transaction.Msg) (transaction.Msg, error) {
return nil, errors.New("cannot execute in query context")
},
k.queryModule,
@ -350,7 +347,7 @@ func (k Keeper) sendAnyMessages(ctx context.Context, sender []byte, anyMessages
if err != nil {
return nil, err
}
resp, err := k.SendModuleMessageUntyped(ctx, sender, msg)
resp, err := k.SendModuleMessage(ctx, sender, msg)
if err != nil {
return nil, fmt.Errorf("failed to execute message %d: %s", i, err.Error())
}
@ -363,9 +360,9 @@ func (k Keeper) sendAnyMessages(ctx context.Context, sender []byte, anyMessages
return anyResponses, nil
}
// SendModuleMessageUntyped can be used to send a message towards a module.
// SendModuleMessage can be used to send a message towards a module.
// It should be used when the response type is not known by the caller.
func (k Keeper) SendModuleMessageUntyped(ctx context.Context, sender []byte, msg implementation.ProtoMsg) (implementation.ProtoMsg, error) {
func (k Keeper) SendModuleMessage(ctx context.Context, sender []byte, msg transaction.Msg) (transaction.Msg, error) {
// do sender assertions.
wantSenders, _, err := k.codec.GetMsgSigners(msg)
if err != nil {
@ -377,7 +374,7 @@ func (k Keeper) SendModuleMessageUntyped(ctx context.Context, sender []byte, msg
if !bytes.Equal(sender, wantSenders[0]) {
return nil, fmt.Errorf("%w: sender does not match expected sender", ErrUnauthorized)
}
resp, err := k.MsgRouterService.InvokeUntyped(ctx, msg)
resp, err := k.MsgRouterService.Invoke(ctx, msg)
if err != nil {
return nil, err
}
@ -388,26 +385,27 @@ func (k Keeper) SendModuleMessageUntyped(ctx context.Context, sender []byte, msg
// sendModuleMessage can be used to send a message towards a module. It expects the
// response type to be known by the caller. It will also assert the sender has the right
// is not trying to impersonate another account.
func (k Keeper) sendModuleMessage(ctx context.Context, sender []byte, msg, msgResp implementation.ProtoMsg) error {
func (k Keeper) sendModuleMessage(ctx context.Context, sender []byte, msg transaction.Msg) (transaction.Msg, error) {
// do sender assertions.
wantSenders, _, err := k.codec.GetMsgSigners(msg)
if err != nil {
return fmt.Errorf("cannot get signers: %w", err)
return nil, fmt.Errorf("cannot get signers: %w", err)
}
if len(wantSenders) != 1 {
return fmt.Errorf("expected only one signer, got %d", len(wantSenders))
return nil, fmt.Errorf("expected only one signer, got %d", len(wantSenders))
}
if !bytes.Equal(sender, wantSenders[0]) {
return fmt.Errorf("%w: sender does not match expected sender", ErrUnauthorized)
return nil, fmt.Errorf("%w: sender does not match expected sender", ErrUnauthorized)
}
return k.MsgRouterService.InvokeTyped(ctx, msg, msgResp)
return k.MsgRouterService.Invoke(ctx, msg)
}
// queryModule is the entrypoint for an account to query a module.
// It will try to find the query handler for the given query and execute it.
// If multiple query handlers are found, it will return an error.
func (k Keeper) queryModule(ctx context.Context, queryReq, queryResp implementation.ProtoMsg) error {
return k.QueryRouterService.InvokeTyped(ctx, queryReq, queryResp)
func (k Keeper) queryModule(ctx context.Context, queryReq transaction.Msg) (transaction.Msg, error) {
return k.QueryRouterService.Invoke(ctx, queryReq)
}
// maybeSendFunds will send the provided coins between the provided addresses, if amt
@ -417,23 +415,24 @@ func (k Keeper) maybeSendFunds(ctx context.Context, from, to []byte, amt sdk.Coi
return nil
}
msg, msgResp, err := k.makeSendCoinsMsg(from, to, amt)
msg, err := k.makeSendCoinsMsg(from, to, amt)
if err != nil {
return err
}
// send module message ensures that "from" cannot impersonate.
err = k.sendModuleMessage(ctx, from, msg, msgResp)
_, err = k.sendModuleMessage(ctx, from, msg)
if err != nil {
return err
}
return nil
}
const msgInterfaceName = "cosmos.accounts.v1.MsgInterface"
// creates a new interface type which is an alias of the proto message interface to avoid conflicts with sdk.Msg
type msgInterface implementation.ProtoMsg
type msgInterface transaction.Msg
var msgInterfaceType = (*msgInterface)(nil)

View File

@ -46,11 +46,16 @@ func (sud SetUpContextDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, _ bool,
newCtx = SetGasMeter(ctx, gasTx.GetGas())
// TODO: possibly cache the result of this query for other antehandlers to use
var res consensusv1.QueryParamsResponse
if err := sud.env.QueryRouterService.InvokeTyped(ctx, &consensusv1.QueryParamsRequest{}, &res); err != nil {
resp, err := sud.env.QueryRouterService.Invoke(ctx, &consensusv1.QueryParamsRequest{})
if err != nil {
return newCtx, err
}
res, ok := resp.(*consensusv1.QueryParamsResponse)
if !ok {
return newCtx, fmt.Errorf("unexpected response type: %T", resp)
}
if res.Params.Block != nil {
// If there exists a maximum block gas limit, we must ensure that the tx
// does not exceed it.

View File

@ -29,7 +29,7 @@ import (
// GetMultiSignCommand returns the multi-sign command
func GetMultiSignCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "multi-sign <file> <name> [<signature>...]",
Use: "multi-sign <file> <name> [<signature>...]",
Aliases: []string{"multisign"},
Short: "Generate multisig signatures for transactions generated offline",
Long: strings.TrimSpace(

View File

@ -315,7 +315,7 @@ func (ak AccountKeeper) NonAtomicMsgsExec(ctx context.Context, signer sdk.AccAdd
}
if err := ak.BranchService.Execute(ctx, func(ctx context.Context) error {
result, err := ak.AccountsModKeeper.SendModuleMessageUntyped(ctx, signer, msg)
result, err := ak.AccountsModKeeper.SendModuleMessage(ctx, signer, msg)
if err != nil {
// If an error occurs during message execution, append error response
response := &types.NonAtomicExecResult{Resp: nil, Error: err.Error()}

View File

@ -185,7 +185,7 @@ func (s *KeeperTestSuite) TestNonAtomicExec() {
},
}
s.acctsModKeeper.EXPECT().SendModuleMessageUntyped(gomock.Any(), gomock.Any(), gomock.Any()).
s.acctsModKeeper.EXPECT().SendModuleMessage(gomock.Any(), gomock.Any(), gomock.Any()).
DoAndReturn(func(_ context.Context, sender []byte, msg proto.Message) (protoiface.MessageV1, error) {
return msg, nil
}).AnyTimes()

View File

@ -8,9 +8,9 @@ import (
context "context"
reflect "reflect"
transaction "cosmossdk.io/core/transaction"
types "github.com/cosmos/cosmos-sdk/types"
gomock "github.com/golang/mock/gomock"
protoiface "google.golang.org/protobuf/runtime/protoiface"
)
// MockBankKeeper is a mock of BankKeeper interface.
@ -149,17 +149,17 @@ func (mr *MockAccountsModKeeperMockRecorder) NextAccountNumber(ctx interface{})
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NextAccountNumber", reflect.TypeOf((*MockAccountsModKeeper)(nil).NextAccountNumber), ctx)
}
// SendModuleMessageUntyped mocks base method.
func (m *MockAccountsModKeeper) SendModuleMessageUntyped(ctx context.Context, sender []byte, msg protoiface.MessageV1) (protoiface.MessageV1, error) {
// SendModuleMessage mocks base method.
func (m *MockAccountsModKeeper) SendModuleMessage(ctx context.Context, sender []byte, msg transaction.Msg) (transaction.Msg, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SendModuleMessageUntyped", ctx, sender, msg)
ret0, _ := ret[0].(protoiface.MessageV1)
ret := m.ctrl.Call(m, "SendModuleMessage", ctx, sender, msg)
ret0, _ := ret[0].(transaction.Msg)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// SendModuleMessageUntyped indicates an expected call of SendModuleMessageUntyped.
func (mr *MockAccountsModKeeperMockRecorder) SendModuleMessageUntyped(ctx, sender, msg interface{}) *gomock.Call {
// SendModuleMessage indicates an expected call of SendModuleMessage.
func (mr *MockAccountsModKeeperMockRecorder) SendModuleMessage(ctx, sender, msg interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendModuleMessageUntyped", reflect.TypeOf((*MockAccountsModKeeper)(nil).SendModuleMessageUntyped), ctx, sender, msg)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendModuleMessage", reflect.TypeOf((*MockAccountsModKeeper)(nil).SendModuleMessage), ctx, sender, msg)
}

View File

@ -3,7 +3,7 @@ package types
import (
"context"
"google.golang.org/protobuf/runtime/protoiface"
"cosmossdk.io/core/transaction"
sdk "github.com/cosmos/cosmos-sdk/types"
)
@ -17,7 +17,7 @@ type BankKeeper interface {
// AccountsModKeeper defines the contract for x/accounts APIs
type AccountsModKeeper interface {
SendModuleMessageUntyped(ctx context.Context, sender []byte, msg protoiface.MessageV1) (protoiface.MessageV1, error)
SendModuleMessage(ctx context.Context, sender []byte, msg transaction.Msg) (transaction.Msg, error)
IsAccountsModuleAccount(ctx context.Context, accountAddr []byte) bool
NextAccountNumber(ctx context.Context) (accNum uint64, err error)

View File

@ -8,9 +8,9 @@ import (
context "context"
reflect "reflect"
transaction "cosmossdk.io/core/transaction"
types "github.com/cosmos/cosmos-sdk/types"
gomock "github.com/golang/mock/gomock"
protoiface "google.golang.org/protobuf/runtime/protoiface"
)
// MockBankKeeper is a mock of BankKeeper interface.
@ -149,17 +149,17 @@ func (mr *MockAccountsModKeeperMockRecorder) NextAccountNumber(ctx interface{})
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NextAccountNumber", reflect.TypeOf((*MockAccountsModKeeper)(nil).NextAccountNumber), ctx)
}
// SendModuleMessageUntyped mocks base method.
func (m *MockAccountsModKeeper) SendModuleMessageUntyped(ctx context.Context, sender []byte, msg protoiface.MessageV1) (protoiface.MessageV1, error) {
// SendModuleMessage mocks base method.
func (m *MockAccountsModKeeper) SendModuleMessage(ctx context.Context, sender []byte, msg transaction.Msg) (transaction.Msg, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SendModuleMessageUntyped", ctx, sender, msg)
ret0, _ := ret[0].(protoiface.MessageV1)
ret := m.ctrl.Call(m, "SendModuleMessage", ctx, sender, msg)
ret0, _ := ret[0].(transaction.Msg)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// SendModuleMessageUntyped indicates an expected call of SendModuleMessageUntyped.
func (mr *MockAccountsModKeeperMockRecorder) SendModuleMessageUntyped(ctx, sender, msg interface{}) *gomock.Call {
// SendModuleMessage indicates an expected call of SendModuleMessage.
func (mr *MockAccountsModKeeperMockRecorder) SendModuleMessage(ctx, sender, msg interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendModuleMessageUntyped", reflect.TypeOf((*MockAccountsModKeeper)(nil).SendModuleMessageUntyped), ctx, sender, msg)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendModuleMessage", reflect.TypeOf((*MockAccountsModKeeper)(nil).SendModuleMessage), ctx, sender, msg)
}

View File

@ -58,8 +58,8 @@ func GetTxCmd() *cobra.Command {
// but it will be removed in future versions.
func NewCmdExecAuthorization() *cobra.Command {
cmd := &cobra.Command{
Use: "legacy-exec <tx-json-file> --from <grantee>",
Short: "Execute tx on behalf of granter account. Deprecated, use exec instead.",
Use: "legacy-exec <tx-json-file> --from <grantee>",
Short: "Execute tx on behalf of granter account. Deprecated, use exec instead.",
Example: fmt.Sprintf("$ %s tx authz exec tx.json --from grantee\n $ %[1]s tx bank send [granter] [recipient] [amount] --generate-only tx.json && %[1]s tx authz exec tx.json --from grantee", version.AppName),
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {

View File

@ -146,7 +146,7 @@ func (k Keeper) DispatchActions(ctx context.Context, grantee sdk.AccAddress, msg
}
// no need to use the branch service here, as if the transaction fails, the transaction will be reverted
resp, err := k.MsgRouterService.InvokeUntyped(ctx, msg)
resp, err := k.MsgRouterService.Invoke(ctx, msg)
if err != nil {
return nil, fmt.Errorf("failed to execute message %d; message %v: %w", i, msg, err)
}

View File

@ -73,10 +73,15 @@ func (k Keeper) handleEquivocationEvidence(ctx context.Context, evidence *types.
// Reject evidence if the double-sign is too old. Evidence is considered stale
// if the difference in time and number of blocks is greater than the allowed
// parameters defined.
var res consensusv1.QueryParamsResponse
if err := k.QueryRouterService.InvokeTyped(ctx, &consensusv1.QueryParamsRequest{}, &res); err != nil {
resp, err := k.QueryRouterService.Invoke(ctx, &consensusv1.QueryParamsRequest{})
if err != nil {
return fmt.Errorf("failed to query consensus params: %w", err)
}
res, ok := resp.(*consensusv1.QueryParamsResponse)
if !ok {
return fmt.Errorf("unexpected response type: %T", resp)
}
if res.Params.Evidence != nil {
if ageDuration > res.Params.Evidence.MaxAgeDuration && ageBlocks > res.Params.Evidence.MaxAgeNumBlocks {
k.Logger.Info(

View File

@ -288,7 +288,7 @@ func safeExecuteHandler(ctx context.Context, msg sdk.Msg, router router.Service)
}
}()
res, err = router.InvokeUntyped(ctx, msg)
res, err = router.Invoke(ctx, msg)
return
}

View File

@ -16,7 +16,7 @@ type mockRouterService struct {
panic bool
}
func (m *mockRouterService) InvokeUntyped(ctx context.Context, req gogoproto.Message) (res gogoproto.Message, err error) {
func (m *mockRouterService) Invoke(ctx context.Context, req gogoproto.Message) (res gogoproto.Message, err error) {
if m.panic {
panic("test-fail")
}

View File

@ -5,10 +5,9 @@ import (
"encoding/json"
"fmt"
"google.golang.org/protobuf/runtime/protoiface"
corecontext "cosmossdk.io/core/context"
"cosmossdk.io/core/event"
"cosmossdk.io/core/transaction"
"cosmossdk.io/errors"
"cosmossdk.io/math"
govtypes "cosmossdk.io/x/gov/types"
@ -379,14 +378,14 @@ func (k msgServer) SudoExec(ctx context.Context, msg *v1.MsgSudoExec) (*v1.MsgSu
}
}
var msgResp protoiface.MessageV1
var msgResp transaction.Msg
if err := k.BranchService.Execute(ctx, func(ctx context.Context) error {
// TODO add route check here
if err := k.MsgRouterService.CanInvoke(ctx, sdk.MsgTypeURL(sudoedMsg)); err != nil {
return errors.Wrap(govtypes.ErrInvalidProposal, err.Error())
}
msgResp, err = k.MsgRouterService.InvokeUntyped(ctx, sudoedMsg)
msgResp, err = k.MsgRouterService.Invoke(ctx, sudoedMsg)
if err != nil {
return errors.Wrapf(err, "failed to execute sudo-ed message; message %v", sudoedMsg)
}

View File

@ -45,6 +45,7 @@ require (
cosmossdk.io/schema v0.1.1 // indirect
cosmossdk.io/x/accounts/defaults/lockup v0.0.0-20240417181816-5e7aae0db1f5 // indirect
cosmossdk.io/x/accounts/defaults/multisig v0.0.0-00010101000000-000000000000 // indirect
cosmossdk.io/x/distribution v0.0.0-00010101000000-000000000000 // indirect
cosmossdk.io/x/epochs v0.0.0-20240522060652-a1ae4c3e0337 // indirect
cosmossdk.io/x/tx v0.13.3 // indirect
filippo.io/edwards25519 v1.1.0 // indirect
@ -189,6 +190,7 @@ replace (
cosmossdk.io/core => ../../core
cosmossdk.io/core/testing => ../../core/testing
cosmossdk.io/x/accounts => ../accounts
cosmossdk.io/x/accounts/defaults/lockup => ../accounts/defaults/lockup
cosmossdk.io/x/accounts/defaults/multisig => ../accounts/defaults/multisig
cosmossdk.io/x/auth => ../auth
cosmossdk.io/x/authz => ../authz

View File

@ -16,8 +16,6 @@ cosmossdk.io/schema v0.1.1 h1:I0M6pgI7R10nq+/HCQfbO6BsGBZA8sQy+duR1Y3aKcA=
cosmossdk.io/schema v0.1.1/go.mod h1:RDAhxIeNB4bYqAlF4NBJwRrgtnciMcyyg0DOKnhNZQQ=
cosmossdk.io/store v1.1.1-0.20240418092142-896cdf1971bc h1:R9O9d75e0qZYUsVV0zzi+D7cNLnX2JrUOQNoIPaF0Bg=
cosmossdk.io/store v1.1.1-0.20240418092142-896cdf1971bc/go.mod h1:amTTatOUV3u1PsKmNb87z6/galCxrRbz9kRdJkL0DyU=
cosmossdk.io/x/accounts/defaults/lockup v0.0.0-20240417181816-5e7aae0db1f5 h1:eb0kcGyaYHSS0do7+MIWg7UKlskSH01biRNENbm/zDA=
cosmossdk.io/x/accounts/defaults/lockup v0.0.0-20240417181816-5e7aae0db1f5/go.mod h1:drzY4oVisyWvSgpsM7ccQ7IX3efMuVIvd9Eij1Gm/6o=
cosmossdk.io/x/epochs v0.0.0-20240522060652-a1ae4c3e0337 h1:GuBrfHsK3RD5vlD4DuBz3DXslR6VlnzrYmHOC3L679Q=
cosmossdk.io/x/epochs v0.0.0-20240522060652-a1ae4c3e0337/go.mod h1:PhLn1pMBilyRC4GfRkoYhm+XVAYhF4adVrzut8AdpJI=
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=

View File

@ -45,7 +45,7 @@ func (k Keeper) doExecuteMsgs(ctx context.Context, proposal group.Proposal, grou
}
for i, msg := range msgs {
if _, err := k.MsgRouterService.InvokeUntyped(ctx, msg); err != nil {
if _, err := k.MsgRouterService.Invoke(ctx, msg); err != nil {
return errorsmod.Wrapf(err, "message %s at position %d", sdk.MsgTypeURL(msg), i)
}
}

View File

@ -69,10 +69,15 @@ func (k msgServer) CreateValidator(ctx context.Context, msg *types.MsgCreateVali
return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidType, "Expecting cryptotypes.PubKey, got %T", msg.Pubkey.GetCachedValue())
}
res := consensusv1.QueryParamsResponse{}
if err := k.QueryRouterService.InvokeTyped(ctx, &consensusv1.QueryParamsRequest{}, &res); err != nil {
resp, err := k.QueryRouterService.Invoke(ctx, &consensusv1.QueryParamsRequest{})
if err != nil {
return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "failed to query consensus params: %s", err)
}
res, ok := resp.(*consensusv1.QueryParamsResponse)
if !ok {
return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "unexpected response type: %T", resp)
}
if res.Params.Validator != nil {
pkType := pk.Type()
if !slices.Contains(res.Params.Validator.PubKeyTypes, pkType) {
@ -652,10 +657,15 @@ func (k msgServer) RotateConsPubKey(ctx context.Context, msg *types.MsgRotateCon
}
// check if the new public key type is valid
paramsRes := consensusv1.QueryParamsResponse{}
if err := k.QueryRouterService.InvokeTyped(ctx, &consensusv1.QueryParamsRequest{}, &paramsRes); err != nil {
resp, err := k.QueryRouterService.Invoke(ctx, &consensusv1.QueryParamsRequest{})
if err != nil {
return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "failed to query consensus params: %s", err)
}
paramsRes, ok := resp.(*consensusv1.QueryParamsResponse)
if !ok {
return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "unexpected response type: %T", resp)
}
if paramsRes.Params.Validator != nil {
pkType := pk.Type()
if !slices.Contains(paramsRes.Params.Validator.PubKeyTypes, pkType) {

View File

@ -45,10 +45,16 @@ func (k Keeper) PreBlocker(ctx context.Context) error {
if lastAppliedPlan != "" && !k.HasHandler(lastAppliedPlan) {
var appVersion uint64
var res consensusv1.QueryParamsResponse
if err := k.QueryRouterService.InvokeTyped(ctx, &consensusv1.QueryParamsRequest{}, &res); err != nil {
resp, err := k.QueryRouterService.Invoke(ctx, &consensusv1.QueryParamsRequest{})
if err != nil {
return errors.New("failed to query consensus params")
}
res, ok := resp.(*consensusv1.QueryParamsResponse)
if !ok {
return fmt.Errorf("unexpected response type: %T", resp)
}
if res.Params.Version != nil {
appVersion = res.Params.Version.App
}