refactor(x/authz): set environment in context (#20502)
This commit is contained in:
parent
ba4bc19175
commit
0f81966de8
@ -682,6 +682,14 @@ To learn more see the [docs](https://docs.cosmos.network/main/learn/advanced/tra
|
||||
|
||||
### Modules
|
||||
|
||||
<!-- create server/v2 changes docs and mention it here
|
||||
* mention changes in tx validators
|
||||
* mention changes with appmodulev2
|
||||
* mention changes with sdk context removal
|
||||
* mention changes with environment
|
||||
* mention changes with environment in context in interfaces
|
||||
-->
|
||||
|
||||
#### `**all**`
|
||||
|
||||
* [RFC 001](https://docs.cosmos.network/main/rfc/rfc-001-tx-validation) has defined a simplification of the message validation process for modules.
|
||||
|
||||
@ -6,3 +6,8 @@ const (
|
||||
ExecModeKey contextKey = iota
|
||||
CometInfoKey contextKey = iota
|
||||
)
|
||||
|
||||
// EnvironmentContextKey is the context key for the environment.
|
||||
// A caller should not assume the environment is available in each context.
|
||||
// ref: https://github.com/cosmos/cosmos-sdk/issues/19640
|
||||
var EnvironmentContextKey = struct{}{}
|
||||
|
||||
@ -32,6 +32,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
||||
|
||||
### API Breaking Changes
|
||||
|
||||
* [#20502](https://github.com/cosmos/cosmos-sdk/pull/20502) `Accept` on the `Authorization` interface now expects the authz environment in the `context.Context`. This is already done when `Accept` is called by `k.DispatchActions`, but should be done manually if `Accept` is called directly.
|
||||
* [#19783](https://github.com/cosmos/cosmos-sdk/pull/19783) Removes the use of Accounts String() method
|
||||
* `NewMsgExec`, `NewMsgGrant` and `NewMsgRevoke` now takes strings as arguments instead of `sdk.AccAddress`.
|
||||
* `ExportGenesis` also returns an error.
|
||||
|
||||
@ -9,6 +9,7 @@ import (
|
||||
"github.com/cosmos/gogoproto/proto"
|
||||
|
||||
"cosmossdk.io/core/appmodule"
|
||||
corecontext "cosmossdk.io/core/context"
|
||||
errorsmod "cosmossdk.io/errors"
|
||||
storetypes "cosmossdk.io/store/types"
|
||||
"cosmossdk.io/x/authz"
|
||||
@ -83,8 +84,7 @@ func (k Keeper) update(ctx context.Context, grantee, granter sdk.AccAddress, upd
|
||||
// grants from the message signer to the grantee.
|
||||
func (k Keeper) DispatchActions(ctx context.Context, grantee sdk.AccAddress, msgs []sdk.Msg) ([][]byte, error) {
|
||||
results := make([][]byte, len(msgs))
|
||||
sdkCtx := sdk.UnwrapSDKContext(ctx)
|
||||
now := sdkCtx.HeaderInfo().Time
|
||||
now := k.Environment.HeaderService.HeaderInfo(ctx).Time
|
||||
|
||||
for i, msg := range msgs {
|
||||
signers, _, err := k.cdc.GetMsgSigners(msg)
|
||||
@ -118,7 +118,10 @@ func (k Keeper) DispatchActions(ctx context.Context, grantee sdk.AccAddress, msg
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := authorization.Accept(sdkCtx, msg)
|
||||
// pass the environment in the context
|
||||
// users on server/v2 are expected to unwrap the environment from the context
|
||||
// users on baseapp can still unwrap the sdk context
|
||||
resp, err := authorization.Accept(context.WithValue(ctx, corecontext.EnvironmentContextKey, k.Environment), msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
package authz
|
||||
|
||||
const (
|
||||
// ModuleName is the module name constant used in many places
|
||||
ModuleName = "authz"
|
||||
)
|
||||
// ModuleName is the module name constant used in many places
|
||||
const ModuleName = "authz"
|
||||
|
||||
@ -1,10 +1,15 @@
|
||||
package simulation
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"cosmossdk.io/core/address"
|
||||
"cosmossdk.io/core/appmodule"
|
||||
corecontext "cosmossdk.io/core/context"
|
||||
coregas "cosmossdk.io/core/gas"
|
||||
coreheader "cosmossdk.io/core/header"
|
||||
"cosmossdk.io/x/authz"
|
||||
"cosmossdk.io/x/authz/keeper"
|
||||
banktype "cosmossdk.io/x/bank/types"
|
||||
@ -315,7 +320,12 @@ func SimulateMsgExec(
|
||||
|
||||
msg := []sdk.Msg{banktype.NewMsgSend(graStr, greStr, coins)}
|
||||
|
||||
_, err = sendAuth.Accept(ctx, msg[0])
|
||||
goCtx := context.WithValue(ctx.Context(), corecontext.EnvironmentContextKey, appmodule.Environment{
|
||||
HeaderService: headerService{},
|
||||
GasService: mockGasService{},
|
||||
})
|
||||
|
||||
_, err = sendAuth.Accept(goCtx, msg[0])
|
||||
if err != nil {
|
||||
if sdkerrors.ErrInsufficientFunds.Is(err) {
|
||||
return simtypes.NoOpMsg(authz.ModuleName, TypeMsgExec, err.Error()), nil, nil
|
||||
@ -359,3 +369,25 @@ func SimulateMsgExec(
|
||||
return simtypes.NewOperationMsg(&msgExec, true, "success"), nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
type headerService struct{}
|
||||
|
||||
func (h headerService) HeaderInfo(ctx context.Context) coreheader.Info {
|
||||
return sdk.UnwrapSDKContext(ctx).HeaderInfo()
|
||||
}
|
||||
|
||||
type mockGasService struct {
|
||||
coregas.Service
|
||||
}
|
||||
|
||||
func (m mockGasService) GasMeter(ctx context.Context) coregas.Meter {
|
||||
return mockGasMeter{}
|
||||
}
|
||||
|
||||
type mockGasMeter struct {
|
||||
coregas.Meter
|
||||
}
|
||||
|
||||
func (m mockGasMeter) Consume(amount coregas.Gas, descriptor string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -4,6 +4,8 @@ import (
|
||||
"context"
|
||||
|
||||
"cosmossdk.io/core/address"
|
||||
"cosmossdk.io/core/appmodule/v2"
|
||||
corecontext "cosmossdk.io/core/context"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/authz"
|
||||
@ -40,12 +42,19 @@ func (a SendAuthorization) Accept(ctx context.Context, msg sdk.Msg) (authz.Accep
|
||||
return authz.AcceptResponse{}, sdkerrors.ErrInsufficientFunds.Wrapf("requested amount is more than spend limit")
|
||||
}
|
||||
|
||||
authzEnv, ok := ctx.Value(corecontext.EnvironmentContextKey).(appmodule.Environment)
|
||||
if !ok {
|
||||
return authz.AcceptResponse{}, sdkerrors.ErrUnauthorized.Wrap("environment not set")
|
||||
}
|
||||
|
||||
isAddrExists := false
|
||||
toAddr := mSend.ToAddress
|
||||
allowedList := a.GetAllowList()
|
||||
sdkCtx := sdk.UnwrapSDKContext(ctx)
|
||||
for _, addr := range allowedList {
|
||||
sdkCtx.GasMeter().ConsumeGas(gasCostPerIteration, "send authorization")
|
||||
if err := authzEnv.GasService.GasMeter(ctx).Consume(gasCostPerIteration, "send authorization"); err != nil {
|
||||
return authz.AcceptResponse{}, err
|
||||
}
|
||||
|
||||
if addr == toAddr {
|
||||
isAddrExists = true
|
||||
break
|
||||
|
||||
@ -1,12 +1,16 @@
|
||||
package types_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"cosmossdk.io/core/header"
|
||||
"cosmossdk.io/core/appmodule/v2"
|
||||
corecontext "cosmossdk.io/core/context"
|
||||
coregas "cosmossdk.io/core/gas"
|
||||
coreheader "cosmossdk.io/core/header"
|
||||
sdkmath "cosmossdk.io/math"
|
||||
storetypes "cosmossdk.io/store/types"
|
||||
"cosmossdk.io/x/bank/types"
|
||||
@ -25,9 +29,36 @@ var (
|
||||
unknownAddrStr = "cosmos1ta047h6lw4hxkmn0wah97h6lta0sml880l"
|
||||
)
|
||||
|
||||
type headerService struct{}
|
||||
|
||||
func (h headerService) HeaderInfo(ctx context.Context) coreheader.Info {
|
||||
return sdk.UnwrapSDKContext(ctx).HeaderInfo()
|
||||
}
|
||||
|
||||
type mockGasService struct {
|
||||
coregas.Service
|
||||
}
|
||||
|
||||
func (m mockGasService) GasMeter(ctx context.Context) coregas.Meter {
|
||||
return mockGasMeter{}
|
||||
}
|
||||
|
||||
type mockGasMeter struct {
|
||||
coregas.Meter
|
||||
}
|
||||
|
||||
func (m mockGasMeter) Consume(amount coregas.Gas, descriptor string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestSendAuthorization(t *testing.T) {
|
||||
ac := codectestutil.CodecOptions{}.GetAddressCodec()
|
||||
ctx := testutil.DefaultContextWithDB(t, storetypes.NewKVStoreKey(types.StoreKey), storetypes.NewTransientStoreKey("transient_test")).Ctx.WithHeaderInfo(header.Info{})
|
||||
sdkCtx := testutil.DefaultContextWithDB(t, storetypes.NewKVStoreKey(types.StoreKey), storetypes.NewTransientStoreKey("transient_test")).Ctx.WithHeaderInfo(coreheader.Info{})
|
||||
ctx := context.WithValue(sdkCtx.Context(), corecontext.EnvironmentContextKey, appmodule.Environment{
|
||||
HeaderService: headerService{},
|
||||
GasService: mockGasService{},
|
||||
})
|
||||
|
||||
allowList := make([]sdk.AccAddress, 1)
|
||||
allowList[0] = toAddr
|
||||
authorization := types.NewSendAuthorization(coins1000, nil, ac)
|
||||
|
||||
@ -5,6 +5,8 @@ import (
|
||||
"fmt"
|
||||
|
||||
"cosmossdk.io/core/address"
|
||||
"cosmossdk.io/core/appmodule"
|
||||
corecontext "cosmossdk.io/core/context"
|
||||
errorsmod "cosmossdk.io/errors"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
@ -100,11 +102,17 @@ func (a StakeAuthorization) Accept(ctx context.Context, msg sdk.Msg) (authz.Acce
|
||||
return authz.AcceptResponse{}, sdkerrors.ErrInvalidRequest.Wrap("unknown msg type")
|
||||
}
|
||||
|
||||
authzEnv, ok := ctx.Value(corecontext.EnvironmentContextKey).(appmodule.Environment)
|
||||
if !ok {
|
||||
return authz.AcceptResponse{}, sdkerrors.ErrUnauthorized.Wrap("environment not set")
|
||||
}
|
||||
isValidatorExists := false
|
||||
allowedList := a.GetAllowList().GetAddress()
|
||||
sdkCtx := sdk.UnwrapSDKContext(ctx)
|
||||
for _, validator := range allowedList {
|
||||
sdkCtx.GasMeter().ConsumeGas(gasCostPerIteration, "stake authorization")
|
||||
if err := authzEnv.GasService.GasMeter(ctx).Consume(gasCostPerIteration, "stake authorization"); err != nil {
|
||||
return authz.AcceptResponse{}, err
|
||||
}
|
||||
|
||||
if validator == validatorAddress {
|
||||
isValidatorExists = true
|
||||
break
|
||||
@ -113,7 +121,10 @@ func (a StakeAuthorization) Accept(ctx context.Context, msg sdk.Msg) (authz.Acce
|
||||
|
||||
denyList := a.GetDenyList().GetAddress()
|
||||
for _, validator := range denyList {
|
||||
sdkCtx.GasMeter().ConsumeGas(gasCostPerIteration, "stake authorization")
|
||||
if err := authzEnv.GasService.GasMeter(ctx).Consume(gasCostPerIteration, "stake authorization"); err != nil {
|
||||
return authz.AcceptResponse{}, err
|
||||
}
|
||||
|
||||
if validator == validatorAddress {
|
||||
return authz.AcceptResponse{}, sdkerrors.ErrUnauthorized.Wrapf("cannot delegate/undelegate to %s validator", validator)
|
||||
}
|
||||
|
||||
@ -1,11 +1,15 @@
|
||||
package types_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"cosmossdk.io/core/appmodule/v2"
|
||||
corecontext "cosmossdk.io/core/context"
|
||||
coregas "cosmossdk.io/core/gas"
|
||||
coreheader "cosmossdk.io/core/header"
|
||||
storetypes "cosmossdk.io/store/types"
|
||||
stakingtypes "cosmossdk.io/x/staking/types"
|
||||
@ -39,10 +43,37 @@ func accAddressToString(t *testing.T, addr sdk.AccAddress) string {
|
||||
return r
|
||||
}
|
||||
|
||||
type headerService struct{}
|
||||
|
||||
func (h headerService) HeaderInfo(ctx context.Context) coreheader.Info {
|
||||
return sdk.UnwrapSDKContext(ctx).HeaderInfo()
|
||||
}
|
||||
|
||||
type mockGasService struct {
|
||||
coregas.Service
|
||||
}
|
||||
|
||||
func (m mockGasService) GasMeter(ctx context.Context) coregas.Meter {
|
||||
return mockGasMeter{}
|
||||
}
|
||||
|
||||
type mockGasMeter struct {
|
||||
coregas.Meter
|
||||
}
|
||||
|
||||
func (m mockGasMeter) Consume(amount coregas.Gas, descriptor string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestAuthzAuthorizations(t *testing.T) {
|
||||
key := storetypes.NewKVStoreKey(stakingtypes.StoreKey)
|
||||
testCtx := testutil.DefaultContextWithDB(t, key, storetypes.NewTransientStoreKey("transient_test"))
|
||||
ctx := testCtx.Ctx.WithHeaderInfo(coreheader.Info{})
|
||||
sdkCtx := testCtx.Ctx.WithHeaderInfo(coreheader.Info{})
|
||||
ctx := context.WithValue(sdkCtx.Context(), corecontext.EnvironmentContextKey, appmodule.Environment{
|
||||
HeaderService: headerService{},
|
||||
GasService: mockGasService{},
|
||||
})
|
||||
|
||||
valAddressCodec := codectestutil.CodecOptions{}.GetValidatorCodec()
|
||||
// verify ValidateBasic returns error for the AUTHORIZATION_TYPE_UNSPECIFIED authorization type
|
||||
delAuth, err := stakingtypes.NewStakeAuthorization([]sdk.ValAddress{val1, val2}, []sdk.ValAddress{}, stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_UNSPECIFIED, &coin100, valAddressCodec)
|
||||
@ -313,7 +344,7 @@ func TestAuthzAuthorizations(t *testing.T) {
|
||||
[]sdk.ValAddress{},
|
||||
stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_CANCEL_UNBONDING_DELEGATION,
|
||||
&coin100,
|
||||
stakingtypes.NewMsgCancelUnbondingDelegation(accAddressToString(t, delAddr), valAddressToString(t, val1), ctx.HeaderInfo().Height, coin100),
|
||||
stakingtypes.NewMsgCancelUnbondingDelegation(accAddressToString(t, delAddr), valAddressToString(t, val1), sdkCtx.HeaderInfo().Height, coin100),
|
||||
false,
|
||||
true,
|
||||
nil,
|
||||
@ -324,7 +355,7 @@ func TestAuthzAuthorizations(t *testing.T) {
|
||||
[]sdk.ValAddress{},
|
||||
stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_CANCEL_UNBONDING_DELEGATION,
|
||||
&coin100,
|
||||
stakingtypes.NewMsgCancelUnbondingDelegation(accAddressToString(t, delAddr), valAddressToString(t, val1), ctx.HeaderInfo().Height, coin50),
|
||||
stakingtypes.NewMsgCancelUnbondingDelegation(accAddressToString(t, delAddr), valAddressToString(t, val1), sdkCtx.HeaderInfo().Height, coin50),
|
||||
false,
|
||||
false,
|
||||
&stakingtypes.StakeAuthorization{
|
||||
@ -341,7 +372,7 @@ func TestAuthzAuthorizations(t *testing.T) {
|
||||
[]sdk.ValAddress{},
|
||||
stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_CANCEL_UNBONDING_DELEGATION,
|
||||
&coin100,
|
||||
stakingtypes.NewMsgCancelUnbondingDelegation(accAddressToString(t, delAddr), valAddressToString(t, val3), ctx.HeaderInfo().Height, coin50),
|
||||
stakingtypes.NewMsgCancelUnbondingDelegation(accAddressToString(t, delAddr), valAddressToString(t, val3), sdkCtx.HeaderInfo().Height, coin50),
|
||||
true,
|
||||
false,
|
||||
nil,
|
||||
@ -352,7 +383,7 @@ func TestAuthzAuthorizations(t *testing.T) {
|
||||
[]sdk.ValAddress{},
|
||||
stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_CANCEL_UNBONDING_DELEGATION,
|
||||
nil,
|
||||
stakingtypes.NewMsgCancelUnbondingDelegation(accAddressToString(t, delAddr), valAddressToString(t, val2), ctx.HeaderInfo().Height, coin100),
|
||||
stakingtypes.NewMsgCancelUnbondingDelegation(accAddressToString(t, delAddr), valAddressToString(t, val2), sdkCtx.HeaderInfo().Height, coin100),
|
||||
false,
|
||||
false,
|
||||
&stakingtypes.StakeAuthorization{
|
||||
@ -369,7 +400,7 @@ func TestAuthzAuthorizations(t *testing.T) {
|
||||
[]sdk.ValAddress{val1},
|
||||
stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_CANCEL_UNBONDING_DELEGATION,
|
||||
&coin100,
|
||||
stakingtypes.NewMsgCancelUnbondingDelegation(accAddressToString(t, delAddr), valAddressToString(t, val1), ctx.HeaderInfo().Height, coin100),
|
||||
stakingtypes.NewMsgCancelUnbondingDelegation(accAddressToString(t, delAddr), valAddressToString(t, val1), sdkCtx.HeaderInfo().Height, coin100),
|
||||
true,
|
||||
false,
|
||||
nil,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user