Skip to content

Commit

Permalink
epoching: refactor test infra, mock messages and sample fuzz tests (#65)
Browse files Browse the repository at this point in the history
  • Loading branch information
SebastianElvis authored Jul 19, 2022
1 parent 88ff081 commit 5b07f34
Show file tree
Hide file tree
Showing 12 changed files with 469 additions and 198 deletions.
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

0 comments on commit 5b07f34

Please sign in to comment.