Skip to content

Commit

Permalink
refactor(x/slashing)!: use kvStoreService, context.Context and return…
Browse files Browse the repository at this point in the history
… errors (#16246)
  • Loading branch information
facundomedica authored May 30, 2023
1 parent 0e34478 commit 903d99e
Show file tree
Hide file tree
Showing 30 changed files with 485 additions and 291 deletions.
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`. `GetValidatorSigningInfo` now returns an error instead of a `found bool`, the error can be `nil` (found), `ErrNoSigningInfoFound` (not found) and any other 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

0 comments on commit 903d99e

Please sign in to comment.