Skip to content

Commit

Permalink
refactor: x/evidence audit (backport #14260) (#14292)
Browse files Browse the repository at this point in the history
Co-authored-by: Julien Robert <julien@rbrt.fr>
  • Loading branch information
mergify[bot] and julienrbrt authored Dec 13, 2022
1 parent ac168db commit 3335aa6
Show file tree
Hide file tree
Showing 3 changed files with 235 additions and 181 deletions.
234 changes: 234 additions & 0 deletions tests/integration/evidence/keeper/infraction_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
package keeper_test

import (
"encoding/hex"
"fmt"
"testing"
"time"

tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
"gotest.tools/v3/assert"

codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/runtime"
simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
sdk "github.com/cosmos/cosmos-sdk/types"
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper"
"github.com/cosmos/cosmos-sdk/x/evidence/exported"
"github.com/cosmos/cosmos-sdk/x/evidence/keeper"
"github.com/cosmos/cosmos-sdk/x/evidence/testutil"
"github.com/cosmos/cosmos-sdk/x/evidence/types"
minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper"
slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types"
"github.com/cosmos/cosmos-sdk/x/staking"
stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper"
stakingtestutil "github.com/cosmos/cosmos-sdk/x/staking/testutil"
)

var (
pubkeys = []cryptotypes.PubKey{
newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB50"),
newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB51"),
newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB52"),
}

valAddresses = []sdk.ValAddress{
sdk.ValAddress(pubkeys[0].Address()),
sdk.ValAddress(pubkeys[1].Address()),
sdk.ValAddress(pubkeys[2].Address()),
}

// The default power validators are initialized to have within tests
initAmt = sdk.TokensFromConsensusPower(200, sdk.DefaultPowerReduction)
initCoins = sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initAmt))
)

type fixture struct {
ctx sdk.Context
app *runtime.App

evidenceKeeper keeper.Keeper
bankKeeper bankkeeper.Keeper
accountKeeper authkeeper.AccountKeeper
slashingKeeper slashingkeeper.Keeper
stakingKeeper *stakingkeeper.Keeper
interfaceRegistry codectypes.InterfaceRegistry
}

func initFixture(t assert.TestingT) *fixture {
f := &fixture{}
var evidenceKeeper keeper.Keeper

app, err := simtestutil.Setup(testutil.AppConfig,
&evidenceKeeper,
&f.interfaceRegistry,
&f.accountKeeper,
&f.bankKeeper,
&f.slashingKeeper,
&f.stakingKeeper,
)
assert.NilError(t, err)

router := types.NewRouter()
router = router.AddRoute(types.RouteEquivocation, testEquivocationHandler(evidenceKeeper))
evidenceKeeper.SetRouter(router)

f.ctx = app.BaseApp.NewContext(false, tmproto.Header{Height: 1})
f.app = app
f.evidenceKeeper = evidenceKeeper

return f
}

func TestHandleDoubleSign(t *testing.T) {
t.Parallel()
f := initFixture(t)

ctx := f.ctx.WithIsCheckTx(false).WithBlockHeight(1)
populateValidators(t, f)

power := int64(100)
stakingParams := f.stakingKeeper.GetParams(ctx)
operatorAddr, val := valAddresses[0], pubkeys[0]
tstaking := stakingtestutil.NewHelper(t, ctx, f.stakingKeeper)

selfDelegation := tstaking.CreateValidatorWithValPower(operatorAddr, val, power, true)

// execute end-blocker and verify validator attributes
staking.EndBlocker(ctx, f.stakingKeeper)
assert.DeepEqual(t,
f.bankKeeper.GetAllBalances(ctx, sdk.AccAddress(operatorAddr)).String(),
sdk.NewCoins(sdk.NewCoin(stakingParams.BondDenom, initAmt.Sub(selfDelegation))).String(),
)
assert.DeepEqual(t, selfDelegation, f.stakingKeeper.Validator(ctx, operatorAddr).GetBondedTokens())

// handle a signature to set signing info
f.slashingKeeper.HandleValidatorSignature(ctx, val.Address(), selfDelegation.Int64(), true)

// double sign less than max age
oldTokens := f.stakingKeeper.Validator(ctx, operatorAddr).GetTokens()
evidence := &types.Equivocation{
Height: 0,
Time: time.Unix(0, 0),
Power: power,
ConsensusAddress: sdk.ConsAddress(val.Address()).String(),
}
f.evidenceKeeper.HandleEquivocationEvidence(ctx, evidence)

// should be jailed and tombstoned
assert.Assert(t, f.stakingKeeper.Validator(ctx, operatorAddr).IsJailed())
assert.Assert(t, f.slashingKeeper.IsTombstoned(ctx, sdk.ConsAddress(val.Address())))

// tokens should be decreased
newTokens := f.stakingKeeper.Validator(ctx, operatorAddr).GetTokens()
assert.Assert(t, newTokens.LT(oldTokens))

// submit duplicate evidence
f.evidenceKeeper.HandleEquivocationEvidence(ctx, evidence)

// tokens should be the same (capped slash)
assert.Assert(t, f.stakingKeeper.Validator(ctx, operatorAddr).GetTokens().Equal(newTokens))

// jump to past the unbonding period
ctx = ctx.WithBlockTime(time.Unix(1, 0).Add(stakingParams.UnbondingTime))

// require we cannot unjail
assert.Error(t, f.slashingKeeper.Unjail(ctx, operatorAddr), slashingtypes.ErrValidatorJailed.Error())

// require we be able to unbond now
ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1)
del, _ := f.stakingKeeper.GetDelegation(ctx, sdk.AccAddress(operatorAddr), operatorAddr)
validator, _ := f.stakingKeeper.GetValidator(ctx, operatorAddr)
totalBond := validator.TokensFromShares(del.GetShares()).TruncateInt()
tstaking.Ctx = ctx
tstaking.Denom = stakingParams.BondDenom
tstaking.Undelegate(sdk.AccAddress(operatorAddr), operatorAddr, totalBond, true)

