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: copy/paste necessary code from staking/evidence/slashing and make modifications #28

Merged
merged 17 commits into from
Jun 29, 2022
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
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
20 changes: 12 additions & 8 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ func NewBabylonApp(
),
)

app.EpochingKeeper = epochingkeeper.NewKeeper(appCodec, keys[epochingtypes.StoreKey], keys[epochingtypes.StoreKey], app.GetSubspace(epochingtypes.ModuleName))
app.EpochingKeeper = epochingkeeper.NewKeeper(appCodec, keys[epochingtypes.StoreKey], keys[epochingtypes.StoreKey], app.GetSubspace(epochingtypes.ModuleName), &app.StakingKeeper)
app.BTCLightClientKeeper = *btclightclientkeeper.NewKeeper(appCodec, keys[btclightclienttypes.StoreKey], keys[btclightclienttypes.MemStoreKey], app.GetSubspace(btclightclienttypes.ModuleName))
app.BtcCheckpointKeeper = btccheckpointkeeper.NewKeeper(appCodec, keys[btccheckpointtypes.StoreKey], keys[btccheckpointtypes.MemStoreKey], app.GetSubspace(btccheckpointtypes.ModuleName))
app.CheckpointingKeeper = checkpointingkeeper.NewKeeper(appCodec, keys[checkpointingtypes.StoreKey], keys[checkpointingtypes.MemStoreKey], app.GetSubspace(checkpointingtypes.ModuleName))
Expand Down Expand Up @@ -359,7 +359,7 @@ func NewBabylonApp(
evidence.NewAppModule(app.EvidenceKeeper),
params.NewAppModule(app.ParamsKeeper),
authzmodule.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry),
epoching.NewAppModule(appCodec, app.EpochingKeeper, app.AccountKeeper, app.BankKeeper),
epoching.NewAppModule(appCodec, app.EpochingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper),
btclightclient.NewAppModule(appCodec, app.BTCLightClientKeeper, app.AccountKeeper, app.BankKeeper),
btccheckpoint.NewAppModule(appCodec, app.BtcCheckpointKeeper, app.AccountKeeper, app.BankKeeper),
checkpointing.NewAppModule(appCodec, app.CheckpointingKeeper, app.AccountKeeper, app.BankKeeper),
Expand All @@ -381,21 +381,25 @@ func NewBabylonApp(
btccheckpointtypes.ModuleName,
checkpointingtypes.ModuleName,
)
app.mm.SetOrderEndBlockers(
crisistypes.ModuleName, govtypes.ModuleName, stakingtypes.ModuleName,
// TODO: there will be an architecture design on whether to modify slashing/evidence, specifically
// - how many validators can we slash in a single epoch and
// - whether and when to jail slashed validators
// app.mm.OrderBeginBlockers = append(app.mm.OrderBeginBlockers[:4], app.mm.OrderBeginBlockers[4+1:]...) // remove slashingtypes.ModuleName
// app.mm.OrderBeginBlockers = append(app.mm.OrderBeginBlockers[:4], app.mm.OrderBeginBlockers[4+1:]...) // remove evidencetypes.ModuleName

app.mm.SetOrderEndBlockers(crisistypes.ModuleName, govtypes.ModuleName, stakingtypes.ModuleName,
capabilitytypes.ModuleName, authtypes.ModuleName, banktypes.ModuleName, distrtypes.ModuleName,
slashingtypes.ModuleName, minttypes.ModuleName,
genutiltypes.ModuleName, evidencetypes.ModuleName, authz.ModuleName,
feegrant.ModuleName,
paramstypes.ModuleName, upgradetypes.ModuleName, vestingtypes.ModuleName,
// TODO: BBL doesn't want the staking module to update the validator set at the end of each block. We consider two approaches to fix this:
// - remove stakingtypes.ModuleName from here, and let `epoching.EndBlock` do everything
// - call `epoching.EndBlock` first but only to dequeue the delayed staking requests, then let `staking.EndBlock` take care of executing them and return the changeset.
epochingtypes.ModuleName,
btclightclienttypes.ModuleName,
btccheckpointtypes.ModuleName,
checkpointingtypes.ModuleName,
)
// BBL does not want EndBlock processing in staking
app.mm.OrderEndBlockers = append(app.mm.OrderEndBlockers[:2], app.mm.OrderEndBlockers[2+1:]...) // remove stakingtypes.ModuleName
Copy link
Contributor

Choose a reason for hiding this comment

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

I didn't think about that method! 😃


// NOTE: The genutils module must occur after staking so that pools are
// properly initialized with tokens from genesis accounts.
Expand Down Expand Up @@ -442,7 +446,7 @@ func NewBabylonApp(
params.NewAppModule(app.ParamsKeeper),
evidence.NewAppModule(app.EvidenceKeeper),
authzmodule.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry),
epoching.NewAppModule(appCodec, app.EpochingKeeper, app.AccountKeeper, app.BankKeeper),
epoching.NewAppModule(appCodec, app.EpochingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper),
btclightclient.NewAppModule(appCodec, app.BTCLightClientKeeper, app.AccountKeeper, app.BankKeeper),
btccheckpoint.NewAppModule(appCodec, app.BtcCheckpointKeeper, app.AccountKeeper, app.BankKeeper),
checkpointing.NewAppModule(appCodec, app.CheckpointingKeeper, app.AccountKeeper, app.BankKeeper),
Expand Down
2 changes: 2 additions & 0 deletions testutil/keeper/epoching.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ func EpochingKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) {
storeKey,
memStoreKey,
paramsSubspace,
// TODO: make this compile at the moment, will fix for integrated testing
nil,
)

