Skip to content

Commit

Permalink
changes with slash record type
Browse files Browse the repository at this point in the history
  • Loading branch information
shaspitz committed Jun 26, 2023
1 parent 90266ab commit 6848464
Show file tree
Hide file tree
Showing 7 changed files with 362 additions and 76 deletions.
8 changes: 8 additions & 0 deletions proto/interchain_security/ccv/consumer/v1/consumer.proto
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,11 @@ message MaturingVSCPacket {
google.protobuf.Timestamp maturity_time = 2
[ (gogoproto.stdtime) = true, (gogoproto.nullable) = false ];
}

// A record storing the state of a slash packet sent to the provider chain
// which maybe bounced back and forth until handled by the provider.
message SlashRecord {
bool waiting_on_reply = 1;
google.protobuf.Timestamp send_time = 2
[ (gogoproto.stdtime) = true, (gogoproto.nullable) = false ];
}
17 changes: 8 additions & 9 deletions x/ccv/consumer/keeper/relay.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,7 @@ func (k Keeper) SendPackets(ctx sdk.Context) {

pending := k.GetPendingPackets(ctx)
for _, p := range pending {
if k.GetWaitingOnBouncingSlash(ctx) {
// If we are waiting on the resp of the provider for a bouncing slash, don't send any more packets.
if !k.PacketSendingPermitted(ctx) {
return
}

Expand Down Expand Up @@ -213,11 +212,11 @@ func (k Keeper) SendPackets(ctx sdk.Context) {
k.Logger(ctx).Error("cannot send IBC packet; leaving packet data stored:", "type", p.Type.String(), "err", err.Error())
return
}
// If the packet that was just sent was a Slash packet, set the waiting on bouncing slash flag.
// If the packet that was just sent was a Slash packet, set the waiting on slash reply flag.
// This flag will be toggled false again when consumer hears back from provider. See OnAcknowledgementPacket below.
if p.Type == ccv.SlashPacket {
k.SetWaitingOnBouncingSlash(ctx)
// Return so bouncing slash stays at head of queue.
k.UpdateSlashRecordOnSend(ctx)
// Return so slash stays at head of queue.
return
}
k.DeletePendingDataPackets(ctx, p.Idx) // Can be it's own PR
Expand All @@ -238,11 +237,11 @@ func (k Keeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Pac
case ccv.NoOpResult[0]:
k.Logger(ctx).Info("recv no-op ack", "channel", packet.SourceChannel, "ack", res)
case ccv.SlashPacketHandledResult[0]:
k.ClearWaitingOnBouncingSlash(ctx) // Unblock sending of pending packets.
k.DeleteHeadOfPendingPackets(ctx) // Remove bouncing slash from head of queue. It's been handled.
k.ClearSlashRecord(ctx) // Clears slash record state, unblocks sending of pending packets.
k.DeleteHeadOfPendingPackets(ctx) // Remove slash from head of queue. It's been handled.
case ccv.SlashPacketBouncedResult[0]:
k.ClearWaitingOnBouncingSlash(ctx) // Unblock sending of pending packets.
// Note bouncing slash is still at head of queue and will now be retried.
k.UpdateSlashRecordOnReply(ctx)
// Note slash is still at head of queue and will now be retried after appropriate delay period.
default:
k.Logger(ctx).Error("recv invalid result ack; expected 1, 2, or 3", "channel", packet.SourceChannel, "ack", res)
}
Expand Down
70 changes: 61 additions & 9 deletions x/ccv/consumer/keeper/throttle_retry.go
Original file line number Diff line number Diff line change
@@ -1,27 +1,79 @@
package keeper

import (
"fmt"
"time"

sdktypes "github.com/cosmos/cosmos-sdk/types"
consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types"
)

// TODO: Adjust SendPackets in relay.go
// TODO: will need good integration tests making sure this state is properly init, cleared, etc.

// TODO: incorporate retry delay
// TODO: note on FSM design

// TODO: will need good integration tests making sure this state is properly init, cleared, etc.
func (k Keeper) PacketSendingPermitted(ctx sdktypes.Context) bool {
record, found := k.GetSlashRecord(ctx)
if !found {
// no bouncing slash exists, send permitted
return true
}
if record.WaitingOnReply {
// We are waiting on a reply from provider, block sending
return false
}
// retryDelayPeriod := k.GetParams(ctx).RetryDelayPeriod
retryDelayPeriod := time.Hour
timeSinceSend := ctx.BlockTime().Sub(record.SendTime)
// If retry delay period has elapsed, we can send again
retryPeriodElapsed := timeSinceSend >= retryDelayPeriod
return retryPeriodElapsed
}

func (k Keeper) UpdateSlashRecordOnSend(ctx sdktypes.Context) {
record := consumertypes.NewSlashRecord(
ctx.BlockTime(), // sendTime
true, // waitingOnReply
)
// We don't mind overwriting here, since this is either a retry or the first time we send a slash
k.SetSlashRecord(ctx, record)
}

func (k Keeper) UpdateSlashRecordOnReply(ctx sdktypes.Context) {
record, found := k.GetSlashRecord(ctx)
if !found {
// This should never happen
panic("could not find slash record, but reply was received from provider")
}
record.WaitingOnReply = false
k.SetSlashRecord(ctx, record)
}

func (k Keeper) GetWaitingOnBouncingSlash(ctx sdktypes.Context) bool {
func (k Keeper) GetSlashRecord(ctx sdktypes.Context) (record consumertypes.SlashRecord, found bool) {
store := ctx.KVStore(k.storeKey)
return store.Has(consumertypes.WaitingOnBouncingSlashKey())
bz := store.Get(consumertypes.SlashRecordKey())
if bz == nil {
return record, false
}
err := record.Unmarshal(bz)
if err != nil {
// This should never happen
panic(fmt.Sprintf("could not unmarshal slash record: %v", err))
}
return record, true
}

func (k Keeper) SetWaitingOnBouncingSlash(ctx sdktypes.Context) {
func (k Keeper) SetSlashRecord(ctx sdktypes.Context, record consumertypes.SlashRecord) {
store := ctx.KVStore(k.storeKey)
store.Set(consumertypes.WaitingOnBouncingSlashKey(), []byte{1})
bz, err := record.Marshal()
if err != nil {
// This should never happen
panic(fmt.Sprintf("could not marshal slash record: %v", err))
}
store.Set(consumertypes.SlashRecordKey(), bz)
}

func (k Keeper) ClearWaitingOnBouncingSlash(ctx sdktypes.Context) {
func (k Keeper) ClearSlashRecord(ctx sdktypes.Context) {
store := ctx.KVStore(k.storeKey)
store.Delete(consumertypes.WaitingOnBouncingSlashKey())
store.Delete(consumertypes.SlashRecordKey())
}
Loading

0 comments on commit 6848464

Please sign in to comment.