feat(auth): support accounts from auth (#21688)
This commit is contained in:
+3
-1
@@ -34,7 +34,8 @@ require (
|
||||
|
||||
require (
|
||||
cosmossdk.io/core/testing v0.0.0-00010101000000-000000000000
|
||||
cosmossdk.io/x/accounts v0.0.0-20240226161501-23359a0b6d91
|
||||
cosmossdk.io/x/accounts v0.0.0-20240913065641-0064ccbce64e
|
||||
cosmossdk.io/x/accounts/defaults/base v0.0.0-00010101000000-000000000000
|
||||
cosmossdk.io/x/accounts/defaults/lockup v0.0.0-20240417181816-5e7aae0db1f5
|
||||
cosmossdk.io/x/accounts/defaults/multisig v0.0.0-00010101000000-000000000000
|
||||
cosmossdk.io/x/authz v0.0.0-00010101000000-000000000000
|
||||
@@ -239,6 +240,7 @@ replace (
|
||||
cosmossdk.io/core/testing => ../core/testing
|
||||
cosmossdk.io/store => ../store
|
||||
cosmossdk.io/x/accounts => ../x/accounts
|
||||
cosmossdk.io/x/accounts/defaults/base => ../x/accounts/defaults/base
|
||||
cosmossdk.io/x/accounts/defaults/lockup => ../x/accounts/defaults/lockup
|
||||
cosmossdk.io/x/accounts/defaults/multisig => ../x/accounts/defaults/multisig
|
||||
cosmossdk.io/x/authz => ../x/authz
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
package keeper_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
gogotypes "github.com/cosmos/gogoproto/types"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
"cosmossdk.io/x/accounts/accountstd"
|
||||
basev1 "cosmossdk.io/x/accounts/defaults/base/v1"
|
||||
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
|
||||
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
)
|
||||
|
||||
var _ accountstd.Interface = mockRetroCompatAccount{}
|
||||
|
||||
type mockRetroCompatAccount struct {
|
||||
retroCompat *authtypes.QueryLegacyAccountResponse
|
||||
address []byte
|
||||
}
|
||||
|
||||
func (m mockRetroCompatAccount) RegisterInitHandler(builder *accountstd.InitBuilder) {
|
||||
accountstd.RegisterInitHandler(builder, func(ctx context.Context, req *gogotypes.Empty) (*gogotypes.Empty, error) {
|
||||
return &gogotypes.Empty{}, nil
|
||||
})
|
||||
}
|
||||
|
||||
func (m mockRetroCompatAccount) RegisterExecuteHandlers(_ *accountstd.ExecuteBuilder) {}
|
||||
|
||||
func (m mockRetroCompatAccount) RegisterQueryHandlers(builder *accountstd.QueryBuilder) {
|
||||
if m.retroCompat == nil {
|
||||
return
|
||||
}
|
||||
accountstd.RegisterQueryHandler(builder, func(ctx context.Context, req *authtypes.QueryLegacyAccount) (*authtypes.QueryLegacyAccountResponse, error) {
|
||||
return m.retroCompat, nil
|
||||
})
|
||||
}
|
||||
|
||||
func TestAuthToAccountsGRPCCompat(t *testing.T) {
|
||||
valid := &mockRetroCompatAccount{
|
||||
retroCompat: &authtypes.QueryLegacyAccountResponse{
|
||||
Account: &codectypes.Any{},
|
||||
Info: &authtypes.BaseAccount{
|
||||
Address: "test",
|
||||
PubKey: nil,
|
||||
AccountNumber: 10,
|
||||
Sequence: 20,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
noInfo := &mockRetroCompatAccount{
|
||||
retroCompat: &authtypes.QueryLegacyAccountResponse{
|
||||
Account: &codectypes.Any{},
|
||||
},
|
||||
}
|
||||
noImplement := &mockRetroCompatAccount{
|
||||
retroCompat: nil,
|
||||
}
|
||||
|
||||
accs := map[string]accountstd.Interface{
|
||||
"valid": valid,
|
||||
"no_info": noInfo,
|
||||
"no_implement": noImplement,
|
||||
}
|
||||
|
||||
f := initFixture(t, accs)
|
||||
|
||||
// init three accounts
|
||||
for n, a := range accs {
|
||||
_, addr, err := f.accountsKeeper.Init(f.ctx, n, []byte("me"), &gogotypes.Empty{}, nil)
|
||||
require.NoError(t, err)
|
||||
a.(*mockRetroCompatAccount).address = addr
|
||||
}
|
||||
|
||||
qs := authkeeper.NewQueryServer(f.authKeeper)
|
||||
|
||||
t.Run("account supports info and account query", func(t *testing.T) {
|
||||
infoResp, err := qs.AccountInfo(f.ctx, &authtypes.QueryAccountInfoRequest{
|
||||
Address: f.mustAddr(valid.address),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, infoResp.Info, valid.retroCompat.Info)
|
||||
|
||||
accountResp, err := qs.Account(f.ctx, &authtypes.QueryAccountRequest{
|
||||
Address: f.mustAddr(noInfo.address),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, accountResp.Account, valid.retroCompat.Account)
|
||||
})
|
||||
|
||||
t.Run("account only supports account query, not info", func(t *testing.T) {
|
||||
_, err := qs.AccountInfo(f.ctx, &authtypes.QueryAccountInfoRequest{
|
||||
Address: f.mustAddr(noInfo.address),
|
||||
})
|
||||
require.Error(t, err)
|
||||
require.Equal(t, status.Code(err), codes.NotFound)
|
||||
|
||||
resp, err := qs.Account(f.ctx, &authtypes.QueryAccountRequest{
|
||||
Address: f.mustAddr(noInfo.address),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, resp.Account, valid.retroCompat.Account)
|
||||
})
|
||||
|
||||
t.Run("account does not support any retro compat", func(t *testing.T) {
|
||||
_, err := qs.AccountInfo(f.ctx, &authtypes.QueryAccountInfoRequest{
|
||||
Address: f.mustAddr(noImplement.address),
|
||||
})
|
||||
require.Error(t, err)
|
||||
require.Equal(t, status.Code(err), codes.NotFound)
|
||||
|
||||
_, err = qs.Account(f.ctx, &authtypes.QueryAccountRequest{
|
||||
Address: f.mustAddr(noImplement.address),
|
||||
})
|
||||
|
||||
require.Error(t, err)
|
||||
require.Equal(t, status.Code(err), codes.NotFound)
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccountsBaseAccountRetroCompat(t *testing.T) {
|
||||
f := initFixture(t, nil)
|
||||
// init a base acc
|
||||
anyPk, err := codectypes.NewAnyWithValue(secp256k1.GenPrivKey().PubKey())
|
||||
require.NoError(t, err)
|
||||
|
||||
// we init two accounts to have account num not be zero.
|
||||
_, _, err = f.accountsKeeper.Init(f.ctx, "base", []byte("me"), &basev1.MsgInit{PubKey: anyPk}, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, addr, err := f.accountsKeeper.Init(f.ctx, "base", []byte("me"), &basev1.MsgInit{PubKey: anyPk}, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
// try to query it via auth
|
||||
qs := authkeeper.NewQueryServer(f.authKeeper)
|
||||
|
||||
r, err := qs.Account(f.ctx, &authtypes.QueryAccountRequest{
|
||||
Address: f.mustAddr(addr),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, r.Account)
|
||||
|
||||
info, err := qs.AccountInfo(f.ctx, &authtypes.QueryAccountInfoRequest{
|
||||
Address: f.mustAddr(addr),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, info.Info)
|
||||
require.Equal(t, info.Info.PubKey, anyPk)
|
||||
require.Equal(t, info.Info.AccountNumber, uint64(1))
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
package keeper_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"gotest.tools/v3/assert"
|
||||
|
||||
"cosmossdk.io/core/appmodule"
|
||||
"cosmossdk.io/log"
|
||||
storetypes "cosmossdk.io/store/types"
|
||||
"cosmossdk.io/x/accounts"
|
||||
"cosmossdk.io/x/accounts/accountstd"
|
||||
baseaccount "cosmossdk.io/x/accounts/defaults/base"
|
||||
accountsv1 "cosmossdk.io/x/accounts/v1"
|
||||
"cosmossdk.io/x/bank"
|
||||
bankkeeper "cosmossdk.io/x/bank/keeper"
|
||||
banktypes "cosmossdk.io/x/bank/types"
|
||||
minttypes "cosmossdk.io/x/mint/types"
|
||||
"cosmossdk.io/x/tx/signing"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
addresscodec "github.com/cosmos/cosmos-sdk/codec/address"
|
||||
codectestutil "github.com/cosmos/cosmos-sdk/codec/testutil"
|
||||
"github.com/cosmos/cosmos-sdk/runtime"
|
||||
"github.com/cosmos/cosmos-sdk/testutil/integration"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
|
||||
authsims "github.com/cosmos/cosmos-sdk/x/auth/simulation"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
)
|
||||
|
||||
type fixture struct {
|
||||
app *integration.App
|
||||
|
||||
cdc codec.Codec
|
||||
ctx sdk.Context
|
||||
|
||||
authKeeper authkeeper.AccountKeeper
|
||||
accountsKeeper accounts.Keeper
|
||||
bankKeeper bankkeeper.Keeper
|
||||
}
|
||||
|
||||
func (f fixture) mustAddr(address []byte) string {
|
||||
s, _ := f.authKeeper.AddressCodec().BytesToString(address)
|
||||
return s
|
||||
}
|
||||
|
||||
func initFixture(t *testing.T, extraAccs map[string]accountstd.Interface) *fixture {
|
||||
t.Helper()
|
||||
keys := storetypes.NewKVStoreKeys(
|
||||
authtypes.StoreKey, banktypes.StoreKey, accounts.StoreKey,
|
||||
)
|
||||
encodingCfg := moduletestutil.MakeTestEncodingConfig(codectestutil.CodecOptions{}, auth.AppModule{}, bank.AppModule{}, accounts.AppModule{})
|
||||
cdc := encodingCfg.Codec
|
||||
|
||||
logger := log.NewTestLogger(t)
|
||||
cms := integration.CreateMultiStore(keys, logger)
|
||||
|
||||
newCtx := sdk.NewContext(cms, true, logger)
|
||||
|
||||
router := baseapp.NewMsgServiceRouter()
|
||||
queryRouter := baseapp.NewGRPCQueryRouter()
|
||||
|
||||
handler := directHandler{}
|
||||
account := baseaccount.NewAccount("base", signing.NewHandlerMap(handler), baseaccount.WithSecp256K1PubKey())
|
||||
|
||||
var accs []accountstd.AccountCreatorFunc
|
||||
for name, acc := range extraAccs {
|
||||
f := accountstd.AddAccount(name, func(_ accountstd.Dependencies) (accountstd.Interface, error) {
|
||||
return acc, nil
|
||||
})
|
||||
accs = append(accs, f)
|
||||
}
|
||||
accountsKeeper, err := accounts.NewKeeper(
|
||||
cdc,
|
||||
runtime.NewEnvironment(runtime.NewKVStoreService(keys[accounts.StoreKey]), log.NewNopLogger(), runtime.EnvWithQueryRouterService(queryRouter), runtime.EnvWithMsgRouterService(router)),
|
||||
addresscodec.NewBech32Codec("cosmos"),
|
||||
cdc.InterfaceRegistry(),
|
||||
append(accs, account)...,
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
accountsv1.RegisterQueryServer(queryRouter, accounts.NewQueryServer(accountsKeeper))
|
||||
|
||||
authority := authtypes.NewModuleAddress("gov")
|
||||
|
||||
authKeeper := authkeeper.NewAccountKeeper(
|
||||
runtime.NewEnvironment(runtime.NewKVStoreService(keys[authtypes.StoreKey]), log.NewNopLogger()),
|
||||
cdc,
|
||||
authtypes.ProtoBaseAccount,
|
||||
accountsKeeper,
|
||||
map[string][]string{minttypes.ModuleName: {authtypes.Minter}},
|
||||
addresscodec.NewBech32Codec(sdk.Bech32MainPrefix),
|
||||
sdk.Bech32MainPrefix,
|
||||
authority.String(),
|
||||
)
|
||||
|
||||
blockedAddresses := map[string]bool{
|
||||
authKeeper.GetAuthority(): false,
|
||||
}
|
||||
bankKeeper := bankkeeper.NewBaseKeeper(
|
||||
runtime.NewEnvironment(runtime.NewKVStoreService(keys[banktypes.StoreKey]), log.NewNopLogger()),
|
||||
cdc,
|
||||
authKeeper,
|
||||
blockedAddresses,
|
||||
authority.String(),
|
||||
)
|
||||
|
||||
params := banktypes.DefaultParams()
|
||||
assert.NilError(t, bankKeeper.SetParams(newCtx, params))
|
||||
|
||||
accountsModule := accounts.NewAppModule(cdc, accountsKeeper)
|
||||
authModule := auth.NewAppModule(cdc, authKeeper, accountsKeeper, authsims.RandomGenesisAccounts, nil)
|
||||
bankModule := bank.NewAppModule(cdc, bankKeeper, authKeeper)
|
||||
|
||||
integrationApp := integration.NewIntegrationApp(newCtx, logger, keys, cdc,
|
||||
encodingCfg.InterfaceRegistry.SigningContext().AddressCodec(),
|
||||
encodingCfg.InterfaceRegistry.SigningContext().ValidatorAddressCodec(),
|
||||
map[string]appmodule.AppModule{
|
||||
accounts.ModuleName: accountsModule,
|
||||
authtypes.ModuleName: authModule,
|
||||
banktypes.ModuleName: bankModule,
|
||||
}, router, queryRouter)
|
||||
|
||||
authtypes.RegisterInterfaces(cdc.InterfaceRegistry())
|
||||
banktypes.RegisterInterfaces(cdc.InterfaceRegistry())
|
||||
|
||||
authtypes.RegisterMsgServer(integrationApp.MsgServiceRouter(), authkeeper.NewMsgServerImpl(authKeeper))
|
||||
authtypes.RegisterQueryServer(integrationApp.QueryHelper(), authkeeper.NewQueryServer(authKeeper))
|
||||
|
||||
banktypes.RegisterMsgServer(router, bankkeeper.NewMsgServerImpl(bankKeeper))
|
||||
|
||||
return &fixture{
|
||||
app: integrationApp,
|
||||
cdc: cdc,
|
||||
ctx: newCtx,
|
||||
accountsKeeper: accountsKeeper,
|
||||
authKeeper: authKeeper,
|
||||
bankKeeper: bankKeeper,
|
||||
}
|
||||
}
|
||||
@@ -9,46 +9,18 @@ import (
|
||||
"gotest.tools/v3/assert"
|
||||
|
||||
signingv1beta1 "cosmossdk.io/api/cosmos/tx/signing/v1beta1"
|
||||
"cosmossdk.io/core/appmodule"
|
||||
"cosmossdk.io/log"
|
||||
sdkmath "cosmossdk.io/math"
|
||||
storetypes "cosmossdk.io/store/types"
|
||||
"cosmossdk.io/x/accounts"
|
||||
baseaccount "cosmossdk.io/x/accounts/defaults/base"
|
||||
"cosmossdk.io/x/bank"
|
||||
bankkeeper "cosmossdk.io/x/bank/keeper"
|
||||
"cosmossdk.io/x/bank/testutil"
|
||||
banktypes "cosmossdk.io/x/bank/types"
|
||||
minttypes "cosmossdk.io/x/mint/types"
|
||||
"cosmossdk.io/x/tx/signing"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
addresscodec "github.com/cosmos/cosmos-sdk/codec/address"
|
||||
codectestutil "github.com/cosmos/cosmos-sdk/codec/testutil"
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
"github.com/cosmos/cosmos-sdk/runtime"
|
||||
"github.com/cosmos/cosmos-sdk/testutil/integration"
|
||||
simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
|
||||
authsims "github.com/cosmos/cosmos-sdk/x/auth/simulation"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
)
|
||||
|
||||
type fixture struct {
|
||||
app *integration.App
|
||||
|
||||
cdc codec.Codec
|
||||
ctx sdk.Context
|
||||
|
||||
authKeeper authkeeper.AccountKeeper
|
||||
accountsKeeper accounts.Keeper
|
||||
bankKeeper bankkeeper.Keeper
|
||||
}
|
||||
|
||||
var _ signing.SignModeHandler = directHandler{}
|
||||
|
||||
type directHandler struct{}
|
||||
@@ -61,94 +33,9 @@ func (s directHandler) GetSignBytes(_ context.Context, _ signing.SignerData, _ s
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func initFixture(t *testing.T) *fixture {
|
||||
t.Helper()
|
||||
keys := storetypes.NewKVStoreKeys(
|
||||
authtypes.StoreKey, banktypes.StoreKey, accounts.StoreKey,
|
||||
)
|
||||
encodingCfg := moduletestutil.MakeTestEncodingConfig(codectestutil.CodecOptions{}, auth.AppModule{}, bank.AppModule{}, accounts.AppModule{})
|
||||
cdc := encodingCfg.Codec
|
||||
|
||||
logger := log.NewTestLogger(t)
|
||||
cms := integration.CreateMultiStore(keys, logger)
|
||||
|
||||
newCtx := sdk.NewContext(cms, true, logger)
|
||||
|
||||
router := baseapp.NewMsgServiceRouter()
|
||||
queryRouter := baseapp.NewGRPCQueryRouter()
|
||||
|
||||
handler := directHandler{}
|
||||
account := baseaccount.NewAccount("base", signing.NewHandlerMap(handler), baseaccount.WithSecp256K1PubKey())
|
||||
accountsKeeper, err := accounts.NewKeeper(
|
||||
cdc,
|
||||
runtime.NewEnvironment(runtime.NewKVStoreService(keys[accounts.StoreKey]), log.NewNopLogger(), runtime.EnvWithQueryRouterService(queryRouter), runtime.EnvWithMsgRouterService(router)),
|
||||
addresscodec.NewBech32Codec("cosmos"),
|
||||
cdc.InterfaceRegistry(),
|
||||
account,
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
authority := authtypes.NewModuleAddress("gov")
|
||||
|
||||
authKeeper := authkeeper.NewAccountKeeper(
|
||||
runtime.NewEnvironment(runtime.NewKVStoreService(keys[authtypes.StoreKey]), log.NewNopLogger()),
|
||||
cdc,
|
||||
authtypes.ProtoBaseAccount,
|
||||
accountsKeeper,
|
||||
map[string][]string{minttypes.ModuleName: {authtypes.Minter}},
|
||||
addresscodec.NewBech32Codec(sdk.Bech32MainPrefix),
|
||||
sdk.Bech32MainPrefix,
|
||||
authority.String(),
|
||||
)
|
||||
|
||||
blockedAddresses := map[string]bool{
|
||||
authKeeper.GetAuthority(): false,
|
||||
}
|
||||
bankKeeper := bankkeeper.NewBaseKeeper(
|
||||
runtime.NewEnvironment(runtime.NewKVStoreService(keys[banktypes.StoreKey]), log.NewNopLogger()),
|
||||
cdc,
|
||||
authKeeper,
|
||||
blockedAddresses,
|
||||
authority.String(),
|
||||
)
|
||||
|
||||
params := banktypes.DefaultParams()
|
||||
assert.NilError(t, bankKeeper.SetParams(newCtx, params))
|
||||
|
||||
accountsModule := accounts.NewAppModule(cdc, accountsKeeper)
|
||||
authModule := auth.NewAppModule(cdc, authKeeper, accountsKeeper, authsims.RandomGenesisAccounts, nil)
|
||||
bankModule := bank.NewAppModule(cdc, bankKeeper, authKeeper)
|
||||
|
||||
integrationApp := integration.NewIntegrationApp(newCtx, logger, keys, cdc,
|
||||
encodingCfg.InterfaceRegistry.SigningContext().AddressCodec(),
|
||||
encodingCfg.InterfaceRegistry.SigningContext().ValidatorAddressCodec(),
|
||||
map[string]appmodule.AppModule{
|
||||
accounts.ModuleName: accountsModule,
|
||||
authtypes.ModuleName: authModule,
|
||||
banktypes.ModuleName: bankModule,
|
||||
}, router, queryRouter)
|
||||
|
||||
authtypes.RegisterInterfaces(cdc.InterfaceRegistry())
|
||||
banktypes.RegisterInterfaces(cdc.InterfaceRegistry())
|
||||
|
||||
authtypes.RegisterMsgServer(integrationApp.MsgServiceRouter(), authkeeper.NewMsgServerImpl(authKeeper))
|
||||
authtypes.RegisterQueryServer(integrationApp.QueryHelper(), authkeeper.NewQueryServer(authKeeper))
|
||||
|
||||
banktypes.RegisterMsgServer(router, bankkeeper.NewMsgServerImpl(bankKeeper))
|
||||
|
||||
return &fixture{
|
||||
app: integrationApp,
|
||||
cdc: cdc,
|
||||
ctx: newCtx,
|
||||
accountsKeeper: accountsKeeper,
|
||||
authKeeper: authKeeper,
|
||||
bankKeeper: bankKeeper,
|
||||
}
|
||||
}
|
||||
|
||||
func TestAsyncExec(t *testing.T) {
|
||||
t.Parallel()
|
||||
f := initFixture(t)
|
||||
f := initFixture(t, nil)
|
||||
|
||||
addrs := simtestutil.CreateIncrementalAccounts(2)
|
||||
coins := sdk.NewCoins(sdk.NewCoin("stake", sdkmath.NewInt(10)))
|
||||
|
||||
Reference in New Issue
Block a user