github.com/cosmos/cosmos-sdk@v0.50.10/x/group/keeper/msg_server.go (about)

     1  package keeper
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"encoding/binary"
     7  	"encoding/json"
     8  	"fmt"
     9  	"strings"
    10  
    11  	errorsmod "cosmossdk.io/errors"
    12  
    13  	sdk "github.com/cosmos/cosmos-sdk/types"
    14  	sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
    15  	authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
    16  	govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
    17  	"github.com/cosmos/cosmos-sdk/x/group"
    18  	"github.com/cosmos/cosmos-sdk/x/group/errors"
    19  	"github.com/cosmos/cosmos-sdk/x/group/internal/math"
    20  	"github.com/cosmos/cosmos-sdk/x/group/internal/orm"
    21  )
    22  
    23  var _ group.MsgServer = Keeper{}
    24  
    25  // TODO: Revisit this once we have proper gas fee framework.
    26  // Tracking issues https://github.com/cosmos/cosmos-sdk/issues/9054, https://github.com/cosmos/cosmos-sdk/discussions/9072
    27  const gasCostPerIteration = uint64(20)
    28  
    29  func (k Keeper) CreateGroup(goCtx context.Context, msg *group.MsgCreateGroup) (*group.MsgCreateGroupResponse, error) {
    30  	if _, err := k.accKeeper.AddressCodec().StringToBytes(msg.Admin); err != nil {
    31  		return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid admin address: %s", msg.Admin)
    32  	}
    33  
    34  	if err := k.validateMembers(msg.Members); err != nil {
    35  		return nil, errorsmod.Wrap(err, "members")
    36  	}
    37  
    38  	if err := k.assertMetadataLength(msg.Metadata, "group metadata"); err != nil {
    39  		return nil, err
    40  	}
    41  
    42  	totalWeight := math.NewDecFromInt64(0)
    43  	for _, m := range msg.Members {
    44  		if err := k.assertMetadataLength(m.Metadata, "member metadata"); err != nil {
    45  			return nil, err
    46  		}
    47  
    48  		// Members of a group must have a positive weight.
    49  		// NOTE: group member with zero weight are only allowed when updating group members.
    50  		// If the member has a zero weight, it will be removed from the group.
    51  		weight, err := math.NewPositiveDecFromString(m.Weight)
    52  		if err != nil {
    53  			return nil, err
    54  		}
    55  
    56  		// Adding up members weights to compute group total weight.
    57  		totalWeight, err = totalWeight.Add(weight)
    58  		if err != nil {
    59  			return nil, err
    60  		}
    61  	}
    62  
    63  	// Create a new group in the groupTable.
    64  	ctx := sdk.UnwrapSDKContext(goCtx)
    65  	groupInfo := &group.GroupInfo{
    66  		Id:          k.groupTable.Sequence().PeekNextVal(ctx.KVStore(k.key)),
    67  		Admin:       msg.Admin,
    68  		Metadata:    msg.Metadata,
    69  		Version:     1,
    70  		TotalWeight: totalWeight.String(),
    71  		CreatedAt:   ctx.BlockTime(),
    72  	}
    73  	groupID, err := k.groupTable.Create(ctx.KVStore(k.key), groupInfo)
    74  	if err != nil {
    75  		return nil, errorsmod.Wrap(err, "could not create group")
    76  	}
    77  
    78  	// Create new group members in the groupMemberTable.
    79  	for i, m := range msg.Members {
    80  		err := k.groupMemberTable.Create(ctx.KVStore(k.key), &group.GroupMember{
    81  			GroupId: groupID,
    82  			Member: &group.Member{
    83  				Address:  m.Address,
    84  				Weight:   m.Weight,
    85  				Metadata: m.Metadata,
    86  				AddedAt:  ctx.BlockTime(),
    87  			},
    88  		})
    89  		if err != nil {
    90  			return nil, errorsmod.Wrapf(err, "could not store member %d", i)
    91  		}
    92  	}
    93  
    94  	if err := ctx.EventManager().EmitTypedEvent(&group.EventCreateGroup{GroupId: groupID}); err != nil {
    95  		return nil, err
    96  	}
    97  
    98  	return &group.MsgCreateGroupResponse{GroupId: groupID}, nil
    99  }
   100  
   101  func (k Keeper) UpdateGroupMembers(goCtx context.Context, msg *group.MsgUpdateGroupMembers) (*group.MsgUpdateGroupMembersResponse, error) {
   102  	if msg.GroupId == 0 {
   103  		return nil, errorsmod.Wrap(errors.ErrEmpty, "group id")
   104  	}
   105  
   106  	if len(msg.MemberUpdates) == 0 {
   107  		return nil, errorsmod.Wrap(errors.ErrEmpty, "member updates")
   108  	}
   109  
   110  	if err := k.validateMembers(msg.MemberUpdates); err != nil {
   111  		return nil, errorsmod.Wrap(err, "members")
   112  	}
   113  
   114  	ctx := sdk.UnwrapSDKContext(goCtx)
   115  	action := func(g *group.GroupInfo) error {
   116  		totalWeight, err := math.NewNonNegativeDecFromString(g.TotalWeight)
   117  		if err != nil {
   118  			return errorsmod.Wrap(err, "group total weight")
   119  		}
   120  
   121  		for _, member := range msg.MemberUpdates {
   122  			if err := k.assertMetadataLength(member.Metadata, "group member metadata"); err != nil {
   123  				return err
   124  			}
   125  			groupMember := group.GroupMember{
   126  				GroupId: msg.GroupId,
   127  				Member: &group.Member{
   128  					Address:  member.Address,
   129  					Weight:   member.Weight,
   130  					Metadata: member.Metadata,
   131  				},
   132  			}
   133  
   134  			// Checking if the group member is already part of the group
   135  			var found bool
   136  			var prevGroupMember group.GroupMember
   137  			switch err := k.groupMemberTable.GetOne(ctx.KVStore(k.key), orm.PrimaryKey(&groupMember), &prevGroupMember); {
   138  			case err == nil:
   139  				found = true
   140  			case sdkerrors.ErrNotFound.Is(err):
   141  				found = false
   142  			default:
   143  				return errorsmod.Wrap(err, "get group member")
   144  			}
   145  
   146  			newMemberWeight, err := math.NewNonNegativeDecFromString(groupMember.Member.Weight)
   147  			if err != nil {
   148  				return err
   149  			}
   150  
   151  			// Handle delete for members with zero weight.
   152  			if newMemberWeight.IsZero() {
   153  				// We can't delete a group member that doesn't already exist.
   154  				if !found {
   155  					return errorsmod.Wrap(sdkerrors.ErrNotFound, "unknown member")
   156  				}
   157  
   158  				previousMemberWeight, err := math.NewPositiveDecFromString(prevGroupMember.Member.Weight)
   159  				if err != nil {
   160  					return err
   161  				}
   162  
   163  				// Subtract the weight of the group member to delete from the group total weight.
   164  				totalWeight, err = math.SubNonNegative(totalWeight, previousMemberWeight)
   165  				if err != nil {
   166  					return err
   167  				}
   168  
   169  				// Delete group member in the groupMemberTable.
   170  				if err := k.groupMemberTable.Delete(ctx.KVStore(k.key), &groupMember); err != nil {
   171  					return errorsmod.Wrap(err, "delete member")
   172  				}
   173  				continue
   174  			}
   175  			// If group member already exists, handle update
   176  			if found {
   177  				previousMemberWeight, err := math.NewPositiveDecFromString(prevGroupMember.Member.Weight)
   178  				if err != nil {
   179  					return err
   180  				}
   181  				// Subtract previous weight from the group total weight.
   182  				totalWeight, err = math.SubNonNegative(totalWeight, previousMemberWeight)
   183  				if err != nil {
   184  					return err
   185  				}
   186  				// Save updated group member in the groupMemberTable.
   187  				groupMember.Member.AddedAt = prevGroupMember.Member.AddedAt
   188  				if err := k.groupMemberTable.Update(ctx.KVStore(k.key), &groupMember); err != nil {
   189  					return errorsmod.Wrap(err, "add member")
   190  				}
   191  			} else { // else handle create.
   192  				groupMember.Member.AddedAt = ctx.BlockTime()
   193  				if err := k.groupMemberTable.Create(ctx.KVStore(k.key), &groupMember); err != nil {
   194  					return errorsmod.Wrap(err, "add member")
   195  				}
   196  			}
   197  			// In both cases (handle + update), we need to add the new member's weight to the group total weight.
   198  			totalWeight, err = totalWeight.Add(newMemberWeight)
   199  			if err != nil {
   200  				return err
   201  			}
   202  		}
   203  		// Update group in the groupTable.
   204  		g.TotalWeight = totalWeight.String()
   205  		g.Version++
   206  
   207  		if err := k.validateDecisionPolicies(ctx, *g); err != nil {
   208  			return err
   209  		}
   210  
   211  		return k.groupTable.Update(ctx.KVStore(k.key), g.Id, g)
   212  	}
   213  
   214  	if err := k.doUpdateGroup(ctx, msg.GetGroupID(), msg.GetAdmin(), action, "members updated"); err != nil {
   215  		return nil, err
   216  	}
   217  
   218  	return &group.MsgUpdateGroupMembersResponse{}, nil
   219  }
   220  
   221  func (k Keeper) UpdateGroupAdmin(goCtx context.Context, msg *group.MsgUpdateGroupAdmin) (*group.MsgUpdateGroupAdminResponse, error) {
   222  	if msg.GroupId == 0 {
   223  		return nil, errorsmod.Wrap(errors.ErrEmpty, "group id")
   224  	}
   225  
   226  	if strings.EqualFold(msg.Admin, msg.NewAdmin) {
   227  		return nil, errorsmod.Wrap(errors.ErrInvalid, "new and old admin are the same")
   228  	}
   229  
   230  	if _, err := k.accKeeper.AddressCodec().StringToBytes(msg.Admin); err != nil {
   231  		return nil, errorsmod.Wrap(sdkerrors.ErrInvalidAddress, "admin address")
   232  	}
   233  
   234  	if _, err := k.accKeeper.AddressCodec().StringToBytes(msg.NewAdmin); err != nil {
   235  		return nil, errorsmod.Wrap(sdkerrors.ErrInvalidAddress, "new admin address")
   236  	}
   237  
   238  	ctx := sdk.UnwrapSDKContext(goCtx)
   239  	action := func(g *group.GroupInfo) error {
   240  		g.Admin = msg.NewAdmin
   241  		g.Version++
   242  
   243  		return k.groupTable.Update(ctx.KVStore(k.key), g.Id, g)
   244  	}
   245  
   246  	if err := k.doUpdateGroup(ctx, msg.GetGroupID(), msg.GetAdmin(), action, "admin updated"); err != nil {
   247  		return nil, err
   248  	}
   249  
   250  	return &group.MsgUpdateGroupAdminResponse{}, nil
   251  }
   252  
   253  func (k Keeper) UpdateGroupMetadata(goCtx context.Context, msg *group.MsgUpdateGroupMetadata) (*group.MsgUpdateGroupMetadataResponse, error) {
   254  	if msg.GroupId == 0 {
   255  		return nil, errorsmod.Wrap(errors.ErrEmpty, "group id")
   256  	}
   257  
   258  	if err := k.assertMetadataLength(msg.Metadata, "group metadata"); err != nil {
   259  		return nil, err
   260  	}
   261  
   262  	if _, err := k.accKeeper.AddressCodec().StringToBytes(msg.Admin); err != nil {
   263  		return nil, errorsmod.Wrap(sdkerrors.ErrInvalidAddress, "admin address")
   264  	}
   265  
   266  	ctx := sdk.UnwrapSDKContext(goCtx)
   267  	action := func(g *group.GroupInfo) error {
   268  		g.Metadata = msg.Metadata
   269  		g.Version++
   270  		return k.groupTable.Update(ctx.KVStore(k.key), g.Id, g)
   271  	}
   272  
   273  	if err := k.doUpdateGroup(ctx, msg.GetGroupID(), msg.GetAdmin(), action, "metadata updated"); err != nil {
   274  		return nil, err
   275  	}
   276  
   277  	return &group.MsgUpdateGroupMetadataResponse{}, nil
   278  }
   279  
   280  func (k Keeper) CreateGroupWithPolicy(ctx context.Context, msg *group.MsgCreateGroupWithPolicy) (*group.MsgCreateGroupWithPolicyResponse, error) {
   281  	// NOTE: admin, and group message validation is performed in the CreateGroup method
   282  	groupRes, err := k.CreateGroup(ctx, &group.MsgCreateGroup{
   283  		Admin:    msg.Admin,
   284  		Members:  msg.Members,
   285  		Metadata: msg.GroupMetadata,
   286  	})
   287  	if err != nil {
   288  		return nil, errorsmod.Wrap(err, "group response")
   289  	}
   290  	groupID := groupRes.GroupId
   291  
   292  	// NOTE: group policy message validation is performed in the CreateGroupPolicy method
   293  	groupPolicyRes, err := k.CreateGroupPolicy(ctx, &group.MsgCreateGroupPolicy{
   294  		Admin:          msg.Admin,
   295  		GroupId:        groupID,
   296  		Metadata:       msg.GroupPolicyMetadata,
   297  		DecisionPolicy: msg.DecisionPolicy,
   298  	})
   299  	if err != nil {
   300  		return nil, errorsmod.Wrap(err, "group policy response")
   301  	}
   302  
   303  	if msg.GroupPolicyAsAdmin {
   304  		updateAdminReq := &group.MsgUpdateGroupAdmin{
   305  			GroupId:  groupID,
   306  			Admin:    msg.Admin,
   307  			NewAdmin: groupPolicyRes.Address,
   308  		}
   309  		_, err = k.UpdateGroupAdmin(ctx, updateAdminReq)
   310  		if err != nil {
   311  			return nil, err
   312  		}
   313  
   314  		updatePolicyAddressReq := &group.MsgUpdateGroupPolicyAdmin{
   315  			Admin:              msg.Admin,
   316  			GroupPolicyAddress: groupPolicyRes.Address,
   317  			NewAdmin:           groupPolicyRes.Address,
   318  		}
   319  		_, err = k.UpdateGroupPolicyAdmin(ctx, updatePolicyAddressReq)
   320  		if err != nil {
   321  			return nil, err
   322  		}
   323  	}
   324  
   325  	return &group.MsgCreateGroupWithPolicyResponse{GroupId: groupID, GroupPolicyAddress: groupPolicyRes.Address}, nil
   326  }
   327  
   328  func (k Keeper) CreateGroupPolicy(goCtx context.Context, msg *group.MsgCreateGroupPolicy) (*group.MsgCreateGroupPolicyResponse, error) {
   329  	if msg.GroupId == 0 {
   330  		return nil, errorsmod.Wrap(errors.ErrEmpty, "group id")
   331  	}
   332  
   333  	if err := k.assertMetadataLength(msg.GetMetadata(), "group policy metadata"); err != nil {
   334  		return nil, err
   335  	}
   336  
   337  	policy, err := msg.GetDecisionPolicy()
   338  	if err != nil {
   339  		return nil, errorsmod.Wrap(err, "request decision policy")
   340  	}
   341  
   342  	if err := policy.ValidateBasic(); err != nil {
   343  		return nil, errorsmod.Wrap(err, "decision policy")
   344  	}
   345  
   346  	reqGroupAdmin, err := k.accKeeper.AddressCodec().StringToBytes(msg.GetAdmin())
   347  	if err != nil {
   348  		return nil, errorsmod.Wrap(err, "request admin")
   349  	}
   350  
   351  	ctx := sdk.UnwrapSDKContext(goCtx)
   352  	groupInfo, err := k.getGroupInfo(ctx, msg.GetGroupID())
   353  	if err != nil {
   354  		return nil, err
   355  	}
   356  
   357  	groupAdmin, err := k.accKeeper.AddressCodec().StringToBytes(groupInfo.Admin)
   358  	if err != nil {
   359  		return nil, errorsmod.Wrap(err, "group admin")
   360  	}
   361  
   362  	// Only current group admin is authorized to create a group policy for this
   363  	if !bytes.Equal(groupAdmin, reqGroupAdmin) {
   364  		return nil, errorsmod.Wrap(sdkerrors.ErrUnauthorized, "not group admin")
   365  	}
   366  
   367  	if err := policy.Validate(groupInfo, k.config); err != nil {
   368  		return nil, err
   369  	}
   370  
   371  	// Generate account address of group policy.
   372  	var accountAddr sdk.AccAddress
   373  	// loop here in the rare case where a ADR-028-derived address creates a
   374  	// collision with an existing address.
   375  	for {
   376  		nextAccVal := k.groupPolicySeq.NextVal(ctx.KVStore(k.key))
   377  		derivationKey := make([]byte, 8)
   378  		binary.BigEndian.PutUint64(derivationKey, nextAccVal)
   379  
   380  		ac, err := authtypes.NewModuleCredential(group.ModuleName, []byte{GroupPolicyTablePrefix}, derivationKey)
   381  		if err != nil {
   382  			return nil, err
   383  		}
   384  		accountAddr = sdk.AccAddress(ac.Address())
   385  		if k.accKeeper.GetAccount(ctx, accountAddr) != nil {
   386  			// handle a rare collision, in which case we just go on to the
   387  			// next sequence value and derive a new address.
   388  			continue
   389  		}
   390  
   391  		// group policy accounts are unclaimable base accounts
   392  		account, err := authtypes.NewBaseAccountWithPubKey(ac)
   393  		if err != nil {
   394  			return nil, errorsmod.Wrap(err, "could not create group policy account")
   395  		}
   396  
   397  		acc := k.accKeeper.NewAccount(ctx, account)
   398  		k.accKeeper.SetAccount(ctx, acc)
   399  
   400  		break
   401  	}
   402  
   403  	groupPolicy, err := group.NewGroupPolicyInfo(
   404  		accountAddr,
   405  		msg.GetGroupID(),
   406  		reqGroupAdmin,
   407  		msg.GetMetadata(),
   408  		1,
   409  		policy,
   410  		ctx.BlockTime(),
   411  	)
   412  	if err != nil {
   413  		return nil, err
   414  	}
   415  
   416  	if err := k.groupPolicyTable.Create(ctx.KVStore(k.key), &groupPolicy); err != nil {
   417  		return nil, errorsmod.Wrap(err, "could not create group policy")
   418  	}
   419  
   420  	if err := ctx.EventManager().EmitTypedEvent(&group.EventCreateGroupPolicy{Address: accountAddr.String()}); err != nil {
   421  		return nil, err
   422  	}
   423  
   424  	return &group.MsgCreateGroupPolicyResponse{Address: accountAddr.String()}, nil
   425  }
   426  
   427  func (k Keeper) UpdateGroupPolicyAdmin(goCtx context.Context, msg *group.MsgUpdateGroupPolicyAdmin) (*group.MsgUpdateGroupPolicyAdminResponse, error) {
   428  	if strings.EqualFold(msg.Admin, msg.NewAdmin) {
   429  		return nil, errorsmod.Wrap(errors.ErrInvalid, "new and old admin are same")
   430  	}
   431  
   432  	if _, err := k.accKeeper.AddressCodec().StringToBytes(msg.NewAdmin); err != nil {
   433  		return nil, errorsmod.Wrap(sdkerrors.ErrInvalidAddress, "new admin address")
   434  	}
   435  
   436  	ctx := sdk.UnwrapSDKContext(goCtx)
   437  	action := func(groupPolicy *group.GroupPolicyInfo) error {
   438  		groupPolicy.Admin = msg.NewAdmin
   439  		groupPolicy.Version++
   440  		return k.groupPolicyTable.Update(ctx.KVStore(k.key), groupPolicy)
   441  	}
   442  
   443  	if err := k.doUpdateGroupPolicy(ctx, msg.GroupPolicyAddress, msg.Admin, action, "group policy admin updated"); err != nil {
   444  		return nil, err
   445  	}
   446  
   447  	return &group.MsgUpdateGroupPolicyAdminResponse{}, nil
   448  }
   449  
   450  func (k Keeper) UpdateGroupPolicyDecisionPolicy(goCtx context.Context, msg *group.MsgUpdateGroupPolicyDecisionPolicy) (*group.MsgUpdateGroupPolicyDecisionPolicyResponse, error) {
   451  	policy, err := msg.GetDecisionPolicy()
   452  	if err != nil {
   453  		return nil, errorsmod.Wrap(err, "decision policy")
   454  	}
   455  
   456  	if err := policy.ValidateBasic(); err != nil {
   457  		return nil, errorsmod.Wrap(err, "decision policy")
   458  	}
   459  
   460  	ctx := sdk.UnwrapSDKContext(goCtx)
   461  	action := func(groupPolicy *group.GroupPolicyInfo) error {
   462  		groupInfo, err := k.getGroupInfo(ctx, groupPolicy.GroupId)
   463  		if err != nil {
   464  			return err
   465  		}
   466  
   467  		err = policy.Validate(groupInfo, k.config)
   468  		if err != nil {
   469  			return err
   470  		}
   471  
   472  		err = groupPolicy.SetDecisionPolicy(policy)
   473  		if err != nil {
   474  			return err
   475  		}
   476  
   477  		groupPolicy.Version++
   478  		return k.groupPolicyTable.Update(ctx.KVStore(k.key), groupPolicy)
   479  	}
   480  
   481  	if err = k.doUpdateGroupPolicy(ctx, msg.GroupPolicyAddress, msg.Admin, action, "group policy's decision policy updated"); err != nil {
   482  		return nil, err
   483  	}
   484  
   485  	return &group.MsgUpdateGroupPolicyDecisionPolicyResponse{}, nil
   486  }
   487  
   488  func (k Keeper) UpdateGroupPolicyMetadata(goCtx context.Context, msg *group.MsgUpdateGroupPolicyMetadata) (*group.MsgUpdateGroupPolicyMetadataResponse, error) {
   489  	ctx := sdk.UnwrapSDKContext(goCtx)
   490  	metadata := msg.GetMetadata()
   491  
   492  	action := func(groupPolicy *group.GroupPolicyInfo) error {
   493  		groupPolicy.Metadata = metadata
   494  		groupPolicy.Version++
   495  		return k.groupPolicyTable.Update(ctx.KVStore(k.key), groupPolicy)
   496  	}
   497  
   498  	if err := k.assertMetadataLength(metadata, "group policy metadata"); err != nil {
   499  		return nil, err
   500  	}
   501  
   502  	err := k.doUpdateGroupPolicy(ctx, msg.GroupPolicyAddress, msg.Admin, action, "group policy metadata updated")
   503  	if err != nil {
   504  		return nil, err
   505  	}
   506  
   507  	return &group.MsgUpdateGroupPolicyMetadataResponse{}, nil
   508  }
   509  
   510  func (k Keeper) SubmitProposal(goCtx context.Context, msg *group.MsgSubmitProposal) (*group.MsgSubmitProposalResponse, error) {
   511  	if len(msg.Proposers) == 0 {
   512  		return nil, errorsmod.Wrap(errors.ErrEmpty, "proposers")
   513  	}
   514  
   515  	if err := k.validateProposers(msg.Proposers); err != nil {
   516  		return nil, err
   517  	}
   518  
   519  	groupPolicyAddr, err := k.accKeeper.AddressCodec().StringToBytes(msg.GroupPolicyAddress)
   520  	if err != nil {
   521  		return nil, errorsmod.Wrap(err, "request account address of group policy")
   522  	}
   523  
   524  	if err := k.assertMetadataLength(msg.Title, "proposal Title"); err != nil {
   525  		return nil, err
   526  	}
   527  
   528  	if err := k.assertSummaryLength(msg.Summary); err != nil {
   529  		return nil, err
   530  	}
   531  
   532  	if err := k.assertMetadataLength(msg.Metadata, "metadata"); err != nil {
   533  		return nil, err
   534  	}
   535  
   536  	// verify that if present, the metadata title and summary equals the proposal title and summary
   537  	if len(msg.Metadata) != 0 {
   538  		proposalMetadata := govtypes.ProposalMetadata{}
   539  		if err := json.Unmarshal([]byte(msg.Metadata), &proposalMetadata); err == nil {
   540  			if proposalMetadata.Title != msg.Title {
   541  				return nil, fmt.Errorf("metadata title '%s' must equal proposal title '%s'", proposalMetadata.Title, msg.Title)
   542  			}
   543  
   544  			if proposalMetadata.Summary != msg.Summary {
   545  				return nil, fmt.Errorf("metadata summary '%s' must equal proposal summary '%s'", proposalMetadata.Summary, msg.Summary)
   546  			}
   547  		}
   548  
   549  		// if we can't unmarshal the metadata, this means the client didn't use the recommended metadata format
   550  		// nothing can be done here, and this is still a valid case, so we ignore the error
   551  	}
   552  
   553  	msgs, err := msg.GetMsgs()
   554  	if err != nil {
   555  		return nil, errorsmod.Wrap(err, "request msgs")
   556  	}
   557  
   558  	if err := validateMsgs(msgs); err != nil {
   559  		return nil, err
   560  	}
   561  
   562  	ctx := sdk.UnwrapSDKContext(goCtx)
   563  	policyAcc, err := k.getGroupPolicyInfo(ctx, msg.GroupPolicyAddress)
   564  	if err != nil {
   565  		return nil, errorsmod.Wrapf(err, "load group policy: %s", msg.GroupPolicyAddress)
   566  	}
   567  
   568  	groupInfo, err := k.getGroupInfo(ctx, policyAcc.GroupId)
   569  	if err != nil {
   570  		return nil, errorsmod.Wrap(err, "get group by groupId of group policy")
   571  	}
   572  
   573  	// Only members of the group can submit a new proposal.
   574  	for _, proposer := range msg.Proposers {
   575  		if !k.groupMemberTable.Has(ctx.KVStore(k.key), orm.PrimaryKey(&group.GroupMember{GroupId: groupInfo.Id, Member: &group.Member{Address: proposer}})) {
   576  			return nil, errorsmod.Wrapf(errors.ErrUnauthorized, "not in group: %s", proposer)
   577  		}
   578  	}
   579  
   580  	// Check that if the messages require signers, they are all equal to the given account address of group policy.
   581  	if err := ensureMsgAuthZ(msgs, groupPolicyAddr, k.cdc); err != nil {
   582  		return nil, err
   583  	}
   584  
   585  	policy, err := policyAcc.GetDecisionPolicy()
   586  	if err != nil {
   587  		return nil, errorsmod.Wrap(err, "proposal group policy decision policy")
   588  	}
   589  
   590  	// Prevent proposal that cannot succeed.
   591  	if err = policy.Validate(groupInfo, k.config); err != nil {
   592  		return nil, err
   593  	}
   594  
   595  	m := &group.Proposal{
   596  		Id:                 k.proposalTable.Sequence().PeekNextVal(ctx.KVStore(k.key)),
   597  		GroupPolicyAddress: msg.GroupPolicyAddress,
   598  		Metadata:           msg.Metadata,
   599  		Proposers:          msg.Proposers,
   600  		SubmitTime:         ctx.BlockTime(),
   601  		GroupVersion:       groupInfo.Version,
   602  		GroupPolicyVersion: policyAcc.Version,
   603  		Status:             group.PROPOSAL_STATUS_SUBMITTED,
   604  		ExecutorResult:     group.PROPOSAL_EXECUTOR_RESULT_NOT_RUN,
   605  		VotingPeriodEnd:    ctx.BlockTime().Add(policy.GetVotingPeriod()), // The voting window begins as soon as the proposal is submitted.
   606  		FinalTallyResult:   group.DefaultTallyResult(),
   607  		Title:              msg.Title,
   608  		Summary:            msg.Summary,
   609  	}
   610  
   611  	if err := m.SetMsgs(msgs); err != nil {
   612  		return nil, errorsmod.Wrap(err, "create proposal")
   613  	}
   614  
   615  	id, err := k.proposalTable.Create(ctx.KVStore(k.key), m)
   616  	if err != nil {
   617  		return nil, errorsmod.Wrap(err, "create proposal")
   618  	}
   619  
   620  	if err := ctx.EventManager().EmitTypedEvent(&group.EventSubmitProposal{ProposalId: id}); err != nil {
   621  		return nil, err
   622  	}
   623  
   624  	// Try to execute proposal immediately
   625  	if msg.Exec == group.Exec_EXEC_TRY {
   626  		// Consider proposers as Yes votes
   627  		for _, proposer := range msg.Proposers {
   628  			ctx.GasMeter().ConsumeGas(gasCostPerIteration, "vote on proposal")
   629  			_, err = k.Vote(ctx, &group.MsgVote{
   630  				ProposalId: id,
   631  				Voter:      proposer,
   632  				Option:     group.VOTE_OPTION_YES,
   633  			})
   634  			if err != nil {
   635  				return &group.MsgSubmitProposalResponse{ProposalId: id}, errorsmod.Wrapf(err, "the proposal was created but failed on vote for voter %s", proposer)
   636  			}
   637  		}
   638  
   639  		// Then try to execute the proposal
   640  		_, err = k.Exec(ctx, &group.MsgExec{
   641  			ProposalId: id,
   642  			// We consider the first proposer as the MsgExecRequest signer
   643  			// but that could be revisited (eg using the group policy)
   644  			Executor: msg.Proposers[0],
   645  		})
   646  		if err != nil {
   647  			return &group.MsgSubmitProposalResponse{ProposalId: id}, errorsmod.Wrap(err, "the proposal was created but failed on exec")
   648  		}
   649  	}
   650  
   651  	return &group.MsgSubmitProposalResponse{ProposalId: id}, nil
   652  }
   653  
   654  func (k Keeper) WithdrawProposal(goCtx context.Context, msg *group.MsgWithdrawProposal) (*group.MsgWithdrawProposalResponse, error) {
   655  	if msg.ProposalId == 0 {
   656  		return nil, errorsmod.Wrap(errors.ErrEmpty, "proposal id")
   657  	}
   658  
   659  	if _, err := k.accKeeper.AddressCodec().StringToBytes(msg.Address); err != nil {
   660  		return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid group policy admin / proposer address: %s", msg.Address)
   661  	}
   662  
   663  	ctx := sdk.UnwrapSDKContext(goCtx)
   664  	proposal, err := k.getProposal(ctx, msg.ProposalId)
   665  	if err != nil {
   666  		return nil, err
   667  	}
   668  
   669  	// Ensure the proposal can be withdrawn.
   670  	if proposal.Status != group.PROPOSAL_STATUS_SUBMITTED {
   671  		return nil, errorsmod.Wrapf(errors.ErrInvalid, "cannot withdraw a proposal with the status of %s", proposal.Status.String())
   672  	}
   673  
   674  	var policyInfo group.GroupPolicyInfo
   675  	if policyInfo, err = k.getGroupPolicyInfo(ctx, proposal.GroupPolicyAddress); err != nil {
   676  		return nil, errorsmod.Wrap(err, "load group policy")
   677  	}
   678  
   679  	// check address is the group policy admin he is in proposers list..
   680  	if msg.Address != policyInfo.Admin && !isProposer(proposal, msg.Address) {
   681  		return nil, errorsmod.Wrapf(errors.ErrUnauthorized, "given address is neither group policy admin nor in proposers: %s", msg.Address)
   682  	}
   683  
   684  	proposal.Status = group.PROPOSAL_STATUS_WITHDRAWN
   685  	if err := k.proposalTable.Update(ctx.KVStore(k.key), msg.ProposalId, &proposal); err != nil {
   686  		return nil, err
   687  	}
   688  
   689  	if err := ctx.EventManager().EmitTypedEvent(&group.EventWithdrawProposal{ProposalId: msg.ProposalId}); err != nil {
   690  		return nil, err
   691  	}
   692  
   693  	return &group.MsgWithdrawProposalResponse{}, nil
   694  }
   695  
   696  func (k Keeper) Vote(goCtx context.Context, msg *group.MsgVote) (*group.MsgVoteResponse, error) {
   697  	if msg.ProposalId == 0 {
   698  		return nil, errorsmod.Wrap(errors.ErrEmpty, "proposal id")
   699  	}
   700  
   701  	// verify vote options
   702  	if msg.Option == group.VOTE_OPTION_UNSPECIFIED {
   703  		return nil, errorsmod.Wrap(errors.ErrEmpty, "vote option")
   704  	}
   705  
   706  	if _, ok := group.VoteOption_name[int32(msg.Option)]; !ok {
   707  		return nil, errorsmod.Wrap(errors.ErrInvalid, "vote option")
   708  	}
   709  
   710  	if err := k.assertMetadataLength(msg.Metadata, "metadata"); err != nil {
   711  		return nil, err
   712  	}
   713  
   714  	if _, err := k.accKeeper.AddressCodec().StringToBytes(msg.Voter); err != nil {
   715  		return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid voter address: %s", msg.Voter)
   716  	}
   717  
   718  	ctx := sdk.UnwrapSDKContext(goCtx)
   719  	proposal, err := k.getProposal(ctx, msg.ProposalId)
   720  	if err != nil {
   721  		return nil, err
   722  	}
   723  
   724  	// Ensure that we can still accept votes for this proposal.
   725  	if proposal.Status != group.PROPOSAL_STATUS_SUBMITTED {
   726  		return nil, errorsmod.Wrap(errors.ErrInvalid, "proposal not open for voting")
   727  	}
   728  
   729  	if ctx.BlockTime().After(proposal.VotingPeriodEnd) {
   730  		return nil, errorsmod.Wrap(errors.ErrExpired, "voting period has ended already")
   731  	}
   732  
   733  	policyInfo, err := k.getGroupPolicyInfo(ctx, proposal.GroupPolicyAddress)
   734  	if err != nil {
   735  		return nil, errorsmod.Wrap(err, "load group policy")
   736  	}
   737  
   738  	groupInfo, err := k.getGroupInfo(ctx, policyInfo.GroupId)
   739  	if err != nil {
   740  		return nil, err
   741  	}
   742  
   743  	// Count and store votes.
   744  	voter := group.GroupMember{GroupId: groupInfo.Id, Member: &group.Member{Address: msg.Voter}}
   745  	if err := k.groupMemberTable.GetOne(ctx.KVStore(k.key), orm.PrimaryKey(&voter), &voter); err != nil {
   746  		return nil, errorsmod.Wrapf(err, "voter address: %s", msg.Voter)
   747  	}
   748  	newVote := group.Vote{
   749  		ProposalId: msg.ProposalId,
   750  		Voter:      msg.Voter,
   751  		Option:     msg.Option,
   752  		Metadata:   msg.Metadata,
   753  		SubmitTime: ctx.BlockTime(),
   754  	}
   755  
   756  	// The ORM will return an error if the vote already exists,
   757  	// making sure than a voter hasn't already voted.
   758  	if err := k.voteTable.Create(ctx.KVStore(k.key), &newVote); err != nil {
   759  		return nil, errorsmod.Wrap(err, "store vote")
   760  	}
   761  
   762  	if err := ctx.EventManager().EmitTypedEvent(&group.EventVote{ProposalId: msg.ProposalId}); err != nil {
   763  		return nil, err
   764  	}
   765  
   766  	// Try to execute proposal immediately
   767  	if msg.Exec == group.Exec_EXEC_TRY {
   768  		_, err = k.Exec(ctx, &group.MsgExec{ProposalId: msg.ProposalId, Executor: msg.Voter})
   769  		if err != nil {
   770  			return nil, err
   771  		}
   772  	}
   773  
   774  	return &group.MsgVoteResponse{}, nil
   775  }
   776  
   777  // doTallyAndUpdate performs a tally, and, if the tally result is final, then:
   778  // - updates the proposal's `Status` and `FinalTallyResult` fields,
   779  // - prune all the votes.
   780  func (k Keeper) doTallyAndUpdate(ctx sdk.Context, p *group.Proposal, groupInfo group.GroupInfo, policyInfo group.GroupPolicyInfo) error {
   781  	policy, err := policyInfo.GetDecisionPolicy()
   782  	if err != nil {
   783  		return err
   784  	}
   785  
   786  	tallyResult, err := k.Tally(ctx, *p, policyInfo.GroupId)
   787  	if err != nil {
   788  		return err
   789  	}
   790  
   791  	result, err := policy.Allow(tallyResult, groupInfo.TotalWeight)
   792  	if err != nil {
   793  		return errorsmod.Wrap(err, "policy allow")
   794  	}
   795  
   796  	// If the result was final (i.e. enough votes to pass) or if the voting
   797  	// period ended, then we consider the proposal as final.
   798  	if isFinal := result.Final || ctx.BlockTime().After(p.VotingPeriodEnd); isFinal {
   799  		if err := k.pruneVotes(ctx, p.Id); err != nil {
   800  			return err
   801  		}
   802  		p.FinalTallyResult = tallyResult
   803  		if result.Allow {
   804  			p.Status = group.PROPOSAL_STATUS_ACCEPTED
   805  		} else {
   806  			p.Status = group.PROPOSAL_STATUS_REJECTED
   807  		}
   808  
   809  	}
   810  
   811  	return nil
   812  }
   813  
   814  // Exec executes the messages from a proposal.
   815  func (k Keeper) Exec(goCtx context.Context, msg *group.MsgExec) (*group.MsgExecResponse, error) {
   816  	if msg.ProposalId == 0 {
   817  		return nil, errorsmod.Wrap(errors.ErrEmpty, "proposal id")
   818  	}
   819  
   820  	ctx := sdk.UnwrapSDKContext(goCtx)
   821  	proposal, err := k.getProposal(ctx, msg.ProposalId)
   822  	if err != nil {
   823  		return nil, err
   824  	}
   825  
   826  	if proposal.Status != group.PROPOSAL_STATUS_SUBMITTED && proposal.Status != group.PROPOSAL_STATUS_ACCEPTED {
   827  		return nil, errorsmod.Wrapf(errors.ErrInvalid, "not possible to exec with proposal status %s", proposal.Status.String())
   828  	}
   829  
   830  	policyInfo, err := k.getGroupPolicyInfo(ctx, proposal.GroupPolicyAddress)
   831  	if err != nil {
   832  		return nil, errorsmod.Wrap(err, "load group policy")
   833  	}
   834  
   835  	// If proposal is still in SUBMITTED phase, it means that the voting period
   836  	// didn't end yet, and tallying hasn't been done. In this case, we need to
   837  	// tally first.
   838  	if proposal.Status == group.PROPOSAL_STATUS_SUBMITTED {
   839  		groupInfo, err := k.getGroupInfo(ctx, policyInfo.GroupId)
   840  		if err != nil {
   841  			return nil, errorsmod.Wrap(err, "load group")
   842  		}
   843  
   844  		if err = k.doTallyAndUpdate(ctx, &proposal, groupInfo, policyInfo); err != nil {
   845  			return nil, err
   846  		}
   847  	}
   848  
   849  	// Execute proposal payload.
   850  	var logs string
   851  	if proposal.Status == group.PROPOSAL_STATUS_ACCEPTED && proposal.ExecutorResult != group.PROPOSAL_EXECUTOR_RESULT_SUCCESS {
   852  		// Caching context so that we don't update the store in case of failure.
   853  		cacheCtx, flush := ctx.CacheContext()
   854  
   855  		addr, err := k.accKeeper.AddressCodec().StringToBytes(policyInfo.Address)
   856  		if err != nil {
   857  			return nil, err
   858  		}
   859  
   860  		decisionPolicy := policyInfo.DecisionPolicy.GetCachedValue().(group.DecisionPolicy)
   861  		if results, err := k.doExecuteMsgs(cacheCtx, k.router, proposal, addr, decisionPolicy); err != nil {
   862  			proposal.ExecutorResult = group.PROPOSAL_EXECUTOR_RESULT_FAILURE
   863  			logs = fmt.Sprintf("proposal execution failed on proposal %d, because of error %s", proposal.Id, err.Error())
   864  			k.Logger(ctx).Info("proposal execution failed", "cause", err, "proposalID", proposal.Id)
   865  		} else {
   866  			proposal.ExecutorResult = group.PROPOSAL_EXECUTOR_RESULT_SUCCESS
   867  			flush()
   868  
   869  			for _, res := range results {
   870  				// NOTE: The sdk msg handler creates a new EventManager, so events must be correctly propagated back to the current context
   871  				ctx.EventManager().EmitEvents(res.GetEvents())
   872  			}
   873  		}
   874  	}
   875  
   876  	// Update proposal in proposalTable
   877  	// If proposal has successfully run, delete it from state.
   878  	if proposal.ExecutorResult == group.PROPOSAL_EXECUTOR_RESULT_SUCCESS {
   879  		if err := k.pruneProposal(ctx, proposal.Id); err != nil {
   880  			return nil, err
   881  		}
   882  
   883  		// Emit event for proposal finalized with its result
   884  		if err := ctx.EventManager().EmitTypedEvent(
   885  			&group.EventProposalPruned{
   886  				ProposalId:  proposal.Id,
   887  				Status:      proposal.Status,
   888  				TallyResult: &proposal.FinalTallyResult,
   889  			}); err != nil {
   890  			return nil, err
   891  		}
   892  	} else {
   893  		store := ctx.KVStore(k.key)
   894  		if err := k.proposalTable.Update(store, proposal.Id, &proposal); err != nil {
   895  			return nil, err
   896  		}
   897  	}
   898  
   899  	if err := ctx.EventManager().EmitTypedEvent(&group.EventExec{
   900  		ProposalId: proposal.Id,
   901  		Logs:       logs,
   902  		Result:     proposal.ExecutorResult,
   903  	}); err != nil {
   904  		return nil, err
   905  	}
   906  
   907  	return &group.MsgExecResponse{
   908  		Result: proposal.ExecutorResult,
   909  	}, nil
   910  }
   911  
   912  // LeaveGroup implements the MsgServer/LeaveGroup method.
   913  func (k Keeper) LeaveGroup(goCtx context.Context, msg *group.MsgLeaveGroup) (*group.MsgLeaveGroupResponse, error) {
   914  	if msg.GroupId == 0 {
   915  		return nil, errorsmod.Wrap(errors.ErrEmpty, "group-id")
   916  	}
   917  
   918  	_, err := k.accKeeper.AddressCodec().StringToBytes(msg.Address)
   919  	if err != nil {
   920  		return nil, errorsmod.Wrap(err, "group member")
   921  	}
   922  
   923  	ctx := sdk.UnwrapSDKContext(goCtx)
   924  	groupInfo, err := k.getGroupInfo(ctx, msg.GroupId)
   925  	if err != nil {
   926  		return nil, errorsmod.Wrap(err, "group")
   927  	}
   928  
   929  	groupWeight, err := math.NewNonNegativeDecFromString(groupInfo.TotalWeight)
   930  	if err != nil {
   931  		return nil, err
   932  	}
   933  
   934  	gm, err := k.getGroupMember(ctx, &group.GroupMember{
   935  		GroupId: msg.GroupId,
   936  		Member:  &group.Member{Address: msg.Address},
   937  	})
   938  	if err != nil {
   939  		return nil, err
   940  	}
   941  
   942  	memberWeight, err := math.NewPositiveDecFromString(gm.Member.Weight)
   943  	if err != nil {
   944  		return nil, err
   945  	}
   946  
   947  	updatedWeight, err := math.SubNonNegative(groupWeight, memberWeight)
   948  	if err != nil {
   949  		return nil, err
   950  	}
   951  
   952  	// delete group member in the groupMemberTable.
   953  	if err := k.groupMemberTable.Delete(ctx.KVStore(k.key), gm); err != nil {
   954  		return nil, errorsmod.Wrap(err, "group member")
   955  	}
   956  
   957  	// update group weight
   958  	groupInfo.TotalWeight = updatedWeight.String()
   959  	groupInfo.Version++
   960  
   961  	if err := k.validateDecisionPolicies(ctx, groupInfo); err != nil {
   962  		return nil, err
   963  	}
   964  
   965  	if err := k.groupTable.Update(ctx.KVStore(k.key), groupInfo.Id, &groupInfo); err != nil {
   966  		return nil, err
   967  	}
   968  
   969  	if err := ctx.EventManager().EmitTypedEvent(&group.EventLeaveGroup{
   970  		GroupId: msg.GroupId,
   971  		Address: msg.Address,
   972  	}); err != nil {
   973  		return nil, err
   974  	}
   975  
   976  	return &group.MsgLeaveGroupResponse{}, nil
   977  }
   978  
   979  func (k Keeper) getGroupMember(ctx sdk.Context, member *group.GroupMember) (*group.GroupMember, error) {
   980  	var groupMember group.GroupMember
   981  	switch err := k.groupMemberTable.GetOne(ctx.KVStore(k.key),
   982  		orm.PrimaryKey(member), &groupMember); {
   983  	case err == nil:
   984  		break
   985  	case sdkerrors.ErrNotFound.Is(err):
   986  		return nil, sdkerrors.ErrNotFound.Wrapf("%s is not part of group %d", member.Member.Address, member.GroupId)
   987  	default:
   988  		return nil, err
   989  	}
   990  
   991  	return &groupMember, nil
   992  }
   993  
   994  type (
   995  	actionFn            func(m *group.GroupInfo) error
   996  	groupPolicyActionFn func(m *group.GroupPolicyInfo) error
   997  )
   998  
   999  // doUpdateGroupPolicy first makes sure that the group policy admin initiated the group policy update,
  1000  // before performing the group policy update and emitting an event.
  1001  func (k Keeper) doUpdateGroupPolicy(ctx sdk.Context, reqGroupPolicy, reqAdmin string, action groupPolicyActionFn, note string) error {
  1002  	groupPolicyAddr, err := k.accKeeper.AddressCodec().StringToBytes(reqGroupPolicy)
  1003  	if err != nil {
  1004  		return errorsmod.Wrap(err, "group policy address")
  1005  	}
  1006  
  1007  	_, err = k.accKeeper.AddressCodec().StringToBytes(reqAdmin)
  1008  	if err != nil {
  1009  		return errorsmod.Wrap(err, "group policy admin")
  1010  	}
  1011  
  1012  	groupPolicyInfo, err := k.getGroupPolicyInfo(ctx, reqGroupPolicy)
  1013  	if err != nil {
  1014  		return errorsmod.Wrap(err, "load group policy")
  1015  	}
  1016  
  1017  	// Only current group policy admin is authorized to update a group policy.
  1018  	if reqAdmin != groupPolicyInfo.Admin {
  1019  		return errorsmod.Wrap(sdkerrors.ErrUnauthorized, "not group policy admin")
  1020  	}
  1021  
  1022  	if err := action(&groupPolicyInfo); err != nil {
  1023  		return errorsmod.Wrap(err, note)
  1024  	}
  1025  
  1026  	if err = k.abortProposals(ctx, groupPolicyAddr); err != nil {
  1027  		return err
  1028  	}
  1029  
  1030  	if err = ctx.EventManager().EmitTypedEvent(&group.EventUpdateGroupPolicy{Address: groupPolicyInfo.Address}); err != nil {
  1031  		return err
  1032  	}
  1033  
  1034  	return nil
  1035  }
  1036  
  1037  // doUpdateGroup first makes sure that the group admin initiated the group update,
  1038  // before performing the group update and emitting an event.
  1039  func (k Keeper) doUpdateGroup(ctx sdk.Context, groupID uint64, reqGroupAdmin string, action actionFn, errNote string) error {
  1040  	groupInfo, err := k.getGroupInfo(ctx, groupID)
  1041  	if err != nil {
  1042  		return err
  1043  	}
  1044  
  1045  	if !strings.EqualFold(groupInfo.Admin, reqGroupAdmin) {
  1046  		return errorsmod.Wrapf(sdkerrors.ErrUnauthorized, "not group admin; got %s, expected %s", reqGroupAdmin, groupInfo.Admin)
  1047  	}
  1048  
  1049  	if err := action(&groupInfo); err != nil {
  1050  		return errorsmod.Wrap(err, errNote)
  1051  	}
  1052  
  1053  	if err := ctx.EventManager().EmitTypedEvent(&group.EventUpdateGroup{GroupId: groupID}); err != nil {
  1054  		return err
  1055  	}
  1056  
  1057  	return nil
  1058  }
  1059  
  1060  // assertMetadataLength returns an error if given metadata length
  1061  // is greater than a pre-defined maxMetadataLen.
  1062  func (k Keeper) assertMetadataLength(metadata, description string) error {
  1063  	if metadata != "" && uint64(len(metadata)) > k.config.MaxMetadataLen {
  1064  		return errorsmod.Wrapf(errors.ErrMaxLimit, description)
  1065  	}
  1066  	return nil
  1067  }
  1068  
  1069  // assertSummaryLength returns an error if given summary length
  1070  // is greater than a pre-defined 40*MaxMetadataLen.
  1071  func (k Keeper) assertSummaryLength(summary string) error {
  1072  	if summary != "" && uint64(len(summary)) > 40*k.config.MaxMetadataLen {
  1073  		return errorsmod.Wrapf(errors.ErrMaxLimit, "proposal summary is too long")
  1074  	}
  1075  	return nil
  1076  }
  1077  
  1078  // validateDecisionPolicies loops through all decision policies from the group,
  1079  // and calls each of their Validate() method.
  1080  func (k Keeper) validateDecisionPolicies(ctx sdk.Context, g group.GroupInfo) error {
  1081  	it, err := k.groupPolicyByGroupIndex.Get(ctx.KVStore(k.key), g.Id)
  1082  	if err != nil {
  1083  		return err
  1084  	}
  1085  	defer it.Close()
  1086  
  1087  	for {
  1088  		var groupPolicy group.GroupPolicyInfo
  1089  		_, err = it.LoadNext(&groupPolicy)
  1090  		if errors.ErrORMIteratorDone.Is(err) {
  1091  			break
  1092  		}
  1093  		if err != nil {
  1094  			return err
  1095  		}
  1096  
  1097  		err = groupPolicy.DecisionPolicy.GetCachedValue().(group.DecisionPolicy).Validate(g, k.config)
  1098  		if err != nil {
  1099  			return err
  1100  		}
  1101  	}
  1102  
  1103  	return nil
  1104  }
  1105  
  1106  // validateProposers checks that all proposers addresses are valid.
  1107  // It as well verifies that there is no duplicate address.
  1108  func (k Keeper) validateProposers(proposers []string) error {
  1109  	index := make(map[string]struct{}, len(proposers))
  1110  	for _, proposer := range proposers {
  1111  		if _, exists := index[proposer]; exists {
  1112  			return errorsmod.Wrapf(errors.ErrDuplicate, "address: %s", proposer)
  1113  		}
  1114  
  1115  		_, err := k.accKeeper.AddressCodec().StringToBytes(proposer)
  1116  		if err != nil {
  1117  			return errorsmod.Wrapf(err, "proposer address %s", proposer)
  1118  		}
  1119  
  1120  		index[proposer] = struct{}{}
  1121  	}
  1122  
  1123  	return nil
  1124  }
  1125  
  1126  // validateMembers checks that all members addresses are valid.
  1127  // additionally it verifies that there is no duplicate address
  1128  // and the member weight is non-negative.
  1129  // Note: in state, a member's weight MUST be positive. However, in some Msgs,
  1130  // it's possible to set a zero member weight, for example in
  1131  // MsgUpdateGroupMembers to denote that we're removing a member.
  1132  // It returns an error if any of the above conditions is not met.
  1133  func (k Keeper) validateMembers(members []group.MemberRequest) error {
  1134  	index := make(map[string]struct{}, len(members))
  1135  	for _, member := range members {
  1136  		if _, exists := index[member.Address]; exists {
  1137  			return errorsmod.Wrapf(errors.ErrDuplicate, "address: %s", member.Address)
  1138  		}
  1139  
  1140  		_, err := k.accKeeper.AddressCodec().StringToBytes(member.Address)
  1141  		if err != nil {
  1142  			return errorsmod.Wrapf(err, "member address %s", member.Address)
  1143  		}
  1144  
  1145  		if _, err := math.NewNonNegativeDecFromString(member.Weight); err != nil {
  1146  			return errorsmod.Wrap(err, "weight must be non negative")
  1147  		}
  1148  
  1149  		index[member.Address] = struct{}{}
  1150  	}
  1151  
  1152  	return nil
  1153  }
  1154  
  1155  // isProposer checks that an address is a proposer of a given proposal.
  1156  func isProposer(proposal group.Proposal, address string) bool {
  1157  	for _, proposer := range proposal.Proposers {
  1158  		if proposer == address {
  1159  			return true
  1160  		}
  1161  	}
  1162  
  1163  	return false
  1164  }
  1165  
  1166  func validateMsgs(msgs []sdk.Msg) error {
  1167  	for i, msg := range msgs {
  1168  		m, ok := msg.(sdk.HasValidateBasic)
  1169  		if !ok {
  1170  			continue
  1171  		}
  1172  
  1173  		if err := m.ValidateBasic(); err != nil {
  1174  			return errorsmod.Wrapf(err, "msg %d", i)
  1175  		}
  1176  	}
  1177  
  1178  	return nil
  1179  }