cosmos-sdk/x/authz/simulation/msg_factory.go
2025-10-10 08:52:49 -04:00

108 lines
3.7 KiB
Go

package simulation
import (
"context"
"time"
"github.com/cosmos/cosmos-sdk/testutil/simsx"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/authz"
"github.com/cosmos/cosmos-sdk/x/authz/keeper"
banktype "github.com/cosmos/cosmos-sdk/x/bank/types"
)
func MsgGrantFactory() simsx.SimMsgFactoryFn[*authz.MsgGrant] {
return func(ctx context.Context, testData *simsx.ChainDataSource, reporter simsx.SimulationReporter) ([]simsx.SimAccount, *authz.MsgGrant) {
granter := testData.AnyAccount(reporter, simsx.WithSpendableBalance())
grantee := testData.AnyAccount(reporter, simsx.ExcludeAccounts(granter))
spendLimit := granter.LiquidBalance().RandSubsetCoins(reporter, simsx.WithSendEnabledCoins())
r := testData.Rand()
var expiration *time.Time
if t1 := r.Timestamp(); !t1.Before(simsx.BlockTime(ctx)) {
expiration = &t1
}
// pick random authorization
authorizations := []authz.Authorization{
banktype.NewSendAuthorization(spendLimit, nil),
authz.NewGenericAuthorization(sdk.MsgTypeURL(&banktype.MsgSend{})),
}
randomAuthz := simsx.OneOf(r, authorizations)
msg, err := authz.NewMsgGrant(granter.Address, grantee.Address, randomAuthz, expiration)
if err != nil {
reporter.Skip(err.Error())
return nil, nil
}
return []simsx.SimAccount{granter}, msg
}
}
func MsgExecFactory(k keeper.Keeper) simsx.SimMsgFactoryFn[*authz.MsgExec] {
return func(ctx context.Context, testData *simsx.ChainDataSource, reporter simsx.SimulationReporter) ([]simsx.SimAccount, *authz.MsgExec) {
bankSendOnlyFilter := func(a authz.Authorization) bool {
_, ok := a.(*banktype.SendAuthorization)
return ok
}
granterAddr, granteeAddr, gAuthz := findGrant(ctx, k, reporter, bankSendOnlyFilter)
granter := testData.GetAccountbyAccAddr(reporter, granterAddr)
grantee := testData.GetAccountbyAccAddr(reporter, granteeAddr)
if reporter.IsSkipped() {
return nil, nil
}
amount := granter.LiquidBalance().RandSubsetCoins(reporter, simsx.WithSendEnabledCoins())
amount = amount.Min(gAuthz.(*banktype.SendAuthorization).SpendLimit)
if !amount.IsAllPositive() {
reporter.Skip("amount is not positive")
return nil, nil
}
payloadMsg := []sdk.Msg{banktype.NewMsgSend(granter.Address, grantee.Address, amount)}
msgExec := authz.NewMsgExec(grantee.Address, payloadMsg)
return []simsx.SimAccount{grantee}, &msgExec
}
}
func MsgRevokeFactory(k keeper.Keeper) simsx.SimMsgFactoryFn[*authz.MsgRevoke] {
return func(ctx context.Context, testData *simsx.ChainDataSource, reporter simsx.SimulationReporter) ([]simsx.SimAccount, *authz.MsgRevoke) {
granterAddr, granteeAddr, auth := findGrant(ctx, k, reporter)
granter := testData.GetAccountbyAccAddr(reporter, granterAddr)
grantee := testData.GetAccountbyAccAddr(reporter, granteeAddr)
if reporter.IsSkipped() {
return nil, nil
}
msgExec := authz.NewMsgRevoke(granter.Address, grantee.Address, auth.MsgTypeURL())
return []simsx.SimAccount{granter}, &msgExec
}
}
func findGrant(
ctx context.Context,
k keeper.Keeper,
reporter simsx.SimulationReporter,
acceptFilter ...func(a authz.Authorization) bool,
) (granterAddr, granteeAddr sdk.AccAddress, auth authz.Authorization) {
var innerErr error
k.IterateGrants(ctx, func(granter, grantee sdk.AccAddress, grant authz.Grant) bool {
a, err2 := grant.GetAuthorization()
if err2 != nil {
innerErr = err2
return true
}
for _, filter := range acceptFilter {
if !filter(a) {
return false
}
}
granterAddr, granteeAddr, auth = granter, grantee, a
return true
})
if innerErr != nil {
reporter.Skip(innerErr.Error())
return granterAddr, granteeAddr, auth
}
if auth == nil {
reporter.Skip("no grant found")
}
return granterAddr, granteeAddr, auth
}