ctx := sdk.NewContext(stateStore, tmproto.Header{}, false, log.NewNopLogger())
Expand Down
34 changes: 34 additions & 0 deletions x/epoching/abci.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package epoching

import (
"time"

"github.com/babylonchain/babylon/x/epoching/keeper"
"github.com/babylonchain/babylon/x/epoching/types"

stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"

"github.com/cosmos/cosmos-sdk/telemetry"
sdk "github.com/cosmos/cosmos-sdk/types"
abci "github.com/tendermint/tendermint/abci/types"
)

func BeginBlocker(ctx sdk.Context, k keeper.Keeper, req abci.RequestBeginBlock) {
defer telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), telemetry.MetricKeyBeginBlocker)

// TODO: unimplemented:
// - if the first block of an epoch,
// - increment epoch number
// - trigger hook and emit event
}

// Called every block, update validator set
func EndBlocker(ctx sdk.Context, k keeper.Keeper) []abci.ValidatorUpdate {
defer telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), telemetry.MetricKeyEndBlocker)
defer telemetry.ModuleMeasureSince(stakingtypes.ModuleName, time.Now(), telemetry.MetricKeyEndBlocker)

// TODO: unimplemented:
// - if an epoch is newly checkpointed, make unbonding validators/delegations in this epoch unbonded
Copy link
Contributor

Choose a reason for hiding this comment

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

