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

refactor(x/slashing)!: use kvStoreService, context.Context and return errors #16246

Merged
merged 20 commits into from
May 30, 2023
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ Ref: https://keepachangelog.com/en/1.0.0/

### API Breaking Changes

* (x/slashing) [#16246](https://github.com/cosmos/cosmos-sdk/issues/16246) `NewKeeper` now takes a `KVStoreService` instead of a `StoreKey`, and methods in the `Keeper` now take a `context.Context` instead of a `sdk.Context` and return an `error`.
* (x/mint) [#16179](https://github.com/cosmos/cosmos-sdk/issues/16179) `NewKeeper` now takes a `KVStoreService` instead of a `StoreKey`, and methods in the `Keeper` now take a `context.Context` instead of a `sdk.Context` and return an `error`.
* (x/crisis) [#16216](https://github.com/cosmos/cosmos-sdk/issues/16216) `NewKeeper` now takes a `KVStoreService` instead of a `StoreKey`, methods in the `Keeper` now take a `context.Context` instead of a `sdk.Context` and return an `error` instead of panicking.
* (x/gov) [#15988](https://github.com/cosmos/cosmos-sdk/issues/15988) `NewKeeper` now takes a `KVStoreService` instead of a `StoreKey`, methods in the `Keeper` now take a `context.Context` instead of a `sdk.Context` and return an `error` (instead of panicking or returning a `found bool`). Iterators callback functions now return an error instead of a `bool`.
Expand Down
4 changes: 3 additions & 1 deletion UPGRADING.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,9 @@ The following modules `NewKeeper` function now take a `KVStoreService` instead o
* `x/gov`
* `x/mint`
* `x/nft`
* `x/slashing`

User manually wiring their chain need to use the `runtime.NewKVStoreService` method to create a `KVStoreService` from a `StoreKey`:
Users manually wiring their chain need to use the `runtime.NewKVStoreService` method to create a `KVStoreService` from a `StoreKey`:

```diff
app.ConsensusParamsKeeper = consensusparamkeeper.NewKeeper(
Expand All @@ -105,6 +106,7 @@ The following modules' `Keeper` methods now take in a `context.Context` instead
* `x/distribution`
* `x/evidence`
* `x/gov`
* `x/slashing`

**Users using depinject do not need any changes, this is automatically done for them.**

Expand Down
2 changes: 1 addition & 1 deletion simapp/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ func NewSimApp(
app.DistrKeeper = distrkeeper.NewKeeper(appCodec, runtime.NewKVStoreService(keys[distrtypes.StoreKey]), app.AccountKeeper, app.BankKeeper, app.StakingKeeper, authtypes.FeeCollectorName, authtypes.NewModuleAddress(govtypes.ModuleName).String())

app.SlashingKeeper = slashingkeeper.NewKeeper(
appCodec, legacyAmino, keys[slashingtypes.StoreKey], app.StakingKeeper, authtypes.NewModuleAddress(govtypes.ModuleName).String(),
appCodec, legacyAmino, runtime.NewKVStoreService(keys[slashingtypes.StoreKey]), app.StakingKeeper, authtypes.NewModuleAddress(govtypes.ModuleName).String(),
)

invCheckPeriod := cast.ToUint(appOpts.Get(server.FlagInvCheckPeriod))
Expand Down
2 changes: 1 addition & 1 deletion tests/integration/evidence/keeper/infraction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ func initFixture(t testing.TB) *fixture {

stakingKeeper := stakingkeeper.NewKeeper(cdc, keys[stakingtypes.StoreKey], accountKeeper, bankKeeper, authority.String())

slashingKeeper := slashingkeeper.NewKeeper(cdc, codec.NewLegacyAmino(), keys[slashingtypes.StoreKey], stakingKeeper, authority.String())
slashingKeeper := slashingkeeper.NewKeeper(cdc, codec.NewLegacyAmino(), runtime.NewKVStoreService(keys[slashingtypes.StoreKey]), stakingKeeper, authority.String())

evidenceKeeper := keeper.NewKeeper(cdc, runtime.NewKVStoreService(keys[evidencetypes.StoreKey]), stakingKeeper, slashingKeeper, address.NewBech32Codec("cosmos"), runtime.ProvideCometInfoService())
router := evidencetypes.NewRouter()
Expand Down
96 changes: 63 additions & 33 deletions tests/integration/slashing/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ func initFixture(t testing.TB) *fixture {

stakingKeeper := stakingkeeper.NewKeeper(cdc, keys[stakingtypes.StoreKey], accountKeeper, bankKeeper, authority.String())

slashingKeeper := slashingkeeper.NewKeeper(cdc, &codec.LegacyAmino{}, keys[slashingtypes.StoreKey], stakingKeeper, authority.String())
slashingKeeper := slashingkeeper.NewKeeper(cdc, &codec.LegacyAmino{}, runtime.NewKVStoreService(keys[slashingtypes.StoreKey]), stakingKeeper, authority.String())

bankModule := bank.NewAppModule(cdc, bankKeeper, accountKeeper, nil)
stakingModule := staking.NewAppModule(cdc, stakingKeeper, accountKeeper, bankKeeper, nil)
Expand Down Expand Up @@ -214,31 +214,35 @@ func TestHandleNewValidator(t *testing.T) {
pks := simtestutil.CreateTestPubKeys(1)
addr, val := f.valAddrs[0], pks[0]
tstaking := stakingtestutil.NewHelper(t, f.ctx, f.stakingKeeper)
f.ctx = f.ctx.WithBlockHeight(f.slashingKeeper.SignedBlocksWindow(f.ctx) + 1)
signedBlocksWindow, err := f.slashingKeeper.SignedBlocksWindow(f.ctx)
assert.NilError(t, err)
f.ctx = f.ctx.WithBlockHeight(signedBlocksWindow + 1)

f.slashingKeeper.AddPubkey(f.ctx, pks[0])
assert.NilError(t, f.slashingKeeper.AddPubkey(f.ctx, pks[0]))

info := slashingtypes.NewValidatorSigningInfo(sdk.ConsAddress(val.Address()), f.ctx.BlockHeight(), int64(0), time.Unix(0, 0), false, int64(0))
f.slashingKeeper.SetValidatorSigningInfo(f.ctx, sdk.ConsAddress(val.Address()), info)
err = f.slashingKeeper.SetValidatorSigningInfo(f.ctx, sdk.ConsAddress(val.Address()), info)
assert.NilError(t, err)

// Validator created
amt := tstaking.CreateValidatorWithValPower(addr, val, 100, true)

f.stakingKeeper.EndBlocker(f.ctx)
_, err = f.stakingKeeper.EndBlocker(f.ctx)
assert.NilError(t, err)
assert.DeepEqual(
t, f.bankKeeper.GetAllBalances(f.ctx, sdk.AccAddress(addr)),
sdk.NewCoins(sdk.NewCoin(f.stakingKeeper.GetParams(f.ctx).BondDenom, testutil.InitTokens.Sub(amt))),
)
assert.DeepEqual(t, amt, f.stakingKeeper.Validator(f.ctx, addr).GetBondedTokens())

// Now a validator, for two blocks
f.slashingKeeper.HandleValidatorSignature(f.ctx, val.Address(), 100, comet.BlockIDFlagCommit)
f.ctx = f.ctx.WithBlockHeight(f.slashingKeeper.SignedBlocksWindow(f.ctx) + 2)
f.slashingKeeper.HandleValidatorSignature(f.ctx, val.Address(), 100, comet.BlockIDFlagAbsent)
assert.NilError(t, f.slashingKeeper.HandleValidatorSignature(f.ctx, val.Address(), 100, comet.BlockIDFlagCommit))
f.ctx = f.ctx.WithBlockHeight(signedBlocksWindow + 2)
assert.NilError(t, f.slashingKeeper.HandleValidatorSignature(f.ctx, val.Address(), 100, comet.BlockIDFlagAbsent))

info, found := f.slashingKeeper.GetValidatorSigningInfo(f.ctx, sdk.ConsAddress(val.Address()))
assert.Assert(t, found)
assert.Equal(t, f.slashingKeeper.SignedBlocksWindow(f.ctx)+1, info.StartHeight)
assert.Equal(t, signedBlocksWindow+1, info.StartHeight)
assert.Equal(t, int64(2), info.IndexOffset)
assert.Equal(t, int64(1), info.MissedBlocksCounter)
assert.Equal(t, time.Unix(0, 0).UTC(), info.JailedUntil)
Expand All @@ -262,30 +266,41 @@ func TestHandleAlreadyJailed(t *testing.T) {
power := int64(100)
tstaking := stakingtestutil.NewHelper(t, f.ctx, f.stakingKeeper)

f.slashingKeeper.AddPubkey(f.ctx, pks[0])
err := f.slashingKeeper.AddPubkey(f.ctx, pks[0])
assert.NilError(t, err)

info := slashingtypes.NewValidatorSigningInfo(sdk.ConsAddress(val.Address()), f.ctx.BlockHeight(), int64(0), time.Unix(0, 0), false, int64(0))
f.slashingKeeper.SetValidatorSigningInfo(f.ctx, sdk.ConsAddress(val.Address()), info)
assert.NilError(t, f.slashingKeeper.SetValidatorSigningInfo(f.ctx, sdk.ConsAddress(val.Address()), info))

amt := tstaking.CreateValidatorWithValPower(addr, val, power, true)

f.stakingKeeper.EndBlocker(f.ctx)
_, err = f.stakingKeeper.EndBlocker(f.ctx)
assert.NilError(t, err)

signedBlocksWindow, err := f.slashingKeeper.SignedBlocksWindow(f.ctx)
assert.NilError(t, err)

// 1000 first blocks OK
height := int64(0)
for ; height < f.slashingKeeper.SignedBlocksWindow(f.ctx); height++ {
for ; height < signedBlocksWindow; height++ {
f.ctx = f.ctx.WithBlockHeight(height)
f.slashingKeeper.HandleValidatorSignature(f.ctx, val.Address(), power, comet.BlockIDFlagCommit)
err = f.slashingKeeper.HandleValidatorSignature(f.ctx, val.Address(), power, comet.BlockIDFlagCommit)
assert.NilError(t, err)
}

minSignedPerWindow, err := f.slashingKeeper.MinSignedPerWindow(f.ctx)
assert.NilError(t, err)

// 501 blocks missed
for ; height < f.slashingKeeper.SignedBlocksWindow(f.ctx)+(f.slashingKeeper.SignedBlocksWindow(f.ctx)-f.slashingKeeper.MinSignedPerWindow(f.ctx))+1; height++ {
for ; height < signedBlocksWindow+(signedBlocksWindow-minSignedPerWindow)+1; height++ {
f.ctx = f.ctx.WithBlockHeight(height)
f.slashingKeeper.HandleValidatorSignature(f.ctx, val.Address(), power, comet.BlockIDFlagAbsent)
err = f.slashingKeeper.HandleValidatorSignature(f.ctx, val.Address(), power, comet.BlockIDFlagAbsent)
assert.NilError(t, err)
}

// end block
f.stakingKeeper.EndBlocker(f.ctx)
_, err = f.stakingKeeper.EndBlocker(f.ctx)
assert.NilError(t, err)

// validator should have been jailed and slashed
validator, _ := f.stakingKeeper.GetValidatorByConsAddr(f.ctx, sdk.GetConsAddress(val))
Expand All @@ -297,7 +312,7 @@ func TestHandleAlreadyJailed(t *testing.T) {

// another block missed
f.ctx = f.ctx.WithBlockHeight(height)
f.slashingKeeper.HandleValidatorSignature(f.ctx, val.Address(), power, comet.BlockIDFlagAbsent)
assert.NilError(t, f.slashingKeeper.HandleValidatorSignature(f.ctx, val.Address(), power, comet.BlockIDFlagAbsent))

// validator should not have been slashed twice
validator, _ = f.stakingKeeper.GetValidatorByConsAddr(f.ctx, sdk.GetConsAddress(val))
Expand All @@ -324,10 +339,10 @@ func TestValidatorDippingInAndOut(t *testing.T) {
tstaking := stakingtestutil.NewHelper(t, f.ctx, f.stakingKeeper)
valAddr := sdk.ValAddress(addr)

f.slashingKeeper.AddPubkey(f.ctx, pks[0])
assert.NilError(t, f.slashingKeeper.AddPubkey(f.ctx, pks[0]))

info := slashingtypes.NewValidatorSigningInfo(consAddr, f.ctx.BlockHeight(), int64(0), time.Unix(0, 0), false, int64(0))
f.slashingKeeper.SetValidatorSigningInfo(f.ctx, consAddr, info)
assert.NilError(t, f.slashingKeeper.SetValidatorSigningInfo(f.ctx, consAddr, info))

tstaking.CreateValidatorWithValPower(valAddr, val, power, true)
validatorUpdates, err := f.stakingKeeper.EndBlocker(f.ctx)
Expand All @@ -339,7 +354,7 @@ func TestValidatorDippingInAndOut(t *testing.T) {
height := int64(0)
for ; height < int64(100); height++ {
f.ctx = f.ctx.WithBlockHeight(height)
f.slashingKeeper.HandleValidatorSignature(f.ctx, val.Address(), power, comet.BlockIDFlagCommit)
assert.NilError(t, f.slashingKeeper.HandleValidatorSignature(f.ctx, val.Address(), power, comet.BlockIDFlagCommit))
}

// kick first validator out of validator set
Expand All @@ -364,26 +379,32 @@ func TestValidatorDippingInAndOut(t *testing.T) {
newPower := power + 50

// validator misses a block
f.slashingKeeper.HandleValidatorSignature(f.ctx, val.Address(), newPower, comet.BlockIDFlagAbsent)
assert.NilError(t, f.slashingKeeper.HandleValidatorSignature(f.ctx, val.Address(), newPower, comet.BlockIDFlagAbsent))
height++

// shouldn't be jailed/kicked yet
tstaking.CheckValidator(valAddr, stakingtypes.Bonded, false)

signedBlocksWindow, err := f.slashingKeeper.SignedBlocksWindow(f.ctx)
assert.NilError(t, err)

// validator misses an additional 500 more blocks within the SignedBlockWindow (here 1000 blocks).
latest := f.slashingKeeper.SignedBlocksWindow(f.ctx) + height
latest := signedBlocksWindow + height
// misses 500 blocks + within the signing windows i.e. 700-1700
// validators misses all 1000 blocks of a SignedBlockWindows
for ; height < latest+1; height++ {
f.slashingKeeper.HandleValidatorSignature(f.ctx.WithBlockHeight(height), val.Address(), newPower, comet.BlockIDFlagAbsent)
err = f.slashingKeeper.HandleValidatorSignature(f.ctx.WithBlockHeight(height), val.Address(), newPower, comet.BlockIDFlagAbsent)
assert.NilError(t, err)
}

// should now be jailed & kicked
f.stakingKeeper.EndBlocker(f.ctx)
_, err = f.stakingKeeper.EndBlocker(f.ctx)
assert.NilError(t, err)
tstaking.CheckValidator(valAddr, stakingtypes.Unbonding, true)

info = slashingtypes.NewValidatorSigningInfo(consAddr, f.ctx.BlockHeight(), int64(0), time.Unix(0, 0), false, int64(0))
f.slashingKeeper.SetValidatorSigningInfo(f.ctx, consAddr, info)
err = f.slashingKeeper.SetValidatorSigningInfo(f.ctx, consAddr, info)
assert.NilError(t, err)

// check all the signing information
signInfo, found := f.slashingKeeper.GetValidatorSigningInfo(f.ctx, consAddr)
Expand All @@ -397,30 +418,39 @@ func TestValidatorDippingInAndOut(t *testing.T) {
f.ctx = f.ctx.WithBlockHeight(height)

info = slashingtypes.NewValidatorSigningInfo(consAddr, f.ctx.BlockHeight(), int64(0), time.Unix(0, 0), false, int64(0))
f.slashingKeeper.SetValidatorSigningInfo(f.ctx, consAddr, info)
err = f.slashingKeeper.SetValidatorSigningInfo(f.ctx, consAddr, info)
assert.NilError(t, err)

// validator rejoins and starts signing again
f.stakingKeeper.Unjail(f.ctx, consAddr)

f.slashingKeeper.HandleValidatorSignature(f.ctx, val.Address(), newPower, comet.BlockIDFlagCommit)
err = f.slashingKeeper.HandleValidatorSignature(f.ctx, val.Address(), newPower, comet.BlockIDFlagCommit)
assert.NilError(t, err)

// validator should not be kicked since we reset counter/array when it was jailed
f.stakingKeeper.EndBlocker(f.ctx)
_, err = f.stakingKeeper.EndBlocker(f.ctx)
assert.NilError(t, err)
tstaking.CheckValidator(valAddr, stakingtypes.Bonded, false)

// check start height is correctly set
signInfo, found = f.slashingKeeper.GetValidatorSigningInfo(f.ctx, consAddr)
assert.Assert(t, found)
assert.Equal(t, height, signInfo.StartHeight)

minSignedPerWindow, err := f.slashingKeeper.MinSignedPerWindow(f.ctx)
assert.NilError(t, err)

// validator misses 501 blocks after SignedBlockWindow period (1000 blocks)
latest = f.slashingKeeper.SignedBlocksWindow(f.ctx) + height
for ; height < latest+f.slashingKeeper.MinSignedPerWindow(f.ctx); height++ {
latest = signedBlocksWindow + height
for ; height < latest+minSignedPerWindow; height++ {
f.ctx = f.ctx.WithBlockHeight(height)
f.slashingKeeper.HandleValidatorSignature(f.ctx, val.Address(), newPower, comet.BlockIDFlagAbsent)
err = f.slashingKeeper.HandleValidatorSignature(f.ctx, val.Address(), newPower, comet.BlockIDFlagAbsent)
assert.NilError(t, err)
}

// validator should now be jailed & kicked
f.stakingKeeper.EndBlocker(f.ctx)
_, err = f.stakingKeeper.EndBlocker(f.ctx)
assert.NilError(t, err)

tstaking.CheckValidator(valAddr, stakingtypes.Unbonding, true)
}
36 changes: 27 additions & 9 deletions x/evidence/keeper/infraction.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func (k Keeper) handleEquivocationEvidence(ctx context.Context, evidence *types.
}

if !validator.GetOperator().Empty() {
if _, err := k.slashingKeeper.GetPubkey(sdkCtx, consAddr.Bytes()); err != nil {
if _, err := k.slashingKeeper.GetPubkey(ctx, consAddr.Bytes()); err != nil {
// Ignore evidence that cannot be handled.
//
// NOTE: We used to panic with:
Expand Down Expand Up @@ -76,12 +76,12 @@ func (k Keeper) handleEquivocationEvidence(ctx context.Context, evidence *types.
}
}

if ok := k.slashingKeeper.HasValidatorSigningInfo(sdkCtx, consAddr); !ok {
if ok := k.slashingKeeper.HasValidatorSigningInfo(ctx, consAddr); !ok {
panic(fmt.Sprintf("expected signing info for validator %s but not found", consAddr))
}

// ignore if the validator is already tombstoned
if k.slashingKeeper.IsTombstoned(sdkCtx, consAddr) {
if k.slashingKeeper.IsTombstoned(ctx, consAddr) {
logger.Info(
"ignored equivocation; validator already tombstoned",
"validator", consAddr,
Expand Down Expand Up @@ -110,21 +110,39 @@ func (k Keeper) handleEquivocationEvidence(ctx context.Context, evidence *types.
// to/by CometBFT. This value is validator.Tokens as sent to CometBFT via
// ABCI, and now received as evidence. The fraction is passed in to separately
// to slash unbonding and rebonding delegations.
k.slashingKeeper.SlashWithInfractionReason(
sdkCtx,
slashFractionDoubleSign, err := k.slashingKeeper.SlashFractionDoubleSign(ctx)
if err != nil {
return err
}

err = k.slashingKeeper.SlashWithInfractionReason(
ctx,
consAddr,
k.slashingKeeper.SlashFractionDoubleSign(sdkCtx),
slashFractionDoubleSign,
evidence.GetValidatorPower(), distributionHeight,
stakingtypes.Infraction_INFRACTION_DOUBLE_SIGN,
)
if err != nil {
return err
}

// Jail the validator if not already jailed. This will begin unbonding the
// validator if not already unbonding (tombstoned).
if !validator.IsJailed() {
k.slashingKeeper.Jail(sdkCtx, consAddr)
err = k.slashingKeeper.Jail(ctx, consAddr)
if err != nil {
return err
}
}

k.slashingKeeper.JailUntil(sdkCtx, consAddr, types.DoubleSignJailEndTime)
k.slashingKeeper.Tombstone(sdkCtx, consAddr)
err = k.slashingKeeper.JailUntil(ctx, consAddr, types.DoubleSignJailEndTime)
if err != nil {
return err
}

err = k.slashingKeeper.Tombstone(ctx, consAddr)
if err != nil {
return err
}
return k.SetEvidence(ctx, evidence)
}
Loading