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: more test infra and some fuzz tests on keeper functionalities #60

Merged
merged 80 commits into from
Jul 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
951dcf3
init
SebastianElvis Jun 24, 2022
af5ff8d
abci interface
SebastianElvis Jun 24, 2022
e12dd3f
module stuff
SebastianElvis Jun 24, 2022
d6333c1
slash without jail
SebastianElvis Jun 24, 2022
6cd242a
minor
SebastianElvis Jun 24, 2022
d997725
minor
SebastianElvis Jun 24, 2022
82eb108
apply mature unbonding fix
SebastianElvis Jun 27, 2022
d6d5996
avoid assertions
SebastianElvis Jun 27, 2022
a91c059
a lot
SebastianElvis Jun 27, 2022
6bc1fb3
fix order of beginblockers and endblockers
SebastianElvis Jun 27, 2022
729da0b
Merge branch 'main' into epoching-staking-code-migration
SebastianElvis Jun 28, 2022
3d5f5a1
don't touch evidence/slashing at the moment
SebastianElvis Jun 28, 2022
a6aa599
fix and make required staking functions a part of epoching
SebastianElvis Jun 28, 2022
34caaa5
minor
SebastianElvis Jun 28, 2022
97c36cd
add dependency to evidence and slashing
SebastianElvis Jun 28, 2022
8818a67
Merge branch 'epoching-staking-code-migration' into epoching-endblock…
SebastianElvis Jun 28, 2022
1b8de2f
minor
SebastianElvis Jun 28, 2022
3273562
minor
SebastianElvis Jun 28, 2022
bf09eb8
minor
SebastianElvis Jun 28, 2022
39b7d61
minor
SebastianElvis Jun 28, 2022
a06bbc1
Merge branch 'epoching-staking-code-migration' into epoching-endblock…
SebastianElvis Jun 28, 2022
602ffee
msgserver
SebastianElvis Jun 28, 2022
a766236
Merge branch 'main' into epoching-endblock-beginblock
SebastianElvis Jun 29, 2022
8a6a88c
order
SebastianElvis Jun 29, 2022
94e91e6
epoching hooks to staking
SebastianElvis Jun 29, 2022
fe44d45
BeforeValidatorSlashed hook in epoching
SebastianElvis Jun 29, 2022
be19c4f
BeforeValidatorSlashed hook
SebastianElvis Jun 29, 2022
12cfbf6
minor
SebastianElvis Jul 1, 2022
8b014f3
Merge branch 'main' into epoching-endblock-beginblock
SebastianElvis Jul 1, 2022
6e7872a
fix
SebastianElvis Jul 4, 2022
54c3292
minor
SebastianElvis Jul 4, 2022
dc8b09a
error to panic
SebastianElvis Jul 4, 2022
7c8fe31
hanlde queued msg
SebastianElvis Jul 4, 2022
b337667
Merge branch 'main' into epoching-slash-panicing
SebastianElvis Jul 4, 2022
6bad046
merge
SebastianElvis Jul 4, 2022
5d2cd5d
fix
SebastianElvis Jul 4, 2022
ebdc449
making stakingmsgserver private
SebastianElvis Jul 4, 2022
7ec30d4
txid for queuedmessage
SebastianElvis Jul 5, 2022
8f23255
router
SebastianElvis Jul 5, 2022
26b04af
minor
SebastianElvis Jul 5, 2022
237121f
setup test infra
SebastianElvis Jul 5, 2022
8fb65d7
sample tests
SebastianElvis Jul 5, 2022
805c431
Merge branch 'epoching-tests' into epoching-slash-panicing
SebastianElvis Jul 5, 2022
a2405f2
fix
SebastianElvis Jul 5, 2022
05ed1ae
Merge branch 'main' into epoching-slash-panicing
SebastianElvis Jul 6, 2022
2ec73fb
minor
SebastianElvis Jul 6, 2022
e50688c
fix
SebastianElvis Jul 6, 2022
eb2b31d
slashed val set schema
SebastianElvis Jul 7, 2022
f8ca14c
Merge branch 'main' into epoching-slash-panicing
SebastianElvis Jul 7, 2022
64a3cc1
Merge branch 'main' into epoching-slash-panicing
SebastianElvis Jul 7, 2022
d3dcfb8
prefix and other fixes
SebastianElvis Jul 8, 2022
bb7ca42
slash by voting power
SebastianElvis Jul 8, 2022
0439e57
Merge branch 'main' into epoching-slash-panicing
SebastianElvis Jul 8, 2022
9d0b65d
slashed voting power
SebastianElvis Jul 8, 2022
69164ba
error types
SebastianElvis Jul 8, 2022
29c3c2d
fix
SebastianElvis Jul 8, 2022
1808729
epoching: test infra and unit tests of keeper/types (#47)
SebastianElvis Jul 8, 2022
4a31892
wrap epoch
SebastianElvis Jul 8, 2022
af3e327
wrap epoch
SebastianElvis Jul 8, 2022
9750d21
rm unnecessary interfaces
SebastianElvis Jul 8, 2022
509c09e
fix
SebastianElvis Jul 8, 2022
abcdcaa
merge
SebastianElvis Jul 8, 2022
522d7f4
fix
SebastianElvis Jul 11, 2022
c8c60b0
replace sdk.Uint with uint64
SebastianElvis Jul 11, 2022
4ae0a62
fix EpochInterface
SebastianElvis Jul 11, 2022
0565c96
Merge branch 'main' into epoching-epoch-struct
SebastianElvis Jul 11, 2022
2cea378
getter of epoch type to keep functions consistent
SebastianElvis Jul 11, 2022
82dd3ae
fuzzepoch
SebastianElvis Jul 11, 2022
fbbcd4c
minor fixes
SebastianElvis Jul 11, 2022
a82ef68
Merge branch 'main' into epoching-keeper-tests
SebastianElvis Jul 12, 2022
b739661
some fuzz tests and infra
SebastianElvis Jul 12, 2022
fd1383f
minor
SebastianElvis Jul 12, 2022
faaada2
test intra and mark TODOs
SebastianElvis Jul 12, 2022
6d05839
extend to multiple genesis validators
SebastianElvis Jul 13, 2022
f3a1f28
fix
SebastianElvis Jul 13, 2022
efb1dde
fix ci
SebastianElvis Jul 13, 2022
e7d7f45
Merge branch 'main' into epoching-keeper-tests
SebastianElvis Jul 13, 2022
3278402
bug fix
SebastianElvis Jul 13, 2022
3fc6cab
fix
SebastianElvis Jul 14, 2022
a6cd3d6
TODOs
SebastianElvis Jul 14, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,15 @@ func NewBabylonApp(
stakingKeeper := stakingkeeper.NewKeeper(
appCodec, keys[stakingtypes.StoreKey], app.AccountKeeper, app.BankKeeper, app.GetSubspace(stakingtypes.ModuleName),
)

// NOTE: the epoching module has to be set before the chekpointing module, as the checkpointing module will have access to the epoching module
epochingKeeper := epochingkeeper.NewKeeper(
appCodec, keys[epochingtypes.StoreKey], keys[epochingtypes.StoreKey], app.GetSubspace(epochingtypes.ModuleName), &app.StakingKeeper,
aakoshh marked this conversation as resolved.
Show resolved Hide resolved
)
// add msgServiceRouter so that the epoching module can forward unwrapped messages to the staking module
epochingKeeper.SetMsgServiceRouter(app.BaseApp.MsgServiceRouter())
app.EpochingKeeper = epochingKeeper

app.MintKeeper = mintkeeper.NewKeeper(
appCodec, keys[minttypes.StoreKey], app.GetSubspace(minttypes.ModuleName), &stakingKeeper,
app.AccountKeeper, app.BankKeeper, authtypes.FeeCollectorName,
Expand Down Expand Up @@ -321,15 +330,6 @@ func NewBabylonApp(
),
)

// setup epoching keeper
// NOTE: the epoching module has to be set before the chekpointing module, as the checkpointing module will have access to the epoching module
epochingKeeper := epochingkeeper.NewKeeper(appCodec, keys[epochingtypes.StoreKey], keys[epochingtypes.StoreKey], app.GetSubspace(epochingtypes.ModuleName), &app.StakingKeeper)
// TODO: add modules that need to hook onto the epoching module here
epochingKeeper.SetHooks(epochingtypes.NewMultiEpochingHooks())
// add msgServiceRouter so that the epoching module can forward unwrapped messages to the staking module
epochingKeeper.SetMsgServiceRouter(app.BaseApp.MsgServiceRouter())
app.EpochingKeeper = epochingKeeper

btclightclientKeeper := *btclightclientkeeper.NewKeeper(appCodec, keys[btclightclienttypes.StoreKey], keys[btclightclienttypes.MemStoreKey], app.GetSubspace(btclightclienttypes.ModuleName))
btclightclientKeeper.SetHooks(btclightclienttypes.NewMultiBTCLightClientHooks())
app.BTCLightClientKeeper = btclightclientKeeper
Expand Down
23 changes: 15 additions & 8 deletions app/test_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func Setup(isCheckTx bool) *BabylonApp {
// that also act as delegators. For simplicity, each validator is bonded with a delegation
// of one consensus engine unit (10^6) in the default token of the babylon app from first genesis
// account. A Nop logger is set in BabylonApp.
func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs []authtypes.GenesisAccount, balances ...banktypes.Balance) *BabylonApp {
func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs []authtypes.GenesisAccount, balances ...banktypes.Balance) (*BabylonApp, sdk.Context) {
app, genesisState := setup(true, 5)
// set genesis accounts
authGenesis := authtypes.NewGenesisState(authtypes.DefaultParams(), genAccs)
Expand Down Expand Up @@ -120,22 +120,26 @@ func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs
}
validators = append(validators, validator)
delegations = append(delegations, stakingtypes.NewDelegation(genAccs[0].GetAddress(), val.Address.Bytes(), sdk.OneDec()))

}

// total bond amount = bond amount * number of validators
require.Equal(t, len(validators), len(delegations))
totalBondAmt := bondAmt.MulRaw(int64(len(validators)))

// set validators and delegations
stakingGenesis := stakingtypes.NewGenesisState(stakingtypes.DefaultParams(), validators, delegations)
genesisState[stakingtypes.ModuleName] = app.AppCodec().MustMarshalJSON(stakingGenesis)

totalSupply := sdk.NewCoins()
for _, b := range balances {
// add genesis acc tokens and delegated tokens to total supply
totalSupply = totalSupply.Add(b.Coins.Add(sdk.NewCoin(sdk.DefaultBondDenom, bondAmt))...)
totalSupply = totalSupply.Add(b.Coins.Add(sdk.NewCoin(sdk.DefaultBondDenom, totalBondAmt))...)
}

// add bonded amount to bonded pool module account
balances = append(balances, banktypes.Balance{
Address: authtypes.NewModuleAddress(stakingtypes.BondedPoolName).String(),
Coins: sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, bondAmt)},
Coins: sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, totalBondAmt)},
})

