From 0abc3ac59bd0781cb679ed77295d7f7ac173aa32 Mon Sep 17 00:00:00 2001 From: yys Date: Mon, 11 Apr 2022 17:53:21 +0900 Subject: [PATCH] increase code coverage (#664) * increase coverage oracle module * add oracle fuzz test * exclude proto files from codecov * add sort for fuzz test * Chore/coverage (#673) * update wasm querier test * update legacy querier test Co-authored-by: Geoff Lee --- .codecov.yml | 10 ++ README.md | 2 +- go.mod | 1 + go.sum | 3 +- x/oracle/abci.go | 2 +- x/oracle/genesis_test.go | 102 +++++++++++++++ x/oracle/keeper/legacy_querier_test.go | 82 ++++++++---- x/oracle/keeper/msg_server_test.go | 170 +++++++++++++++++++++++++ x/oracle/keeper/querier_test.go | 40 ++++++ x/oracle/tally.go | 4 +- x/oracle/tally_fuzz_test.go | 139 ++++++++++++++++++++ x/oracle/types/ballot_test.go | 91 +++++++++---- x/oracle/types/denom_test.go | 34 +++++ x/oracle/types/genesis.go | 16 +-- x/oracle/types/genesis_test.go | 20 ++- x/oracle/types/hash_test.go | 12 +- x/oracle/types/msgs_test.go | 42 ++++-- x/oracle/types/params_test.go | 94 +++++++++++--- x/oracle/types/vote_test.go | 13 +- x/wasm/keeper/legacy_querier_test.go | 14 ++ x/wasm/keeper/querier_test.go | 56 ++++++++ 21 files changed, 837 insertions(+), 110 deletions(-) create mode 100644 x/oracle/keeper/msg_server_test.go create mode 100644 x/oracle/tally_fuzz_test.go create mode 100644 x/oracle/types/denom_test.go diff --git a/.codecov.yml b/.codecov.yml index 7bbc9f1b..0d6b82c3 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -20,5 +20,15 @@ ignore: - "contrib/" - "docs/" - "networks/" + - "proto/" + - "scripts/" + - "thrid_party/" + - "docker/" + - "client/" + - "custom/" - "**/cli" - "**/rest" + - "**/*.pb.go" + - "**/*.pb.gw.go" + - "**/test_utils.go" + - "**/module.go" diff --git a/README.md b/README.md index d49bc0ce..98f7d840 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Full-node software implementing the Terra protocol

- + diff --git a/go.mod b/go.mod index 5272182b..1bc12c31 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/cosmos/ibc-go v1.1.5 github.com/gogo/protobuf v1.3.3 github.com/golang/protobuf v1.5.2 + github.com/google/gofuzz v1.2.0 github.com/gorilla/mux v1.8.0 github.com/grpc-ecosystem/grpc-gateway v1.16.0 github.com/pkg/errors v0.9.1 diff --git a/go.sum b/go.sum index a80ac3af..4bf0dc1e 100644 --- a/go.sum +++ b/go.sum @@ -358,8 +358,9 @@ github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa h1:Q75Upo5UN4JbPFURXZ8nLKYUvF85dyFRop/vQ0Rv+64= github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= diff --git a/x/oracle/abci.go b/x/oracle/abci.go index 07f2fc1b..37ae9a52 100644 --- a/x/oracle/abci.go +++ b/x/oracle/abci.go @@ -57,7 +57,7 @@ func EndBlocker(ctx sdk.Context, k keeper.Keeper) { // NOTE: **Make abstain votes to have zero vote power** voteMap := k.OrganizeBallotByDenom(ctx, validatorClaimMap) - if referenceTerra := pickReferenceTerra(ctx, k, voteTargets, voteMap); referenceTerra != "" { + if referenceTerra := PickReferenceTerra(ctx, k, voteTargets, voteMap); referenceTerra != "" { // make voteMap of Reference Terra to calculate cross exchange rates ballotRT := voteMap[referenceTerra] voteMapRT := ballotRT.ToMap() diff --git a/x/oracle/genesis_test.go b/x/oracle/genesis_test.go index 4b08d4b5..1c2b2720 100644 --- a/x/oracle/genesis_test.go +++ b/x/oracle/genesis_test.go @@ -21,6 +21,7 @@ func TestExportInitGenesis(t *testing.T) { input.OracleKeeper.SetAggregateExchangeRateVote(input.Ctx, keeper.ValAddrs[0], types.NewAggregateExchangeRateVote(types.ExchangeRateTuples{{Denom: "foo", ExchangeRate: sdk.NewDec(123)}}, keeper.ValAddrs[0])) input.OracleKeeper.SetTobinTax(input.Ctx, "denom", sdk.NewDecWithPrec(123, 3)) input.OracleKeeper.SetTobinTax(input.Ctx, "denom2", sdk.NewDecWithPrec(123, 3)) + input.OracleKeeper.SetMissCounter(input.Ctx, keeper.ValAddrs[0], 10) genesis := oracle.ExportGenesis(input.Ctx, input.OracleKeeper) newInput := keeper.CreateTestInput(t) @@ -29,3 +30,104 @@ func TestExportInitGenesis(t *testing.T) { require.Equal(t, genesis, newGenesis) } + +func TestInitGenesis(t *testing.T) { + input, _ := setup(t) + genesis := types.DefaultGenesisState() + require.NotPanics(t, func() { + oracle.InitGenesis(input.Ctx, input.OracleKeeper, genesis) + }) + + genesis.FeederDelegations = []types.FeederDelegation{{ + FeederAddress: keeper.Addrs[0].String(), + ValidatorAddress: "invalid", + }} + + require.Panics(t, func() { + oracle.InitGenesis(input.Ctx, input.OracleKeeper, genesis) + }) + + genesis.FeederDelegations = []types.FeederDelegation{{ + FeederAddress: "invalid", + ValidatorAddress: keeper.ValAddrs[0].String(), + }} + + require.Panics(t, func() { + oracle.InitGenesis(input.Ctx, input.OracleKeeper, genesis) + }) + + genesis.FeederDelegations = []types.FeederDelegation{{ + FeederAddress: keeper.Addrs[0].String(), + ValidatorAddress: keeper.ValAddrs[0].String(), + }} + + genesis.MissCounters = []types.MissCounter{ + { + ValidatorAddress: "invalid", + MissCounter: 10, + }, + } + + require.Panics(t, func() { + oracle.InitGenesis(input.Ctx, input.OracleKeeper, genesis) + }) + + genesis.MissCounters = []types.MissCounter{ + { + ValidatorAddress: keeper.ValAddrs[0].String(), + MissCounter: 10, + }, + } + + genesis.AggregateExchangeRatePrevotes = []types.AggregateExchangeRatePrevote{ + { + Hash: "hash", + Voter: "invalid", + SubmitBlock: 100, + }, + } + + require.Panics(t, func() { + oracle.InitGenesis(input.Ctx, input.OracleKeeper, genesis) + }) + + genesis.AggregateExchangeRatePrevotes = []types.AggregateExchangeRatePrevote{ + { + Hash: "hash", + Voter: keeper.ValAddrs[0].String(), + SubmitBlock: 100, + }, + } + + genesis.AggregateExchangeRateVotes = []types.AggregateExchangeRateVote{ + { + ExchangeRateTuples: []types.ExchangeRateTuple{ + { + Denom: "ukrw", + ExchangeRate: sdk.NewDec(10), + }, + }, + Voter: "invalid", + }, + } + + require.Panics(t, func() { + oracle.InitGenesis(input.Ctx, input.OracleKeeper, genesis) + }) + + genesis.AggregateExchangeRateVotes = []types.AggregateExchangeRateVote{ + { + ExchangeRateTuples: []types.ExchangeRateTuple{ + { + Denom: "ukrw", + ExchangeRate: sdk.NewDec(10), + }, + }, + Voter: keeper.ValAddrs[0].String(), + }, + } + + require.NotPanics(t, func() { + oracle.InitGenesis(input.Ctx, input.OracleKeeper, genesis) + }) +} diff --git a/x/oracle/keeper/legacy_querier_test.go b/x/oracle/keeper/legacy_querier_test.go index 7ee1ea84..b0e1902a 100644 --- a/x/oracle/keeper/legacy_querier_test.go +++ b/x/oracle/keeper/legacy_querier_test.go @@ -28,6 +28,20 @@ func TestLegacyNewLegacyQuerier(t *testing.T) { require.NoError(t, err) } +func TestLegacyFilter(t *testing.T) { + input := CreateTestInput(t) + + querier := NewLegacyQuerier(input.OracleKeeper, input.Cdc) + + query := abci.RequestQuery{ + Path: "", + Data: []byte{}, + } + + _, err := querier(input.Ctx, []string{"invalid"}, query) + require.Error(t, err) +} + func TestLegacyQueryParams(t *testing.T) { input := CreateTestInput(t) querier := NewLegacyQuerier(input.OracleKeeper, input.Cdc) @@ -46,6 +60,31 @@ func TestLegacyQueryParams(t *testing.T) { require.Equal(t, input.OracleKeeper.GetParams(input.Ctx), params) } +func TestLegacyQueryMissCounter(t *testing.T) { + input := CreateTestInput(t) + querier := NewLegacyQuerier(input.OracleKeeper, input.Cdc) + + queryParams := types.NewQueryMissCounterParams(ValAddrs[0]) + bz, err := input.Cdc.MarshalJSON(queryParams) + require.NoError(t, err) + + _, err = querier(input.Ctx, []string{types.QueryMissCounter}, abci.RequestQuery{}) + require.Error(t, err) + + req := abci.RequestQuery{ + Path: "", + Data: bz, + } + + res, err := querier(input.Ctx, []string{types.QueryMissCounter}, req) + require.NoError(t, err) + + var missCounter uint64 + err = input.Cdc.UnmarshalJSON(res, &missCounter) + require.NoError(t, err) + require.Equal(t, input.OracleKeeper.GetMissCounter(input.Ctx, ValAddrs[0]), missCounter) +} + func TestLegacyQueryExchangeRate(t *testing.T) { input := CreateTestInput(t) querier := NewLegacyQuerier(input.OracleKeeper, input.Cdc) @@ -58,6 +97,9 @@ func TestLegacyQueryExchangeRate(t *testing.T) { bz, err := input.Cdc.MarshalJSON(queryParams) require.NoError(t, err) + _, err = querier(input.Ctx, []string{types.QueryExchangeRate}, abci.RequestQuery{}) + require.Error(t, err) + req := abci.RequestQuery{ Path: "", Data: bz, @@ -126,6 +168,9 @@ func TestLegacyQueryFeederDelegation(t *testing.T) { bz, err := input.Cdc.MarshalJSON(queryParams) require.NoError(t, err) + _, err = querier(input.Ctx, []string{types.QueryFeederDelegation}, abci.RequestQuery{}) + require.Error(t, err) + req := abci.RequestQuery{ Path: "", Data: bz, @@ -155,6 +200,9 @@ func TestLegacyQueryAggregatePrevote(t *testing.T) { bz, err := input.Cdc.MarshalJSON(queryParams) require.NoError(t, err) + _, err = querier(input.Ctx, []string{types.QueryAggregatePrevote}, abci.RequestQuery{}) + require.Error(t, err) + req := abci.RequestQuery{ Path: "", Data: bz, @@ -204,12 +252,7 @@ func TestLegacyQueryAggregatePrevotes(t *testing.T) { return bytes.Compare(addr1, addr2) == -1 }) - req := abci.RequestQuery{ - Path: "", - Data: nil, - } - - res, err := querier(input.Ctx, []string{types.QueryAggregatePrevotes}, req) + res, err := querier(input.Ctx, []string{types.QueryAggregatePrevotes}, abci.RequestQuery{}) require.NoError(t, err) var prevotes []types.AggregateExchangeRatePrevote @@ -234,6 +277,9 @@ func TestLegacyQueryAggregateVote(t *testing.T) { bz, err := input.Cdc.MarshalJSON(queryParams) require.NoError(t, err) + _, err = querier(input.Ctx, []string{types.QueryAggregateVote}, abci.RequestQuery{}) + require.Error(t, err) + req := abci.RequestQuery{ Path: "", Data: bz, @@ -283,12 +329,7 @@ func TestLegacyQueryAggregateVotes(t *testing.T) { return bytes.Compare(addr1, addr2) == -1 }) - req := abci.RequestQuery{ - Path: "", - Data: nil, - } - - res, err := querier(input.Ctx, []string{types.QueryAggregateVotes}, req) + res, err := querier(input.Ctx, []string{types.QueryAggregateVotes}, abci.RequestQuery{}) require.NoError(t, err) var votes []types.AggregateExchangeRateVote @@ -309,12 +350,7 @@ func TestLegacyQueryVoteTargets(t *testing.T) { input.OracleKeeper.SetTobinTax(input.Ctx, target, sdk.OneDec()) } - req := abci.RequestQuery{ - Path: "", - Data: nil, - } - - res, err := querier(input.Ctx, []string{types.QueryVoteTargets}, req) + res, err := querier(input.Ctx, []string{types.QueryVoteTargets}, abci.RequestQuery{}) require.NoError(t, err) var voteTargetsRes []string @@ -341,12 +377,7 @@ func TestLegacyQueryTobinTaxes(t *testing.T) { input.OracleKeeper.SetTobinTax(input.Ctx, item.Name, item.TobinTax) } - req := abci.RequestQuery{ - Path: "", - Data: nil, - } - - res, err := querier(input.Ctx, []string{types.QueryTobinTaxes}, req) + res, err := querier(input.Ctx, []string{types.QueryTobinTaxes}, abci.RequestQuery{}) require.NoError(t, err) var tobinTaxesRes types.DenomList @@ -366,6 +397,9 @@ func TestLegacyQueryTobinTax(t *testing.T) { bz, err := input.Cdc.MarshalJSON(queryParams) require.NoError(t, err) + _, err = querier(input.Ctx, []string{types.QueryTobinTax}, abci.RequestQuery{}) + require.Error(t, err) + req := abci.RequestQuery{ Path: "", Data: bz, diff --git a/x/oracle/keeper/msg_server_test.go b/x/oracle/keeper/msg_server_test.go new file mode 100644 index 00000000..28ed4534 --- /dev/null +++ b/x/oracle/keeper/msg_server_test.go @@ -0,0 +1,170 @@ +package keeper + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" + + core "github.com/terra-money/core/types" + "github.com/terra-money/core/x/oracle/types" + + "github.com/cosmos/cosmos-sdk/x/staking" +) + +func TestMsgServer_FeederDelegation(t *testing.T) { + input, msgServer := setup(t) + + salt := "1" + hash := types.GetAggregateVoteHash(salt, randomExchangeRate.String()+core.MicroSDRDenom, ValAddrs[0]) + + // Case 1: empty message + delegateFeedConsentMsg := types.MsgDelegateFeedConsent{} + _, err := msgServer.DelegateFeedConsent(sdk.WrapSDKContext(input.Ctx), &delegateFeedConsentMsg) + require.Error(t, err) + + // Case 2: Normal Prevote - without delegation + prevoteMsg := types.NewMsgAggregateExchangeRatePrevote(hash, Addrs[0], ValAddrs[0]) + _, err = msgServer.AggregateExchangeRatePrevote(sdk.WrapSDKContext(input.Ctx), prevoteMsg) + require.NoError(t, err) + + // Case 2.1: Normal Prevote - with delegation fails + prevoteMsg = types.NewMsgAggregateExchangeRatePrevote(hash, Addrs[1], ValAddrs[0]) + _, err = msgServer.AggregateExchangeRatePrevote(sdk.WrapSDKContext(input.Ctx), prevoteMsg) + require.Error(t, err) + + // Case 2.2: Normal Vote - without delegation + voteMsg := types.NewMsgAggregateExchangeRateVote(salt, randomExchangeRate.String()+core.MicroSDRDenom, Addrs[0], ValAddrs[0]) + _, err = msgServer.AggregateExchangeRateVote(sdk.WrapSDKContext(input.Ctx.WithBlockHeight(1)), voteMsg) + require.NoError(t, err) + + // Case 2.3: Normal Vote - with delegation fails + voteMsg = types.NewMsgAggregateExchangeRateVote(salt, randomExchangeRate.String()+core.MicroSDRDenom, Addrs[1], ValAddrs[0]) + _, err = msgServer.AggregateExchangeRateVote(sdk.WrapSDKContext(input.Ctx.WithBlockHeight(1)), voteMsg) + require.Error(t, err) + + // Case 3: Normal MsgDelegateFeedConsent succeeds + msg := types.NewMsgDelegateFeedConsent(ValAddrs[0], Addrs[1]) + _, err = msgServer.DelegateFeedConsent(sdk.WrapSDKContext(input.Ctx), msg) + require.NoError(t, err) + + // Case 4.1: Normal Prevote - without delegation fails + prevoteMsg = types.NewMsgAggregateExchangeRatePrevote(hash, Addrs[2], ValAddrs[0]) + _, err = msgServer.AggregateExchangeRatePrevote(sdk.WrapSDKContext(input.Ctx), prevoteMsg) + require.Error(t, err) + + // Case 4.2: Normal Prevote - with delegation succeeds + prevoteMsg = types.NewMsgAggregateExchangeRatePrevote(hash, Addrs[1], ValAddrs[0]) + _, err = msgServer.AggregateExchangeRatePrevote(sdk.WrapSDKContext(input.Ctx), prevoteMsg) + require.NoError(t, err) + + // Case 4.3: Normal Vote - without delegation fails + voteMsg = types.NewMsgAggregateExchangeRateVote(salt, randomExchangeRate.String()+core.MicroSDRDenom, Addrs[2], ValAddrs[0]) + _, err = msgServer.AggregateExchangeRateVote(sdk.WrapSDKContext(input.Ctx.WithBlockHeight(1)), voteMsg) + require.Error(t, err) + + // Case 4.4: Normal Vote - with delegation succeeds + voteMsg = types.NewMsgAggregateExchangeRateVote(salt, randomExchangeRate.String()+core.MicroSDRDenom, Addrs[1], ValAddrs[0]) + _, err = msgServer.AggregateExchangeRateVote(sdk.WrapSDKContext(input.Ctx.WithBlockHeight(1)), voteMsg) + require.NoError(t, err) +} + +func TestMsgServer_AggregatePrevoteVote(t *testing.T) { + input, msgServer := setup(t) + + salt := "1" + exchangeRatesStr := fmt.Sprintf("1000.23%s,0.29%s,0.27%s", core.MicroKRWDenom, core.MicroUSDDenom, core.MicroSDRDenom) + otherExchangeRateStr := fmt.Sprintf("1000.12%s,0.29%s,0.27%s", core.MicroKRWDenom, core.MicroUSDDenom, core.MicroUSDDenom) + unintendedExchageRateStr := fmt.Sprintf("1000.23%s,0.29%s,0.27%s", core.MicroKRWDenom, core.MicroUSDDenom, core.MicroCNYDenom) + invalidExchangeRateStr := fmt.Sprintf("1000.23%s,0.29%s,0.27", core.MicroKRWDenom, core.MicroUSDDenom) + + hash := types.GetAggregateVoteHash(salt, exchangeRatesStr, ValAddrs[0]) + + aggregateExchangeRatePrevoteMsg := types.NewMsgAggregateExchangeRatePrevote(hash, Addrs[0], ValAddrs[0]) + _, err := msgServer.AggregateExchangeRatePrevote(sdk.WrapSDKContext(input.Ctx), aggregateExchangeRatePrevoteMsg) + require.NoError(t, err) + + // Unauthorized feeder + aggregateExchangeRatePrevoteMsg = types.NewMsgAggregateExchangeRatePrevote(hash, Addrs[1], ValAddrs[0]) + _, err = msgServer.AggregateExchangeRatePrevote(sdk.WrapSDKContext(input.Ctx), aggregateExchangeRatePrevoteMsg) + require.Error(t, err) + + // Invalid addr + aggregateExchangeRatePrevoteMsg = types.NewMsgAggregateExchangeRatePrevote(hash, sdk.AccAddress{}, ValAddrs[0]) + _, err = msgServer.AggregateExchangeRatePrevote(sdk.WrapSDKContext(input.Ctx), aggregateExchangeRatePrevoteMsg) + require.Error(t, err) + + // Invalid validator addr + aggregateExchangeRatePrevoteMsg = types.NewMsgAggregateExchangeRatePrevote(hash, Addrs[0], sdk.ValAddress{}) + _, err = msgServer.AggregateExchangeRatePrevote(sdk.WrapSDKContext(input.Ctx), aggregateExchangeRatePrevoteMsg) + require.Error(t, err) + + // Invalid reveal period + aggregateExchangeRateVoteMsg := types.NewMsgAggregateExchangeRateVote(salt, exchangeRatesStr, Addrs[0], ValAddrs[0]) + _, err = msgServer.AggregateExchangeRateVote(sdk.WrapSDKContext(input.Ctx), aggregateExchangeRateVoteMsg) + require.Error(t, err) + + // Invalid reveal period + input.Ctx = input.Ctx.WithBlockHeight(2) + aggregateExchangeRateVoteMsg = types.NewMsgAggregateExchangeRateVote(salt, exchangeRatesStr, Addrs[0], ValAddrs[0]) + _, err = msgServer.AggregateExchangeRateVote(sdk.WrapSDKContext(input.Ctx), aggregateExchangeRateVoteMsg) + require.Error(t, err) + + // Other exchange rate with valid real period + input.Ctx = input.Ctx.WithBlockHeight(1) + aggregateExchangeRateVoteMsg = types.NewMsgAggregateExchangeRateVote(salt, otherExchangeRateStr, Addrs[0], ValAddrs[0]) + _, err = msgServer.AggregateExchangeRateVote(sdk.WrapSDKContext(input.Ctx), aggregateExchangeRateVoteMsg) + require.Error(t, err) + + // Invalid exchange rate with valid real period + input.Ctx = input.Ctx.WithBlockHeight(1) + aggregateExchangeRateVoteMsg = types.NewMsgAggregateExchangeRateVote(salt, invalidExchangeRateStr, Addrs[0], ValAddrs[0]) + _, err = msgServer.AggregateExchangeRateVote(sdk.WrapSDKContext(input.Ctx), aggregateExchangeRateVoteMsg) + require.Error(t, err) + + // Unauthorized feeder + aggregateExchangeRateVoteMsg = types.NewMsgAggregateExchangeRateVote(salt, invalidExchangeRateStr, Addrs[1], ValAddrs[0]) + _, err = msgServer.AggregateExchangeRateVote(sdk.WrapSDKContext(input.Ctx), aggregateExchangeRateVoteMsg) + require.Error(t, err) + + // Unintended denom vote + aggregateExchangeRateVoteMsg = types.NewMsgAggregateExchangeRateVote(salt, unintendedExchageRateStr, Addrs[0], ValAddrs[0]) + _, err = msgServer.AggregateExchangeRateVote(sdk.WrapSDKContext(input.Ctx), aggregateExchangeRateVoteMsg) + require.Error(t, err) + + // Valid exchange rate reveal submission + input.Ctx = input.Ctx.WithBlockHeight(1) + aggregateExchangeRateVoteMsg = types.NewMsgAggregateExchangeRateVote(salt, exchangeRatesStr, Addrs[0], ValAddrs[0]) + _, err = msgServer.AggregateExchangeRateVote(sdk.WrapSDKContext(input.Ctx), aggregateExchangeRateVoteMsg) + require.NoError(t, err) +} + +var ( + stakingAmt = sdk.TokensFromConsensusPower(10, sdk.DefaultPowerReduction) + randomExchangeRate = sdk.NewDec(1700) +) + +func setup(t *testing.T) (TestInput, types.MsgServer) { + input := CreateTestInput(t) + params := input.OracleKeeper.GetParams(input.Ctx) + params.VotePeriod = 1 + params.SlashWindow = 100 + params.RewardDistributionWindow = 100 + input.OracleKeeper.SetParams(input.Ctx, params) + msgServer := NewMsgServerImpl(input.OracleKeeper) + + sh := staking.NewHandler(input.StakingKeeper) + + // Validator created + _, err := sh(input.Ctx, NewTestMsgCreateValidator(ValAddrs[0], ValPubKeys[0], stakingAmt)) + require.NoError(t, err) + _, err = sh(input.Ctx, NewTestMsgCreateValidator(ValAddrs[1], ValPubKeys[1], stakingAmt)) + require.NoError(t, err) + _, err = sh(input.Ctx, NewTestMsgCreateValidator(ValAddrs[2], ValPubKeys[2], stakingAmt)) + require.NoError(t, err) + staking.EndBlocker(input.Ctx, input.StakingKeeper) + + return input, msgServer +} diff --git a/x/oracle/keeper/querier_test.go b/x/oracle/keeper/querier_test.go index 19d47068..41550e60 100644 --- a/x/oracle/keeper/querier_test.go +++ b/x/oracle/keeper/querier_test.go @@ -32,6 +32,10 @@ func TestQueryExchangeRate(t *testing.T) { rate := sdk.NewDec(1700) input.OracleKeeper.SetLunaExchangeRate(input.Ctx, core.MicroSDRDenom, rate) + // empty request + _, err := querier.ExchangeRate(ctx, nil) + require.Error(t, err) + // Query to grpc res, err := querier.ExchangeRate(ctx, &types.QueryExchangeRateRequest{ Denom: core.MicroSDRDenom, @@ -40,6 +44,26 @@ func TestQueryExchangeRate(t *testing.T) { require.Equal(t, rate, res.ExchangeRate) } +func TestQueryMissCounter(t *testing.T) { + input := CreateTestInput(t) + ctx := sdk.WrapSDKContext(input.Ctx) + querier := NewQuerier(input.OracleKeeper) + + missCounter := uint64(1) + input.OracleKeeper.SetMissCounter(input.Ctx, ValAddrs[0], missCounter) + + // empty request + _, err := querier.MissCounter(ctx, nil) + require.Error(t, err) + + // Query to grpc + res, err := querier.MissCounter(ctx, &types.QueryMissCounterRequest{ + ValidatorAddr: ValAddrs[0].String(), + }) + require.NoError(t, err) + require.Equal(t, missCounter, res.MissCounter) +} + func TestQueryExchangeRates(t *testing.T) { input := CreateTestInput(t) ctx := sdk.WrapSDKContext(input.Ctx) @@ -87,6 +111,10 @@ func TestQueryFeederDelegation(t *testing.T) { input.OracleKeeper.SetFeederDelegation(input.Ctx, ValAddrs[0], Addrs[1]) + // empty request + _, err := querier.FeederDelegation(ctx, nil) + require.Error(t, err) + res, err := querier.FeederDelegation(ctx, &types.QueryFeederDelegationRequest{ ValidatorAddr: ValAddrs[0].String(), }) @@ -112,6 +140,10 @@ func TestQueryAggregatePrevote(t *testing.T) { require.NoError(t, err) require.Equal(t, prevote1, res.AggregatePrevote) + // empty request + _, err = querier.AggregatePrevote(ctx, nil) + require.Error(t, err) + // validator 1 address params res, err = querier.AggregatePrevote(ctx, &types.QueryAggregatePrevoteRequest{ ValidatorAddr: ValAddrs[1].String(), @@ -154,6 +186,10 @@ func TestQueryAggregateVote(t *testing.T) { vote2 := types.NewAggregateExchangeRateVote(types.ExchangeRateTuples{{Denom: "", ExchangeRate: sdk.OneDec()}}, ValAddrs[1]) input.OracleKeeper.SetAggregateExchangeRateVote(input.Ctx, ValAddrs[1], vote2) + // empty request + _, err := querier.AggregateVote(ctx, nil) + require.Error(t, err) + // validator 0 address params res, err := querier.AggregateVote(ctx, &types.QueryAggregateVoteRequest{ ValidatorAddr: ValAddrs[0].String(), @@ -243,6 +279,10 @@ func TestQueryTobinTax(t *testing.T) { denom := types.Denom{Name: core.MicroKRWDenom, TobinTax: sdk.OneDec()} input.OracleKeeper.SetTobinTax(input.Ctx, denom.Name, denom.TobinTax) + // empty request + _, err := querier.TobinTax(ctx, nil) + require.Error(t, err) + res, err := querier.TobinTax(ctx, &types.QueryTobinTaxRequest{ Denom: core.MicroKRWDenom, }) diff --git a/x/oracle/tally.go b/x/oracle/tally.go index c33b5c4d..d30dd94d 100644 --- a/x/oracle/tally.go +++ b/x/oracle/tally.go @@ -50,10 +50,10 @@ func ballotIsPassing(ballot types.ExchangeRateBallot, thresholdVotes sdk.Int) (s return ballotPower, !ballotPower.IsZero() && ballotPower.GTE(thresholdVotes) } -// choose Reference Terra with the highest voter turnout +// PickReferenceTerra choose Reference Terra with the highest voter turnout // If the voting power of the two denominations is the same, // select reference Terra in alphabetical order. -func pickReferenceTerra(ctx sdk.Context, k keeper.Keeper, voteTargets map[string]sdk.Dec, voteMap map[string]types.ExchangeRateBallot) string { +func PickReferenceTerra(ctx sdk.Context, k keeper.Keeper, voteTargets map[string]sdk.Dec, voteMap map[string]types.ExchangeRateBallot) string { largestBallotPower := int64(0) referenceTerra := "" diff --git a/x/oracle/tally_fuzz_test.go b/x/oracle/tally_fuzz_test.go new file mode 100644 index 00000000..7aaab86d --- /dev/null +++ b/x/oracle/tally_fuzz_test.go @@ -0,0 +1,139 @@ +package oracle_test + +import ( + "sort" + "testing" + + fuzz "github.com/google/gofuzz" + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/terra-money/core/x/oracle" + "github.com/terra-money/core/x/oracle/types" +) + +func TestFuzz_Tally(t *testing.T) { + validators := map[string]int64{} + + f := fuzz.New().NilChance(0).Funcs( + func(e *sdk.Dec, c fuzz.Continue) { + *e = sdk.NewDec(c.Int63()) + }, + func(e *map[string]int64, c fuzz.Continue) { + numValidators := c.Intn(100) + 5 + + for i := 0; i < numValidators; i++ { + (*e)[sdk.ValAddress(secp256k1.GenPrivKey().PubKey().Address()).String()] = c.Int63n(100) + } + }, + func(e *map[string]types.Claim, c fuzz.Continue) { + for validator, power := range validators { + addr, err := sdk.ValAddressFromBech32(validator) + require.NoError(t, err) + (*e)[validator] = types.NewClaim(power, 0, 0, addr) + } + }, + func(e *types.ExchangeRateBallot, c fuzz.Continue) { + + ballot := types.ExchangeRateBallot{} + for addr, power := range validators { + addr, _ := sdk.ValAddressFromBech32(addr) + + var rate sdk.Dec + c.Fuzz(&rate) + + ballot = append(ballot, types.NewVoteForTally(rate, c.RandString(), addr, power)) + } + + sort.Sort(ballot) + + *e = ballot + }, + ) + + // set random denoms and validators + f.Fuzz(&validators) + + input, _ := setup(t) + + claimMap := map[string]types.Claim{} + f.Fuzz(&claimMap) + + ballot := types.ExchangeRateBallot{} + f.Fuzz(&ballot) + + var rewardBand sdk.Dec + f.Fuzz(&rewardBand) + + require.NotPanics(t, func() { + oracle.Tally(input.Ctx, ballot, rewardBand, claimMap) + }) +} + +func TestFuzz_PickReferenceTerra(t *testing.T) { + var denoms []string + + f := fuzz.New().NilChance(0).Funcs( + func(e *[]string, c fuzz.Continue) { + numDenoms := c.Intn(100) + 5 + + for i := 0; i < numDenoms; i++ { + *e = append(*e, c.RandString()) + } + }, + func(e *sdk.Dec, c fuzz.Continue) { + *e = sdk.NewDec(c.Int63()) + }, + func(e *map[string]sdk.Dec, c fuzz.Continue) { + for _, denom := range denoms { + var rate sdk.Dec + c.Fuzz(&rate) + + (*e)[denom] = rate + } + }, + func(e *map[string]int64, c fuzz.Continue) { + numValidator := c.Intn(100) + 5 + for i := 0; i < numValidator; i++ { + (*e)[sdk.ValAddress(secp256k1.GenPrivKey().PubKey().Address()).String()] = int64(c.Intn(100) + 1) + } + }, + func(e *map[string]types.ExchangeRateBallot, c fuzz.Continue) { + validators := map[string]int64{} + c.Fuzz(&validators) + + for _, denom := range denoms { + ballot := types.ExchangeRateBallot{} + + for addr, power := range validators { + addr, _ := sdk.ValAddressFromBech32(addr) + + var rate sdk.Dec + c.Fuzz(&rate) + + ballot = append(ballot, types.NewVoteForTally(rate, denom, addr, power)) + } + + sort.Sort(ballot) + (*e)[denom] = ballot + } + }, + ) + + // set random denoms + f.Fuzz(&denoms) + + input, _ := setup(t) + + voteTargets := map[string]sdk.Dec{} + f.Fuzz(&voteTargets) + + voteMap := map[string]types.ExchangeRateBallot{} + f.Fuzz(&voteMap) + + require.NotPanics(t, func() { + oracle.PickReferenceTerra(input.Ctx, input.OracleKeeper, voteTargets, voteMap) + }) +} diff --git a/x/oracle/types/ballot_test.go b/x/oracle/types/ballot_test.go index 59485044..2179bd2a 100644 --- a/x/oracle/types/ballot_test.go +++ b/x/oracle/types/ballot_test.go @@ -1,4 +1,4 @@ -package types +package types_test import ( "fmt" @@ -16,15 +16,16 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" core "github.com/terra-money/core/types" + "github.com/terra-money/core/x/oracle/types" ) func TestToMap(t *testing.T) { tests := struct { - votes []VoteForTally + votes []types.VoteForTally isValid []bool }{ - []VoteForTally{ + []types.VoteForTally{ { Voter: sdk.ValAddress(secp256k1.GenPrivKey().PubKey().Address()), @@ -50,7 +51,7 @@ func TestToMap(t *testing.T) { []bool{true, false, true}, } - pb := ExchangeRateBallot(tests.votes) + pb := types.ExchangeRateBallot(tests.votes) mapData := pb.ToMap() for i, vote := range tests.votes { exchangeRate, ok := mapData[string(vote.Voter)] @@ -86,27 +87,29 @@ func TestToCrossRate(t *testing.T) { }, } - pbBase := ExchangeRateBallot{} - pbQuote := ExchangeRateBallot{} - cb := ExchangeRateBallot{} + pbBase := types.ExchangeRateBallot{} + pbQuote := types.ExchangeRateBallot{} + cb := types.ExchangeRateBallot{} for _, data := range data { valAddr := sdk.ValAddress(secp256k1.GenPrivKey().PubKey().Address()) if !data.base.IsZero() { - pbBase = append(pbBase, NewVoteForTally(data.base, core.MicroKRWDenom, valAddr, 100)) + pbBase = append(pbBase, types.NewVoteForTally(data.base, core.MicroKRWDenom, valAddr, 100)) } - pbQuote = append(pbQuote, NewVoteForTally(data.quote, core.MicroKRWDenom, valAddr, 100)) + pbQuote = append(pbQuote, types.NewVoteForTally(data.quote, core.MicroKRWDenom, valAddr, 100)) if !data.base.IsZero() && !data.quote.IsZero() { - cb = append(cb, NewVoteForTally(data.base.Quo(data.quote), core.MicroKRWDenom, valAddr, 100)) + cb = append(cb, types.NewVoteForTally(data.base.Quo(data.quote), core.MicroKRWDenom, valAddr, 100)) } else { - cb = append(cb, NewVoteForTally(sdk.ZeroDec(), core.MicroKRWDenom, valAddr, 0)) + cb = append(cb, types.NewVoteForTally(sdk.ZeroDec(), core.MicroKRWDenom, valAddr, 0)) } } + baseMapBallot := pbBase.ToMap() + require.Equal(t, cb, pbQuote.ToCrossRate(baseMapBallot)) + sort.Sort(cb) - baseMapBallot := pbBase.ToMap() require.Equal(t, cb, pbQuote.ToCrossRateWithSort(baseMapBallot)) } @@ -125,13 +128,13 @@ func TestSqrt(t *testing.T) { func TestPBPower(t *testing.T) { ctx := sdk.NewContext(nil, tmproto.Header{}, false, nil) - _, valAccAddrs, sk := GenerateRandomTestCase() - pb := ExchangeRateBallot{} + _, valAccAddrs, sk := types.GenerateRandomTestCase() + pb := types.ExchangeRateBallot{} ballotPower := int64(0) for i := 0; i < len(sk.Validators()); i++ { power := sk.Validator(ctx, valAccAddrs[i]).GetConsensusPower(sdk.DefaultPowerReduction) - vote := NewVoteForTally( + vote := types.NewVoteForTally( sdk.ZeroDec(), core.MicroSDRDenom, valAccAddrs[i], @@ -150,7 +153,7 @@ func TestPBPower(t *testing.T) { // Mix in a fake validator, the total power should not have changed. pubKey := secp256k1.GenPrivKey().PubKey() faceValAddr := sdk.ValAddress(pubKey.Address()) - fakeVote := NewVoteForTally( + fakeVote := types.NewVoteForTally( sdk.OneDec(), core.MicroSDRDenom, faceValAddr, @@ -167,6 +170,7 @@ func TestPBWeightedMedian(t *testing.T) { weights []int64 isValidator []bool median sdk.Dec + panic bool }{ { // Supermajority one number @@ -174,6 +178,7 @@ func TestPBWeightedMedian(t *testing.T) { []int64{1, 1, 100, 1}, []bool{true, true, true, true}, sdk.NewDec(10), + false, }, { // Adding fake validator doesn't change outcome @@ -181,6 +186,7 @@ func TestPBWeightedMedian(t *testing.T) { []int64{1, 1, 100, 1, 10000}, []bool{true, true, true, true, false}, sdk.NewDec(10), + false, }, { // Tie votes @@ -188,6 +194,7 @@ func TestPBWeightedMedian(t *testing.T) { []int64{1, 100, 100, 1}, []bool{true, true, true, true}, sdk.NewDec(2), + false, }, { // No votes @@ -195,11 +202,20 @@ func TestPBWeightedMedian(t *testing.T) { []int64{}, []bool{true, true, true, true}, sdk.NewDec(0), + false, + }, + { + // not sorted panic + []int64{2, 1, 10, 100000}, + []int64{1, 1, 100, 1}, + []bool{true, true, true, true}, + sdk.NewDec(10), + true, }, } for _, tc := range tests { - pb := ExchangeRateBallot{} + pb := types.ExchangeRateBallot{} for i, input := range tc.inputs { valAddr := sdk.ValAddress(secp256k1.GenPrivKey().PubKey().Address()) @@ -208,7 +224,7 @@ func TestPBWeightedMedian(t *testing.T) { power = 0 } - vote := NewVoteForTally( + vote := types.NewVoteForTally( sdk.NewDec(int64(input)), core.MicroSDRDenom, valAddr, @@ -218,7 +234,12 @@ func TestPBWeightedMedian(t *testing.T) { pb = append(pb, vote) } - require.Equal(t, tc.median, pb.WeightedMedianWithAssertion()) + if tc.panic { + require.Panics(t, func() { pb.WeightedMedianWithAssertion() }) + } else { + require.Equal(t, tc.median, pb.WeightedMedian()) + require.Equal(t, tc.median, pb.WeightedMedianWithAssertion()) + } } } @@ -234,21 +255,21 @@ func TestPBStandardDeviation(t *testing.T) { []float64{1.0, 2.0, 10.0, 100000.0}, []int64{1, 1, 100, 1}, []bool{true, true, true, true}, - sdk.NewDecWithPrec(4999500036300, OracleDecPrecision), + sdk.NewDecWithPrec(4999500036300, types.OracleDecPrecision), }, { // Adding fake validator doesn't change outcome []float64{1.0, 2.0, 10.0, 100000.0, 10000000000}, []int64{1, 1, 100, 1, 10000}, []bool{true, true, true, true, false}, - sdk.NewDecWithPrec(447213595075100600, OracleDecPrecision), + sdk.NewDecWithPrec(447213595075100600, types.OracleDecPrecision), }, { // Tie votes []float64{1.0, 2.0, 3.0, 4.0}, []int64{1, 100, 100, 1}, []bool{true, true, true, true}, - sdk.NewDecWithPrec(122474500, OracleDecPrecision), + sdk.NewDecWithPrec(122474500, types.OracleDecPrecision), }, { // No votes @@ -259,9 +280,9 @@ func TestPBStandardDeviation(t *testing.T) { }, } - base := math.Pow10(OracleDecPrecision) + base := math.Pow10(types.OracleDecPrecision) for _, tc := range tests { - pb := ExchangeRateBallot{} + pb := types.ExchangeRateBallot{} for i, input := range tc.inputs { valAddr := sdk.ValAddress(secp256k1.GenPrivKey().PubKey().Address()) @@ -270,8 +291,8 @@ func TestPBStandardDeviation(t *testing.T) { power = 0 } - vote := NewVoteForTally( - sdk.NewDecWithPrec(int64(input*base), int64(OracleDecPrecision)), + vote := types.NewVoteForTally( + sdk.NewDecWithPrec(int64(input*base), int64(types.OracleDecPrecision)), core.MicroSDRDenom, valAddr, power, @@ -289,12 +310,12 @@ func TestPBStandardDeviationOverflow(t *testing.T) { exchangeRate, err := sdk.NewDecFromStr("100000000000000000000000000000000000000000000000000000000.0") require.NoError(t, err) - pb := ExchangeRateBallot{NewVoteForTally( + pb := types.ExchangeRateBallot{types.NewVoteForTally( sdk.ZeroDec(), core.MicroSDRDenom, valAddr, 2, - ), NewVoteForTally( + ), types.NewVoteForTally( exchangeRate, core.MicroSDRDenom, valAddr, @@ -303,3 +324,17 @@ func TestPBStandardDeviationOverflow(t *testing.T) { require.Equal(t, sdk.ZeroDec(), pb.StandardDeviation(pb.WeightedMedianWithAssertion())) } + +func TestNewClaim(t *testing.T) { + power := int64(10) + weight := int64(11) + winCount := int64(1) + addr := sdk.ValAddress(secp256k1.GenPrivKey().PubKey().Address().Bytes()) + claim := types.NewClaim(power, weight, winCount, addr) + require.Equal(t, types.Claim{ + Power: power, + Weight: weight, + WinCount: winCount, + Recipient: addr, + }, claim) +} diff --git a/x/oracle/types/denom_test.go b/x/oracle/types/denom_test.go new file mode 100644 index 00000000..38b402da --- /dev/null +++ b/x/oracle/types/denom_test.go @@ -0,0 +1,34 @@ +package types_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + "github.com/terra-money/core/x/oracle/types" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func Test_DenomList(t *testing.T) { + denoms := types.DenomList{ + types.Denom{ + Name: "denom1", + TobinTax: sdk.NewDec(100), + }, + types.Denom{ + Name: "denom2", + TobinTax: sdk.NewDec(200), + }, + types.Denom{ + Name: "denom3", + TobinTax: sdk.NewDec(300), + }, + } + + require.False(t, denoms[0].Equal(&denoms[1])) + require.True(t, denoms[0].Equal(&denoms[0])) + require.Equal(t, "name: denom1\ntobin_tax: \"100.000000000000000000\"\n", denoms[0].String()) + require.Equal(t, "name: denom2\ntobin_tax: \"200.000000000000000000\"\n", denoms[1].String()) + require.Equal(t, "name: denom3\ntobin_tax: \"300.000000000000000000\"\n", denoms[2].String()) + require.Equal(t, "name: denom1\ntobin_tax: \"100.000000000000000000\"\n\nname: denom2\ntobin_tax: \"200.000000000000000000\"\n\nname: denom3\ntobin_tax: \"300.000000000000000000\"", denoms.String()) +} diff --git a/x/oracle/types/genesis.go b/x/oracle/types/genesis.go index 4eb6493f..80eab941 100644 --- a/x/oracle/types/genesis.go +++ b/x/oracle/types/genesis.go @@ -28,15 +28,13 @@ func NewGenesisState( // DefaultGenesisState - default GenesisState used by columbus-2 func DefaultGenesisState() *GenesisState { - return &GenesisState{ - Params: DefaultParams(), - ExchangeRates: []ExchangeRateTuple{}, - FeederDelegations: []FeederDelegation{}, - MissCounters: []MissCounter{}, - AggregateExchangeRatePrevotes: []AggregateExchangeRatePrevote{}, - AggregateExchangeRateVotes: []AggregateExchangeRateVote{}, - TobinTaxes: []TobinTax{}, - } + return NewGenesisState(DefaultParams(), + []ExchangeRateTuple{}, + []FeederDelegation{}, + []MissCounter{}, + []AggregateExchangeRatePrevote{}, + []AggregateExchangeRateVote{}, + []TobinTax{}) } // ValidateGenesis validates the oracle genesis state diff --git a/x/oracle/types/genesis_test.go b/x/oracle/types/genesis_test.go index 48a371d0..0fb5ca7a 100644 --- a/x/oracle/types/genesis_test.go +++ b/x/oracle/types/genesis_test.go @@ -1,15 +1,27 @@ -package types +package types_test import ( + "encoding/json" "testing" "github.com/stretchr/testify/require" + "github.com/terra-money/core/app" + "github.com/terra-money/core/x/oracle/types" ) func TestGenesisValidation(t *testing.T) { - genState := DefaultGenesisState() - require.NoError(t, ValidateGenesis(genState)) + genState := types.DefaultGenesisState() + require.NoError(t, types.ValidateGenesis(genState)) genState.Params.VotePeriod = 0 - require.Error(t, ValidateGenesis(genState)) + require.Error(t, types.ValidateGenesis(genState)) +} + +func TestGetGenesisStateFromAppState(t *testing.T) { + cdc := app.MakeEncodingConfig().Marshaler + appState := make(map[string]json.RawMessage) + + defaultGenesisState := types.DefaultGenesisState() + appState[types.ModuleName] = cdc.MustMarshalJSON(defaultGenesisState) + require.Equal(t, *defaultGenesisState, *types.GetGenesisStateFromAppState(cdc, appState)) } diff --git a/x/oracle/types/hash_test.go b/x/oracle/types/hash_test.go index 8e3995d2..3b36e7bd 100644 --- a/x/oracle/types/hash_test.go +++ b/x/oracle/types/hash_test.go @@ -1,4 +1,4 @@ -package types +package types_test import ( "encoding/hex" @@ -6,6 +6,8 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/yaml.v2" + "github.com/terra-money/core/x/oracle/types" + sdk "github.com/cosmos/cosmos-sdk/types" "testing" @@ -16,18 +18,18 @@ func TestAggregateVoteHash(t *testing.T) { sdk.AccAddress([]byte("addr1_______________")), } - aggregateVoteHash := GetAggregateVoteHash("salt", "100ukrw,200uusd", sdk.ValAddress(addrs[0])) + aggregateVoteHash := types.GetAggregateVoteHash("salt", "100ukrw,200uusd", sdk.ValAddress(addrs[0])) hexStr := hex.EncodeToString(aggregateVoteHash) - aggregateVoteHashRes, err := AggregateVoteHashFromHexString(hexStr) + aggregateVoteHashRes, err := types.AggregateVoteHashFromHexString(hexStr) require.NoError(t, err) require.Equal(t, aggregateVoteHash, aggregateVoteHashRes) require.True(t, aggregateVoteHash.Equal(aggregateVoteHash)) - require.True(t, AggregateVoteHash([]byte{}).Empty()) + require.True(t, types.AggregateVoteHash([]byte{}).Empty()) got, _ := yaml.Marshal(&aggregateVoteHash) require.Equal(t, aggregateVoteHash.String()+"\n", string(got)) - res := AggregateVoteHash{} + res := types.AggregateVoteHash{} testMarshal(t, &aggregateVoteHash, &res, aggregateVoteHash.MarshalJSON, (&res).UnmarshalJSON) testMarshal(t, &aggregateVoteHash, &res, aggregateVoteHash.Marshal, (&res).Unmarshal) } diff --git a/x/oracle/types/msgs_test.go b/x/oracle/types/msgs_test.go index d8497e11..9fe7a17a 100644 --- a/x/oracle/types/msgs_test.go +++ b/x/oracle/types/msgs_test.go @@ -1,9 +1,11 @@ -package types +package types_test import ( + "math/rand" "testing" core "github.com/terra-money/core/types" + "github.com/terra-money/core/x/oracle/types" "github.com/stretchr/testify/require" @@ -28,7 +30,7 @@ func TestMsgFeederDelegation(t *testing.T) { } for i, tc := range tests { - msg := NewMsgDelegateFeedConsent(tc.delegator, tc.delegate) + msg := types.NewMsgDelegateFeedConsent(tc.delegator, tc.delegate) if tc.expectPass { require.Nil(t, msg.ValidateBasic(), "test: %v", i) } else { @@ -43,10 +45,10 @@ func TestMsgAggregateExchangeRatePrevote(t *testing.T) { } exchangeRates := sdk.DecCoins{sdk.NewDecCoinFromDec(core.MicroSDRDenom, sdk.OneDec()), sdk.NewDecCoinFromDec(core.MicroKRWDenom, sdk.NewDecWithPrec(32121, 1))} - bz := GetAggregateVoteHash("1", exchangeRates.String(), sdk.ValAddress(addrs[0])) + bz := types.GetAggregateVoteHash("1", exchangeRates.String(), sdk.ValAddress(addrs[0])) tests := []struct { - hash AggregateVoteHash + hash types.AggregateVoteHash exchangeRates sdk.DecCoins voter sdk.AccAddress expectPass bool @@ -54,11 +56,11 @@ func TestMsgAggregateExchangeRatePrevote(t *testing.T) { {bz, exchangeRates, addrs[0], true}, {bz[1:], exchangeRates, addrs[0], false}, {bz, exchangeRates, sdk.AccAddress{}, false}, - {AggregateVoteHash{}, exchangeRates, addrs[0], false}, + {types.AggregateVoteHash{}, exchangeRates, addrs[0], false}, } for i, tc := range tests { - msg := NewMsgAggregateExchangeRatePrevote(tc.hash, tc.voter, sdk.ValAddress(tc.voter)) + msg := types.NewMsgAggregateExchangeRatePrevote(tc.hash, tc.voter, sdk.ValAddress(tc.voter)) if tc.expectPass { require.NoError(t, msg.ValidateBasic(), "test: %v", i) } else { @@ -79,20 +81,24 @@ func TestMsgAggregateExchangeRateVote(t *testing.T) { tests := []struct { voter sdk.AccAddress + validator sdk.ValAddress salt string exchangeRates string expectPass bool }{ - {addrs[0], "123", exchangeRates, true}, - {addrs[0], "123", invalidExchangeRates, false}, - {addrs[0], "123", abstainExchangeRates, true}, - {addrs[0], "123", overFlowExchangeRates, false}, - {sdk.AccAddress{}, "123", exchangeRates, false}, - {addrs[0], "", exchangeRates, false}, + {addrs[0], sdk.ValAddress(addrs[0]), "123", exchangeRates, true}, + {addrs[0], sdk.ValAddress(addrs[0]), "123", invalidExchangeRates, false}, + {addrs[0], sdk.ValAddress(addrs[0]), "123", abstainExchangeRates, true}, + {addrs[0], sdk.ValAddress(addrs[0]), "123", overFlowExchangeRates, false}, + {sdk.AccAddress{}, sdk.ValAddress(addrs[0]), "123", exchangeRates, false}, + {addrs[0], sdk.ValAddress(addrs[0]), "123", "", false}, + {addrs[0], sdk.ValAddress(addrs[0]), "", randSeq(4097), false}, + {addrs[0], sdk.ValAddress{}, "123", abstainExchangeRates, false}, + {addrs[0], sdk.ValAddress(addrs[0]), "", abstainExchangeRates, false}, } for i, tc := range tests { - msg := NewMsgAggregateExchangeRateVote(tc.salt, tc.exchangeRates, tc.voter, sdk.ValAddress(tc.voter)) + msg := types.NewMsgAggregateExchangeRateVote(tc.salt, tc.exchangeRates, tc.voter, tc.validator) if tc.expectPass { require.Nil(t, msg.ValidateBasic(), "test: %v", i) } else { @@ -100,3 +106,13 @@ func TestMsgAggregateExchangeRateVote(t *testing.T) { } } } + +var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") + +func randSeq(n int) string { + b := make([]rune, n) + for i := range b { + b[i] = letters[rand.Intn(len(letters))] + } + return string(b) +} diff --git a/x/oracle/types/params_test.go b/x/oracle/types/params_test.go index 0a4c65a3..e2a8b657 100644 --- a/x/oracle/types/params_test.go +++ b/x/oracle/types/params_test.go @@ -1,15 +1,18 @@ -package types +package types_test import ( + "bytes" "testing" "github.com/stretchr/testify/require" + "github.com/terra-money/core/x/oracle/types" + sdk "github.com/cosmos/cosmos-sdk/types" ) func TestParamsEqual(t *testing.T) { - p1 := DefaultParams() + p1 := types.DefaultParams() err := p1.Validate() require.NoError(t, err) @@ -19,54 +22,113 @@ func TestParamsEqual(t *testing.T) { require.Error(t, err) // small vote threshold - p2 := DefaultParams() + p2 := types.DefaultParams() p2.VoteThreshold = sdk.ZeroDec() err = p2.Validate() require.Error(t, err) // negative reward band - p3 := DefaultParams() + p3 := types.DefaultParams() p3.RewardBand = sdk.NewDecWithPrec(-1, 2) err = p3.Validate() require.Error(t, err) // negative slash fraction - p4 := DefaultParams() + p4 := types.DefaultParams() p4.SlashFraction = sdk.NewDec(-1) err = p4.Validate() require.Error(t, err) // negative min valid per window - p5 := DefaultParams() + p5 := types.DefaultParams() p5.MinValidPerWindow = sdk.NewDec(-1) err = p5.Validate() require.Error(t, err) // small slash window - p6 := DefaultParams() + p6 := types.DefaultParams() p6.SlashWindow = 0 err = p6.Validate() require.Error(t, err) // small distribution window - p7 := DefaultParams() + p7 := types.DefaultParams() p7.RewardDistributionWindow = 0 err = p7.Validate() require.Error(t, err) // non-positive tobin tax - p8 := DefaultParams() - p8.Whitelist[0].TobinTax = sdk.NewDec(-1) + p8 := types.DefaultParams() + p8.Whitelist[0].Name = "" err = p8.Validate() require.Error(t, err) - // empty name - p9 := DefaultParams() - p9.Whitelist[0].Name = "" + // invalid name tobin tax + p9 := types.DefaultParams() + p9.Whitelist[0].TobinTax = sdk.NewDec(-1) err = p9.Validate() require.Error(t, err) - p10 := DefaultParams() - require.NotNil(t, p10.ParamSetPairs()) - require.NotNil(t, p10.String()) + // empty name + p10 := types.DefaultParams() + p10.Whitelist[0].Name = "" + err = p10.Validate() + require.Error(t, err) + + p11 := types.DefaultParams() + require.NotNil(t, p11.ParamSetPairs()) + require.NotNil(t, p11.String()) +} + +func TestValidate(t *testing.T) { + p1 := types.DefaultParams() + pairs := p1.ParamSetPairs() + for _, pair := range pairs { + switch { + case bytes.Compare(types.KeyVotePeriod, pair.Key) == 0 || + bytes.Compare(types.KeyRewardDistributionWindow, pair.Key) == 0 || + bytes.Compare(types.KeySlashWindow, pair.Key) == 0: + require.NoError(t, pair.ValidatorFn(uint64(1))) + require.Error(t, pair.ValidatorFn("invalid")) + require.Error(t, pair.ValidatorFn(uint64(0))) + case bytes.Compare(types.KeyVoteThreshold, pair.Key) == 0: + require.NoError(t, pair.ValidatorFn(sdk.NewDecWithPrec(33, 2))) + require.Error(t, pair.ValidatorFn("invalid")) + require.Error(t, pair.ValidatorFn(sdk.NewDecWithPrec(32, 2))) + require.Error(t, pair.ValidatorFn(sdk.NewDecWithPrec(101, 2))) + case bytes.Compare(types.KeyRewardBand, pair.Key) == 0 || + bytes.Compare(types.KeySlashFraction, pair.Key) == 0 || + bytes.Compare(types.KeyMinValidPerWindow, pair.Key) == 0: + require.NoError(t, pair.ValidatorFn(sdk.NewDecWithPrec(7, 2))) + require.Error(t, pair.ValidatorFn("invalid")) + require.Error(t, pair.ValidatorFn(sdk.NewDecWithPrec(-1, 2))) + require.Error(t, pair.ValidatorFn(sdk.NewDecWithPrec(101, 2))) + case bytes.Compare(types.KeyWhitelist, pair.Key) == 0: + require.NoError(t, pair.ValidatorFn(types.DenomList{ + { + Name: "denom", + TobinTax: sdk.NewDecWithPrec(10, 2), + }, + })) + require.Error(t, pair.ValidatorFn("invalid")) + require.Error(t, pair.ValidatorFn(types.DenomList{ + { + Name: "", + TobinTax: sdk.NewDecWithPrec(10, 2), + }, + })) + require.Error(t, pair.ValidatorFn(types.DenomList{ + { + Name: "denom", + TobinTax: sdk.NewDecWithPrec(101, 2), + }, + })) + require.Error(t, pair.ValidatorFn(types.DenomList{ + { + Name: "denom", + TobinTax: sdk.NewDecWithPrec(-1, 2), + }, + })) + } + } } diff --git a/x/oracle/types/vote_test.go b/x/oracle/types/vote_test.go index df50bb21..ad21dbb3 100644 --- a/x/oracle/types/vote_test.go +++ b/x/oracle/types/vote_test.go @@ -1,29 +1,30 @@ -package types +package types_test import ( "testing" "github.com/stretchr/testify/require" + "github.com/terra-money/core/x/oracle/types" ) func TestParseExchangeRateTuples(t *testing.T) { valid := "123.0uluna,123.123ukrw" - _, err := ParseExchangeRateTuples(valid) + _, err := types.ParseExchangeRateTuples(valid) require.NoError(t, err) duplicatedDenom := "100.0uluna,123.123ukrw,121233.123ukrw" - _, err = ParseExchangeRateTuples(duplicatedDenom) + _, err = types.ParseExchangeRateTuples(duplicatedDenom) require.Error(t, err) invalidCoins := "123.123" - _, err = ParseExchangeRateTuples(invalidCoins) + _, err = types.ParseExchangeRateTuples(invalidCoins) require.Error(t, err) invalidCoinsWithValid := "123.0uluna,123.1" - _, err = ParseExchangeRateTuples(invalidCoinsWithValid) + _, err = types.ParseExchangeRateTuples(invalidCoinsWithValid) require.Error(t, err) abstainCoinsWithValid := "0.0uluna,123.1ukrw" - _, err = ParseExchangeRateTuples(abstainCoinsWithValid) + _, err = types.ParseExchangeRateTuples(abstainCoinsWithValid) require.NoError(t, err) } diff --git a/x/wasm/keeper/legacy_querier_test.go b/x/wasm/keeper/legacy_querier_test.go index f792fb47..555fe1bf 100644 --- a/x/wasm/keeper/legacy_querier_test.go +++ b/x/wasm/keeper/legacy_querier_test.go @@ -81,6 +81,20 @@ func TestLegacyContractState(t *testing.T) { _, err = querier(ctx, []string{types.QueryContractStore}, abci.RequestQuery{Data: []byte(bz)}) require.Error(t, err) + + bz, err = input.Cdc.MarshalJSON(types.NewQueryCodeIDParams(contractID)) + _, err = querier(ctx, []string{types.QueryGetByteCode}, abci.RequestQuery{Data: []byte(bz)}) + require.NoError(t, err) + + _, err = querier(ctx, []string{types.QueryGetCodeInfo}, abci.RequestQuery{Data: []byte(bz)}) + require.NoError(t, err) + + bz, err = input.Cdc.MarshalJSON(types.NewQueryContractAddressParams(addr)) + _, err = querier(ctx, []string{types.QueryGetContractInfo}, abci.RequestQuery{Data: []byte(bz)}) + require.NoError(t, err) + + _, err = querier(ctx, []string{types.QueryParameters}, abci.RequestQuery{}) + require.NoError(t, err) } func TestLegacyParams(t *testing.T) { diff --git a/x/wasm/keeper/querier_test.go b/x/wasm/keeper/querier_test.go index 4df4eb87..62612351 100644 --- a/x/wasm/keeper/querier_test.go +++ b/x/wasm/keeper/querier_test.go @@ -129,3 +129,59 @@ func TestQueryMultipleGoroutines(t *testing.T) { } wg.Wait() } + +func TestQueryCodeAndContractInfo(t *testing.T) { + input := CreateTestInput(t) + goCtx := sdk.WrapSDKContext(input.Ctx) + ctx, accKeeper, bankKeeper, keeper := input.Ctx, input.AccKeeper, input.BankKeeper, input.WasmKeeper + + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) + topUp := sdk.NewCoins(sdk.NewInt64Coin("denom", 5000)) + creator := createFakeFundedAccount(ctx, accKeeper, bankKeeper, deposit.Add(deposit...)) + anyAddr := createFakeFundedAccount(ctx, accKeeper, bankKeeper, topUp) + + wasmCode, err := ioutil.ReadFile("./testdata/hackatom.wasm") + require.NoError(t, err) + + contractID, err := keeper.StoreCode(ctx, creator, wasmCode) + require.NoError(t, err) + + _, _, bob := keyPubAddr() + initMsg := HackatomExampleInitMsg{ + Verifier: anyAddr, + Beneficiary: bob, + } + initMsgBz, err := json.Marshal(initMsg) + require.NoError(t, err) + + addr, _, err := keeper.InstantiateContract(ctx, contractID, creator, sdk.AccAddress{}, initMsgBz, deposit) + require.NoError(t, err) + + contractModel := []types.Model{ + {Key: []byte("foo"), Value: []byte(`"bar"`)}, + {Key: []byte{0x0, 0x1}, Value: []byte(`{"count":8}`)}, + } + + keeper.SetContractStore(ctx, addr, contractModel) + + querier := NewQuerier(keeper) + + res, err := querier.CodeInfo(goCtx, &types.QueryCodeInfoRequest{CodeId: contractID}) + require.NoError(t, err) + require.Equal(t, creator.String(), res.GetCodeInfo().Creator) + require.Equal(t, contractID, res.GetCodeInfo().CodeID) + + res2, err := querier.ByteCode(goCtx, &types.QueryByteCodeRequest{CodeId: contractID}) + require.NoError(t, err) + require.Equal(t, res2.GetByteCode(), wasmCode) + + res3, err := querier.ContractInfo(goCtx, &types.QueryContractInfoRequest{ContractAddress: addr.String()}) + require.NoError(t, err) + require.Equal(t, addr.String(), res3.GetContractInfo().Address) + require.Equal(t, "", res3.GetContractInfo().Admin) + require.Equal(t, creator.String(), res3.GetContractInfo().Creator) + require.Equal(t, contractID, res3.GetContractInfo().CodeID) + queriedInitMsg, err := res3.GetContractInfo().InitMsg.MarshalJSON() + require.NoError(t, err) + require.Equal(t, initMsgBz, queriedInitMsg) +}