Skip to content

Commit

Permalink
Fix logic to make e2e test works
Browse files Browse the repository at this point in the history
  • Loading branch information
trinitys7 committed Aug 29, 2024
1 parent 7d715d3 commit ddec50f
Show file tree
Hide file tree
Showing 17 changed files with 95 additions and 41 deletions.
2 changes: 1 addition & 1 deletion tests/e2e/slashing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func TestSlashingScenario1(t *testing.T) {
// ==============
// Deposit - A user deposits the vault denom to provide some collateral to their account
execMsg := fmt.Sprintf(`{"bond":{"amount":{"denom":"%s", "amount":"200000000"}}}`, x.ProviderDenom)
providerCli.MustExecVault(execMsg, sdk.NewCoin(x.ProviderDenom, sdk.NewInt(200000000)))
providerCli.MustExecVault(execMsg)

// Stake Locally - A user triggers a local staking action to a chosen validator.
myLocalValidatorAddr := sdk.ValAddress(x.ProviderChain.Vals.Validators[0].Address).String()
Expand Down
18 changes: 18 additions & 0 deletions tests/e2e/valset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,24 @@ func unjailValidator(t *testing.T, consAddr sdk.ConsAddress, operatorKeys *secp2
chain.NextBlock()
}

func tombstoneValidator(t *testing.T, consAddr sdk.ConsAddress, operatorKeys *secp256k1.PrivKey, chain *TestChain, app *app.MeshApp) {
e := &types.Equivocation{
Height: chain.GetContext().BlockHeight(),
Power: 100,
Time: chain.GetContext().BlockTime(),
ConsensusAddress: consAddr.String(),
}
// when
app.EvidenceKeeper.HandleEquivocationEvidence(chain.GetContext(), e)
chain.NextBlock()

packets := chain.PendingSendPackets
require.Len(t, packets, 1)
tombstoned := gjson.Get(string(packets[0].Data), "valset_update.tombstoned").Array()
require.Len(t, tombstoned, 1, string(packets[0].Data))
require.Equal(t, sdk.ValAddress(operatorKeys.PubKey().Address()).String(), tombstoned[0].String())
}

func CreateNewValidator(t *testing.T, operatorKeys *secp256k1.PrivKey, chain *TestChain, power int64) mock.PV {
privVal := mock.NewPV()
bondCoin := sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(power, sdk.DefaultPowerReduction))
Expand Down
1 change: 0 additions & 1 deletion tests/starship/mvp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

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

"github.com/osmosis-labs/mesh-security-sdk/tests/starship/setup"
Expand Down
Binary file modified tests/testdata/mesh_converter.wasm.gz
Binary file not shown.
Binary file modified tests/testdata/mesh_external_staking.wasm.gz
Binary file not shown.
Binary file modified tests/testdata/mesh_native_staking.wasm.gz
Binary file not shown.
Binary file modified tests/testdata/mesh_native_staking_proxy.wasm.gz
Binary file not shown.
Binary file modified tests/testdata/mesh_osmosis_price_provider.wasm.gz
Binary file not shown.
Binary file modified tests/testdata/mesh_remote_price_feed.wasm.gz
Binary file not shown.
Binary file modified tests/testdata/mesh_simple_price_feed.wasm.gz
Binary file not shown.
Binary file modified tests/testdata/mesh_vault.wasm.gz
Binary file not shown.
Binary file modified tests/testdata/mesh_virtual_staking.wasm.gz
Binary file not shown.
2 changes: 1 addition & 1 deletion tests/testdata/version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
e8d2571a5e581d53921cb12be56a8d29b53a5c7c
04112d0fa65c2a42ea179617ccd76088567b2727
2 changes: 1 addition & 1 deletion x/meshsecurity/contract/out_message.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,6 @@ type (
Jailed []ValidatorAddr `json:"jailed"`
Unjailed []ValidatorAddr `json:"unjailed"`
Tombstoned []ValidatorAddr `json:"tombstoned"`
Slashed []ValidatorSlash `json:"slashed"`
Slashed []ValidatorSlash `json:"slashed,omitempty"`
}
)
16 changes: 10 additions & 6 deletions x/meshsecurity/keeper/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,17 +115,12 @@ func NewStakingDecorator(stakingKeeper slashingtypes.StakingKeeper, k *Keeper) *

