feat: Add non atomic multimsg (#19350)
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/stretchr/testify/suite"
|
||||
"pgregory.net/rapid"
|
||||
|
||||
@@ -16,6 +17,7 @@ import (
|
||||
"cosmossdk.io/x/auth"
|
||||
authcodec "cosmossdk.io/x/auth/codec"
|
||||
"cosmossdk.io/x/auth/keeper"
|
||||
authtestutil "cosmossdk.io/x/auth/testutil"
|
||||
"cosmossdk.io/x/auth/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
@@ -33,13 +35,14 @@ type DeterministicTestSuite struct {
|
||||
|
||||
accountNumberLanes uint64
|
||||
|
||||
key *storetypes.KVStoreKey
|
||||
environment appmodule.Environment
|
||||
ctx sdk.Context
|
||||
queryClient types.QueryClient
|
||||
accountKeeper keeper.AccountKeeper
|
||||
encCfg moduletestutil.TestEncodingConfig
|
||||
maccPerms map[string][]string
|
||||
key *storetypes.KVStoreKey
|
||||
environment appmodule.Environment
|
||||
ctx sdk.Context
|
||||
queryClient types.QueryClient
|
||||
accountKeeper keeper.AccountKeeper
|
||||
acctsModKeeper *authtestutil.MockAccountsModKeeper
|
||||
encCfg moduletestutil.TestEncodingConfig
|
||||
maccPerms map[string][]string
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -62,6 +65,11 @@ func (suite *DeterministicTestSuite) SetupTest() {
|
||||
testCtx := testutil.DefaultContextWithDB(suite.T(), key, storetypes.NewTransientStoreKey("transient_test"))
|
||||
suite.ctx = testCtx.Ctx.WithHeaderInfo(header.Info{})
|
||||
|
||||
// gomock initializations
|
||||
ctrl := gomock.NewController(suite.T())
|
||||
acctsModKeeper := authtestutil.NewMockAccountsModKeeper(ctrl)
|
||||
suite.acctsModKeeper = acctsModKeeper
|
||||
|
||||
maccPerms := map[string][]string{
|
||||
"fee_collector": nil,
|
||||
"mint": {"minter"},
|
||||
@@ -75,11 +83,11 @@ func (suite *DeterministicTestSuite) SetupTest() {
|
||||
env,
|
||||
suite.encCfg.Codec,
|
||||
types.ProtoBaseAccount,
|
||||
suite.acctsModKeeper,
|
||||
maccPerms,
|
||||
authcodec.NewBech32Codec("cosmos"),
|
||||
"cosmos",
|
||||
types.NewModuleAddress("gov").String(),
|
||||
nil,
|
||||
)
|
||||
|
||||
queryHelper := baseapp.NewQueryServerTestHelper(suite.ctx, suite.encCfg.InterfaceRegistry)
|
||||
@@ -296,11 +304,11 @@ func (suite *DeterministicTestSuite) TestGRPCQueryModuleAccounts() {
|
||||
suite.environment,
|
||||
suite.encCfg.Codec,
|
||||
types.ProtoBaseAccount,
|
||||
suite.acctsModKeeper,
|
||||
maccPerms,
|
||||
authcodec.NewBech32Codec("cosmos"),
|
||||
"cosmos",
|
||||
types.NewModuleAddress("gov").String(),
|
||||
nil,
|
||||
)
|
||||
suite.setModuleAccounts(suite.ctx, ak, maccs)
|
||||
|
||||
@@ -344,11 +352,11 @@ func (suite *DeterministicTestSuite) TestGRPCQueryModuleAccountByName() {
|
||||
suite.environment,
|
||||
suite.encCfg.Codec,
|
||||
types.ProtoBaseAccount,
|
||||
suite.acctsModKeeper,
|
||||
maccPerms,
|
||||
authcodec.NewBech32Codec("cosmos"),
|
||||
"cosmos",
|
||||
types.NewModuleAddress("gov").String(),
|
||||
nil,
|
||||
)
|
||||
suite.setModuleAccounts(suite.ctx, ak, []string{mName})
|
||||
|
||||
|
||||
+41
-3
@@ -14,6 +14,7 @@ import (
|
||||
"cosmossdk.io/x/auth/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
@@ -115,8 +116,8 @@ var _ AccountKeeperI = &AccountKeeper{}
|
||||
// and don't have to fit into any predefined structure. This auth module does not use account permissions internally, though other modules
|
||||
// may use auth.Keeper to access the accounts permissions map.
|
||||
func NewAccountKeeper(
|
||||
env appmodule.Environment, cdc codec.BinaryCodec, proto func() sdk.AccountI,
|
||||
maccPerms map[string][]string, ac address.Codec, bech32Prefix, authority string, accountsModKeeper types.AccountsModKeeper,
|
||||
env appmodule.Environment, cdc codec.BinaryCodec, proto func() sdk.AccountI, accountsModKeeper types.AccountsModKeeper,
|
||||
maccPerms map[string][]string, ac address.Codec, bech32Prefix, authority string,
|
||||
) AccountKeeper {
|
||||
permAddrs := make(map[string]types.PermissionsForAddress)
|
||||
for name, perms := range maccPerms {
|
||||
@@ -131,12 +132,12 @@ func NewAccountKeeper(
|
||||
environment: env,
|
||||
proto: proto,
|
||||
cdc: cdc,
|
||||
AccountsModKeeper: accountsModKeeper,
|
||||
permAddrs: permAddrs,
|
||||
authority: authority,
|
||||
Params: collections.NewItem(sb, types.ParamsKey, "params", codec.CollValue[types.Params](cdc)),
|
||||
AccountNumber: collections.NewSequence(sb, types.GlobalAccountNumberKey, "account_number"),
|
||||
Accounts: collections.NewIndexedMap(sb, types.AddressStoreKeyPrefix, "accounts", sdk.AccAddressKey, codec.CollInterfaceValue[sdk.AccountI](cdc), NewAccountIndexes(sb)),
|
||||
AccountsModKeeper: accountsModKeeper,
|
||||
}
|
||||
schema, err := sb.Build()
|
||||
if err != nil {
|
||||
@@ -281,6 +282,43 @@ func (ak AccountKeeper) GetParams(ctx context.Context) (params types.Params) {
|
||||
return params
|
||||
}
|
||||
|
||||
func (ak AccountKeeper) NonAtomicMsgsExec(ctx context.Context, signer sdk.AccAddress, msgs []sdk.Msg) ([]*types.NonAtomicExecResult, error) {
|
||||
msgResponses := make([]*types.NonAtomicExecResult, 0, len(msgs))
|
||||
|
||||
for _, msg := range msgs {
|
||||
if m, ok := msg.(sdk.HasValidateBasic); ok {
|
||||
if err := m.ValidateBasic(); err != nil {
|
||||
value := &types.NonAtomicExecResult{Error: err.Error()}
|
||||
msgResponses = append(msgResponses, value)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if err := ak.environment.BranchService.Execute(ctx, func(ctx context.Context) error {
|
||||
result, err := ak.AccountsModKeeper.SendModuleMessageUntyped(ctx, signer, msg)
|
||||
if err != nil {
|
||||
// If an error occurs during message execution, append error response
|
||||
response := &types.NonAtomicExecResult{Resp: nil, Error: err.Error()}
|
||||
msgResponses = append(msgResponses, response)
|
||||
} else {
|
||||
resp, err := codectypes.NewAnyWithValue(result)
|
||||
if err != nil {
|
||||
response := &types.NonAtomicExecResult{Resp: nil, Error: err.Error()}
|
||||
msgResponses = append(msgResponses, response)
|
||||
}
|
||||
response := &types.NonAtomicExecResult{Resp: resp, Error: ""}
|
||||
msgResponses = append(msgResponses, response)
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return msgResponses, nil
|
||||
}
|
||||
|
||||
// Environment returns the module's environment.
|
||||
func (ak AccountKeeper) Environment() appmodule.Environment {
|
||||
return ak.environment
|
||||
|
||||
@@ -3,6 +3,7 @@ package keeper_test
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
@@ -12,6 +13,7 @@ import (
|
||||
"cosmossdk.io/x/auth"
|
||||
authcodec "cosmossdk.io/x/auth/codec"
|
||||
"cosmossdk.io/x/auth/keeper"
|
||||
authtestutil "cosmossdk.io/x/auth/testutil"
|
||||
"cosmossdk.io/x/auth/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
@@ -40,10 +42,11 @@ type KeeperTestSuite struct {
|
||||
|
||||
ctx sdk.Context
|
||||
|
||||
queryClient types.QueryClient
|
||||
accountKeeper keeper.AccountKeeper
|
||||
msgServer types.MsgServer
|
||||
encCfg moduletestutil.TestEncodingConfig
|
||||
queryClient types.QueryClient
|
||||
accountKeeper keeper.AccountKeeper
|
||||
acctsModKeeper *authtestutil.MockAccountsModKeeper
|
||||
msgServer types.MsgServer
|
||||
encCfg moduletestutil.TestEncodingConfig
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) SetupTest() {
|
||||
@@ -55,6 +58,11 @@ func (suite *KeeperTestSuite) SetupTest() {
|
||||
testCtx := testutil.DefaultContextWithDB(suite.T(), key, storetypes.NewTransientStoreKey("transient_test"))
|
||||
suite.ctx = testCtx.Ctx.WithHeaderInfo(header.Info{})
|
||||
|
||||
// gomock initializations
|
||||
ctrl := gomock.NewController(suite.T())
|
||||
acctsModKeeper := authtestutil.NewMockAccountsModKeeper(ctrl)
|
||||
suite.acctsModKeeper = acctsModKeeper
|
||||
|
||||
maccPerms := map[string][]string{
|
||||
"fee_collector": nil,
|
||||
"mint": {"minter"},
|
||||
@@ -68,11 +76,11 @@ func (suite *KeeperTestSuite) SetupTest() {
|
||||
env,
|
||||
suite.encCfg.Codec,
|
||||
types.ProtoBaseAccount,
|
||||
acctsModKeeper,
|
||||
maccPerms,
|
||||
authcodec.NewBech32Codec("cosmos"),
|
||||
"cosmos",
|
||||
types.NewModuleAddress("gov").String(),
|
||||
nil,
|
||||
)
|
||||
suite.msgServer = keeper.NewMsgServerImpl(suite.accountKeeper)
|
||||
queryHelper := baseapp.NewQueryServerTestHelper(suite.ctx, suite.encCfg.InterfaceRegistry)
|
||||
|
||||
@@ -2,9 +2,12 @@ package keeper
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"cosmossdk.io/x/auth/types"
|
||||
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
)
|
||||
|
||||
var _ types.MsgServer = msgServer{}
|
||||
@@ -20,6 +23,35 @@ func NewMsgServerImpl(ak AccountKeeper) types.MsgServer {
|
||||
}
|
||||
}
|
||||
|
||||
func (ms msgServer) NonAtomicExec(goCtx context.Context, msg *types.MsgNonAtomicExec) (*types.MsgNonAtomicExecResponse, error) {
|
||||
if msg.Signer == "" {
|
||||
return nil, errors.New("empty signer address string is not allowed")
|
||||
}
|
||||
|
||||
signer, err := ms.ak.AddressCodec().StringToBytes(msg.Signer)
|
||||
if err != nil {
|
||||
return nil, sdkerrors.ErrInvalidAddress.Wrapf("invalid signer address: %s", err)
|
||||
}
|
||||
|
||||
if len(msg.Msgs) == 0 {
|
||||
return nil, sdkerrors.ErrInvalidRequest.Wrapf("messages cannot be empty")
|
||||
}
|
||||
|
||||
msgs, err := msg.GetMessages()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
results, err := ms.ak.NonAtomicMsgsExec(goCtx, signer, msgs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &types.MsgNonAtomicExecResponse{
|
||||
Results: results,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (ms msgServer) UpdateParams(ctx context.Context, msg *types.MsgUpdateParams) (*types.MsgUpdateParamsResponse, error) {
|
||||
if ms.ak.authority != msg.Authority {
|
||||
return nil, fmt.Errorf(
|
||||
|
||||
Reference in New Issue
Block a user