From ceffc5e01cb5a68491dc2fadccec1cf3e7998cb5 Mon Sep 17 00:00:00 2001 From: atheeshp <59333759+atheeshp@users.noreply.github.com> Date: Fri, 16 Sep 2022 12:52:09 +0530 Subject: [PATCH] feat: x/auth determinism tests for `Account` query (#13255) * WIP: rapid tests * remove commented code * review changes * review changes * review changes * review changes * review changes * review changes * review changes * review changes * review changes * review changes * `go mod tidy` --- simapp/go.mod | 1 + simapp/go.sum | 1 + tests/go.mod | 1 + tests/go.sum | 1 + testutil/testdata/tx.go | 9 +++ x/auth/keeper/deterministic_test.go | 120 ++++++++++++++++++++++++++++ 6 files changed, 133 insertions(+) create mode 100644 x/auth/keeper/deterministic_test.go diff --git a/simapp/go.mod b/simapp/go.mod index 4f886ebcaf63..8468a82199d4 100644 --- a/simapp/go.mod +++ b/simapp/go.mod @@ -146,6 +146,7 @@ require ( gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect nhooyr.io/websocket v1.8.6 // indirect + pgregory.net/rapid v0.5.2 // indirect sigs.k8s.io/yaml v1.3.0 // indirect ) diff --git a/simapp/go.sum b/simapp/go.sum index 428774f2deac..c6bbc67733be 100644 --- a/simapp/go.sum +++ b/simapp/go.sum @@ -1381,6 +1381,7 @@ nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k= nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= pgregory.net/rapid v0.4.7/go.mod h1:UYpPVyjFHzYBGHIxLFoupi8vwk6rXNzRY9OMvVxFIOU= pgregory.net/rapid v0.5.2 h1:zC+jmuzcz5yJvG/igG06aLx8kcGmZY435NcuyhblKjY= +pgregory.net/rapid v0.5.2/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/tests/go.mod b/tests/go.mod index c54ff374b909..aa044c5887fa 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -148,6 +148,7 @@ require ( gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect nhooyr.io/websocket v1.8.6 // indirect + pgregory.net/rapid v0.5.2 // indirect sigs.k8s.io/yaml v1.3.0 // indirect ) diff --git a/tests/go.sum b/tests/go.sum index 1db1515111cc..beac75ee56c8 100644 --- a/tests/go.sum +++ b/tests/go.sum @@ -1383,6 +1383,7 @@ nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k= nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= pgregory.net/rapid v0.4.7/go.mod h1:UYpPVyjFHzYBGHIxLFoupi8vwk6rXNzRY9OMvVxFIOU= pgregory.net/rapid v0.5.2 h1:zC+jmuzcz5yJvG/igG06aLx8kcGmZY435NcuyhblKjY= +pgregory.net/rapid v0.5.2/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/testutil/testdata/tx.go b/testutil/testdata/tx.go index d16dd06d0ebd..72f728cf59c0 100644 --- a/testutil/testdata/tx.go +++ b/testutil/testdata/tx.go @@ -4,6 +4,7 @@ import ( "encoding/json" "github.com/stretchr/testify/require" + "pgregory.net/rapid" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256r1" @@ -12,6 +13,14 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) +// AddressGenerator creates and returns a random address generator using rapid. +func AddressGenerator(t *rapid.T) *rapid.Generator[sdk.AccAddress] { + return rapid.Custom(func(t *rapid.T) sdk.AccAddress { + pkBz := rapid.SliceOfN(rapid.Byte(), 20, 20).Draw(t, "hex") + return sdk.AccAddress(pkBz) + }) +} + // KeyTestPubAddr generates a new secp256k1 keypair. func KeyTestPubAddr() (cryptotypes.PrivKey, cryptotypes.PubKey, sdk.AccAddress) { key := secp256k1.GenPrivKey() diff --git a/x/auth/keeper/deterministic_test.go b/x/auth/keeper/deterministic_test.go new file mode 100644 index 000000000000..471b0956b6d8 --- /dev/null +++ b/x/auth/keeper/deterministic_test.go @@ -0,0 +1,120 @@ +package keeper_test + +import ( + "encoding/hex" + "testing" + + "github.com/cosmos/cosmos-sdk/baseapp" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + "github.com/cosmos/cosmos-sdk/testutil" + sdk "github.com/cosmos/cosmos-sdk/types" + moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/auth/keeper" + "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/stretchr/testify/suite" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + "pgregory.net/rapid" +) + +type DeterministicTestSuite struct { + suite.Suite + + ctx sdk.Context + queryClient types.QueryClient + accountKeeper keeper.AccountKeeper + encCfg moduletestutil.TestEncodingConfig +} + +func TestDeterministicTestSuite(t *testing.T) { + suite.Run(t, new(DeterministicTestSuite)) +} + +func (suite *DeterministicTestSuite) SetupTest() { + suite.encCfg = moduletestutil.MakeTestEncodingConfig(auth.AppModuleBasic{}) + + key := sdk.NewKVStoreKey(types.StoreKey) + testCtx := testutil.DefaultContextWithDB(suite.T(), key, sdk.NewTransientStoreKey("transient_test")) + suite.ctx = testCtx.Ctx.WithBlockHeader(tmproto.Header{}) + + maccPerms := map[string][]string{ + "fee_collector": nil, + "mint": {"minter"}, + "bonded_tokens_pool": {"burner", "staking"}, + "not_bonded_tokens_pool": {"burner", "staking"}, + multiPerm: {"burner", "minter", "staking"}, + randomPerm: {"random"}, + } + + suite.accountKeeper = keeper.NewAccountKeeper( + suite.encCfg.Codec, + key, + types.ProtoBaseAccount, + maccPerms, + "cosmos", + types.NewModuleAddress("gov").String(), + ) + + queryHelper := baseapp.NewQueryServerTestHelper(suite.ctx, suite.encCfg.InterfaceRegistry) + types.RegisterQueryServer(queryHelper, suite.accountKeeper) + suite.queryClient = types.NewQueryClient(queryHelper) +} + +func (suite *DeterministicTestSuite) runAccountIterations(addr sdk.AccAddress, prevRes types.AccountI) { + for i := 0; i < 1000; i++ { + acc, err := suite.queryClient.Account(suite.ctx, &types.QueryAccountRequest{Address: addr.String()}) + suite.Require().NoError(err) + suite.Require().NotNil(acc) + + var account types.AccountI + err = suite.encCfg.InterfaceRegistry.UnpackAny(acc.Account, &account) + suite.Require().NoError(err) + suite.Require().Equal(account.GetAddress(), addr) + + if prevRes != nil { + any, err := codectypes.NewAnyWithValue(prevRes) + suite.Require().NoError(err) + + suite.Require().Equal(acc.Account, any) + suite.Require().Equal(account, prevRes) + } + + prevRes = account + } +} + +func (suite *DeterministicTestSuite) TestGRPCQueryAccount() { + rapid.Check(suite.T(), func(t *rapid.T) { + pub := pubkeyGenerator(t).Draw(t, "pubkey") + addr := sdk.AccAddress(pub.Address()) + accNum := rapid.Uint64().Draw(t, "account-number") + seq := rapid.Uint64().Draw(t, "sequence") + + acc1 := types.NewBaseAccount(addr, &pub, accNum, seq) + suite.accountKeeper.SetAccount(suite.ctx, acc1) + + suite.runAccountIterations(addr, acc1) + }) + + // Regression test + addr1 := sdk.MustAccAddressFromBech32("cosmos139f7kncmglres2nf3h4hc4tade85ekfr8sulz5") + pub, err := hex.DecodeString("02950e1cdfcb133d6024109fd489f734eeb4502418e538c28481f22bce276f248c") + suite.Require().NoError(err) + + accNum := uint64(10087) + seq := uint64(0) + + acc1 := types.NewBaseAccount(addr1, &secp256k1.PubKey{Key: pub}, accNum, seq) + + suite.accountKeeper.SetAccount(suite.ctx, acc1) + suite.runAccountIterations(addr1, acc1) +} + +// pubkeyGenerator creates and returns a random pubkey generator using rapid. +func pubkeyGenerator(t *rapid.T) *rapid.Generator[secp256k1.PubKey] { + return rapid.Custom(func(t *rapid.T) secp256k1.PubKey { + pkBz := rapid.SliceOfN(rapid.Byte(), 33, 33).Draw(t, "hex") + return secp256k1.PubKey{Key: pkBz} + }) +}