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

fix key and add time Infraction #172

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all 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
36 changes: 36 additions & 0 deletions docs/proto/proto-docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

- [osmosis/meshsecurity/v1beta1/meshsecurity.proto](#osmosis/meshsecurity/v1beta1/meshsecurity.proto)
- [Params](#osmosis.meshsecurity.v1beta1.Params)
- [SlashInfo](#osmosis.meshsecurity.v1beta1.SlashInfo)
- [VirtualStakingMaxCapInfo](#osmosis.meshsecurity.v1beta1.VirtualStakingMaxCapInfo)

- [osmosis/meshsecurity/v1beta1/genesis.proto](#osmosis/meshsecurity/v1beta1/genesis.proto)
Expand All @@ -22,6 +23,7 @@
- [Query](#osmosis.meshsecurity.v1beta1.Query)

- [osmosis/meshsecurity/v1beta1/scheduler.proto](#osmosis/meshsecurity/v1beta1/scheduler.proto)
- [ScheduledWork](#osmosis.meshsecurity.v1beta1.ScheduledWork)
- [ValidatorAddress](#osmosis.meshsecurity.v1beta1.ValidatorAddress)

- [osmosis/meshsecurity/v1beta1/tx.proto](#osmosis/meshsecurity/v1beta1/tx.proto)
Expand Down Expand Up @@ -58,6 +60,25 @@ Params defines the parameters for the x/meshsecurity module.



<a name="osmosis.meshsecurity.v1beta1.SlashInfo"></a>

### SlashInfo
SlashInfo defines info event from slashing


| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `infraction_height` | [int64](#int64) | | |
| `power` | [int64](#int64) | | |
| `total_slash_amount` | [string](#string) | | |
| `slash_fraction` | [string](#string) | | |
| `time_infraction` | [int64](#int64) | | |






<a name="osmosis.meshsecurity.v1beta1.VirtualStakingMaxCapInfo"></a>

### VirtualStakingMaxCapInfo
Expand Down Expand Up @@ -238,6 +259,21 @@ Query provides defines the gRPC querier service



<a name="osmosis.meshsecurity.v1beta1.ScheduledWork"></a>

### ScheduledWork



| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `repeat` | [bool](#bool) | | |






<a name="osmosis.meshsecurity.v1beta1.ValidatorAddress"></a>

### ValidatorAddress
Expand Down
9 changes: 9 additions & 0 deletions proto/osmosis/meshsecurity/v1beta1/meshsecurity.proto
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,13 @@ message Params {
// MaxGasEndBlocker defines the maximum gas that can be spent in a contract
// sudo callback
uint32 max_gas_end_blocker = 3;
}

// SlashInfo defines info event from slashing
message SlashInfo {
int64 infraction_height = 1;
int64 power = 2;
string total_slash_amount = 3;
string slash_fraction = 4;
int64 time_infraction = 5;
}
3 changes: 2 additions & 1 deletion x/meshsecurity/keeper/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,8 @@ func (s StakingDecorator) Slash(ctx sdk.Context, consAddr sdk.ConsAddress, power
if val == nil {
ModuleLogger(ctx).
Error("can not propagate slash: validator not found", "validator", consAddr.String())
} else if err := s.k.ScheduleSlashed(ctx, val.GetOperator(), power, height, totalSlashAmount, slashRatio); err != nil {
// TODO: add TimeInfraction (Needs to be gathered from the caller)
} else if err := s.k.ScheduleSlashed(ctx, val.GetOperator(), power, height, totalSlashAmount, slashRatio, 0); err != nil {
ModuleLogger(ctx).
Error("can not propagate slash: schedule event",
"cause", err,
Expand Down
36 changes: 19 additions & 17 deletions x/meshsecurity/keeper/valset_updates.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,13 @@ func (k Keeper) ScheduleUnbonded(ctx sdk.Context, addr sdk.ValAddress) error {
}

// ScheduleSlashed store a validator slash event / data for the valset update report
func (k Keeper) ScheduleSlashed(ctx sdk.Context, addr sdk.ValAddress, power int64, height int64, totalSlashAmount math.Int, slashRatio sdk.Dec) error {
func (k Keeper) ScheduleSlashed(ctx sdk.Context, addr sdk.ValAddress, power int64, height int64, totalSlashAmount math.Int, slashRatio sdk.Dec, timeInfraction int64) error {
var slashInfo = &types.SlashInfo{
Power: power,
InfractionHeight: height,
TotalSlashAmount: totalSlashAmount.String(),
SlashFraction: slashRatio.String(),
TimeInfraction: timeInfraction,
}
return k.sendAsync(ctx, types.ValidatorSlashed, addr, slashInfo)
}
Expand Down Expand Up @@ -59,7 +60,16 @@ func (k Keeper) ScheduleModified(ctx sdk.Context, addr sdk.ValAddress) error {
// and async send to all registered contracts in the end blocker
func (k Keeper) sendAsync(ctx sdk.Context, op types.PipedValsetOperation, valAddr sdk.ValAddress, slashInfo *types.SlashInfo) error {
ModuleLogger(ctx).Debug("storing for async update", "operation", int(op), "val", valAddr.String())
ctx.KVStore(k.memKey).Set(types.BuildPipedValsetOpKey(op, valAddr, slashInfo), []byte{})
if op == types.ValidatorSlashed {
value, err := slashInfo.Marshal()
if err != nil {
return err
}
ctx.KVStore(k.memKey).Set(types.BuildPipedValsetOpKey(op, valAddr), value)
} else {
ctx.KVStore(k.memKey).Set(types.BuildPipedValsetOpKey(op, valAddr), []byte{})
}

// and schedule an update callback for all registered contracts
var innerErr error
k.IterateMaxCapLimit(ctx, func(contractAddr sdk.AccAddress, m math.Int) bool {
Expand Down Expand Up @@ -127,8 +137,7 @@ func (k Keeper) ValsetUpdateReport(ctx sdk.Context) (contract.ValsetUpdate, erro
case types.ValidatorModified:
return appendValidator(&r.Updated, valAddr)
case types.ValidatorSlashed:
// TODO: Add / send the infraction time
return slashValidator(&r.Slashed, valAddr, slashInfo.Power, slashInfo.InfractionHeight, 0,
return slashValidator(&r.Slashed, valAddr, slashInfo.Power, slashInfo.InfractionHeight, slashInfo.TimeInfraction,
slashInfo.TotalSlashAmount, slashInfo.SlashFraction)
default:
innerErr = types.ErrInvalid.Wrapf("undefined operation type %X", op)
Expand Down Expand Up @@ -162,22 +171,15 @@ func (k Keeper) iteratePipedValsetOperations(ctx sdk.Context, cb func(valAddress
iter := pStore.Iterator(nil, nil)
for ; iter.Valid(); iter.Next() {
key := iter.Key()
addrLen := key[0]
addr, op := key[1:addrLen+1], key[addrLen+1]
var slashInfo *types.SlashInfo = nil
addr, op := key[:len(key)-1], key[len(key)-1]

var slashInfo types.SlashInfo
if types.PipedValsetOperation(op) == types.ValidatorSlashed {
if len(key) <= 1+int(addrLen)+1+8+8+1 {
return types.ErrInvalid.Wrapf("invalid slash key length %d", len(key))
}
totalSlashAmountLen := key[addrLen+2+8+8]
slashInfo = &types.SlashInfo{
Power: int64(sdk.BigEndianToUint64(key[addrLen+2 : addrLen+2+8])),
InfractionHeight: int64(sdk.BigEndianToUint64(key[addrLen+2+8 : addrLen+2+8+8])),
TotalSlashAmount: string(key[addrLen+2+8+8+1 : addrLen+2+8+8+1+totalSlashAmountLen]),
SlashFraction: string(key[addrLen+2+8+8+1+totalSlashAmountLen:]),
if err := slashInfo.Unmarshal(iter.Value()); err != nil {
panic(err)
}
}
if cb(addr, types.PipedValsetOperation(op), slashInfo) {
if cb(addr, types.PipedValsetOperation(op), &slashInfo) {
break
}
}
Expand Down
38 changes: 38 additions & 0 deletions x/meshsecurity/keeper/valset_updates_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bytes"
stdrand "math/rand"
"testing"
"time"

"github.com/cometbft/cometbft/libs/rand"
"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -232,3 +233,40 @@ func TestClearPipedValsetOperations(t *testing.T) {
// then
assert.Empty(t, FetchAllStoredOperations(t, ctx, k))
}

func TestSetAndGetScheduleSlashed(t *testing.T) {
DongLieu marked this conversation as resolved.
Show resolved Hide resolved
ctx, keepers := CreateDefaultTestInput(t)
k := keepers.MeshKeeper

var valAdrees sdk.ValAddress
valAdrees = rand.Bytes(address.Len)
slashInfo := &types.SlashInfo{
Power: 12,
InfractionHeight: 123,
TotalSlashAmount: sdk.NewInt(1000).String(),
SlashFraction: sdk.NewDec(1).String(),
TimeInfraction: time.Now().Unix(),
}
// set
err := k.sendAsync(ctx, types.ValidatorSlashed, valAdrees, slashInfo)
require.NoError(t, err)
// get
var getSlash types.SlashInfo
var val sdk.ValAddress
err = k.iteratePipedValsetOperations(ctx, func(valAddress sdk.ValAddress, op types.PipedValsetOperation, slashInfo *types.SlashInfo) bool {

if op == types.ValidatorSlashed {
getSlash = *slashInfo
val = valAddress
return true
}
return false
})
require.NoError(t, err)
// check
require.Equal(t, slashInfo.TimeInfraction, getSlash.TimeInfraction)
require.Equal(t, slashInfo.Power, getSlash.Power)
require.Equal(t, slashInfo.InfractionHeight, getSlash.InfractionHeight)
require.Equal(t, slashInfo.TotalSlashAmount, getSlash.TotalSlashAmount)
require.Equal(t, valAdrees, val)
}
38 changes: 4 additions & 34 deletions x/meshsecurity/types/keys.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package types

import (
"encoding/binary"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/address"
)

const (
Expand Down Expand Up @@ -46,13 +44,6 @@ const (
ValidatorSlashed
)

type SlashInfo struct {
InfractionHeight int64
Power int64
TotalSlashAmount string
SlashFraction string
}

// BuildMaxCapLimitKey build max cap limit store key
func BuildMaxCapLimitKey(contractAddr sdk.AccAddress) []byte {
return append(MaxCapLimitKeyPrefix, contractAddr.Bytes()...)
Expand Down Expand Up @@ -90,32 +81,11 @@ func BuildSchedulerContractKey(tp SchedulerTaskType, blockHeight uint64, contrac
}

// BuildPipedValsetOpKey build store key for the temporary valset operation store
func BuildPipedValsetOpKey(op PipedValsetOperation, val sdk.ValAddress, slashInfo *SlashInfo) []byte {
func BuildPipedValsetOpKey(op PipedValsetOperation, val sdk.ValAddress) []byte {
if op == ValsetOperationUndefined {
panic("empty operation")
}
pn, an := len(PipedValsetPrefix), len(val)
sn := 0
if op == ValidatorSlashed {
if slashInfo == nil {
panic("slash info is nil")
}
sn = 8 + 8 + 1 + len(slashInfo.TotalSlashAmount) + len(slashInfo.SlashFraction) // 8 for height, 8 for power, +1 for total amount length
}
r := make([]byte, pn+an+sn+1+1) // +1 for address prefix, +1 for op
copy(r, PipedValsetPrefix)
copy(r[pn:], address.MustLengthPrefix(val))
r[pn+an+1] = byte(op)
if op == ValidatorSlashed {
b := make([]byte, 8)
binary.BigEndian.PutUint64(b, uint64(slashInfo.InfractionHeight))
copy(r[pn+an+1+1:], b)
binary.BigEndian.PutUint64(b, uint64(slashInfo.Power))
copy(r[pn+an+1+1+8:], b)
tn := len(slashInfo.TotalSlashAmount)
r[pn+an+1+1+8+8] = byte(tn)
copy(r[pn+an+1+1+8+8+1:], slashInfo.TotalSlashAmount)
copy(r[pn+an+1+1+8+8+1+tn:], slashInfo.SlashFraction)
}
return r
k := append(append(PipedValsetPrefix, val...), byte(op))
// return
return k
}
Loading
Loading