From 6eaa44faaf2b3556a6d5d3617950e8527f0576b6 Mon Sep 17 00:00:00 2001 From: Yarom Swisa Date: Thu, 16 May 2024 15:14:36 +0300 Subject: [PATCH 01/16] add provider jail --- .../lava/epochstorage/stake_entry.proto | 2 + x/dualstaking/keeper/delegate.go | 2 +- x/epochstorage/types/stake_entry.go | 4 + x/epochstorage/types/stake_entry.pb.go | 142 ++++++++++++++---- x/pairing/keeper/msg_server_unfreeze.go | 25 ++- x/pairing/keeper/unresponsive_provider.go | 27 +++- x/pairing/types/errors.go | 1 + x/pairing/types/expected_keepers.go | 1 + 8 files changed, 158 insertions(+), 46 deletions(-) diff --git a/proto/lavanet/lava/epochstorage/stake_entry.proto b/proto/lavanet/lava/epochstorage/stake_entry.proto index cbb4877023..6cb938b8af 100644 --- a/proto/lavanet/lava/epochstorage/stake_entry.proto +++ b/proto/lavanet/lava/epochstorage/stake_entry.proto @@ -21,6 +21,8 @@ message StakeEntry { uint64 last_change = 12; BlockReport block_report = 13; string vault = 14; + uint64 jails = 16; + int64 jail_time = 17; } // BlockReport holds the most up-to-date info regarding blocks of the provider diff --git a/x/dualstaking/keeper/delegate.go b/x/dualstaking/keeper/delegate.go index dfb7c47fdd..1ef52df6eb 100644 --- a/x/dualstaking/keeper/delegate.go +++ b/x/dualstaking/keeper/delegate.go @@ -230,7 +230,7 @@ func (k Keeper) modifyStakeEntryDelegation(ctx sdk.Context, delegator, provider, details["min_spec_stake"] = k.specKeeper.GetMinStake(ctx, chainID).String() utils.LogLavaEvent(ctx, k.Logger(ctx), types.FreezeFromUnbond, details, "freezing provider due to stake below min spec stake") stakeEntry.Freeze() - } else if delegator == stakeEntry.Vault && stakeEntry.IsFrozen() { + } else if delegator == stakeEntry.Vault && stakeEntry.IsFrozen() && !stakeEntry.IsJailed(ctx.BlockTime().UTC().Unix()) { stakeEntry.UnFreeze(k.epochstorageKeeper.GetCurrentNextEpoch(ctx) + 1) } diff --git a/x/epochstorage/types/stake_entry.go b/x/epochstorage/types/stake_entry.go index 4fda988dae..bfa3e42fce 100644 --- a/x/epochstorage/types/stake_entry.go +++ b/x/epochstorage/types/stake_entry.go @@ -33,6 +33,10 @@ func (stakeEntry *StakeEntry) IsFrozen() bool { return stakeEntry.StakeAppliedBlock == FROZEN_BLOCK } +func (stakeEntry *StakeEntry) IsJailed(time int64) bool { + return stakeEntry.JailTime > time +} + func (stakeEntry *StakeEntry) IsAddressVaultAndNotProvider(address string) bool { return address != stakeEntry.Address && address == stakeEntry.Vault } diff --git a/x/epochstorage/types/stake_entry.pb.go b/x/epochstorage/types/stake_entry.pb.go index 8e8965bb5a..39249ecb97 100644 --- a/x/epochstorage/types/stake_entry.pb.go +++ b/x/epochstorage/types/stake_entry.pb.go @@ -38,6 +38,8 @@ type StakeEntry struct { LastChange uint64 `protobuf:"varint,12,opt,name=last_change,json=lastChange,proto3" json:"last_change,omitempty"` BlockReport *BlockReport `protobuf:"bytes,13,opt,name=block_report,json=blockReport,proto3" json:"block_report,omitempty"` Vault string `protobuf:"bytes,14,opt,name=vault,proto3" json:"vault,omitempty"` + Jails uint64 `protobuf:"varint,16,opt,name=jails,proto3" json:"jails,omitempty"` + JailTime int64 `protobuf:"varint,17,opt,name=jail_time,json=jailTime,proto3" json:"jail_time,omitempty"` } func (m *StakeEntry) Reset() { *m = StakeEntry{} } @@ -164,6 +166,20 @@ func (m *StakeEntry) GetVault() string { return "" } +func (m *StakeEntry) GetJails() uint64 { + if m != nil { + return m.Jails + } + return 0 +} + +func (m *StakeEntry) GetJailTime() int64 { + if m != nil { + return m.JailTime + } + return 0 +} + // BlockReport holds the most up-to-date info regarding blocks of the provider // It is set in the relay payment TX logic // used by the consumer to calculate the provider's sync score @@ -229,39 +245,41 @@ func init() { } var fileDescriptor_df6302d6b53c056e = []byte{ - // 510 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x53, 0x41, 0x6e, 0xdb, 0x3a, - 0x10, 0xb5, 0x12, 0x39, 0xb1, 0x29, 0x27, 0xf8, 0x9f, 0xc9, 0x82, 0xc9, 0x42, 0x51, 0x53, 0xa0, - 0x10, 0xd0, 0x82, 0x42, 0x52, 0xf4, 0x00, 0xb5, 0x11, 0x17, 0x2d, 0xba, 0x52, 0xbb, 0xea, 0xc6, - 0xa0, 0x24, 0x42, 0x26, 0x2c, 0x71, 0x04, 0x91, 0x31, 0x9a, 0x5b, 0xf4, 0x58, 0x59, 0x66, 0xd9, - 0x55, 0x51, 0xd8, 0x27, 0xe8, 0x0d, 0x0a, 0x92, 0x72, 0x12, 0x2f, 0x52, 0xb4, 0x2b, 0x72, 0xe6, - 0xbd, 0x37, 0x98, 0x79, 0xe4, 0xa0, 0x97, 0x15, 0x5b, 0x32, 0xc9, 0x75, 0x62, 0xce, 0x84, 0x37, - 0x90, 0xcf, 0x95, 0x86, 0x96, 0x95, 0x3c, 0x51, 0x9a, 0x2d, 0xf8, 0x8c, 0x4b, 0xdd, 0xde, 0xd0, - 0xa6, 0x05, 0x0d, 0xf8, 0xa4, 0x23, 0x53, 0x73, 0xd2, 0xc7, 0xe4, 0xd3, 0xf8, 0xe9, 0x3a, 0x5c, - 0x16, 0x0d, 0x08, 0xa9, 0x5d, 0x91, 0xd3, 0xe3, 0x12, 0x4a, 0xb0, 0xd7, 0xc4, 0xdc, 0xba, 0x6c, - 0x98, 0x83, 0xaa, 0x41, 0x25, 0x19, 0x53, 0x3c, 0x59, 0x5e, 0x64, 0x5c, 0xb3, 0x8b, 0x24, 0x07, - 0x21, 0x1d, 0x7e, 0xfe, 0xcb, 0x47, 0xe8, 0x93, 0x69, 0xe8, 0xca, 0xf4, 0x83, 0xdf, 0xa0, 0xbe, - 0x6d, 0x8f, 0x78, 0x91, 0x17, 0x07, 0x97, 0x27, 0xd4, 0xc9, 0xa9, 0x91, 0xd3, 0x4e, 0x4e, 0x27, - 0x20, 0xe4, 0xd8, 0xbf, 0xfd, 0x71, 0xd6, 0x4b, 0x1d, 0x1b, 0x13, 0xb4, 0xcf, 0x8a, 0xa2, 0xe5, - 0x4a, 0x91, 0x9d, 0xc8, 0x8b, 0x87, 0xe9, 0x26, 0xc4, 0x14, 0x1d, 0xb9, 0x79, 0x59, 0xd3, 0x54, - 0x82, 0x17, 0xb3, 0xac, 0x82, 0x7c, 0x41, 0x76, 0x23, 0x2f, 0xf6, 0xd3, 0xff, 0x2d, 0xf4, 0xd6, - 0x21, 0x63, 0x03, 0xe0, 0x77, 0x68, 0xb8, 0x99, 0x4b, 0x11, 0x3f, 0xda, 0x8d, 0x83, 0xcb, 0xe7, - 0xf4, 0x49, 0x7b, 0xe8, 0x55, 0xc7, 0xed, 0xda, 0x79, 0xd0, 0xe2, 0x08, 0x05, 0x25, 0x87, 0x0a, - 0x72, 0xa6, 0x05, 0x48, 0xd2, 0x8f, 0xbc, 0xb8, 0x9f, 0x3e, 0x4e, 0xe1, 0x63, 0xd4, 0xcf, 0xe7, - 0x4c, 0x48, 0xb2, 0x67, 0x5b, 0x76, 0x81, 0x19, 0xa5, 0x06, 0x29, 0x16, 0xbc, 0x25, 0x03, 0x37, - 0x4a, 0x17, 0xe2, 0x29, 0x3a, 0x2c, 0x78, 0xc5, 0x4b, 0xa6, 0xf9, 0x4c, 0x83, 0x66, 0x15, 0x19, - 0xfe, 0x9d, 0x49, 0x07, 0x1b, 0xd9, 0x67, 0xa3, 0xda, 0xaa, 0x53, 0x89, 0x5a, 0x68, 0x82, 0xfe, - 0xb1, 0xce, 0x47, 0xa3, 0xc2, 0x09, 0x3a, 0xba, 0xaf, 0x93, 0x43, 0x5d, 0x0b, 0xa5, 0xcc, 0xa4, - 0x81, 0xb5, 0x16, 0x6f, 0xa0, 0xc9, 0x3d, 0x82, 0xcf, 0x50, 0x50, 0x31, 0xa5, 0x67, 0xf9, 0x9c, - 0xc9, 0x92, 0x93, 0x91, 0x25, 0x22, 0x93, 0x9a, 0xd8, 0x0c, 0x7e, 0x8f, 0x46, 0xf6, 0x79, 0x66, - 0x2d, 0x6f, 0xa0, 0xd5, 0xe4, 0xc0, 0xf6, 0xf5, 0xe2, 0x0f, 0xfe, 0xdb, 0x47, 0x4b, 0x2d, 0x3b, - 0x0d, 0xb2, 0x87, 0xc0, 0x98, 0xbb, 0x64, 0xd7, 0x95, 0x26, 0x87, 0xce, 0x5c, 0x1b, 0x7c, 0xf0, - 0x07, 0xfb, 0xff, 0x0d, 0xce, 0xa7, 0x28, 0x18, 0x6f, 0x53, 0x6d, 0x4d, 0xfb, 0xe7, 0xfc, 0xd4, - 0x05, 0xf8, 0x19, 0x1a, 0x55, 0x4c, 0x73, 0xa5, 0xbb, 0x1f, 0xb3, 0x63, 0xc1, 0xc0, 0xe5, 0xac, - 0x7c, 0x3c, 0xbd, 0x5d, 0x85, 0xde, 0xdd, 0x2a, 0xf4, 0x7e, 0xae, 0x42, 0xef, 0xdb, 0x3a, 0xec, - 0xdd, 0xad, 0xc3, 0xde, 0xf7, 0x75, 0xd8, 0xfb, 0xf2, 0xaa, 0x14, 0x7a, 0x7e, 0x9d, 0xd1, 0x1c, - 0xea, 0x64, 0x6b, 0x81, 0xbe, 0x6e, 0xaf, 0x90, 0xbe, 0x69, 0xb8, 0xca, 0xf6, 0xec, 0x2a, 0xbc, - 0xfe, 0x1d, 0x00, 0x00, 0xff, 0xff, 0xc7, 0x25, 0xca, 0x07, 0xb4, 0x03, 0x00, 0x00, + // 539 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x53, 0xd1, 0x4e, 0xdb, 0x30, + 0x14, 0x6d, 0xa0, 0x85, 0xd6, 0x01, 0x04, 0x86, 0x07, 0xc3, 0xa4, 0x90, 0x31, 0x69, 0x8a, 0xb4, + 0xc9, 0x11, 0x4c, 0xfb, 0x80, 0xb5, 0xa2, 0xd3, 0xa6, 0x3d, 0x65, 0x3c, 0xed, 0x25, 0x72, 0xd2, + 0xab, 0xd4, 0xab, 0x13, 0x47, 0xb1, 0xa9, 0xc6, 0x5f, 0xec, 0x23, 0xf6, 0x31, 0x3c, 0xf2, 0xb8, + 0xa7, 0x69, 0x6a, 0x7f, 0x64, 0xb2, 0x9d, 0x02, 0x7d, 0x60, 0xda, 0x9e, 0xe2, 0x73, 0xce, 0x3d, + 0x37, 0xe7, 0xde, 0xc4, 0xe8, 0x95, 0x60, 0x73, 0x56, 0x81, 0x8e, 0xcd, 0x33, 0x86, 0x5a, 0xe6, + 0x53, 0xa5, 0x65, 0xc3, 0x0a, 0x88, 0x95, 0x66, 0x33, 0x48, 0xa1, 0xd2, 0xcd, 0x0d, 0xad, 0x1b, + 0xa9, 0x25, 0x3e, 0x6e, 0x8b, 0xa9, 0x79, 0xd2, 0xc7, 0xc5, 0x27, 0xd1, 0xd3, 0x7d, 0xa0, 0x9a, + 0xd4, 0x92, 0x57, 0xda, 0x35, 0x39, 0x39, 0x2a, 0x64, 0x21, 0xed, 0x31, 0x36, 0xa7, 0x96, 0x0d, + 0x72, 0xa9, 0x4a, 0xa9, 0xe2, 0x8c, 0x29, 0x88, 0xe7, 0xe7, 0x19, 0x68, 0x76, 0x1e, 0xe7, 0x92, + 0x57, 0x4e, 0x3f, 0xfb, 0xd1, 0x43, 0xe8, 0xb3, 0x09, 0x74, 0x69, 0xf2, 0xe0, 0xb7, 0xa8, 0x67, + 0xe3, 0x11, 0x2f, 0xf4, 0x22, 0xff, 0xe2, 0x98, 0x3a, 0x3b, 0x35, 0x76, 0xda, 0xda, 0xe9, 0x48, + 0xf2, 0x6a, 0xd8, 0xbd, 0xfd, 0x75, 0xda, 0x49, 0x5c, 0x35, 0x26, 0x68, 0x9b, 0x4d, 0x26, 0x0d, + 0x28, 0x45, 0x36, 0x42, 0x2f, 0x1a, 0x24, 0x2b, 0x88, 0x29, 0x3a, 0x74, 0xf3, 0xb2, 0xba, 0x16, + 0x1c, 0x26, 0x69, 0x26, 0x64, 0x3e, 0x23, 0x9b, 0xa1, 0x17, 0x75, 0x93, 0x03, 0x2b, 0xbd, 0x73, + 0xca, 0xd0, 0x08, 0xf8, 0x3d, 0x1a, 0xac, 0xe6, 0x52, 0xa4, 0x1b, 0x6e, 0x46, 0xfe, 0xc5, 0x0b, + 0xfa, 0xe4, 0x7a, 0xe8, 0x65, 0x5b, 0xdb, 0xc6, 0x79, 0xf0, 0xe2, 0x10, 0xf9, 0x05, 0x48, 0x21, + 0x73, 0xa6, 0xb9, 0xac, 0x48, 0x2f, 0xf4, 0xa2, 0x5e, 0xf2, 0x98, 0xc2, 0x47, 0xa8, 0x97, 0x4f, + 0x19, 0xaf, 0xc8, 0x96, 0x8d, 0xec, 0x80, 0x19, 0xa5, 0x94, 0x15, 0x9f, 0x41, 0x43, 0xfa, 0x6e, + 0x94, 0x16, 0xe2, 0x31, 0xda, 0x9b, 0x80, 0x80, 0x82, 0x69, 0x48, 0xb5, 0xd4, 0x4c, 0x90, 0xc1, + 0xbf, 0x2d, 0x69, 0x77, 0x65, 0xbb, 0x32, 0xae, 0xb5, 0x3e, 0x82, 0x97, 0x5c, 0x13, 0xf4, 0x9f, + 0x7d, 0x3e, 0x19, 0x17, 0x8e, 0xd1, 0xe1, 0x7d, 0x9f, 0x5c, 0x96, 0x25, 0x57, 0xca, 0x4c, 0xea, + 0xdb, 0xd5, 0xe2, 0x95, 0x34, 0xba, 0x57, 0xf0, 0x29, 0xf2, 0x05, 0x53, 0x3a, 0xcd, 0xa7, 0xac, + 0x2a, 0x80, 0xec, 0xd8, 0x42, 0x64, 0xa8, 0x91, 0x65, 0xf0, 0x07, 0xb4, 0x63, 0x3f, 0x4f, 0xda, + 0x40, 0x2d, 0x1b, 0x4d, 0x76, 0x6d, 0xae, 0x97, 0x7f, 0xd9, 0xbf, 0xfd, 0x68, 0x89, 0xad, 0x4e, + 0xfc, 0xec, 0x01, 0x98, 0xe5, 0xce, 0xd9, 0xb5, 0xd0, 0x64, 0xcf, 0x2d, 0xd7, 0x02, 0xc3, 0x7e, + 0x65, 0x5c, 0x28, 0xb2, 0x6f, 0xdf, 0xed, 0x00, 0x7e, 0x86, 0x06, 0xe6, 0x90, 0x6a, 0x5e, 0x02, + 0x39, 0x08, 0xbd, 0x68, 0x33, 0xe9, 0x1b, 0xe2, 0x8a, 0x97, 0xf0, 0xb1, 0xdb, 0xdf, 0xde, 0xef, + 0x9f, 0x8d, 0x91, 0x3f, 0x5c, 0xef, 0x6e, 0x63, 0xd8, 0xdf, 0xb4, 0x9b, 0x38, 0x80, 0x9f, 0xa3, + 0x1d, 0xc1, 0x34, 0x28, 0xdd, 0xfe, 0x64, 0x1b, 0x56, 0xf4, 0x1d, 0x67, 0xed, 0xc3, 0xf1, 0xed, + 0x22, 0xf0, 0xee, 0x16, 0x81, 0xf7, 0x7b, 0x11, 0x78, 0xdf, 0x97, 0x41, 0xe7, 0x6e, 0x19, 0x74, + 0x7e, 0x2e, 0x83, 0xce, 0x97, 0xd7, 0x05, 0xd7, 0xd3, 0xeb, 0x8c, 0xe6, 0xb2, 0x8c, 0xd7, 0xee, + 0xdc, 0xb7, 0xf5, 0x5b, 0xa7, 0x6f, 0x6a, 0x50, 0xd9, 0x96, 0xbd, 0x3d, 0x6f, 0xfe, 0x04, 0x00, + 0x00, 0xff, 0xff, 0xbc, 0xdc, 0x84, 0xc1, 0xe7, 0x03, 0x00, 0x00, } func (m *StakeEntry) Marshal() (dAtA []byte, err error) { @@ -284,6 +302,20 @@ func (m *StakeEntry) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.JailTime != 0 { + i = encodeVarintStakeEntry(dAtA, i, uint64(m.JailTime)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x88 + } + if m.Jails != 0 { + i = encodeVarintStakeEntry(dAtA, i, uint64(m.Jails)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x80 + } if len(m.Vault) > 0 { i -= len(m.Vault) copy(dAtA[i:], m.Vault) @@ -485,6 +517,12 @@ func (m *StakeEntry) Size() (n int) { if l > 0 { n += 1 + l + sovStakeEntry(uint64(l)) } + if m.Jails != 0 { + n += 2 + sovStakeEntry(uint64(m.Jails)) + } + if m.JailTime != 0 { + n += 2 + sovStakeEntry(uint64(m.JailTime)) + } return n } @@ -911,6 +949,44 @@ func (m *StakeEntry) Unmarshal(dAtA []byte) error { } m.Vault = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 16: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Jails", wireType) + } + m.Jails = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakeEntry + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Jails |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 17: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field JailTime", wireType) + } + m.JailTime = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakeEntry + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.JailTime |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipStakeEntry(dAtA[iNdEx:]) diff --git a/x/pairing/keeper/msg_server_unfreeze.go b/x/pairing/keeper/msg_server_unfreeze.go index 2296394238..32d9c1b169 100644 --- a/x/pairing/keeper/msg_server_unfreeze.go +++ b/x/pairing/keeper/msg_server_unfreeze.go @@ -20,6 +20,11 @@ func (k msgServer) UnfreezeProvider(goCtx context.Context, msg *types.MsgUnfreez return nil, utils.LavaFormatWarning("Unfreeze_cant_get_stake_entry", types.FreezeStakeEntryNotFoundError, []utils.Attribute{{Key: "chainID", Value: chainId}, {Key: "providerAddress", Value: msg.GetCreator()}}...) } + // the provider is not frozen (active or jailed), continue to other chainIDs + if !stakeEntry.IsFrozen() { + continue + } + minStake := k.Keeper.specKeeper.GetMinStake(ctx, chainId) if stakeEntry.EffectiveStake().LT(minStake.Amount) { return nil, utils.LavaFormatWarning("Unfreeze_insufficient_stake", types.UnFreezeInsufficientStakeError, @@ -31,13 +36,21 @@ func (k msgServer) UnfreezeProvider(goCtx context.Context, msg *types.MsgUnfreez }...) } - if stakeEntry.StakeAppliedBlock > unfreezeBlock { - // unfreeze the provider by making the StakeAppliedBlock the current block. This will let the provider be added to the pairing list in the next epoch, when current entries becomes the front of epochStorage - stakeEntry.UnFreeze(unfreezeBlock) - k.epochStorageKeeper.ModifyStakeEntryCurrent(ctx, chainId, stakeEntry) - unfrozen_chains = append(unfrozen_chains, chainId) + if stakeEntry.IsJailed(ctx.BlockTime().UTC().Unix()) { + return nil, utils.LavaFormatWarning("Unfreeze_jailed_provider", types.UnFreezeJailedStakeError, + []utils.Attribute{ + {Key: "chainID", Value: chainId}, + {Key: "providerAddress", Value: msg.GetCreator()}, + {Key: "jailEnd", Value: stakeEntry.JailTime}, + }...) } - // else case does not throw an error because we don't want to fail unfreezing other chains + + // unfreeze the provider by making the StakeAppliedBlock the current block. This will let the provider be added to the pairing list in the next epoch, when current entries becomes the front of epochStorage + stakeEntry.UnFreeze(unfreezeBlock) + stakeEntry.JailTime = 0 + stakeEntry.Jails = 0 + k.epochStorageKeeper.ModifyStakeEntryCurrent(ctx, chainId, stakeEntry) + unfrozen_chains = append(unfrozen_chains, chainId) } utils.LogLavaEvent(ctx, ctx.Logger(), "unfreeze_provider", map[string]string{"providerAddress": msg.GetCreator(), "chainIDs": strings.Join(unfrozen_chains, ",")}, "Provider Unfreeze") return &types.MsgUnfreezeProviderResponse{}, nil diff --git a/x/pairing/keeper/unresponsive_provider.go b/x/pairing/keeper/unresponsive_provider.go index b0ca9f6448..a1239e3b08 100644 --- a/x/pairing/keeper/unresponsive_provider.go +++ b/x/pairing/keeper/unresponsive_provider.go @@ -5,6 +5,7 @@ import ( "math" "strconv" "strings" + "time" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/lavanet/lava/utils" @@ -227,14 +228,28 @@ func (k Keeper) getCurrentProviderStakeStorageList(ctx sdk.Context) []epochstora // Function that punishes providers. Current punishment is freeze func (k Keeper) punishUnresponsiveProvider(ctx sdk.Context, epochs []uint64, provider, chainID string, complaintCU uint64, servicedCU uint64, providerEpochCuMap map[uint64]types.ProviderEpochComplainerCu) error { - // freeze the unresponsive provider - err := k.FreezeProvider(ctx, provider, []string{chainID}, "unresponsiveness") - if err != nil { - utils.LavaFormatError("unable to freeze provider entry due to unresponsiveness", err, - utils.Attribute{Key: "provider", Value: provider}, - utils.Attribute{Key: "chainID", Value: chainID}, + if !utils.IsBech32Address(provider) { + return utils.LavaFormatWarning("Freeze_get_provider_address", fmt.Errorf("invalid address"), + utils.Attribute{Key: "providerAddress", Value: provider}, ) } + + stakeEntry, found := k.epochStorageKeeper.GetStakeEntryByAddressCurrent(ctx, chainID, provider) + if !found { + return utils.LavaFormatWarning("Freeze_cant_get_stake_entry", types.FreezeStakeEntryNotFoundError, []utils.Attribute{{Key: "chainID", Value: chainID}, {Key: "providerAddress", Value: provider}}...) + } + + stakeEntry.Jails++ + + if stakeEntry.Jails > 2 { + stakeEntry.Freeze() + stakeEntry.JailTime = ctx.BlockTime().UTC().Unix() + int64(24*time.Hour) + } else { + stakeEntry.JailTime = ctx.BlockTime().UTC().Unix() + int64(time.Hour) + stakeEntry.StakeAppliedBlock = uint64(ctx.BlockHeight()) + uint64(time.Hour/k.downtimeKeeper.GetParams(ctx).EpochDuration)*k.epochStorageKeeper.EpochBlocksRaw(ctx) + } + k.epochStorageKeeper.ModifyStakeEntryCurrent(ctx, chainID, stakeEntry) + utils.LogLavaEvent(ctx, k.Logger(ctx), types.ProviderJailedEventName, map[string]string{ "provider_address": provider, diff --git a/x/pairing/types/errors.go b/x/pairing/types/errors.go index 92459a4d40..64c934fee6 100644 --- a/x/pairing/types/errors.go +++ b/x/pairing/types/errors.go @@ -24,4 +24,5 @@ var ( UnFreezeInsufficientStakeError = sdkerrors.New("UnFreezeInsufficientStakeError Error", 697, "Could not unfreeze provider due to insufficient stake. Stake must be above minimum stake to unfreeze") InvalidCreatorAddressError = sdkerrors.New("InvalidCreatorAddressError Error", 698, "The creator address is invalid") AmountCoinError = sdkerrors.New("AmountCoinError Error", 699, "Amount limit coin is invalid") + UnFreezeJailedStakeError = sdkerrors.New("UnFreezeJailedStakeError Error", 700, "Could not unfreeze provider due to being jailed") ) diff --git a/x/pairing/types/expected_keepers.go b/x/pairing/types/expected_keepers.go index 601a85248f..562feb1b2b 100644 --- a/x/pairing/types/expected_keepers.go +++ b/x/pairing/types/expected_keepers.go @@ -58,6 +58,7 @@ type EpochstorageKeeper interface { AddFixationRegistry(fixationKey string, getParamFunction func(sdk.Context) any) GetDeletedEpochs(ctx sdk.Context) []uint64 EpochBlocks(ctx sdk.Context, block uint64) (res uint64, err error) + EpochBlocksRaw(ctx sdk.Context) (res uint64) GetUnstakeHoldBlocks(ctx sdk.Context, chainID string) uint64 } From 9a1e5b25f922c70f2dadd4d7834c4293cf179062 Mon Sep 17 00:00:00 2001 From: Yarom Swisa Date: Thu, 16 May 2024 15:26:18 +0300 Subject: [PATCH 02/16] fix existing tests --- .../keeper/unresponsive_provider_test.go | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/x/pairing/keeper/unresponsive_provider_test.go b/x/pairing/keeper/unresponsive_provider_test.go index 92c2c1f2a9..7e0370a62f 100644 --- a/x/pairing/keeper/unresponsive_provider_test.go +++ b/x/pairing/keeper/unresponsive_provider_test.go @@ -8,19 +8,14 @@ import ( "github.com/lavanet/lava/utils/lavaslices" "github.com/lavanet/lava/utils/rand" "github.com/lavanet/lava/utils/sigs" - epochstoragetypes "github.com/lavanet/lava/x/epochstorage/types" "github.com/lavanet/lava/x/pairing/types" "github.com/stretchr/testify/require" ) -func (ts *tester) checkProviderFreeze(provider string, shouldFreeze bool) { +func (ts *tester) checkProviderJailed(provider string, shouldFreeze bool) { stakeEntry, stakeStorageFound := ts.Keepers.Epochstorage.GetStakeEntryByAddressCurrent(ts.Ctx, ts.spec.Name, provider) require.True(ts.T, stakeStorageFound) - if shouldFreeze { - require.Equal(ts.T, uint64(epochstoragetypes.FROZEN_BLOCK), stakeEntry.StakeAppliedBlock) - } else { - require.NotEqual(ts.T, uint64(epochstoragetypes.FROZEN_BLOCK), stakeEntry.StakeAppliedBlock) - } + require.Equal(ts.T, shouldFreeze, stakeEntry.IsJailed(ts.Ctx.BlockTime().UTC().Unix())) } func (ts *tester) checkComplainerReset(provider string, epoch uint64) { @@ -122,7 +117,7 @@ func TestUnresponsivenessStressTest(t *testing.T) { ts.AdvanceEpochs(largerConst) for i := 0; i < unresponsiveCount; i++ { - ts.checkProviderFreeze(providers[i].Addr.String(), true) + ts.checkProviderJailed(providers[i].Addr.String(), true) ts.checkComplainerReset(providers[i].Addr.String(), relayEpoch) } @@ -187,7 +182,7 @@ func TestFreezingProviderForUnresponsiveness(t *testing.T) { ts.AdvanceEpochs(largerConst) - ts.checkProviderFreeze(provider1, true) + ts.checkProviderJailed(provider1, true) ts.checkComplainerReset(provider1, relayEpoch) ts.checkProviderStaked(provider0) } @@ -244,7 +239,7 @@ func TestFreezingProviderForUnresponsivenessContinueComplainingAfterFreeze(t *te ts.AdvanceEpochs(largerConst) - ts.checkProviderFreeze(provider1, true) + ts.checkProviderJailed(provider1, true) ts.checkComplainerReset(provider1, relayEpoch) ts.AdvanceEpochs(2) @@ -266,7 +261,7 @@ func TestFreezingProviderForUnresponsivenessContinueComplainingAfterFreeze(t *te } // test the provider is still frozen - ts.checkProviderFreeze(provider1, true) + ts.checkProviderJailed(provider1, true) } func TestNotFreezingProviderForUnresponsivenessWithMinProviders(t *testing.T) { @@ -341,6 +336,6 @@ func TestNotFreezingProviderForUnresponsivenessWithMinProviders(t *testing.T) { ts.AdvanceEpochs(largerConst) // test the unresponsive provider1 hasn't froze - ts.checkProviderFreeze(provider1Provider, play.shouldBeFrozen) + ts.checkProviderJailed(provider1Provider, play.shouldBeFrozen) } } From c358f973a20c09c40209508c9ac4413774a4c308 Mon Sep 17 00:00:00 2001 From: Yarom Swisa Date: Thu, 16 May 2024 16:01:22 +0300 Subject: [PATCH 03/16] add jail to readme --- x/pairing/README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/x/pairing/README.md b/x/pairing/README.md index a570a6be2b..bba78f6b7f 100644 --- a/x/pairing/README.md +++ b/x/pairing/README.md @@ -62,6 +62,8 @@ type StakeEntry struct { DelegateTotal types.Coin // total delegation to the provider (without self delegation) DelegateLimit types.Coin // delegation total limit DelegateCommission uint64 // commission from delegation rewards + Jails uint64 // number of times the provider have been jailed + JailTime int64 // the time when the jail period is finished the he can come back to service } ``` @@ -95,6 +97,12 @@ A provider can unstake and retrieve their coins. When a provider unstakes, they Freeze Mode enables the Provider to temporarily suspend their node's operation during maintenance to avoid bad Quality of Service (QoS). Freeze/Unfreeze is applied on the next Epoch. The Provider can initiate multiple Freeze actions with one command. +#### Jail + +If a provider is down and is being reported as such by users it will be jailed. +The first 3 times jail is temporary for 1H and will be removed automatically. +After 3 consecutive jails the provider will e jailed for 24H and set to a frozen state, to continue activity the provider must send unfreeze transaction after jail time is over. + ### Pairing The Pairing Engine is a core component of the Lava Network, responsible for connecting consumers with the most suitable service providers. It operates on a complex array of inputs, including the strictest policies defined at the plan, subscription, and project levels. These policies set the boundaries for service provisioning, ensuring that consumers' specific requirements are met while adhering to the network's overarching rules. From 1e24a14319f58a56b717215c1f2c7a92395b78be Mon Sep 17 00:00:00 2001 From: Yarom Swisa Date: Thu, 16 May 2024 16:04:04 +0300 Subject: [PATCH 04/16] reset jail counter after 24H --- x/pairing/keeper/unresponsive_provider.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/x/pairing/keeper/unresponsive_provider.go b/x/pairing/keeper/unresponsive_provider.go index a1239e3b08..c4fab3fde9 100644 --- a/x/pairing/keeper/unresponsive_provider.go +++ b/x/pairing/keeper/unresponsive_provider.go @@ -239,6 +239,10 @@ func (k Keeper) punishUnresponsiveProvider(ctx sdk.Context, epochs []uint64, pro return utils.LavaFormatWarning("Freeze_cant_get_stake_entry", types.FreezeStakeEntryNotFoundError, []utils.Attribute{{Key: "chainID", Value: chainID}, {Key: "providerAddress", Value: provider}}...) } + // if last jail was more than 24H ago, reset the jails counter + if !stakeEntry.IsJailed(ctx.BlockTime().UTC().Unix() + int64(24*time.Hour)) { + stakeEntry.Jails = 0 + } stakeEntry.Jails++ if stakeEntry.Jails > 2 { From f1a0a0463a848c0605e28e3b068220f5afdf8ccb Mon Sep 17 00:00:00 2001 From: Yarom Swisa Date: Mon, 20 May 2024 18:49:22 +0300 Subject: [PATCH 05/16] pr changes --- x/pairing/README.md | 4 +- x/pairing/keeper/unresponsive_provider.go | 58 ++++++++++++----------- 2 files changed, 33 insertions(+), 29 deletions(-) diff --git a/x/pairing/README.md b/x/pairing/README.md index bba78f6b7f..0a23e75b57 100644 --- a/x/pairing/README.md +++ b/x/pairing/README.md @@ -62,8 +62,8 @@ type StakeEntry struct { DelegateTotal types.Coin // total delegation to the provider (without self delegation) DelegateLimit types.Coin // delegation total limit DelegateCommission uint64 // commission from delegation rewards - Jails uint64 // number of times the provider have been jailed - JailTime int64 // the time when the jail period is finished the he can come back to service + Jails uint64 // number of times the provider has been jailed + JailTime int64 // the end of the jail time, after which the provider can return to service } ``` diff --git a/x/pairing/keeper/unresponsive_provider.go b/x/pairing/keeper/unresponsive_provider.go index c4fab3fde9..bfb6431a11 100644 --- a/x/pairing/keeper/unresponsive_provider.go +++ b/x/pairing/keeper/unresponsive_provider.go @@ -13,7 +13,12 @@ import ( "github.com/lavanet/lava/x/pairing/types" ) -const THRESHOLD_FACTOR = 4 +const ( + THRESHOLD_FACTOR = 4 + SOFT_JAILS = 2 + SOFT_JAIL_TIME = 1 * time.Hour + HARD_JAIL_TIME = 24 * time.Hour +) // PunishUnresponsiveProviders punished unresponsive providers (current punishment: freeze) func (k Keeper) PunishUnresponsiveProviders(ctx sdk.Context, epochsNumToCheckCUForUnresponsiveProvider, epochsNumToCheckCUForComplainers uint64) { @@ -79,15 +84,15 @@ func (k Keeper) PunishUnresponsiveProviders(ctx sdk.Context, epochsNumToCheckCUF // check all supported providers from all geolocations prior to making decisions existingProviders := map[string]uint64{} - stakeAppliedBlockProviders := map[string]uint64{} + stakeEntries := map[string]epochstoragetypes.StakeEntry{} for _, providerStakeStorage := range providerStakeStorageList { providerStakeEntriesForChain := providerStakeStorage.GetStakeEntries() // count providers per geolocation for _, providerStakeEntry := range providerStakeEntriesForChain { if !providerStakeEntry.IsFrozen() { existingProviders[providerStakeEntry.GetChain()]++ - stakeAppliedBlockProviders[ProviderChainID(providerStakeEntry.Address, providerStakeEntry.Chain)] = providerStakeEntry.StakeAppliedBlock } + stakeEntries[ProviderChainID(providerStakeEntry.Address, providerStakeEntry.Chain)] = providerStakeEntry } } @@ -97,9 +102,14 @@ func (k Keeper) PunishUnresponsiveProviders(ctx sdk.Context, epochsNumToCheckCUF pecsDetailed := k.GetAllProviderEpochComplainerCuStore(ctx) complainedProviders := map[string]map[uint64]types.ProviderEpochComplainerCu{} // map[provider chainID]map[epoch]ProviderEpochComplainerCu for _, pec := range pecsDetailed { - if minHistoryBlock < stakeAppliedBlockProviders[pec.Provider] { - // this staked provider has too short history (either since staking - // or since it was last unfrozen) - do not consider for jailing + entry, ok := stakeEntries[pec.Provider] + if ok { + if minHistoryBlock < entry.StakeAppliedBlock { + // this staked provider has too short history (either since staking + // or since it was last unfrozen) - do not consider for jailing + continue + } + } else { continue } @@ -136,7 +146,12 @@ func (k Keeper) PunishUnresponsiveProviders(ctx sdk.Context, epochsNumToCheckCUF // providerPaymentStorageKeyList is not empty -> provider should be punished if len(epochs) != 0 && existingProviders[chainID] > minProviders { - err = k.punishUnresponsiveProvider(ctx, epochs, provider, chainID, complaintCU, servicedCU, complainedProviders[key]) + entry, ok := stakeEntries[key] + if !ok { + utils.LavaFormatWarning("Freeze_cant_get_stake_entry", types.FreezeStakeEntryNotFoundError, []utils.Attribute{{Key: "chainID", Value: chainID}, {Key: "providerAddress", Value: provider}}...) + + } + err = k.punishUnresponsiveProvider(ctx, epochs, entry, complaintCU, servicedCU, complainedProviders[key]) existingProviders[chainID]-- if err != nil { utils.LavaFormatError("unstake unresponsive providers failed to punish provider", err, @@ -227,44 +242,33 @@ func (k Keeper) getCurrentProviderStakeStorageList(ctx sdk.Context) []epochstora } // Function that punishes providers. Current punishment is freeze -func (k Keeper) punishUnresponsiveProvider(ctx sdk.Context, epochs []uint64, provider, chainID string, complaintCU uint64, servicedCU uint64, providerEpochCuMap map[uint64]types.ProviderEpochComplainerCu) error { - if !utils.IsBech32Address(provider) { - return utils.LavaFormatWarning("Freeze_get_provider_address", fmt.Errorf("invalid address"), - utils.Attribute{Key: "providerAddress", Value: provider}, - ) - } - - stakeEntry, found := k.epochStorageKeeper.GetStakeEntryByAddressCurrent(ctx, chainID, provider) - if !found { - return utils.LavaFormatWarning("Freeze_cant_get_stake_entry", types.FreezeStakeEntryNotFoundError, []utils.Attribute{{Key: "chainID", Value: chainID}, {Key: "providerAddress", Value: provider}}...) - } - +func (k Keeper) punishUnresponsiveProvider(ctx sdk.Context, epochs []uint64, stakeEntry epochstoragetypes.StakeEntry, complaintCU uint64, servicedCU uint64, providerEpochCuMap map[uint64]types.ProviderEpochComplainerCu) error { // if last jail was more than 24H ago, reset the jails counter - if !stakeEntry.IsJailed(ctx.BlockTime().UTC().Unix() + int64(24*time.Hour)) { + if !stakeEntry.IsJailed(ctx.BlockTime().UTC().Unix() - int64(HARD_JAIL_TIME)) { stakeEntry.Jails = 0 } stakeEntry.Jails++ - if stakeEntry.Jails > 2 { + if stakeEntry.Jails > SOFT_JAILS { stakeEntry.Freeze() - stakeEntry.JailTime = ctx.BlockTime().UTC().Unix() + int64(24*time.Hour) + stakeEntry.JailTime = ctx.BlockTime().UTC().Unix() + int64(HARD_JAIL_TIME) } else { - stakeEntry.JailTime = ctx.BlockTime().UTC().Unix() + int64(time.Hour) + stakeEntry.JailTime = ctx.BlockTime().UTC().Unix() + int64(SOFT_JAIL_TIME) stakeEntry.StakeAppliedBlock = uint64(ctx.BlockHeight()) + uint64(time.Hour/k.downtimeKeeper.GetParams(ctx).EpochDuration)*k.epochStorageKeeper.EpochBlocksRaw(ctx) } - k.epochStorageKeeper.ModifyStakeEntryCurrent(ctx, chainID, stakeEntry) + k.epochStorageKeeper.ModifyStakeEntryCurrent(ctx, stakeEntry.Chain, stakeEntry) utils.LogLavaEvent(ctx, k.Logger(ctx), types.ProviderJailedEventName, map[string]string{ - "provider_address": provider, - "chain_id": chainID, + "provider_address": stakeEntry.Address, + "chain_id": stakeEntry.Chain, "complaint_cu": strconv.FormatUint(complaintCU, 10), "serviced_cu": strconv.FormatUint(servicedCU, 10), }, "Unresponsive provider was freezed due to unresponsiveness") // reset the provider's complainer CU (so he won't get punished for the same complaints twice) - k.resetComplainersCU(ctx, epochs, provider, chainID, providerEpochCuMap) + k.resetComplainersCU(ctx, epochs, stakeEntry.Address, stakeEntry.Chain, providerEpochCuMap) return nil } From 1e88e071e43b4eefbd67504557125405307606f5 Mon Sep 17 00:00:00 2001 From: Yarom Swisa Date: Mon, 20 May 2024 18:49:58 +0300 Subject: [PATCH 06/16] lint --- x/pairing/keeper/unresponsive_provider.go | 1 - 1 file changed, 1 deletion(-) diff --git a/x/pairing/keeper/unresponsive_provider.go b/x/pairing/keeper/unresponsive_provider.go index bfb6431a11..aea686b366 100644 --- a/x/pairing/keeper/unresponsive_provider.go +++ b/x/pairing/keeper/unresponsive_provider.go @@ -149,7 +149,6 @@ func (k Keeper) PunishUnresponsiveProviders(ctx sdk.Context, epochsNumToCheckCUF entry, ok := stakeEntries[key] if !ok { utils.LavaFormatWarning("Freeze_cant_get_stake_entry", types.FreezeStakeEntryNotFoundError, []utils.Attribute{{Key: "chainID", Value: chainID}, {Key: "providerAddress", Value: provider}}...) - } err = k.punishUnresponsiveProvider(ctx, epochs, entry, complaintCU, servicedCU, complainedProviders[key]) existingProviders[chainID]-- From f48699cace5f4cbb0902ad856248a23d2fe90ca8 Mon Sep 17 00:00:00 2001 From: Yarom Swisa Date: Tue, 21 May 2024 13:38:42 +0300 Subject: [PATCH 07/16] fix bug --- x/pairing/keeper/unresponsive_provider.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x/pairing/keeper/unresponsive_provider.go b/x/pairing/keeper/unresponsive_provider.go index aea686b366..36aeb8ddf0 100644 --- a/x/pairing/keeper/unresponsive_provider.go +++ b/x/pairing/keeper/unresponsive_provider.go @@ -102,7 +102,7 @@ func (k Keeper) PunishUnresponsiveProviders(ctx sdk.Context, epochsNumToCheckCUF pecsDetailed := k.GetAllProviderEpochComplainerCuStore(ctx) complainedProviders := map[string]map[uint64]types.ProviderEpochComplainerCu{} // map[provider chainID]map[epoch]ProviderEpochComplainerCu for _, pec := range pecsDetailed { - entry, ok := stakeEntries[pec.Provider] + entry, ok := stakeEntries[ProviderChainID(pec.Provider, pec.ChainId)] if ok { if minHistoryBlock < entry.StakeAppliedBlock { // this staked provider has too short history (either since staking @@ -149,6 +149,7 @@ func (k Keeper) PunishUnresponsiveProviders(ctx sdk.Context, epochsNumToCheckCUF entry, ok := stakeEntries[key] if !ok { utils.LavaFormatWarning("Freeze_cant_get_stake_entry", types.FreezeStakeEntryNotFoundError, []utils.Attribute{{Key: "chainID", Value: chainID}, {Key: "providerAddress", Value: provider}}...) + continue } err = k.punishUnresponsiveProvider(ctx, epochs, entry, complaintCU, servicedCU, complainedProviders[key]) existingProviders[chainID]-- From db61538dcf2d3cb2323588e57fc499dc51bc3b7f Mon Sep 17 00:00:00 2001 From: Yarom Swisa Date: Tue, 21 May 2024 15:37:59 +0300 Subject: [PATCH 08/16] update readme --- x/pairing/README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/x/pairing/README.md b/x/pairing/README.md index 0a23e75b57..b89d76bb26 100644 --- a/x/pairing/README.md +++ b/x/pairing/README.md @@ -97,12 +97,6 @@ A provider can unstake and retrieve their coins. When a provider unstakes, they Freeze Mode enables the Provider to temporarily suspend their node's operation during maintenance to avoid bad Quality of Service (QoS). Freeze/Unfreeze is applied on the next Epoch. The Provider can initiate multiple Freeze actions with one command. -#### Jail - -If a provider is down and is being reported as such by users it will be jailed. -The first 3 times jail is temporary for 1H and will be removed automatically. -After 3 consecutive jails the provider will e jailed for 24H and set to a frozen state, to continue activity the provider must send unfreeze transaction after jail time is over. - ### Pairing The Pairing Engine is a core component of the Lava Network, responsible for connecting consumers with the most suitable service providers. It operates on a complex array of inputs, including the strictest policies defined at the plan, subscription, and project levels. These policies set the boundaries for service provisioning, ensuring that consumers' specific requirements are met while adhering to the network's overarching rules. @@ -214,12 +208,18 @@ Pairing verification is used by the provider to determine whether to offer servi #### Unresponsiveness -Providers can get punished for being unresponsive to consumer requests. If a provider wishes to stop getting paired with consumers for any reason to avoid getting punished, it can freeze itself. Currently, the punishment for being unresponsive is freezing. In the future, providers will be jailed for this kind of behaviour. +Providers can get punished for being unresponsive to consumer requests. If a provider wishes to stop getting paired with consumers for any reason to avoid getting punished, it can freeze itself. Currently, the punishment for being unresponsive is jailing. When a consumer is getting paired with a provider, it sends requests for service. If provider A is unresponsive after a few tries, the consumer switches to another provider from its pairing list, provider B, and send requests to it. When communicatting with provider B, the consumer appends the address of provider A to its request, thus adding the current request's CU to provider A's "complainers CU" counter. Every epoch start, the amount of complainers CU is compared with the amount of serviced CU of each provider across a few epochs back. If the complainers CU is higher, the provider is considered unresponsive and gets punished. The number of epochs back is determined by the recommendedEpochNumToCollectPayment parameter +#### Jail + +If a provider is down and users report it, the provider will be jailed. +The first three instances of jailing are temporary, lasting 1 hour each, and will be automatically removed. +After three consecutive jailings, the provider will be jailed for 24 hours and set to a 'frozen' state. To resume activity, the provider must send an 'unfreeze' transaction after the jail time has ended. + #### Static Providers Static providers are Lava chain providers that offer services to any consumer without relying on pairing. This feature allows new consumers to communicate with the Lava chain without a centralized provider. For example, when a new consumer wants to start using Lava, it needs to obtain its pairing list from a Lava node. However, since it initially does not have a list of providers to communicate with, it can use the static providers list to obtain its initial pairing list. From 152d5bb9851cab38fdcdc7f192fec1bf1bc46589 Mon Sep 17 00:00:00 2001 From: Yarom Swisa Date: Mon, 27 May 2024 15:05:52 +0300 Subject: [PATCH 09/16] prepare for testing --- testutil/keeper/keepers_init.go | 18 ++++------------ x/pairing/keeper/unresponsive_provider.go | 4 ++-- .../keeper/unresponsive_provider_test.go | 21 +++++++++++-------- 3 files changed, 18 insertions(+), 25 deletions(-) diff --git a/testutil/keeper/keepers_init.go b/testutil/keeper/keepers_init.go index e364ca4a6d..984c93689e 100644 --- a/testutil/keeper/keepers_init.go +++ b/testutil/keeper/keepers_init.go @@ -453,16 +453,9 @@ func AdvanceToBlock(ctx context.Context, ks *Keepers, block uint64, customBlockT return ctx } - if len(customBlockTime) > 0 { - for uint64(unwrapedCtx.BlockHeight()) < block { - ctx = AdvanceBlock(ctx, ks, customBlockTime...) - unwrapedCtx = sdk.UnwrapSDKContext(ctx) - } - } else { - for uint64(unwrapedCtx.BlockHeight()) < block { - ctx = AdvanceBlock(ctx, ks) - unwrapedCtx = sdk.UnwrapSDKContext(ctx) - } + for uint64(unwrapedCtx.BlockHeight()) < block { + ctx = AdvanceBlock(ctx, ks, customBlockTime...) + unwrapedCtx = sdk.UnwrapSDKContext(ctx) } return ctx @@ -476,10 +469,7 @@ func AdvanceEpoch(ctx context.Context, ks *Keepers, customBlockTime ...time.Dura if err != nil { panic(err) } - if len(customBlockTime) > 0 { - return AdvanceToBlock(ctx, ks, nextEpochBlockNum, customBlockTime...) - } - return AdvanceToBlock(ctx, ks, nextEpochBlockNum) + return AdvanceToBlock(ctx, ks, nextEpochBlockNum, customBlockTime...) } // Make sure you save the new context diff --git a/x/pairing/keeper/unresponsive_provider.go b/x/pairing/keeper/unresponsive_provider.go index 36aeb8ddf0..0278579f96 100644 --- a/x/pairing/keeper/unresponsive_provider.go +++ b/x/pairing/keeper/unresponsive_provider.go @@ -16,8 +16,8 @@ import ( const ( THRESHOLD_FACTOR = 4 SOFT_JAILS = 2 - SOFT_JAIL_TIME = 1 * time.Hour - HARD_JAIL_TIME = 24 * time.Hour + SOFT_JAIL_TIME = 1 * time.Hour / time.Second + HARD_JAIL_TIME = 24 * time.Hour / time.Second ) // PunishUnresponsiveProviders punished unresponsive providers (current punishment: freeze) diff --git a/x/pairing/keeper/unresponsive_provider_test.go b/x/pairing/keeper/unresponsive_provider_test.go index 7e0370a62f..6917cdf4e5 100644 --- a/x/pairing/keeper/unresponsive_provider_test.go +++ b/x/pairing/keeper/unresponsive_provider_test.go @@ -2,12 +2,13 @@ package keeper_test import ( "testing" + "time" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/lavanet/lava/testutil/common" "github.com/lavanet/lava/utils/lavaslices" "github.com/lavanet/lava/utils/rand" "github.com/lavanet/lava/utils/sigs" + "github.com/lavanet/lava/x/pairing/keeper" "github.com/lavanet/lava/x/pairing/types" "github.com/stretchr/testify/require" ) @@ -16,6 +17,9 @@ func (ts *tester) checkProviderJailed(provider string, shouldFreeze bool) { stakeEntry, stakeStorageFound := ts.Keepers.Epochstorage.GetStakeEntryByAddressCurrent(ts.Ctx, ts.spec.Name, provider) require.True(ts.T, stakeStorageFound) require.Equal(ts.T, shouldFreeze, stakeEntry.IsJailed(ts.Ctx.BlockTime().UTC().Unix())) + if shouldFreeze { + require.InDelta(ts.T, stakeEntry.JailTime, ts.BlockTime().UTC().Unix(), float64(keeper.SOFT_JAIL_TIME)) + } } func (ts *tester) checkComplainerReset(provider string, epoch uint64) { @@ -114,7 +118,7 @@ func TestUnresponsivenessStressTest(t *testing.T) { largerConst = recommendedEpochNumToCollectPayment } - ts.AdvanceEpochs(largerConst) + ts.AdvanceEpochs(largerConst, time.Nanosecond) for i := 0; i < unresponsiveCount; i++ { ts.checkProviderJailed(providers[i].Addr.String(), true) @@ -180,7 +184,7 @@ func TestFreezingProviderForUnresponsiveness(t *testing.T) { largerConst = recommendedEpochNumToCollectPayment } - ts.AdvanceEpochs(largerConst) + ts.AdvanceEpochs(largerConst, time.Second) ts.checkProviderJailed(provider1, true) ts.checkComplainerReset(provider1, relayEpoch) @@ -237,12 +241,12 @@ func TestFreezingProviderForUnresponsivenessContinueComplainingAfterFreeze(t *te largerConst = recommendedEpochNumToCollectPayment } - ts.AdvanceEpochs(largerConst) + ts.AdvanceEpochs(largerConst, time.Second) ts.checkProviderJailed(provider1, true) ts.checkComplainerReset(provider1, relayEpoch) - ts.AdvanceEpochs(2) + ts.AdvanceEpochs(2, time.Second) // create more relay requests for provider0 that contain complaints about provider1 for clientIndex := 0; clientIndex < clientsCount; clientIndex++ { @@ -298,14 +302,13 @@ func TestNotFreezingProviderForUnresponsivenessWithMinProviders(t *testing.T) { } // advance enough epochs so we can check punishment due to unresponsiveness // (if the epoch is too early, there's no punishment) - ts.AdvanceEpochs(largerConst + recommendedEpochNumToCollectPayment) + ts.AdvanceEpochs(largerConst+recommendedEpochNumToCollectPayment, time.Nanosecond) // find two providers in the pairing pairing, err := ts.QueryPairingGetPairing(ts.spec.Name, clients[0].Addr.String()) require.NoError(t, err) provider0Provider := pairing.Providers[0].Address provider1Provider := pairing.Providers[1].Address - provider0Vault := sdk.MustAccAddressFromBech32(pairing.Providers[0].Vault) // create unresponsive data that includes provider1 being unresponsive unresponsiveProvidersData := []*types.ReportedProvider{{Address: provider1Provider}} @@ -325,7 +328,7 @@ func TestNotFreezingProviderForUnresponsivenessWithMinProviders(t *testing.T) { Relays: lavaslices.Slice(relaySession), } - ts.payAndVerifyBalance(relayPaymentMessage, clients[clientIndex].Addr, provider0Vault, true, true, 100) + ts.relayPaymentWithoutPay(relayPaymentMessage, true) } // advance enough epochs so the unresponsive provider will be punished @@ -333,7 +336,7 @@ func TestNotFreezingProviderForUnresponsivenessWithMinProviders(t *testing.T) { largerConst = recommendedEpochNumToCollectPayment } - ts.AdvanceEpochs(largerConst) + ts.AdvanceEpochs(largerConst, time.Nanosecond) // test the unresponsive provider1 hasn't froze ts.checkProviderJailed(provider1Provider, play.shouldBeFrozen) From 099a68306d25f3acdfc1a749ae837f5c22c88e1b Mon Sep 17 00:00:00 2001 From: Yaroms Date: Mon, 27 May 2024 23:10:09 +0300 Subject: [PATCH 10/16] add unitest --- .../keeper/unresponsive_provider_test.go | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/x/pairing/keeper/unresponsive_provider_test.go b/x/pairing/keeper/unresponsive_provider_test.go index 6917cdf4e5..ab836e9d09 100644 --- a/x/pairing/keeper/unresponsive_provider_test.go +++ b/x/pairing/keeper/unresponsive_provider_test.go @@ -342,3 +342,89 @@ func TestNotFreezingProviderForUnresponsivenessWithMinProviders(t *testing.T) { ts.checkProviderJailed(provider1Provider, play.shouldBeFrozen) } } + +// Test to measure the time the check for unresponsiveness every epoch start takes +func TestJailProviderForUnresponsiveness(t *testing.T) { + // setup test for unresponsiveness + clientsCount := 1 + providersCount := 10 + + ts := newTester(t) + ts.setupForPayments(providersCount, clientsCount, providersCount-1) // set providers-to-pair + + clients := ts.Accounts(common.CONSUMER) + + recommendedEpochNumToCollectPayment := ts.Keepers.Pairing.RecommendedEpochNumToCollectPayment(ts.Ctx) + + largerConst := types.EPOCHS_NUM_TO_CHECK_CU_FOR_UNRESPONSIVE_PROVIDER + if largerConst < types.EPOCHS_NUM_TO_CHECK_FOR_COMPLAINERS { + largerConst = types.EPOCHS_NUM_TO_CHECK_FOR_COMPLAINERS + } + + // advance enough epochs so we can check punishment due to unresponsiveness + // (if the epoch is too early, there's no punishment) + ts.AdvanceEpochs(largerConst + recommendedEpochNumToCollectPayment) + + // find two providers in the pairing + pairing, err := ts.QueryPairingGetPairing(ts.spec.Name, clients[0].Addr.String()) + require.NoError(t, err) + provider0 := pairing.Providers[0].Address + provider1 := pairing.Providers[1].Address + + jailProvider := func() { + found := false + // make sure our provider is in the pairing + for !found { + ts.AdvanceEpoch(0) + pairing1, err := ts.QueryPairingVerifyPairing(ts.spec.Name, clients[0].Addr.String(), provider0, ts.BlockHeight()) + require.NoError(t, err) + + pairing2, err := ts.QueryPairingVerifyPairing(ts.spec.Name, clients[0].Addr.String(), provider1, ts.BlockHeight()) + require.NoError(t, err) + found = pairing1.Valid && pairing2.Valid + } + + // create relay requests for provider0 that contain complaints about provider1 + unresponsiveProvidersData := []*types.ReportedProvider{{Address: provider1}} + relayEpoch := ts.BlockHeight() + cuSum := ts.spec.ApiCollections[0].Apis[0].ComputeUnits * 10 + + relaySession := ts.newRelaySession(provider0, 0, cuSum, relayEpoch, 0) + relaySession.UnresponsiveProviders = unresponsiveProvidersData + sig, err := sigs.Sign(clients[0].SK, *relaySession) + relaySession.Sig = sig + require.NoError(t, err) + relayPaymentMessage := types.MsgRelayPayment{ + Creator: provider0, + Relays: lavaslices.Slice(relaySession), + } + ts.relayPaymentWithoutPay(relayPaymentMessage, true) + + // advance enough epochs so the unresponsive provider will be punished + if largerConst < recommendedEpochNumToCollectPayment { + largerConst = recommendedEpochNumToCollectPayment + } + + ts.AdvanceEpochs(largerConst, 0) + + ts.checkProviderJailed(provider1, true) + ts.checkComplainerReset(provider1, relayEpoch) + ts.checkProviderStaked(provider0) + } + + // jail first time + jailProvider() + + // advance epoch and one hour to leave jail + ts.AdvanceBlock(time.Hour) + ts.AdvanceEpoch(0) + ts.checkProviderJailed(provider1, false) + + // jail second time + jailProvider() + + // advance epoch and one hour to leave jail + ts.AdvanceBlock(time.Hour) + ts.AdvanceEpoch(time.Nanosecond) + ts.checkProviderJailed(provider1, false) +} From 745909a01d15a0101e22e26ad1797e6c7ccfd31f Mon Sep 17 00:00:00 2001 From: Yaroms Date: Tue, 28 May 2024 02:13:37 +0300 Subject: [PATCH 11/16] fix bugs and unitest --- x/pairing/keeper/epoch_cu.go | 6 ++++ x/pairing/keeper/unresponsive_provider.go | 15 ++++------ .../keeper/unresponsive_provider_test.go | 29 +++++++++++++------ 3 files changed, 31 insertions(+), 19 deletions(-) diff --git a/x/pairing/keeper/epoch_cu.go b/x/pairing/keeper/epoch_cu.go index 8951a4d626..c9b9135e2c 100644 --- a/x/pairing/keeper/epoch_cu.go +++ b/x/pairing/keeper/epoch_cu.go @@ -158,6 +158,12 @@ func (k Keeper) GetProviderEpochComplainerCu(ctx sdk.Context, epoch uint64, prov return val, true } +// RemoveProviderEpochComplainerCu deletes a ProviderEpochComplainerCu in the store +func (k Keeper) RemoveProviderEpochComplainerCu(ctx sdk.Context, epoch uint64, provider string, chainID string) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.ProviderEpochComplainerCuKeyPrefix()) + store.Delete(types.ProviderEpochCuKey(epoch, provider, chainID)) +} + // RemoveProviderEpochComplainerCu removes a ProviderEpochCu from the store func (k Keeper) RemoveAllProviderEpochComplainerCu(ctx sdk.Context, epoch uint64) { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.ProviderEpochComplainerCuKeyPrefix()) diff --git a/x/pairing/keeper/unresponsive_provider.go b/x/pairing/keeper/unresponsive_provider.go index 0278579f96..49ed3c5ede 100644 --- a/x/pairing/keeper/unresponsive_provider.go +++ b/x/pairing/keeper/unresponsive_provider.go @@ -104,7 +104,7 @@ func (k Keeper) PunishUnresponsiveProviders(ctx sdk.Context, epochsNumToCheckCUF for _, pec := range pecsDetailed { entry, ok := stakeEntries[ProviderChainID(pec.Provider, pec.ChainId)] if ok { - if minHistoryBlock < entry.StakeAppliedBlock { + if minHistoryBlock < entry.StakeAppliedBlock && entry.Jails == 0 { // this staked provider has too short history (either since staking // or since it was last unfrozen) - do not consider for jailing continue @@ -254,7 +254,9 @@ func (k Keeper) punishUnresponsiveProvider(ctx sdk.Context, epochs []uint64, sta stakeEntry.JailTime = ctx.BlockTime().UTC().Unix() + int64(HARD_JAIL_TIME) } else { stakeEntry.JailTime = ctx.BlockTime().UTC().Unix() + int64(SOFT_JAIL_TIME) - stakeEntry.StakeAppliedBlock = uint64(ctx.BlockHeight()) + uint64(time.Hour/k.downtimeKeeper.GetParams(ctx).EpochDuration)*k.epochStorageKeeper.EpochBlocksRaw(ctx) + epochduration := k.downtimeKeeper.GetParams(ctx).EpochDuration / time.Second + epochblocks := k.epochStorageKeeper.EpochBlocksRaw(ctx) + stakeEntry.StakeAppliedBlock = uint64(ctx.BlockHeight()) + uint64(SOFT_JAIL_TIME/epochduration)*epochblocks } k.epochStorageKeeper.ModifyStakeEntryCurrent(ctx, stakeEntry.Chain, stakeEntry) @@ -276,13 +278,6 @@ func (k Keeper) punishUnresponsiveProvider(ctx sdk.Context, epochs []uint64, sta // resetComplainersCU resets the complainers CU for a specific provider and chain func (k Keeper) resetComplainersCU(ctx sdk.Context, epochs []uint64, provider string, chainID string, providerEpochCuMap map[uint64]types.ProviderEpochComplainerCu) { for _, epoch := range epochs { - pec, ok := providerEpochCuMap[epoch] - if !ok { - continue - } - - // reset the complainer CU - pec.ComplainersCu = 0 - k.SetProviderEpochComplainerCu(ctx, epoch, provider, chainID, pec) + k.RemoveProviderEpochComplainerCu(ctx, epoch, provider, chainID) } } diff --git a/x/pairing/keeper/unresponsive_provider_test.go b/x/pairing/keeper/unresponsive_provider_test.go index ab836e9d09..038bd7d019 100644 --- a/x/pairing/keeper/unresponsive_provider_test.go +++ b/x/pairing/keeper/unresponsive_provider_test.go @@ -18,16 +18,19 @@ func (ts *tester) checkProviderJailed(provider string, shouldFreeze bool) { require.True(ts.T, stakeStorageFound) require.Equal(ts.T, shouldFreeze, stakeEntry.IsJailed(ts.Ctx.BlockTime().UTC().Unix())) if shouldFreeze { - require.InDelta(ts.T, stakeEntry.JailTime, ts.BlockTime().UTC().Unix(), float64(keeper.SOFT_JAIL_TIME)) + jailDelta := keeper.SOFT_JAIL_TIME + if stakeEntry.Jails > keeper.SOFT_JAILS { + jailDelta = keeper.HARD_JAIL_TIME + } + require.InDelta(ts.T, stakeEntry.JailTime, ts.BlockTime().UTC().Unix(), float64(jailDelta)) } } func (ts *tester) checkComplainerReset(provider string, epoch uint64) { // validate the complainers CU field in the unresponsive provider's providerPaymentStorage // was reset after being punished (use the epoch from the relay - when it got reported) - pec, found := ts.Keepers.Pairing.GetProviderEpochComplainerCu(ts.Ctx, epoch, provider, ts.spec.Name) - require.Equal(ts.T, true, found) - require.Equal(ts.T, uint64(0), pec.ComplainersCu) + _, found := ts.Keepers.Pairing.GetProviderEpochComplainerCu(ts.Ctx, epoch, provider, ts.spec.Name) + require.Equal(ts.T, false, found) } func (ts *tester) checkProviderStaked(provider string) { @@ -365,6 +368,11 @@ func TestJailProviderForUnresponsiveness(t *testing.T) { // (if the epoch is too early, there's no punishment) ts.AdvanceEpochs(largerConst + recommendedEpochNumToCollectPayment) + // advance enough epochs so the unresponsive provider will be punished + if largerConst < recommendedEpochNumToCollectPayment { + largerConst = recommendedEpochNumToCollectPayment + } + // find two providers in the pairing pairing, err := ts.QueryPairingGetPairing(ts.spec.Name, clients[0].Addr.String()) require.NoError(t, err) @@ -400,11 +408,6 @@ func TestJailProviderForUnresponsiveness(t *testing.T) { } ts.relayPaymentWithoutPay(relayPaymentMessage, true) - // advance enough epochs so the unresponsive provider will be punished - if largerConst < recommendedEpochNumToCollectPayment { - largerConst = recommendedEpochNumToCollectPayment - } - ts.AdvanceEpochs(largerConst, 0) ts.checkProviderJailed(provider1, true) @@ -427,4 +430,12 @@ func TestJailProviderForUnresponsiveness(t *testing.T) { ts.AdvanceBlock(time.Hour) ts.AdvanceEpoch(time.Nanosecond) ts.checkProviderJailed(provider1, false) + + // jail third time + jailProvider() + + // advance epoch and one hour to leave jail + ts.AdvanceBlock(time.Hour) + ts.AdvanceEpoch(time.Nanosecond) + ts.checkProviderJailed(provider1, true) } From 9798ffc0683fd56dcbf3453ea338082b1f114c2a Mon Sep 17 00:00:00 2001 From: Yaroms Date: Tue, 28 May 2024 02:31:01 +0300 Subject: [PATCH 12/16] we have a big test for all jailed events --- .../keeper/unresponsive_provider_test.go | 41 +++++++++++++++++-- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/x/pairing/keeper/unresponsive_provider_test.go b/x/pairing/keeper/unresponsive_provider_test.go index 038bd7d019..b52d182e7e 100644 --- a/x/pairing/keeper/unresponsive_provider_test.go +++ b/x/pairing/keeper/unresponsive_provider_test.go @@ -417,6 +417,12 @@ func TestJailProviderForUnresponsiveness(t *testing.T) { // jail first time jailProvider() + // try to unfreeze with increase of self delegation + _, err = ts.TxDualstakingDelegate(provider1, provider1, ts.spec.Index, common.NewCoin(ts.TokenDenom(), 1)) + require.Nil(t, err) + + _, err = ts.TxPairingUnfreezeProvider(provider1, ts.spec.Index) + require.Nil(t, err) // advance epoch and one hour to leave jail ts.AdvanceBlock(time.Hour) @@ -425,17 +431,46 @@ func TestJailProviderForUnresponsiveness(t *testing.T) { // jail second time jailProvider() + _, err = ts.TxPairingUnfreezeProvider(provider1, ts.spec.Index) + require.Nil(t, err) // advance epoch and one hour to leave jail ts.AdvanceBlock(time.Hour) - ts.AdvanceEpoch(time.Nanosecond) + ts.AdvanceEpoch(0) ts.checkProviderJailed(provider1, false) // jail third time jailProvider() + // try to unfreeze with increase of self delegation + _, err = ts.TxDualstakingDelegate(provider1, provider1, ts.spec.Index, common.NewCoin(ts.TokenDenom(), 1)) + require.Nil(t, err) - // advance epoch and one hour to leave jail + _, err = ts.TxPairingUnfreezeProvider(provider1, ts.spec.Index) + require.NotNil(t, err) + + // advance epoch and one hour to try leave jail ts.AdvanceBlock(time.Hour) - ts.AdvanceEpoch(time.Nanosecond) + ts.AdvanceEpoch(0) ts.checkProviderJailed(provider1, true) + + // advance epoch and 24 hour to try leave jail + ts.AdvanceBlock(24 * time.Hour) + ts.AdvanceEpoch(0) + ts.checkProviderJailed(provider1, false) + + // advance more 24H + ts.AdvanceBlock(24 * time.Hour) + _, err = ts.TxPairingUnfreezeProvider(provider1, ts.spec.Index) + require.Nil(t, err) + ts.AdvanceEpochs(largerConst + recommendedEpochNumToCollectPayment) + + // jail first time again + jailProvider() + _, err = ts.TxPairingUnfreezeProvider(provider1, ts.spec.Index) + require.Nil(t, err) + + // advance epoch and one hour to leave jail + ts.AdvanceBlock(time.Hour) + ts.AdvanceEpoch(0) + ts.checkProviderJailed(provider1, false) } From cb36d41fe64130f31f273d8f058d57d451570fec Mon Sep 17 00:00:00 2001 From: Yarom Swisa Date: Tue, 28 May 2024 12:10:30 +0300 Subject: [PATCH 13/16] change proto name --- .../lava/epochstorage/stake_entry.proto | 2 +- x/epochstorage/types/stake_entry.go | 2 +- x/epochstorage/types/stake_entry.pb.go | 98 +++++++++---------- x/pairing/keeper/msg_server_unfreeze.go | 4 +- x/pairing/keeper/unresponsive_provider.go | 4 +- .../keeper/unresponsive_provider_test.go | 2 +- 6 files changed, 56 insertions(+), 56 deletions(-) diff --git a/proto/lavanet/lava/epochstorage/stake_entry.proto b/proto/lavanet/lava/epochstorage/stake_entry.proto index ee81acd0a7..5a337698ce 100644 --- a/proto/lavanet/lava/epochstorage/stake_entry.proto +++ b/proto/lavanet/lava/epochstorage/stake_entry.proto @@ -25,7 +25,7 @@ message StakeEntry { string vault = 14; cosmos.staking.v1beta1.Description description = 15 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true]; uint64 jails = 16; - int64 jail_time = 17; + int64 jail_end_time = 17; } // BlockReport holds the most up-to-date info regarding blocks of the provider diff --git a/x/epochstorage/types/stake_entry.go b/x/epochstorage/types/stake_entry.go index bfa3e42fce..dad926835c 100644 --- a/x/epochstorage/types/stake_entry.go +++ b/x/epochstorage/types/stake_entry.go @@ -34,7 +34,7 @@ func (stakeEntry *StakeEntry) IsFrozen() bool { } func (stakeEntry *StakeEntry) IsJailed(time int64) bool { - return stakeEntry.JailTime > time + return stakeEntry.JailEndTime > time } func (stakeEntry *StakeEntry) IsAddressVaultAndNotProvider(address string) bool { diff --git a/x/epochstorage/types/stake_entry.pb.go b/x/epochstorage/types/stake_entry.pb.go index 15b649c1c7..1eb9867989 100644 --- a/x/epochstorage/types/stake_entry.pb.go +++ b/x/epochstorage/types/stake_entry.pb.go @@ -42,7 +42,7 @@ type StakeEntry struct { Vault string `protobuf:"bytes,14,opt,name=vault,proto3" json:"vault,omitempty"` Description types1.Description `protobuf:"bytes,15,opt,name=description,proto3" json:"description"` Jails uint64 `protobuf:"varint,16,opt,name=jails,proto3" json:"jails,omitempty"` - JailTime int64 `protobuf:"varint,17,opt,name=jail_time,json=jailTime,proto3" json:"jail_time,omitempty"` + JailEndTime int64 `protobuf:"varint,17,opt,name=jail_end_time,json=jailEndTime,proto3" json:"jail_end_time,omitempty"` } func (m *StakeEntry) Reset() { *m = StakeEntry{} } @@ -183,9 +183,9 @@ func (m *StakeEntry) GetJails() uint64 { return 0 } -func (m *StakeEntry) GetJailTime() int64 { +func (m *StakeEntry) GetJailEndTime() int64 { if m != nil { - return m.JailTime + return m.JailEndTime } return 0 } @@ -255,45 +255,45 @@ func init() { } var fileDescriptor_df6302d6b53c056e = []byte{ - // 603 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0x4f, 0x6f, 0xd3, 0x3e, - 0x18, 0x6e, 0xb6, 0x76, 0x6b, 0x9d, 0x6d, 0xbf, 0xd5, 0xdb, 0xc1, 0xdb, 0x4f, 0xca, 0xc2, 0x86, - 0x50, 0x04, 0x28, 0xd1, 0x86, 0xf8, 0x00, 0xb4, 0xac, 0x08, 0xc4, 0x01, 0x85, 0x9d, 0xb8, 0x44, - 0x4e, 0x62, 0xa5, 0xa6, 0x89, 0x1d, 0xc5, 0x5e, 0xc5, 0xbe, 0x05, 0x1f, 0x83, 0x23, 0x1f, 0x63, - 0xc7, 0x1d, 0x39, 0x21, 0xd4, 0x1e, 0xf8, 0x06, 0x9c, 0x91, 0xed, 0xa4, 0x7f, 0x0e, 0x43, 0x70, - 0x69, 0xfc, 0xbe, 0xef, 0xf3, 0x3e, 0x7e, 0x9f, 0xc7, 0x76, 0xc1, 0x93, 0x1c, 0x4f, 0x31, 0x23, - 0x32, 0x50, 0xdf, 0x80, 0x94, 0x3c, 0x19, 0x0b, 0xc9, 0x2b, 0x9c, 0x91, 0x40, 0x48, 0x3c, 0x21, - 0x11, 0x61, 0xb2, 0xba, 0xf1, 0xcb, 0x8a, 0x4b, 0x0e, 0x8f, 0x6a, 0xb0, 0xaf, 0xbe, 0xfe, 0x2a, - 0xf8, 0xd8, 0xbb, 0x9f, 0x87, 0xb0, 0xb4, 0xe4, 0x94, 0x49, 0x43, 0x72, 0x7c, 0x98, 0xf1, 0x8c, - 0xeb, 0x65, 0xa0, 0x56, 0x75, 0xd6, 0x49, 0xb8, 0x28, 0xb8, 0x08, 0x62, 0x2c, 0x48, 0x30, 0x3d, - 0x8f, 0x89, 0xc4, 0xe7, 0x41, 0xc2, 0x29, 0xab, 0xeb, 0x0f, 0xeb, 0xba, 0x1a, 0x8a, 0xb2, 0x6c, - 0x01, 0xa9, 0xe3, 0x1a, 0xd5, 0xc7, 0x05, 0x65, 0x3c, 0xd0, 0xbf, 0x26, 0x75, 0xfa, 0xab, 0x03, - 0xc0, 0x7b, 0xa5, 0xe4, 0x52, 0x09, 0x81, 0xcf, 0x41, 0x47, 0xeb, 0x42, 0x96, 0x6b, 0x79, 0xf6, - 0xc5, 0x91, 0x6f, 0x78, 0x7d, 0xb5, 0xaf, 0x5f, 0x93, 0xfa, 0x43, 0x4e, 0xd9, 0xa0, 0x7d, 0xfb, - 0xfd, 0xa4, 0x15, 0x1a, 0x34, 0x44, 0x60, 0x1b, 0xa7, 0x69, 0x45, 0x84, 0x40, 0x1b, 0xae, 0xe5, - 0xf5, 0xc2, 0x26, 0x84, 0x3e, 0x38, 0x30, 0x46, 0xe1, 0xb2, 0xcc, 0x29, 0x49, 0xa3, 0x38, 0xe7, - 0xc9, 0x04, 0x6d, 0xba, 0x96, 0xd7, 0x0e, 0xfb, 0xba, 0xf4, 0xc2, 0x54, 0x06, 0xaa, 0x00, 0x5f, - 0x81, 0x5e, 0x63, 0x88, 0x40, 0x6d, 0x77, 0xd3, 0xb3, 0x2f, 0xce, 0xfc, 0x7b, 0x7d, 0xf5, 0x2f, - 0x6b, 0x6c, 0x3d, 0xce, 0xb2, 0x17, 0xba, 0xc0, 0xce, 0x08, 0xcf, 0x79, 0x82, 0x25, 0xe5, 0x0c, - 0x75, 0x5c, 0xcb, 0xeb, 0x84, 0xab, 0x29, 0x78, 0x08, 0x3a, 0xc9, 0x18, 0x53, 0x86, 0xb6, 0xf4, - 0xc8, 0x26, 0x50, 0x52, 0x0a, 0xce, 0xe8, 0x84, 0x54, 0xa8, 0x6b, 0xa4, 0xd4, 0x21, 0x1c, 0x81, - 0xbd, 0x94, 0xe4, 0x24, 0xc3, 0x92, 0x44, 0x92, 0x4b, 0x9c, 0xa3, 0xde, 0xdf, 0x99, 0xb4, 0xdb, - 0xb4, 0x5d, 0xa9, 0xae, 0x35, 0x9e, 0x9c, 0x16, 0x54, 0x22, 0xf0, 0x8f, 0x3c, 0x6f, 0x55, 0x17, - 0x0c, 0xc0, 0xc1, 0x82, 0x27, 0xe1, 0x45, 0x41, 0x85, 0x50, 0x4a, 0x6d, 0x6d, 0x2d, 0x6c, 0x4a, - 0xc3, 0x45, 0x05, 0x9e, 0x00, 0x3b, 0xc7, 0x42, 0x46, 0xc9, 0x18, 0xb3, 0x8c, 0xa0, 0x1d, 0x0d, - 0x04, 0x2a, 0x35, 0xd4, 0x19, 0xf8, 0x1a, 0xec, 0xe8, 0xe3, 0x89, 0x2a, 0x52, 0xf2, 0x4a, 0xa2, - 0x5d, 0x3d, 0xd7, 0xa3, 0x3f, 0xf8, 0xaf, 0x0f, 0x2d, 0xd4, 0xe8, 0xd0, 0x8e, 0x97, 0x81, 0x32, - 0x77, 0x8a, 0xaf, 0x73, 0x89, 0xf6, 0x8c, 0xb9, 0x3a, 0x80, 0xef, 0x80, 0x9d, 0x12, 0x91, 0x54, - 0xb4, 0xd4, 0x87, 0xf2, 0x9f, 0xe6, 0x3f, 0x6b, 0x74, 0x37, 0x97, 0xb5, 0x91, 0xfe, 0x72, 0x09, - 0x1d, 0xf4, 0x94, 0x03, 0x5f, 0x7e, 0x7e, 0x7d, 0x6c, 0x85, 0xab, 0x14, 0x6a, 0x9f, 0x8f, 0x98, - 0xe6, 0x02, 0xed, 0x6b, 0x35, 0x26, 0x80, 0xff, 0x83, 0x9e, 0x5a, 0x44, 0x92, 0x16, 0x04, 0xf5, - 0x5d, 0xcb, 0xdb, 0x0c, 0xbb, 0x2a, 0x71, 0x45, 0x0b, 0xf2, 0xa6, 0xdd, 0xdd, 0xde, 0xef, 0x9e, - 0x8e, 0x80, 0x3d, 0x58, 0x9f, 0x57, 0x0b, 0xd3, 0x17, 0xbf, 0x1d, 0x9a, 0x00, 0x3e, 0x00, 0x3b, - 0x39, 0x96, 0x44, 0xc8, 0xfa, 0xda, 0x6e, 0xe8, 0xa2, 0x6d, 0x72, 0xba, 0x7d, 0x30, 0xba, 0x9d, - 0x39, 0xd6, 0xdd, 0xcc, 0xb1, 0x7e, 0xcc, 0x1c, 0xeb, 0xf3, 0xdc, 0x69, 0xdd, 0xcd, 0x9d, 0xd6, - 0xb7, 0xb9, 0xd3, 0xfa, 0xf0, 0x34, 0xa3, 0x72, 0x7c, 0x1d, 0xfb, 0x09, 0x2f, 0x82, 0xb5, 0xe7, - 0xff, 0x69, 0xfd, 0x0f, 0x40, 0xde, 0x94, 0x44, 0xc4, 0x5b, 0xfa, 0x3d, 0x3e, 0xfb, 0x1d, 0x00, - 0x00, 0xff, 0xff, 0xd6, 0x19, 0x94, 0xba, 0x72, 0x04, 0x00, 0x00, + // 607 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0xcf, 0x6e, 0xd3, 0x30, + 0x18, 0x6f, 0xb6, 0x76, 0x5b, 0x9d, 0x6d, 0x6c, 0xde, 0x0e, 0xde, 0x0e, 0x59, 0xe8, 0x10, 0x8a, + 0x00, 0x25, 0xda, 0x10, 0x0f, 0x40, 0x4b, 0x8b, 0x40, 0x1c, 0x50, 0xd8, 0x89, 0x4b, 0xe4, 0x24, + 0x56, 0x6a, 0x9a, 0xd8, 0x51, 0xec, 0x55, 0xec, 0x2d, 0x78, 0x0c, 0x8e, 0x3c, 0xc6, 0x8e, 0x3b, + 0x72, 0x42, 0xa8, 0x3d, 0xf0, 0x14, 0x48, 0xc8, 0x76, 0xd2, 0x3f, 0x87, 0x21, 0xb8, 0x34, 0xfe, + 0xbe, 0xef, 0xf7, 0xfd, 0xfc, 0xfd, 0x7e, 0x76, 0x0d, 0x9e, 0xe6, 0x78, 0x8a, 0x19, 0x91, 0x81, + 0xfa, 0x06, 0xa4, 0xe4, 0xc9, 0x58, 0x48, 0x5e, 0xe1, 0x8c, 0x04, 0x42, 0xe2, 0x09, 0x89, 0x08, + 0x93, 0xd5, 0x8d, 0x5f, 0x56, 0x5c, 0x72, 0x78, 0x52, 0x83, 0x7d, 0xf5, 0xf5, 0x57, 0xc1, 0xa7, + 0xde, 0xfd, 0x3c, 0x84, 0xa5, 0x25, 0xa7, 0x4c, 0x1a, 0x92, 0xd3, 0xe3, 0x8c, 0x67, 0x5c, 0x2f, + 0x03, 0xb5, 0xaa, 0xb3, 0x4e, 0xc2, 0x45, 0xc1, 0x45, 0x10, 0x63, 0x41, 0x82, 0xe9, 0x45, 0x4c, + 0x24, 0xbe, 0x08, 0x12, 0x4e, 0x59, 0x5d, 0x7f, 0x54, 0xd7, 0xd5, 0x50, 0x94, 0x65, 0x0b, 0x48, + 0x1d, 0xd7, 0xa8, 0x43, 0x5c, 0x50, 0xc6, 0x03, 0xfd, 0x6b, 0x52, 0xbd, 0xdf, 0x1d, 0x00, 0x3e, + 0x28, 0x25, 0x43, 0x25, 0x04, 0xbe, 0x00, 0x1d, 0xad, 0x0b, 0x59, 0xae, 0xe5, 0xd9, 0x97, 0x27, + 0xbe, 0xe1, 0xf5, 0xd5, 0xbe, 0x7e, 0x4d, 0xea, 0x0f, 0x38, 0x65, 0xfd, 0xf6, 0xed, 0x8f, 0xb3, + 0x56, 0x68, 0xd0, 0x10, 0x81, 0x6d, 0x9c, 0xa6, 0x15, 0x11, 0x02, 0x6d, 0xb8, 0x96, 0xd7, 0x0d, + 0x9b, 0x10, 0xfa, 0xe0, 0xc8, 0x18, 0x85, 0xcb, 0x32, 0xa7, 0x24, 0x8d, 0xe2, 0x9c, 0x27, 0x13, + 0xb4, 0xe9, 0x5a, 0x5e, 0x3b, 0x3c, 0xd4, 0xa5, 0x97, 0xa6, 0xd2, 0x57, 0x05, 0xf8, 0x1a, 0x74, + 0x1b, 0x43, 0x04, 0x6a, 0xbb, 0x9b, 0x9e, 0x7d, 0x79, 0xee, 0xdf, 0xeb, 0xab, 0x3f, 0xac, 0xb1, + 0xf5, 0x38, 0xcb, 0x5e, 0xe8, 0x02, 0x3b, 0x23, 0x3c, 0xe7, 0x09, 0x96, 0x94, 0x33, 0xd4, 0x71, + 0x2d, 0xaf, 0x13, 0xae, 0xa6, 0xe0, 0x31, 0xe8, 0x24, 0x63, 0x4c, 0x19, 0xda, 0xd2, 0x23, 0x9b, + 0x40, 0x49, 0x29, 0x38, 0xa3, 0x13, 0x52, 0xa1, 0x1d, 0x23, 0xa5, 0x0e, 0xe1, 0x08, 0xec, 0xa7, + 0x24, 0x27, 0x19, 0x96, 0x24, 0x92, 0x5c, 0xe2, 0x1c, 0x75, 0xff, 0xcd, 0xa4, 0xbd, 0xa6, 0xed, + 0x4a, 0x75, 0xad, 0xf1, 0xe4, 0xb4, 0xa0, 0x12, 0x81, 0xff, 0xe4, 0x79, 0xa7, 0xba, 0x60, 0x00, + 0x8e, 0x16, 0x3c, 0x09, 0x2f, 0x0a, 0x2a, 0x84, 0x52, 0x6a, 0x6b, 0x6b, 0x61, 0x53, 0x1a, 0x2c, + 0x2a, 0xf0, 0x0c, 0xd8, 0x39, 0x16, 0x32, 0x4a, 0xc6, 0x98, 0x65, 0x04, 0xed, 0x6a, 0x20, 0x50, + 0xa9, 0x81, 0xce, 0xc0, 0x37, 0x60, 0x57, 0x1f, 0x4f, 0x54, 0x91, 0x92, 0x57, 0x12, 0xed, 0xe9, + 0xb9, 0x1e, 0xff, 0xc5, 0x7f, 0x7d, 0x68, 0xa1, 0x46, 0x87, 0x76, 0xbc, 0x0c, 0x94, 0xb9, 0x53, + 0x7c, 0x9d, 0x4b, 0xb4, 0x6f, 0xcc, 0xd5, 0x01, 0x7c, 0x0f, 0xec, 0x94, 0x88, 0xa4, 0xa2, 0xa5, + 0x3e, 0x94, 0x07, 0x9a, 0xff, 0xbc, 0xd1, 0xdd, 0x5c, 0xd6, 0x46, 0xfa, 0xab, 0x25, 0xb4, 0xdf, + 0x55, 0x0e, 0x7c, 0xfd, 0xf5, 0xed, 0x89, 0x15, 0xae, 0x52, 0xa8, 0x7d, 0x3e, 0x61, 0x9a, 0x0b, + 0x74, 0xa0, 0xd5, 0x98, 0x00, 0xf6, 0xc0, 0x9e, 0x5a, 0x44, 0x84, 0xa5, 0x91, 0xa4, 0x05, 0x41, + 0x87, 0xae, 0xe5, 0x6d, 0x86, 0xb6, 0x4a, 0x0e, 0x59, 0x7a, 0x45, 0x0b, 0xf2, 0xb6, 0xbd, 0xb3, + 0x7d, 0xb0, 0xd3, 0x1b, 0x01, 0xbb, 0xbf, 0x3e, 0xb6, 0xd6, 0xa7, 0xef, 0x7f, 0x3b, 0x34, 0x01, + 0x7c, 0x08, 0x76, 0x73, 0x2c, 0x89, 0x90, 0xf5, 0xed, 0xdd, 0xd0, 0x45, 0xdb, 0xe4, 0x74, 0x7b, + 0x7f, 0x74, 0x3b, 0x73, 0xac, 0xbb, 0x99, 0x63, 0xfd, 0x9c, 0x39, 0xd6, 0x97, 0xb9, 0xd3, 0xba, + 0x9b, 0x3b, 0xad, 0xef, 0x73, 0xa7, 0xf5, 0xf1, 0x59, 0x46, 0xe5, 0xf8, 0x3a, 0xf6, 0x13, 0x5e, + 0x04, 0x6b, 0xaf, 0xc0, 0xe7, 0xf5, 0x77, 0x40, 0xde, 0x94, 0x44, 0xc4, 0x5b, 0xfa, 0x6f, 0xf9, + 0xfc, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x42, 0x11, 0xd6, 0x4d, 0x79, 0x04, 0x00, 0x00, } func (m *StakeEntry) Marshal() (dAtA []byte, err error) { @@ -316,8 +316,8 @@ func (m *StakeEntry) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.JailTime != 0 { - i = encodeVarintStakeEntry(dAtA, i, uint64(m.JailTime)) + if m.JailEndTime != 0 { + i = encodeVarintStakeEntry(dAtA, i, uint64(m.JailEndTime)) i-- dAtA[i] = 0x1 i-- @@ -546,8 +546,8 @@ func (m *StakeEntry) Size() (n int) { if m.Jails != 0 { n += 2 + sovStakeEntry(uint64(m.Jails)) } - if m.JailTime != 0 { - n += 2 + sovStakeEntry(uint64(m.JailTime)) + if m.JailEndTime != 0 { + n += 2 + sovStakeEntry(uint64(m.JailEndTime)) } return n } @@ -1029,9 +1029,9 @@ func (m *StakeEntry) Unmarshal(dAtA []byte) error { } case 17: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field JailTime", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field JailEndTime", wireType) } - m.JailTime = 0 + m.JailEndTime = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowStakeEntry @@ -1041,7 +1041,7 @@ func (m *StakeEntry) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.JailTime |= int64(b&0x7F) << shift + m.JailEndTime |= int64(b&0x7F) << shift if b < 0x80 { break } diff --git a/x/pairing/keeper/msg_server_unfreeze.go b/x/pairing/keeper/msg_server_unfreeze.go index 32d9c1b169..3cd2da1061 100644 --- a/x/pairing/keeper/msg_server_unfreeze.go +++ b/x/pairing/keeper/msg_server_unfreeze.go @@ -41,13 +41,13 @@ func (k msgServer) UnfreezeProvider(goCtx context.Context, msg *types.MsgUnfreez []utils.Attribute{ {Key: "chainID", Value: chainId}, {Key: "providerAddress", Value: msg.GetCreator()}, - {Key: "jailEnd", Value: stakeEntry.JailTime}, + {Key: "jailEnd", Value: stakeEntry.JailEndTime}, }...) } // unfreeze the provider by making the StakeAppliedBlock the current block. This will let the provider be added to the pairing list in the next epoch, when current entries becomes the front of epochStorage stakeEntry.UnFreeze(unfreezeBlock) - stakeEntry.JailTime = 0 + stakeEntry.JailEndTime = 0 stakeEntry.Jails = 0 k.epochStorageKeeper.ModifyStakeEntryCurrent(ctx, chainId, stakeEntry) unfrozen_chains = append(unfrozen_chains, chainId) diff --git a/x/pairing/keeper/unresponsive_provider.go b/x/pairing/keeper/unresponsive_provider.go index 49ed3c5ede..691a662c5d 100644 --- a/x/pairing/keeper/unresponsive_provider.go +++ b/x/pairing/keeper/unresponsive_provider.go @@ -251,9 +251,9 @@ func (k Keeper) punishUnresponsiveProvider(ctx sdk.Context, epochs []uint64, sta if stakeEntry.Jails > SOFT_JAILS { stakeEntry.Freeze() - stakeEntry.JailTime = ctx.BlockTime().UTC().Unix() + int64(HARD_JAIL_TIME) + stakeEntry.JailEndTime = ctx.BlockTime().UTC().Unix() + int64(HARD_JAIL_TIME) } else { - stakeEntry.JailTime = ctx.BlockTime().UTC().Unix() + int64(SOFT_JAIL_TIME) + stakeEntry.JailEndTime = ctx.BlockTime().UTC().Unix() + int64(SOFT_JAIL_TIME) epochduration := k.downtimeKeeper.GetParams(ctx).EpochDuration / time.Second epochblocks := k.epochStorageKeeper.EpochBlocksRaw(ctx) stakeEntry.StakeAppliedBlock = uint64(ctx.BlockHeight()) + uint64(SOFT_JAIL_TIME/epochduration)*epochblocks diff --git a/x/pairing/keeper/unresponsive_provider_test.go b/x/pairing/keeper/unresponsive_provider_test.go index b52d182e7e..40736749cc 100644 --- a/x/pairing/keeper/unresponsive_provider_test.go +++ b/x/pairing/keeper/unresponsive_provider_test.go @@ -22,7 +22,7 @@ func (ts *tester) checkProviderJailed(provider string, shouldFreeze bool) { if stakeEntry.Jails > keeper.SOFT_JAILS { jailDelta = keeper.HARD_JAIL_TIME } - require.InDelta(ts.T, stakeEntry.JailTime, ts.BlockTime().UTC().Unix(), float64(jailDelta)) + require.InDelta(ts.T, stakeEntry.JailEndTime, ts.BlockTime().UTC().Unix(), float64(jailDelta)) } } From b356a036060427db141022178cdcbd8f5285f4f7 Mon Sep 17 00:00:00 2001 From: Yarom Swisa Date: Tue, 28 May 2024 12:13:54 +0300 Subject: [PATCH 14/16] fix unitest --- x/pairing/keeper/unresponsive_provider.go | 2 +- x/pairing/keeper/unresponsive_provider_test.go | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/x/pairing/keeper/unresponsive_provider.go b/x/pairing/keeper/unresponsive_provider.go index 691a662c5d..9547ed29da 100644 --- a/x/pairing/keeper/unresponsive_provider.go +++ b/x/pairing/keeper/unresponsive_provider.go @@ -148,7 +148,7 @@ func (k Keeper) PunishUnresponsiveProviders(ctx sdk.Context, epochsNumToCheckCUF if len(epochs) != 0 && existingProviders[chainID] > minProviders { entry, ok := stakeEntries[key] if !ok { - utils.LavaFormatWarning("Freeze_cant_get_stake_entry", types.FreezeStakeEntryNotFoundError, []utils.Attribute{{Key: "chainID", Value: chainID}, {Key: "providerAddress", Value: provider}}...) + utils.LavaFormatError("Jail_cant_get_stake_entry", types.FreezeStakeEntryNotFoundError, []utils.Attribute{{Key: "chainID", Value: chainID}, {Key: "providerAddress", Value: provider}}...) continue } err = k.punishUnresponsiveProvider(ctx, epochs, entry, complaintCU, servicedCU, complainedProviders[key]) diff --git a/x/pairing/keeper/unresponsive_provider_test.go b/x/pairing/keeper/unresponsive_provider_test.go index 40736749cc..1c14046c0c 100644 --- a/x/pairing/keeper/unresponsive_provider_test.go +++ b/x/pairing/keeper/unresponsive_provider_test.go @@ -424,6 +424,8 @@ func TestJailProviderForUnresponsiveness(t *testing.T) { _, err = ts.TxPairingUnfreezeProvider(provider1, ts.spec.Index) require.Nil(t, err) + ts.checkProviderJailed(provider1, true) + // advance epoch and one hour to leave jail ts.AdvanceBlock(time.Hour) ts.AdvanceEpoch(0) @@ -434,6 +436,8 @@ func TestJailProviderForUnresponsiveness(t *testing.T) { _, err = ts.TxPairingUnfreezeProvider(provider1, ts.spec.Index) require.Nil(t, err) + ts.checkProviderJailed(provider1, true) + // advance epoch and one hour to leave jail ts.AdvanceBlock(time.Hour) ts.AdvanceEpoch(0) @@ -458,8 +462,6 @@ func TestJailProviderForUnresponsiveness(t *testing.T) { ts.AdvanceEpoch(0) ts.checkProviderJailed(provider1, false) - // advance more 24H - ts.AdvanceBlock(24 * time.Hour) _, err = ts.TxPairingUnfreezeProvider(provider1, ts.spec.Index) require.Nil(t, err) ts.AdvanceEpochs(largerConst + recommendedEpochNumToCollectPayment) @@ -469,6 +471,8 @@ func TestJailProviderForUnresponsiveness(t *testing.T) { _, err = ts.TxPairingUnfreezeProvider(provider1, ts.spec.Index) require.Nil(t, err) + ts.checkProviderJailed(provider1, true) + // advance epoch and one hour to leave jail ts.AdvanceBlock(time.Hour) ts.AdvanceEpoch(0) From 2c93939072c2bf1389ddceceb12a8df26edecd4e Mon Sep 17 00:00:00 2001 From: Yarom Swisa Date: Tue, 28 May 2024 12:15:45 +0300 Subject: [PATCH 15/16] fix readme --- x/pairing/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x/pairing/README.md b/x/pairing/README.md index ee02c8704c..d884d67091 100644 --- a/x/pairing/README.md +++ b/x/pairing/README.md @@ -218,8 +218,8 @@ Every epoch start, the amount of complainers CU is compared with the amount of s #### Jail If a provider is down and users report it, the provider will be jailed. -The first three instances of jailing are temporary, lasting 1 hour each, and will be automatically removed. -After three consecutive jailings, the provider will be jailed for 24 hours and set to a 'frozen' state. To resume activity, the provider must send an 'unfreeze' transaction after the jail time has ended. +The first 2 instances of jailing are temporary, lasting 1 hour each, and will be automatically removed. +After 2 consecutive jailings, the provider will be jailed for 24 hours and set to a 'frozen' state. To resume activity, the provider must send an 'unfreeze' transaction after the jail time has ended. #### Static Providers From 04b449b0ec5cbea51089fec47673d129b03fc460 Mon Sep 17 00:00:00 2001 From: Yarom Swisa Date: Thu, 30 May 2024 14:22:18 +0300 Subject: [PATCH 16/16] pr changes --- x/pairing/keeper/unresponsive_provider.go | 34 ++++++++++++------- .../keeper/unresponsive_provider_test.go | 7 ++-- x/pairing/types/types.go | 13 +++---- 3 files changed, 33 insertions(+), 21 deletions(-) diff --git a/x/pairing/keeper/unresponsive_provider.go b/x/pairing/keeper/unresponsive_provider.go index 9547ed29da..1025a4529a 100644 --- a/x/pairing/keeper/unresponsive_provider.go +++ b/x/pairing/keeper/unresponsive_provider.go @@ -151,7 +151,7 @@ func (k Keeper) PunishUnresponsiveProviders(ctx sdk.Context, epochsNumToCheckCUF utils.LavaFormatError("Jail_cant_get_stake_entry", types.FreezeStakeEntryNotFoundError, []utils.Attribute{{Key: "chainID", Value: chainID}, {Key: "providerAddress", Value: provider}}...) continue } - err = k.punishUnresponsiveProvider(ctx, epochs, entry, complaintCU, servicedCU, complainedProviders[key]) + err = k.punishUnresponsiveProvider(ctx, epochs, entry, complaintCU, servicedCU) existingProviders[chainID]-- if err != nil { utils.LavaFormatError("unstake unresponsive providers failed to punish provider", err, @@ -242,41 +242,49 @@ func (k Keeper) getCurrentProviderStakeStorageList(ctx sdk.Context) []epochstora } // Function that punishes providers. Current punishment is freeze -func (k Keeper) punishUnresponsiveProvider(ctx sdk.Context, epochs []uint64, stakeEntry epochstoragetypes.StakeEntry, complaintCU uint64, servicedCU uint64, providerEpochCuMap map[uint64]types.ProviderEpochComplainerCu) error { +func (k Keeper) punishUnresponsiveProvider(ctx sdk.Context, epochs []uint64, stakeEntry epochstoragetypes.StakeEntry, complaintCU uint64, servicedCU uint64) error { // if last jail was more than 24H ago, reset the jails counter if !stakeEntry.IsJailed(ctx.BlockTime().UTC().Unix() - int64(HARD_JAIL_TIME)) { stakeEntry.Jails = 0 } stakeEntry.Jails++ + details := map[string]string{ + "provider_address": stakeEntry.Address, + "chain_id": stakeEntry.Chain, + "complaint_cu": strconv.FormatUint(complaintCU, 10), + "serviced_cu": strconv.FormatUint(servicedCU, 10), + } + if stakeEntry.Jails > SOFT_JAILS { stakeEntry.Freeze() stakeEntry.JailEndTime = ctx.BlockTime().UTC().Unix() + int64(HARD_JAIL_TIME) + + details["duration"] = HARD_JAIL_TIME.String() + details["end"] = strconv.FormatInt(stakeEntry.JailEndTime, 10) + utils.LogLavaEvent(ctx, k.Logger(ctx), types.ProviderFreezeJailedEventName, details, + "Unresponsive provider was jailed due to unresponsiveness") } else { stakeEntry.JailEndTime = ctx.BlockTime().UTC().Unix() + int64(SOFT_JAIL_TIME) epochduration := k.downtimeKeeper.GetParams(ctx).EpochDuration / time.Second epochblocks := k.epochStorageKeeper.EpochBlocksRaw(ctx) stakeEntry.StakeAppliedBlock = uint64(ctx.BlockHeight()) + uint64(SOFT_JAIL_TIME/epochduration)*epochblocks + + details["duration"] = SOFT_JAIL_TIME.String() + details["end"] = strconv.FormatInt(stakeEntry.JailEndTime, 10) + utils.LogLavaEvent(ctx, k.Logger(ctx), types.ProviderTemporaryJailedEventName, details, + "Unresponsive provider was jailed due to unresponsiveness") } k.epochStorageKeeper.ModifyStakeEntryCurrent(ctx, stakeEntry.Chain, stakeEntry) - utils.LogLavaEvent(ctx, k.Logger(ctx), types.ProviderJailedEventName, - map[string]string{ - "provider_address": stakeEntry.Address, - "chain_id": stakeEntry.Chain, - "complaint_cu": strconv.FormatUint(complaintCU, 10), - "serviced_cu": strconv.FormatUint(servicedCU, 10), - }, - "Unresponsive provider was freezed due to unresponsiveness") - // reset the provider's complainer CU (so he won't get punished for the same complaints twice) - k.resetComplainersCU(ctx, epochs, stakeEntry.Address, stakeEntry.Chain, providerEpochCuMap) + k.resetComplainersCU(ctx, epochs, stakeEntry.Address, stakeEntry.Chain) return nil } // resetComplainersCU resets the complainers CU for a specific provider and chain -func (k Keeper) resetComplainersCU(ctx sdk.Context, epochs []uint64, provider string, chainID string, providerEpochCuMap map[uint64]types.ProviderEpochComplainerCu) { +func (k Keeper) resetComplainersCU(ctx sdk.Context, epochs []uint64, provider string, chainID string) { for _, epoch := range epochs { k.RemoveProviderEpochComplainerCu(ctx, epoch, provider, chainID) } diff --git a/x/pairing/keeper/unresponsive_provider_test.go b/x/pairing/keeper/unresponsive_provider_test.go index 1c14046c0c..b57189b739 100644 --- a/x/pairing/keeper/unresponsive_provider_test.go +++ b/x/pairing/keeper/unresponsive_provider_test.go @@ -408,11 +408,14 @@ func TestJailProviderForUnresponsiveness(t *testing.T) { } ts.relayPaymentWithoutPay(relayPaymentMessage, true) - ts.AdvanceEpochs(largerConst, 0) - + ts.AdvanceEpochs(recommendedEpochNumToCollectPayment+1, 0) ts.checkProviderJailed(provider1, true) ts.checkComplainerReset(provider1, relayEpoch) ts.checkProviderStaked(provider0) + + res, err := ts.QueryPairingVerifyPairing(ts.spec.Name, clients[0].Addr.String(), provider1, ts.BlockHeight()) + require.NoError(t, err) + require.False(t, res.Valid) } // jail first time diff --git a/x/pairing/types/types.go b/x/pairing/types/types.go index 02daaccdf2..38cff91711 100644 --- a/x/pairing/types/types.go +++ b/x/pairing/types/types.go @@ -5,12 +5,13 @@ const ( ProviderStakeUpdateEventName = "stake_update_provider" ProviderUnstakeEventName = "provider_unstake_commit" - RelayPaymentEventName = "relay_payment" - ProviderJailedEventName = "provider_jailed" - ProviderReportedEventName = "provider_reported" - LatestBlocksReportEventName = "provider_latest_block_report" - RejectedCuEventName = "rejected_cu" - UnstakeProposalEventName = "unstake_gov_proposal" + RelayPaymentEventName = "relay_payment" + ProviderTemporaryJailedEventName = "provider_temporary_jailed" + ProviderFreezeJailedEventName = "provider_jailed" + ProviderReportedEventName = "provider_reported" + LatestBlocksReportEventName = "provider_latest_block_report" + RejectedCuEventName = "rejected_cu" + UnstakeProposalEventName = "unstake_gov_proposal" ) // unstake description strings