feat: Add non atomic multimsg (#19350)

This commit is contained in:
Likhita Polavarapu
2024-04-15 09:32:29 +00:00
committed by GitHub
parent 037cf98f7e
commit 07c0aa73e0
41 changed files with 3229 additions and 196 deletions
+18 -10
View File
@@ -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
View File
@@ -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
+13 -5
View File
@@ -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)
+32
View File
@@ -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(