From 332e015520fa37ad53c47c709d9f933055d537dc Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Fri, 5 Jul 2024 15:36:44 +0200 Subject: [PATCH 01/13] feat: Unbonding period endblocker --- api/poktroll/shared/supplier.pulsar.go | 97 +++++++++++++++---- proto/poktroll/shared/supplier.proto | 1 + testutil/integration/app.go | 1 + x/shared/types/supplier.pb.go | 80 ++++++++++----- x/supplier/keeper/keeper.go | 7 +- .../keeper/msg_server_stake_supplier.go | 3 + .../keeper/msg_server_unstake_supplier.go | 42 +++++--- x/supplier/keeper/unbond_suppliers.go | 59 +++++++++++ x/supplier/module/abci.go | 16 +++ x/supplier/module/module.go | 23 +++-- x/supplier/module/simulation.go | 8 +- x/supplier/types/errors.go | 1 + x/supplier/types/expected_keepers.go | 8 ++ 13 files changed, 275 insertions(+), 71 deletions(-) create mode 100644 x/supplier/keeper/unbond_suppliers.go create mode 100644 x/supplier/module/abci.go diff --git a/api/poktroll/shared/supplier.pulsar.go b/api/poktroll/shared/supplier.pulsar.go index ac65f36e6..4006947aa 100644 --- a/api/poktroll/shared/supplier.pulsar.go +++ b/api/poktroll/shared/supplier.pulsar.go @@ -66,10 +66,11 @@ func (x *_Supplier_3_list) IsValid() bool { } var ( - md_Supplier protoreflect.MessageDescriptor - fd_Supplier_address protoreflect.FieldDescriptor - fd_Supplier_stake protoreflect.FieldDescriptor - fd_Supplier_services protoreflect.FieldDescriptor + md_Supplier protoreflect.MessageDescriptor + fd_Supplier_address protoreflect.FieldDescriptor + fd_Supplier_stake protoreflect.FieldDescriptor + fd_Supplier_services protoreflect.FieldDescriptor + fd_Supplier_unbondingHeight protoreflect.FieldDescriptor ) func init() { @@ -78,6 +79,7 @@ func init() { fd_Supplier_address = md_Supplier.Fields().ByName("address") fd_Supplier_stake = md_Supplier.Fields().ByName("stake") fd_Supplier_services = md_Supplier.Fields().ByName("services") + fd_Supplier_unbondingHeight = md_Supplier.Fields().ByName("unbondingHeight") } var _ protoreflect.Message = (*fastReflection_Supplier)(nil) @@ -163,6 +165,12 @@ func (x *fastReflection_Supplier) Range(f func(protoreflect.FieldDescriptor, pro return } } + if x.UnbondingHeight != int64(0) { + value := protoreflect.ValueOfInt64(x.UnbondingHeight) + if !f(fd_Supplier_unbondingHeight, value) { + return + } + } } // Has reports whether a field is populated. @@ -184,6 +192,8 @@ func (x *fastReflection_Supplier) Has(fd protoreflect.FieldDescriptor) bool { return x.Stake != nil case "poktroll.shared.Supplier.services": return len(x.Services) != 0 + case "poktroll.shared.Supplier.unbondingHeight": + return x.UnbondingHeight != int64(0) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.shared.Supplier")) @@ -206,6 +216,8 @@ func (x *fastReflection_Supplier) Clear(fd protoreflect.FieldDescriptor) { x.Stake = nil case "poktroll.shared.Supplier.services": x.Services = nil + case "poktroll.shared.Supplier.unbondingHeight": + x.UnbondingHeight = int64(0) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.shared.Supplier")) @@ -234,6 +246,9 @@ func (x *fastReflection_Supplier) Get(descriptor protoreflect.FieldDescriptor) p } listValue := &_Supplier_3_list{list: &x.Services} return protoreflect.ValueOfList(listValue) + case "poktroll.shared.Supplier.unbondingHeight": + value := x.UnbondingHeight + return protoreflect.ValueOfInt64(value) default: if descriptor.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.shared.Supplier")) @@ -262,6 +277,8 @@ func (x *fastReflection_Supplier) Set(fd protoreflect.FieldDescriptor, value pro lv := value.List() clv := lv.(*_Supplier_3_list) x.Services = *clv.list + case "poktroll.shared.Supplier.unbondingHeight": + x.UnbondingHeight = value.Int() default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.shared.Supplier")) @@ -295,6 +312,8 @@ func (x *fastReflection_Supplier) Mutable(fd protoreflect.FieldDescriptor) proto return protoreflect.ValueOfList(value) case "poktroll.shared.Supplier.address": panic(fmt.Errorf("field address of message poktroll.shared.Supplier is not mutable")) + case "poktroll.shared.Supplier.unbondingHeight": + panic(fmt.Errorf("field unbondingHeight of message poktroll.shared.Supplier is not mutable")) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.shared.Supplier")) @@ -316,6 +335,8 @@ func (x *fastReflection_Supplier) NewField(fd protoreflect.FieldDescriptor) prot case "poktroll.shared.Supplier.services": list := []*SupplierServiceConfig{} return protoreflect.ValueOfList(&_Supplier_3_list{list: &list}) + case "poktroll.shared.Supplier.unbondingHeight": + return protoreflect.ValueOfInt64(int64(0)) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.shared.Supplier")) @@ -399,6 +420,9 @@ func (x *fastReflection_Supplier) ProtoMethods() *protoiface.Methods { n += 1 + l + runtime.Sov(uint64(l)) } } + if x.UnbondingHeight != 0 { + n += 1 + runtime.Sov(uint64(x.UnbondingHeight)) + } if x.unknownFields != nil { n += len(x.unknownFields) } @@ -428,6 +452,11 @@ func (x *fastReflection_Supplier) ProtoMethods() *protoiface.Methods { i -= len(x.unknownFields) copy(dAtA[i:], x.unknownFields) } + if x.UnbondingHeight != 0 { + i = runtime.EncodeVarint(dAtA, i, uint64(x.UnbondingHeight)) + i-- + dAtA[i] = 0x20 + } if len(x.Services) > 0 { for iNdEx := len(x.Services) - 1; iNdEx >= 0; iNdEx-- { encoded, err := options.Marshal(x.Services[iNdEx]) @@ -616,6 +645,25 @@ func (x *fastReflection_Supplier) ProtoMethods() *protoiface.Methods { return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err } iNdEx = postIndex + case 4: + if wireType != 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field UnbondingHeight", wireType) + } + x.UnbondingHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + x.UnbondingHeight |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := runtime.Skip(dAtA[iNdEx:]) @@ -670,9 +718,10 @@ type Supplier struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` // The Bech32 address of the supplier using cosmos' ScalarDescriptor to ensure deterministic encoding - Stake *v1beta1.Coin `protobuf:"bytes,2,opt,name=stake,proto3" json:"stake,omitempty"` // The total amount of uPOKT the supplier has staked - Services []*SupplierServiceConfig `protobuf:"bytes,3,rep,name=services,proto3" json:"services,omitempty"` // The service configs this supplier can support + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` // The Bech32 address of the supplier using cosmos' ScalarDescriptor to ensure deterministic encoding + Stake *v1beta1.Coin `protobuf:"bytes,2,opt,name=stake,proto3" json:"stake,omitempty"` // The total amount of uPOKT the supplier has staked + Services []*SupplierServiceConfig `protobuf:"bytes,3,rep,name=services,proto3" json:"services,omitempty"` // The service configs this supplier can support + UnbondingHeight int64 `protobuf:"varint,4,opt,name=unbondingHeight,proto3" json:"unbondingHeight,omitempty"` // The height at which the supplier will be unbonded } func (x *Supplier) Reset() { @@ -716,6 +765,13 @@ func (x *Supplier) GetServices() []*SupplierServiceConfig { return nil } +func (x *Supplier) GetUnbondingHeight() int64 { + if x != nil { + return x.UnbondingHeight + } + return 0 +} + var File_poktroll_shared_supplier_proto protoreflect.FileDescriptor var file_poktroll_shared_supplier_proto_rawDesc = []byte{ @@ -727,7 +783,7 @@ var file_poktroll_shared_supplier_proto_rawDesc = []byte{ 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x62, 0x61, 0x73, 0x65, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x63, 0x6f, 0x69, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1d, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x2f, 0x73, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb3, 0x01, 0x0a, 0x08, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xdd, 0x01, 0x0a, 0x08, 0x53, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x12, 0x32, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, 0xd2, 0xb4, 0x2d, 0x14, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, 0x74, 0x72, @@ -739,17 +795,20 @@ var file_poktroll_shared_supplier_proto_rawDesc = []byte{ 0x26, 0x2e, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x2e, 0x53, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x73, 0x42, 0xa3, 0x01, 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, - 0x6c, 0x6c, 0x2e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x42, 0x0d, 0x53, 0x75, 0x70, 0x70, 0x6c, - 0x69, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x20, 0x63, 0x6f, 0x73, 0x6d, - 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x6f, 0x6b, - 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0xa2, 0x02, 0x03, 0x50, - 0x53, 0x58, 0xaa, 0x02, 0x0f, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x53, 0x68, - 0x61, 0x72, 0x65, 0x64, 0xca, 0x02, 0x0f, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, - 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0xe2, 0x02, 0x1b, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, - 0x6c, 0x5c, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x10, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x3a, - 0x3a, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x73, 0x12, 0x28, 0x0a, 0x0f, 0x75, 0x6e, 0x62, 0x6f, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x65, + 0x69, 0x67, 0x68, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x75, 0x6e, 0x62, 0x6f, + 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x42, 0xa3, 0x01, 0x0a, 0x13, + 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x73, 0x68, 0x61, + 0x72, 0x65, 0x64, 0x42, 0x0d, 0x53, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x50, 0x72, 0x6f, + 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x20, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, + 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2f, + 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0xa2, 0x02, 0x03, 0x50, 0x53, 0x58, 0xaa, 0x02, 0x0f, 0x50, + 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0xca, 0x02, + 0x0f, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, + 0xe2, 0x02, 0x1b, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x53, 0x68, 0x61, 0x72, + 0x65, 0x64, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, + 0x10, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x3a, 0x3a, 0x53, 0x68, 0x61, 0x72, 0x65, + 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/proto/poktroll/shared/supplier.proto b/proto/poktroll/shared/supplier.proto index 5553f5673..df04d7e9c 100644 --- a/proto/poktroll/shared/supplier.proto +++ b/proto/poktroll/shared/supplier.proto @@ -13,5 +13,6 @@ message Supplier { string address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; // The Bech32 address of the supplier using cosmos' ScalarDescriptor to ensure deterministic encoding cosmos.base.v1beta1.Coin stake = 2; // The total amount of uPOKT the supplier has staked repeated SupplierServiceConfig services = 3; // The service configs this supplier can support + int64 unbondingHeight = 4; // The height at which the supplier will be unbonded } diff --git a/testutil/integration/app.go b/testutil/integration/app.go index 98197836a..2a4eeed0f 100644 --- a/testutil/integration/app.go +++ b/testutil/integration/app.go @@ -338,6 +338,7 @@ func NewCompleteIntegrationApp(t *testing.T) *App { logger, authority.String(), bankKeeper, + sharedKeeper, ) supplierModule := supplier.NewAppModule( cdc, diff --git a/x/shared/types/supplier.pb.go b/x/shared/types/supplier.pb.go index 716a0c1ac..f34a35fdb 100644 --- a/x/shared/types/supplier.pb.go +++ b/x/shared/types/supplier.pb.go @@ -26,9 +26,10 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // Supplier is the type defining the actor in Pocket Network that provides RPC services. type Supplier struct { - Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` - Stake *types.Coin `protobuf:"bytes,2,opt,name=stake,proto3" json:"stake,omitempty"` - Services []*SupplierServiceConfig `protobuf:"bytes,3,rep,name=services,proto3" json:"services,omitempty"` + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + Stake *types.Coin `protobuf:"bytes,2,opt,name=stake,proto3" json:"stake,omitempty"` + Services []*SupplierServiceConfig `protobuf:"bytes,3,rep,name=services,proto3" json:"services,omitempty"` + UnbondingHeight int64 `protobuf:"varint,4,opt,name=unbondingHeight,proto3" json:"unbondingHeight,omitempty"` } func (m *Supplier) Reset() { *m = Supplier{} } @@ -85,6 +86,13 @@ func (m *Supplier) GetServices() []*SupplierServiceConfig { return nil } +func (m *Supplier) GetUnbondingHeight() int64 { + if m != nil { + return m.UnbondingHeight + } + return 0 +} + func init() { proto.RegisterType((*Supplier)(nil), "poktroll.shared.Supplier") } @@ -92,26 +100,27 @@ func init() { func init() { proto.RegisterFile("poktroll/shared/supplier.proto", fileDescriptor_4a189b52ba503cf2) } var fileDescriptor_4a189b52ba503cf2 = []byte{ - // 289 bytes of a gzipped FileDescriptorProto + // 312 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x90, 0xbd, 0x4e, 0xf3, 0x30, - 0x18, 0x85, 0xe3, 0xaf, 0xfa, 0xa0, 0xa4, 0x03, 0x52, 0xc4, 0x90, 0x56, 0xc2, 0x8a, 0x18, 0x50, - 0x96, 0xda, 0x6a, 0xb8, 0x02, 0xd2, 0x89, 0x35, 0xd9, 0x58, 0x50, 0x7e, 0x4c, 0x6a, 0x25, 0xcd, - 0x6b, 0xd9, 0x6e, 0x81, 0xbb, 0xe0, 0x5e, 0xe0, 0x22, 0x18, 0x2b, 0x26, 0x46, 0x94, 0xdc, 0x08, - 0x6a, 0xed, 0x74, 0x80, 0xf1, 0xd5, 0xf3, 0x24, 0xe7, 0xf8, 0xb8, 0x58, 0x40, 0xad, 0x25, 0x34, - 0x0d, 0x55, 0xab, 0x4c, 0xb2, 0x92, 0xaa, 0x8d, 0x10, 0x0d, 0x67, 0x92, 0x08, 0x09, 0x1a, 0xbc, - 0xf3, 0x81, 0x13, 0xc3, 0x67, 0xd3, 0x02, 0xd4, 0x1a, 0xd4, 0xc3, 0x01, 0x53, 0x73, 0x18, 0x77, - 0x86, 0xcd, 0x45, 0xf3, 0x4c, 0x31, 0xba, 0x5d, 0xe4, 0x4c, 0x67, 0x0b, 0x5a, 0x00, 0x6f, 0x2d, - 0xbf, 0xfc, 0x93, 0xc5, 0xe4, 0x96, 0x17, 0xcc, 0xe0, 0xab, 0x37, 0xe4, 0x8e, 0x53, 0x9b, 0xee, - 0x45, 0xee, 0x69, 0x56, 0x96, 0x92, 0x29, 0xe5, 0xa3, 0x00, 0x85, 0x67, 0xb1, 0xff, 0xf9, 0x3e, - 0xbf, 0xb0, 0x71, 0xb7, 0x86, 0xa4, 0x5a, 0xf2, 0xb6, 0x4a, 0x06, 0xd1, 0xa3, 0xee, 0x7f, 0xa5, - 0xb3, 0x9a, 0xf9, 0xff, 0x02, 0x14, 0x4e, 0xa2, 0x29, 0xb1, 0xfa, 0xbe, 0x0f, 0xb1, 0x7d, 0xc8, - 0x12, 0x78, 0x9b, 0x18, 0xcf, 0x8b, 0xdd, 0xb1, 0xad, 0xa0, 0xfc, 0x51, 0x30, 0x0a, 0x27, 0xd1, - 0x35, 0xf9, 0xf5, 0x5e, 0x32, 0x34, 0x4a, 0x8d, 0xb8, 0x84, 0xf6, 0x91, 0x57, 0xc9, 0xf1, 0xbb, - 0xf8, 0xee, 0xa3, 0xc3, 0x68, 0xd7, 0x61, 0xf4, 0xdd, 0x61, 0xf4, 0xda, 0x63, 0x67, 0xd7, 0x63, - 0xe7, 0xab, 0xc7, 0xce, 0x3d, 0xad, 0xb8, 0x5e, 0x6d, 0x72, 0x52, 0xc0, 0x9a, 0xee, 0xff, 0x3a, - 0x6f, 0x99, 0x7e, 0x02, 0x59, 0xd3, 0xe3, 0x0c, 0xcf, 0xc3, 0x10, 0xfa, 0x45, 0x30, 0x95, 0x9f, - 0x1c, 0x76, 0xb8, 0xf9, 0x09, 0x00, 0x00, 0xff, 0xff, 0xa0, 0x1a, 0x95, 0x9c, 0x94, 0x01, 0x00, - 0x00, + 0x18, 0x85, 0xeb, 0xaf, 0x1f, 0x50, 0xdc, 0xa1, 0x52, 0xc4, 0x90, 0x56, 0xc2, 0x8a, 0x18, 0x50, + 0x96, 0xda, 0x6a, 0xb9, 0x02, 0xda, 0x05, 0xd6, 0x74, 0x63, 0x41, 0xf9, 0x31, 0xa9, 0xd5, 0xd4, + 0x6f, 0x64, 0x3b, 0x05, 0xee, 0x82, 0x8b, 0xe1, 0x22, 0x18, 0x2b, 0x26, 0x16, 0x24, 0x94, 0xdc, + 0x08, 0x6a, 0xed, 0x74, 0x28, 0xe3, 0x9b, 0xe7, 0x89, 0xce, 0xf1, 0xc1, 0xa4, 0x84, 0x95, 0x51, + 0x50, 0x14, 0x4c, 0x2f, 0x63, 0xc5, 0x33, 0xa6, 0xab, 0xb2, 0x2c, 0x04, 0x57, 0xb4, 0x54, 0x60, + 0xc0, 0x1b, 0xb4, 0x9c, 0x5a, 0x3e, 0x1a, 0xa6, 0xa0, 0xd7, 0xa0, 0x1f, 0xf7, 0x98, 0xd9, 0xc3, + 0xba, 0x23, 0x62, 0x2f, 0x96, 0xc4, 0x9a, 0xb3, 0xcd, 0x24, 0xe1, 0x26, 0x9e, 0xb0, 0x14, 0x84, + 0x74, 0xfc, 0xf2, 0x4f, 0x16, 0x57, 0x1b, 0x91, 0x72, 0x8b, 0xaf, 0xbe, 0x11, 0xee, 0x2d, 0x5c, + 0xba, 0x37, 0xc5, 0x67, 0x71, 0x96, 0x29, 0xae, 0xb5, 0x8f, 0x02, 0x14, 0x9e, 0xcf, 0xfc, 0xcf, + 0xf7, 0xf1, 0x85, 0x8b, 0xbb, 0xb5, 0x64, 0x61, 0x94, 0x90, 0x79, 0xd4, 0x8a, 0x1e, 0xc3, 0x27, + 0xda, 0xc4, 0x2b, 0xee, 0xff, 0x0b, 0x50, 0xd8, 0x9f, 0x0e, 0xa9, 0xd3, 0x77, 0x7d, 0xa8, 0xeb, + 0x43, 0xe7, 0x20, 0x64, 0x64, 0x3d, 0x6f, 0x86, 0x7b, 0xae, 0x82, 0xf6, 0xbb, 0x41, 0x37, 0xec, + 0x4f, 0xaf, 0xe9, 0xd1, 0x7b, 0x69, 0xdb, 0x68, 0x61, 0xc5, 0x39, 0xc8, 0x27, 0x91, 0x47, 0x87, + 0xff, 0xbc, 0x10, 0x0f, 0x2a, 0x99, 0x80, 0xcc, 0x84, 0xcc, 0xef, 0xb8, 0xc8, 0x97, 0xc6, 0xff, + 0x1f, 0xa0, 0xb0, 0x1b, 0x1d, 0x7f, 0x9e, 0xdd, 0x7f, 0xd4, 0x04, 0x6d, 0x6b, 0x82, 0x7e, 0x6a, + 0x82, 0xde, 0x1a, 0xd2, 0xd9, 0x36, 0xa4, 0xf3, 0xd5, 0x90, 0xce, 0x03, 0xcb, 0x85, 0x59, 0x56, + 0x09, 0x4d, 0x61, 0xcd, 0x76, 0xf9, 0x63, 0xc9, 0xcd, 0x33, 0xa8, 0x15, 0x3b, 0x0c, 0xf6, 0xd2, + 0x4e, 0x66, 0x5e, 0x4b, 0xae, 0x93, 0xd3, 0xfd, 0x62, 0x37, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, + 0x0a, 0xaf, 0xb1, 0x4b, 0xbe, 0x01, 0x00, 0x00, } func (m *Supplier) Marshal() (dAtA []byte, err error) { @@ -134,6 +143,11 @@ func (m *Supplier) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.UnbondingHeight != 0 { + i = encodeVarintSupplier(dAtA, i, uint64(m.UnbondingHeight)) + i-- + dAtA[i] = 0x20 + } if len(m.Services) > 0 { for iNdEx := len(m.Services) - 1; iNdEx >= 0; iNdEx-- { { @@ -201,6 +215,9 @@ func (m *Supplier) Size() (n int) { n += 1 + l + sovSupplier(uint64(l)) } } + if m.UnbondingHeight != 0 { + n += 1 + sovSupplier(uint64(m.UnbondingHeight)) + } return n } @@ -341,6 +358,25 @@ func (m *Supplier) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field UnbondingHeight", wireType) + } + m.UnbondingHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSupplier + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.UnbondingHeight |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipSupplier(dAtA[iNdEx:]) diff --git a/x/supplier/keeper/keeper.go b/x/supplier/keeper/keeper.go index ef87b8f4d..e6d6b9912 100644 --- a/x/supplier/keeper/keeper.go +++ b/x/supplier/keeper/keeper.go @@ -21,7 +21,8 @@ type ( // should be the x/gov module account. authority string - bankKeeper types.BankKeeper + bankKeeper types.BankKeeper + sharedKeeper types.SharedKeeper } ) @@ -32,6 +33,7 @@ func NewKeeper( authority string, bankKeeper types.BankKeeper, + sharedKeeper types.SharedKeeper, ) Keeper { if _, err := sdk.AccAddressFromBech32(authority); err != nil { panic(fmt.Sprintf("invalid authority address: %s", authority)) @@ -43,7 +45,8 @@ func NewKeeper( authority: authority, logger: logger, - bankKeeper: bankKeeper, + bankKeeper: bankKeeper, + sharedKeeper: sharedKeeper, } } diff --git a/x/supplier/keeper/msg_server_stake_supplier.go b/x/supplier/keeper/msg_server_stake_supplier.go index f0a823d0f..8d704853b 100644 --- a/x/supplier/keeper/msg_server_stake_supplier.go +++ b/x/supplier/keeper/msg_server_stake_supplier.go @@ -48,6 +48,9 @@ func (k msgServer) StakeSupplier(ctx context.Context, msg *types.MsgStakeSupplie return nil, err } logger.Info(fmt.Sprintf("Supplier is going to escrow an additional %+v coins", coinsToEscrow)) + + // If the supplier has initiated the unstake action, reset the unbonding height + supplier.UnbondingHeight = 0 } // Must always stake or upstake (> 0 delta) diff --git a/x/supplier/keeper/msg_server_unstake_supplier.go b/x/supplier/keeper/msg_server_unstake_supplier.go index dd36c7f2e..aa277ef2e 100644 --- a/x/supplier/keeper/msg_server_unstake_supplier.go +++ b/x/supplier/keeper/msg_server_unstake_supplier.go @@ -7,6 +7,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/pokt-network/poktroll/telemetry" + "github.com/pokt-network/poktroll/x/shared" + sharedtypes "github.com/pokt-network/poktroll/x/shared/types" "github.com/pokt-network/poktroll/x/supplier/types" ) @@ -37,24 +39,36 @@ func (k msgServer) UnstakeSupplier( } logger.Info(fmt.Sprintf("Supplier found. Unstaking supplier for address %s", msg.Address)) - // Retrieve the address of the supplier - supplierAddress, err := sdk.AccAddressFromBech32(msg.Address) - if err != nil { - logger.Error(fmt.Sprintf("could not parse address %s", msg.Address)) - return nil, err + // Check if the supplier has already initiated the unstake action and is in the unbonding period + if supplier.UnbondingHeight > 0 { + logger.Warn(fmt.Sprintf("Supplier %s has not finished the unbonding period", msg.Address)) + return nil, types.ErrSupplierUnbonding } - // Send the coins from the supplier pool back to the supplier - err = k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, supplierAddress, []sdk.Coin{*supplier.Stake}) - if err != nil { - logger.Error(fmt.Sprintf("could not send %v coins from %s module to %s account due to %v", supplier.Stake, supplierAddress, types.ModuleName, err)) - return nil, err - } + sdkCtx := sdk.UnwrapSDKContext(ctx) + currentHeight := sdkCtx.BlockHeight() + sharedParams := k.sharedKeeper.GetParams(ctx) - // Update the Supplier in the store - k.RemoveSupplier(ctx, supplierAddress.String()) - logger.Info(fmt.Sprintf("Successfully removed the supplier: %+v", supplier)) + supplier.UnbondingHeight = GetSupplierUnbondingHeight(&sharedParams, currentHeight) + k.SetSupplier(ctx, supplier) isSuccessful = true return &types.MsgUnstakeSupplierResponse{}, nil } + +// GetSupplierUnbondingHeight returns the height at which the supplier will be able to withdraw +// the staked coins after the unbonding period. +func GetSupplierUnbondingHeight(sharedParams *sharedtypes.Params, currentHeight int64) int64 { + sessionEndHeight := shared.GetSessionEndHeight(sharedParams, currentHeight) + + // TODO_IN_THIS_PR: Make the unbonding period a governance parameter. + unbondingPeriodInBlocks := int64(sharedParams.GetNumBlocksPerSession()) + + // Unbonding period has a minimum duration of 1 session, which means that if + // the current height is prior to the end of the session, the unbonding height + // will be set to the end of the session that is after the current session. + // This is to avoid the case where a supplier is able to withdraw after 1 block, + // if it unstakes right before the end of the current session. + return sessionEndHeight + unbondingPeriodInBlocks + +} diff --git a/x/supplier/keeper/unbond_suppliers.go b/x/supplier/keeper/unbond_suppliers.go new file mode 100644 index 000000000..77d77efef --- /dev/null +++ b/x/supplier/keeper/unbond_suppliers.go @@ -0,0 +1,59 @@ +package keeper + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/pokt-network/poktroll/x/shared" + "github.com/pokt-network/poktroll/x/supplier/types" +) + +// EndBlockerPruneAppToGatewayPendingUndelegation runs at the end of each block +// and prunes app to gateway undelegations that have exceeded the retention delay. +func (k Keeper) EndBlockerUnbondSupplier(ctx sdk.Context) error { + currentHeight := ctx.BlockHeight() + sharedParams := k.sharedKeeper.GetParams(ctx) + sessionEndHeight := shared.GetSessionEndHeight(&sharedParams, currentHeight) + + // Only process unbonding at the end of the session. + if currentHeight != sessionEndHeight { + return nil + } + + logger := k.Logger().With("method", "UnbondSupplier") + + // Iterate over all suppliers and unbond suppliers that have finished the unbonding period. + for _, supplier := range k.GetAllSuppliers(ctx) { + // Ignore suppliers that have not initiated the unbonding action. + if supplier.UnbondingHeight == 0 { + continue + } + + if supplier.UnbondingHeight <= currentHeight { + + // Retrieve the address of the supplier + supplierAddress, err := sdk.AccAddressFromBech32(supplier.Address) + if err != nil { + logger.Error(fmt.Sprintf("could not parse address %s", supplier.Address)) + return err + } + + // Send the coins from the supplier pool back to the supplier + if err = k.bankKeeper.SendCoinsFromModuleToAccount( + ctx, types.ModuleName, supplierAddress, []sdk.Coin{*supplier.Stake}, + ); err != nil { + logger.Error(fmt.Sprintf( + "could not send %v coins from %s module to %s account due to %v", + supplier.Stake, supplierAddress, types.ModuleName, err, + )) + return err + } + + // Update the Supplier in the store + k.RemoveSupplier(ctx, supplierAddress.String()) + logger.Info(fmt.Sprintf("Successfully removed the supplier: %+v", supplier)) + } + } + + return nil +} diff --git a/x/supplier/module/abci.go b/x/supplier/module/abci.go new file mode 100644 index 000000000..24d42ba48 --- /dev/null +++ b/x/supplier/module/abci.go @@ -0,0 +1,16 @@ +package supplier + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/pokt-network/poktroll/x/supplier/keeper" +) + +// EndBlocker is called every block and handles supplier related updates. +func EndBlocker(ctx sdk.Context, k keeper.Keeper) error { + if err := k.EndBlockerUnbondSupplier(ctx); err != nil { + return err + } + + return nil +} diff --git a/x/supplier/module/module.go b/x/supplier/module/module.go index 8ac44e592..0312f379b 100644 --- a/x/supplier/module/module.go +++ b/x/supplier/module/module.go @@ -95,9 +95,9 @@ func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *r type AppModule struct { AppModuleBasic - keeper keeper.Keeper - accountKeeper types.AccountKeeper - bankKeeper types.BankKeeper + supplierKeeper keeper.Keeper + accountKeeper types.AccountKeeper + bankKeeper types.BankKeeper } func NewAppModule( @@ -108,7 +108,7 @@ func NewAppModule( ) AppModule { return AppModule{ AppModuleBasic: NewAppModuleBasic(cdc), - keeper: keeper, + supplierKeeper: keeper, accountKeeper: accountKeeper, bankKeeper: bankKeeper, } @@ -116,8 +116,8 @@ func NewAppModule( // RegisterServices registers a gRPC query service to respond to the module-specific gRPC queries func (am AppModule) RegisterServices(cfg module.Configurator) { - types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper)) - types.RegisterQueryServer(cfg.QueryServer(), am.keeper) + types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.supplierKeeper)) + types.RegisterQueryServer(cfg.QueryServer(), am.supplierKeeper) } // RegisterInvariants registers the invariants of the module. If an invariant deviates from its predicted value, the InvariantRegistry triggers appropriate logic (most often the chain will be halted) @@ -129,12 +129,12 @@ func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, gs json.Ra // Initialize global index to index in genesis state cdc.MustUnmarshalJSON(gs, &genState) - InitGenesis(ctx, am.keeper, genState) + InitGenesis(ctx, am.supplierKeeper, genState) } // ExportGenesis returns the module's exported genesis state as raw JSON bytes. func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { - genState := ExportGenesis(ctx, am.keeper) + genState := ExportGenesis(ctx, am.supplierKeeper) return cdc.MustMarshalJSON(genState) } @@ -151,8 +151,9 @@ func (am AppModule) BeginBlock(_ context.Context) error { // EndBlock contains the logic that is automatically triggered at the end of each block. // The end block implementation is optional. -func (am AppModule) EndBlock(_ context.Context) error { - return nil +func (am AppModule) EndBlock(goCtx context.Context) error { + ctx := sdk.UnwrapSDKContext(goCtx) + return EndBlocker(ctx, am.supplierKeeper) } // IsOnePerModuleType implements the depinject.OnePerModuleType interface. @@ -179,6 +180,7 @@ type ModuleInputs struct { AccountKeeper types.AccountKeeper BankKeeper types.BankKeeper + SharedKeeper types.SharedKeeper } type ModuleOutputs struct { @@ -200,6 +202,7 @@ func ProvideModule(in ModuleInputs) ModuleOutputs { in.Logger, authority.String(), in.BankKeeper, + in.SharedKeeper, ) m := NewAppModule( in.Cdc, diff --git a/x/supplier/module/simulation.go b/x/supplier/module/simulation.go index 0d735d61f..84919c582 100644 --- a/x/supplier/module/simulation.go +++ b/x/supplier/module/simulation.go @@ -67,7 +67,7 @@ func (am AppModule) WeightedOperations(simState module.SimulationState) []simtyp ) operations = append(operations, simulation.NewWeightedOperation( weightMsgStakeSupplier, - suppliersimulation.SimulateMsgStakeSupplier(am.accountKeeper, am.bankKeeper, am.keeper), + suppliersimulation.SimulateMsgStakeSupplier(am.accountKeeper, am.bankKeeper, am.supplierKeeper), )) var weightMsgUnstakeSupplier int @@ -78,7 +78,7 @@ func (am AppModule) WeightedOperations(simState module.SimulationState) []simtyp ) operations = append(operations, simulation.NewWeightedOperation( weightMsgUnstakeSupplier, - suppliersimulation.SimulateMsgUnstakeSupplier(am.accountKeeper, am.bankKeeper, am.keeper), + suppliersimulation.SimulateMsgUnstakeSupplier(am.accountKeeper, am.bankKeeper, am.supplierKeeper), )) // this line is used by starport scaffolding # simapp/module/operation @@ -93,7 +93,7 @@ func (am AppModule) ProposalMsgs(simState module.SimulationState) []simtypes.Wei opWeightMsgStakeSupplier, defaultWeightMsgStakeSupplier, func(r *rand.Rand, ctx sdk.Context, accs []simtypes.Account) sdk.Msg { - suppliersimulation.SimulateMsgStakeSupplier(am.accountKeeper, am.bankKeeper, am.keeper) + suppliersimulation.SimulateMsgStakeSupplier(am.accountKeeper, am.bankKeeper, am.supplierKeeper) return nil }, ), @@ -101,7 +101,7 @@ func (am AppModule) ProposalMsgs(simState module.SimulationState) []simtypes.Wei opWeightMsgUnstakeSupplier, defaultWeightMsgUnstakeSupplier, func(r *rand.Rand, ctx sdk.Context, accs []simtypes.Account) sdk.Msg { - suppliersimulation.SimulateMsgUnstakeSupplier(am.accountKeeper, am.bankKeeper, am.keeper) + suppliersimulation.SimulateMsgUnstakeSupplier(am.accountKeeper, am.bankKeeper, am.supplierKeeper) return nil }, ), diff --git a/x/supplier/types/errors.go b/x/supplier/types/errors.go index c89c13e39..286c16435 100644 --- a/x/supplier/types/errors.go +++ b/x/supplier/types/errors.go @@ -16,4 +16,5 @@ var ( ErrSupplierInvalidSessionId = sdkerrors.Register(ModuleName, 1107, "invalid session ID") ErrSupplierInvalidService = sdkerrors.Register(ModuleName, 1108, "invalid service in supplier") ErrSupplierInvalidSessionEndHeight = sdkerrors.Register(ModuleName, 1109, "invalid session ending height") + ErrSupplierUnbonding = sdkerrors.Register(ModuleName, 1110, "supplier is in unbonding period") ) diff --git a/x/supplier/types/expected_keepers.go b/x/supplier/types/expected_keepers.go index ba491c020..8d86868d6 100644 --- a/x/supplier/types/expected_keepers.go +++ b/x/supplier/types/expected_keepers.go @@ -6,6 +6,8 @@ import ( "context" sdk "github.com/cosmos/cosmos-sdk/types" + + sharedtypes "github.com/pokt-network/poktroll/x/shared/types" ) // AccountKeeper defines the expected interface for the Account module. @@ -19,3 +21,9 @@ type BankKeeper interface { SendCoinsFromAccountToModule(ctx context.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error SendCoinsFromModuleToAccount(ctx context.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error } + +// SharedKeeper defines the expected interface needed to retrieve shared information. +type SharedKeeper interface { + GetParams(ctx context.Context) sharedtypes.Params + GetSessionEndHeight(ctx context.Context, queryHeight int64) int64 +} From 065097a22ccf38649263e5d6d98f33dcdf3d2a40 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Fri, 5 Jul 2024 16:37:30 +0200 Subject: [PATCH 02/13] chore: Update comments --- x/supplier/keeper/unbond_suppliers.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/x/supplier/keeper/unbond_suppliers.go b/x/supplier/keeper/unbond_suppliers.go index 77d77efef..ded0139bd 100644 --- a/x/supplier/keeper/unbond_suppliers.go +++ b/x/supplier/keeper/unbond_suppliers.go @@ -8,8 +8,7 @@ import ( "github.com/pokt-network/poktroll/x/supplier/types" ) -// EndBlockerPruneAppToGatewayPendingUndelegation runs at the end of each block -// and prunes app to gateway undelegations that have exceeded the retention delay. +// EndBlockerUnbondSupplier unbonds suppliers that have finished the unbonding period. func (k Keeper) EndBlockerUnbondSupplier(ctx sdk.Context) error { currentHeight := ctx.BlockHeight() sharedParams := k.sharedKeeper.GetParams(ctx) @@ -23,6 +22,8 @@ func (k Keeper) EndBlockerUnbondSupplier(ctx sdk.Context) error { logger := k.Logger().With("method", "UnbondSupplier") // Iterate over all suppliers and unbond suppliers that have finished the unbonding period. + // TODO_IMPROVE: Use an index to iterate over suppliers that have initiated the + // unbonding action instead of iterating over all suppliers. for _, supplier := range k.GetAllSuppliers(ctx) { // Ignore suppliers that have not initiated the unbonding action. if supplier.UnbondingHeight == 0 { From 16a5e0194c9314e4b795d2c71c8425632a8af873 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Mon, 8 Jul 2024 20:23:20 +0200 Subject: [PATCH 03/13] test: Add unbonding tests --- testutil/integration/app.go | 13 +- testutil/keeper/proof.go | 1 + testutil/keeper/supplier.go | 17 +- testutil/keeper/tokenomics.go | 1 + .../msg_server_unstake_supplier_test.go | 145 +++++++++++++++--- 5 files changed, 146 insertions(+), 31 deletions(-) diff --git a/testutil/integration/app.go b/testutil/integration/app.go index 2a4eeed0f..fa3d840a3 100644 --- a/testutil/integration/app.go +++ b/testutil/integration/app.go @@ -456,9 +456,6 @@ func NewCompleteIntegrationApp(t *testing.T) *App { // authtypes.RegisterQueryServer(queryHelper, accountKeeper) sessiontypes.RegisterQueryServer(queryHelper, sessionKeeper) - // Need to go to the next block to finalize the genesis and setup - integrationApp.NextBlock(t) - // Set the default params for all the modules err := sharedKeeper.SetParams(integrationApp.GetSdkCtx(), sharedtypes.DefaultParams()) require.NoError(t, err) @@ -473,6 +470,11 @@ func NewCompleteIntegrationApp(t *testing.T) *App { err = applicationKeeper.SetParams(integrationApp.GetSdkCtx(), apptypes.DefaultParams()) require.NoError(t, err) + // Need to go to the next block to finalize the genesis and setup. + // This has to be after the params are set, as the params are stored in the + // store and need to be committed. + integrationApp.NextBlock(t) + // Prepare default testing fixtures // // Construct a keyring to hold the keypairs for the accounts used in the test. @@ -706,7 +708,10 @@ func (app *App) nextBlockUpdateCtx() { newContext := app.BaseApp.NewUncachedContext(true, header). WithBlockHeader(header). WithHeaderInfo(headerInfo). - WithEventManager(prevCtx.EventManager()) + WithEventManager(prevCtx.EventManager()). + // Pass the multi-store to the new context, otherwise the new context will + // create a new multi-store. + WithMultiStore(prevCtx.MultiStore()) *app.sdkCtx = newContext } diff --git a/testutil/keeper/proof.go b/testutil/keeper/proof.go index 35ab490db..eb4ea6dd4 100644 --- a/testutil/keeper/proof.go +++ b/testutil/keeper/proof.go @@ -186,6 +186,7 @@ func NewProofModuleKeepers(t testing.TB, opts ...ProofKeepersOpt) (_ *ProofModul log.NewNopLogger(), authority.String(), suppliermocks.NewMockBankKeeper(ctrl), + sharedKeeper, ) require.NoError(t, supplierKeeper.SetParams(ctx, suppliertypes.DefaultParams())) diff --git a/testutil/keeper/supplier.go b/testutil/keeper/supplier.go index 6f502a316..865439e86 100644 --- a/testutil/keeper/supplier.go +++ b/testutil/keeper/supplier.go @@ -20,6 +20,8 @@ import ( "github.com/stretchr/testify/require" "github.com/pokt-network/poktroll/testutil/supplier/mocks" + sharedkeeper "github.com/pokt-network/poktroll/x/shared/keeper" + sharedtypes "github.com/pokt-network/poktroll/x/shared/types" "github.com/pokt-network/poktroll/x/supplier/keeper" "github.com/pokt-network/poktroll/x/supplier/types" ) @@ -34,6 +36,9 @@ func SupplierKeeper(t testing.TB) (keeper.Keeper, context.Context) { stateStore.MountStoreWithDB(storeKey, storetypes.StoreTypeIAVL, db) require.NoError(t, stateStore.LoadLatestVersion()) + logger := log.NewTestLogger(t) + ctx := sdk.NewContext(stateStore, cmtproto.Header{}, false, logger) + registry := codectypes.NewInterfaceRegistry() cdc := codec.NewProtoCodec(registry) authority := authtypes.NewModuleAddress(govtypes.ModuleName) @@ -43,16 +48,24 @@ func SupplierKeeper(t testing.TB) (keeper.Keeper, context.Context) { mockBankKeeper.EXPECT().SendCoinsFromAccountToModule(gomock.Any(), gomock.Any(), types.ModuleName, gomock.Any()).AnyTimes() mockBankKeeper.EXPECT().SendCoinsFromModuleToAccount(gomock.Any(), types.ModuleName, gomock.Any(), gomock.Any()).AnyTimes() + // Construct a real shared keeper. + sharedKeeper := sharedkeeper.NewKeeper( + cdc, + runtime.NewKVStoreService(storeKey), + logger, + authority.String(), + ) + require.NoError(t, sharedKeeper.SetParams(ctx, sharedtypes.DefaultParams())) + k := keeper.NewKeeper( cdc, runtime.NewKVStoreService(storeKey), log.NewNopLogger(), authority.String(), mockBankKeeper, + sharedKeeper, ) - ctx := sdk.NewContext(stateStore, cmtproto.Header{}, false, log.NewNopLogger()) - // Initialize params require.NoError(t, k.SetParams(ctx, types.DefaultParams())) diff --git a/testutil/keeper/tokenomics.go b/testutil/keeper/tokenomics.go index f54bc13c1..a56784380 100644 --- a/testutil/keeper/tokenomics.go +++ b/testutil/keeper/tokenomics.go @@ -290,6 +290,7 @@ func NewTokenomicsModuleKeepers( log.NewNopLogger(), authority.String(), bankKeeper, + sharedKeeper, ) require.NoError(t, supplierKeeper.SetParams(ctx, suppliertypes.DefaultParams())) diff --git a/x/supplier/keeper/msg_server_unstake_supplier_test.go b/x/supplier/keeper/msg_server_unstake_supplier_test.go index fc601f9d9..24e26e2d6 100644 --- a/x/supplier/keeper/msg_server_unstake_supplier_test.go +++ b/x/supplier/keeper/msg_server_unstake_supplier_test.go @@ -25,26 +25,8 @@ func TestMsgServer_UnstakeSupplier_Success(t *testing.T) { _, isSupplierFound := k.GetSupplier(ctx, supplierAddr) require.False(t, isSupplierFound) - // Prepare the supplier - initialStake := sdk.NewCoin("upokt", math.NewInt(100)) - stakeMsg := &types.MsgStakeSupplier{ - Address: supplierAddr, - Stake: &initialStake, - Services: []*sharedtypes.SupplierServiceConfig{ - { - Service: &sharedtypes.Service{ - Id: "svcId", - }, - Endpoints: []*sharedtypes.SupplierEndpoint{ - { - Url: "http://localhost:8080", - RpcType: sharedtypes.RPCType_JSON_RPC, - Configs: make([]*sharedtypes.ConfigOption, 0), - }, - }, - }, - }, - } + initialStake := int64(100) + stakeMsg := createStakeMsg(supplierAddr, initialStake) // Stake the supplier _, err := srv.StakeSupplier(ctx, stakeMsg) @@ -54,19 +36,84 @@ func TestMsgServer_UnstakeSupplier_Success(t *testing.T) { foundSupplier, isSupplierFound := k.GetSupplier(ctx, supplierAddr) require.True(t, isSupplierFound) require.Equal(t, supplierAddr, foundSupplier.Address) - require.Equal(t, initialStake.Amount, foundSupplier.Stake.Amount) + require.Equal(t, math.NewInt(initialStake), foundSupplier.Stake.Amount) require.Len(t, foundSupplier.Services, 1) - // Unstake the supplier + // Initiate the supplier unstaking unstakeMsg := &types.MsgUnstakeSupplier{Address: supplierAddr} _, err = srv.UnstakeSupplier(ctx, unstakeMsg) require.NoError(t, err) - // Make sure the supplier can no longer be found after unstaking - _, isSupplierFound = k.GetSupplier(ctx, supplierAddr) + // Make sure the supplier entered the unbonding period + foundSupplier, isSupplierFound = k.GetSupplier(ctx, supplierAddr) + require.True(t, isSupplierFound) + require.Greater(t, foundSupplier.UnbondingHeight, int64(0)) + + sdkCtx := sdk.UnwrapSDKContext(ctx) + sdkCtx = sdkCtx.WithBlockHeight(foundSupplier.UnbondingHeight) + + // Run the endblocker to unbond the supplier + err = k.EndBlockerUnbondSupplier(sdkCtx) + require.NoError(t, err) + + // Make sure the supplier is removed from the suppliers list when the + // unbonding period is over + _, isSupplierFound = k.GetSupplier(sdkCtx, supplierAddr) require.False(t, isSupplierFound) } +func TestMsgServer_UnstakeSupplier_CancelUnbondingIfRestaked(t *testing.T) { + k, ctx := keepertest.SupplierKeeper(t) + srv := keeper.NewMsgServerImpl(k) + + // Generate an address for the supplier + supplierAddr := sample.AccAddress() + + // Stake the supplier + initialStake := int64(100) + stakeMsg := createStakeMsg(supplierAddr, initialStake) + _, err := srv.StakeSupplier(ctx, stakeMsg) + require.NoError(t, err) + + // Verify that the supplier exists with no unbonding height + foundSupplier, isSupplierFound := k.GetSupplier(ctx, supplierAddr) + require.True(t, isSupplierFound) + require.Equal(t, int64(0), foundSupplier.UnbondingHeight) + + // Initiate the supplier unstaking + unstakeMsg := &types.MsgUnstakeSupplier{Address: supplierAddr} + _, err = srv.UnstakeSupplier(ctx, unstakeMsg) + require.NoError(t, err) + + // Make sure the supplier entered the unbonding period + foundSupplier, isSupplierFound = k.GetSupplier(ctx, supplierAddr) + require.True(t, isSupplierFound) + require.Greater(t, foundSupplier.UnbondingHeight, int64(0)) + unbondingHeight := foundSupplier.UnbondingHeight + + // Stake the supplier again + stakeMsg = createStakeMsg(supplierAddr, initialStake+1) + _, err = srv.StakeSupplier(ctx, stakeMsg) + require.NoError(t, err) + + // Make sure the supplier is no longer in the unbonding period + foundSupplier, isSupplierFound = k.GetSupplier(ctx, supplierAddr) + require.True(t, isSupplierFound) + require.Equal(t, foundSupplier.UnbondingHeight, int64(0)) + + sdkCtx := sdk.UnwrapSDKContext(ctx) + sdkCtx = sdkCtx.WithBlockHeight(unbondingHeight) + + // Run the endblocker to unbond the supplier + err = k.EndBlockerUnbondSupplier(sdkCtx) + require.NoError(t, err) + + // Make sure the supplier is still in the suppliers list with an unbonding height of 0 + foundSupplier, isSupplierFound = k.GetSupplier(sdkCtx, supplierAddr) + require.True(t, isSupplierFound) + require.Equal(t, foundSupplier.UnbondingHeight, int64(0)) +} + func TestMsgServer_UnstakeSupplier_FailIfNotStaked(t *testing.T) { k, ctx := keepertest.SupplierKeeper(t) srv := keeper.NewMsgServerImpl(k) @@ -78,7 +125,7 @@ func TestMsgServer_UnstakeSupplier_FailIfNotStaked(t *testing.T) { _, isSupplierFound := k.GetSupplier(ctx, supplierAddr) require.False(t, isSupplierFound) - // Unstake the supplier + // Initiate the supplier unstaking unstakeMsg := &types.MsgUnstakeSupplier{Address: supplierAddr} _, err := srv.UnstakeSupplier(ctx, unstakeMsg) require.Error(t, err) @@ -87,3 +134,51 @@ func TestMsgServer_UnstakeSupplier_FailIfNotStaked(t *testing.T) { _, isSupplierFound = k.GetSupplier(ctx, supplierAddr) require.False(t, isSupplierFound) } + +func TestMsgServer_UnstakeSupplier_FailIfNotInUnbondingPeriod(t *testing.T) { + k, ctx := keepertest.SupplierKeeper(t) + srv := keeper.NewMsgServerImpl(k) + + // Generate an address for the supplier + supplierAddr := sample.AccAddress() + + // Stake the supplier + initialStake := int64(100) + stakeMsg := createStakeMsg(supplierAddr, initialStake) + _, err := srv.StakeSupplier(ctx, stakeMsg) + require.NoError(t, err) + + // Initiate the supplier unstaking + unstakeMsg := &types.MsgUnstakeSupplier{Address: supplierAddr} + _, err = srv.UnstakeSupplier(ctx, unstakeMsg) + require.NoError(t, err) + + sdkCtx := sdk.UnwrapSDKContext(ctx) + sdkCtx = sdkCtx.WithBlockHeight(sdkCtx.BlockHeight() + 1) + + _, err = srv.UnstakeSupplier(sdkCtx, unstakeMsg) + require.ErrorIs(t, err, types.ErrSupplierUnbonding) +} + +func createStakeMsg(supplierAddr string, stakeAmount int64) *types.MsgStakeSupplier { + initialStake := sdk.NewCoin("upokt", math.NewInt(stakeAmount)) + return &types.MsgStakeSupplier{ + Address: supplierAddr, + Stake: &initialStake, + Services: []*sharedtypes.SupplierServiceConfig{ + { + Service: &sharedtypes.Service{ + Id: "svcId", + }, + Endpoints: []*sharedtypes.SupplierEndpoint{ + { + Url: "http://localhost:8080", + RpcType: sharedtypes.RPCType_JSON_RPC, + Configs: make([]*sharedtypes.ConfigOption, 0), + }, + }, + }, + }, + } + +} From cdb4a256e62b7aea4ed7e98a32ff37356a643cc3 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Tue, 9 Jul 2024 01:43:07 +0200 Subject: [PATCH 04/13] test: Update E2E tests --- e2e/tests/init_test.go | 38 ++++++++++++++++++++++++++++++++ e2e/tests/session_steps_test.go | 29 ++++++++++++++++++++++++ e2e/tests/stake_app.feature | 5 ++--- e2e/tests/stake_gateway.feature | 5 ++--- e2e/tests/stake_supplier.feature | 8 +++---- 5 files changed, 75 insertions(+), 10 deletions(-) diff --git a/e2e/tests/init_test.go b/e2e/tests/init_test.go index 084fa26b9..16f1cd913 100644 --- a/e2e/tests/init_test.go +++ b/e2e/tests/init_test.go @@ -442,6 +442,24 @@ func (s *suite) AModuleEndBlockEventIsBroadcast(module, eventType string) { s.waitForNewBlockEvent(newEventTypeMatchFn(module, eventType)) } +func (s *suite) TheSupplierForAccountIsUnbonding(accName string) { + _, ok := accNameToSupplierMap[accName] + require.True(s, ok, "supplier %s not found", accName) + + s.waitForTxResultEvent(newEventMsgTypeMatchFn("supplier", "UnstakeSupplier")) + + supplier := s.getSupplierInfo(accName) + require.Greater(s, supplier.UnbondingHeight, int64(0), "supplier %s is not unbonding", accName) +} + +func (s *suite) TheUserWaitsForUnbondingPeriodToPass(accName string) { + _, ok := accNameToSupplierMap[accName] + require.True(s, ok, "supplier %s not found", accName) + + supplier := s.getSupplierInfo(accName) + s.waitForBlockHeight(supplier.UnbondingHeight) +} + func (s *suite) getStakedAmount(actorType, accName string) (int, bool) { s.Helper() args := []string{ @@ -566,6 +584,26 @@ func (s *suite) validateAmountChange(prevAmount, currAmount int, expectedAmountC } +// getSupplierInfo returns the supplier information for a given supplier address +func (s *suite) getSupplierInfo(supplierAddr string) *sharedtypes.Supplier { + args := []string{ + "query", + "supplier", + "show-supplier", + accNameToAddrMap[supplierAddr], + "--output=json", + } + + res, err := s.pocketd.RunCommandOnHostWithRetry("", numQueryRetries, args...) + require.NoError(s, err, "error getting supplier %s", supplierAddr) + s.pocketd.result = res + + var resp suppliertypes.QueryGetSupplierResponse + responseBz := []byte(strings.TrimSpace(res.Stdout)) + s.cdc.MustUnmarshalJSON(responseBz, &resp) + return &resp.Supplier +} + // TODO_IMPROVE: use `sessionId` and `supplierName` since those are the two values // used to create the primary composite key on-chain to uniquely distinguish relays. func relayReferenceKey(appName, supplierName string) string { diff --git a/e2e/tests/session_steps_test.go b/e2e/tests/session_steps_test.go index 0a07c6340..63fdfa1fa 100644 --- a/e2e/tests/session_steps_test.go +++ b/e2e/tests/session_steps_test.go @@ -251,6 +251,35 @@ func (s *suite) waitForNewBlockEvent( } } +// waitForBlockHeight waits for a NewBlock event to be observed whose height is +// greater than or equal to the target height. +func (s *suite) waitForBlockHeight(targetHeight int64) { + ctx, done := context.WithCancel(s.ctx) + + // For each observed event, **asynchronously** check if it is greater than + // or equal to the target height + channel.ForEach[*block.CometNewBlockEvent]( + ctx, s.newBlockEventsReplayClient.EventsSequence(ctx), + func(_ context.Context, newBlockEvent *block.CometNewBlockEvent) { + if newBlockEvent == nil { + return + } + + if newBlockEvent.Data.Value.Block.Header.Height >= targetHeight { + done() + return + } + }, + ) + + select { + case <-time.After(eventTimeout): + s.Fatalf("ERROR: timed out waiting for block height", targetHeight) + case <-ctx.Done(): + s.Log("Success; height detected before timeout.") + } +} + // newEventTypeMatchFn returns a function that matches an event based on its type // field. The type URL is constructed from the given module and eventType arguments // where module is the module name and eventType is the protobuf message type name diff --git a/e2e/tests/stake_app.feature b/e2e/tests/stake_app.feature index b88b437f3..ae311847d 100644 --- a/e2e/tests/stake_app.feature +++ b/e2e/tests/stake_app.feature @@ -10,8 +10,7 @@ Feature: Stake App Namespaces Then the user should be able to see standard output containing "txhash:" And the user should be able to see standard output containing "code: 0" And the pocketd binary should exit without error - # TODO_TECHDEBT(@red-0ne): Wait for an admitted stake event instead of a time based waiting. - And the user should wait for "5" seconds + And the user should wait for the "application" module "StakeApplication" message to be submitted And the "application" for account "app2" is staked with "1000070" uPOKT And the account balance of "app2" should be "1000070" uPOKT "less" than before @@ -23,6 +22,6 @@ Feature: Stake App Namespaces Then the user should be able to see standard output containing "txhash:" And the user should be able to see standard output containing "code: 0" And the pocketd binary should exit without error - And the user should wait for "5" seconds + And the user should wait for the "application" module "UnstakeApplication" message to be submitted And the "application" for account "app2" is not staked And the account balance of "app2" should be "1000070" uPOKT "more" than before \ No newline at end of file diff --git a/e2e/tests/stake_gateway.feature b/e2e/tests/stake_gateway.feature index bbfc5bb9c..654d2d7dd 100644 --- a/e2e/tests/stake_gateway.feature +++ b/e2e/tests/stake_gateway.feature @@ -8,8 +8,7 @@ Feature: Stake Gateway Namespaces Then the user should be able to see standard output containing "txhash:" And the user should be able to see standard output containing "code: 0" And the pocketd binary should exit without error - # TODO_TECHDEBT(@red-0ne): Replace these time-based waits with event listening waits - And the user should wait for "5" seconds + And the user should wait for the "gateway" module "StakeGateway" message to be submitted And the "gateway" for account "gateway2" is staked with "1000070" uPOKT And the account balance of "gateway2" should be "1000070" uPOKT "less" than before @@ -21,6 +20,6 @@ Feature: Stake Gateway Namespaces Then the user should be able to see standard output containing "txhash:" And the user should be able to see standard output containing "code: 0" And the pocketd binary should exit without error - And the user should wait for "5" seconds + And the user should wait for the "gateway" module "UnstakeGateway" message to be submitted And the "gateway" for account "gateway2" is not staked And the account balance of "gateway2" should be "1000070" uPOKT "more" than before \ No newline at end of file diff --git a/e2e/tests/stake_supplier.feature b/e2e/tests/stake_supplier.feature index 52f84989d..dbddaf890 100644 --- a/e2e/tests/stake_supplier.feature +++ b/e2e/tests/stake_supplier.feature @@ -10,8 +10,7 @@ Feature: Stake Supplier Namespace Then the user should be able to see standard output containing "txhash:" And the user should be able to see standard output containing "code: 0" And the pocketd binary should exit without error - # TODO_TECHDEBT(@red-0ne): Replace these time-based waits with event listening waits - And the user should wait for "5" seconds + And the user should wait for the "supplier" module "StakeSupplier" message to be submitted And the "supplier" for account "supplier2" is staked with "1000070" uPOKT And the account balance of "supplier2" should be "1000070" uPOKT "less" than before @@ -23,6 +22,7 @@ Feature: Stake Supplier Namespace Then the user should be able to see standard output containing "txhash:" And the user should be able to see standard output containing "code: 0" And the pocketd binary should exit without error - And the user should wait for "5" seconds - And the "supplier" for account "supplier2" is not staked + And the supplier for account "supplier2" is unbonding + When the user waits for "supplier2" unbonding period to pass + Then the "supplier" for account "supplier2" is not staked And the account balance of "supplier2" should be "1000070" uPOKT "more" than before \ No newline at end of file From a1afa75f86a4e5ea2621be46fdd6198b6d36e44c Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Wed, 10 Jul 2024 04:54:19 +0200 Subject: [PATCH 05/13] feat: Add unbonding gov param --- api/poktroll/shared/supplier.pulsar.go | 76 ++++++++++--------- api/poktroll/supplier/params.pulsar.go | 72 +++++++++++++++++- e2e/tests/init_test.go | 30 +++++++- proto/poktroll/shared/supplier.proto | 2 +- proto/poktroll/supplier/params.proto | 4 + testutil/keeper/supplier.go | 6 +- x/session/keeper/session_hydrator.go | 6 ++ x/shared/types/supplier.pb.go | 69 ++++++++--------- .../keeper/msg_server_stake_supplier.go | 4 +- .../keeper/msg_server_unstake_supplier.go | 33 +++----- .../msg_server_unstake_supplier_test.go | 18 +++-- x/supplier/keeper/msg_update_params_test.go | 14 +++- x/supplier/keeper/unbond_suppliers.go | 7 +- x/supplier/types/errors.go | 1 + x/supplier/types/genesis_test.go | 53 ++++++++++++- x/supplier/types/params.go | 45 ++++++++++- x/supplier/types/params.pb.go | 61 ++++++++++++--- 17 files changed, 372 insertions(+), 129 deletions(-) diff --git a/api/poktroll/shared/supplier.pulsar.go b/api/poktroll/shared/supplier.pulsar.go index 4006947aa..58c838148 100644 --- a/api/poktroll/shared/supplier.pulsar.go +++ b/api/poktroll/shared/supplier.pulsar.go @@ -66,11 +66,11 @@ func (x *_Supplier_3_list) IsValid() bool { } var ( - md_Supplier protoreflect.MessageDescriptor - fd_Supplier_address protoreflect.FieldDescriptor - fd_Supplier_stake protoreflect.FieldDescriptor - fd_Supplier_services protoreflect.FieldDescriptor - fd_Supplier_unbondingHeight protoreflect.FieldDescriptor + md_Supplier protoreflect.MessageDescriptor + fd_Supplier_address protoreflect.FieldDescriptor + fd_Supplier_stake protoreflect.FieldDescriptor + fd_Supplier_services protoreflect.FieldDescriptor + fd_Supplier_unstake_commit_session_end_height protoreflect.FieldDescriptor ) func init() { @@ -79,7 +79,7 @@ func init() { fd_Supplier_address = md_Supplier.Fields().ByName("address") fd_Supplier_stake = md_Supplier.Fields().ByName("stake") fd_Supplier_services = md_Supplier.Fields().ByName("services") - fd_Supplier_unbondingHeight = md_Supplier.Fields().ByName("unbondingHeight") + fd_Supplier_unstake_commit_session_end_height = md_Supplier.Fields().ByName("unstake_commit_session_end_height") } var _ protoreflect.Message = (*fastReflection_Supplier)(nil) @@ -165,9 +165,9 @@ func (x *fastReflection_Supplier) Range(f func(protoreflect.FieldDescriptor, pro return } } - if x.UnbondingHeight != int64(0) { - value := protoreflect.ValueOfInt64(x.UnbondingHeight) - if !f(fd_Supplier_unbondingHeight, value) { + if x.UnstakeCommitSessionEndHeight != int64(0) { + value := protoreflect.ValueOfInt64(x.UnstakeCommitSessionEndHeight) + if !f(fd_Supplier_unstake_commit_session_end_height, value) { return } } @@ -192,8 +192,8 @@ func (x *fastReflection_Supplier) Has(fd protoreflect.FieldDescriptor) bool { return x.Stake != nil case "poktroll.shared.Supplier.services": return len(x.Services) != 0 - case "poktroll.shared.Supplier.unbondingHeight": - return x.UnbondingHeight != int64(0) + case "poktroll.shared.Supplier.unstake_commit_session_end_height": + return x.UnstakeCommitSessionEndHeight != int64(0) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.shared.Supplier")) @@ -216,8 +216,8 @@ func (x *fastReflection_Supplier) Clear(fd protoreflect.FieldDescriptor) { x.Stake = nil case "poktroll.shared.Supplier.services": x.Services = nil - case "poktroll.shared.Supplier.unbondingHeight": - x.UnbondingHeight = int64(0) + case "poktroll.shared.Supplier.unstake_commit_session_end_height": + x.UnstakeCommitSessionEndHeight = int64(0) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.shared.Supplier")) @@ -246,8 +246,8 @@ func (x *fastReflection_Supplier) Get(descriptor protoreflect.FieldDescriptor) p } listValue := &_Supplier_3_list{list: &x.Services} return protoreflect.ValueOfList(listValue) - case "poktroll.shared.Supplier.unbondingHeight": - value := x.UnbondingHeight + case "poktroll.shared.Supplier.unstake_commit_session_end_height": + value := x.UnstakeCommitSessionEndHeight return protoreflect.ValueOfInt64(value) default: if descriptor.IsExtension() { @@ -277,8 +277,8 @@ func (x *fastReflection_Supplier) Set(fd protoreflect.FieldDescriptor, value pro lv := value.List() clv := lv.(*_Supplier_3_list) x.Services = *clv.list - case "poktroll.shared.Supplier.unbondingHeight": - x.UnbondingHeight = value.Int() + case "poktroll.shared.Supplier.unstake_commit_session_end_height": + x.UnstakeCommitSessionEndHeight = value.Int() default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.shared.Supplier")) @@ -312,8 +312,8 @@ func (x *fastReflection_Supplier) Mutable(fd protoreflect.FieldDescriptor) proto return protoreflect.ValueOfList(value) case "poktroll.shared.Supplier.address": panic(fmt.Errorf("field address of message poktroll.shared.Supplier is not mutable")) - case "poktroll.shared.Supplier.unbondingHeight": - panic(fmt.Errorf("field unbondingHeight of message poktroll.shared.Supplier is not mutable")) + case "poktroll.shared.Supplier.unstake_commit_session_end_height": + panic(fmt.Errorf("field unstake_commit_session_end_height of message poktroll.shared.Supplier is not mutable")) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.shared.Supplier")) @@ -335,7 +335,7 @@ func (x *fastReflection_Supplier) NewField(fd protoreflect.FieldDescriptor) prot case "poktroll.shared.Supplier.services": list := []*SupplierServiceConfig{} return protoreflect.ValueOfList(&_Supplier_3_list{list: &list}) - case "poktroll.shared.Supplier.unbondingHeight": + case "poktroll.shared.Supplier.unstake_commit_session_end_height": return protoreflect.ValueOfInt64(int64(0)) default: if fd.IsExtension() { @@ -420,8 +420,8 @@ func (x *fastReflection_Supplier) ProtoMethods() *protoiface.Methods { n += 1 + l + runtime.Sov(uint64(l)) } } - if x.UnbondingHeight != 0 { - n += 1 + runtime.Sov(uint64(x.UnbondingHeight)) + if x.UnstakeCommitSessionEndHeight != 0 { + n += 1 + runtime.Sov(uint64(x.UnstakeCommitSessionEndHeight)) } if x.unknownFields != nil { n += len(x.unknownFields) @@ -452,8 +452,8 @@ func (x *fastReflection_Supplier) ProtoMethods() *protoiface.Methods { i -= len(x.unknownFields) copy(dAtA[i:], x.unknownFields) } - if x.UnbondingHeight != 0 { - i = runtime.EncodeVarint(dAtA, i, uint64(x.UnbondingHeight)) + if x.UnstakeCommitSessionEndHeight != 0 { + i = runtime.EncodeVarint(dAtA, i, uint64(x.UnstakeCommitSessionEndHeight)) i-- dAtA[i] = 0x20 } @@ -647,9 +647,9 @@ func (x *fastReflection_Supplier) ProtoMethods() *protoiface.Methods { iNdEx = postIndex case 4: if wireType != 0 { - return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field UnbondingHeight", wireType) + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field UnstakeCommitSessionEndHeight", wireType) } - x.UnbondingHeight = 0 + x.UnstakeCommitSessionEndHeight = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow @@ -659,7 +659,7 @@ func (x *fastReflection_Supplier) ProtoMethods() *protoiface.Methods { } b := dAtA[iNdEx] iNdEx++ - x.UnbondingHeight |= int64(b&0x7F) << shift + x.UnstakeCommitSessionEndHeight |= int64(b&0x7F) << shift if b < 0x80 { break } @@ -718,10 +718,10 @@ type Supplier struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` // The Bech32 address of the supplier using cosmos' ScalarDescriptor to ensure deterministic encoding - Stake *v1beta1.Coin `protobuf:"bytes,2,opt,name=stake,proto3" json:"stake,omitempty"` // The total amount of uPOKT the supplier has staked - Services []*SupplierServiceConfig `protobuf:"bytes,3,rep,name=services,proto3" json:"services,omitempty"` // The service configs this supplier can support - UnbondingHeight int64 `protobuf:"varint,4,opt,name=unbondingHeight,proto3" json:"unbondingHeight,omitempty"` // The height at which the supplier will be unbonded + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` // The Bech32 address of the supplier using cosmos' ScalarDescriptor to ensure deterministic encoding + Stake *v1beta1.Coin `protobuf:"bytes,2,opt,name=stake,proto3" json:"stake,omitempty"` // The total amount of uPOKT the supplier has staked + Services []*SupplierServiceConfig `protobuf:"bytes,3,rep,name=services,proto3" json:"services,omitempty"` // The service configs this supplier can support + UnstakeCommitSessionEndHeight int64 `protobuf:"varint,4,opt,name=unstake_commit_session_end_height,json=unstakeCommitSessionEndHeight,proto3" json:"unstake_commit_session_end_height,omitempty"` // The session end height corresponding the the unstake tx commit height } func (x *Supplier) Reset() { @@ -765,9 +765,9 @@ func (x *Supplier) GetServices() []*SupplierServiceConfig { return nil } -func (x *Supplier) GetUnbondingHeight() int64 { +func (x *Supplier) GetUnstakeCommitSessionEndHeight() int64 { if x != nil { - return x.UnbondingHeight + return x.UnstakeCommitSessionEndHeight } return 0 } @@ -783,7 +783,7 @@ var file_poktroll_shared_supplier_proto_rawDesc = []byte{ 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x62, 0x61, 0x73, 0x65, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x63, 0x6f, 0x69, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1d, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x2f, 0x73, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xdd, 0x01, 0x0a, 0x08, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xfd, 0x01, 0x0a, 0x08, 0x53, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x12, 0x32, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, 0xd2, 0xb4, 0x2d, 0x14, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, 0x74, 0x72, @@ -795,9 +795,11 @@ var file_poktroll_shared_supplier_proto_rawDesc = []byte{ 0x26, 0x2e, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x2e, 0x53, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x73, 0x12, 0x28, 0x0a, 0x0f, 0x75, 0x6e, 0x62, 0x6f, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x65, - 0x69, 0x67, 0x68, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x75, 0x6e, 0x62, 0x6f, - 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x42, 0xa3, 0x01, 0x0a, 0x13, + 0x73, 0x12, 0x48, 0x0a, 0x21, 0x75, 0x6e, 0x73, 0x74, 0x61, 0x6b, 0x65, 0x5f, 0x63, 0x6f, 0x6d, + 0x6d, 0x69, 0x74, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x6e, 0x64, 0x5f, + 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x1d, 0x75, 0x6e, + 0x73, 0x74, 0x61, 0x6b, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x45, 0x6e, 0x64, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x42, 0xa3, 0x01, 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x42, 0x0d, 0x53, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x20, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, diff --git a/api/poktroll/supplier/params.pulsar.go b/api/poktroll/supplier/params.pulsar.go index 7108db140..44ff49feb 100644 --- a/api/poktroll/supplier/params.pulsar.go +++ b/api/poktroll/supplier/params.pulsar.go @@ -15,12 +15,14 @@ import ( ) var ( - md_Params protoreflect.MessageDescriptor + md_Params protoreflect.MessageDescriptor + fd_Params_supplier_unbonding_period_blocks protoreflect.FieldDescriptor ) func init() { file_poktroll_supplier_params_proto_init() md_Params = File_poktroll_supplier_params_proto.Messages().ByName("Params") + fd_Params_supplier_unbonding_period_blocks = md_Params.Fields().ByName("supplier_unbonding_period_blocks") } var _ protoreflect.Message = (*fastReflection_Params)(nil) @@ -88,6 +90,12 @@ func (x *fastReflection_Params) Interface() protoreflect.ProtoMessage { // While iterating, mutating operations may only be performed // on the current field descriptor. func (x *fastReflection_Params) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.SupplierUnbondingPeriodBlocks != uint64(0) { + value := protoreflect.ValueOfUint64(x.SupplierUnbondingPeriodBlocks) + if !f(fd_Params_supplier_unbonding_period_blocks, value) { + return + } + } } // Has reports whether a field is populated. @@ -103,6 +111,8 @@ func (x *fastReflection_Params) Range(f func(protoreflect.FieldDescriptor, proto // a repeated field is populated if it is non-empty. func (x *fastReflection_Params) Has(fd protoreflect.FieldDescriptor) bool { switch fd.FullName() { + case "poktroll.supplier.Params.supplier_unbonding_period_blocks": + return x.SupplierUnbondingPeriodBlocks != uint64(0) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.supplier.Params")) @@ -119,6 +129,8 @@ func (x *fastReflection_Params) Has(fd protoreflect.FieldDescriptor) bool { // Clear is a mutating operation and unsafe for concurrent use. func (x *fastReflection_Params) Clear(fd protoreflect.FieldDescriptor) { switch fd.FullName() { + case "poktroll.supplier.Params.supplier_unbonding_period_blocks": + x.SupplierUnbondingPeriodBlocks = uint64(0) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.supplier.Params")) @@ -135,6 +147,9 @@ func (x *fastReflection_Params) Clear(fd protoreflect.FieldDescriptor) { // of the value; to obtain a mutable reference, use Mutable. func (x *fastReflection_Params) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { switch descriptor.FullName() { + case "poktroll.supplier.Params.supplier_unbonding_period_blocks": + value := x.SupplierUnbondingPeriodBlocks + return protoreflect.ValueOfUint64(value) default: if descriptor.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.supplier.Params")) @@ -155,6 +170,8 @@ func (x *fastReflection_Params) Get(descriptor protoreflect.FieldDescriptor) pro // Set is a mutating operation and unsafe for concurrent use. func (x *fastReflection_Params) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { switch fd.FullName() { + case "poktroll.supplier.Params.supplier_unbonding_period_blocks": + x.SupplierUnbondingPeriodBlocks = value.Uint() default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.supplier.Params")) @@ -175,6 +192,8 @@ func (x *fastReflection_Params) Set(fd protoreflect.FieldDescriptor, value proto // Mutable is a mutating operation and unsafe for concurrent use. func (x *fastReflection_Params) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { switch fd.FullName() { + case "poktroll.supplier.Params.supplier_unbonding_period_blocks": + panic(fmt.Errorf("field supplier_unbonding_period_blocks of message poktroll.supplier.Params is not mutable")) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.supplier.Params")) @@ -188,6 +207,8 @@ func (x *fastReflection_Params) Mutable(fd protoreflect.FieldDescriptor) protore // For lists, maps, and messages, this returns a new, empty, mutable value. func (x *fastReflection_Params) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { switch fd.FullName() { + case "poktroll.supplier.Params.supplier_unbonding_period_blocks": + return protoreflect.ValueOfUint64(uint64(0)) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.supplier.Params")) @@ -257,6 +278,9 @@ func (x *fastReflection_Params) ProtoMethods() *protoiface.Methods { var n int var l int _ = l + if x.SupplierUnbondingPeriodBlocks != 0 { + n += 1 + runtime.Sov(uint64(x.SupplierUnbondingPeriodBlocks)) + } if x.unknownFields != nil { n += len(x.unknownFields) } @@ -286,6 +310,11 @@ func (x *fastReflection_Params) ProtoMethods() *protoiface.Methods { i -= len(x.unknownFields) copy(dAtA[i:], x.unknownFields) } + if x.SupplierUnbondingPeriodBlocks != 0 { + i = runtime.EncodeVarint(dAtA, i, uint64(x.SupplierUnbondingPeriodBlocks)) + i-- + dAtA[i] = 0x38 + } if input.Buf != nil { input.Buf = append(input.Buf, dAtA...) } else { @@ -335,6 +364,25 @@ func (x *fastReflection_Params) ProtoMethods() *protoiface.Methods { return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { + case 7: + if wireType != 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field SupplierUnbondingPeriodBlocks", wireType) + } + x.SupplierUnbondingPeriodBlocks = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + x.SupplierUnbondingPeriodBlocks |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := runtime.Skip(dAtA[iNdEx:]) @@ -388,6 +436,10 @@ type Params struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + + // supplier_unbonding_period_blocks is the number of blocks that a supplier must wait + // after unstaking before they can withdraw their staked tokens. + SupplierUnbondingPeriodBlocks uint64 `protobuf:"varint,7,opt,name=supplier_unbonding_period_blocks,json=supplierUnbondingPeriodBlocks,proto3" json:"supplier_unbonding_period_blocks,omitempty"` } func (x *Params) Reset() { @@ -410,6 +462,13 @@ func (*Params) Descriptor() ([]byte, []int) { return file_poktroll_supplier_params_proto_rawDescGZIP(), []int{0} } +func (x *Params) GetSupplierUnbondingPeriodBlocks() uint64 { + if x != nil { + return x.SupplierUnbondingPeriodBlocks + } + return 0 +} + var File_poktroll_supplier_params_proto protoreflect.FileDescriptor var file_poktroll_supplier_params_proto_rawDesc = []byte{ @@ -418,8 +477,15 @@ var file_poktroll_supplier_params_proto_rawDesc = []byte{ 0x12, 0x11, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x73, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x1a, 0x11, 0x61, 0x6d, 0x69, 0x6e, 0x6f, 0x2f, 0x61, 0x6d, 0x69, 0x6e, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x14, 0x67, 0x6f, 0x67, 0x6f, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2f, 0x67, 0x6f, 0x67, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x2d, 0x0a, 0x06, - 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x3a, 0x23, 0xe8, 0xa0, 0x1f, 0x01, 0x8a, 0xe7, 0xb0, 0x2a, + 0x6f, 0x2f, 0x67, 0x6f, 0x67, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x9c, 0x01, 0x0a, + 0x06, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x6d, 0x0a, 0x20, 0x73, 0x75, 0x70, 0x70, 0x6c, + 0x69, 0x65, 0x72, 0x5f, 0x75, 0x6e, 0x62, 0x6f, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x70, 0x65, + 0x72, 0x69, 0x6f, 0x64, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x04, 0x42, 0x24, 0xea, 0xde, 0x1f, 0x20, 0x73, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x5f, + 0x75, 0x6e, 0x62, 0x6f, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, + 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x1d, 0x73, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, + 0x72, 0x55, 0x6e, 0x62, 0x6f, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x3a, 0x23, 0xe8, 0xa0, 0x1f, 0x01, 0x8a, 0xe7, 0xb0, 0x2a, 0x1a, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2f, 0x78, 0x2f, 0x73, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x2f, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x42, 0xad, 0x01, 0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x73, 0x75, 0x70, diff --git a/e2e/tests/init_test.go b/e2e/tests/init_test.go index 16f1cd913..f8245b5dd 100644 --- a/e2e/tests/init_test.go +++ b/e2e/tests/init_test.go @@ -449,15 +449,19 @@ func (s *suite) TheSupplierForAccountIsUnbonding(accName string) { s.waitForTxResultEvent(newEventMsgTypeMatchFn("supplier", "UnstakeSupplier")) supplier := s.getSupplierInfo(accName) - require.Greater(s, supplier.UnbondingHeight, int64(0), "supplier %s is not unbonding", accName) + require.Greater(s, + supplier.UnstakeCommitSessionEndHeight, + int64(0), + "supplier %s is not unbonding", accName, + ) } func (s *suite) TheUserWaitsForUnbondingPeriodToPass(accName string) { _, ok := accNameToSupplierMap[accName] require.True(s, ok, "supplier %s not found", accName) - supplier := s.getSupplierInfo(accName) - s.waitForBlockHeight(supplier.UnbondingHeight) + unbondingHeight := s.getSupplierUnbondingHeight(accName) + s.waitForBlockHeight(unbondingHeight) } func (s *suite) getStakedAmount(actorType, accName string) (int, bool) { @@ -604,6 +608,26 @@ func (s *suite) getSupplierInfo(supplierAddr string) *sharedtypes.Supplier { return &resp.Supplier } +// getSupplierUnbondingHeight returns the height at which the supplier will be unbonded. +func (s *suite) getSupplierUnbondingHeight(accName string) int64 { + supplier := s.getSupplierInfo(accName) + + args := []string{ + "query", + "supplier", + "params", + "--output=json", + } + + res, err := s.pocketd.RunCommandOnHostWithRetry("", numQueryRetries, args...) + require.NoError(s, err, "error getting supplier module params") + + var resp suppliertypes.QueryParamsResponse + responseBz := []byte(strings.TrimSpace(res.Stdout)) + s.cdc.MustUnmarshalJSON(responseBz, &resp) + return supplier.UnstakeCommitSessionEndHeight + int64(resp.Params.SupplierUnbondingPeriodBlocks) +} + // TODO_IMPROVE: use `sessionId` and `supplierName` since those are the two values // used to create the primary composite key on-chain to uniquely distinguish relays. func relayReferenceKey(appName, supplierName string) string { diff --git a/proto/poktroll/shared/supplier.proto b/proto/poktroll/shared/supplier.proto index df04d7e9c..3aec13e54 100644 --- a/proto/poktroll/shared/supplier.proto +++ b/proto/poktroll/shared/supplier.proto @@ -13,6 +13,6 @@ message Supplier { string address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; // The Bech32 address of the supplier using cosmos' ScalarDescriptor to ensure deterministic encoding cosmos.base.v1beta1.Coin stake = 2; // The total amount of uPOKT the supplier has staked repeated SupplierServiceConfig services = 3; // The service configs this supplier can support - int64 unbondingHeight = 4; // The height at which the supplier will be unbonded + int64 unstake_commit_session_end_height = 4; // The session end height corresponding the the unstake tx commit height } diff --git a/proto/poktroll/supplier/params.proto b/proto/poktroll/supplier/params.proto index a27a7ba7c..705778509 100644 --- a/proto/poktroll/supplier/params.proto +++ b/proto/poktroll/supplier/params.proto @@ -10,4 +10,8 @@ import "gogoproto/gogo.proto"; message Params { option (amino.name) = "poktroll/x/supplier/Params"; option (gogoproto.equal) = true; + + // supplier_unbonding_period_blocks is the number of blocks that a supplier must wait + // after unstaking before they can withdraw their staked tokens. + uint64 supplier_unbonding_period_blocks = 7 [(gogoproto.jsontag) = "supplier_unbonding_period_blocks"]; } \ No newline at end of file diff --git a/testutil/keeper/supplier.go b/testutil/keeper/supplier.go index 865439e86..8009508ce 100644 --- a/testutil/keeper/supplier.go +++ b/testutil/keeper/supplier.go @@ -69,7 +69,11 @@ func SupplierKeeper(t testing.TB) (keeper.Keeper, context.Context) { // Initialize params require.NoError(t, k.SetParams(ctx, types.DefaultParams())) - return k, ctx + // Move block height to 1 to get a non zero session end height + sdkCtx := sdk.UnwrapSDKContext(ctx) + sdkCtx = sdkCtx.WithBlockHeight(sdkCtx.BlockHeight() + 1) + + return k, sdkCtx } // TODO_OPTIMIZE: Index suppliers by service so we can easily query k.GetAllSuppliers(ctx, Service) diff --git a/x/session/keeper/session_hydrator.go b/x/session/keeper/session_hydrator.go index 9d07626f5..b5d1b032d 100644 --- a/x/session/keeper/session_hydrator.go +++ b/x/session/keeper/session_hydrator.go @@ -172,6 +172,12 @@ func (k Keeper) hydrateSessionSuppliers(ctx context.Context, sh *sessionHydrator candidateSuppliers := make([]*sharedtypes.Supplier, 0) for _, s := range suppliers { + // Exclude suppliers that are in an unbonding period. + if s.UnstakeCommitSessionEndHeight != 0 && + sh.sessionHeader.SessionEndBlockHeight > s.UnstakeCommitSessionEndHeight { + continue + } + // NB: Allocate a new heap variable as s is a value and we're appending // to a slice of pointers; otherwise, we'd be appending new pointers to // the same memory address containing the last supplier in the loop. diff --git a/x/shared/types/supplier.pb.go b/x/shared/types/supplier.pb.go index f34a35fdb..448836744 100644 --- a/x/shared/types/supplier.pb.go +++ b/x/shared/types/supplier.pb.go @@ -26,10 +26,10 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // Supplier is the type defining the actor in Pocket Network that provides RPC services. type Supplier struct { - Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` - Stake *types.Coin `protobuf:"bytes,2,opt,name=stake,proto3" json:"stake,omitempty"` - Services []*SupplierServiceConfig `protobuf:"bytes,3,rep,name=services,proto3" json:"services,omitempty"` - UnbondingHeight int64 `protobuf:"varint,4,opt,name=unbondingHeight,proto3" json:"unbondingHeight,omitempty"` + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + Stake *types.Coin `protobuf:"bytes,2,opt,name=stake,proto3" json:"stake,omitempty"` + Services []*SupplierServiceConfig `protobuf:"bytes,3,rep,name=services,proto3" json:"services,omitempty"` + UnstakeCommitSessionEndHeight int64 `protobuf:"varint,4,opt,name=unstake_commit_session_end_height,json=unstakeCommitSessionEndHeight,proto3" json:"unstake_commit_session_end_height,omitempty"` } func (m *Supplier) Reset() { *m = Supplier{} } @@ -86,9 +86,9 @@ func (m *Supplier) GetServices() []*SupplierServiceConfig { return nil } -func (m *Supplier) GetUnbondingHeight() int64 { +func (m *Supplier) GetUnstakeCommitSessionEndHeight() int64 { if m != nil { - return m.UnbondingHeight + return m.UnstakeCommitSessionEndHeight } return 0 } @@ -100,27 +100,28 @@ func init() { func init() { proto.RegisterFile("poktroll/shared/supplier.proto", fileDescriptor_4a189b52ba503cf2) } var fileDescriptor_4a189b52ba503cf2 = []byte{ - // 312 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x90, 0xbd, 0x4e, 0xf3, 0x30, - 0x18, 0x85, 0xeb, 0xaf, 0x1f, 0x50, 0xdc, 0xa1, 0x52, 0xc4, 0x90, 0x56, 0xc2, 0x8a, 0x18, 0x50, - 0x96, 0xda, 0x6a, 0xb9, 0x02, 0xda, 0x05, 0xd6, 0x74, 0x63, 0x41, 0xf9, 0x31, 0xa9, 0xd5, 0xd4, - 0x6f, 0x64, 0x3b, 0x05, 0xee, 0x82, 0x8b, 0xe1, 0x22, 0x18, 0x2b, 0x26, 0x16, 0x24, 0x94, 0xdc, - 0x08, 0x6a, 0xed, 0x74, 0x28, 0xe3, 0x9b, 0xe7, 0x89, 0xce, 0xf1, 0xc1, 0xa4, 0x84, 0x95, 0x51, - 0x50, 0x14, 0x4c, 0x2f, 0x63, 0xc5, 0x33, 0xa6, 0xab, 0xb2, 0x2c, 0x04, 0x57, 0xb4, 0x54, 0x60, - 0xc0, 0x1b, 0xb4, 0x9c, 0x5a, 0x3e, 0x1a, 0xa6, 0xa0, 0xd7, 0xa0, 0x1f, 0xf7, 0x98, 0xd9, 0xc3, - 0xba, 0x23, 0x62, 0x2f, 0x96, 0xc4, 0x9a, 0xb3, 0xcd, 0x24, 0xe1, 0x26, 0x9e, 0xb0, 0x14, 0x84, - 0x74, 0xfc, 0xf2, 0x4f, 0x16, 0x57, 0x1b, 0x91, 0x72, 0x8b, 0xaf, 0xbe, 0x11, 0xee, 0x2d, 0x5c, - 0xba, 0x37, 0xc5, 0x67, 0x71, 0x96, 0x29, 0xae, 0xb5, 0x8f, 0x02, 0x14, 0x9e, 0xcf, 0xfc, 0xcf, - 0xf7, 0xf1, 0x85, 0x8b, 0xbb, 0xb5, 0x64, 0x61, 0x94, 0x90, 0x79, 0xd4, 0x8a, 0x1e, 0xc3, 0x27, - 0xda, 0xc4, 0x2b, 0xee, 0xff, 0x0b, 0x50, 0xd8, 0x9f, 0x0e, 0xa9, 0xd3, 0x77, 0x7d, 0xa8, 0xeb, - 0x43, 0xe7, 0x20, 0x64, 0x64, 0x3d, 0x6f, 0x86, 0x7b, 0xae, 0x82, 0xf6, 0xbb, 0x41, 0x37, 0xec, - 0x4f, 0xaf, 0xe9, 0xd1, 0x7b, 0x69, 0xdb, 0x68, 0x61, 0xc5, 0x39, 0xc8, 0x27, 0x91, 0x47, 0x87, - 0xff, 0xbc, 0x10, 0x0f, 0x2a, 0x99, 0x80, 0xcc, 0x84, 0xcc, 0xef, 0xb8, 0xc8, 0x97, 0xc6, 0xff, - 0x1f, 0xa0, 0xb0, 0x1b, 0x1d, 0x7f, 0x9e, 0xdd, 0x7f, 0xd4, 0x04, 0x6d, 0x6b, 0x82, 0x7e, 0x6a, - 0x82, 0xde, 0x1a, 0xd2, 0xd9, 0x36, 0xa4, 0xf3, 0xd5, 0x90, 0xce, 0x03, 0xcb, 0x85, 0x59, 0x56, - 0x09, 0x4d, 0x61, 0xcd, 0x76, 0xf9, 0x63, 0xc9, 0xcd, 0x33, 0xa8, 0x15, 0x3b, 0x0c, 0xf6, 0xd2, - 0x4e, 0x66, 0x5e, 0x4b, 0xae, 0x93, 0xd3, 0xfd, 0x62, 0x37, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, - 0x0a, 0xaf, 0xb1, 0x4b, 0xbe, 0x01, 0x00, 0x00, + // 335 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x90, 0xbf, 0x4e, 0xeb, 0x30, + 0x18, 0xc5, 0xeb, 0xdb, 0x7b, 0x2f, 0x25, 0x1d, 0x90, 0x22, 0x86, 0xb4, 0x52, 0xad, 0xc0, 0x80, + 0xb2, 0xd4, 0x56, 0xcb, 0x13, 0xd0, 0x0a, 0xa9, 0xac, 0xc9, 0xc6, 0x12, 0xe5, 0x8f, 0x49, 0xac, + 0x36, 0x76, 0xe4, 0xcf, 0x2d, 0xf0, 0x16, 0x3c, 0x0c, 0x0f, 0xc1, 0x58, 0x31, 0x31, 0xa2, 0xf6, + 0x39, 0x90, 0x50, 0x63, 0xa7, 0x03, 0x8c, 0x9f, 0x7e, 0xbf, 0xe4, 0x1c, 0x1f, 0x07, 0xd7, 0x72, + 0xa9, 0x95, 0x5c, 0xad, 0x28, 0x94, 0x89, 0x62, 0x39, 0x85, 0x75, 0x5d, 0xaf, 0x38, 0x53, 0xa4, + 0x56, 0x52, 0x4b, 0xf7, 0xac, 0xe5, 0xc4, 0xf0, 0xe1, 0x20, 0x93, 0x50, 0x49, 0x88, 0x1b, 0x4c, + 0xcd, 0x61, 0xdc, 0x21, 0x36, 0x17, 0x4d, 0x13, 0x60, 0x74, 0x33, 0x49, 0x99, 0x4e, 0x26, 0x34, + 0x93, 0x5c, 0x58, 0x3e, 0xfa, 0x95, 0xc5, 0xd4, 0x86, 0x67, 0xcc, 0xe0, 0xcb, 0x2f, 0xe4, 0xf4, + 0x22, 0x9b, 0xee, 0x4e, 0x9d, 0x93, 0x24, 0xcf, 0x15, 0x03, 0xf0, 0x90, 0x8f, 0x82, 0xd3, 0x99, + 0xf7, 0xfe, 0x3a, 0x3e, 0xb7, 0x71, 0x37, 0x86, 0x44, 0x5a, 0x71, 0x51, 0x84, 0xad, 0xe8, 0x52, + 0xe7, 0x1f, 0xe8, 0x64, 0xc9, 0xbc, 0x3f, 0x3e, 0x0a, 0xfa, 0xd3, 0x01, 0xb1, 0xfa, 0xa1, 0x0f, + 0xb1, 0x7d, 0xc8, 0x5c, 0x72, 0x11, 0x1a, 0xcf, 0x9d, 0x39, 0x3d, 0x5b, 0x01, 0xbc, 0xae, 0xdf, + 0x0d, 0xfa, 0xd3, 0x2b, 0xf2, 0xe3, 0xbd, 0xa4, 0x6d, 0x14, 0x19, 0x71, 0x2e, 0xc5, 0x03, 0x2f, + 0xc2, 0xe3, 0x77, 0xee, 0xc2, 0xb9, 0x58, 0x8b, 0xe6, 0x77, 0x71, 0x26, 0xab, 0x8a, 0xeb, 0x18, + 0x18, 0x00, 0x97, 0x22, 0x66, 0x22, 0x8f, 0x4b, 0xc6, 0x8b, 0x52, 0x7b, 0x7f, 0x7d, 0x14, 0x74, + 0xc3, 0x91, 0x15, 0xe7, 0x8d, 0x17, 0x19, 0xed, 0x56, 0xe4, 0x8b, 0x46, 0x9a, 0xdd, 0xbd, 0xed, + 0x30, 0xda, 0xee, 0x30, 0xfa, 0xdc, 0x61, 0xf4, 0xb2, 0xc7, 0x9d, 0xed, 0x1e, 0x77, 0x3e, 0xf6, + 0xb8, 0x73, 0x4f, 0x0b, 0xae, 0xcb, 0x75, 0x4a, 0x32, 0x59, 0xd1, 0x43, 0xbf, 0xb1, 0x60, 0xfa, + 0x51, 0xaa, 0x25, 0x3d, 0x0e, 0xfa, 0xd4, 0x4e, 0xaa, 0x9f, 0x6b, 0x06, 0xe9, 0xff, 0x66, 0xd1, + 0xeb, 0xef, 0x00, 0x00, 0x00, 0xff, 0xff, 0x35, 0x3c, 0xfd, 0xfe, 0xde, 0x01, 0x00, 0x00, } func (m *Supplier) Marshal() (dAtA []byte, err error) { @@ -143,8 +144,8 @@ func (m *Supplier) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.UnbondingHeight != 0 { - i = encodeVarintSupplier(dAtA, i, uint64(m.UnbondingHeight)) + if m.UnstakeCommitSessionEndHeight != 0 { + i = encodeVarintSupplier(dAtA, i, uint64(m.UnstakeCommitSessionEndHeight)) i-- dAtA[i] = 0x20 } @@ -215,8 +216,8 @@ func (m *Supplier) Size() (n int) { n += 1 + l + sovSupplier(uint64(l)) } } - if m.UnbondingHeight != 0 { - n += 1 + sovSupplier(uint64(m.UnbondingHeight)) + if m.UnstakeCommitSessionEndHeight != 0 { + n += 1 + sovSupplier(uint64(m.UnstakeCommitSessionEndHeight)) } return n } @@ -360,9 +361,9 @@ func (m *Supplier) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 4: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field UnbondingHeight", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field UnstakeCommitSessionEndHeight", wireType) } - m.UnbondingHeight = 0 + m.UnstakeCommitSessionEndHeight = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowSupplier @@ -372,7 +373,7 @@ func (m *Supplier) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.UnbondingHeight |= int64(b&0x7F) << shift + m.UnstakeCommitSessionEndHeight |= int64(b&0x7F) << shift if b < 0x80 { break } diff --git a/x/supplier/keeper/msg_server_stake_supplier.go b/x/supplier/keeper/msg_server_stake_supplier.go index 8d704853b..c4c12abbf 100644 --- a/x/supplier/keeper/msg_server_stake_supplier.go +++ b/x/supplier/keeper/msg_server_stake_supplier.go @@ -49,8 +49,8 @@ func (k msgServer) StakeSupplier(ctx context.Context, msg *types.MsgStakeSupplie } logger.Info(fmt.Sprintf("Supplier is going to escrow an additional %+v coins", coinsToEscrow)) - // If the supplier has initiated the unstake action, reset the unbonding height - supplier.UnbondingHeight = 0 + // If the supplier has initiated an unstake action, cancel it since they are staking again. + supplier.UnstakeCommitSessionEndHeight = 0 } // Must always stake or upstake (> 0 delta) diff --git a/x/supplier/keeper/msg_server_unstake_supplier.go b/x/supplier/keeper/msg_server_unstake_supplier.go index aa277ef2e..a6eea4584 100644 --- a/x/supplier/keeper/msg_server_unstake_supplier.go +++ b/x/supplier/keeper/msg_server_unstake_supplier.go @@ -8,7 +8,6 @@ import ( "github.com/pokt-network/poktroll/telemetry" "github.com/pokt-network/poktroll/x/shared" - sharedtypes "github.com/pokt-network/poktroll/x/shared/types" "github.com/pokt-network/poktroll/x/supplier/types" ) @@ -39,9 +38,9 @@ func (k msgServer) UnstakeSupplier( } logger.Info(fmt.Sprintf("Supplier found. Unstaking supplier for address %s", msg.Address)) - // Check if the supplier has already initiated the unstake action and is in the unbonding period - if supplier.UnbondingHeight > 0 { - logger.Warn(fmt.Sprintf("Supplier %s has not finished the unbonding period", msg.Address)) + // Check if the supplier has already initiated the unstake action. + if supplier.UnstakeCommitSessionEndHeight > 0 { + logger.Warn(fmt.Sprintf("Supplier %s still unbonding from previous unstaking", msg.Address)) return nil, types.ErrSupplierUnbonding } @@ -49,26 +48,16 @@ func (k msgServer) UnstakeSupplier( currentHeight := sdkCtx.BlockHeight() sharedParams := k.sharedKeeper.GetParams(ctx) - supplier.UnbondingHeight = GetSupplierUnbondingHeight(&sharedParams, currentHeight) + // Mark the supplier as unstaking by recording the height at which it should stop + // providing service. + // The supplier MUST continue to provide service until the end of the current + // session, which which should not change its suppliers list mid-session. + // Removing it right away could have undesired effects on the network + // (e.g. a session with less than the minimum or 0 number of suppliers, + // off-chain actors that need to listen to session supplier's change mid-session, etc). + supplier.UnstakeCommitSessionEndHeight = shared.GetSessionEndHeight(&sharedParams, currentHeight) k.SetSupplier(ctx, supplier) isSuccessful = true return &types.MsgUnstakeSupplierResponse{}, nil } - -// GetSupplierUnbondingHeight returns the height at which the supplier will be able to withdraw -// the staked coins after the unbonding period. -func GetSupplierUnbondingHeight(sharedParams *sharedtypes.Params, currentHeight int64) int64 { - sessionEndHeight := shared.GetSessionEndHeight(sharedParams, currentHeight) - - // TODO_IN_THIS_PR: Make the unbonding period a governance parameter. - unbondingPeriodInBlocks := int64(sharedParams.GetNumBlocksPerSession()) - - // Unbonding period has a minimum duration of 1 session, which means that if - // the current height is prior to the end of the session, the unbonding height - // will be set to the end of the session that is after the current session. - // This is to avoid the case where a supplier is able to withdraw after 1 block, - // if it unstakes right before the end of the current session. - return sessionEndHeight + unbondingPeriodInBlocks - -} diff --git a/x/supplier/keeper/msg_server_unstake_supplier_test.go b/x/supplier/keeper/msg_server_unstake_supplier_test.go index 24e26e2d6..cca4f8fec 100644 --- a/x/supplier/keeper/msg_server_unstake_supplier_test.go +++ b/x/supplier/keeper/msg_server_unstake_supplier_test.go @@ -47,10 +47,12 @@ func TestMsgServer_UnstakeSupplier_Success(t *testing.T) { // Make sure the supplier entered the unbonding period foundSupplier, isSupplierFound = k.GetSupplier(ctx, supplierAddr) require.True(t, isSupplierFound) - require.Greater(t, foundSupplier.UnbondingHeight, int64(0)) + require.Greater(t, foundSupplier.UnstakeCommitSessionEndHeight, int64(0)) + // Move block height to the end of the unbonding period + unbondingHeight := foundSupplier.UnstakeCommitSessionEndHeight + int64(k.GetParams(ctx).SupplierUnbondingPeriodBlocks) sdkCtx := sdk.UnwrapSDKContext(ctx) - sdkCtx = sdkCtx.WithBlockHeight(foundSupplier.UnbondingHeight) + sdkCtx = sdkCtx.WithBlockHeight(unbondingHeight) // Run the endblocker to unbond the supplier err = k.EndBlockerUnbondSupplier(sdkCtx) @@ -78,7 +80,7 @@ func TestMsgServer_UnstakeSupplier_CancelUnbondingIfRestaked(t *testing.T) { // Verify that the supplier exists with no unbonding height foundSupplier, isSupplierFound := k.GetSupplier(ctx, supplierAddr) require.True(t, isSupplierFound) - require.Equal(t, int64(0), foundSupplier.UnbondingHeight) + require.Equal(t, int64(0), foundSupplier.UnstakeCommitSessionEndHeight) // Initiate the supplier unstaking unstakeMsg := &types.MsgUnstakeSupplier{Address: supplierAddr} @@ -88,8 +90,9 @@ func TestMsgServer_UnstakeSupplier_CancelUnbondingIfRestaked(t *testing.T) { // Make sure the supplier entered the unbonding period foundSupplier, isSupplierFound = k.GetSupplier(ctx, supplierAddr) require.True(t, isSupplierFound) - require.Greater(t, foundSupplier.UnbondingHeight, int64(0)) - unbondingHeight := foundSupplier.UnbondingHeight + require.Greater(t, foundSupplier.UnstakeCommitSessionEndHeight, int64(0)) + + unbondingHeight := foundSupplier.UnstakeCommitSessionEndHeight + int64(k.GetParams(ctx).SupplierUnbondingPeriodBlocks) // Stake the supplier again stakeMsg = createStakeMsg(supplierAddr, initialStake+1) @@ -99,7 +102,7 @@ func TestMsgServer_UnstakeSupplier_CancelUnbondingIfRestaked(t *testing.T) { // Make sure the supplier is no longer in the unbonding period foundSupplier, isSupplierFound = k.GetSupplier(ctx, supplierAddr) require.True(t, isSupplierFound) - require.Equal(t, foundSupplier.UnbondingHeight, int64(0)) + require.Equal(t, foundSupplier.UnstakeCommitSessionEndHeight, int64(0)) sdkCtx := sdk.UnwrapSDKContext(ctx) sdkCtx = sdkCtx.WithBlockHeight(unbondingHeight) @@ -111,7 +114,7 @@ func TestMsgServer_UnstakeSupplier_CancelUnbondingIfRestaked(t *testing.T) { // Make sure the supplier is still in the suppliers list with an unbonding height of 0 foundSupplier, isSupplierFound = k.GetSupplier(sdkCtx, supplierAddr) require.True(t, isSupplierFound) - require.Equal(t, foundSupplier.UnbondingHeight, int64(0)) + require.Equal(t, foundSupplier.UnstakeCommitSessionEndHeight, int64(0)) } func TestMsgServer_UnstakeSupplier_FailIfNotStaked(t *testing.T) { @@ -180,5 +183,4 @@ func createStakeMsg(supplierAddr string, stakeAmount int64) *types.MsgStakeSuppl }, }, } - } diff --git a/x/supplier/keeper/msg_update_params_test.go b/x/supplier/keeper/msg_update_params_test.go index 9efd6db7d..f8984d7f8 100644 --- a/x/supplier/keeper/msg_update_params_test.go +++ b/x/supplier/keeper/msg_update_params_test.go @@ -30,12 +30,22 @@ func TestMsgUpdateParams(t *testing.T) { expectedErrMsg: "invalid authority", }, { - desc: "send empty params", + desc: "invalid: send empty params", params: &types.MsgUpdateParams{ Authority: k.GetAuthority(), Params: types.Params{}, }, - shouldError: false, + shouldError: true, + }, + { + desc: "invalid: Zero SupplierUnbondingPeriodBlocks", + params: &types.MsgUpdateParams{ + Authority: k.GetAuthority(), + Params: types.Params{ + SupplierUnbondingPeriodBlocks: 0, + }, + }, + shouldError: true, }, { desc: "valid: send default params", diff --git a/x/supplier/keeper/unbond_suppliers.go b/x/supplier/keeper/unbond_suppliers.go index ded0139bd..2477ac2a4 100644 --- a/x/supplier/keeper/unbond_suppliers.go +++ b/x/supplier/keeper/unbond_suppliers.go @@ -26,11 +26,14 @@ func (k Keeper) EndBlockerUnbondSupplier(ctx sdk.Context) error { // unbonding action instead of iterating over all suppliers. for _, supplier := range k.GetAllSuppliers(ctx) { // Ignore suppliers that have not initiated the unbonding action. - if supplier.UnbondingHeight == 0 { + if supplier.UnstakeCommitSessionEndHeight == 0 { continue } - if supplier.UnbondingHeight <= currentHeight { + unbondingPeriodBlocks := int64(k.GetParams(ctx).SupplierUnbondingPeriodBlocks) + unbondingHeight := supplier.UnstakeCommitSessionEndHeight + unbondingPeriodBlocks + + if unbondingHeight <= currentHeight { // Retrieve the address of the supplier supplierAddress, err := sdk.AccAddressFromBech32(supplier.Address) diff --git a/x/supplier/types/errors.go b/x/supplier/types/errors.go index 286c16435..03877b5c2 100644 --- a/x/supplier/types/errors.go +++ b/x/supplier/types/errors.go @@ -17,4 +17,5 @@ var ( ErrSupplierInvalidService = sdkerrors.Register(ModuleName, 1108, "invalid service in supplier") ErrSupplierInvalidSessionEndHeight = sdkerrors.Register(ModuleName, 1109, "invalid session ending height") ErrSupplierUnbonding = sdkerrors.Register(ModuleName, 1110, "supplier is in unbonding period") + ErrSupplierParamsInvalid = sdkerrors.Register(ModuleName, 1111, "invalid supplier params") ) diff --git a/x/supplier/types/genesis_test.go b/x/supplier/types/genesis_test.go index 23b16b327..a6c1b1e7c 100644 --- a/x/supplier/types/genesis_test.go +++ b/x/supplier/types/genesis_test.go @@ -13,6 +13,7 @@ import ( ) func TestGenesisState_Validate(t *testing.T) { + defaultParams := types.DefaultParams() addr1 := sample.AccAddress() stake1 := sdk.NewCoin("upokt", math.NewInt(100)) serviceConfig1 := &sharedtypes.SupplierServiceConfig{ @@ -58,7 +59,7 @@ func TestGenesisState_Validate(t *testing.T) { { desc: "valid genesis state", genState: &types.GenesisState{ - + Params: defaultParams, SupplierList: []sharedtypes.Supplier{ { Address: addr1, @@ -78,6 +79,7 @@ func TestGenesisState_Validate(t *testing.T) { { desc: "invalid - zero supplier stake", genState: &types.GenesisState{ + Params: defaultParams, SupplierList: []sharedtypes.Supplier{ { Address: addr1, @@ -96,6 +98,7 @@ func TestGenesisState_Validate(t *testing.T) { { desc: "invalid - negative supplier stake", genState: &types.GenesisState{ + Params: defaultParams, SupplierList: []sharedtypes.Supplier{ { Address: addr1, @@ -114,6 +117,7 @@ func TestGenesisState_Validate(t *testing.T) { { desc: "invalid - wrong stake denom", genState: &types.GenesisState{ + Params: defaultParams, SupplierList: []sharedtypes.Supplier{ { Address: addr1, @@ -132,6 +136,7 @@ func TestGenesisState_Validate(t *testing.T) { { desc: "invalid - missing denom", genState: &types.GenesisState{ + Params: defaultParams, SupplierList: []sharedtypes.Supplier{ { Address: addr1, @@ -150,6 +155,7 @@ func TestGenesisState_Validate(t *testing.T) { { desc: "invalid - due to duplicated supplier address", genState: &types.GenesisState{ + Params: defaultParams, SupplierList: []sharedtypes.Supplier{ { Address: addr1, @@ -168,6 +174,7 @@ func TestGenesisState_Validate(t *testing.T) { { desc: "invalid - due to nil supplier stake", genState: &types.GenesisState{ + Params: defaultParams, SupplierList: []sharedtypes.Supplier{ { Address: addr1, @@ -186,6 +193,7 @@ func TestGenesisState_Validate(t *testing.T) { { desc: "invalid - due to missing supplier stake", genState: &types.GenesisState{ + Params: defaultParams, SupplierList: []sharedtypes.Supplier{ { Address: addr1, @@ -204,6 +212,7 @@ func TestGenesisState_Validate(t *testing.T) { { desc: "invalid - missing services list", genState: &types.GenesisState{ + Params: defaultParams, SupplierList: []sharedtypes.Supplier{ { Address: addr1, @@ -222,6 +231,7 @@ func TestGenesisState_Validate(t *testing.T) { { desc: "invalid - empty services list", genState: &types.GenesisState{ + Params: defaultParams, SupplierList: []sharedtypes.Supplier{ { Address: addr1, @@ -240,6 +250,7 @@ func TestGenesisState_Validate(t *testing.T) { { desc: "invalid - invalid URL", genState: &types.GenesisState{ + Params: defaultParams, SupplierList: []sharedtypes.Supplier{ { Address: addr1, @@ -271,6 +282,7 @@ func TestGenesisState_Validate(t *testing.T) { { desc: "invalid - invalid RPC Type", genState: &types.GenesisState{ + Params: defaultParams, SupplierList: []sharedtypes.Supplier{ { Address: addr1, @@ -299,6 +311,45 @@ func TestGenesisState_Validate(t *testing.T) { }, isValid: false, }, + { + desc: "invalid - missing params", + genState: &types.GenesisState{ + SupplierList: []sharedtypes.Supplier{ + { + Address: addr1, + Stake: &stake1, + Services: serviceList1, + }, + { + Address: addr2, + Stake: &stake2, + Services: serviceList2, + }, + }, + }, + isValid: false, + }, + { + desc: "invalid - zero supplier unbonding period blocks", + genState: &types.GenesisState{ + Params: types.Params{ + SupplierUnbondingPeriodBlocks: 0, + }, + SupplierList: []sharedtypes.Supplier{ + { + Address: addr1, + Stake: &stake1, + Services: serviceList1, + }, + { + Address: addr2, + Stake: &stake2, + Services: serviceList2, + }, + }, + }, + isValid: false, + }, // this line is used by starport scaffolding # types/genesis/testcase } for _, test := range tests { diff --git a/x/supplier/types/params.go b/x/supplier/types/params.go index 95b0cf8a2..f4f6e7c2e 100644 --- a/x/supplier/types/params.go +++ b/x/supplier/types/params.go @@ -1,8 +1,16 @@ package types -import paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" +import ( + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" +) -var _ paramtypes.ParamSet = (*Params)(nil) +var ( + _ paramtypes.ParamSet = (*Params)(nil) + + KeySupplierUnbondingPeriodBlocks = []byte("SupplierUnbondingPeriodBlocks") + ParamSupplierUnbondingPeriodBlocks = "supplier_unbonding_period_blocks" + DefaultSupplierUnbondingPeriodBlocks uint64 = 4 // TODO_MAINNET: Determine the default value. +) // ParamKeyTable the param key table for launch module func ParamKeyTable() paramtypes.KeyTable { @@ -11,7 +19,9 @@ func ParamKeyTable() paramtypes.KeyTable { // NewParams creates a new Params instance func NewParams() Params { - return Params{} + return Params{ + SupplierUnbondingPeriodBlocks: DefaultSupplierUnbondingPeriodBlocks, + } } // DefaultParams returns a default set of parameters @@ -21,10 +31,37 @@ func DefaultParams() Params { // ParamSetPairs get the params.ParamSet func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { - return paramtypes.ParamSetPairs{} + return paramtypes.ParamSetPairs{ + paramtypes.NewParamSetPair( + KeySupplierUnbondingPeriodBlocks, + &p.SupplierUnbondingPeriodBlocks, + ValidateSupplierUnbondingPeriodBlocks, + ), + } } // Validate validates the set of params func (p Params) Validate() error { + // Validate the SupplierUnbondingPeriodBlocks + if err := ValidateSupplierUnbondingPeriodBlocks(p.SupplierUnbondingPeriodBlocks); err != nil { + return err + } + + return nil +} + +// ValidateSupplierUnbondingPeriodBlocks validates the SupplierUnbondingPeriodBlocks +// governance parameter. +// NB: The argument is an interface type to satisfy the ParamSetPair function signature. +func ValidateSupplierUnbondingPeriodBlocks(v interface{}) error { + supplierUnbondingPeriodBlocks, ok := v.(uint64) + if !ok { + return ErrSupplierParamsInvalid.Wrapf("invalid parameter type: %T", v) + } + + if supplierUnbondingPeriodBlocks <= 0 { + return ErrSupplierParamsInvalid.Wrapf("invalid SupplierUnbondingPeriodBlocks: (%v)", supplierUnbondingPeriodBlocks) + } + return nil } diff --git a/x/supplier/types/params.pb.go b/x/supplier/types/params.pb.go index a80ba2f9c..31879f4c1 100644 --- a/x/supplier/types/params.pb.go +++ b/x/supplier/types/params.pb.go @@ -26,6 +26,9 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // Params defines the parameters for the module. type Params struct { + // supplier_unbonding_period_blocks is the number of blocks that a supplier must wait + // after unstaking before they can withdraw their staked tokens. + SupplierUnbondingPeriodBlocks uint64 `protobuf:"varint,7,opt,name=supplier_unbonding_period_blocks,json=supplierUnbondingPeriodBlocks,proto3" json:"supplier_unbonding_period_blocks"` } func (m *Params) Reset() { *m = Params{} } @@ -61,6 +64,13 @@ func (m *Params) XXX_DiscardUnknown() { var xxx_messageInfo_Params proto.InternalMessageInfo +func (m *Params) GetSupplierUnbondingPeriodBlocks() uint64 { + if m != nil { + return m.SupplierUnbondingPeriodBlocks + } + return 0 +} + func init() { proto.RegisterType((*Params)(nil), "poktroll.supplier.Params") } @@ -68,19 +78,22 @@ func init() { func init() { proto.RegisterFile("poktroll/supplier/params.proto", fileDescriptor_60f7a8031a8c22d5) } var fileDescriptor_60f7a8031a8c22d5 = []byte{ - // 177 bytes of a gzipped FileDescriptorProto + // 235 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x2b, 0xc8, 0xcf, 0x2e, 0x29, 0xca, 0xcf, 0xc9, 0xd1, 0x2f, 0x2e, 0x2d, 0x28, 0xc8, 0xc9, 0x4c, 0x2d, 0xd2, 0x2f, 0x48, 0x2c, 0x4a, 0xcc, 0x2d, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x84, 0xc9, 0xeb, 0xc1, 0xe4, 0xa5, 0x04, 0x13, 0x73, 0x33, 0xf3, 0xf2, 0xf5, 0xc1, 0x24, 0x44, 0x95, 0x94, 0x48, 0x7a, - 0x7e, 0x7a, 0x3e, 0x98, 0xa9, 0x0f, 0x62, 0x41, 0x44, 0x95, 0x74, 0xb9, 0xd8, 0x02, 0xc0, 0x66, - 0x59, 0x29, 0xbf, 0x58, 0x20, 0xcf, 0xd8, 0xf5, 0x7c, 0x83, 0x96, 0x14, 0xdc, 0xba, 0x0a, 0x84, - 0x85, 0x10, 0x45, 0x4e, 0xde, 0x27, 0x1e, 0xc9, 0x31, 0x5e, 0x78, 0x24, 0xc7, 0xf8, 0xe0, 0x91, - 0x1c, 0xe3, 0x84, 0xc7, 0x72, 0x0c, 0x17, 0x1e, 0xcb, 0x31, 0xdc, 0x78, 0x2c, 0xc7, 0x10, 0x65, - 0x98, 0x9e, 0x59, 0x92, 0x51, 0x9a, 0xa4, 0x97, 0x9c, 0x9f, 0xab, 0x0f, 0x32, 0x40, 0x37, 0x2f, - 0xb5, 0xa4, 0x3c, 0xbf, 0x28, 0x5b, 0x1f, 0x9b, 0x69, 0x25, 0x95, 0x05, 0xa9, 0xc5, 0x49, 0x6c, - 0x60, 0x27, 0x18, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0x98, 0x12, 0x64, 0x47, 0xe0, 0x00, 0x00, - 0x00, + 0x7e, 0x7a, 0x3e, 0x98, 0xa9, 0x0f, 0x62, 0x41, 0x44, 0x95, 0xe6, 0x30, 0x72, 0xb1, 0x05, 0x80, + 0x0d, 0x13, 0xca, 0xe5, 0x52, 0x80, 0xe9, 0x8f, 0x2f, 0xcd, 0x4b, 0xca, 0xcf, 0x4b, 0xc9, 0xcc, + 0x4b, 0x8f, 0x2f, 0x48, 0x2d, 0xca, 0xcc, 0x4f, 0x89, 0x4f, 0xca, 0xc9, 0x4f, 0xce, 0x2e, 0x96, + 0x60, 0x57, 0x60, 0xd4, 0x60, 0x71, 0x52, 0x79, 0x75, 0x4f, 0x9e, 0xa0, 0xda, 0x20, 0x59, 0x98, + 0x8a, 0x50, 0x98, 0x82, 0x00, 0xb0, 0xbc, 0x13, 0x58, 0xda, 0x4a, 0xf9, 0xc5, 0x02, 0x79, 0xc6, + 0xae, 0xe7, 0x1b, 0xb4, 0xa4, 0xe0, 0xde, 0xab, 0x40, 0x78, 0x10, 0xe2, 0x26, 0x27, 0xef, 0x13, + 0x8f, 0xe4, 0x18, 0x2f, 0x3c, 0x92, 0x63, 0x7c, 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, 0x39, 0x86, + 0x0b, 0x8f, 0xe5, 0x18, 0x6e, 0x3c, 0x96, 0x63, 0x88, 0x32, 0x4c, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, + 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x07, 0x19, 0xa0, 0x9b, 0x97, 0x5a, 0x52, 0x9e, 0x5f, 0x94, 0xad, + 0x8f, 0xcd, 0xb4, 0x92, 0xca, 0x82, 0xd4, 0xe2, 0x24, 0x36, 0xb0, 0x97, 0x8d, 0x01, 0x01, 0x00, + 0x00, 0xff, 0xff, 0xbe, 0xe1, 0x32, 0x17, 0x50, 0x01, 0x00, 0x00, } func (this *Params) Equal(that interface{}) bool { @@ -102,6 +115,9 @@ func (this *Params) Equal(that interface{}) bool { } else if this == nil { return false } + if this.SupplierUnbondingPeriodBlocks != that1.SupplierUnbondingPeriodBlocks { + return false + } return true } func (m *Params) Marshal() (dAtA []byte, err error) { @@ -124,6 +140,11 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.SupplierUnbondingPeriodBlocks != 0 { + i = encodeVarintParams(dAtA, i, uint64(m.SupplierUnbondingPeriodBlocks)) + i-- + dAtA[i] = 0x38 + } return len(dAtA) - i, nil } @@ -144,6 +165,9 @@ func (m *Params) Size() (n int) { } var l int _ = l + if m.SupplierUnbondingPeriodBlocks != 0 { + n += 1 + sovParams(uint64(m.SupplierUnbondingPeriodBlocks)) + } return n } @@ -182,6 +206,25 @@ func (m *Params) Unmarshal(dAtA []byte) error { return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { + case 7: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field SupplierUnbondingPeriodBlocks", wireType) + } + m.SupplierUnbondingPeriodBlocks = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.SupplierUnbondingPeriodBlocks |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipParams(dAtA[iNdEx:]) From 94f078fb962dbc15690ad2865a78275bcd9e8828 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Wed, 10 Jul 2024 05:01:51 +0200 Subject: [PATCH 06/13] chore: Rename step --- e2e/tests/init_test.go | 2 +- e2e/tests/stake_supplier.feature | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/e2e/tests/init_test.go b/e2e/tests/init_test.go index f8245b5dd..15be47cbd 100644 --- a/e2e/tests/init_test.go +++ b/e2e/tests/init_test.go @@ -456,7 +456,7 @@ func (s *suite) TheSupplierForAccountIsUnbonding(accName string) { ) } -func (s *suite) TheUserWaitsForUnbondingPeriodToPass(accName string) { +func (s *suite) TheUserWaitsForUnbondingPeriodToFinish(accName string) { _, ok := accNameToSupplierMap[accName] require.True(s, ok, "supplier %s not found", accName) diff --git a/e2e/tests/stake_supplier.feature b/e2e/tests/stake_supplier.feature index dbddaf890..8521e8286 100644 --- a/e2e/tests/stake_supplier.feature +++ b/e2e/tests/stake_supplier.feature @@ -23,6 +23,6 @@ Feature: Stake Supplier Namespace And the user should be able to see standard output containing "code: 0" And the pocketd binary should exit without error And the supplier for account "supplier2" is unbonding - When the user waits for "supplier2" unbonding period to pass + When the user waits for "supplier2" unbonding period to finish Then the "supplier" for account "supplier2" is not staked And the account balance of "supplier2" should be "1000070" uPOKT "more" than before \ No newline at end of file From aa26347d274c26a5026ed2847b180725597eee39 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Sat, 13 Jul 2024 00:10:44 +0200 Subject: [PATCH 07/13] chore: Address review change requests --- api/poktroll/shared/supplier.pulsar.go | 30 +++++----- e2e/tests/init_test.go | 10 ++-- proto/poktroll/shared/supplier.proto | 4 +- testutil/keeper/supplier.go | 3 +- x/session/keeper/session_hydrator.go | 4 +- x/shared/types/supplier.pb.go | 56 ++++++++++--------- .../keeper/msg_server_stake_supplier.go | 2 +- .../keeper/msg_server_unstake_supplier.go | 8 +-- .../msg_server_unstake_supplier_test.go | 36 ++++++------ x/supplier/keeper/unbond_suppliers.go | 16 +++--- x/supplier/types/errors.go | 2 +- x/supplier/types/params.go | 3 +- 12 files changed, 91 insertions(+), 83 deletions(-) diff --git a/api/poktroll/shared/supplier.pulsar.go b/api/poktroll/shared/supplier.pulsar.go index 58c838148..05dc8e807 100644 --- a/api/poktroll/shared/supplier.pulsar.go +++ b/api/poktroll/shared/supplier.pulsar.go @@ -165,8 +165,8 @@ func (x *fastReflection_Supplier) Range(f func(protoreflect.FieldDescriptor, pro return } } - if x.UnstakeCommitSessionEndHeight != int64(0) { - value := protoreflect.ValueOfInt64(x.UnstakeCommitSessionEndHeight) + if x.UnstakeCommitSessionEndHeight != uint64(0) { + value := protoreflect.ValueOfUint64(x.UnstakeCommitSessionEndHeight) if !f(fd_Supplier_unstake_commit_session_end_height, value) { return } @@ -193,7 +193,7 @@ func (x *fastReflection_Supplier) Has(fd protoreflect.FieldDescriptor) bool { case "poktroll.shared.Supplier.services": return len(x.Services) != 0 case "poktroll.shared.Supplier.unstake_commit_session_end_height": - return x.UnstakeCommitSessionEndHeight != int64(0) + return x.UnstakeCommitSessionEndHeight != uint64(0) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.shared.Supplier")) @@ -217,7 +217,7 @@ func (x *fastReflection_Supplier) Clear(fd protoreflect.FieldDescriptor) { case "poktroll.shared.Supplier.services": x.Services = nil case "poktroll.shared.Supplier.unstake_commit_session_end_height": - x.UnstakeCommitSessionEndHeight = int64(0) + x.UnstakeCommitSessionEndHeight = uint64(0) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.shared.Supplier")) @@ -248,7 +248,7 @@ func (x *fastReflection_Supplier) Get(descriptor protoreflect.FieldDescriptor) p return protoreflect.ValueOfList(listValue) case "poktroll.shared.Supplier.unstake_commit_session_end_height": value := x.UnstakeCommitSessionEndHeight - return protoreflect.ValueOfInt64(value) + return protoreflect.ValueOfUint64(value) default: if descriptor.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.shared.Supplier")) @@ -278,7 +278,7 @@ func (x *fastReflection_Supplier) Set(fd protoreflect.FieldDescriptor, value pro clv := lv.(*_Supplier_3_list) x.Services = *clv.list case "poktroll.shared.Supplier.unstake_commit_session_end_height": - x.UnstakeCommitSessionEndHeight = value.Int() + x.UnstakeCommitSessionEndHeight = value.Uint() default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.shared.Supplier")) @@ -336,7 +336,7 @@ func (x *fastReflection_Supplier) NewField(fd protoreflect.FieldDescriptor) prot list := []*SupplierServiceConfig{} return protoreflect.ValueOfList(&_Supplier_3_list{list: &list}) case "poktroll.shared.Supplier.unstake_commit_session_end_height": - return protoreflect.ValueOfInt64(int64(0)) + return protoreflect.ValueOfUint64(uint64(0)) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.shared.Supplier")) @@ -659,7 +659,7 @@ func (x *fastReflection_Supplier) ProtoMethods() *protoiface.Methods { } b := dAtA[iNdEx] iNdEx++ - x.UnstakeCommitSessionEndHeight |= int64(b&0x7F) << shift + x.UnstakeCommitSessionEndHeight |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -718,10 +718,12 @@ type Supplier struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` // The Bech32 address of the supplier using cosmos' ScalarDescriptor to ensure deterministic encoding - Stake *v1beta1.Coin `protobuf:"bytes,2,opt,name=stake,proto3" json:"stake,omitempty"` // The total amount of uPOKT the supplier has staked - Services []*SupplierServiceConfig `protobuf:"bytes,3,rep,name=services,proto3" json:"services,omitempty"` // The service configs this supplier can support - UnstakeCommitSessionEndHeight int64 `protobuf:"varint,4,opt,name=unstake_commit_session_end_height,json=unstakeCommitSessionEndHeight,proto3" json:"unstake_commit_session_end_height,omitempty"` // The session end height corresponding the the unstake tx commit height + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` // The Bech32 address of the supplier using cosmos' ScalarDescriptor to ensure deterministic encoding + Stake *v1beta1.Coin `protobuf:"bytes,2,opt,name=stake,proto3" json:"stake,omitempty"` // The total amount of uPOKT the supplier has staked + Services []*SupplierServiceConfig `protobuf:"bytes,3,rep,name=services,proto3" json:"services,omitempty"` // The service configs this supplier can support + // The session end height corresponding the the unstake tx commit height. + // If the supplier is not unstaking, this value will be 0. + UnstakeCommitSessionEndHeight uint64 `protobuf:"varint,4,opt,name=unstake_commit_session_end_height,json=unstakeCommitSessionEndHeight,proto3" json:"unstake_commit_session_end_height,omitempty"` } func (x *Supplier) Reset() { @@ -765,7 +767,7 @@ func (x *Supplier) GetServices() []*SupplierServiceConfig { return nil } -func (x *Supplier) GetUnstakeCommitSessionEndHeight() int64 { +func (x *Supplier) GetUnstakeCommitSessionEndHeight() uint64 { if x != nil { return x.UnstakeCommitSessionEndHeight } @@ -797,7 +799,7 @@ var file_poktroll_shared_supplier_proto_rawDesc = []byte{ 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x48, 0x0a, 0x21, 0x75, 0x6e, 0x73, 0x74, 0x61, 0x6b, 0x65, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x6e, 0x64, 0x5f, - 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x1d, 0x75, 0x6e, + 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1d, 0x75, 0x6e, 0x73, 0x74, 0x61, 0x6b, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x45, 0x6e, 0x64, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x42, 0xa3, 0x01, 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x73, 0x68, 0x61, diff --git a/e2e/tests/init_test.go b/e2e/tests/init_test.go index 15be47cbd..177218145 100644 --- a/e2e/tests/init_test.go +++ b/e2e/tests/init_test.go @@ -449,9 +449,9 @@ func (s *suite) TheSupplierForAccountIsUnbonding(accName string) { s.waitForTxResultEvent(newEventMsgTypeMatchFn("supplier", "UnstakeSupplier")) supplier := s.getSupplierInfo(accName) - require.Greater(s, + require.NotEqual(s, supplier.UnstakeCommitSessionEndHeight, - int64(0), + suppliertypes.SupplierNotUnstaking, "supplier %s is not unbonding", accName, ) } @@ -461,7 +461,7 @@ func (s *suite) TheUserWaitsForUnbondingPeriodToFinish(accName string) { require.True(s, ok, "supplier %s not found", accName) unbondingHeight := s.getSupplierUnbondingHeight(accName) - s.waitForBlockHeight(unbondingHeight) + s.waitForBlockHeight(int64(unbondingHeight)) } func (s *suite) getStakedAmount(actorType, accName string) (int, bool) { @@ -609,7 +609,7 @@ func (s *suite) getSupplierInfo(supplierAddr string) *sharedtypes.Supplier { } // getSupplierUnbondingHeight returns the height at which the supplier will be unbonded. -func (s *suite) getSupplierUnbondingHeight(accName string) int64 { +func (s *suite) getSupplierUnbondingHeight(accName string) uint64 { supplier := s.getSupplierInfo(accName) args := []string{ @@ -625,7 +625,7 @@ func (s *suite) getSupplierUnbondingHeight(accName string) int64 { var resp suppliertypes.QueryParamsResponse responseBz := []byte(strings.TrimSpace(res.Stdout)) s.cdc.MustUnmarshalJSON(responseBz, &resp) - return supplier.UnstakeCommitSessionEndHeight + int64(resp.Params.SupplierUnbondingPeriodBlocks) + return supplier.UnstakeCommitSessionEndHeight + resp.Params.SupplierUnbondingPeriodBlocks } // TODO_IMPROVE: use `sessionId` and `supplierName` since those are the two values diff --git a/proto/poktroll/shared/supplier.proto b/proto/poktroll/shared/supplier.proto index 3aec13e54..28c9ed916 100644 --- a/proto/poktroll/shared/supplier.proto +++ b/proto/poktroll/shared/supplier.proto @@ -13,6 +13,8 @@ message Supplier { string address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; // The Bech32 address of the supplier using cosmos' ScalarDescriptor to ensure deterministic encoding cosmos.base.v1beta1.Coin stake = 2; // The total amount of uPOKT the supplier has staked repeated SupplierServiceConfig services = 3; // The service configs this supplier can support - int64 unstake_commit_session_end_height = 4; // The session end height corresponding the the unstake tx commit height + // The session end height corresponding the the unstake tx commit height. + // If the supplier is not unstaking, this value will be 0. + uint64 unstake_commit_session_end_height = 4; } diff --git a/testutil/keeper/supplier.go b/testutil/keeper/supplier.go index 8009508ce..e364fdd1c 100644 --- a/testutil/keeper/supplier.go +++ b/testutil/keeper/supplier.go @@ -70,8 +70,7 @@ func SupplierKeeper(t testing.TB) (keeper.Keeper, context.Context) { require.NoError(t, k.SetParams(ctx, types.DefaultParams())) // Move block height to 1 to get a non zero session end height - sdkCtx := sdk.UnwrapSDKContext(ctx) - sdkCtx = sdkCtx.WithBlockHeight(sdkCtx.BlockHeight() + 1) + sdkCtx := SetBlockHeight(ctx, 1) return k, sdkCtx } diff --git a/x/session/keeper/session_hydrator.go b/x/session/keeper/session_hydrator.go index b5d1b032d..07ccd90fd 100644 --- a/x/session/keeper/session_hydrator.go +++ b/x/session/keeper/session_hydrator.go @@ -173,8 +173,10 @@ func (k Keeper) hydrateSessionSuppliers(ctx context.Context, sh *sessionHydrator candidateSuppliers := make([]*sharedtypes.Supplier, 0) for _, s := range suppliers { // Exclude suppliers that are in an unbonding period. + // TODO_TECHDEBT: Suppliers that stake mid-session SHOULD NOT be included + // in the current session's suppliers list and must wait until the next one. if s.UnstakeCommitSessionEndHeight != 0 && - sh.sessionHeader.SessionEndBlockHeight > s.UnstakeCommitSessionEndHeight { + uint64(sh.sessionHeader.SessionEndBlockHeight) > s.UnstakeCommitSessionEndHeight { continue } diff --git a/x/shared/types/supplier.pb.go b/x/shared/types/supplier.pb.go index 448836744..dfd4d133a 100644 --- a/x/shared/types/supplier.pb.go +++ b/x/shared/types/supplier.pb.go @@ -26,10 +26,12 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // Supplier is the type defining the actor in Pocket Network that provides RPC services. type Supplier struct { - Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` - Stake *types.Coin `protobuf:"bytes,2,opt,name=stake,proto3" json:"stake,omitempty"` - Services []*SupplierServiceConfig `protobuf:"bytes,3,rep,name=services,proto3" json:"services,omitempty"` - UnstakeCommitSessionEndHeight int64 `protobuf:"varint,4,opt,name=unstake_commit_session_end_height,json=unstakeCommitSessionEndHeight,proto3" json:"unstake_commit_session_end_height,omitempty"` + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + Stake *types.Coin `protobuf:"bytes,2,opt,name=stake,proto3" json:"stake,omitempty"` + Services []*SupplierServiceConfig `protobuf:"bytes,3,rep,name=services,proto3" json:"services,omitempty"` + // The session end height corresponding the the unstake tx commit height. + // If the supplier is not unstaking, this value will be 0. + UnstakeCommitSessionEndHeight uint64 `protobuf:"varint,4,opt,name=unstake_commit_session_end_height,json=unstakeCommitSessionEndHeight,proto3" json:"unstake_commit_session_end_height,omitempty"` } func (m *Supplier) Reset() { *m = Supplier{} } @@ -86,7 +88,7 @@ func (m *Supplier) GetServices() []*SupplierServiceConfig { return nil } -func (m *Supplier) GetUnstakeCommitSessionEndHeight() int64 { +func (m *Supplier) GetUnstakeCommitSessionEndHeight() uint64 { if m != nil { return m.UnstakeCommitSessionEndHeight } @@ -100,28 +102,28 @@ func init() { func init() { proto.RegisterFile("poktroll/shared/supplier.proto", fileDescriptor_4a189b52ba503cf2) } var fileDescriptor_4a189b52ba503cf2 = []byte{ - // 335 bytes of a gzipped FileDescriptorProto + // 336 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x90, 0xbf, 0x4e, 0xeb, 0x30, - 0x18, 0xc5, 0xeb, 0xdb, 0x7b, 0x2f, 0x25, 0x1d, 0x90, 0x22, 0x86, 0xb4, 0x52, 0xad, 0xc0, 0x80, - 0xb2, 0xd4, 0x56, 0xcb, 0x13, 0xd0, 0x0a, 0xa9, 0xac, 0xc9, 0xc6, 0x12, 0xe5, 0x8f, 0x49, 0xac, - 0x36, 0x76, 0xe4, 0xcf, 0x2d, 0xf0, 0x16, 0x3c, 0x0c, 0x0f, 0xc1, 0x58, 0x31, 0x31, 0xa2, 0xf6, - 0x39, 0x90, 0x50, 0x63, 0xa7, 0x03, 0x8c, 0x9f, 0x7e, 0xbf, 0xe4, 0x1c, 0x1f, 0x07, 0xd7, 0x72, - 0xa9, 0x95, 0x5c, 0xad, 0x28, 0x94, 0x89, 0x62, 0x39, 0x85, 0x75, 0x5d, 0xaf, 0x38, 0x53, 0xa4, - 0x56, 0x52, 0x4b, 0xf7, 0xac, 0xe5, 0xc4, 0xf0, 0xe1, 0x20, 0x93, 0x50, 0x49, 0x88, 0x1b, 0x4c, - 0xcd, 0x61, 0xdc, 0x21, 0x36, 0x17, 0x4d, 0x13, 0x60, 0x74, 0x33, 0x49, 0x99, 0x4e, 0x26, 0x34, - 0x93, 0x5c, 0x58, 0x3e, 0xfa, 0x95, 0xc5, 0xd4, 0x86, 0x67, 0xcc, 0xe0, 0xcb, 0x2f, 0xe4, 0xf4, - 0x22, 0x9b, 0xee, 0x4e, 0x9d, 0x93, 0x24, 0xcf, 0x15, 0x03, 0xf0, 0x90, 0x8f, 0x82, 0xd3, 0x99, - 0xf7, 0xfe, 0x3a, 0x3e, 0xb7, 0x71, 0x37, 0x86, 0x44, 0x5a, 0x71, 0x51, 0x84, 0xad, 0xe8, 0x52, - 0xe7, 0x1f, 0xe8, 0x64, 0xc9, 0xbc, 0x3f, 0x3e, 0x0a, 0xfa, 0xd3, 0x01, 0xb1, 0xfa, 0xa1, 0x0f, - 0xb1, 0x7d, 0xc8, 0x5c, 0x72, 0x11, 0x1a, 0xcf, 0x9d, 0x39, 0x3d, 0x5b, 0x01, 0xbc, 0xae, 0xdf, - 0x0d, 0xfa, 0xd3, 0x2b, 0xf2, 0xe3, 0xbd, 0xa4, 0x6d, 0x14, 0x19, 0x71, 0x2e, 0xc5, 0x03, 0x2f, - 0xc2, 0xe3, 0x77, 0xee, 0xc2, 0xb9, 0x58, 0x8b, 0xe6, 0x77, 0x71, 0x26, 0xab, 0x8a, 0xeb, 0x18, - 0x18, 0x00, 0x97, 0x22, 0x66, 0x22, 0x8f, 0x4b, 0xc6, 0x8b, 0x52, 0x7b, 0x7f, 0x7d, 0x14, 0x74, - 0xc3, 0x91, 0x15, 0xe7, 0x8d, 0x17, 0x19, 0xed, 0x56, 0xe4, 0x8b, 0x46, 0x9a, 0xdd, 0xbd, 0xed, - 0x30, 0xda, 0xee, 0x30, 0xfa, 0xdc, 0x61, 0xf4, 0xb2, 0xc7, 0x9d, 0xed, 0x1e, 0x77, 0x3e, 0xf6, - 0xb8, 0x73, 0x4f, 0x0b, 0xae, 0xcb, 0x75, 0x4a, 0x32, 0x59, 0xd1, 0x43, 0xbf, 0xb1, 0x60, 0xfa, - 0x51, 0xaa, 0x25, 0x3d, 0x0e, 0xfa, 0xd4, 0x4e, 0xaa, 0x9f, 0x6b, 0x06, 0xe9, 0xff, 0x66, 0xd1, - 0xeb, 0xef, 0x00, 0x00, 0x00, 0xff, 0xff, 0x35, 0x3c, 0xfd, 0xfe, 0xde, 0x01, 0x00, 0x00, + 0x18, 0xc5, 0xeb, 0xdb, 0xde, 0x7b, 0x7b, 0xd3, 0xe1, 0x4a, 0x11, 0x43, 0x5a, 0xa9, 0x56, 0x60, + 0x40, 0x59, 0x6a, 0xab, 0xe5, 0x09, 0x68, 0x85, 0x54, 0xd6, 0x64, 0x63, 0x89, 0xf2, 0xc7, 0x24, + 0x56, 0x1b, 0x3b, 0xf2, 0xe7, 0x16, 0x78, 0x0b, 0x1e, 0x86, 0x87, 0x60, 0xac, 0x98, 0x18, 0x51, + 0xfb, 0x1c, 0x48, 0xa8, 0xb1, 0xd3, 0x01, 0xc6, 0x4f, 0xbf, 0x5f, 0x72, 0x8e, 0x8f, 0x83, 0x6b, + 0xb9, 0xd2, 0x4a, 0xae, 0xd7, 0x14, 0xca, 0x44, 0xb1, 0x9c, 0xc2, 0xa6, 0xae, 0xd7, 0x9c, 0x29, + 0x52, 0x2b, 0xa9, 0xa5, 0xfb, 0xbf, 0xe5, 0xc4, 0xf0, 0xd1, 0x30, 0x93, 0x50, 0x49, 0x88, 0x1b, + 0x4c, 0xcd, 0x61, 0xdc, 0x11, 0x36, 0x17, 0x4d, 0x13, 0x60, 0x74, 0x3b, 0x4d, 0x99, 0x4e, 0xa6, + 0x34, 0x93, 0x5c, 0x58, 0x3e, 0xfe, 0x91, 0xc5, 0xd4, 0x96, 0x67, 0xcc, 0xe0, 0x8b, 0x4f, 0xe4, + 0xf4, 0x23, 0x9b, 0xee, 0xce, 0x9c, 0xbf, 0x49, 0x9e, 0x2b, 0x06, 0xe0, 0x21, 0x1f, 0x05, 0xff, + 0xe6, 0xde, 0xdb, 0xcb, 0xe4, 0xcc, 0xc6, 0x5d, 0x1b, 0x12, 0x69, 0xc5, 0x45, 0x11, 0xb6, 0xa2, + 0x4b, 0x9d, 0xdf, 0xa0, 0x93, 0x15, 0xf3, 0x7e, 0xf9, 0x28, 0x18, 0xcc, 0x86, 0xc4, 0xea, 0xc7, + 0x3e, 0xc4, 0xf6, 0x21, 0x0b, 0xc9, 0x45, 0x68, 0x3c, 0x77, 0xee, 0xf4, 0x6d, 0x05, 0xf0, 0xba, + 0x7e, 0x37, 0x18, 0xcc, 0x2e, 0xc9, 0xb7, 0xf7, 0x92, 0xb6, 0x51, 0x64, 0xc4, 0x85, 0x14, 0xf7, + 0xbc, 0x08, 0x4f, 0xdf, 0xb9, 0x4b, 0xe7, 0x7c, 0x23, 0x9a, 0xdf, 0xc5, 0x99, 0xac, 0x2a, 0xae, + 0x63, 0x60, 0x00, 0x5c, 0x8a, 0x98, 0x89, 0x3c, 0x2e, 0x19, 0x2f, 0x4a, 0xed, 0xf5, 0x7c, 0x14, + 0xf4, 0xc2, 0xb1, 0x15, 0x17, 0x8d, 0x17, 0x19, 0xed, 0x46, 0xe4, 0xcb, 0x46, 0x9a, 0xdf, 0xbe, + 0xee, 0x31, 0xda, 0xed, 0x31, 0xfa, 0xd8, 0x63, 0xf4, 0x7c, 0xc0, 0x9d, 0xdd, 0x01, 0x77, 0xde, + 0x0f, 0xb8, 0x73, 0x47, 0x0b, 0xae, 0xcb, 0x4d, 0x4a, 0x32, 0x59, 0xd1, 0x63, 0xbf, 0x89, 0x60, + 0xfa, 0x41, 0xaa, 0x15, 0x3d, 0x0d, 0xfa, 0xd8, 0x4e, 0xaa, 0x9f, 0x6a, 0x06, 0xe9, 0x9f, 0x66, + 0xd1, 0xab, 0xaf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xb3, 0xb1, 0xeb, 0xec, 0xde, 0x01, 0x00, 0x00, } func (m *Supplier) Marshal() (dAtA []byte, err error) { @@ -373,7 +375,7 @@ func (m *Supplier) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.UnstakeCommitSessionEndHeight |= int64(b&0x7F) << shift + m.UnstakeCommitSessionEndHeight |= uint64(b&0x7F) << shift if b < 0x80 { break } diff --git a/x/supplier/keeper/msg_server_stake_supplier.go b/x/supplier/keeper/msg_server_stake_supplier.go index c4c12abbf..191bc9d93 100644 --- a/x/supplier/keeper/msg_server_stake_supplier.go +++ b/x/supplier/keeper/msg_server_stake_supplier.go @@ -50,7 +50,7 @@ func (k msgServer) StakeSupplier(ctx context.Context, msg *types.MsgStakeSupplie logger.Info(fmt.Sprintf("Supplier is going to escrow an additional %+v coins", coinsToEscrow)) // If the supplier has initiated an unstake action, cancel it since they are staking again. - supplier.UnstakeCommitSessionEndHeight = 0 + supplier.UnstakeCommitSessionEndHeight = types.SupplierNotUnstaking } // Must always stake or upstake (> 0 delta) diff --git a/x/supplier/keeper/msg_server_unstake_supplier.go b/x/supplier/keeper/msg_server_unstake_supplier.go index a6eea4584..ca79f84a1 100644 --- a/x/supplier/keeper/msg_server_unstake_supplier.go +++ b/x/supplier/keeper/msg_server_unstake_supplier.go @@ -39,9 +39,9 @@ func (k msgServer) UnstakeSupplier( logger.Info(fmt.Sprintf("Supplier found. Unstaking supplier for address %s", msg.Address)) // Check if the supplier has already initiated the unstake action. - if supplier.UnstakeCommitSessionEndHeight > 0 { + if supplier.UnstakeCommitSessionEndHeight != types.SupplierNotUnstaking { logger.Warn(fmt.Sprintf("Supplier %s still unbonding from previous unstaking", msg.Address)) - return nil, types.ErrSupplierUnbonding + return nil, types.ErrSupplierIsUnstaking } sdkCtx := sdk.UnwrapSDKContext(ctx) @@ -51,11 +51,11 @@ func (k msgServer) UnstakeSupplier( // Mark the supplier as unstaking by recording the height at which it should stop // providing service. // The supplier MUST continue to provide service until the end of the current - // session, which which should not change its suppliers list mid-session. + // session. I.e., on-chain sessions' suppliers list MUST NOT change mid-session. // Removing it right away could have undesired effects on the network // (e.g. a session with less than the minimum or 0 number of suppliers, // off-chain actors that need to listen to session supplier's change mid-session, etc). - supplier.UnstakeCommitSessionEndHeight = shared.GetSessionEndHeight(&sharedParams, currentHeight) + supplier.UnstakeCommitSessionEndHeight = uint64(shared.GetSessionEndHeight(&sharedParams, currentHeight)) k.SetSupplier(ctx, supplier) isSuccessful = true diff --git a/x/supplier/keeper/msg_server_unstake_supplier_test.go b/x/supplier/keeper/msg_server_unstake_supplier_test.go index cca4f8fec..ce1017f23 100644 --- a/x/supplier/keeper/msg_server_unstake_supplier_test.go +++ b/x/supplier/keeper/msg_server_unstake_supplier_test.go @@ -47,20 +47,19 @@ func TestMsgServer_UnstakeSupplier_Success(t *testing.T) { // Make sure the supplier entered the unbonding period foundSupplier, isSupplierFound = k.GetSupplier(ctx, supplierAddr) require.True(t, isSupplierFound) - require.Greater(t, foundSupplier.UnstakeCommitSessionEndHeight, int64(0)) + require.NotEqual(t, foundSupplier.UnstakeCommitSessionEndHeight, types.SupplierNotUnstaking) // Move block height to the end of the unbonding period - unbondingHeight := foundSupplier.UnstakeCommitSessionEndHeight + int64(k.GetParams(ctx).SupplierUnbondingPeriodBlocks) - sdkCtx := sdk.UnwrapSDKContext(ctx) - sdkCtx = sdkCtx.WithBlockHeight(unbondingHeight) + unbondingHeight := foundSupplier.UnstakeCommitSessionEndHeight + k.GetParams(ctx).SupplierUnbondingPeriodBlocks + ctx = keepertest.SetBlockHeight(ctx, int64(unbondingHeight)) // Run the endblocker to unbond the supplier - err = k.EndBlockerUnbondSupplier(sdkCtx) + err = k.EndBlockerUnbondSupplier(ctx) require.NoError(t, err) // Make sure the supplier is removed from the suppliers list when the // unbonding period is over - _, isSupplierFound = k.GetSupplier(sdkCtx, supplierAddr) + _, isSupplierFound = k.GetSupplier(ctx, supplierAddr) require.False(t, isSupplierFound) } @@ -80,7 +79,7 @@ func TestMsgServer_UnstakeSupplier_CancelUnbondingIfRestaked(t *testing.T) { // Verify that the supplier exists with no unbonding height foundSupplier, isSupplierFound := k.GetSupplier(ctx, supplierAddr) require.True(t, isSupplierFound) - require.Equal(t, int64(0), foundSupplier.UnstakeCommitSessionEndHeight) + require.Equal(t, types.SupplierNotUnstaking, foundSupplier.UnstakeCommitSessionEndHeight) // Initiate the supplier unstaking unstakeMsg := &types.MsgUnstakeSupplier{Address: supplierAddr} @@ -90,9 +89,9 @@ func TestMsgServer_UnstakeSupplier_CancelUnbondingIfRestaked(t *testing.T) { // Make sure the supplier entered the unbonding period foundSupplier, isSupplierFound = k.GetSupplier(ctx, supplierAddr) require.True(t, isSupplierFound) - require.Greater(t, foundSupplier.UnstakeCommitSessionEndHeight, int64(0)) + require.NotEqual(t, foundSupplier.UnstakeCommitSessionEndHeight, types.SupplierNotUnstaking) - unbondingHeight := foundSupplier.UnstakeCommitSessionEndHeight + int64(k.GetParams(ctx).SupplierUnbondingPeriodBlocks) + unbondingHeight := foundSupplier.UnstakeCommitSessionEndHeight + k.GetParams(ctx).SupplierUnbondingPeriodBlocks // Stake the supplier again stakeMsg = createStakeMsg(supplierAddr, initialStake+1) @@ -102,19 +101,18 @@ func TestMsgServer_UnstakeSupplier_CancelUnbondingIfRestaked(t *testing.T) { // Make sure the supplier is no longer in the unbonding period foundSupplier, isSupplierFound = k.GetSupplier(ctx, supplierAddr) require.True(t, isSupplierFound) - require.Equal(t, foundSupplier.UnstakeCommitSessionEndHeight, int64(0)) + require.Equal(t, foundSupplier.UnstakeCommitSessionEndHeight, types.SupplierNotUnstaking) - sdkCtx := sdk.UnwrapSDKContext(ctx) - sdkCtx = sdkCtx.WithBlockHeight(unbondingHeight) + ctx = keepertest.SetBlockHeight(ctx, int64(unbondingHeight)) // Run the endblocker to unbond the supplier - err = k.EndBlockerUnbondSupplier(sdkCtx) + err = k.EndBlockerUnbondSupplier(ctx) require.NoError(t, err) // Make sure the supplier is still in the suppliers list with an unbonding height of 0 - foundSupplier, isSupplierFound = k.GetSupplier(sdkCtx, supplierAddr) + foundSupplier, isSupplierFound = k.GetSupplier(ctx, supplierAddr) require.True(t, isSupplierFound) - require.Equal(t, foundSupplier.UnstakeCommitSessionEndHeight, int64(0)) + require.Equal(t, foundSupplier.UnstakeCommitSessionEndHeight, types.SupplierNotUnstaking) } func TestMsgServer_UnstakeSupplier_FailIfNotStaked(t *testing.T) { @@ -138,7 +136,7 @@ func TestMsgServer_UnstakeSupplier_FailIfNotStaked(t *testing.T) { require.False(t, isSupplierFound) } -func TestMsgServer_UnstakeSupplier_FailIfNotInUnbondingPeriod(t *testing.T) { +func TestMsgServer_UnstakeSupplier_FailIfCurrentlyUnstaking(t *testing.T) { k, ctx := keepertest.SupplierKeeper(t) srv := keeper.NewMsgServerImpl(k) @@ -157,10 +155,10 @@ func TestMsgServer_UnstakeSupplier_FailIfNotInUnbondingPeriod(t *testing.T) { require.NoError(t, err) sdkCtx := sdk.UnwrapSDKContext(ctx) - sdkCtx = sdkCtx.WithBlockHeight(sdkCtx.BlockHeight() + 1) + ctx = keepertest.SetBlockHeight(ctx, int64(sdkCtx.BlockHeight()+1)) - _, err = srv.UnstakeSupplier(sdkCtx, unstakeMsg) - require.ErrorIs(t, err, types.ErrSupplierUnbonding) + _, err = srv.UnstakeSupplier(ctx, unstakeMsg) + require.ErrorIs(t, err, types.ErrSupplierIsUnstaking) } func createStakeMsg(supplierAddr string, stakeAmount int64) *types.MsgStakeSupplier { diff --git a/x/supplier/keeper/unbond_suppliers.go b/x/supplier/keeper/unbond_suppliers.go index 2477ac2a4..1e377eaaf 100644 --- a/x/supplier/keeper/unbond_suppliers.go +++ b/x/supplier/keeper/unbond_suppliers.go @@ -1,6 +1,7 @@ package keeper import ( + "context" "fmt" sdk "github.com/cosmos/cosmos-sdk/types" @@ -9,8 +10,9 @@ import ( ) // EndBlockerUnbondSupplier unbonds suppliers that have finished the unbonding period. -func (k Keeper) EndBlockerUnbondSupplier(ctx sdk.Context) error { - currentHeight := ctx.BlockHeight() +func (k Keeper) EndBlockerUnbondSupplier(ctx context.Context) error { + sdkCtx := sdk.UnwrapSDKContext(ctx) + currentHeight := sdkCtx.BlockHeight() sharedParams := k.sharedKeeper.GetParams(ctx) sessionEndHeight := shared.GetSessionEndHeight(&sharedParams, currentHeight) @@ -30,19 +32,19 @@ func (k Keeper) EndBlockerUnbondSupplier(ctx sdk.Context) error { continue } - unbondingPeriodBlocks := int64(k.GetParams(ctx).SupplierUnbondingPeriodBlocks) + unbondingPeriodBlocks := k.GetParams(ctx).SupplierUnbondingPeriodBlocks unbondingHeight := supplier.UnstakeCommitSessionEndHeight + unbondingPeriodBlocks - if unbondingHeight <= currentHeight { + if unbondingHeight <= uint64(currentHeight) { - // Retrieve the address of the supplier + // Retrieve the address of the supplier. supplierAddress, err := sdk.AccAddressFromBech32(supplier.Address) if err != nil { logger.Error(fmt.Sprintf("could not parse address %s", supplier.Address)) return err } - // Send the coins from the supplier pool back to the supplier + // Send the coins from the supplier pool back to the supplier. if err = k.bankKeeper.SendCoinsFromModuleToAccount( ctx, types.ModuleName, supplierAddress, []sdk.Coin{*supplier.Stake}, ); err != nil { @@ -53,7 +55,7 @@ func (k Keeper) EndBlockerUnbondSupplier(ctx sdk.Context) error { return err } - // Update the Supplier in the store + // Remove the supplier from the store. k.RemoveSupplier(ctx, supplierAddress.String()) logger.Info(fmt.Sprintf("Successfully removed the supplier: %+v", supplier)) } diff --git a/x/supplier/types/errors.go b/x/supplier/types/errors.go index 03877b5c2..5d04f8477 100644 --- a/x/supplier/types/errors.go +++ b/x/supplier/types/errors.go @@ -16,6 +16,6 @@ var ( ErrSupplierInvalidSessionId = sdkerrors.Register(ModuleName, 1107, "invalid session ID") ErrSupplierInvalidService = sdkerrors.Register(ModuleName, 1108, "invalid service in supplier") ErrSupplierInvalidSessionEndHeight = sdkerrors.Register(ModuleName, 1109, "invalid session ending height") - ErrSupplierUnbonding = sdkerrors.Register(ModuleName, 1110, "supplier is in unbonding period") + ErrSupplierIsUnstaking = sdkerrors.Register(ModuleName, 1110, "supplier is in unbonding period") ErrSupplierParamsInvalid = sdkerrors.Register(ModuleName, 1111, "invalid supplier params") ) diff --git a/x/supplier/types/params.go b/x/supplier/types/params.go index f4f6e7c2e..b932f8ade 100644 --- a/x/supplier/types/params.go +++ b/x/supplier/types/params.go @@ -10,6 +10,7 @@ var ( KeySupplierUnbondingPeriodBlocks = []byte("SupplierUnbondingPeriodBlocks") ParamSupplierUnbondingPeriodBlocks = "supplier_unbonding_period_blocks" DefaultSupplierUnbondingPeriodBlocks uint64 = 4 // TODO_MAINNET: Determine the default value. + SupplierNotUnstaking uint64 = 0 ) // ParamKeyTable the param key table for launch module @@ -59,7 +60,7 @@ func ValidateSupplierUnbondingPeriodBlocks(v interface{}) error { return ErrSupplierParamsInvalid.Wrapf("invalid parameter type: %T", v) } - if supplierUnbondingPeriodBlocks <= 0 { + if supplierUnbondingPeriodBlocks == SupplierNotUnstaking { return ErrSupplierParamsInvalid.Wrapf("invalid SupplierUnbondingPeriodBlocks: (%v)", supplierUnbondingPeriodBlocks) } From 1616f966f28ce1fef0e11f30f27db02ba8ffaf4c Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Mon, 15 Jul 2024 16:36:54 +0200 Subject: [PATCH 08/13] chore: Fix import --- x/supplier/keeper/unbond_suppliers.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/x/supplier/keeper/unbond_suppliers.go b/x/supplier/keeper/unbond_suppliers.go index 1e377eaaf..18bbbc3c6 100644 --- a/x/supplier/keeper/unbond_suppliers.go +++ b/x/supplier/keeper/unbond_suppliers.go @@ -4,14 +4,14 @@ import ( "context" "fmt" - sdk "github.com/cosmos/cosmos-sdk/types" + cosmostypes "github.com/cosmos/cosmos-sdk/types" "github.com/pokt-network/poktroll/x/shared" "github.com/pokt-network/poktroll/x/supplier/types" ) // EndBlockerUnbondSupplier unbonds suppliers that have finished the unbonding period. func (k Keeper) EndBlockerUnbondSupplier(ctx context.Context) error { - sdkCtx := sdk.UnwrapSDKContext(ctx) + sdkCtx := cosmostypes.UnwrapSDKContext(ctx) currentHeight := sdkCtx.BlockHeight() sharedParams := k.sharedKeeper.GetParams(ctx) sessionEndHeight := shared.GetSessionEndHeight(&sharedParams, currentHeight) @@ -38,7 +38,7 @@ func (k Keeper) EndBlockerUnbondSupplier(ctx context.Context) error { if unbondingHeight <= uint64(currentHeight) { // Retrieve the address of the supplier. - supplierAddress, err := sdk.AccAddressFromBech32(supplier.Address) + supplierAddress, err := cosmostypes.AccAddressFromBech32(supplier.Address) if err != nil { logger.Error(fmt.Sprintf("could not parse address %s", supplier.Address)) return err @@ -46,7 +46,7 @@ func (k Keeper) EndBlockerUnbondSupplier(ctx context.Context) error { // Send the coins from the supplier pool back to the supplier. if err = k.bankKeeper.SendCoinsFromModuleToAccount( - ctx, types.ModuleName, supplierAddress, []sdk.Coin{*supplier.Stake}, + ctx, types.ModuleName, supplierAddress, []cosmostypes.Coin{*supplier.Stake}, ); err != nil { logger.Error(fmt.Sprintf( "could not send %v coins from %s module to %s account due to %v", From 1f2da17b7a362c07c37a1f85aeea97c6459bcccf Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Wed, 17 Jul 2024 02:50:10 +0200 Subject: [PATCH 09/13] refactor: Use proof window end as unbonding period --- api/poktroll/supplier/params.pulsar.go | 72 +------------------ e2e/tests/init_test.go | 15 ++-- proto/poktroll/supplier/params.proto | 4 -- x/session/keeper/session_hydrator.go | 3 +- .../msg_server_unstake_supplier_test.go | 6 +- x/supplier/keeper/msg_update_params_test.go | 14 +--- x/supplier/keeper/unbond_suppliers.go | 28 +++++--- x/supplier/types/genesis_test.go | 52 -------------- x/supplier/types/params.go | 45 ++---------- x/supplier/types/params.pb.go | 61 +++------------- 10 files changed, 51 insertions(+), 249 deletions(-) diff --git a/api/poktroll/supplier/params.pulsar.go b/api/poktroll/supplier/params.pulsar.go index 44ff49feb..7108db140 100644 --- a/api/poktroll/supplier/params.pulsar.go +++ b/api/poktroll/supplier/params.pulsar.go @@ -15,14 +15,12 @@ import ( ) var ( - md_Params protoreflect.MessageDescriptor - fd_Params_supplier_unbonding_period_blocks protoreflect.FieldDescriptor + md_Params protoreflect.MessageDescriptor ) func init() { file_poktroll_supplier_params_proto_init() md_Params = File_poktroll_supplier_params_proto.Messages().ByName("Params") - fd_Params_supplier_unbonding_period_blocks = md_Params.Fields().ByName("supplier_unbonding_period_blocks") } var _ protoreflect.Message = (*fastReflection_Params)(nil) @@ -90,12 +88,6 @@ func (x *fastReflection_Params) Interface() protoreflect.ProtoMessage { // While iterating, mutating operations may only be performed // on the current field descriptor. func (x *fastReflection_Params) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { - if x.SupplierUnbondingPeriodBlocks != uint64(0) { - value := protoreflect.ValueOfUint64(x.SupplierUnbondingPeriodBlocks) - if !f(fd_Params_supplier_unbonding_period_blocks, value) { - return - } - } } // Has reports whether a field is populated. @@ -111,8 +103,6 @@ func (x *fastReflection_Params) Range(f func(protoreflect.FieldDescriptor, proto // a repeated field is populated if it is non-empty. func (x *fastReflection_Params) Has(fd protoreflect.FieldDescriptor) bool { switch fd.FullName() { - case "poktroll.supplier.Params.supplier_unbonding_period_blocks": - return x.SupplierUnbondingPeriodBlocks != uint64(0) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.supplier.Params")) @@ -129,8 +119,6 @@ func (x *fastReflection_Params) Has(fd protoreflect.FieldDescriptor) bool { // Clear is a mutating operation and unsafe for concurrent use. func (x *fastReflection_Params) Clear(fd protoreflect.FieldDescriptor) { switch fd.FullName() { - case "poktroll.supplier.Params.supplier_unbonding_period_blocks": - x.SupplierUnbondingPeriodBlocks = uint64(0) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.supplier.Params")) @@ -147,9 +135,6 @@ func (x *fastReflection_Params) Clear(fd protoreflect.FieldDescriptor) { // of the value; to obtain a mutable reference, use Mutable. func (x *fastReflection_Params) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { switch descriptor.FullName() { - case "poktroll.supplier.Params.supplier_unbonding_period_blocks": - value := x.SupplierUnbondingPeriodBlocks - return protoreflect.ValueOfUint64(value) default: if descriptor.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.supplier.Params")) @@ -170,8 +155,6 @@ func (x *fastReflection_Params) Get(descriptor protoreflect.FieldDescriptor) pro // Set is a mutating operation and unsafe for concurrent use. func (x *fastReflection_Params) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { switch fd.FullName() { - case "poktroll.supplier.Params.supplier_unbonding_period_blocks": - x.SupplierUnbondingPeriodBlocks = value.Uint() default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.supplier.Params")) @@ -192,8 +175,6 @@ func (x *fastReflection_Params) Set(fd protoreflect.FieldDescriptor, value proto // Mutable is a mutating operation and unsafe for concurrent use. func (x *fastReflection_Params) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { switch fd.FullName() { - case "poktroll.supplier.Params.supplier_unbonding_period_blocks": - panic(fmt.Errorf("field supplier_unbonding_period_blocks of message poktroll.supplier.Params is not mutable")) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.supplier.Params")) @@ -207,8 +188,6 @@ func (x *fastReflection_Params) Mutable(fd protoreflect.FieldDescriptor) protore // For lists, maps, and messages, this returns a new, empty, mutable value. func (x *fastReflection_Params) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { switch fd.FullName() { - case "poktroll.supplier.Params.supplier_unbonding_period_blocks": - return protoreflect.ValueOfUint64(uint64(0)) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.supplier.Params")) @@ -278,9 +257,6 @@ func (x *fastReflection_Params) ProtoMethods() *protoiface.Methods { var n int var l int _ = l - if x.SupplierUnbondingPeriodBlocks != 0 { - n += 1 + runtime.Sov(uint64(x.SupplierUnbondingPeriodBlocks)) - } if x.unknownFields != nil { n += len(x.unknownFields) } @@ -310,11 +286,6 @@ func (x *fastReflection_Params) ProtoMethods() *protoiface.Methods { i -= len(x.unknownFields) copy(dAtA[i:], x.unknownFields) } - if x.SupplierUnbondingPeriodBlocks != 0 { - i = runtime.EncodeVarint(dAtA, i, uint64(x.SupplierUnbondingPeriodBlocks)) - i-- - dAtA[i] = 0x38 - } if input.Buf != nil { input.Buf = append(input.Buf, dAtA...) } else { @@ -364,25 +335,6 @@ func (x *fastReflection_Params) ProtoMethods() *protoiface.Methods { return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { - case 7: - if wireType != 0 { - return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field SupplierUnbondingPeriodBlocks", wireType) - } - x.SupplierUnbondingPeriodBlocks = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow - } - if iNdEx >= l { - return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - x.SupplierUnbondingPeriodBlocks |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } default: iNdEx = preIndex skippy, err := runtime.Skip(dAtA[iNdEx:]) @@ -436,10 +388,6 @@ type Params struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - - // supplier_unbonding_period_blocks is the number of blocks that a supplier must wait - // after unstaking before they can withdraw their staked tokens. - SupplierUnbondingPeriodBlocks uint64 `protobuf:"varint,7,opt,name=supplier_unbonding_period_blocks,json=supplierUnbondingPeriodBlocks,proto3" json:"supplier_unbonding_period_blocks,omitempty"` } func (x *Params) Reset() { @@ -462,13 +410,6 @@ func (*Params) Descriptor() ([]byte, []int) { return file_poktroll_supplier_params_proto_rawDescGZIP(), []int{0} } -func (x *Params) GetSupplierUnbondingPeriodBlocks() uint64 { - if x != nil { - return x.SupplierUnbondingPeriodBlocks - } - return 0 -} - var File_poktroll_supplier_params_proto protoreflect.FileDescriptor var file_poktroll_supplier_params_proto_rawDesc = []byte{ @@ -477,15 +418,8 @@ var file_poktroll_supplier_params_proto_rawDesc = []byte{ 0x12, 0x11, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x73, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x1a, 0x11, 0x61, 0x6d, 0x69, 0x6e, 0x6f, 0x2f, 0x61, 0x6d, 0x69, 0x6e, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x14, 0x67, 0x6f, 0x67, 0x6f, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2f, 0x67, 0x6f, 0x67, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x9c, 0x01, 0x0a, - 0x06, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x6d, 0x0a, 0x20, 0x73, 0x75, 0x70, 0x70, 0x6c, - 0x69, 0x65, 0x72, 0x5f, 0x75, 0x6e, 0x62, 0x6f, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x70, 0x65, - 0x72, 0x69, 0x6f, 0x64, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, - 0x04, 0x42, 0x24, 0xea, 0xde, 0x1f, 0x20, 0x73, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x5f, - 0x75, 0x6e, 0x62, 0x6f, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, - 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x1d, 0x73, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, - 0x72, 0x55, 0x6e, 0x62, 0x6f, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x3a, 0x23, 0xe8, 0xa0, 0x1f, 0x01, 0x8a, 0xe7, 0xb0, 0x2a, + 0x6f, 0x2f, 0x67, 0x6f, 0x67, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x2d, 0x0a, 0x06, + 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x3a, 0x23, 0xe8, 0xa0, 0x1f, 0x01, 0x8a, 0xe7, 0xb0, 0x2a, 0x1a, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2f, 0x78, 0x2f, 0x73, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x2f, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x42, 0xad, 0x01, 0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x73, 0x75, 0x70, diff --git a/e2e/tests/init_test.go b/e2e/tests/init_test.go index 177218145..399ddcb3b 100644 --- a/e2e/tests/init_test.go +++ b/e2e/tests/init_test.go @@ -36,6 +36,7 @@ import ( apptypes "github.com/pokt-network/poktroll/x/application/types" prooftypes "github.com/pokt-network/poktroll/x/proof/types" sessiontypes "github.com/pokt-network/poktroll/x/session/types" + shared "github.com/pokt-network/poktroll/x/shared" sharedtypes "github.com/pokt-network/poktroll/x/shared/types" suppliertypes "github.com/pokt-network/poktroll/x/supplier/types" ) @@ -461,7 +462,7 @@ func (s *suite) TheUserWaitsForUnbondingPeriodToFinish(accName string) { require.True(s, ok, "supplier %s not found", accName) unbondingHeight := s.getSupplierUnbondingHeight(accName) - s.waitForBlockHeight(int64(unbondingHeight)) + s.waitForBlockHeight(unbondingHeight) } func (s *suite) getStakedAmount(actorType, accName string) (int, bool) { @@ -609,12 +610,12 @@ func (s *suite) getSupplierInfo(supplierAddr string) *sharedtypes.Supplier { } // getSupplierUnbondingHeight returns the height at which the supplier will be unbonded. -func (s *suite) getSupplierUnbondingHeight(accName string) uint64 { +func (s *suite) getSupplierUnbondingHeight(accName string) int64 { supplier := s.getSupplierInfo(accName) args := []string{ "query", - "supplier", + "shared", "params", "--output=json", } @@ -622,10 +623,14 @@ func (s *suite) getSupplierUnbondingHeight(accName string) uint64 { res, err := s.pocketd.RunCommandOnHostWithRetry("", numQueryRetries, args...) require.NoError(s, err, "error getting supplier module params") - var resp suppliertypes.QueryParamsResponse + var resp sharedtypes.QueryParamsResponse responseBz := []byte(strings.TrimSpace(res.Stdout)) s.cdc.MustUnmarshalJSON(responseBz, &resp) - return supplier.UnstakeCommitSessionEndHeight + resp.Params.SupplierUnbondingPeriodBlocks + windowCloseHeight := shared.GetProofWindowCloseHeight( + &resp.Params, + int64(supplier.UnstakeCommitSessionEndHeight), + ) + return windowCloseHeight } // TODO_IMPROVE: use `sessionId` and `supplierName` since those are the two values diff --git a/proto/poktroll/supplier/params.proto b/proto/poktroll/supplier/params.proto index 705778509..a27a7ba7c 100644 --- a/proto/poktroll/supplier/params.proto +++ b/proto/poktroll/supplier/params.proto @@ -10,8 +10,4 @@ import "gogoproto/gogo.proto"; message Params { option (amino.name) = "poktroll/x/supplier/Params"; option (gogoproto.equal) = true; - - // supplier_unbonding_period_blocks is the number of blocks that a supplier must wait - // after unstaking before they can withdraw their staked tokens. - uint64 supplier_unbonding_period_blocks = 7 [(gogoproto.jsontag) = "supplier_unbonding_period_blocks"]; } \ No newline at end of file diff --git a/x/session/keeper/session_hydrator.go b/x/session/keeper/session_hydrator.go index 07ccd90fd..c520097d4 100644 --- a/x/session/keeper/session_hydrator.go +++ b/x/session/keeper/session_hydrator.go @@ -16,6 +16,7 @@ import ( "github.com/pokt-network/poktroll/x/shared" sharedhelpers "github.com/pokt-network/poktroll/x/shared/helpers" sharedtypes "github.com/pokt-network/poktroll/x/shared/types" + suppliertypes "github.com/pokt-network/poktroll/x/supplier/types" ) var SHA3HashLen = crypto.SHA3_256.Size() @@ -175,7 +176,7 @@ func (k Keeper) hydrateSessionSuppliers(ctx context.Context, sh *sessionHydrator // Exclude suppliers that are in an unbonding period. // TODO_TECHDEBT: Suppliers that stake mid-session SHOULD NOT be included // in the current session's suppliers list and must wait until the next one. - if s.UnstakeCommitSessionEndHeight != 0 && + if s.UnstakeCommitSessionEndHeight != suppliertypes.SupplierNotUnstaking && uint64(sh.sessionHeader.SessionEndBlockHeight) > s.UnstakeCommitSessionEndHeight { continue } diff --git a/x/supplier/keeper/msg_server_unstake_supplier_test.go b/x/supplier/keeper/msg_server_unstake_supplier_test.go index ce1017f23..35f010834 100644 --- a/x/supplier/keeper/msg_server_unstake_supplier_test.go +++ b/x/supplier/keeper/msg_server_unstake_supplier_test.go @@ -50,8 +50,8 @@ func TestMsgServer_UnstakeSupplier_Success(t *testing.T) { require.NotEqual(t, foundSupplier.UnstakeCommitSessionEndHeight, types.SupplierNotUnstaking) // Move block height to the end of the unbonding period - unbondingHeight := foundSupplier.UnstakeCommitSessionEndHeight + k.GetParams(ctx).SupplierUnbondingPeriodBlocks - ctx = keepertest.SetBlockHeight(ctx, int64(unbondingHeight)) + unbondingHeight := k.GetSupplierUnbondingHeight(ctx, &foundSupplier) + ctx = keepertest.SetBlockHeight(ctx, unbondingHeight) // Run the endblocker to unbond the supplier err = k.EndBlockerUnbondSupplier(ctx) @@ -91,7 +91,7 @@ func TestMsgServer_UnstakeSupplier_CancelUnbondingIfRestaked(t *testing.T) { require.True(t, isSupplierFound) require.NotEqual(t, foundSupplier.UnstakeCommitSessionEndHeight, types.SupplierNotUnstaking) - unbondingHeight := foundSupplier.UnstakeCommitSessionEndHeight + k.GetParams(ctx).SupplierUnbondingPeriodBlocks + unbondingHeight := k.GetSupplierUnbondingHeight(ctx, &foundSupplier) // Stake the supplier again stakeMsg = createStakeMsg(supplierAddr, initialStake+1) diff --git a/x/supplier/keeper/msg_update_params_test.go b/x/supplier/keeper/msg_update_params_test.go index f8984d7f8..9efd6db7d 100644 --- a/x/supplier/keeper/msg_update_params_test.go +++ b/x/supplier/keeper/msg_update_params_test.go @@ -30,22 +30,12 @@ func TestMsgUpdateParams(t *testing.T) { expectedErrMsg: "invalid authority", }, { - desc: "invalid: send empty params", + desc: "send empty params", params: &types.MsgUpdateParams{ Authority: k.GetAuthority(), Params: types.Params{}, }, - shouldError: true, - }, - { - desc: "invalid: Zero SupplierUnbondingPeriodBlocks", - params: &types.MsgUpdateParams{ - Authority: k.GetAuthority(), - Params: types.Params{ - SupplierUnbondingPeriodBlocks: 0, - }, - }, - shouldError: true, + shouldError: false, }, { desc: "valid: send default params", diff --git a/x/supplier/keeper/unbond_suppliers.go b/x/supplier/keeper/unbond_suppliers.go index 18bbbc3c6..d1ecccb68 100644 --- a/x/supplier/keeper/unbond_suppliers.go +++ b/x/supplier/keeper/unbond_suppliers.go @@ -6,6 +6,7 @@ import ( cosmostypes "github.com/cosmos/cosmos-sdk/types" "github.com/pokt-network/poktroll/x/shared" + sharedtypes "github.com/pokt-network/poktroll/x/shared/types" "github.com/pokt-network/poktroll/x/supplier/types" ) @@ -13,13 +14,6 @@ import ( func (k Keeper) EndBlockerUnbondSupplier(ctx context.Context) error { sdkCtx := cosmostypes.UnwrapSDKContext(ctx) currentHeight := sdkCtx.BlockHeight() - sharedParams := k.sharedKeeper.GetParams(ctx) - sessionEndHeight := shared.GetSessionEndHeight(&sharedParams, currentHeight) - - // Only process unbonding at the end of the session. - if currentHeight != sessionEndHeight { - return nil - } logger := k.Logger().With("method", "UnbondSupplier") @@ -28,14 +22,13 @@ func (k Keeper) EndBlockerUnbondSupplier(ctx context.Context) error { // unbonding action instead of iterating over all suppliers. for _, supplier := range k.GetAllSuppliers(ctx) { // Ignore suppliers that have not initiated the unbonding action. - if supplier.UnstakeCommitSessionEndHeight == 0 { + if supplier.UnstakeCommitSessionEndHeight == types.SupplierNotUnstaking { continue } - unbondingPeriodBlocks := k.GetParams(ctx).SupplierUnbondingPeriodBlocks - unbondingHeight := supplier.UnstakeCommitSessionEndHeight + unbondingPeriodBlocks + unbondingHeight := k.GetSupplierUnbondingHeight(ctx, &supplier) - if unbondingHeight <= uint64(currentHeight) { + if unbondingHeight <= currentHeight { // Retrieve the address of the supplier. supplierAddress, err := cosmostypes.AccAddressFromBech32(supplier.Address) @@ -63,3 +56,16 @@ func (k Keeper) EndBlockerUnbondSupplier(ctx context.Context) error { return nil } + +// GetSupplierUnbondingHeight returns the height at which the supplier can be unbonded. +func (k Keeper) GetSupplierUnbondingHeight( + ctx context.Context, + supplier *sharedtypes.Supplier, +) int64 { + sharedParams := k.sharedKeeper.GetParams(ctx) + + return shared.GetProofWindowCloseHeight( + &sharedParams, + int64(supplier.UnstakeCommitSessionEndHeight), + ) +} diff --git a/x/supplier/types/genesis_test.go b/x/supplier/types/genesis_test.go index a6c1b1e7c..6898d96d3 100644 --- a/x/supplier/types/genesis_test.go +++ b/x/supplier/types/genesis_test.go @@ -13,7 +13,6 @@ import ( ) func TestGenesisState_Validate(t *testing.T) { - defaultParams := types.DefaultParams() addr1 := sample.AccAddress() stake1 := sdk.NewCoin("upokt", math.NewInt(100)) serviceConfig1 := &sharedtypes.SupplierServiceConfig{ @@ -59,7 +58,6 @@ func TestGenesisState_Validate(t *testing.T) { { desc: "valid genesis state", genState: &types.GenesisState{ - Params: defaultParams, SupplierList: []sharedtypes.Supplier{ { Address: addr1, @@ -79,7 +77,6 @@ func TestGenesisState_Validate(t *testing.T) { { desc: "invalid - zero supplier stake", genState: &types.GenesisState{ - Params: defaultParams, SupplierList: []sharedtypes.Supplier{ { Address: addr1, @@ -98,7 +95,6 @@ func TestGenesisState_Validate(t *testing.T) { { desc: "invalid - negative supplier stake", genState: &types.GenesisState{ - Params: defaultParams, SupplierList: []sharedtypes.Supplier{ { Address: addr1, @@ -117,7 +113,6 @@ func TestGenesisState_Validate(t *testing.T) { { desc: "invalid - wrong stake denom", genState: &types.GenesisState{ - Params: defaultParams, SupplierList: []sharedtypes.Supplier{ { Address: addr1, @@ -136,7 +131,6 @@ func TestGenesisState_Validate(t *testing.T) { { desc: "invalid - missing denom", genState: &types.GenesisState{ - Params: defaultParams, SupplierList: []sharedtypes.Supplier{ { Address: addr1, @@ -155,7 +149,6 @@ func TestGenesisState_Validate(t *testing.T) { { desc: "invalid - due to duplicated supplier address", genState: &types.GenesisState{ - Params: defaultParams, SupplierList: []sharedtypes.Supplier{ { Address: addr1, @@ -174,7 +167,6 @@ func TestGenesisState_Validate(t *testing.T) { { desc: "invalid - due to nil supplier stake", genState: &types.GenesisState{ - Params: defaultParams, SupplierList: []sharedtypes.Supplier{ { Address: addr1, @@ -193,7 +185,6 @@ func TestGenesisState_Validate(t *testing.T) { { desc: "invalid - due to missing supplier stake", genState: &types.GenesisState{ - Params: defaultParams, SupplierList: []sharedtypes.Supplier{ { Address: addr1, @@ -212,7 +203,6 @@ func TestGenesisState_Validate(t *testing.T) { { desc: "invalid - missing services list", genState: &types.GenesisState{ - Params: defaultParams, SupplierList: []sharedtypes.Supplier{ { Address: addr1, @@ -231,7 +221,6 @@ func TestGenesisState_Validate(t *testing.T) { { desc: "invalid - empty services list", genState: &types.GenesisState{ - Params: defaultParams, SupplierList: []sharedtypes.Supplier{ { Address: addr1, @@ -250,7 +239,6 @@ func TestGenesisState_Validate(t *testing.T) { { desc: "invalid - invalid URL", genState: &types.GenesisState{ - Params: defaultParams, SupplierList: []sharedtypes.Supplier{ { Address: addr1, @@ -282,7 +270,6 @@ func TestGenesisState_Validate(t *testing.T) { { desc: "invalid - invalid RPC Type", genState: &types.GenesisState{ - Params: defaultParams, SupplierList: []sharedtypes.Supplier{ { Address: addr1, @@ -311,45 +298,6 @@ func TestGenesisState_Validate(t *testing.T) { }, isValid: false, }, - { - desc: "invalid - missing params", - genState: &types.GenesisState{ - SupplierList: []sharedtypes.Supplier{ - { - Address: addr1, - Stake: &stake1, - Services: serviceList1, - }, - { - Address: addr2, - Stake: &stake2, - Services: serviceList2, - }, - }, - }, - isValid: false, - }, - { - desc: "invalid - zero supplier unbonding period blocks", - genState: &types.GenesisState{ - Params: types.Params{ - SupplierUnbondingPeriodBlocks: 0, - }, - SupplierList: []sharedtypes.Supplier{ - { - Address: addr1, - Stake: &stake1, - Services: serviceList1, - }, - { - Address: addr2, - Stake: &stake2, - Services: serviceList2, - }, - }, - }, - isValid: false, - }, // this line is used by starport scaffolding # types/genesis/testcase } for _, test := range tests { diff --git a/x/supplier/types/params.go b/x/supplier/types/params.go index b932f8ade..0b099f495 100644 --- a/x/supplier/types/params.go +++ b/x/supplier/types/params.go @@ -1,16 +1,10 @@ package types -import ( - paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" -) +import paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" var ( - _ paramtypes.ParamSet = (*Params)(nil) - - KeySupplierUnbondingPeriodBlocks = []byte("SupplierUnbondingPeriodBlocks") - ParamSupplierUnbondingPeriodBlocks = "supplier_unbonding_period_blocks" - DefaultSupplierUnbondingPeriodBlocks uint64 = 4 // TODO_MAINNET: Determine the default value. - SupplierNotUnstaking uint64 = 0 + _ paramtypes.ParamSet = (*Params)(nil) + SupplierNotUnstaking uint64 = 0 ) // ParamKeyTable the param key table for launch module @@ -20,9 +14,7 @@ func ParamKeyTable() paramtypes.KeyTable { // NewParams creates a new Params instance func NewParams() Params { - return Params{ - SupplierUnbondingPeriodBlocks: DefaultSupplierUnbondingPeriodBlocks, - } + return Params{} } // DefaultParams returns a default set of parameters @@ -32,37 +24,10 @@ func DefaultParams() Params { // ParamSetPairs get the params.ParamSet func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { - return paramtypes.ParamSetPairs{ - paramtypes.NewParamSetPair( - KeySupplierUnbondingPeriodBlocks, - &p.SupplierUnbondingPeriodBlocks, - ValidateSupplierUnbondingPeriodBlocks, - ), - } + return paramtypes.ParamSetPairs{} } // Validate validates the set of params func (p Params) Validate() error { - // Validate the SupplierUnbondingPeriodBlocks - if err := ValidateSupplierUnbondingPeriodBlocks(p.SupplierUnbondingPeriodBlocks); err != nil { - return err - } - - return nil -} - -// ValidateSupplierUnbondingPeriodBlocks validates the SupplierUnbondingPeriodBlocks -// governance parameter. -// NB: The argument is an interface type to satisfy the ParamSetPair function signature. -func ValidateSupplierUnbondingPeriodBlocks(v interface{}) error { - supplierUnbondingPeriodBlocks, ok := v.(uint64) - if !ok { - return ErrSupplierParamsInvalid.Wrapf("invalid parameter type: %T", v) - } - - if supplierUnbondingPeriodBlocks == SupplierNotUnstaking { - return ErrSupplierParamsInvalid.Wrapf("invalid SupplierUnbondingPeriodBlocks: (%v)", supplierUnbondingPeriodBlocks) - } - return nil } diff --git a/x/supplier/types/params.pb.go b/x/supplier/types/params.pb.go index 31879f4c1..a80ba2f9c 100644 --- a/x/supplier/types/params.pb.go +++ b/x/supplier/types/params.pb.go @@ -26,9 +26,6 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // Params defines the parameters for the module. type Params struct { - // supplier_unbonding_period_blocks is the number of blocks that a supplier must wait - // after unstaking before they can withdraw their staked tokens. - SupplierUnbondingPeriodBlocks uint64 `protobuf:"varint,7,opt,name=supplier_unbonding_period_blocks,json=supplierUnbondingPeriodBlocks,proto3" json:"supplier_unbonding_period_blocks"` } func (m *Params) Reset() { *m = Params{} } @@ -64,13 +61,6 @@ func (m *Params) XXX_DiscardUnknown() { var xxx_messageInfo_Params proto.InternalMessageInfo -func (m *Params) GetSupplierUnbondingPeriodBlocks() uint64 { - if m != nil { - return m.SupplierUnbondingPeriodBlocks - } - return 0 -} - func init() { proto.RegisterType((*Params)(nil), "poktroll.supplier.Params") } @@ -78,22 +68,19 @@ func init() { func init() { proto.RegisterFile("poktroll/supplier/params.proto", fileDescriptor_60f7a8031a8c22d5) } var fileDescriptor_60f7a8031a8c22d5 = []byte{ - // 235 bytes of a gzipped FileDescriptorProto + // 177 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x2b, 0xc8, 0xcf, 0x2e, 0x29, 0xca, 0xcf, 0xc9, 0xd1, 0x2f, 0x2e, 0x2d, 0x28, 0xc8, 0xc9, 0x4c, 0x2d, 0xd2, 0x2f, 0x48, 0x2c, 0x4a, 0xcc, 0x2d, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x84, 0xc9, 0xeb, 0xc1, 0xe4, 0xa5, 0x04, 0x13, 0x73, 0x33, 0xf3, 0xf2, 0xf5, 0xc1, 0x24, 0x44, 0x95, 0x94, 0x48, 0x7a, - 0x7e, 0x7a, 0x3e, 0x98, 0xa9, 0x0f, 0x62, 0x41, 0x44, 0x95, 0xe6, 0x30, 0x72, 0xb1, 0x05, 0x80, - 0x0d, 0x13, 0xca, 0xe5, 0x52, 0x80, 0xe9, 0x8f, 0x2f, 0xcd, 0x4b, 0xca, 0xcf, 0x4b, 0xc9, 0xcc, - 0x4b, 0x8f, 0x2f, 0x48, 0x2d, 0xca, 0xcc, 0x4f, 0x89, 0x4f, 0xca, 0xc9, 0x4f, 0xce, 0x2e, 0x96, - 0x60, 0x57, 0x60, 0xd4, 0x60, 0x71, 0x52, 0x79, 0x75, 0x4f, 0x9e, 0xa0, 0xda, 0x20, 0x59, 0x98, - 0x8a, 0x50, 0x98, 0x82, 0x00, 0xb0, 0xbc, 0x13, 0x58, 0xda, 0x4a, 0xf9, 0xc5, 0x02, 0x79, 0xc6, - 0xae, 0xe7, 0x1b, 0xb4, 0xa4, 0xe0, 0xde, 0xab, 0x40, 0x78, 0x10, 0xe2, 0x26, 0x27, 0xef, 0x13, - 0x8f, 0xe4, 0x18, 0x2f, 0x3c, 0x92, 0x63, 0x7c, 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, 0x39, 0x86, - 0x0b, 0x8f, 0xe5, 0x18, 0x6e, 0x3c, 0x96, 0x63, 0x88, 0x32, 0x4c, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, - 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x07, 0x19, 0xa0, 0x9b, 0x97, 0x5a, 0x52, 0x9e, 0x5f, 0x94, 0xad, - 0x8f, 0xcd, 0xb4, 0x92, 0xca, 0x82, 0xd4, 0xe2, 0x24, 0x36, 0xb0, 0x97, 0x8d, 0x01, 0x01, 0x00, - 0x00, 0xff, 0xff, 0xbe, 0xe1, 0x32, 0x17, 0x50, 0x01, 0x00, 0x00, + 0x7e, 0x7a, 0x3e, 0x98, 0xa9, 0x0f, 0x62, 0x41, 0x44, 0x95, 0x74, 0xb9, 0xd8, 0x02, 0xc0, 0x66, + 0x59, 0x29, 0xbf, 0x58, 0x20, 0xcf, 0xd8, 0xf5, 0x7c, 0x83, 0x96, 0x14, 0xdc, 0xba, 0x0a, 0x84, + 0x85, 0x10, 0x45, 0x4e, 0xde, 0x27, 0x1e, 0xc9, 0x31, 0x5e, 0x78, 0x24, 0xc7, 0xf8, 0xe0, 0x91, + 0x1c, 0xe3, 0x84, 0xc7, 0x72, 0x0c, 0x17, 0x1e, 0xcb, 0x31, 0xdc, 0x78, 0x2c, 0xc7, 0x10, 0x65, + 0x98, 0x9e, 0x59, 0x92, 0x51, 0x9a, 0xa4, 0x97, 0x9c, 0x9f, 0xab, 0x0f, 0x32, 0x40, 0x37, 0x2f, + 0xb5, 0xa4, 0x3c, 0xbf, 0x28, 0x5b, 0x1f, 0x9b, 0x69, 0x25, 0x95, 0x05, 0xa9, 0xc5, 0x49, 0x6c, + 0x60, 0x27, 0x18, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0x98, 0x12, 0x64, 0x47, 0xe0, 0x00, 0x00, + 0x00, } func (this *Params) Equal(that interface{}) bool { @@ -115,9 +102,6 @@ func (this *Params) Equal(that interface{}) bool { } else if this == nil { return false } - if this.SupplierUnbondingPeriodBlocks != that1.SupplierUnbondingPeriodBlocks { - return false - } return true } func (m *Params) Marshal() (dAtA []byte, err error) { @@ -140,11 +124,6 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.SupplierUnbondingPeriodBlocks != 0 { - i = encodeVarintParams(dAtA, i, uint64(m.SupplierUnbondingPeriodBlocks)) - i-- - dAtA[i] = 0x38 - } return len(dAtA) - i, nil } @@ -165,9 +144,6 @@ func (m *Params) Size() (n int) { } var l int _ = l - if m.SupplierUnbondingPeriodBlocks != 0 { - n += 1 + sovParams(uint64(m.SupplierUnbondingPeriodBlocks)) - } return n } @@ -206,25 +182,6 @@ func (m *Params) Unmarshal(dAtA []byte) error { return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { - case 7: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field SupplierUnbondingPeriodBlocks", wireType) - } - m.SupplierUnbondingPeriodBlocks = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowParams - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.SupplierUnbondingPeriodBlocks |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } default: iNdEx = preIndex skippy, err := skipParams(dAtA[iNdEx:]) From f4b5c9551db596e430ce85532f459aa1e5ff874c Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Thu, 18 Jul 2024 23:00:20 +0200 Subject: [PATCH 10/13] chore: Address review change requests --- api/poktroll/shared/supplier.pulsar.go | 97 +++++++++---------- e2e/tests/init_test.go | 15 +-- proto/poktroll/shared/supplier.proto | 6 +- testutil/keeper/supplier.go | 10 +- x/session/keeper/session_hydrator.go | 8 +- x/shared/supplier.go | 12 +++ x/shared/types/supplier.go | 13 +++ x/shared/types/supplier.pb.go | 68 ++++++------- .../keeper/msg_server_stake_supplier.go | 2 +- .../keeper/msg_server_unstake_supplier.go | 4 +- .../msg_server_unstake_supplier_test.go | 54 +++++++---- x/supplier/keeper/unbond_suppliers.go | 17 ++-- x/supplier/module/abci.go | 2 +- x/supplier/types/params.go | 5 +- 14 files changed, 169 insertions(+), 144 deletions(-) create mode 100644 x/shared/supplier.go create mode 100644 x/shared/types/supplier.go diff --git a/api/poktroll/shared/supplier.pulsar.go b/api/poktroll/shared/supplier.pulsar.go index 05dc8e807..bc0dae789 100644 --- a/api/poktroll/shared/supplier.pulsar.go +++ b/api/poktroll/shared/supplier.pulsar.go @@ -66,11 +66,11 @@ func (x *_Supplier_3_list) IsValid() bool { } var ( - md_Supplier protoreflect.MessageDescriptor - fd_Supplier_address protoreflect.FieldDescriptor - fd_Supplier_stake protoreflect.FieldDescriptor - fd_Supplier_services protoreflect.FieldDescriptor - fd_Supplier_unstake_commit_session_end_height protoreflect.FieldDescriptor + md_Supplier protoreflect.MessageDescriptor + fd_Supplier_address protoreflect.FieldDescriptor + fd_Supplier_stake protoreflect.FieldDescriptor + fd_Supplier_services protoreflect.FieldDescriptor + fd_Supplier_unstake_session_end_height protoreflect.FieldDescriptor ) func init() { @@ -79,7 +79,7 @@ func init() { fd_Supplier_address = md_Supplier.Fields().ByName("address") fd_Supplier_stake = md_Supplier.Fields().ByName("stake") fd_Supplier_services = md_Supplier.Fields().ByName("services") - fd_Supplier_unstake_commit_session_end_height = md_Supplier.Fields().ByName("unstake_commit_session_end_height") + fd_Supplier_unstake_session_end_height = md_Supplier.Fields().ByName("unstake_session_end_height") } var _ protoreflect.Message = (*fastReflection_Supplier)(nil) @@ -165,9 +165,9 @@ func (x *fastReflection_Supplier) Range(f func(protoreflect.FieldDescriptor, pro return } } - if x.UnstakeCommitSessionEndHeight != uint64(0) { - value := protoreflect.ValueOfUint64(x.UnstakeCommitSessionEndHeight) - if !f(fd_Supplier_unstake_commit_session_end_height, value) { + if x.UnstakeSessionEndHeight != uint64(0) { + value := protoreflect.ValueOfUint64(x.UnstakeSessionEndHeight) + if !f(fd_Supplier_unstake_session_end_height, value) { return } } @@ -192,8 +192,8 @@ func (x *fastReflection_Supplier) Has(fd protoreflect.FieldDescriptor) bool { return x.Stake != nil case "poktroll.shared.Supplier.services": return len(x.Services) != 0 - case "poktroll.shared.Supplier.unstake_commit_session_end_height": - return x.UnstakeCommitSessionEndHeight != uint64(0) + case "poktroll.shared.Supplier.unstake_session_end_height": + return x.UnstakeSessionEndHeight != uint64(0) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.shared.Supplier")) @@ -216,8 +216,8 @@ func (x *fastReflection_Supplier) Clear(fd protoreflect.FieldDescriptor) { x.Stake = nil case "poktroll.shared.Supplier.services": x.Services = nil - case "poktroll.shared.Supplier.unstake_commit_session_end_height": - x.UnstakeCommitSessionEndHeight = uint64(0) + case "poktroll.shared.Supplier.unstake_session_end_height": + x.UnstakeSessionEndHeight = uint64(0) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.shared.Supplier")) @@ -246,8 +246,8 @@ func (x *fastReflection_Supplier) Get(descriptor protoreflect.FieldDescriptor) p } listValue := &_Supplier_3_list{list: &x.Services} return protoreflect.ValueOfList(listValue) - case "poktroll.shared.Supplier.unstake_commit_session_end_height": - value := x.UnstakeCommitSessionEndHeight + case "poktroll.shared.Supplier.unstake_session_end_height": + value := x.UnstakeSessionEndHeight return protoreflect.ValueOfUint64(value) default: if descriptor.IsExtension() { @@ -277,8 +277,8 @@ func (x *fastReflection_Supplier) Set(fd protoreflect.FieldDescriptor, value pro lv := value.List() clv := lv.(*_Supplier_3_list) x.Services = *clv.list - case "poktroll.shared.Supplier.unstake_commit_session_end_height": - x.UnstakeCommitSessionEndHeight = value.Uint() + case "poktroll.shared.Supplier.unstake_session_end_height": + x.UnstakeSessionEndHeight = value.Uint() default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.shared.Supplier")) @@ -312,8 +312,8 @@ func (x *fastReflection_Supplier) Mutable(fd protoreflect.FieldDescriptor) proto return protoreflect.ValueOfList(value) case "poktroll.shared.Supplier.address": panic(fmt.Errorf("field address of message poktroll.shared.Supplier is not mutable")) - case "poktroll.shared.Supplier.unstake_commit_session_end_height": - panic(fmt.Errorf("field unstake_commit_session_end_height of message poktroll.shared.Supplier is not mutable")) + case "poktroll.shared.Supplier.unstake_session_end_height": + panic(fmt.Errorf("field unstake_session_end_height of message poktroll.shared.Supplier is not mutable")) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.shared.Supplier")) @@ -335,7 +335,7 @@ func (x *fastReflection_Supplier) NewField(fd protoreflect.FieldDescriptor) prot case "poktroll.shared.Supplier.services": list := []*SupplierServiceConfig{} return protoreflect.ValueOfList(&_Supplier_3_list{list: &list}) - case "poktroll.shared.Supplier.unstake_commit_session_end_height": + case "poktroll.shared.Supplier.unstake_session_end_height": return protoreflect.ValueOfUint64(uint64(0)) default: if fd.IsExtension() { @@ -420,8 +420,8 @@ func (x *fastReflection_Supplier) ProtoMethods() *protoiface.Methods { n += 1 + l + runtime.Sov(uint64(l)) } } - if x.UnstakeCommitSessionEndHeight != 0 { - n += 1 + runtime.Sov(uint64(x.UnstakeCommitSessionEndHeight)) + if x.UnstakeSessionEndHeight != 0 { + n += 1 + runtime.Sov(uint64(x.UnstakeSessionEndHeight)) } if x.unknownFields != nil { n += len(x.unknownFields) @@ -452,8 +452,8 @@ func (x *fastReflection_Supplier) ProtoMethods() *protoiface.Methods { i -= len(x.unknownFields) copy(dAtA[i:], x.unknownFields) } - if x.UnstakeCommitSessionEndHeight != 0 { - i = runtime.EncodeVarint(dAtA, i, uint64(x.UnstakeCommitSessionEndHeight)) + if x.UnstakeSessionEndHeight != 0 { + i = runtime.EncodeVarint(dAtA, i, uint64(x.UnstakeSessionEndHeight)) i-- dAtA[i] = 0x20 } @@ -647,9 +647,9 @@ func (x *fastReflection_Supplier) ProtoMethods() *protoiface.Methods { iNdEx = postIndex case 4: if wireType != 0 { - return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field UnstakeCommitSessionEndHeight", wireType) + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field UnstakeSessionEndHeight", wireType) } - x.UnstakeCommitSessionEndHeight = 0 + x.UnstakeSessionEndHeight = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow @@ -659,7 +659,7 @@ func (x *fastReflection_Supplier) ProtoMethods() *protoiface.Methods { } b := dAtA[iNdEx] iNdEx++ - x.UnstakeCommitSessionEndHeight |= uint64(b&0x7F) << shift + x.UnstakeSessionEndHeight |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -721,9 +721,9 @@ type Supplier struct { Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` // The Bech32 address of the supplier using cosmos' ScalarDescriptor to ensure deterministic encoding Stake *v1beta1.Coin `protobuf:"bytes,2,opt,name=stake,proto3" json:"stake,omitempty"` // The total amount of uPOKT the supplier has staked Services []*SupplierServiceConfig `protobuf:"bytes,3,rep,name=services,proto3" json:"services,omitempty"` // The service configs this supplier can support - // The session end height corresponding the the unstake tx commit height. - // If the supplier is not unstaking, this value will be 0. - UnstakeCommitSessionEndHeight uint64 `protobuf:"varint,4,opt,name=unstake_commit_session_end_height,json=unstakeCommitSessionEndHeight,proto3" json:"unstake_commit_session_end_height,omitempty"` + // The session end height at which an actively unbonding supplier unbonds its stake. + // If the supplier did not unstake, this value will be 0. + UnstakeSessionEndHeight uint64 `protobuf:"varint,4,opt,name=unstake_session_end_height,json=unstakeSessionEndHeight,proto3" json:"unstake_session_end_height,omitempty"` } func (x *Supplier) Reset() { @@ -767,9 +767,9 @@ func (x *Supplier) GetServices() []*SupplierServiceConfig { return nil } -func (x *Supplier) GetUnstakeCommitSessionEndHeight() uint64 { +func (x *Supplier) GetUnstakeSessionEndHeight() uint64 { if x != nil { - return x.UnstakeCommitSessionEndHeight + return x.UnstakeSessionEndHeight } return 0 } @@ -785,7 +785,7 @@ var file_poktroll_shared_supplier_proto_rawDesc = []byte{ 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x62, 0x61, 0x73, 0x65, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x63, 0x6f, 0x69, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1d, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x2f, 0x73, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xfd, 0x01, 0x0a, 0x08, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xf0, 0x01, 0x0a, 0x08, 0x53, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x12, 0x32, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, 0xd2, 0xb4, 0x2d, 0x14, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, 0x74, 0x72, @@ -797,22 +797,21 @@ var file_poktroll_shared_supplier_proto_rawDesc = []byte{ 0x26, 0x2e, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x2e, 0x53, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x73, 0x12, 0x48, 0x0a, 0x21, 0x75, 0x6e, 0x73, 0x74, 0x61, 0x6b, 0x65, 0x5f, 0x63, 0x6f, 0x6d, - 0x6d, 0x69, 0x74, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x6e, 0x64, 0x5f, - 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1d, 0x75, 0x6e, - 0x73, 0x74, 0x61, 0x6b, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x45, 0x6e, 0x64, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x42, 0xa3, 0x01, 0x0a, 0x13, - 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x73, 0x68, 0x61, - 0x72, 0x65, 0x64, 0x42, 0x0d, 0x53, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x50, 0x72, 0x6f, - 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x20, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, - 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2f, - 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0xa2, 0x02, 0x03, 0x50, 0x53, 0x58, 0xaa, 0x02, 0x0f, 0x50, - 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0xca, 0x02, - 0x0f, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, - 0xe2, 0x02, 0x1b, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x53, 0x68, 0x61, 0x72, - 0x65, 0x64, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, - 0x10, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x3a, 0x3a, 0x53, 0x68, 0x61, 0x72, 0x65, - 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x73, 0x12, 0x3b, 0x0a, 0x1a, 0x75, 0x6e, 0x73, 0x74, 0x61, 0x6b, 0x65, 0x5f, 0x73, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x6e, 0x64, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x17, 0x75, 0x6e, 0x73, 0x74, 0x61, 0x6b, 0x65, 0x53, 0x65, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x45, 0x6e, 0x64, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x42, 0xa3, + 0x01, 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, + 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x42, 0x0d, 0x53, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x20, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, + 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, + 0x6c, 0x6c, 0x2f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0xa2, 0x02, 0x03, 0x50, 0x53, 0x58, 0xaa, + 0x02, 0x0f, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x53, 0x68, 0x61, 0x72, 0x65, + 0x64, 0xca, 0x02, 0x0f, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x53, 0x68, 0x61, + 0x72, 0x65, 0x64, 0xe2, 0x02, 0x1b, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x53, + 0x68, 0x61, 0x72, 0x65, 0x64, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0xea, 0x02, 0x10, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x3a, 0x3a, 0x53, 0x68, + 0x61, 0x72, 0x65, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/e2e/tests/init_test.go b/e2e/tests/init_test.go index 399ddcb3b..3220b93e7 100644 --- a/e2e/tests/init_test.go +++ b/e2e/tests/init_test.go @@ -450,11 +450,7 @@ func (s *suite) TheSupplierForAccountIsUnbonding(accName string) { s.waitForTxResultEvent(newEventMsgTypeMatchFn("supplier", "UnstakeSupplier")) supplier := s.getSupplierInfo(accName) - require.NotEqual(s, - supplier.UnstakeCommitSessionEndHeight, - suppliertypes.SupplierNotUnstaking, - "supplier %s is not unbonding", accName, - ) + require.True(s, supplier.IsUnbonding()) } func (s *suite) TheUserWaitsForUnbondingPeriodToFinish(accName string) { @@ -621,16 +617,13 @@ func (s *suite) getSupplierUnbondingHeight(accName string) int64 { } res, err := s.pocketd.RunCommandOnHostWithRetry("", numQueryRetries, args...) - require.NoError(s, err, "error getting supplier module params") + require.NoError(s, err, "error getting shared module params") var resp sharedtypes.QueryParamsResponse responseBz := []byte(strings.TrimSpace(res.Stdout)) s.cdc.MustUnmarshalJSON(responseBz, &resp) - windowCloseHeight := shared.GetProofWindowCloseHeight( - &resp.Params, - int64(supplier.UnstakeCommitSessionEndHeight), - ) - return windowCloseHeight + unbondingHeight := shared.GetSupplierUnbondingHeight(&resp.Params, supplier) + return unbondingHeight } // TODO_IMPROVE: use `sessionId` and `supplierName` since those are the two values diff --git a/proto/poktroll/shared/supplier.proto b/proto/poktroll/shared/supplier.proto index 28c9ed916..aa632c511 100644 --- a/proto/poktroll/shared/supplier.proto +++ b/proto/poktroll/shared/supplier.proto @@ -13,8 +13,8 @@ message Supplier { string address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; // The Bech32 address of the supplier using cosmos' ScalarDescriptor to ensure deterministic encoding cosmos.base.v1beta1.Coin stake = 2; // The total amount of uPOKT the supplier has staked repeated SupplierServiceConfig services = 3; // The service configs this supplier can support - // The session end height corresponding the the unstake tx commit height. - // If the supplier is not unstaking, this value will be 0. - uint64 unstake_commit_session_end_height = 4; + // The session end height at which an actively unbonding supplier unbonds its stake. + // If the supplier did not unstake, this value will be 0. + uint64 unstake_session_end_height = 4; } diff --git a/testutil/keeper/supplier.go b/testutil/keeper/supplier.go index aa8511fc9..b05168340 100644 --- a/testutil/keeper/supplier.go +++ b/testutil/keeper/supplier.go @@ -38,7 +38,7 @@ func SupplierKeeper(t testing.TB) (keeper.Keeper, context.Context) { require.NoError(t, stateStore.LoadLatestVersion()) logger := log.NewTestLogger(t) - ctx := sdk.NewContext(stateStore, cmtproto.Header{}, false, logger) + sdkCtx := sdk.NewContext(stateStore, cmtproto.Header{}, false, logger) registry := codectypes.NewInterfaceRegistry() cdc := codec.NewProtoCodec(registry) @@ -57,7 +57,7 @@ func SupplierKeeper(t testing.TB) (keeper.Keeper, context.Context) { logger, authority.String(), ) - require.NoError(t, sharedKeeper.SetParams(ctx, sharedtypes.DefaultParams())) + require.NoError(t, sharedKeeper.SetParams(sdkCtx, sharedtypes.DefaultParams())) serviceKeeper := servicekeeper.NewKeeper( cdc, @@ -78,16 +78,16 @@ func SupplierKeeper(t testing.TB) (keeper.Keeper, context.Context) { ) // Initialize params - require.NoError(t, k.SetParams(ctx, types.DefaultParams())) + require.NoError(t, k.SetParams(sdkCtx, types.DefaultParams())) // Move block height to 1 to get a non zero session end height - sdkCtx := SetBlockHeight(ctx, 1) + ctx := SetBlockHeight(sdkCtx, 1) // Add existing services used in the test. serviceKeeper.SetService(ctx, sharedtypes.Service{Id: "svcId"}) serviceKeeper.SetService(ctx, sharedtypes.Service{Id: "svcId2"}) - return k, sdkCtx + return k, ctx } // TODO_OPTIMIZE: Index suppliers by service so we can easily query k.GetAllSuppliers(ctx, Service) diff --git a/x/session/keeper/session_hydrator.go b/x/session/keeper/session_hydrator.go index e040bc731..1a74da84b 100644 --- a/x/session/keeper/session_hydrator.go +++ b/x/session/keeper/session_hydrator.go @@ -16,7 +16,6 @@ import ( "github.com/pokt-network/poktroll/x/shared" sharedhelpers "github.com/pokt-network/poktroll/x/shared/helpers" sharedtypes "github.com/pokt-network/poktroll/x/shared/types" - suppliertypes "github.com/pokt-network/poktroll/x/supplier/types" ) var SHA3HashLen = crypto.SHA3_256.Size() @@ -168,11 +167,10 @@ func (k Keeper) hydrateSessionSuppliers(ctx context.Context, sh *sessionHydrator candidateSuppliers := make([]*sharedtypes.Supplier, 0) for _, s := range suppliers { - // Exclude suppliers that are in an unbonding period. - // TODO_TECHDEBT: Suppliers that stake mid-session SHOULD NOT be included + // Exclude suppliers that are inactive (i.e. currently unbonding). + // TODO_TECHDEBT(#695): Suppliers that stake mid-session SHOULD NOT be included // in the current session's suppliers list and must wait until the next one. - if s.UnstakeCommitSessionEndHeight != suppliertypes.SupplierNotUnstaking && - uint64(sh.sessionHeader.SessionEndBlockHeight) > s.UnstakeCommitSessionEndHeight { + if !s.IsActive(sh.sessionHeader.SessionEndBlockHeight) { continue } diff --git a/x/shared/supplier.go b/x/shared/supplier.go new file mode 100644 index 000000000..f78392c26 --- /dev/null +++ b/x/shared/supplier.go @@ -0,0 +1,12 @@ +package shared + +import ( + sharedtypes "github.com/pokt-network/poktroll/x/shared/types" +) + +func GetSupplierUnbondingHeight( + sharedParams *sharedtypes.Params, + supplier *sharedtypes.Supplier, +) int64 { + return GetProofWindowCloseHeight(sharedParams, int64(supplier.UnstakeSessionEndHeight)) +} diff --git a/x/shared/types/supplier.go b/x/shared/types/supplier.go new file mode 100644 index 000000000..ce00152f1 --- /dev/null +++ b/x/shared/types/supplier.go @@ -0,0 +1,13 @@ +package types + +// SupplierNotUnstaking is the value of `unstake_session_end_height` if the +// supplier is not actively in the unbonding period. +const SupplierNotUnstaking uint64 = 0 + +func (s *Supplier) IsUnbonding() bool { + return s.UnstakeSessionEndHeight != SupplierNotUnstaking +} + +func (s *Supplier) IsActive(queryHeight int64) bool { + return !s.IsUnbonding() || uint64(queryHeight) <= s.UnstakeSessionEndHeight +} diff --git a/x/shared/types/supplier.pb.go b/x/shared/types/supplier.pb.go index dfd4d133a..3e19ef0ea 100644 --- a/x/shared/types/supplier.pb.go +++ b/x/shared/types/supplier.pb.go @@ -29,9 +29,9 @@ type Supplier struct { Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` Stake *types.Coin `protobuf:"bytes,2,opt,name=stake,proto3" json:"stake,omitempty"` Services []*SupplierServiceConfig `protobuf:"bytes,3,rep,name=services,proto3" json:"services,omitempty"` - // The session end height corresponding the the unstake tx commit height. - // If the supplier is not unstaking, this value will be 0. - UnstakeCommitSessionEndHeight uint64 `protobuf:"varint,4,opt,name=unstake_commit_session_end_height,json=unstakeCommitSessionEndHeight,proto3" json:"unstake_commit_session_end_height,omitempty"` + // The session end height at which an actively unbonding supplier unbonds its stake. + // If the supplier did not unstake, this value will be 0. + UnstakeSessionEndHeight uint64 `protobuf:"varint,4,opt,name=unstake_session_end_height,json=unstakeSessionEndHeight,proto3" json:"unstake_session_end_height,omitempty"` } func (m *Supplier) Reset() { *m = Supplier{} } @@ -88,9 +88,9 @@ func (m *Supplier) GetServices() []*SupplierServiceConfig { return nil } -func (m *Supplier) GetUnstakeCommitSessionEndHeight() uint64 { +func (m *Supplier) GetUnstakeSessionEndHeight() uint64 { if m != nil { - return m.UnstakeCommitSessionEndHeight + return m.UnstakeSessionEndHeight } return 0 } @@ -102,28 +102,28 @@ func init() { func init() { proto.RegisterFile("poktroll/shared/supplier.proto", fileDescriptor_4a189b52ba503cf2) } var fileDescriptor_4a189b52ba503cf2 = []byte{ - // 336 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x90, 0xbf, 0x4e, 0xeb, 0x30, - 0x18, 0xc5, 0xeb, 0xdb, 0xde, 0x7b, 0x7b, 0xd3, 0xe1, 0x4a, 0x11, 0x43, 0x5a, 0xa9, 0x56, 0x60, - 0x40, 0x59, 0x6a, 0xab, 0xe5, 0x09, 0x68, 0x85, 0x54, 0xd6, 0x64, 0x63, 0x89, 0xf2, 0xc7, 0x24, - 0x56, 0x1b, 0x3b, 0xf2, 0xe7, 0x16, 0x78, 0x0b, 0x1e, 0x86, 0x87, 0x60, 0xac, 0x98, 0x18, 0x51, - 0xfb, 0x1c, 0x48, 0xa8, 0xb1, 0xd3, 0x01, 0xc6, 0x4f, 0xbf, 0x5f, 0x72, 0x8e, 0x8f, 0x83, 0x6b, - 0xb9, 0xd2, 0x4a, 0xae, 0xd7, 0x14, 0xca, 0x44, 0xb1, 0x9c, 0xc2, 0xa6, 0xae, 0xd7, 0x9c, 0x29, - 0x52, 0x2b, 0xa9, 0xa5, 0xfb, 0xbf, 0xe5, 0xc4, 0xf0, 0xd1, 0x30, 0x93, 0x50, 0x49, 0x88, 0x1b, - 0x4c, 0xcd, 0x61, 0xdc, 0x11, 0x36, 0x17, 0x4d, 0x13, 0x60, 0x74, 0x3b, 0x4d, 0x99, 0x4e, 0xa6, - 0x34, 0x93, 0x5c, 0x58, 0x3e, 0xfe, 0x91, 0xc5, 0xd4, 0x96, 0x67, 0xcc, 0xe0, 0x8b, 0x4f, 0xe4, - 0xf4, 0x23, 0x9b, 0xee, 0xce, 0x9c, 0xbf, 0x49, 0x9e, 0x2b, 0x06, 0xe0, 0x21, 0x1f, 0x05, 0xff, - 0xe6, 0xde, 0xdb, 0xcb, 0xe4, 0xcc, 0xc6, 0x5d, 0x1b, 0x12, 0x69, 0xc5, 0x45, 0x11, 0xb6, 0xa2, - 0x4b, 0x9d, 0xdf, 0xa0, 0x93, 0x15, 0xf3, 0x7e, 0xf9, 0x28, 0x18, 0xcc, 0x86, 0xc4, 0xea, 0xc7, - 0x3e, 0xc4, 0xf6, 0x21, 0x0b, 0xc9, 0x45, 0x68, 0x3c, 0x77, 0xee, 0xf4, 0x6d, 0x05, 0xf0, 0xba, - 0x7e, 0x37, 0x18, 0xcc, 0x2e, 0xc9, 0xb7, 0xf7, 0x92, 0xb6, 0x51, 0x64, 0xc4, 0x85, 0x14, 0xf7, - 0xbc, 0x08, 0x4f, 0xdf, 0xb9, 0x4b, 0xe7, 0x7c, 0x23, 0x9a, 0xdf, 0xc5, 0x99, 0xac, 0x2a, 0xae, - 0x63, 0x60, 0x00, 0x5c, 0x8a, 0x98, 0x89, 0x3c, 0x2e, 0x19, 0x2f, 0x4a, 0xed, 0xf5, 0x7c, 0x14, - 0xf4, 0xc2, 0xb1, 0x15, 0x17, 0x8d, 0x17, 0x19, 0xed, 0x46, 0xe4, 0xcb, 0x46, 0x9a, 0xdf, 0xbe, - 0xee, 0x31, 0xda, 0xed, 0x31, 0xfa, 0xd8, 0x63, 0xf4, 0x7c, 0xc0, 0x9d, 0xdd, 0x01, 0x77, 0xde, - 0x0f, 0xb8, 0x73, 0x47, 0x0b, 0xae, 0xcb, 0x4d, 0x4a, 0x32, 0x59, 0xd1, 0x63, 0xbf, 0x89, 0x60, - 0xfa, 0x41, 0xaa, 0x15, 0x3d, 0x0d, 0xfa, 0xd8, 0x4e, 0xaa, 0x9f, 0x6a, 0x06, 0xe9, 0x9f, 0x66, - 0xd1, 0xab, 0xaf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xb3, 0xb1, 0xeb, 0xec, 0xde, 0x01, 0x00, 0x00, + // 326 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x90, 0x3f, 0x4e, 0xc3, 0x30, + 0x18, 0xc5, 0x6b, 0x5a, 0xa0, 0xa4, 0x03, 0x52, 0x84, 0x44, 0x5a, 0x09, 0x2b, 0x62, 0x40, 0x59, + 0x6a, 0xab, 0x65, 0x64, 0xa2, 0x15, 0x12, 0xac, 0xc9, 0xc6, 0x12, 0xe5, 0x8f, 0x49, 0xac, 0xb6, + 0x76, 0xe4, 0xcf, 0x2d, 0x70, 0x0b, 0x0e, 0xc3, 0x21, 0x18, 0x2b, 0x26, 0x46, 0xd4, 0x5e, 0x80, + 0x23, 0xa0, 0xc6, 0x4e, 0x07, 0x18, 0x3f, 0xfd, 0x7e, 0xc9, 0x7b, 0x7e, 0x0e, 0xae, 0xe4, 0x4c, + 0x2b, 0x39, 0x9f, 0x53, 0x28, 0x13, 0xc5, 0x72, 0x0a, 0xcb, 0xaa, 0x9a, 0x73, 0xa6, 0x48, 0xa5, + 0xa4, 0x96, 0xee, 0x69, 0xc3, 0x89, 0xe1, 0x83, 0x7e, 0x26, 0x61, 0x21, 0x21, 0xae, 0x31, 0x35, + 0x87, 0x71, 0x07, 0xd8, 0x5c, 0x34, 0x4d, 0x80, 0xd1, 0xd5, 0x28, 0x65, 0x3a, 0x19, 0xd1, 0x4c, + 0x72, 0x61, 0xf9, 0xc5, 0xbf, 0x2c, 0xa6, 0x56, 0x3c, 0x63, 0x06, 0x5f, 0xfe, 0x20, 0xa7, 0x1b, + 0xd9, 0x74, 0x77, 0xec, 0x1c, 0x27, 0x79, 0xae, 0x18, 0x80, 0x87, 0x7c, 0x14, 0x9c, 0x4c, 0xbc, + 0xcf, 0xf7, 0xe1, 0x99, 0x8d, 0xbb, 0x35, 0x24, 0xd2, 0x8a, 0x8b, 0x22, 0x6c, 0x44, 0x97, 0x3a, + 0x87, 0xa0, 0x93, 0x19, 0xf3, 0x0e, 0x7c, 0x14, 0xf4, 0xc6, 0x7d, 0x62, 0xf5, 0x5d, 0x1f, 0x62, + 0xfb, 0x90, 0xa9, 0xe4, 0x22, 0x34, 0x9e, 0x3b, 0x71, 0xba, 0xb6, 0x02, 0x78, 0x6d, 0xbf, 0x1d, + 0xf4, 0xc6, 0x57, 0xe4, 0xcf, 0x7b, 0x49, 0xd3, 0x28, 0x32, 0xe2, 0x54, 0x8a, 0x27, 0x5e, 0x84, + 0xfb, 0xef, 0xdc, 0x1b, 0x67, 0xb0, 0x14, 0xf5, 0xef, 0x62, 0x60, 0x00, 0x5c, 0x8a, 0x98, 0x89, + 0x3c, 0x2e, 0x19, 0x2f, 0x4a, 0xed, 0x75, 0x7c, 0x14, 0x74, 0xc2, 0x73, 0x6b, 0x44, 0x46, 0xb8, + 0x13, 0xf9, 0x7d, 0x8d, 0x27, 0x0f, 0x1f, 0x1b, 0x8c, 0xd6, 0x1b, 0x8c, 0xbe, 0x37, 0x18, 0xbd, + 0x6d, 0x71, 0x6b, 0xbd, 0xc5, 0xad, 0xaf, 0x2d, 0x6e, 0x3d, 0xd2, 0x82, 0xeb, 0x72, 0x99, 0x92, + 0x4c, 0x2e, 0xe8, 0xae, 0xd2, 0x50, 0x30, 0xfd, 0x2c, 0xd5, 0x8c, 0xee, 0x37, 0x7c, 0x69, 0x56, + 0xd4, 0xaf, 0x15, 0x83, 0xf4, 0xa8, 0x1e, 0xf1, 0xfa, 0x37, 0x00, 0x00, 0xff, 0xff, 0x7d, 0x97, + 0x5a, 0x2e, 0xd1, 0x01, 0x00, 0x00, } func (m *Supplier) Marshal() (dAtA []byte, err error) { @@ -146,8 +146,8 @@ func (m *Supplier) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.UnstakeCommitSessionEndHeight != 0 { - i = encodeVarintSupplier(dAtA, i, uint64(m.UnstakeCommitSessionEndHeight)) + if m.UnstakeSessionEndHeight != 0 { + i = encodeVarintSupplier(dAtA, i, uint64(m.UnstakeSessionEndHeight)) i-- dAtA[i] = 0x20 } @@ -218,8 +218,8 @@ func (m *Supplier) Size() (n int) { n += 1 + l + sovSupplier(uint64(l)) } } - if m.UnstakeCommitSessionEndHeight != 0 { - n += 1 + sovSupplier(uint64(m.UnstakeCommitSessionEndHeight)) + if m.UnstakeSessionEndHeight != 0 { + n += 1 + sovSupplier(uint64(m.UnstakeSessionEndHeight)) } return n } @@ -363,9 +363,9 @@ func (m *Supplier) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 4: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field UnstakeCommitSessionEndHeight", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field UnstakeSessionEndHeight", wireType) } - m.UnstakeCommitSessionEndHeight = 0 + m.UnstakeSessionEndHeight = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowSupplier @@ -375,7 +375,7 @@ func (m *Supplier) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.UnstakeCommitSessionEndHeight |= uint64(b&0x7F) << shift + m.UnstakeSessionEndHeight |= uint64(b&0x7F) << shift if b < 0x80 { break } diff --git a/x/supplier/keeper/msg_server_stake_supplier.go b/x/supplier/keeper/msg_server_stake_supplier.go index 3181dd0a1..093937d93 100644 --- a/x/supplier/keeper/msg_server_stake_supplier.go +++ b/x/supplier/keeper/msg_server_stake_supplier.go @@ -58,7 +58,7 @@ func (k msgServer) StakeSupplier(ctx context.Context, msg *types.MsgStakeSupplie logger.Info(fmt.Sprintf("Supplier is going to escrow an additional %+v coins", coinsToEscrow)) // If the supplier has initiated an unstake action, cancel it since they are staking again. - supplier.UnstakeCommitSessionEndHeight = types.SupplierNotUnstaking + supplier.UnstakeSessionEndHeight = sharedtypes.SupplierNotUnstaking } // Must always stake or upstake (> 0 delta) diff --git a/x/supplier/keeper/msg_server_unstake_supplier.go b/x/supplier/keeper/msg_server_unstake_supplier.go index ca79f84a1..c11b1892b 100644 --- a/x/supplier/keeper/msg_server_unstake_supplier.go +++ b/x/supplier/keeper/msg_server_unstake_supplier.go @@ -39,7 +39,7 @@ func (k msgServer) UnstakeSupplier( logger.Info(fmt.Sprintf("Supplier found. Unstaking supplier for address %s", msg.Address)) // Check if the supplier has already initiated the unstake action. - if supplier.UnstakeCommitSessionEndHeight != types.SupplierNotUnstaking { + if supplier.IsUnbonding() { logger.Warn(fmt.Sprintf("Supplier %s still unbonding from previous unstaking", msg.Address)) return nil, types.ErrSupplierIsUnstaking } @@ -55,7 +55,7 @@ func (k msgServer) UnstakeSupplier( // Removing it right away could have undesired effects on the network // (e.g. a session with less than the minimum or 0 number of suppliers, // off-chain actors that need to listen to session supplier's change mid-session, etc). - supplier.UnstakeCommitSessionEndHeight = uint64(shared.GetSessionEndHeight(&sharedParams, currentHeight)) + supplier.UnstakeSessionEndHeight = uint64(shared.GetSessionEndHeight(&sharedParams, currentHeight)) k.SetSupplier(ctx, supplier) isSuccessful = true diff --git a/x/supplier/keeper/msg_server_unstake_supplier_test.go b/x/supplier/keeper/msg_server_unstake_supplier_test.go index 35f010834..2c6c5415a 100644 --- a/x/supplier/keeper/msg_server_unstake_supplier_test.go +++ b/x/supplier/keeper/msg_server_unstake_supplier_test.go @@ -18,49 +18,65 @@ func TestMsgServer_UnstakeSupplier_Success(t *testing.T) { k, ctx := keepertest.SupplierKeeper(t) srv := keeper.NewMsgServerImpl(k) - // Generate an address for the supplier - supplierAddr := sample.AccAddress() + // Generate two addresses for an unstaking and a non-unstaking suppliers + unstakingSupplierAddr := sample.AccAddress() // Verify that the supplier does not exist yet - _, isSupplierFound := k.GetSupplier(ctx, supplierAddr) + _, isSupplierFound := k.GetSupplier(ctx, unstakingSupplierAddr) require.False(t, isSupplierFound) initialStake := int64(100) - stakeMsg := createStakeMsg(supplierAddr, initialStake) + stakeMsg := createStakeMsg(unstakingSupplierAddr, initialStake) // Stake the supplier _, err := srv.StakeSupplier(ctx, stakeMsg) require.NoError(t, err) // Verify that the supplier exists - foundSupplier, isSupplierFound := k.GetSupplier(ctx, supplierAddr) + foundSupplier, isSupplierFound := k.GetSupplier(ctx, unstakingSupplierAddr) require.True(t, isSupplierFound) - require.Equal(t, supplierAddr, foundSupplier.Address) + require.Equal(t, unstakingSupplierAddr, foundSupplier.Address) require.Equal(t, math.NewInt(initialStake), foundSupplier.Stake.Amount) require.Len(t, foundSupplier.Services, 1) + // Create and stake another supplier that will not be unstaked to assert that only the + // unstaking supplier is removed from the suppliers list when the unbonding period is over. + nonUnstakingSupplierAddr := sample.AccAddress() + stakeMsg = createStakeMsg(nonUnstakingSupplierAddr, initialStake) + _, err = srv.StakeSupplier(ctx, stakeMsg) + require.NoError(t, err) + + // Verify that the non-unstaking supplier exists + _, isSupplierFound = k.GetSupplier(ctx, nonUnstakingSupplierAddr) + require.True(t, isSupplierFound) + // Initiate the supplier unstaking - unstakeMsg := &types.MsgUnstakeSupplier{Address: supplierAddr} + unstakeMsg := &types.MsgUnstakeSupplier{Address: unstakingSupplierAddr} _, err = srv.UnstakeSupplier(ctx, unstakeMsg) require.NoError(t, err) // Make sure the supplier entered the unbonding period - foundSupplier, isSupplierFound = k.GetSupplier(ctx, supplierAddr) + foundSupplier, isSupplierFound = k.GetSupplier(ctx, unstakingSupplierAddr) require.True(t, isSupplierFound) - require.NotEqual(t, foundSupplier.UnstakeCommitSessionEndHeight, types.SupplierNotUnstaking) + require.True(t, foundSupplier.IsUnbonding()) // Move block height to the end of the unbonding period unbondingHeight := k.GetSupplierUnbondingHeight(ctx, &foundSupplier) ctx = keepertest.SetBlockHeight(ctx, unbondingHeight) - // Run the endblocker to unbond the supplier - err = k.EndBlockerUnbondSupplier(ctx) + // Run the endblocker to unbond suppliers + err = k.EndBlockerUnbondSuppliers(ctx) require.NoError(t, err) - // Make sure the supplier is removed from the suppliers list when the + // Make sure the unstaking supplier is removed from the suppliers list when the // unbonding period is over - _, isSupplierFound = k.GetSupplier(ctx, supplierAddr) + _, isSupplierFound = k.GetSupplier(ctx, unstakingSupplierAddr) require.False(t, isSupplierFound) + + // Verify that the non-unstaking supplier still exists + nonUnstakingSupplier, isSupplierFound := k.GetSupplier(ctx, nonUnstakingSupplierAddr) + require.True(t, isSupplierFound) + require.False(t, nonUnstakingSupplier.IsUnbonding()) } func TestMsgServer_UnstakeSupplier_CancelUnbondingIfRestaked(t *testing.T) { @@ -79,7 +95,7 @@ func TestMsgServer_UnstakeSupplier_CancelUnbondingIfRestaked(t *testing.T) { // Verify that the supplier exists with no unbonding height foundSupplier, isSupplierFound := k.GetSupplier(ctx, supplierAddr) require.True(t, isSupplierFound) - require.Equal(t, types.SupplierNotUnstaking, foundSupplier.UnstakeCommitSessionEndHeight) + require.False(t, foundSupplier.IsUnbonding()) // Initiate the supplier unstaking unstakeMsg := &types.MsgUnstakeSupplier{Address: supplierAddr} @@ -89,7 +105,7 @@ func TestMsgServer_UnstakeSupplier_CancelUnbondingIfRestaked(t *testing.T) { // Make sure the supplier entered the unbonding period foundSupplier, isSupplierFound = k.GetSupplier(ctx, supplierAddr) require.True(t, isSupplierFound) - require.NotEqual(t, foundSupplier.UnstakeCommitSessionEndHeight, types.SupplierNotUnstaking) + require.True(t, foundSupplier.IsUnbonding()) unbondingHeight := k.GetSupplierUnbondingHeight(ctx, &foundSupplier) @@ -101,18 +117,18 @@ func TestMsgServer_UnstakeSupplier_CancelUnbondingIfRestaked(t *testing.T) { // Make sure the supplier is no longer in the unbonding period foundSupplier, isSupplierFound = k.GetSupplier(ctx, supplierAddr) require.True(t, isSupplierFound) - require.Equal(t, foundSupplier.UnstakeCommitSessionEndHeight, types.SupplierNotUnstaking) + require.False(t, foundSupplier.IsUnbonding()) ctx = keepertest.SetBlockHeight(ctx, int64(unbondingHeight)) - // Run the endblocker to unbond the supplier - err = k.EndBlockerUnbondSupplier(ctx) + // Run the EndBlocker, the supplier should not be unbonding. + err = k.EndBlockerUnbondSuppliers(ctx) require.NoError(t, err) // Make sure the supplier is still in the suppliers list with an unbonding height of 0 foundSupplier, isSupplierFound = k.GetSupplier(ctx, supplierAddr) require.True(t, isSupplierFound) - require.Equal(t, foundSupplier.UnstakeCommitSessionEndHeight, types.SupplierNotUnstaking) + require.False(t, foundSupplier.IsUnbonding()) } func TestMsgServer_UnstakeSupplier_FailIfNotStaked(t *testing.T) { diff --git a/x/supplier/keeper/unbond_suppliers.go b/x/supplier/keeper/unbond_suppliers.go index d1ecccb68..184cce721 100644 --- a/x/supplier/keeper/unbond_suppliers.go +++ b/x/supplier/keeper/unbond_suppliers.go @@ -10,8 +10,8 @@ import ( "github.com/pokt-network/poktroll/x/supplier/types" ) -// EndBlockerUnbondSupplier unbonds suppliers that have finished the unbonding period. -func (k Keeper) EndBlockerUnbondSupplier(ctx context.Context) error { +// EndBlockerUnbondSuppliers unbonds suppliers whose unbonding period has elapsed. +func (k Keeper) EndBlockerUnbondSuppliers(ctx context.Context) error { sdkCtx := cosmostypes.UnwrapSDKContext(ctx) currentHeight := sdkCtx.BlockHeight() @@ -22,14 +22,14 @@ func (k Keeper) EndBlockerUnbondSupplier(ctx context.Context) error { // unbonding action instead of iterating over all suppliers. for _, supplier := range k.GetAllSuppliers(ctx) { // Ignore suppliers that have not initiated the unbonding action. - if supplier.UnstakeCommitSessionEndHeight == types.SupplierNotUnstaking { + if !supplier.IsUnbonding() { continue } unbondingHeight := k.GetSupplierUnbondingHeight(ctx, &supplier) + // If the unbonding height is older (less) than the current height, unbond the supplier. if unbondingHeight <= currentHeight { - // Retrieve the address of the supplier. supplierAddress, err := cosmostypes.AccAddressFromBech32(supplier.Address) if err != nil { @@ -42,8 +42,8 @@ func (k Keeper) EndBlockerUnbondSupplier(ctx context.Context) error { ctx, types.ModuleName, supplierAddress, []cosmostypes.Coin{*supplier.Stake}, ); err != nil { logger.Error(fmt.Sprintf( - "could not send %v coins from %s module to %s account due to %v", - supplier.Stake, supplierAddress, types.ModuleName, err, + "could not send %s coins from %s module to %s account due to %s", + supplier.Stake.String(), supplierAddress, types.ModuleName, err, )) return err } @@ -64,8 +64,5 @@ func (k Keeper) GetSupplierUnbondingHeight( ) int64 { sharedParams := k.sharedKeeper.GetParams(ctx) - return shared.GetProofWindowCloseHeight( - &sharedParams, - int64(supplier.UnstakeCommitSessionEndHeight), - ) + return shared.GetSupplierUnbondingHeight(&sharedParams, supplier) } diff --git a/x/supplier/module/abci.go b/x/supplier/module/abci.go index 24d42ba48..35937128c 100644 --- a/x/supplier/module/abci.go +++ b/x/supplier/module/abci.go @@ -8,7 +8,7 @@ import ( // EndBlocker is called every block and handles supplier related updates. func EndBlocker(ctx sdk.Context, k keeper.Keeper) error { - if err := k.EndBlockerUnbondSupplier(ctx); err != nil { + if err := k.EndBlockerUnbondSuppliers(ctx); err != nil { return err } diff --git a/x/supplier/types/params.go b/x/supplier/types/params.go index 0b099f495..95b0cf8a2 100644 --- a/x/supplier/types/params.go +++ b/x/supplier/types/params.go @@ -2,10 +2,7 @@ package types import paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" -var ( - _ paramtypes.ParamSet = (*Params)(nil) - SupplierNotUnstaking uint64 = 0 -) +var _ paramtypes.ParamSet = (*Params)(nil) // ParamKeyTable the param key table for launch module func ParamKeyTable() paramtypes.KeyTable { From 304fc70b5a7f969bd02a7fd0c67dc169a6f8fce7 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Mon, 22 Jul 2024 19:03:50 +0200 Subject: [PATCH 11/13] chore: Add IsUnbonding and IsActive godoc --- x/shared/types/supplier.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/x/shared/types/supplier.go b/x/shared/types/supplier.go index ce00152f1..f9742e958 100644 --- a/x/shared/types/supplier.go +++ b/x/shared/types/supplier.go @@ -4,10 +4,17 @@ package types // supplier is not actively in the unbonding period. const SupplierNotUnstaking uint64 = 0 +// IsUnbonding returns whether the supplier has submitted an unstake message, +// in which case the supplier has an UnstakeSessionEndHeight set. func (s *Supplier) IsUnbonding() bool { return s.UnstakeSessionEndHeight != SupplierNotUnstaking } +// IsActive returns whether the supplier is allowed to serve requests at the +// given query height. +// A supplier that has not submitted an unstake message is always active. +// A supplier that has submitted an unstake message is active until the end of +// the session containing the height at which unstake message was submitted. func (s *Supplier) IsActive(queryHeight int64) bool { return !s.IsUnbonding() || uint64(queryHeight) <= s.UnstakeSessionEndHeight } From c77015a5d84a26bd30df49cc747e025a4f8559d1 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Tue, 23 Jul 2024 13:09:18 +0200 Subject: [PATCH 12/13] chore: Address reivew change requests --- x/shared/supplier.go | 5 +++ x/shared/types/supplier.go | 7 ++-- x/supplier/keeper/unbond_suppliers.go | 47 +++++++++++++++------------ x/supplier/module/abci.go | 1 + 4 files changed, 37 insertions(+), 23 deletions(-) diff --git a/x/shared/supplier.go b/x/shared/supplier.go index f78392c26..e1b40ef6c 100644 --- a/x/shared/supplier.go +++ b/x/shared/supplier.go @@ -4,9 +4,14 @@ import ( sharedtypes "github.com/pokt-network/poktroll/x/shared/types" ) +// GetProofWindowCloseHeight returns the height at which the given supplier finishes unbonding. func GetSupplierUnbondingHeight( sharedParams *sharedtypes.Params, supplier *sharedtypes.Supplier, ) int64 { + // TODO_UPNEXT(red-0ne): Add a governance parameter called `supplier_unbonding_period` + // equal to the number of blocks required to unbond. The value should enforce + // (when being updated) to be after proof window close height and should still + // round to the end of the nearest session. return GetProofWindowCloseHeight(sharedParams, int64(supplier.UnstakeSessionEndHeight)) } diff --git a/x/shared/types/supplier.go b/x/shared/types/supplier.go index f9742e958..ac6fe4782 100644 --- a/x/shared/types/supplier.go +++ b/x/shared/types/supplier.go @@ -4,8 +4,9 @@ package types // supplier is not actively in the unbonding period. const SupplierNotUnstaking uint64 = 0 -// IsUnbonding returns whether the supplier has submitted an unstake message, -// in which case the supplier has an UnstakeSessionEndHeight set. +// IsUnbonding returns true if the supplier is actively unbonding. +// It determines if the supplier has submitted an unstake message, in which case +// the supplier has its UnstakeSessionEndHeight set. func (s *Supplier) IsUnbonding() bool { return s.UnstakeSessionEndHeight != SupplierNotUnstaking } @@ -16,5 +17,7 @@ func (s *Supplier) IsUnbonding() bool { // A supplier that has submitted an unstake message is active until the end of // the session containing the height at which unstake message was submitted. func (s *Supplier) IsActive(queryHeight int64) bool { + // TODO_UPNEXT(@red-0ne): When introducing a governance parameter for unbonding, this + // will also need to be updated to reflect sessions when the supplier is not active. return !s.IsUnbonding() || uint64(queryHeight) <= s.UnstakeSessionEndHeight } diff --git a/x/supplier/keeper/unbond_suppliers.go b/x/supplier/keeper/unbond_suppliers.go index 184cce721..63c08a3c4 100644 --- a/x/supplier/keeper/unbond_suppliers.go +++ b/x/supplier/keeper/unbond_suppliers.go @@ -28,36 +28,41 @@ func (k Keeper) EndBlockerUnbondSuppliers(ctx context.Context) error { unbondingHeight := k.GetSupplierUnbondingHeight(ctx, &supplier) - // If the unbonding height is older (less) than the current height, unbond the supplier. - if unbondingHeight <= currentHeight { - // Retrieve the address of the supplier. - supplierAddress, err := cosmostypes.AccAddressFromBech32(supplier.Address) - if err != nil { - logger.Error(fmt.Sprintf("could not parse address %s", supplier.Address)) - return err - } + // If the unbonding height is ahead of the current height, the supplier + // stays in the unbonding state. + if unbondingHeight > currentHeight { + continue + } - // Send the coins from the supplier pool back to the supplier. - if err = k.bankKeeper.SendCoinsFromModuleToAccount( - ctx, types.ModuleName, supplierAddress, []cosmostypes.Coin{*supplier.Stake}, - ); err != nil { - logger.Error(fmt.Sprintf( - "could not send %s coins from %s module to %s account due to %s", - supplier.Stake.String(), supplierAddress, types.ModuleName, err, - )) - return err - } + // Retrieve the address of the supplier. + supplierAddress, err := cosmostypes.AccAddressFromBech32(supplier.Address) + if err != nil { + logger.Error(fmt.Sprintf("could not parse address %s", supplier.Address)) + return err + } - // Remove the supplier from the store. - k.RemoveSupplier(ctx, supplierAddress.String()) - logger.Info(fmt.Sprintf("Successfully removed the supplier: %+v", supplier)) + // Send the coins from the supplier pool back to the supplier. + if err = k.bankKeeper.SendCoinsFromModuleToAccount( + ctx, types.ModuleName, supplierAddress, []cosmostypes.Coin{*supplier.Stake}, + ); err != nil { + logger.Error(fmt.Sprintf( + "could not send %s coins from %s module to %s account due to %s", + supplier.Stake.String(), supplierAddress, types.ModuleName, err, + )) + return err } + + // Remove the supplier from the store. + k.RemoveSupplier(ctx, supplierAddress.String()) + logger.Info(fmt.Sprintf("Successfully removed the supplier: %+v", supplier)) } return nil } // GetSupplierUnbondingHeight returns the height at which the supplier can be unbonded. +// TODO_REFACTOR(@red-0ne): Make this a static function in the shared pkg alongside +// the window height helpers. func (k Keeper) GetSupplierUnbondingHeight( ctx context.Context, supplier *sharedtypes.Supplier, diff --git a/x/supplier/module/abci.go b/x/supplier/module/abci.go index 35937128c..86e463ea5 100644 --- a/x/supplier/module/abci.go +++ b/x/supplier/module/abci.go @@ -8,6 +8,7 @@ import ( // EndBlocker is called every block and handles supplier related updates. func EndBlocker(ctx sdk.Context, k keeper.Keeper) error { + // TODO_IMPROVE(@red-0ne): Add logs and/or telemetry on the number of unbonded suppliers. if err := k.EndBlockerUnbondSuppliers(ctx); err != nil { return err } From cadef6c7f8e1810c1da4a5e123369cc4cb89f258 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Thu, 25 Jul 2024 02:50:40 +0200 Subject: [PATCH 13/13] fix: godoc function name --- x/shared/supplier.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/shared/supplier.go b/x/shared/supplier.go index e1b40ef6c..637298f9c 100644 --- a/x/shared/supplier.go +++ b/x/shared/supplier.go @@ -4,7 +4,7 @@ import ( sharedtypes "github.com/pokt-network/poktroll/x/shared/types" ) -// GetProofWindowCloseHeight returns the height at which the given supplier finishes unbonding. +// GetSupplierUnbondingHeight returns the height at which the given supplier finishes unbonding. func GetSupplierUnbondingHeight( sharedParams *sharedtypes.Params, supplier *sharedtypes.Supplier,