I [put this in the diagram to happen when the BTC checkpoint is confirmed, mostly because this is the easiest in terms of book-keeping: I can clearly see when a checkpoint is going confirmed the first time. To do it at the end would be more difficult, need to capture before and after.

I also thought it's not actually the epoch's job to know about checkpointing, and that release is related to checkpointing, so it should be in the checkpointing module.

Copy link
Member Author

Choose a reason for hiding this comment

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

I was meaning that the epoching module gets the epoch's chechpoint status from the checkpointing module, rather than judging the status by itself. Is my understanding correct and consistent with yours?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, but I mean I'm not sure that the epoching module even needs a notion of status. To put it differently, it doesn't have to know that it's being checkpointed. It knows that it has ended, and it can tell other modules what the last block was, but those dependant modules can figure out on their own what they need to do. It just so happens that the checkpointing module needs the last commit hash for its own purposes, and it will use the checkpointing status as a requirement to release unbonding tokens. But the epoching can be oblivious to that.

Copy link
Member Author

Choose a reason for hiding this comment

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

It just so happens that the checkpointing module needs the last commit hash for its own purposes, and it will use the checkpointing status as a requirement to release unbonding tokens. But the epoching can be oblivious to that.

Checkpoint-assisted unbonding is a part of the epoching module rather than checkpointing, right?

One of the main reasons that checkpoint-assisted unbonding fits the epoching module better is that, the checkpoint-assisted unbonding depends on the staking module (especially the "mature" queues), maintained by the epoching module.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think we agreed with @fishermanymc that the release of unbonding tokens doesn't need to be tied to the epoch.

You can imagine using just epochs, with 21 days unbonding, it's fine. But because we are doing checkpointing, we can release tokens earlier, as soon as the checkpoints are confirmed. Therefore it's associated with checkpoints, not epochs. It happens in the middle of the next epoch, depends on BTC, not the next epoch boundary.

Epochs manage the delayed staking indeed, but they only manage the inputs. The maturing queues are managed by the staking module itself, it doesn't need further input from the epochs. It just happens to be that we can use the epochs as a bucket for the confirmation height and the time step function - instead of maturing in 21 days, we take manual control of setting the height which we consider mature. But again, this doesn't depend on any active participation from the epoching module.

Copy link
Member Author

Choose a reason for hiding this comment

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

How about we do the following?

  • The epoching module maintains the modified version of staking (e.g., the ApplyMatureUnbonding thing)
  • Whenever an epoch is checkpointed, the checkpointing module invokes epochingKeeper.ApplyMatureUnbonding in order to unbond mature validators/delegations?

This way each module does its own thing, and we only have a dependency from checkpointing to epoching (instead of being the other way where epoching hooks to the EpochConfirmed hook in the checkpointing module).

Choose a reason for hiding this comment

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

Thanks @SebastianElvis and @aakoshh . The BTC/Babylon-specific bond release condition is that all the epochs up to the epoch where the unbonding request is submitted are confirmed. The bond release does not have to happen at the epoch boundary unless there are implementation level limitations preventing us from doing this.

// - if reaching an epoch boundary, execute validator-related msgs (bonded -> unbonding)
return nil
Copy link
Contributor

Choose a reason for hiding this comment

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

Doesn't matter too much, but you could return an empty array like the rest of the modules. I say doesn't matter because if we never call the staking module at all the app won't work anyway. Might as well panic, to make sure this doesn't go unnoticed.

Copy link
Member Author

Choose a reason for hiding this comment

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

Do we really need to copy paste slashing and evidence handling? If we want those to be processed immediately, why not just let nature take its course?

Default operations in slashing/evidence handling include both slashing and jailing. We want the slashing part but not the jailing part, right?

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh, I don't know much about jailing. What would happen if we allow it to go through?

Copy link
Member Author

Choose a reason for hiding this comment

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

When a validator is jailed, then:

  1. It loses all voting power (https://github.com/cosmos/cosmos-sdk/blob/v0.45.5/x/staking/keeper/val_state_change.go#L259-L268).
  2. The validator's status Jailed becomes true. To be unjailed, the validator needs to submit a message MsgUnjail and redo self-delegation (https://github.com/cosmos/cosmos-sdk/blob/v0.45.5/x/slashing/keeper/unjail.go#L9-L63).

If we allow jailing, then 1 will change the validator set within an epoch, and MsgUnjail in 2 needs to be delayed as well. The proposal 4 at https://babylon-chain.atlassian.net/wiki/spaces/BABYLON/pages/14745602/Four+proposals+on+handling+slashed+validators that we agreed upon gets rid of the jailing part due to such complexity.

Copy link
Contributor

Choose a reason for hiding this comment

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

Okay, so jailing does remove the power and does change the validator set, but only temporarily, without slashing.

I don't know if this has a big impact on our epochs. I'm a bit lost, I thought we can let slashing happen immediately, which changes some of the power, and it sounds like jailing has a similar effect, so as long as it's done in moderation, the system should keep working.

Because you can't replicate the whole behaviour with copy-pasting, I would not include that part in this PR. What we are doing is not functionally equivalent to what the SDK is doing, therefore it is unacceptable IMO. We can't ignore certain bits on the basis that we may or may not be able to fix it later, when we don't even understand what we are breaking.

I would first restrict ourselves to dealing with the delayed staking, and have another go at consulting with Frojdi about whether we can just let jailing happen in the middle of the epoch.

@fishermanymc wdyt?

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't know if this has a big impact on our epochs. I'm a bit lost, I thought we can let slashing happen immediately, which changes some of the power, and it sounds like jailing has a similar effect, so as long as it's done in moderation, the system should keep working.

A potential issue is as follows. Assuming the system slashes only a part of its stake (say, 50%) of a validator, then:

  • if we jail it, then it is removed from the validator set from a node's view, but remains in the validator set from a checkpoint's view (as it's included in the bitmap).
  • if we don't jail it, then the validator set is consistent from a node or a checkpoint's view.

Because you can't replicate the whole behaviour with copy-pasting, I would not include that part in this PR.

Agree with this one. At the moment we have limited understanding on this part and the modification might break the system. At least the vanilla evidence/slashing modules will still work when only few validators are slashed.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes you are right, if we don't slash/jail then the validator set won't change from what it was at the beginning of the epoch and everyone in the bitmap is still okay to present a BLS signature.

To our advantage in this is that

  • we only need +1/3 of the validators to send BLS signatures
  • what needs to be signed comes from the Babylon chain, produced by the remaining validators, so the BLS signatures of the slashed validators should still be okay

Is that true? If we slash +1/3 then these dishonest validators can produce a BLS signature on their own, but in order to convince anyone's Tendermint node to go to an adversarial fork, you would need +2/3 to be dishonest.

What the slashed validators can do is to submit what looks like a "bogus" checkpoint, with their valid signatures, and send the application down this path. Looks like we have to be careful in that situation not to over react and kill Tendermint.

My understanding so far has been that:

  1. We start Epoch_n, and take a snapshot of who the ValidatorSet_n is, and their BLS signatures.
  2. We start Epoch_n+1; the commit hash over Epoch_n becomes known, produced by +2/3 of ValidatorSet_n.
  3. We collect BLS signatures from +1/3 members of ValidatorSet_n; we produce the raw checkpoint.

If we took the snapshot for ValidatorSet_n at the end of Epoch_n, we would have only the people who weren't slashed. Is it important to use the validators from the beginning? If we already know that only slashing can influence it during an epoch?

I suppose we can always discard BLS signatures from slashed validators during collection, and thus reject checkpoints signed by them as well, so we would know that an honest Tendermint validator set would not produce such a checkpoint.

Ultimately, in each epoch we assume that +2/3rd are honest, and if we have to slash +1/3rd we have just proven that assumption to be wrong. Not sure if at that point if the +1/3rd dishonest people need to produce a real alternative fork, or just pretend to have signed a hidden fork, for us to conclude that Babylon failed.

@fishermanymc wdyt?

Choose a reason for hiding this comment

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

This is a complicated topic.

Option-1: If slashing is 100%, then BLS signatures from the slashed validators are useless and should be ignored during signature aggregation. This is because even if they create an attacking QC and get caught later, they have nothing more to be slashed. These are the lunatic malicious validators here: https://babylon-chain.atlassian.net/wiki/spaces/BABYLON/pages/15597569/How+Many+Validators+Can+Babylon+Slash+During+an+Epoch+WIP#3.-Tendermint%E2%80%99s-Native-Slashing-Capacity-in-One-Block

Option-2: If slashing is less than 100%, then the slashed nodes still have some stake in the system and thus are motivated to sign genuine BLS to get unbonded.

There seems also theoretical tradeoff between how many to slash and how many BLS signatures should be collected, which affects the security - liveness tradeoff. David and Nusret are working on this.

As our first pass, let's 1) not delay any slashing, and 2) ask the checkpointing module to only accept BLS signatures from unslashed validators from the original validator set at the beginning of the epoch. The aggregated power should be min(1/3, 1-X), where X is the slashed power. @gitferry , you are also a stakeholder.

Copy link
Member Author

@SebastianElvis SebastianElvis Jun 28, 2022

Choose a reason for hiding this comment

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

Thanks for the insightful discussions Akosh and Fisher! I also have a feeling that how many to slash and whether to jail seem to have connection with some fundamental trade-offs. Given that we are at the MVP phase and David and Nusret are working on related issues, at the moment let's follow the minimalist 2/3-secure approach proposed above, at least in this PR:

  • Follow Cosmos SDK's original evidence/slashing implementations with both jailing and slashing
  • Reject all BLS signatures from unslashed validators, even if they were in the validator set at the epoch beginning

}
3 changes: 3 additions & 0 deletions x/epoching/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ type (
memKey sdk.StoreKey
hooks types.EpochingHooks
paramstore paramtypes.Subspace
stk types.StakingKeeper
}
)

Expand All @@ -29,6 +30,7 @@ func NewKeeper(
storeKey,
memKey sdk.StoreKey,
ps paramtypes.Subspace,
stk types.StakingKeeper,
) Keeper {
// set KeyTable if it has not already been set
if !ps.HasKeyTable() {
Expand All @@ -41,6 +43,7 @@ func NewKeeper(
memKey: memKey,
paramstore: ps,
hooks: nil,
stk: stk,
}
}

Expand Down
110 changes: 110 additions & 0 deletions x/epoching/keeper/modified_staking.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package keeper

import (
abci "github.com/tendermint/tendermint/abci/types"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/staking/types"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
)

// ApplyMatureUnbonding
// - unbonds all mature validators/delegations, and
// - finishes all mature redelegations
// in the corresponding queues, where
// - an unbonding/redelegation becomes mature when its corresponding epoch and all previous epochs have been checkpointed.
// Triggered by the checkpointing module upon the above condition.
// (adapted from https://github.com/cosmos/cosmos-sdk/blob/v0.45.5/x/staking/keeper/val_state_change.go#L32-L91)
func (k *Keeper) ApplyMatureUnbonding(ctx sdk.Context, epochBoundaryHeader tmproto.Header) {
currHeader := ctx.BlockHeader()

// unbond all mature validators till the epoch boundary from the unbonding queue
ctx.WithBlockHeader(epochBoundaryHeader)
k.stk.UnbondAllMatureValidators(ctx)
ctx.WithBlockHeader(currHeader)

// get all mature unbonding delegations the epoch boundary from the ubd queue.
ctx.WithBlockHeader(epochBoundaryHeader)
matureUnbonds := k.stk.DequeueAllMatureUBDQueue(ctx, epochBoundaryHeader.Time)
ctx.WithBlockHeader(currHeader)
// unbond all mature delegations
for _, dvPair := range matureUnbonds {
addr, err := sdk.ValAddressFromBech32(dvPair.ValidatorAddress)
if err != nil {
panic(err)
}
delegatorAddress, err := sdk.AccAddressFromBech32(dvPair.DelegatorAddress)
if err != nil {
panic(err)
}
balances, err := k.stk.CompleteUnbonding(ctx, delegatorAddress, addr)
if err != nil {
continue
}

ctx.EventManager().EmitEvent(
sdk.NewEvent(
types.EventTypeCompleteUnbonding,
sdk.NewAttribute(sdk.AttributeKeyAmount, balances.String()),
sdk.NewAttribute(types.AttributeKeyValidator, dvPair.ValidatorAddress),
sdk.NewAttribute(types.AttributeKeyDelegator, dvPair.DelegatorAddress),
),
)
}

// get all mature redelegations till the epoch boundary from the red queue.
ctx.WithBlockHeader(epochBoundaryHeader)
matureRedelegations := k.stk.DequeueAllMatureRedelegationQueue(ctx, epochBoundaryHeader.Time)
ctx.WithBlockHeader(currHeader)
// finish all mature redelegations
for _, dvvTriplet := range matureRedelegations {
valSrcAddr, err := sdk.ValAddressFromBech32(dvvTriplet.ValidatorSrcAddress)
if err != nil {
panic(err)
}
valDstAddr, err := sdk.ValAddressFromBech32(dvvTriplet.ValidatorDstAddress)
if err != nil {
panic(err)
}
delegatorAddress, err := sdk.AccAddressFromBech32(dvvTriplet.DelegatorAddress)
if err != nil {
panic(err)
}
balances, err := k.stk.CompleteRedelegation(
ctx,
delegatorAddress,
valSrcAddr,
valDstAddr,
)
if err != nil {
continue
}

ctx.EventManager().EmitEvent(
sdk.NewEvent(
types.EventTypeCompleteRedelegation,
sdk.NewAttribute(sdk.AttributeKeyAmount, balances.String()),
sdk.NewAttribute(types.AttributeKeyDelegator, dvvTriplet.DelegatorAddress),
sdk.NewAttribute(types.AttributeKeySrcValidator, dvvTriplet.ValidatorSrcAddress),
sdk.NewAttribute(types.AttributeKeyDstValidator, dvvTriplet.ValidatorDstAddress),
),
)
}
}

// ApplyAndReturnValidatorSetUpdates applies and return accumulated updates to the bonded validator set, including
// * Updates the active validator set as keyed by LastValidatorPowerKey.
// * Updates the total power as keyed by LastTotalPowerKey.
// * Updates validator status' according to updated powers.
// * Updates the fee pool bonded vs not-bonded tokens.
// * Updates relevant indices.
// Triggered upon every epoch.
// (adapted from https://github.com/cosmos/cosmos-sdk/blob/v0.45.5/x/staking/keeper/val_state_change.go#L18-L30)
func (k *Keeper) ApplyAndReturnValidatorSetUpdates(ctx sdk.Context) []abci.ValidatorUpdate {
validatorUpdates, err := k.stk.ApplyAndReturnValidatorSetUpdates(ctx)
if err != nil {
panic(err)
}

return validatorUpdates
}
16 changes: 7 additions & 9 deletions x/epoching/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,20 +102,22 @@ type AppModule struct {
keeper keeper.Keeper
accountKeeper types.AccountKeeper
bankKeeper types.BankKeeper
// TODO: add dependencies to staking, slashing and evidence
stakingKeeper types.StakingKeeper
}

func NewAppModule(
cdc codec.Codec,
keeper keeper.Keeper,
accountKeeper types.AccountKeeper,
bankKeeper types.BankKeeper,
stakingKeeper types.StakingKeeper,
) AppModule {
return AppModule{
AppModuleBasic: NewAppModuleBasic(cdc),
keeper: keeper,
accountKeeper: accountKeeper,
bankKeeper: bankKeeper,
stakingKeeper: stakingKeeper,
}
}

Expand Down Expand Up @@ -167,14 +169,10 @@ func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.Raw
// ConsensusVersion implements ConsensusVersion.
func (AppModule) ConsensusVersion() uint64 { return 2 }

// BeginBlock executes all ABCI BeginBlock logic respective to the capability module.
func (am AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {
// TODO: trigger BeginBlock stuff upon the first block of an epoch
func (am AppModule) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) {
BeginBlocker(ctx, am.keeper, req)
}

// EndBlock executes all ABCI EndBlock logic respective to the capability module. It
// returns no validator updates.
func (am AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate {
// TODO: trigger EndBlock stuff upon the last block of an epoch
return []abci.ValidatorUpdate{}
func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate {
return EndBlocker(ctx, am.keeper)
}
20 changes: 17 additions & 3 deletions x/epoching/types/expected_keepers.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
package types

import (
"time"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
abci "github.com/tendermint/tendermint/abci/types"

stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
)

// AccountKeeper defines the expected account keeper used for simulations (noalias)
type AccountKeeper interface {
GetAccount(ctx sdk.Context, addr sdk.AccAddress) types.AccountI
GetAccount(ctx sdk.Context, addr sdk.AccAddress) authtypes.AccountI
// Methods imported from account should be defined here
}

Expand All @@ -17,7 +22,16 @@ type BankKeeper interface {
// Methods imported from bank should be defined here
}

// TODO: add interfaces of staking, slashing and evidence used in epoching
// StakingKeeper defines the staking module interface contract needed by the
// epoching module.
type StakingKeeper interface {
UnbondAllMatureValidators(ctx sdk.Context)
DequeueAllMatureUBDQueue(ctx sdk.Context, currTime time.Time) (matureUnbonds []stakingtypes.DVPair)
CompleteUnbonding(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) (sdk.Coins, error)
DequeueAllMatureRedelegationQueue(ctx sdk.Context, currTime time.Time) (matureRedelegations []stakingtypes.DVVTriplet)
CompleteRedelegation(ctx sdk.Context, delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress) (sdk.Coins, error)
ApplyAndReturnValidatorSetUpdates(ctx sdk.Context) (updates []abci.ValidatorUpdate, err error)
}

// Event Hooks
// These can be utilized to communicate between a staking keeper and another
Expand Down