// update total supply
Expand All @@ -156,14 +160,17 @@ func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs

// commit genesis changes
app.Commit()
app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{
Height: app.LastBlockHeight() + 1,
height := app.LastBlockHeight() + 1
header := tmproto.Header{
Height: height,
AppHash: app.LastCommitID().Hash,
aakoshh marked this conversation as resolved.
Show resolved Hide resolved
ValidatorsHash: valSet.Hash(),
NextValidatorsHash: valSet.Hash(),
}})
}
app.BeginBlock(abci.RequestBeginBlock{Header: header})
ctx := app.BaseApp.NewContext(false, tmproto.Header{})

return app
return app, ctx
}

// SetupWithGenesisAccounts initializes a new BabylonApp with the provided genesis
Expand Down
53 changes: 53 additions & 0 deletions testutil/datagen/priv_validator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package datagen

import (
"github.com/tendermint/tendermint/crypto"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
tmtypes "github.com/tendermint/tendermint/types"

cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
)

// adapted from https://github.com/ClanNetwork/clan-network/blob/d00b1cc465/testutil/simapp/pv.go
// used for creating key pairs for genesis validators in tests

var _ tmtypes.PrivValidator = PV{}

// PV implements PrivValidator without any safety or persistence.
// Only use it for testing.
type PV struct {
PrivKey cryptotypes.PrivKey
}

