Skip to content

Commit

Permalink
wip, tests not fixed yet
Browse files Browse the repository at this point in the history
  • Loading branch information
shaspitz committed Aug 21, 2023
1 parent e9c178e commit 7691bf5
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 605 deletions.
112 changes: 36 additions & 76 deletions x/ccv/provider/keeper/relay.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import (
ccv "github.com/cosmos/interchain-security/v3/x/ccv/types"
)

// OnRecvVSCMaturedPacket handles a VSCMatured packet
// OnRecvVSCMaturedPacket handles a VSCMatured packet and returns a no-op result ack.
func (k Keeper) OnRecvVSCMaturedPacket(
ctx sdk.Context,
packet channeltypes.Packet,
Expand All @@ -34,12 +34,9 @@ func (k Keeper) OnRecvVSCMaturedPacket(
panic(fmt.Errorf("VSCMaturedPacket received on unknown channel %s", packet.DestinationChannel))
}

if err := k.QueueThrottledVSCMaturedPacketData(ctx, chainID, packet.Sequence, data); err != nil {
return ccv.NewErrorAcknowledgementWithLog(ctx, fmt.Errorf(
"failed to queue VSCMatured packet data: %s", err.Error()))
}
k.HandleVSCMaturedPacket(ctx, chainID, data)

k.Logger(ctx).Info("VSCMaturedPacket received and enqueued",
k.Logger(ctx).Info("VSCMaturedPacket handled",
"chainID", chainID,
"vscID", data.ValsetUpdateId,
)
Expand All @@ -48,35 +45,6 @@ func (k Keeper) OnRecvVSCMaturedPacket(
return ack
}

// HandleLeadingVSCMaturedPackets handles all VSCMatured packet data that has been queued this block,
// but does not need to be throttled. The handled data is then removed from the queue.
//
// Note: VSC matured packet data which is queued behind slash packet data CANNOT be
// handled until the leading slash packet data has been handled. This is to maintain
// the "VSC Maturity and Slashing Order" CCV property. If VSC matured packet data DOES NOT
// trail slash packet data for that consumer, it will be handled in this method,
// bypassing HandleThrottleQueues.
func (k Keeper) HandleLeadingVSCMaturedPackets(ctx sdk.Context) (vscMaturedHandledThisBlock int) {
vscMaturedHandledThisBlock = 0
for _, chain := range k.GetAllConsumerChains(ctx) {
// Note: it's assumed the order of the vsc matured slice matches the order of the ibc seq nums slice,
// in that a vsc matured packet data at index i is associated with the ibc seq num at index i.
leadingVscMatured, ibcSeqNums := k.GetLeadingVSCMaturedData(ctx, chain.ChainId)
ibcSeqNumsHandled := []uint64{}
for idx, data := range leadingVscMatured {
if vscMaturedHandledThisBlock >= vscMaturedHandledPerBlockLimit {
// Break from inner for-loop, DeleteThrottledPacketData will still be called for this consumer
break
}
k.HandleVSCMaturedPacket(ctx, chain.ChainId, data)
vscMaturedHandledThisBlock++
ibcSeqNumsHandled = append(ibcSeqNumsHandled, ibcSeqNums[idx])
}
k.DeleteThrottledPacketData(ctx, chain.ChainId, ibcSeqNumsHandled...)
}
return vscMaturedHandledThisBlock
}

// HandleVSCMaturedPacket handles a VSCMatured packet.
//
// Note: This method should only panic for a system critical error like a
Expand Down Expand Up @@ -270,18 +238,10 @@ func (k Keeper) QueueVSCPackets(ctx sdk.Context) {
k.IncrementValidatorSetUpdateId(ctx)
}

// EndBlockCIS contains the EndBlock logic needed for
// the Consumer Initiated Slashing sub-protocol
func (k Keeper) EndBlockCIS(ctx sdk.Context) {
// set the ValsetUpdateBlockHeight
blockHeight := uint64(ctx.BlockHeight()) + 1
valUpdateID := k.GetValidatorSetUpdateId(ctx)
k.SetValsetUpdateBlockHeight(ctx, valUpdateID, blockHeight)
k.Logger(ctx).Debug("vscID was mapped to block height", "vscID", valUpdateID, "height", blockHeight)

// Replenish slash meter if necessary, BEFORE executing slash packet throttling logic.
// This ensures the meter value is replenished, and not greater than the allowance (max value)
// for the block, before the throttling logic is executed.
// BeginBlockCIS contains the BeginBlock logic needed for the Consumer Initiated Slashing sub-protocol.
func (k Keeper) BeginBlockCIS(ctx sdk.Context) {
// Replenish slash meter if necessary. This ensures the meter value is replenished before handling any slash packets,
// and ensures the meter value is not greater than the allowance (max value) for the block.
//
// Note: CheckForSlashMeterReplenishment contains panics for the following scenarios, any of which should never occur
// if the protocol is correct and external data is properly validated:
Expand All @@ -291,23 +251,16 @@ func (k Keeper) EndBlockCIS(ctx sdk.Context) {
// - Marshaling and/or store corruption errors.
// - Setting invalid slash meter values (see SetSlashMeter).
k.CheckForSlashMeterReplenishment(ctx)
}

// Handle leading vsc matured packets before throttling logic.
//
// Note: HandleLeadingVSCMaturedPackets contains panics for the following scenarios, any of which should never occur
// if the protocol is correct and external data is properly validated:
//
// - Marshaling and/or store corruption errors.
vscMaturedHandledThisBlock := k.HandleLeadingVSCMaturedPackets(ctx)
// Handle queue entries considering throttling logic.
//
// Note: HandleThrottleQueues contains panics for the following scenarios, any of which should never occur
// if the protocol is correct and external data is properly validated:
//
// - SlashMeter has not been set (which should be set in InitGenesis, see InitializeSlashMeter).
// - Marshaling and/or store corruption errors.
// - Setting invalid slash meter values (see SetSlashMeter).
k.HandleThrottleQueues(ctx, vscMaturedHandledThisBlock)
// EndBlockCIS contains the EndBlock logic needed for
// the Consumer Initiated Slashing sub-protocol
func (k Keeper) EndBlockCIS(ctx sdk.Context) {
// set the ValsetUpdateBlockHeight
blockHeight := uint64(ctx.BlockHeight()) + 1
valUpdateID := k.GetValidatorSetUpdateId(ctx)
k.SetValsetUpdateBlockHeight(ctx, valUpdateID, blockHeight)
k.Logger(ctx).Debug("vscID was mapped to block height", "vscID", valUpdateID, "height", blockHeight)
}

// OnRecvSlashPacket delivers a received slash packet, validates it and
Expand Down Expand Up @@ -358,28 +311,35 @@ func (k Keeper) OnRecvSlashPacket(ctx sdk.Context, packet channeltypes.Packet, d
return channeltypes.NewResultAcknowledgement(ccv.V1Result)
}

// Queue a slash entry to the global queue, which will be seen by the throttling logic
k.QueueGlobalSlashEntry(ctx, providertypes.NewGlobalSlashEntry(
ctx.BlockTime(), // recv time
chainID, // consumer chain id that sent the packet
packet.Sequence, // IBC sequence number of the packet
providerConsAddr)) // Provider consensus address of val to be slashed

// Queue slash packet data in the same (consumer chain specific) queue as vsc matured packet data,
// to enforce order of handling between the two packet data types.
if err := k.QueueThrottledSlashPacketData(ctx, chainID, packet.Sequence, data); err != nil {
return ccv.NewErrorAcknowledgementWithLog(ctx, fmt.Errorf("failed to queue slash packet data: %s", err.Error()))
meter := k.GetSlashMeter(ctx)
// Return bounce ack if meter is negative in value
if meter.IsNegative() {
k.Logger(ctx).Info("SlashPacket received, but meter is negative. Packet will be bounced",
"chainID", chainID,
"consumer cons addr", consumerConsAddr.String(),
"provider cons addr", providerConsAddr.String(),
"vscID", data.ValsetUpdateId,
"infractionType", data.Infraction,
)
return channeltypes.NewResultAcknowledgement(ccv.SlashPacketBouncedResult)
}

k.Logger(ctx).Info("slash packet received and enqueued",
k.HandleSlashPacket(ctx, chainID, data)

// Subtract voting power that will be jailed/tombstoned from the slash meter
meter = meter.Sub(k.GetEffectiveValPower(ctx, providerConsAddr))
k.SetSlashMeter(ctx, meter)

k.Logger(ctx).Info("slash packet received and handled",
"chainID", chainID,
"consumer cons addr", consumerConsAddr.String(),
"provider cons addr", providerConsAddr.String(),
"vscID", data.ValsetUpdateId,
"infractionType", data.Infraction,
)

return channeltypes.NewResultAcknowledgement(ccv.V1Result)
// Return result ack that the packet was handled successfully
return channeltypes.NewResultAcknowledgement(ccv.SlashPacketHandledResult)
}

// ValidateSlashPacket validates a recv slash packet before it is
Expand Down
90 changes: 0 additions & 90 deletions x/ccv/provider/keeper/relay_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,96 +139,6 @@ func TestOnRecvVSCMaturedPacket(t *testing.T) {
require.Equal(t, uint64(0), providerKeeper.GetThrottledPacketDataSize(ctx, "chain-2"))
}

func TestHandleLeadingVSCMaturedPackets(t *testing.T) {
providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t))
defer ctrl.Finish()
providerKeeper.SetParams(ctx, providertypes.DefaultParams())

vscData := getTenSampleVSCMaturedPacketData()

// Set channel to chain, and chain to client mappings
// (faking multiple established consumer channels)
providerKeeper.SetChannelToChain(ctx, "channel-1", "chain-1")
providerKeeper.SetConsumerClientId(ctx, "chain-1", "client-1")
providerKeeper.SetChannelToChain(ctx, "channel-2", "chain-2")
providerKeeper.SetConsumerClientId(ctx, "chain-2", "client-2")

// Queue some leading vsc matured packet data for chain-1
err := providerKeeper.QueueThrottledVSCMaturedPacketData(ctx, "chain-1", 1, vscData[0])
require.NoError(t, err)
err = providerKeeper.QueueThrottledVSCMaturedPacketData(ctx, "chain-1", 2, vscData[1])
require.NoError(t, err)
err = providerKeeper.QueueThrottledVSCMaturedPacketData(ctx, "chain-1", 3, vscData[2])
require.NoError(t, err)

// Queue some trailing slash packet data (and a couple more vsc matured)
err = providerKeeper.QueueThrottledSlashPacketData(ctx, "chain-1", 4, testkeeper.GetNewSlashPacketData())
require.NoError(t, err)
err = providerKeeper.QueueThrottledSlashPacketData(ctx, "chain-1", 5, testkeeper.GetNewSlashPacketData())
require.NoError(t, err)
err = providerKeeper.QueueThrottledVSCMaturedPacketData(ctx, "chain-1", 6, vscData[3])
require.NoError(t, err)
err = providerKeeper.QueueThrottledVSCMaturedPacketData(ctx, "chain-1", 7, vscData[4])
require.NoError(t, err)

// Queue some leading vsc matured packet data for chain-2
err = providerKeeper.QueueThrottledVSCMaturedPacketData(ctx, "chain-2", 1, vscData[5])
require.NoError(t, err)
err = providerKeeper.QueueThrottledVSCMaturedPacketData(ctx, "chain-2", 2, vscData[6])
require.NoError(t, err)

// And trailing slash packet data for chain-2
err = providerKeeper.QueueThrottledSlashPacketData(ctx, "chain-2", 3, testkeeper.GetNewSlashPacketData())
require.NoError(t, err)
err = providerKeeper.QueueThrottledSlashPacketData(ctx, "chain-2", 4, testkeeper.GetNewSlashPacketData())
require.NoError(t, err)

// And one more trailing vsc matured packet for chain-2
err = providerKeeper.QueueThrottledVSCMaturedPacketData(ctx, "chain-2", 5, vscData[7])
require.NoError(t, err)

// Set VSC Send timestamps for each recv vsc matured packet
providerKeeper.SetVscSendTimestamp(ctx, "chain-1", vscData[0].ValsetUpdateId, time.Now())
providerKeeper.SetVscSendTimestamp(ctx, "chain-1", vscData[1].ValsetUpdateId, time.Now())
providerKeeper.SetVscSendTimestamp(ctx, "chain-1", vscData[2].ValsetUpdateId, time.Now())
providerKeeper.SetVscSendTimestamp(ctx, "chain-1", vscData[3].ValsetUpdateId, time.Now())
providerKeeper.SetVscSendTimestamp(ctx, "chain-1", vscData[4].ValsetUpdateId, time.Now())
providerKeeper.SetVscSendTimestamp(ctx, "chain-2", vscData[5].ValsetUpdateId, time.Now())
providerKeeper.SetVscSendTimestamp(ctx, "chain-2", vscData[6].ValsetUpdateId, time.Now())
providerKeeper.SetVscSendTimestamp(ctx, "chain-2", vscData[7].ValsetUpdateId, time.Now())

// Confirm each chain-specific queue has the expected number of packet data instances
require.Equal(t, uint64(7), providerKeeper.GetThrottledPacketDataSize(ctx, "chain-1"))
require.Equal(t, uint64(5), providerKeeper.GetThrottledPacketDataSize(ctx, "chain-2"))

// Handle leading vsc matured packets and confirm queue sizes change for both chains
providerKeeper.HandleLeadingVSCMaturedPackets(ctx)
require.Equal(t, uint64(4), providerKeeper.GetThrottledPacketDataSize(ctx, "chain-1"))
require.Equal(t, uint64(3), providerKeeper.GetThrottledPacketDataSize(ctx, "chain-2"))

// Confirm the leading vsc matured packet data was handled for both chains,
// but not the vsc matured packet data that trails slash data in the queue.
// This assertion is made by checking that VSC Send timestamps were deleted for
// handled vsc matured packet data.
_, found := providerKeeper.GetVscSendTimestamp(ctx, "chain-1", vscData[0].ValsetUpdateId)
require.False(t, found)
_, found = providerKeeper.GetVscSendTimestamp(ctx, "chain-1", vscData[1].ValsetUpdateId)
require.False(t, found)
_, found = providerKeeper.GetVscSendTimestamp(ctx, "chain-1", vscData[2].ValsetUpdateId)
require.False(t, found)
_, found = providerKeeper.GetVscSendTimestamp(ctx, "chain-1", vscData[3].ValsetUpdateId)
require.True(t, found)
_, found = providerKeeper.GetVscSendTimestamp(ctx, "chain-1", vscData[4].ValsetUpdateId)
require.True(t, found)

_, found = providerKeeper.GetVscSendTimestamp(ctx, "chain-2", vscData[5].ValsetUpdateId)
require.False(t, found)
_, found = providerKeeper.GetVscSendTimestamp(ctx, "chain-2", vscData[6].ValsetUpdateId)
require.False(t, found)
_, found = providerKeeper.GetVscSendTimestamp(ctx, "chain-2", vscData[7].ValsetUpdateId)
require.True(t, found)
}

// TestOnRecvSlashPacket tests the OnRecvSlashPacket method specifically for double-sign slash packets.
func TestOnRecvDoubleSignSlashPacket(t *testing.T) {
providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t))
Expand Down
Loading

0 comments on commit 7691bf5

Please sign in to comment.