Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

epoching: refactor test infra, mock messages and sample fuzz tests #65

Merged
merged 16 commits into from
Jul 19, 2022
72 changes: 68 additions & 4 deletions x/epoching/keeper/epoch_msg_queue_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,22 @@ import (
"math/rand"
"testing"

"github.com/babylonchain/babylon/x/epoching/testepoching"
"github.com/babylonchain/babylon/x/epoching/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/require"
)

func FuzzEpochMsgQueue(f *testing.F) {
var (
coin100 = sdk.NewInt64Coin(sdk.DefaultBondDenom, 100)
coin50 = sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)
// val1 = sdk.ValAddress("_____validator1_____")
// val2 = sdk.ValAddress("_____validator2_____")
// val3 = sdk.ValAddress("_____validator3_____")
)

// FuzzEnqueueMsg tests EnqueueMsg. It enqueues some wrapped msgs, and check if the message queue includes the enqueued msgs or not
func FuzzEnqueueMsg(f *testing.F) {
f.Add(int64(11111))
f.Add(int64(22222))
f.Add(int64(55555))
Expand All @@ -18,7 +28,8 @@ func FuzzEpochMsgQueue(f *testing.F) {
f.Fuzz(func(t *testing.T, seed int64) {
rand.Seed(seed)

_, ctx, keeper, _, _ := setupTestKeeper()
helper := testepoching.NewHelper(t)
ctx, keeper := helper.Ctx, helper.EpochingKeeper
// ensure that the epoch msg queue is correct at the genesis
require.Empty(t, keeper.GetEpochMsgs(ctx))
require.Equal(t, uint64(0), keeper.GetQueueLength(ctx))
Expand Down Expand Up @@ -48,5 +59,58 @@ func FuzzEpochMsgQueue(f *testing.F) {
})
}

// TODO (stateful tests): fuzz HandleQueueMsg. initialise some validators, let them submit some msgs and trigger HandleQueueMsg
// require mocking valid QueueMsgs
// FuzzHandleQueueMsg tests HandleQueueMsg over MsgWrappedDelegate.
// It enqueues some MsgWrappedDelegate, enters a new epoch (which triggers HandleQueueMsg), and check if the message queue is consistent or not, and if the queue msgs are processed or not.
func FuzzHandleQueuedMsg_MsgWrappedDelegate(f *testing.F) {
f.Add(int64(11111))
f.Add(int64(22222))
f.Add(int64(55555))
f.Add(int64(12312))

f.Fuzz(func(t *testing.T, seed int64) {
rand.Seed(seed)

helper := testepoching.NewHelperWithValSet(t)
ctx, keeper, genAccs := helper.Ctx, helper.EpochingKeeper, helper.GenAccs
valSet0 := helper.EpochingKeeper.GetValidatorSet(helper.Ctx, 0)

// validator to be delegated
val := valSet0[0].Addr
valPower, err := helper.EpochingKeeper.GetValidatorVotingPower(ctx, 0, val)
require.NoError(t, err)

// get genesis account's address, whose holder will be the delegator
require.NotNil(t, genAccs)
require.NotEmpty(t, genAccs)
genAddr := genAccs[0].GetAddress()

// generate a random number of validators
numNewVals := rand.Intn(1000)
for i := 0; i < numNewVals; i++ {
helper.WrappedDelegate(genAddr, val, coin50.Amount)
}
// ensure the msgs are queued
epochMsgs := keeper.GetEpochMsgs(ctx)
require.Equal(t, numNewVals, len(epochMsgs))

// enter the 1st block and thus epoch 1
// Note that we missed epoch 0's BeginBlock/EndBlock and thus EpochMsgs are not handled
ctx = helper.GenAndApplyEmptyBlock()
// enter epoch 2
for i := uint64(0); i < keeper.GetParams(ctx).EpochInterval; i++ {
ctx = helper.GenAndApplyEmptyBlock()
}

// ensure queued msgs have been handled
queueLen := keeper.GetQueueLength(ctx)
require.Equal(t, uint64(0), queueLen)
epochMsgs = keeper.GetEpochMsgs(ctx)
require.Equal(t, 0, len(epochMsgs))

// ensure the voting power has been added w.r.t. the newly delegated tokens
valPower2, err := helper.EpochingKeeper.GetValidatorVotingPower(ctx, 2, val)
require.NoError(t, err)
addedPoWer := helper.StakingKeeper.TokensToConsensusPower(ctx, sdk.NewInt(int64(numNewVals*50)))
require.Equal(t, valPower+addedPoWer, valPower2)
})
}
8 changes: 5 additions & 3 deletions x/epoching/keeper/epoch_slashed_val_set_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"sort"
"testing"

"github.com/babylonchain/babylon/x/epoching/testepoching"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/require"
)
Expand All @@ -18,7 +19,8 @@ func FuzzSlashedValSet(f *testing.F) {
f.Fuzz(func(t *testing.T, seed int64) {
rand.Seed(seed)

app, ctx, keeper, _, _, _ := setupTestKeeperWithValSet(t)
helper := testepoching.NewHelperWithValSet(t)
ctx, keeper, stakingKeeper := helper.Ctx, helper.EpochingKeeper, helper.StakingKeeper
getValSet := keeper.GetValidatorSet(ctx, 0)

// slash a random subset of validators
Expand All @@ -27,7 +29,7 @@ func FuzzSlashedValSet(f *testing.F) {
for i := 0; i < numSlashed; i++ {
idx := rand.Intn(len(getValSet))
slashedVal := getValSet[idx]
app.StakingKeeper.Slash(ctx, sdk.ConsAddress(slashedVal.Addr), 0, slashedVal.Power, sdk.OneDec())
stakingKeeper.Slash(ctx, sdk.ConsAddress(slashedVal.Addr), 0, slashedVal.Power, sdk.OneDec())
// add the slashed validator to the slashed validator set
excpectedSlashedVals = append(excpectedSlashedVals, slashedVal.Addr)
// remove the slashed validator from the validator set in order to avoid slashing a validator more than once
Expand All @@ -44,7 +46,7 @@ func FuzzSlashedValSet(f *testing.F) {
}

// go to the 1st block and thus epoch 1
ctx = genAndApplyEmptyBlock(app, ctx)
ctx = helper.GenAndApplyEmptyBlock()
epochNumber := keeper.GetEpoch(ctx).EpochNumber
require.Equal(t, uint64(1), epochNumber)
// no validator is slashed in epoch 1
Expand Down
22 changes: 14 additions & 8 deletions x/epoching/keeper/epoch_val_set_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"math/rand"
"testing"

"github.com/babylonchain/babylon/x/epoching/testepoching"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/require"
)
Expand All @@ -17,27 +18,32 @@ func FuzzEpochValSet(f *testing.F) {
f.Fuzz(func(t *testing.T, seed int64) {
rand.Seed(seed)

app, ctx, keeper, _, _, valSet := setupTestKeeperWithValSet(t)
helper := testepoching.NewHelperWithValSet(t)
ctx, keeper := helper.Ctx, helper.EpochingKeeper
valSet := helper.StakingKeeper.GetLastValidators(helper.Ctx)
getValSet := keeper.GetValidatorSet(ctx, 0)
require.Equal(t, len(valSet.Validators), len(getValSet))
require.Equal(t, len(valSet), len(getValSet))
for i := range getValSet {
require.Equal(t, sdk.ValAddress(valSet.Validators[i].Address), getValSet[i].Addr)
consAddr, err := valSet[i].GetConsAddr()
require.NoError(t, err)
require.Equal(t, sdk.ValAddress(consAddr), getValSet[i].Addr)
}

// generate a random number of new blocks
numIncBlocks := rand.Uint64()%1000 + 1
for i := uint64(0); i < numIncBlocks; i++ {
ctx = genAndApplyEmptyBlock(app, ctx)
ctx = helper.GenAndApplyEmptyBlock()
}

// check whether the validator set remains the same or not
getValSet2 := keeper.GetValidatorSet(ctx, keeper.GetEpoch(ctx).EpochNumber)
require.Equal(t, len(valSet.Validators), len(getValSet2))
require.Equal(t, len(valSet), len(getValSet2))
for i := range getValSet2 {
require.Equal(t, sdk.ValAddress(valSet.Validators[i].Address), getValSet[i].Addr)
consAddr, err := valSet[i].GetConsAddr()
require.NoError(t, err)
require.Equal(t, sdk.ValAddress(consAddr), getValSet[i].Addr)
}
})
}

// TODO (stateful tests): create some random validators and check if the resulting validator set is consistent or not
// require mocking Msg(Wrapped)CreateValidator
// TODO (stateful tests): create some random validators and check if the resulting validator set is consistent or not (require mocking MsgWrappedCreateValidator)
6 changes: 4 additions & 2 deletions x/epoching/keeper/epochs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"math/rand"
"testing"

"github.com/babylonchain/babylon/x/epoching/testepoching"
"github.com/babylonchain/babylon/x/epoching/types"
"github.com/stretchr/testify/require"
)
Expand All @@ -17,7 +18,8 @@ func FuzzEpochs(f *testing.F) {
f.Fuzz(func(t *testing.T, seed int64) {
rand.Seed(seed)

app, ctx, keeper, _, _ := setupTestKeeper()
helper := testepoching.NewHelper(t)
ctx, keeper := helper.Ctx, helper.EpochingKeeper
// ensure that the epoch info is correct at the genesis
epoch := keeper.GetEpoch(ctx)
require.Equal(t, epoch.EpochNumber, uint64(0))
Expand All @@ -31,7 +33,7 @@ func FuzzEpochs(f *testing.F) {
// increment a random number of new blocks
numIncBlocks := rand.Uint64()%1000 + 1
for i := uint64(0); i < numIncBlocks; i++ {
ctx = genAndApplyEmptyBlock(app, ctx)
ctx = helper.GenAndApplyEmptyBlock()
}

// ensure that the epoch info is still correct
Expand Down
12 changes: 8 additions & 4 deletions x/epoching/keeper/grpc_query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"testing"

"github.com/babylonchain/babylon/testutil/datagen"
"github.com/babylonchain/babylon/x/epoching/testepoching"
"github.com/babylonchain/babylon/x/epoching/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/query"
Expand Down Expand Up @@ -36,7 +37,8 @@ func FuzzParamsQuery(f *testing.F) {
params.EpochInterval = uint64(rand.Int())
}

_, ctx, keeper, _, queryClient := setupTestKeeper()
helper := testepoching.NewHelper(t)
ctx, keeper, queryClient := helper.Ctx, helper.EpochingKeeper, helper.QueryClient
wctx := sdk.WrapSDKContext(ctx)
// if setParamsFlag == 0, set params
setParamsFlag := rand.Intn(2)
Expand Down Expand Up @@ -65,7 +67,8 @@ func FuzzCurrentEpoch(f *testing.F) {
f.Add(uint64(3333))

f.Fuzz(func(t *testing.T, increment uint64) {
_, ctx, keeper, _, queryClient := setupTestKeeper()
helper := testepoching.NewHelper(t)
ctx, keeper, queryClient := helper.Ctx, helper.EpochingKeeper, helper.QueryClient
wctx := sdk.WrapSDKContext(ctx)
for i := uint64(0); i < increment; i++ {
keeper.IncEpoch(ctx)
Expand Down Expand Up @@ -94,7 +97,8 @@ func FuzzEpochMsgs(f *testing.F) {
limit := uint64(rand.Int() % 100)

txidsMap := map[string]bool{}
_, ctx, keeper, _, queryClient := setupTestKeeper()
helper := testepoching.NewHelper(t)
ctx, keeper, queryClient := helper.Ctx, helper.EpochingKeeper, helper.QueryClient
wctx := sdk.WrapSDKContext(ctx)
// enque a random number of msgs with random txids
for i := uint64(0); i < numMsgs; i++ {
Expand All @@ -111,7 +115,7 @@ func FuzzEpochMsgs(f *testing.F) {
resp, err := queryClient.EpochMsgs(wctx, &req)
require.NoError(t, err)

require.Equal(t, min(uint64(len(txidsMap)), limit), uint64(len(resp.Msgs)))
require.Equal(t, testepoching.Min(uint64(len(txidsMap)), limit), uint64(len(resp.Msgs)))
for idx := range resp.Msgs {
_, ok := txidsMap[string(resp.Msgs[idx].TxId)]
require.True(t, ok)
Expand Down
Loading