func NewPV() PV {
return PV{ed25519.GenPrivKey()}
}

// GetPubKey implements PrivValidator interface
func (pv PV) GetPubKey() (crypto.PubKey, error) {
return cryptocodec.ToTmPubKeyInterface(pv.PrivKey.PubKey())
}

// SignVote implements PrivValidator interface
func (pv PV) SignVote(chainID string, vote *tmproto.Vote) error {
signBytes := tmtypes.VoteSignBytes(chainID, vote)
sig, err := pv.PrivKey.Sign(signBytes)
if err != nil {
return err
}
vote.Signature = sig
return nil
}

// SignProposal implements PrivValidator interface
func (pv PV) SignProposal(chainID string, proposal *tmproto.Proposal) error {
signBytes := tmtypes.ProposalSignBytes(chainID, proposal)
sig, err := pv.PrivKey.Sign(signBytes)
if err != nil {
return err
}
proposal.Signature = sig
return nil
}
5 changes: 3 additions & 2 deletions x/epoching/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ import (
func BeginBlocker(ctx sdk.Context, k keeper.Keeper, req abci.RequestBeginBlock) {
defer telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), telemetry.MetricKeyBeginBlocker)

// if this block is the first block of an epoch
// if this block is the first block of the next epoch
// note that we haven't incremented the epoch number yet
if k.GetEpoch(ctx).IsFirstBlock(ctx) {
epoch := k.GetEpoch(ctx)
if epoch.IsFirstBlockOfNextEpoch(ctx) {
// increase epoch number
IncEpoch := k.IncEpoch(ctx)
// init the slashed voting power of this new epoch
Expand Down
52 changes: 52 additions & 0 deletions x/epoching/keeper/epoch_msg_queue_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package keeper_test

import (
"math/rand"
"testing"

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

func FuzzEpochMsgQueue(f *testing.F) {
f.Add(int64(11111))
f.Add(int64(22222))
f.Add(int64(55555))
f.Add(int64(12312))
Comment on lines +13 to +16
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why bother with these? If something fails, I thought the application will save it into a place where it can act as a regression test.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is indeed the case when we run individual fuzz tests. However, CI will only run the test cases added by f.Add without trying other random values generated from the corpus. Will having more corpus be beneficial for CI? If not then I will keep only one of them.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, so you want it to run at least a few times. We discussed with @vitsalis that we could add -fuzztime to the CI to run it for a limited amount of iterations.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what you guys think about doing something like f.Add(time.Now().UnixMilli()) so the tests run as unit tests are not always the same, and you aren't forced to include this arbitrary looking boilerplate all the time. It would ensure that it runs them at least once, and if they fail then hopefully it prints the troublesome seed as well.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The counter argument was that it makes builds non-deterministic. It can be annoying if random tests fail sometimes, not other times, but over a long period of time it would catch more bugs than relying on the same seeds. We could even do something like addRandomSeeds(f, 100) to add exactly 100 random seeds, which is what other frameworks are doing (ie. they achieve 100 passes by default for each test, rather than run forever like Go).

Copy link
Contributor

@aakoshh aakoshh Jul 14, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ScalaCheck has CLI flags for the numbers, so maybe we could also support some env vars to adjust defaults. Although I never needed that, I was happy with 100 unless it took really long to generate the data and I had to lower it on a per-test or per-suite basis, like here

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we could add -fuzztime to the CI to run it for a limited amount of iterations.

Are you aware of any projects using such strategy? I feel that this requires a very powerful VM to run the CI. My CPU was super hot when executing fuzz tests and sometimes a fuzz test takes >10s to generate the initial corpus.

We could even do something like addRandomSeeds(f, 100) to add exactly 100 random seeds, which is what other frameworks are doing (ie. they achieve 100 passes by default for each test, rather than run forever like Go).

This is a good idea. Basically we limit the number of tries (rather than the running time) for fuzz tests. I will look into this approach and find a way to try it in the subsequent PRs. Hopefully the CI will be happy to do this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes the QuickCheck family runs 100 tests by default and it's up to you to tweak the numbers. I also want tests to finish in reasonable time, max 10 seconds, so if I see that they take longer then I have to reign in how much data I generate.

Maybe I don't need 1000 blocks with up to 100 transactions in each just to test something simple, and maybe I let my tree generation do too much branching and my tree of 10 depth is exponentially wide. Generating random bytes can also get out of hand, like opaque payloads, we don't need them to be hundreds of kilobytes long.

So it's a good indication of where time is not spent well.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And you are right I'd rather know that a particular test passed 100 runs than that some VM spent overall 1 minute testing all fuzz tests and may or may not have covered them equally.


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

_, ctx, keeper, _, _ := setupTestKeeper()
// 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))

// Enqueue a random number of msgs
numQueuedMsgs := rand.Uint64() % 100
for i := uint64(0); i < numQueuedMsgs; i++ {
msg := types.QueuedMessage{
TxId: sdk.Uint64ToBigEndian(i),
MsgId: sdk.Uint64ToBigEndian(i),
}
keeper.EnqueueMsg(ctx, msg)
}

// ensure that each msg in the queue is correct
epochMsgs := keeper.GetEpochMsgs(ctx)
for i, msg := range epochMsgs {
require.Equal(t, sdk.Uint64ToBigEndian(uint64(i)), msg.TxId)
require.Equal(t, sdk.Uint64ToBigEndian(uint64(i)), msg.MsgId)
require.Nil(t, msg.Msg)
Comment on lines +40 to +41
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may be worth creating a constructor method like NewQueuedMessage(txid, msg) and let it calculate the hash itself, so we're not able to generate invalid ones. Just an idea.

}

// after clearing the msg queue, ensure that the epoch msg queue is empty
keeper.ClearEpochMsgs(ctx)
require.Empty(t, keeper.GetEpochMsgs(ctx))
require.Equal(t, uint64(0), keeper.GetQueueLength(ctx))
})
}

// TODO (stateful tests): fuzz HandleQueueMsg. initialise some validators, let them submit some msgs and trigger HandleQueueMsg
// require mocking valid QueueMsgs
4 changes: 4 additions & 0 deletions x/epoching/keeper/epoch_slashed_val_set_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package keeper_test

// TODO (stateful tests): slash some random validators and check if the resulting (slashed) validator sets are consistent or not
// require mocking slashing
43 changes: 43 additions & 0 deletions x/epoching/keeper/epoch_val_set_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package keeper_test

import (
"math/rand"
"testing"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/require"
)

func FuzzEpochValSet(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)

app, ctx, keeper, _, _, valSet := setupTestKeeperWithValSet(t)
getValSet := keeper.GetValidatorSet(ctx, 0)
require.Equal(t, len(valSet.Validators), len(getValSet))
for i := range getValSet {
require.Equal(t, sdk.ValAddress(valSet.Validators[i].Address), 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)
}

// check whether the validator set remains the same or not
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay but why would it change? There are no transactions, and even if there were the test doesn't say how long an epoch is.

Shouldn't the test generate random registrations and check that the validator set doesn't change during an epoch, but it does at the end?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good idea! However this requires mocking MsgCreateValidator or even MsgWrappedCreateValidator that includes BLS stuff. I have added a TODO on this and will do it in the subsequent PRs.

getValSet2 := keeper.GetValidatorSet(ctx, keeper.GetEpoch(ctx).EpochNumber)
require.Equal(t, len(valSet.Validators), len(getValSet2))
for i := range getValSet2 {
require.Equal(t, sdk.ValAddress(valSet.Validators[i].Address), 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
47 changes: 47 additions & 0 deletions x/epoching/keeper/epochs_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package keeper_test

import (
"math/rand"
"testing"

"github.com/babylonchain/babylon/x/epoching/types"
"github.com/stretchr/testify/require"
)

func FuzzEpochs(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)

app, ctx, keeper, _, _ := setupTestKeeper()
// ensure that the epoch info is correct at the genesis
epoch := keeper.GetEpoch(ctx)
require.Equal(t, epoch.EpochNumber, uint64(0))
require.Equal(t, epoch.FirstBlockHeight, uint64(0))

// set a random epoch interval
epochInterval := rand.Uint64()%100 + 1
keeper.SetParams(ctx, types.Params{
EpochInterval: epochInterval,
})
// increment a random number of new blocks
numIncBlocks := rand.Uint64()%1000 + 1
for i := uint64(0); i < numIncBlocks; i++ {
ctx = genAndApplyEmptyBlock(app, ctx)
}

// ensure that the epoch info is still correct
expectedEpochNumber := numIncBlocks / epochInterval
if numIncBlocks%epochInterval > 0 {
expectedEpochNumber += 1
}
actualNewEpoch := keeper.GetEpoch(ctx)
require.Equal(t, expectedEpochNumber, actualNewEpoch.EpochNumber)
require.Equal(t, epochInterval, actualNewEpoch.CurrentEpochInterval)
require.Equal(t, (expectedEpochNumber-1)*epochInterval+1, actualNewEpoch.FirstBlockHeight)
})
}
Loading