// Slash captures the slash event and calls the decorated staking keeper slash method
func (s StakingDecorator) Slash(ctx sdk.Context, consAddr sdk.ConsAddress, infractionHeight int64, power int64, slashFactor sdk.Dec) math.Int {
return s.SlashWithInfractionReason(ctx, consAddr, infractionHeight, power, slashFactor, stakingtypes.Infraction_INFRACTION_UNSPECIFIED)
}

// SlashWithInfractionReason implementation doesn't require the infraction (types.Infraction) to work but is required by Interchain Security.
func (s StakingDecorator) SlashWithInfractionReason(ctx sdk.Context, consAddr sdk.ConsAddress, infractionHeight int64, power int64, slashFactor sdk.Dec, infraction stakingtypes.Infraction) math.Int {
val := s.StakingKeeper.ValidatorByConsAddr(ctx, consAddr)
totalSlashAmount := s.StakingKeeper.Slash(ctx, consAddr, infractionHeight, power, slashFactor)
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, infractionHeight, totalSlashAmount, slashFactor, infraction); err != nil {
} else if err := s.k.ScheduleSlashed(ctx, val.GetOperator(), power, infractionHeight, totalSlashAmount, slashFactor); err != nil {
ModuleLogger(ctx).
Error("can not propagate slash: schedule event",
"cause", err,
Expand All @@ -134,6 +129,15 @@ func (s StakingDecorator) SlashWithInfractionReason(ctx sdk.Context, consAddr sd
return totalSlashAmount
}

// SlashWithInfractionReason implementation doesn't require the infraction (types.Infraction) to work but is required by Interchain Security.
func (s StakingDecorator) SlashWithInfractionReason(ctx sdk.Context, consAddr sdk.ConsAddress, infractionHeight int64, power int64, slashFactor sdk.Dec, infraction stakingtypes.Infraction) math.Int {
if infraction == stakingtypes.Infraction_INFRACTION_DOUBLE_SIGN {
val := s.StakingKeeper.ValidatorByConsAddr(ctx, consAddr)
s.k.SetTombstonedStatus(ctx, val.GetOperator())
}
return s.Slash(ctx, consAddr, infractionHeight, power, slashFactor)
}

// Jail captures the jail event and calls the decorated staking keeper jail method
func (s StakingDecorator) Jail(ctx sdk.Context, consAddr sdk.ConsAddress) {
val := s.StakingKeeper.ValidatorByConsAddr(ctx, consAddr)
Expand Down
68 changes: 50 additions & 18 deletions x/meshsecurity/keeper/valset_updates.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@ import (
"github.com/cosmos/cosmos-sdk/store/prefix"
sdk "github.com/cosmos/cosmos-sdk/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"

"github.com/osmosis-labs/mesh-security-sdk/x/meshsecurity/contract"
"github.com/osmosis-labs/mesh-security-sdk/x/meshsecurity/types"
gogotypes "github.com/cosmos/gogoproto/types"

outmessage "github.com/osmosis-labs/mesh-security-sdk/x/meshsecurity/contract"
"github.com/osmosis-labs/mesh-security-sdk/x/meshsecurity/types"
)

// ScheduleBonded store a validator update to bonded status for the valset update report
Expand All @@ -25,13 +24,12 @@ 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, infraction stakingtypes.Infraction) error {
func (k Keeper) ScheduleSlashed(ctx sdk.Context, addr sdk.ValAddress, power int64, height int64, totalSlashAmount math.Int, slashRatio sdk.Dec) error {
var slashInfo = &types.SlashInfo{
Power: power,
InfractionHeight: height,
TotalSlashAmount: totalSlashAmount.String(),
SlashFraction: slashRatio.String(),
Infraction: int32(infraction),
}
return k.sendAsync(ctx, types.ValidatorSlashed, addr, slashInfo)
}
Expand Down Expand Up @@ -78,7 +76,7 @@ func (k Keeper) sendAsync(ctx sdk.Context, op types.PipedValsetOperation, valAdd
// ValsetUpdateReport aggregate all stored changes of the current block. Should be called by an end-blocker.
// The events reported are categorized by type and not time. Conflicting events as Bonded/ Unbonded
// are not supposed to happen within the same block
func (k Keeper) ValsetUpdateReport(ctx sdk.Context) (contract.ValsetUpdate, error) {
func (k Keeper) ValsetUpdateReport(ctx sdk.Context) (outmessage.ValsetUpdate, error) {
var innerErr error
appendValidator := func(set *[]wasmvmtypes.Validator, valAddr sdk.ValAddress) bool {
val, ok := k.Staking.GetValidator(ctx, valAddr)
Expand All @@ -90,7 +88,9 @@ func (k Keeper) ValsetUpdateReport(ctx sdk.Context) (contract.ValsetUpdate, erro
return false
}
slashValidator := func(set *[]outmessage.ValidatorSlash, valAddr sdk.ValAddress, power int64, infractionHeight int64,
infractionTime int64, slashAmount string, slashRatio string, infraction int32) bool {
infractionTime int64, slashAmount string, slashRatio string) bool {
isTombstoned := k.IsTombstonedStatus(ctx, valAddr)
k.ClearTombstonedStatus(ctx, valAddr)
valSlash := outmessage.ValidatorSlash{
ValidatorAddr: valAddr.String(),
Power: power,
Expand All @@ -100,19 +100,19 @@ func (k Keeper) ValsetUpdateReport(ctx sdk.Context) (contract.ValsetUpdate, erro
Time: ctx.BlockTime().Unix(),
SlashAmount: slashAmount,
SlashRatio: slashRatio,
IsTombstoned: infraction == int32(stakingtypes.Infraction_INFRACTION_DOUBLE_SIGN),
IsTombstoned: isTombstoned,
}
*set = append(*set, valSlash)
return false
}
r := contract.ValsetUpdate{ // init with empty slices for contract that does not handle null or omitted fields
Additions: make([]contract.Validator, 0),
Removals: make([]contract.ValidatorAddr, 0),
Updated: make([]contract.Validator, 0),
Jailed: make([]contract.ValidatorAddr, 0),
Unjailed: make([]contract.ValidatorAddr, 0),
Tombstoned: make([]contract.ValidatorAddr, 0),
Slashed: make([]contract.ValidatorSlash, 0),
r := outmessage.ValsetUpdate{ // init with empty slices for contract that does not handle null or omitted fields
Additions: make([]outmessage.Validator, 0),
Removals: make([]outmessage.ValidatorAddr, 0),
Updated: make([]outmessage.Validator, 0),
Jailed: make([]outmessage.ValidatorAddr, 0),
Unjailed: make([]outmessage.ValidatorAddr, 0),
Tombstoned: make([]outmessage.ValidatorAddr, 0),
Slashed: make([]outmessage.ValidatorSlash, 0),
}
err := k.iteratePipedValsetOperations(ctx, func(valAddr sdk.ValAddress, op types.PipedValsetOperation, slashInfo *types.SlashInfo) bool {
switch op {
Expand All @@ -129,9 +129,8 @@ 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,
slashInfo.TotalSlashAmount, slashInfo.SlashFraction, slashInfo.Infraction)
slashInfo.TotalSlashAmount, slashInfo.SlashFraction)
default:
innerErr = types.ErrInvalid.Wrapf("undefined operation type %X", op)
return true
Expand All @@ -158,6 +157,39 @@ func (k Keeper) ClearPipedValsetOperations(ctx sdk.Context) {
}
}

// SetTombstonedStatus sets Tombstoned status for the given validator address in the provided store.
func (k Keeper) SetTombstonedStatus(ctx sdk.Context, valAddr sdk.ValAddress) {
store := ctx.KVStore(k.storeKey)

bz := k.cdc.MustMarshal(&gogotypes.BoolValue{Value: true})
store.Set(types.BuildTombstoneStatusKey(valAddr), bz)
}

// IsTombstonedStatus returns whether validator is tombstoned or not
func (k Keeper) IsTombstonedStatus(ctx sdk.Context, valAddr sdk.ValAddress) bool {
store := ctx.KVStore(k.storeKey)
key := types.BuildTombstoneStatusKey(valAddr)
if !store.Has(key) {
return false
}

bz := store.Get(key)
if bz == nil {
return false
}

var enabled gogotypes.BoolValue
k.cdc.MustUnmarshal(bz, &enabled)

return enabled.Value
}

// ClearTombstonedStatus delete all entries from the temporary store that contains the validator status.
func (k Keeper) ClearTombstonedStatus(ctx sdk.Context, valAddr sdk.ValAddress) {
store := ctx.KVStore(k.storeKey)
store.Delete(types.BuildTombstoneStatusKey(valAddr))
}

// iterate through all stored valset updates. Due to the storage key, there are no contract duplicates within an operation type.
func (k Keeper) iteratePipedValsetOperations(ctx sdk.Context, cb func(valAddress sdk.ValAddress, op types.PipedValsetOperation, slashInfo *types.SlashInfo) bool) error {
pStore := prefix.NewStore(ctx.KVStore(k.memKey), types.PipedValsetPrefix)
Expand Down
27 changes: 14 additions & 13 deletions x/meshsecurity/types/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ var (
TotalDelegatedAmountKeyPrefix = []byte{0x3}
SchedulerKeyPrefix = []byte{0x4}

PipedValsetPrefix = []byte{0x5}
PipedValsetPrefix = []byte{0x5}
TombstoneStatusPrefix = []byte{0x6}
)

type PipedValsetOperation byte
Expand Down Expand Up @@ -102,27 +103,27 @@ func BuildPipedValsetOpKey(op PipedValsetOperation, val sdk.ValAddress, slashInf
if slashInfo == nil {
panic("slash info is nil")
}
sn = 8 + 8 + 4 + 1 + len(slashInfo.TotalSlashAmount) + len(slashInfo.SlashFraction) // 8 for height, 8 for power, 4 for infraction, +1 for total amount length
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 {
b1 := make([]byte, 8)
binary.BigEndian.PutUint64(b1, uint64(slashInfo.InfractionHeight))
copy(r[pn+an+1+1:], b1)
binary.BigEndian.PutUint64(b1, uint64(slashInfo.Power))
copy(r[pn+an+1+1+8:], b1)
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)
sn := len(slashInfo.SlashFraction)
r[pn+an+1+1+8+8+1+tn] = byte(sn)
copy(r[pn+an+1+1+8+8+1+tn+1:], slashInfo.SlashFraction)
b2 := make([]byte, 4)
binary.BigEndian.PutUint32(b2, uint32(slashInfo.Infraction))
copy(r[pn+an+1+1+8+8+1+tn+1+sn:], b2)
copy(r[pn+an+1+1+8+8+1+tn:], slashInfo.SlashFraction)
}
return r
}

// BuildTombstoneStatusKey build store key for the tombstone validator status store
func BuildTombstoneStatusKey(valAddr sdk.ValAddress) []byte {
return append(TombstoneStatusPrefix, valAddr.Bytes()...)
}

0 comments on commit ddec50f

Please sign in to comment.