// query evidence from store
evidences := f.evidenceKeeper.GetAllEvidence(ctx)
assert.Assert(t, len(evidences) == 1)
}

func TestHandleDoubleSign_TooOld(t *testing.T) {
t.Parallel()
f := initFixture(t)

ctx := f.ctx.WithIsCheckTx(false).WithBlockHeight(1).WithBlockTime(time.Now())
populateValidators(t, f)

power := int64(100)
stakingParams := f.stakingKeeper.GetParams(ctx)
operatorAddr, val := valAddresses[0], pubkeys[0]
tstaking := stakingtestutil.NewHelper(t, ctx, f.stakingKeeper)

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

// execute end-blocker and verify validator attributes
staking.EndBlocker(ctx, f.stakingKeeper)
assert.DeepEqual(t,
f.bankKeeper.GetAllBalances(ctx, sdk.AccAddress(operatorAddr)),
sdk.NewCoins(sdk.NewCoin(stakingParams.BondDenom, initAmt.Sub(amt))),
)
assert.DeepEqual(t, amt, f.stakingKeeper.Validator(ctx, operatorAddr).GetBondedTokens())

evidence := &types.Equivocation{
Height: 0,
Time: ctx.BlockTime(),
Power: power,
ConsensusAddress: sdk.ConsAddress(val.Address()).String(),
}

cp := f.app.BaseApp.GetConsensusParams(ctx)

ctx = ctx.WithConsensusParams(cp)
ctx = ctx.WithBlockTime(ctx.BlockTime().Add(cp.Evidence.MaxAgeDuration + 1))
ctx = ctx.WithBlockHeight(ctx.BlockHeight() + cp.Evidence.MaxAgeNumBlocks + 1)
f.evidenceKeeper.HandleEquivocationEvidence(ctx, evidence)

assert.Assert(t, f.stakingKeeper.Validator(ctx, operatorAddr).IsJailed() == false)
assert.Assert(t, f.slashingKeeper.IsTombstoned(ctx, sdk.ConsAddress(val.Address())) == false)
}

func populateValidators(t assert.TestingT, f *fixture) {
// add accounts and set total supply
totalSupplyAmt := initAmt.MulRaw(int64(len(valAddresses)))
totalSupply := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, totalSupplyAmt))
assert.NilError(t, f.bankKeeper.MintCoins(f.ctx, minttypes.ModuleName, totalSupply))

for _, addr := range valAddresses {
assert.NilError(t, f.bankKeeper.SendCoinsFromModuleToAccount(f.ctx, minttypes.ModuleName, (sdk.AccAddress)(addr), initCoins))
}
}

func newPubKey(pk string) (res cryptotypes.PubKey) {
pkBytes, err := hex.DecodeString(pk)
if err != nil {
panic(err)
}

pubkey := &ed25519.PubKey{Key: pkBytes}

return pubkey
}

func testEquivocationHandler(_ interface{}) types.Handler {
return func(ctx sdk.Context, e exported.Evidence) error {
if err := e.ValidateBasic(); err != nil {
return err
}

ee, ok := e.(*types.Equivocation)
if !ok {
return fmt.Errorf("unexpected evidence type: %T", e)
}
if ee.Height%2 == 0 {
return fmt.Errorf("unexpected even evidence height: %d", ee.Height)
}

return nil
}
}
Loading

0 comments on commit 3335aa6

Please sign in to comment.