From 6738d21137937f4eb2e23bb6d2a3c0496acc04ec Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Thu, 15 Aug 2024 21:39:08 -0400 Subject: [PATCH 01/53] WIP --- api/poktroll/tokenomics/event.pulsar.go | 800 +++++++++++++++++++-- proto/poktroll/tokenomics/event.proto | 11 +- x/tokenomics/keeper/token_logic_modules.go | 159 +++- x/tokenomics/types/errors.go | 53 +- x/tokenomics/types/event.pb.go | 428 +++++++++-- x/tokenomics/types/tx.pb.go | 1 - 6 files changed, 1300 insertions(+), 152 deletions(-) diff --git a/api/poktroll/tokenomics/event.pulsar.go b/api/poktroll/tokenomics/event.pulsar.go index 300c5cb18..ae7a1d67b 100644 --- a/api/poktroll/tokenomics/event.pulsar.go +++ b/api/poktroll/tokenomics/event.pulsar.go @@ -2395,6 +2395,633 @@ func (x *fastReflection_EventApplicationOverserviced) ProtoMethods() *protoiface } } +var ( + md_EventApplicationReimbursementRequest protoreflect.MessageDescriptor + fd_EventApplicationReimbursementRequest_application_addr protoreflect.FieldDescriptor + fd_EventApplicationReimbursementRequest_service_id protoreflect.FieldDescriptor + fd_EventApplicationReimbursementRequest_session_id protoreflect.FieldDescriptor + fd_EventApplicationReimbursementRequest_amount protoreflect.FieldDescriptor +) + +func init() { + file_poktroll_tokenomics_event_proto_init() + md_EventApplicationReimbursementRequest = File_poktroll_tokenomics_event_proto.Messages().ByName("EventApplicationReimbursementRequest") + fd_EventApplicationReimbursementRequest_application_addr = md_EventApplicationReimbursementRequest.Fields().ByName("application_addr") + fd_EventApplicationReimbursementRequest_service_id = md_EventApplicationReimbursementRequest.Fields().ByName("service_id") + fd_EventApplicationReimbursementRequest_session_id = md_EventApplicationReimbursementRequest.Fields().ByName("session_id") + fd_EventApplicationReimbursementRequest_amount = md_EventApplicationReimbursementRequest.Fields().ByName("amount") +} + +var _ protoreflect.Message = (*fastReflection_EventApplicationReimbursementRequest)(nil) + +type fastReflection_EventApplicationReimbursementRequest EventApplicationReimbursementRequest + +func (x *EventApplicationReimbursementRequest) ProtoReflect() protoreflect.Message { + return (*fastReflection_EventApplicationReimbursementRequest)(x) +} + +func (x *EventApplicationReimbursementRequest) slowProtoReflect() protoreflect.Message { + mi := &file_poktroll_tokenomics_event_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_EventApplicationReimbursementRequest_messageType fastReflection_EventApplicationReimbursementRequest_messageType +var _ protoreflect.MessageType = fastReflection_EventApplicationReimbursementRequest_messageType{} + +type fastReflection_EventApplicationReimbursementRequest_messageType struct{} + +func (x fastReflection_EventApplicationReimbursementRequest_messageType) Zero() protoreflect.Message { + return (*fastReflection_EventApplicationReimbursementRequest)(nil) +} +func (x fastReflection_EventApplicationReimbursementRequest_messageType) New() protoreflect.Message { + return new(fastReflection_EventApplicationReimbursementRequest) +} +func (x fastReflection_EventApplicationReimbursementRequest_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_EventApplicationReimbursementRequest +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_EventApplicationReimbursementRequest) Descriptor() protoreflect.MessageDescriptor { + return md_EventApplicationReimbursementRequest +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_EventApplicationReimbursementRequest) Type() protoreflect.MessageType { + return _fastReflection_EventApplicationReimbursementRequest_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_EventApplicationReimbursementRequest) New() protoreflect.Message { + return new(fastReflection_EventApplicationReimbursementRequest) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_EventApplicationReimbursementRequest) Interface() protoreflect.ProtoMessage { + return (*EventApplicationReimbursementRequest)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_EventApplicationReimbursementRequest) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.ApplicationAddr != "" { + value := protoreflect.ValueOfString(x.ApplicationAddr) + if !f(fd_EventApplicationReimbursementRequest_application_addr, value) { + return + } + } + if x.ServiceId != "" { + value := protoreflect.ValueOfString(x.ServiceId) + if !f(fd_EventApplicationReimbursementRequest_service_id, value) { + return + } + } + if x.SessionId != "" { + value := protoreflect.ValueOfString(x.SessionId) + if !f(fd_EventApplicationReimbursementRequest_session_id, value) { + return + } + } + if x.Amount != nil { + value := protoreflect.ValueOfMessage(x.Amount.ProtoReflect()) + if !f(fd_EventApplicationReimbursementRequest_amount, value) { + return + } + } +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_EventApplicationReimbursementRequest) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "poktroll.tokenomics.EventApplicationReimbursementRequest.application_addr": + return x.ApplicationAddr != "" + case "poktroll.tokenomics.EventApplicationReimbursementRequest.service_id": + return x.ServiceId != "" + case "poktroll.tokenomics.EventApplicationReimbursementRequest.session_id": + return x.SessionId != "" + case "poktroll.tokenomics.EventApplicationReimbursementRequest.amount": + return x.Amount != nil + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.tokenomics.EventApplicationReimbursementRequest")) + } + panic(fmt.Errorf("message poktroll.tokenomics.EventApplicationReimbursementRequest does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_EventApplicationReimbursementRequest) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "poktroll.tokenomics.EventApplicationReimbursementRequest.application_addr": + x.ApplicationAddr = "" + case "poktroll.tokenomics.EventApplicationReimbursementRequest.service_id": + x.ServiceId = "" + case "poktroll.tokenomics.EventApplicationReimbursementRequest.session_id": + x.SessionId = "" + case "poktroll.tokenomics.EventApplicationReimbursementRequest.amount": + x.Amount = nil + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.tokenomics.EventApplicationReimbursementRequest")) + } + panic(fmt.Errorf("message poktroll.tokenomics.EventApplicationReimbursementRequest does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_EventApplicationReimbursementRequest) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "poktroll.tokenomics.EventApplicationReimbursementRequest.application_addr": + value := x.ApplicationAddr + return protoreflect.ValueOfString(value) + case "poktroll.tokenomics.EventApplicationReimbursementRequest.service_id": + value := x.ServiceId + return protoreflect.ValueOfString(value) + case "poktroll.tokenomics.EventApplicationReimbursementRequest.session_id": + value := x.SessionId + return protoreflect.ValueOfString(value) + case "poktroll.tokenomics.EventApplicationReimbursementRequest.amount": + value := x.Amount + return protoreflect.ValueOfMessage(value.ProtoReflect()) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.tokenomics.EventApplicationReimbursementRequest")) + } + panic(fmt.Errorf("message poktroll.tokenomics.EventApplicationReimbursementRequest does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_EventApplicationReimbursementRequest) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "poktroll.tokenomics.EventApplicationReimbursementRequest.application_addr": + x.ApplicationAddr = value.Interface().(string) + case "poktroll.tokenomics.EventApplicationReimbursementRequest.service_id": + x.ServiceId = value.Interface().(string) + case "poktroll.tokenomics.EventApplicationReimbursementRequest.session_id": + x.SessionId = value.Interface().(string) + case "poktroll.tokenomics.EventApplicationReimbursementRequest.amount": + x.Amount = value.Message().Interface().(*v1beta1.Coin) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.tokenomics.EventApplicationReimbursementRequest")) + } + panic(fmt.Errorf("message poktroll.tokenomics.EventApplicationReimbursementRequest does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_EventApplicationReimbursementRequest) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "poktroll.tokenomics.EventApplicationReimbursementRequest.amount": + if x.Amount == nil { + x.Amount = new(v1beta1.Coin) + } + return protoreflect.ValueOfMessage(x.Amount.ProtoReflect()) + case "poktroll.tokenomics.EventApplicationReimbursementRequest.application_addr": + panic(fmt.Errorf("field application_addr of message poktroll.tokenomics.EventApplicationReimbursementRequest is not mutable")) + case "poktroll.tokenomics.EventApplicationReimbursementRequest.service_id": + panic(fmt.Errorf("field service_id of message poktroll.tokenomics.EventApplicationReimbursementRequest is not mutable")) + case "poktroll.tokenomics.EventApplicationReimbursementRequest.session_id": + panic(fmt.Errorf("field session_id of message poktroll.tokenomics.EventApplicationReimbursementRequest is not mutable")) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.tokenomics.EventApplicationReimbursementRequest")) + } + panic(fmt.Errorf("message poktroll.tokenomics.EventApplicationReimbursementRequest does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_EventApplicationReimbursementRequest) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "poktroll.tokenomics.EventApplicationReimbursementRequest.application_addr": + return protoreflect.ValueOfString("") + case "poktroll.tokenomics.EventApplicationReimbursementRequest.service_id": + return protoreflect.ValueOfString("") + case "poktroll.tokenomics.EventApplicationReimbursementRequest.session_id": + return protoreflect.ValueOfString("") + case "poktroll.tokenomics.EventApplicationReimbursementRequest.amount": + m := new(v1beta1.Coin) + return protoreflect.ValueOfMessage(m.ProtoReflect()) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.tokenomics.EventApplicationReimbursementRequest")) + } + panic(fmt.Errorf("message poktroll.tokenomics.EventApplicationReimbursementRequest does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_EventApplicationReimbursementRequest) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in poktroll.tokenomics.EventApplicationReimbursementRequest", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_EventApplicationReimbursementRequest) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_EventApplicationReimbursementRequest) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_EventApplicationReimbursementRequest) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_EventApplicationReimbursementRequest) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*EventApplicationReimbursementRequest) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + l = len(x.ApplicationAddr) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + l = len(x.ServiceId) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + l = len(x.SessionId) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.Amount != nil { + l = options.Size(x.Amount) + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*EventApplicationReimbursementRequest) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if x.Amount != nil { + encoded, err := options.Marshal(x.Amount) + if err != nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) + i-- + dAtA[i] = 0x22 + } + if len(x.SessionId) > 0 { + i -= len(x.SessionId) + copy(dAtA[i:], x.SessionId) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.SessionId))) + i-- + dAtA[i] = 0x1a + } + if len(x.ServiceId) > 0 { + i -= len(x.ServiceId) + copy(dAtA[i:], x.ServiceId) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.ServiceId))) + i-- + dAtA[i] = 0x12 + } + if len(x.ApplicationAddr) > 0 { + i -= len(x.ApplicationAddr) + copy(dAtA[i:], x.ApplicationAddr) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.ApplicationAddr))) + i-- + dAtA[i] = 0xa + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*EventApplicationReimbursementRequest) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + 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++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: EventApplicationReimbursementRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: EventApplicationReimbursementRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field ApplicationAddr", wireType) + } + var stringLen uint64 + 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++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.ApplicationAddr = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field ServiceId", wireType) + } + var stringLen uint64 + 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++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.ServiceId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field SessionId", wireType) + } + var stringLen uint64 + 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++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.SessionId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var msglen int + 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++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if x.Amount == nil { + x.Amount = &v1beta1.Coin{} + } + if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.Amount); err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.27.0 @@ -2703,16 +3330,77 @@ func (x *EventApplicationOverserviced) GetEffectiveBurn() *v1beta1.Coin { return nil } +// EventApplicationReimbursementRequest is emitted when an application requests a +// reimbursement +type EventApplicationReimbursementRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ApplicationAddr string `protobuf:"bytes,1,opt,name=application_addr,json=applicationAddr,proto3" json:"application_addr,omitempty"` + ServiceId string `protobuf:"bytes,2,opt,name=service_id,json=serviceId,proto3" json:"service_id,omitempty"` + SessionId string `protobuf:"bytes,3,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"` + Amount *v1beta1.Coin `protobuf:"bytes,4,opt,name=amount,proto3" json:"amount,omitempty"` +} + +func (x *EventApplicationReimbursementRequest) Reset() { + *x = EventApplicationReimbursementRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_poktroll_tokenomics_event_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EventApplicationReimbursementRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EventApplicationReimbursementRequest) ProtoMessage() {} + +// Deprecated: Use EventApplicationReimbursementRequest.ProtoReflect.Descriptor instead. +func (*EventApplicationReimbursementRequest) Descriptor() ([]byte, []int) { + return file_poktroll_tokenomics_event_proto_rawDescGZIP(), []int{4} +} + +func (x *EventApplicationReimbursementRequest) GetApplicationAddr() string { + if x != nil { + return x.ApplicationAddr + } + return "" +} + +func (x *EventApplicationReimbursementRequest) GetServiceId() string { + if x != nil { + return x.ServiceId + } + return "" +} + +func (x *EventApplicationReimbursementRequest) GetSessionId() string { + if x != nil { + return x.SessionId + } + return "" +} + +func (x *EventApplicationReimbursementRequest) GetAmount() *v1beta1.Coin { + if x != nil { + return x.Amount + } + return nil +} + var File_poktroll_tokenomics_event_proto protoreflect.FileDescriptor var file_poktroll_tokenomics_event_proto_rawDesc = []byte{ 0x0a, 0x1f, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x13, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x74, 0x6f, 0x6b, 0x65, - 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0x1a, 0x14, 0x67, 0x6f, 0x67, 0x6f, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2f, 0x67, 0x6f, 0x67, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x63, 0x6f, - 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, 0x1a, 0x70, 0x6f, + 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0x1a, 0x1e, 0x63, 0x6f, 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, 0x14, 0x67, 0x6f, 0x67, 0x6f, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2f, 0x67, 0x6f, 0x67, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1a, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x2f, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x20, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x2f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, @@ -2785,25 +3473,37 @@ var file_poktroll_tokenomics_event_proto_rawDesc = []byte{ 0x75, 0x72, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x0d, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x42, - 0x75, 0x72, 0x6e, 0x2a, 0x60, 0x0a, 0x15, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x45, 0x78, 0x70, 0x69, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x1d, - 0x45, 0x58, 0x50, 0x49, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, - 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, - 0x11, 0x0a, 0x0d, 0x50, 0x52, 0x4f, 0x4f, 0x46, 0x5f, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4e, 0x47, - 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x52, 0x4f, 0x4f, 0x46, 0x5f, 0x49, 0x4e, 0x56, 0x41, - 0x4c, 0x49, 0x44, 0x10, 0x02, 0x42, 0xb8, 0x01, 0x0a, 0x17, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x6f, - 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, - 0x73, 0x42, 0x0a, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, - 0x24, 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, 0x74, 0x6f, 0x6b, 0x65, 0x6e, - 0x6f, 0x6d, 0x69, 0x63, 0x73, 0xa2, 0x02, 0x03, 0x50, 0x54, 0x58, 0xaa, 0x02, 0x13, 0x50, 0x6f, - 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, - 0x73, 0xca, 0x02, 0x13, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x54, 0x6f, 0x6b, - 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0xe2, 0x02, 0x1f, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, - 0x6c, 0x6c, 0x5c, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0x5c, 0x47, 0x50, - 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x14, 0x50, 0x6f, 0x6b, 0x74, - 0x72, 0x6f, 0x6c, 0x6c, 0x3a, 0x3a, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x75, 0x72, 0x6e, 0x22, 0xc2, 0x01, 0x0a, 0x24, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x41, 0x70, 0x70, + 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x69, 0x6d, 0x62, 0x75, 0x72, 0x73, + 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x29, 0x0a, 0x10, + 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x31, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, + 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x69, 0x6e, + 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x2a, 0x60, 0x0a, 0x15, 0x43, 0x6c, 0x61, 0x69, + 0x6d, 0x45, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x61, 0x73, 0x6f, + 0x6e, 0x12, 0x21, 0x0a, 0x1d, 0x45, 0x58, 0x50, 0x49, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, + 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, + 0x45, 0x44, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x52, 0x4f, 0x4f, 0x46, 0x5f, 0x4d, 0x49, + 0x53, 0x53, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x52, 0x4f, 0x4f, 0x46, + 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x02, 0x42, 0xb8, 0x01, 0x0a, 0x17, 0x63, + 0x6f, 0x6d, 0x2e, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x74, 0x6f, 0x6b, 0x65, + 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0x42, 0x0a, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, + 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x24, 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, + 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0xa2, 0x02, 0x03, 0x50, 0x54, 0x58, + 0xaa, 0x02, 0x13, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x54, 0x6f, 0x6b, 0x65, + 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0xca, 0x02, 0x13, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, + 0x6c, 0x5c, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0xe2, 0x02, 0x1f, 0x50, + 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, + 0x63, 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, + 0x14, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x3a, 0x3a, 0x54, 0x6f, 0x6b, 0x65, 0x6e, + 0x6f, 0x6d, 0x69, 0x63, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -2819,29 +3519,31 @@ func file_poktroll_tokenomics_event_proto_rawDescGZIP() []byte { } var file_poktroll_tokenomics_event_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_poktroll_tokenomics_event_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_poktroll_tokenomics_event_proto_msgTypes = make([]protoimpl.MessageInfo, 5) var file_poktroll_tokenomics_event_proto_goTypes = []interface{}{ - (ClaimExpirationReason)(0), // 0: poktroll.tokenomics.ClaimExpirationReason - (*EventClaimExpired)(nil), // 1: poktroll.tokenomics.EventClaimExpired - (*EventClaimSettled)(nil), // 2: poktroll.tokenomics.EventClaimSettled - (*EventRelayMiningDifficultyUpdated)(nil), // 3: poktroll.tokenomics.EventRelayMiningDifficultyUpdated - (*EventApplicationOverserviced)(nil), // 4: poktroll.tokenomics.EventApplicationOverserviced - (*proof.Claim)(nil), // 5: poktroll.proof.Claim - (proof.ProofRequirementReason)(0), // 6: poktroll.proof.ProofRequirementReason - (*v1beta1.Coin)(nil), // 7: cosmos.base.v1beta1.Coin + (ClaimExpirationReason)(0), // 0: poktroll.tokenomics.ClaimExpirationReason + (*EventClaimExpired)(nil), // 1: poktroll.tokenomics.EventClaimExpired + (*EventClaimSettled)(nil), // 2: poktroll.tokenomics.EventClaimSettled + (*EventRelayMiningDifficultyUpdated)(nil), // 3: poktroll.tokenomics.EventRelayMiningDifficultyUpdated + (*EventApplicationOverserviced)(nil), // 4: poktroll.tokenomics.EventApplicationOverserviced + (*EventApplicationReimbursementRequest)(nil), // 5: poktroll.tokenomics.EventApplicationReimbursementRequest + (*proof.Claim)(nil), // 6: poktroll.proof.Claim + (proof.ProofRequirementReason)(0), // 7: poktroll.proof.ProofRequirementReason + (*v1beta1.Coin)(nil), // 8: cosmos.base.v1beta1.Coin } var file_poktroll_tokenomics_event_proto_depIdxs = []int32{ - 5, // 0: poktroll.tokenomics.EventClaimExpired.claim:type_name -> poktroll.proof.Claim + 6, // 0: poktroll.tokenomics.EventClaimExpired.claim:type_name -> poktroll.proof.Claim 0, // 1: poktroll.tokenomics.EventClaimExpired.expiration_reason:type_name -> poktroll.tokenomics.ClaimExpirationReason - 5, // 2: poktroll.tokenomics.EventClaimSettled.claim:type_name -> poktroll.proof.Claim - 6, // 3: poktroll.tokenomics.EventClaimSettled.proof_requirement:type_name -> poktroll.proof.ProofRequirementReason - 7, // 4: poktroll.tokenomics.EventApplicationOverserviced.expected_burn:type_name -> cosmos.base.v1beta1.Coin - 7, // 5: poktroll.tokenomics.EventApplicationOverserviced.effective_burn:type_name -> cosmos.base.v1beta1.Coin - 6, // [6:6] is the sub-list for method output_type - 6, // [6:6] is the sub-list for method input_type - 6, // [6:6] is the sub-list for extension type_name - 6, // [6:6] is the sub-list for extension extendee - 0, // [0:6] is the sub-list for field type_name + 6, // 2: poktroll.tokenomics.EventClaimSettled.claim:type_name -> poktroll.proof.Claim + 7, // 3: poktroll.tokenomics.EventClaimSettled.proof_requirement:type_name -> poktroll.proof.ProofRequirementReason + 8, // 4: poktroll.tokenomics.EventApplicationOverserviced.expected_burn:type_name -> cosmos.base.v1beta1.Coin + 8, // 5: poktroll.tokenomics.EventApplicationOverserviced.effective_burn:type_name -> cosmos.base.v1beta1.Coin + 8, // 6: poktroll.tokenomics.EventApplicationReimbursementRequest.amount:type_name -> cosmos.base.v1beta1.Coin + 7, // [7:7] is the sub-list for method output_type + 7, // [7:7] is the sub-list for method input_type + 7, // [7:7] is the sub-list for extension type_name + 7, // [7:7] is the sub-list for extension extendee + 0, // [0:7] is the sub-list for field type_name } func init() { file_poktroll_tokenomics_event_proto_init() } @@ -2898,6 +3600,18 @@ func file_poktroll_tokenomics_event_proto_init() { return nil } } + file_poktroll_tokenomics_event_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EventApplicationReimbursementRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -2905,7 +3619,7 @@ func file_poktroll_tokenomics_event_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_poktroll_tokenomics_event_proto_rawDesc, NumEnums: 1, - NumMessages: 4, + NumMessages: 5, NumExtensions: 0, NumServices: 0, }, diff --git a/proto/poktroll/tokenomics/event.proto b/proto/poktroll/tokenomics/event.proto index 780564496..76ef86e5c 100644 --- a/proto/poktroll/tokenomics/event.proto +++ b/proto/poktroll/tokenomics/event.proto @@ -3,8 +3,8 @@ package poktroll.tokenomics; option go_package = "github.com/pokt-network/poktroll/x/tokenomics/types"; -import "gogoproto/gogo.proto"; import "cosmos/base/v1beta1/coin.proto"; +import "gogoproto/gogo.proto"; import "poktroll/proof/claim.proto"; import "poktroll/proof/requirement.proto"; @@ -51,3 +51,12 @@ message EventApplicationOverserviced { cosmos.base.v1beta1.Coin expected_burn = 2; cosmos.base.v1beta1.Coin effective_burn = 3; } + +// EventApplicationReimbursementRequest is emitted when an application requests a +// reimbursement +message EventApplicationReimbursementRequest { + string application_addr = 1; + string service_id = 2; + string session_id = 3; + cosmos.base.v1beta1.Coin amount = 4; +} diff --git a/x/tokenomics/keeper/token_logic_modules.go b/x/tokenomics/keeper/token_logic_modules.go index 74e6d66c3..0190d78b3 100644 --- a/x/tokenomics/keeper/token_logic_modules.go +++ b/x/tokenomics/keeper/token_logic_modules.go @@ -19,6 +19,7 @@ import ( "github.com/pokt-network/poktroll/telemetry" 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" sharedtypes "github.com/pokt-network/poktroll/x/shared/types" suppliertypes "github.com/pokt-network/poktroll/x/supplier/types" tokenomicstypes "github.com/pokt-network/poktroll/x/tokenomics/types" @@ -26,29 +27,46 @@ import ( ) const ( + // Governance parameters for the TLMGlobalMint module + // TODO_UPNEXT(@olshansk): Remove this. An ephemeral placeholder before + // real values are introduced. When this is changed to a governance param, + // make sure to also add the necessary unit tests. + MintGlobalInflation = 0.0000000 // TODO_UPNEXT(@olshansk): Make all of the governance params MintAllocationDAO = 0.1 MintAllocationProposer = 0.05 MintAllocationSupplier = 0.7 MintAllocationSourceOwner = 0.15 MintAllocationApplication = 0.0 - // TODO_UPNEXT(@olshansk): Remove this. An ephemeral placeholder before - // real values are introduced. When this is changed to a governance param, - // make sure to also add the necessary unit tests. - MintGlobalAllocation = 0.0000000 ) type TokenLogicModule int const ( + // TLMRelayBurnEqualsMint is the token logic module that burns the application's + // stake based on the amount of work done by the supplier. The same amount of + // tokens is minted and sent to the supplier. + // When the network achieves equilibrium, this is theoretically the only TLM that will be necessary. TLMRelayBurnEqualsMint TokenLogicModule = iota + + // TLMGlobalMint is the token logic module that mints new tokens based on the + // on global governance parameters in order to reward the participants providing + // services while keeping inflation in check. TLMGlobalMint - // TODO_UPNEXT(@olshansk): Add more TLMs + + // TLMGlobalMintReimbursementRequest is the token logic module that complements + // TLMGlobalMint to enable permissionless demand. In order to prevent self-dealing + // attacks, applications will be overcharged by the amount equal to global inflation, + // those funds will be sent to the DAO/PNF, and event will be emitted to be used + // for reimbursements. + // TODO_POST_MAINNET: Introduce proper tokenomics based on the research done by @rawthil and @shane. + TLMGlobalMintReimbursementRequest ) var tokenLogicModuleStrings = [...]string{ "TLMRelayBurnEqualsMint", "TLMGlobalMint", + "TLMGlobalMintReimbursementRequest", } func (tlm TokenLogicModule) String() string { @@ -69,6 +87,7 @@ type TokenLogicModuleProcessor func( Keeper, context.Context, *sharedtypes.Service, + *sessiontypes.SessionHeader, *apptypes.Application, *sharedtypes.Supplier, cosmostypes.Coin, @@ -245,6 +264,7 @@ func (k Keeper) ProcessTokenLogicModules( func (k Keeper) TokenLogicModuleRelayBurnEqualsMint( ctx context.Context, service *sharedtypes.Service, + _ *sessiontypes.SessionHeader, application *apptypes.Application, supplier *sharedtypes.Supplier, settlementCoin cosmostypes.Coin, @@ -319,24 +339,19 @@ func (k Keeper) TokenLogicModuleRelayBurnEqualsMint( } // TokenLogicModuleGlobalMint processes the business logic for the GlobalMint TLM. -// TODO_UPNEXT(@olshansk): Delete this in favor of a real TLM that mints tokens -// and distributes them to the appropriate accounts via boosts. func (k Keeper) TokenLogicModuleGlobalMint( ctx context.Context, service *sharedtypes.Service, + _ *sessiontypes.SessionHeader, application *apptypes.Application, supplier *sharedtypes.Supplier, - settlementCoins cosmostypes.Coin, + settlementCoin cosmostypes.Coin, relayMiningDifficulty *tokenomictypes.RelayMiningDifficulty, ) error { logger := k.Logger().With("method", "TokenLogicModuleGlobalMint") // Determine how much new uPOKT to mint based on global inflation - // TODO_MAINNET: Consider using fixed point arithmetic for deterministic results. - settlementAmtFloat := new(big.Float).SetUint64(settlementCoins.Amount.Uint64()) - newMintAmtFloat := new(big.Float).Mul(settlementAmtFloat, big.NewFloat(MintGlobalAllocation)) - newMintAmtInt, _ := newMintAmtFloat.Int64() - newMintCoins := sdk.NewCoins(cosmostypes.NewCoin(volatile.DenomuPOKT, math.NewInt(newMintAmtInt))) + newMintCoins, newMintAmtFloat := calculateGlobalMintAllocationFromSettlementAmount(settlementCoin) // Mint new uPOKT to the tokenomics module account if err := k.bankKeeper.MintCoins(ctx, tokenomictypes.ModuleName, newMintCoins); err != nil { @@ -353,15 +368,16 @@ func (k Keeper) TokenLogicModuleGlobalMint( logger.Debug(fmt.Sprintf("sent (%v) newley minted coins from the tokenomics module to the application with address %q", appCoin, application.Address)) // Send a portion of the rewards to the supplier shareholders. - coinsToShareAmt := calculateGlobalMintAllocationFromSettlementAmount(newMintAmtFloat, MintAllocationSupplier) - if err = k.distributeSupplierRewardsToShareHolders(ctx, supplier.OperatorAddress, service.Id, uint64(coinsToShareAmt)); err != nil { + supplierCoinsToShareAmt := calculateAllocationAmount(newMintAmtFloat, MintAllocationSupplier) + supplierCoin := cosmostypes.NewCoin(volatile.DenomuPOKT, math.NewInt(supplierCoinsToShareAmt)) + if err = k.distributeSupplierRewardsToShareHolders(ctx, supplier.OperatorAddress, service.Id, uint64(supplierCoinsToShareAmt)); err != nil { return tokenomicstypes.ErrTokenomicsSupplierModuleMintFailed.Wrapf( "distributing rewards to supplier with operator address %s shareholders: %v", supplier.OperatorAddress, err, ) } - supplierCoin := cosmostypes.NewCoin(volatile.DenomuPOKT, math.NewInt(newMintAmtInt)) + logger.Debug(fmt.Sprintf("sent (%v) newley minted coins from the tokenomics module to the supplier with address %q", supplierCoin, supplier.OperatorAddress)) // Send a portion of the rewards to the DAO @@ -386,16 +402,73 @@ func (k Keeper) TokenLogicModuleGlobalMint( } logger.Debug(fmt.Sprintf("sent (%v) newley minted coins from the tokenomics module to the proposer with address %q", proposerCoin, proposerAddr)) - // TODO_MAINNET: Verify that the total distributed coins equals the settlement coins which could happen due to float rounding + // Check and log the total amount of coins distributed totalDistributedCoins := appCoin.Add(supplierCoin).Add(*daoCoin).Add(*serviceCoin).Add(*proposerCoin) - if totalDistributedCoins.Amount.BigInt().Cmp(settlementCoins.Amount.BigInt()) != 0 { - logger.Error(fmt.Sprintf("TODO_MAINNET: The total distributed coins (%v) does not equal the settlement coins (%v)", totalDistributedCoins, settlementCoins.Amount.BigInt())) + if totalDistributedCoins.Amount.BigInt().Cmp(settlementCoin.Amount.BigInt()) != 0 { + logger.Error(fmt.Sprintf("TODO_MAINNET: Verify why the total distributed coins (%v) do not equal the settlement coins (%v). Likely floating point arithmetic.", totalDistributedCoins, settlementCoin.Amount.BigInt())) } logger.Info(fmt.Sprintf("distributed (%v) coins to the application, supplier, DAO, source owner, and proposer", totalDistributedCoins)) return nil } +// 1. Mint = Burn +// 2. Global Mint +// 4. Overcharge applications +// - Determine the amount send to suppliers +// - Determine the amount send to source owner +// - Overcharge application based on the sum of the two above +// - Send the overcharge to the PNF +// - Emit an event so we can track it +// - PNF manually reimburses the application at the end of the month +// - Prevents self dealing because application has to ask for reimbursement +// - Does not introduce friction to service owners getting rewarded +// - Does not introduce friction to suppliers getting rewarded +// - Ensure NewSession breaks if app stake is too low +// - Ensure relayminer has a toggle to prevent over charging +func (k Keeper) TokenLogicModuleGlobalMintReimbursementRequest( + ctx context.Context, + service *sharedtypes.Service, + sessionHeader *sessiontypes.SessionHeader, + application *apptypes.Application, + supplier *sharedtypes.Supplier, + settlementCoins cosmostypes.Coin, + relayMiningDifficulty *tokenomictypes.RelayMiningDifficulty, +) error { + logger := k.Logger().With("method", "TokenLogicModuleGlobalMint") + + // Determine how much new uPOKT to mint based on global inflation + newMintCoins, _ := calculateGlobalMintAllocationFromSettlementAmount(settlementCoins) + + + + // EventApplicationReimbursementRequest + reimbursementRequest := tokenomictypes.EventApplicationReimbursementRequest{ + ApplicationAddr: application.Address, + ServiceId: service.Id, + SessionId: sessionHeader.SessionId, + Amount: &newMintCoins[0], + } + + eventManager := cosmostypes.UnwrapSDKContext(ctx).EventManager() + if err := eventManager.EmitTypedEvent(&reimbursementRequest); err != nil { + return tokenomicstypes.ErrTokenomicsApplicationReimbursementRequestFailed.Wrapf( + "application address: %s; service Id %s; session Id: %s; amount: %s", + application.GetAddress(), + service.Id, + sessionHeader.SessionId, + newMintCoins.String(), + ) + } + + // EventApplicationReimbursementRequest + // What if the application is overcharged? + // How do I enforce running both of them? + // Need to add a new governance parameter? + // Should we prevent new application sessions from starting if its too low? + return nil +} + // sendRewardsToAccount sends (settlementAmtFloat * allocation) tokens from the // tokenomics module account to the specified address. func (k Keeper) sendRewardsToAccount( @@ -411,7 +484,7 @@ func (k Keeper) sendRewardsToAccount( return nil, err } - coinsToAccAmt := calculateGlobalMintAllocationFromSettlementAmount(settlementAmtFloat, allocation) + coinsToAccAmt := calculateAllocationAmount(settlementAmtFloat, allocation) coinToAcc := cosmostypes.NewCoin(volatile.DenomuPOKT, math.NewInt(coinsToAccAmt)) if err := k.bankKeeper.SendCoinsFromModuleToAccount( ctx, suppliertypes.ModuleName, accountAddr, sdk.NewCoins(coinToAcc), @@ -454,12 +527,13 @@ func (k Keeper) handleOverservicedApplication( } eventManager := cosmostypes.UnwrapSDKContext(ctx).EventManager() if err := eventManager.EmitTypedEvent(applicationOverservicedEvent); err != nil { - return cosmostypes.Coin{}, tokenomicstypes.ErrTokenomicsApplicationOverserviced.Wrapf( - "application address: %s; expected burn %s; effective burn: %s", - application.GetAddress(), - expectedBurn.String(), - application.GetStake().String(), - ) + return cosmostypes.Coin{}, + tokenomicstypes.ErrTokenomicsApplicationOverservicedEvent.Wrapf( + "application address: %s; expected burn %s; effective burn: %s", + application.GetAddress(), + expectedBurn.String(), + application.GetStake().String(), + ) } return *application.Stake, nil } @@ -518,6 +592,7 @@ func (k Keeper) distributeSupplierRewardsToShareHolders( shareAmountMap := GetShareAmountMap(serviceRevShare, amountToDistribute) for shareHolderAddress, shareAmount := range shareAmountMap { + // TODO_IN_THIS_PR: Why don't we use sendRewardsToAccount here? shareAmountCoin := cosmostypes.NewCoin(volatile.DenomuPOKT, math.NewInt(int64(shareAmount))) shareAmountCoins := cosmostypes.NewCoins(shareAmountCoin) shareHolderAccAddress, err := sdk.AccAddressFromBech32(shareHolderAddress) @@ -541,14 +616,26 @@ func (k Keeper) distributeSupplierRewardsToShareHolders( return nil } -// calculateGlobalMintAllocationFromSettlementAmount calculates the global mint -// allocation resulting from the GlobalMint TLM given the settlement amount and -// the allocation percentage. -func calculateGlobalMintAllocationFromSettlementAmount( - settlementAmtFloat *big.Float, - allocation float64, +// calculateGlobalMintAllocationFromSettlementAmount calculates the amount of uPOKT +// to mint based on the global inflation rate as a function of the settlement amount +// for a particular claim(s) or session(s). +func calculateGlobalMintAllocationFromSettlementAmount(settlementCoin sdk.Coin) (sdk.Coins, *big.Float) { + // Determine how much new uPOKT to mint based on global inflation + // TODO_MAINNET: Consider using fixed point arithmetic for deterministic results. + settlementAmtFloat := new(big.Float).SetUint64(settlementCoin.Amount.Uint64()) + newMintAmtFloat := new(big.Float).Mul(settlementAmtFloat, big.NewFloat(MintGlobalInflation)) + newMintAmtInt, _ := newMintAmtFloat.Int64() + mintAmtCoins := sdk.NewCoins(cosmostypes.NewCoin(volatile.DenomuPOKT, math.NewInt(newMintAmtInt))) + return mintAmtCoins, newMintAmtFloat +} + +// calculateAllocationAmount does big float arithmetic to determine the absolute +// amount from amountFloat based on the allocation percentage provided. +func calculateAllocationAmount( + amountFloat *big.Float, + allocationPercentage float64, ) int64 { - coinsToAccAmt, _ := big.NewFloat(0).Mul(settlementAmtFloat, big.NewFloat(allocation)).Int64() + coinsToAccAmt, _ := big.NewFloat(0).Mul(amountFloat, big.NewFloat(allocationPercentage)).Int64() return coinsToAccAmt } @@ -563,12 +650,12 @@ func GetShareAmountMap( ) (shareAmountMap map[string]uint64) { totalDistributed := uint64(0) shareAmountMap = make(map[string]uint64, len(serviceRevShare)) - for _, revshare := range serviceRevShare { + for _, revShare := range serviceRevShare { // TODO_MAINNET: Consider using fixed point arithmetic for deterministic results. - sharePercentageFloat := big.NewFloat(float64(revshare.RevSharePercentage) / 100) + sharePercentageFloat := big.NewFloat(float64(revShare.RevSharePercentage) / 100) amountToDistributeFloat := big.NewFloat(float64(amountToDistribute)) shareAmount, _ := big.NewFloat(0).Mul(amountToDistributeFloat, sharePercentageFloat).Uint64() - shareAmountMap[revshare.Address] = shareAmount + shareAmountMap[revShare.Address] = shareAmount totalDistributed += shareAmount } diff --git a/x/tokenomics/types/errors.go b/x/tokenomics/types/errors.go index 3ff72fc5a..6e7c23a0d 100644 --- a/x/tokenomics/types/errors.go +++ b/x/tokenomics/types/errors.go @@ -6,30 +6,31 @@ import sdkerrors "cosmossdk.io/errors" // x/tokenomics module sentinel errors var ( - ErrTokenomicsInvalidSigner = sdkerrors.Register(ModuleName, 1100, "the provided authority address does not match the on-chain governance address") - ErrTokenomicsAddressInvalid = sdkerrors.Register(ModuleName, 1101, "the provided authority address is not a valid bech32 address") - ErrTokenomicsClaimNil = sdkerrors.Register(ModuleName, 1102, "provided claim is nil") - ErrTokenomicsSessionHeaderNil = sdkerrors.Register(ModuleName, 1103, "provided claim's session header is nil") - ErrTokenomicsSessionHeaderInvalid = sdkerrors.Register(ModuleName, 1104, "provided claim's session header is invalid") - ErrTokenomicsSupplierModuleSendFailed = sdkerrors.Register(ModuleName, 1105, "failed to send uPOKT to supplier module account") - ErrTokenomicsSupplierOperatorAddressInvalid = sdkerrors.Register(ModuleName, 1106, "the supplier operator address in the claim is not a valid bech32 address") - ErrTokenomicsSupplierNotFound = sdkerrors.Register(ModuleName, 1107, "supplier not found") - ErrTokenomicsApplicationNotFound = sdkerrors.Register(ModuleName, 1108, "application not found") - ErrTokenomicsApplicationModuleBurn = sdkerrors.Register(ModuleName, 1109, "failed to burn uPOKT from application module account") - ErrTokenomicsApplicationAddressInvalid = sdkerrors.Register(ModuleName, 1110, "the application address in the claim is not a valid bech32 address") - ErrTokenomicsParamsInvalid = sdkerrors.Register(ModuleName, 1111, "provided params are invalid") - ErrTokenomicsRootHashInvalid = sdkerrors.Register(ModuleName, 1112, "the root hash in the claim is invalid") - ErrTokenomicsApplicationNewStakeInvalid = sdkerrors.Register(ModuleName, 1113, "application stake cannot be reduced to a -ve amount") - ErrTokenomicsParamNameInvalid = sdkerrors.Register(ModuleName, 1114, "the provided param name is invalid") - ErrTokenomicsParamInvalid = sdkerrors.Register(ModuleName, 1115, "the provided param is invalid") - ErrTokenomicsUnmarshalInvalid = sdkerrors.Register(ModuleName, 1116, "failed to unmarshal the provided bytes") - ErrTokenomicsDuplicateIndex = sdkerrors.Register(ModuleName, 1117, "cannot have a duplicate index") - ErrTokenomicsMissingRelayMiningDifficulty = sdkerrors.Register(ModuleName, 1118, "missing relay mining difficulty") - ErrTokenomicsApplicationOverserviced = sdkerrors.Register(ModuleName, 1119, "application was overserviced") - ErrTokenomicsServiceNotFound = sdkerrors.Register(ModuleName, 1120, "service not found") - ErrTokenomicsModuleMintFailed = sdkerrors.Register(ModuleName, 1121, "failed to mint uPOKT to tokenomics module account") - ErrTokenomicsSendingMintRewards = sdkerrors.Register(ModuleName, 1122, "failed to send minted rewards") - ErrTokenomicsSupplierModuleMintFailed = sdkerrors.Register(ModuleName, 1123, "failed to mint uPOKT to supplier module account") - ErrTokenomicsSupplierOwnerAddressInvalid = sdkerrors.Register(ModuleName, 1124, "the supplier owner address in the claim is not a valid bech32 address") - ErrTokenomicsSupplierRevShareFailed = sdkerrors.Register(ModuleName, 1125, "failed to send rev share to supplier shareholders") + ErrTokenomicsInvalidSigner = sdkerrors.Register(ModuleName, 1100, "the provided authority address does not match the on-chain governance address") + ErrTokenomicsAddressInvalid = sdkerrors.Register(ModuleName, 1101, "the provided authority address is not a valid bech32 address") + ErrTokenomicsClaimNil = sdkerrors.Register(ModuleName, 1102, "provided claim is nil") + ErrTokenomicsSessionHeaderNil = sdkerrors.Register(ModuleName, 1103, "provided claim's session header is nil") + ErrTokenomicsSessionHeaderInvalid = sdkerrors.Register(ModuleName, 1104, "provided claim's session header is invalid") + ErrTokenomicsSupplierModuleSendFailed = sdkerrors.Register(ModuleName, 1105, "failed to send uPOKT to supplier module account") + ErrTokenomicsSupplierOperatorAddressInvalid = sdkerrors.Register(ModuleName, 1106, "the supplier operator address in the claim is not a valid bech32 address") + ErrTokenomicsSupplierNotFound = sdkerrors.Register(ModuleName, 1107, "supplier not found") + ErrTokenomicsApplicationNotFound = sdkerrors.Register(ModuleName, 1108, "application not found") + ErrTokenomicsApplicationModuleBurn = sdkerrors.Register(ModuleName, 1109, "failed to burn uPOKT from application module account") + ErrTokenomicsApplicationAddressInvalid = sdkerrors.Register(ModuleName, 1110, "the application address in the claim is not a valid bech32 address") + ErrTokenomicsParamsInvalid = sdkerrors.Register(ModuleName, 1111, "provided params are invalid") + ErrTokenomicsRootHashInvalid = sdkerrors.Register(ModuleName, 1112, "the root hash in the claim is invalid") + ErrTokenomicsApplicationNewStakeInvalid = sdkerrors.Register(ModuleName, 1113, "application stake cannot be reduced to a -ve amount") + ErrTokenomicsParamNameInvalid = sdkerrors.Register(ModuleName, 1114, "the provided param name is invalid") + ErrTokenomicsParamInvalid = sdkerrors.Register(ModuleName, 1115, "the provided param is invalid") + ErrTokenomicsUnmarshalInvalid = sdkerrors.Register(ModuleName, 1116, "failed to unmarshal the provided bytes") + ErrTokenomicsDuplicateIndex = sdkerrors.Register(ModuleName, 1117, "cannot have a duplicate index") + ErrTokenomicsMissingRelayMiningDifficulty = sdkerrors.Register(ModuleName, 1118, "missing relay mining difficulty") + ErrTokenomicsApplicationOverservicedEvent = sdkerrors.Register(ModuleName, 1119, "application overserviced event cannot be sent") + ErrTokenomicsServiceNotFound = sdkerrors.Register(ModuleName, 1120, "service not found") + ErrTokenomicsModuleMintFailed = sdkerrors.Register(ModuleName, 1121, "failed to mint uPOKT to tokenomics module account") + ErrTokenomicsSendingMintRewards = sdkerrors.Register(ModuleName, 1122, "failed to send minted rewards") + ErrTokenomicsSupplierModuleMintFailed = sdkerrors.Register(ModuleName, 1123, "failed to mint uPOKT to supplier module account") + ErrTokenomicsSupplierOwnerAddressInvalid = sdkerrors.Register(ModuleName, 1124, "the supplier owner address in the claim is not a valid bech32 address") + ErrTokenomicsSupplierRevShareFailed = sdkerrors.Register(ModuleName, 1125, "failed to send rev share to supplier shareholders") + ErrTokenomicsApplicationReimbursementRequestFailed = sdkerrors.Register(ModuleName, 1126, "failed to send application reimbursement request event") ) diff --git a/x/tokenomics/types/event.pb.go b/x/tokenomics/types/event.pb.go index 5c55fbc6e..945d4ab97 100644 --- a/x/tokenomics/types/event.pb.go +++ b/x/tokenomics/types/event.pb.go @@ -335,63 +335,138 @@ func (m *EventApplicationOverserviced) GetEffectiveBurn() *types1.Coin { return nil } +// EventApplicationReimbursementRequest is emitted when an application requests a +// reimbursement +type EventApplicationReimbursementRequest struct { + ApplicationAddr string `protobuf:"bytes,1,opt,name=application_addr,json=applicationAddr,proto3" json:"application_addr,omitempty"` + ServiceId string `protobuf:"bytes,2,opt,name=service_id,json=serviceId,proto3" json:"service_id,omitempty"` + SessionId string `protobuf:"bytes,3,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"` + Amount *types1.Coin `protobuf:"bytes,4,opt,name=amount,proto3" json:"amount,omitempty"` +} + +func (m *EventApplicationReimbursementRequest) Reset() { *m = EventApplicationReimbursementRequest{} } +func (m *EventApplicationReimbursementRequest) String() string { return proto.CompactTextString(m) } +func (*EventApplicationReimbursementRequest) ProtoMessage() {} +func (*EventApplicationReimbursementRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_a78874bbf91a58c7, []int{4} +} +func (m *EventApplicationReimbursementRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *EventApplicationReimbursementRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_EventApplicationReimbursementRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *EventApplicationReimbursementRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_EventApplicationReimbursementRequest.Merge(m, src) +} +func (m *EventApplicationReimbursementRequest) XXX_Size() int { + return m.Size() +} +func (m *EventApplicationReimbursementRequest) XXX_DiscardUnknown() { + xxx_messageInfo_EventApplicationReimbursementRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_EventApplicationReimbursementRequest proto.InternalMessageInfo + +func (m *EventApplicationReimbursementRequest) GetApplicationAddr() string { + if m != nil { + return m.ApplicationAddr + } + return "" +} + +func (m *EventApplicationReimbursementRequest) GetServiceId() string { + if m != nil { + return m.ServiceId + } + return "" +} + +func (m *EventApplicationReimbursementRequest) GetSessionId() string { + if m != nil { + return m.SessionId + } + return "" +} + +func (m *EventApplicationReimbursementRequest) GetAmount() *types1.Coin { + if m != nil { + return m.Amount + } + return nil +} + func init() { proto.RegisterEnum("poktroll.tokenomics.ClaimExpirationReason", ClaimExpirationReason_name, ClaimExpirationReason_value) proto.RegisterType((*EventClaimExpired)(nil), "poktroll.tokenomics.EventClaimExpired") proto.RegisterType((*EventClaimSettled)(nil), "poktroll.tokenomics.EventClaimSettled") proto.RegisterType((*EventRelayMiningDifficultyUpdated)(nil), "poktroll.tokenomics.EventRelayMiningDifficultyUpdated") proto.RegisterType((*EventApplicationOverserviced)(nil), "poktroll.tokenomics.EventApplicationOverserviced") + proto.RegisterType((*EventApplicationReimbursementRequest)(nil), "poktroll.tokenomics.EventApplicationReimbursementRequest") } func init() { proto.RegisterFile("poktroll/tokenomics/event.proto", fileDescriptor_a78874bbf91a58c7) } var fileDescriptor_a78874bbf91a58c7 = []byte{ - // 718 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x54, 0xc1, 0x4e, 0xdb, 0x4a, - 0x14, 0x8d, 0x03, 0x3c, 0x29, 0xc3, 0x03, 0x12, 0x53, 0xd4, 0x94, 0x42, 0x12, 0xb2, 0xa8, 0x28, + // 776 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x55, 0xcd, 0x4e, 0xeb, 0x46, + 0x14, 0x8e, 0xc3, 0x8f, 0x94, 0xa1, 0x40, 0x32, 0x14, 0x35, 0xa5, 0x90, 0x84, 0xa8, 0xaa, 0x28, 0x15, 0xb6, 0x00, 0xa9, 0xab, 0x0a, 0x35, 0x09, 0xa6, 0x58, 0x2a, 0x49, 0xe4, 0x40, 0x55, 0x75, - 0x33, 0x75, 0xec, 0x9b, 0x64, 0x4a, 0x3c, 0xe3, 0x8e, 0xc7, 0x49, 0xf8, 0x8b, 0x7e, 0x40, 0x7f, - 0xa0, 0x8b, 0xfe, 0x47, 0xa5, 0x6e, 0x58, 0x76, 0x85, 0x2a, 0xd8, 0xf1, 0x15, 0x95, 0xc7, 0x21, - 0x49, 0x03, 0x55, 0xd7, 0xdd, 0x24, 0xd6, 0x3d, 0xe7, 0xdc, 0x7b, 0xe6, 0x78, 0x7c, 0x51, 0xde, - 0x67, 0x67, 0x82, 0xb3, 0x6e, 0x57, 0x17, 0xec, 0x0c, 0x28, 0xf3, 0x88, 0x13, 0xe8, 0xd0, 0x03, - 0x2a, 0x34, 0x9f, 0x33, 0xc1, 0xd4, 0xe5, 0x5b, 0x82, 0x36, 0x26, 0xac, 0x3e, 0x68, 0xb3, 0x36, - 0x93, 0xb8, 0x1e, 0x3d, 0xc5, 0xd4, 0xd5, 0x9c, 0xc3, 0x02, 0x8f, 0x05, 0x7a, 0xd3, 0x0e, 0x40, - 0xef, 0xed, 0x34, 0x41, 0xd8, 0x3b, 0xba, 0xc3, 0x08, 0x1d, 0xe2, 0xab, 0xa3, 0x59, 0x3e, 0x67, - 0xac, 0xa5, 0x3b, 0x5d, 0x9b, 0x78, 0x43, 0xac, 0x30, 0x85, 0x71, 0xf8, 0x18, 0x12, 0x0e, 0xde, - 0xc8, 0x48, 0xf1, 0x6b, 0x12, 0x65, 0x8c, 0xc8, 0x58, 0x25, 0x92, 0x19, 0x03, 0x9f, 0x70, 0x70, - 0xd5, 0xe7, 0x68, 0x4e, 0xb6, 0xc9, 0x2a, 0x05, 0x65, 0x73, 0x7e, 0x77, 0x45, 0x1b, 0xd9, 0x95, - 0x7d, 0x34, 0x49, 0x2e, 0xa7, 0x6e, 0x2e, 0xf3, 0x31, 0xcf, 0x8a, 0xff, 0xd4, 0x6d, 0x84, 0x68, - 0xe8, 0x61, 0x0e, 0x5d, 0xfb, 0x3c, 0xc8, 0x26, 0x0b, 0xca, 0xe6, 0x6c, 0x79, 0xf1, 0xe6, 0x32, - 0x3f, 0x51, 0xb5, 0x52, 0x34, 0xf4, 0x2c, 0xf9, 0xa8, 0x96, 0x50, 0x26, 0x02, 0x1c, 0xe6, 0xf9, - 0xa1, 0x00, 0x1c, 0x52, 0x22, 0x82, 0xec, 0x8c, 0x54, 0xad, 0xdc, 0x5c, 0xe6, 0xef, 0x82, 0xd6, - 0x12, 0x0d, 0xbd, 0x4a, 0x5c, 0x39, 0x8d, 0x0a, 0x2a, 0x45, 0x19, 0x88, 0x4c, 0xdb, 0x82, 0x30, - 0x8a, 0x39, 0xd8, 0x01, 0xa3, 0xd9, 0xd9, 0x82, 0xb2, 0xb9, 0xb8, 0xbb, 0xa5, 0xdd, 0x13, 0xb2, - 0x36, 0x3e, 0xa7, 0x94, 0x58, 0x52, 0x11, 0x8f, 0xbb, 0xd3, 0xc8, 0x4a, 0xc3, 0x14, 0xb1, 0xf8, - 0xe5, 0xb7, 0xbc, 0x1a, 0x20, 0x44, 0xf7, 0x9f, 0xca, 0xeb, 0x03, 0xca, 0x48, 0x4b, 0x78, 0xe2, - 0x2a, 0x0c, 0xf3, 0x7a, 0x32, 0xed, 0xba, 0x1e, 0xfd, 0x5a, 0x63, 0xde, 0x64, 0x56, 0x77, 0x9a, - 0x58, 0x69, 0x7f, 0x8a, 0x5e, 0xfc, 0x9c, 0x44, 0x1b, 0x32, 0x2b, 0x69, 0xff, 0x98, 0x50, 0x42, - 0xdb, 0x07, 0xa4, 0xd5, 0x22, 0x4e, 0xd8, 0x15, 0xe7, 0xa7, 0xbe, 0x6b, 0x0b, 0x70, 0xd5, 0x75, - 0x84, 0x02, 0xe0, 0x3d, 0xe2, 0x00, 0x26, 0xae, 0x0c, 0x30, 0x65, 0xa5, 0x86, 0x15, 0xd3, 0x55, - 0xf7, 0xd1, 0x9a, 0xcf, 0xa1, 0x87, 0x85, 0xcd, 0xdb, 0x20, 0x70, 0xc7, 0x0e, 0x3a, 0xb8, 0x03, - 0x03, 0x0c, 0xd4, 0x61, 0x2e, 0xb8, 0x32, 0xb4, 0x94, 0x95, 0x8d, 0x38, 0x27, 0x92, 0x72, 0x64, - 0x07, 0x9d, 0x23, 0x18, 0x18, 0x31, 0xae, 0xbe, 0x40, 0x8f, 0x29, 0xf4, 0xff, 0x28, 0x9f, 0x91, - 0xf2, 0x87, 0x14, 0xfa, 0xf7, 0xaa, 0xb7, 0xd1, 0xb2, 0x9c, 0x3e, 0x7e, 0x1f, 0x18, 0x3c, 0x5b, - 0x06, 0x36, 0x1b, 0x9d, 0x18, 0x7a, 0xd5, 0xdb, 0xb7, 0x63, 0x78, 0xb6, 0xfa, 0x0c, 0xa9, 0xd1, - 0xb0, 0x29, 0xf6, 0x9c, 0x64, 0x2f, 0x51, 0xe8, 0x4f, 0x92, 0x8b, 0xdf, 0x15, 0xb4, 0x26, 0xe3, - 0x29, 0xf9, 0x7e, 0x97, 0x38, 0xf2, 0x96, 0xd5, 0x7a, 0xc0, 0x87, 0x67, 0x77, 0xd5, 0xa7, 0x28, - 0x6d, 0x8f, 0x21, 0x6c, 0xbb, 0x2e, 0x1f, 0xe6, 0xb3, 0x34, 0x51, 0x2f, 0xb9, 0x2e, 0x57, 0xf7, - 0xd1, 0x02, 0x0c, 0x7c, 0x70, 0x04, 0xb8, 0xb8, 0x19, 0x72, 0x2a, 0x63, 0x99, 0xdf, 0x7d, 0xa4, - 0xc5, 0xcb, 0x43, 0x8b, 0x96, 0x87, 0x36, 0x5c, 0x1e, 0x5a, 0x85, 0x11, 0x6a, 0xfd, 0x7f, 0xcb, - 0x2f, 0x87, 0x9c, 0xaa, 0x2f, 0xd1, 0x22, 0xb4, 0x5a, 0xe0, 0x08, 0xd2, 0x83, 0xb8, 0xc1, 0xcc, - 0xdf, 0x1a, 0x2c, 0x8c, 0x04, 0x51, 0x87, 0xad, 0xf7, 0x68, 0xe5, 0xde, 0x4f, 0x4b, 0xdd, 0x40, - 0xeb, 0xc6, 0xdb, 0xba, 0x69, 0x95, 0x4e, 0xcc, 0x5a, 0x15, 0x5b, 0x46, 0xa9, 0x51, 0xab, 0xe2, - 0xd3, 0x6a, 0xa3, 0x6e, 0x54, 0xcc, 0x43, 0xd3, 0x38, 0x48, 0x27, 0xd4, 0x0c, 0x5a, 0xa8, 0x5b, - 0xb5, 0xda, 0x21, 0x3e, 0x36, 0x1b, 0x0d, 0xb3, 0xfa, 0x2a, 0xad, 0x8c, 0x4b, 0x66, 0xf5, 0x4d, - 0xe9, 0xb5, 0x79, 0x90, 0x4e, 0x96, 0x8f, 0xbf, 0x5d, 0xe5, 0x94, 0x8b, 0xab, 0x9c, 0xf2, 0xf3, - 0x2a, 0xa7, 0x7c, 0xba, 0xce, 0x25, 0x2e, 0xae, 0x73, 0x89, 0x1f, 0xd7, 0xb9, 0xc4, 0xbb, 0xbd, - 0x36, 0x11, 0x9d, 0xb0, 0xa9, 0x39, 0xcc, 0xd3, 0xa3, 0x3b, 0xbc, 0x4d, 0x41, 0xf4, 0x19, 0x3f, - 0xd3, 0x47, 0xeb, 0x6f, 0x30, 0xb9, 0x88, 0xc5, 0xb9, 0x0f, 0x41, 0xf3, 0x3f, 0xb9, 0x00, 0xf7, - 0x7e, 0x05, 0x00, 0x00, 0xff, 0xff, 0xac, 0x71, 0x68, 0xf9, 0xac, 0x05, 0x00, 0x00, + 0xe3, 0x3a, 0xf6, 0x49, 0x32, 0x25, 0x9e, 0x31, 0xe3, 0x71, 0x12, 0xde, 0xa2, 0x0f, 0xd0, 0x17, + 0xe8, 0xa2, 0x2f, 0xd1, 0x55, 0xa5, 0x6e, 0x58, 0x76, 0x85, 0x2a, 0xd8, 0xf1, 0x14, 0x57, 0x1e, + 0x3b, 0x3f, 0x04, 0xee, 0xbd, 0xba, 0xcb, 0xbb, 0x49, 0x46, 0xe7, 0x7c, 0xdf, 0x37, 0xe7, 0x7c, + 0x73, 0x72, 0x82, 0x8a, 0x3e, 0xbb, 0x16, 0x9c, 0xf5, 0xfb, 0x9a, 0x60, 0xd7, 0x40, 0x99, 0x47, + 0x9c, 0x40, 0x83, 0x01, 0x50, 0xa1, 0xfa, 0x9c, 0x09, 0x86, 0x37, 0xc6, 0x00, 0x75, 0x0a, 0xd8, + 0x2a, 0x38, 0x2c, 0xf0, 0x58, 0xa0, 0xb5, 0xed, 0x00, 0xb4, 0xc1, 0x61, 0x1b, 0x84, 0x7d, 0xa8, + 0x39, 0x8c, 0xd0, 0x98, 0xb4, 0xf5, 0x69, 0x97, 0x75, 0x99, 0x3c, 0x6a, 0xd1, 0x29, 0x89, 0x6e, + 0x4d, 0xee, 0xf2, 0x39, 0x63, 0x1d, 0xcd, 0xe9, 0xdb, 0xc4, 0x4b, 0x72, 0xa5, 0xb9, 0x1c, 0x87, + 0x9b, 0x90, 0x70, 0xf0, 0x26, 0x85, 0x94, 0xff, 0x4a, 0xa3, 0x9c, 0x1e, 0x15, 0x56, 0x8b, 0x68, + 0xfa, 0xc8, 0x27, 0x1c, 0x5c, 0xfc, 0x2d, 0x5a, 0x92, 0x32, 0x79, 0xa5, 0xa4, 0xec, 0xad, 0x1c, + 0x6d, 0xaa, 0x93, 0x72, 0xa5, 0x8e, 0x2a, 0xc1, 0xd5, 0xcc, 0xd3, 0x7d, 0x31, 0xc6, 0x99, 0xf1, + 0x17, 0x3e, 0x40, 0x88, 0x86, 0x9e, 0xc5, 0xa1, 0x6f, 0xdf, 0x06, 0xf9, 0x74, 0x49, 0xd9, 0x5b, + 0xac, 0xae, 0x3d, 0xdd, 0x17, 0x67, 0xa2, 0x66, 0x86, 0x86, 0x9e, 0x29, 0x8f, 0xb8, 0x82, 0x72, + 0x51, 0xc2, 0x61, 0x9e, 0x1f, 0x0a, 0xb0, 0x42, 0x4a, 0x44, 0x90, 0x5f, 0x90, 0xac, 0xcd, 0xa7, + 0xfb, 0xe2, 0xcb, 0xa4, 0xb9, 0x4e, 0x43, 0xaf, 0x16, 0x47, 0xae, 0xa2, 0x00, 0xa6, 0x28, 0x07, + 0x51, 0xd1, 0xb6, 0x20, 0x8c, 0x5a, 0x1c, 0xec, 0x80, 0xd1, 0xfc, 0x62, 0x49, 0xd9, 0x5b, 0x3b, + 0xda, 0x57, 0x5f, 0x31, 0x59, 0x9d, 0xf6, 0x29, 0x29, 0xa6, 0x64, 0xc4, 0xd7, 0xbd, 0x10, 0x32, + 0xb3, 0x30, 0x07, 0x2c, 0xff, 0xf9, 0xcc, 0xaf, 0x16, 0x08, 0xd1, 0xff, 0xa8, 0xfc, 0xfa, 0x0d, + 0xe5, 0x64, 0x49, 0xd6, 0xcc, 0x28, 0x24, 0x7e, 0x7d, 0x35, 0x5f, 0x75, 0x33, 0xfa, 0x34, 0xa7, + 0xb8, 0x59, 0xaf, 0x5e, 0x88, 0x98, 0x59, 0x7f, 0x0e, 0x5e, 0xfe, 0x23, 0x8d, 0x76, 0xa5, 0x57, + 0xb2, 0xfc, 0x0b, 0x42, 0x09, 0xed, 0x9e, 0x92, 0x4e, 0x87, 0x38, 0x61, 0x5f, 0xdc, 0x5e, 0xf9, + 0xae, 0x2d, 0xc0, 0xc5, 0x3b, 0x08, 0x05, 0xc0, 0x07, 0xc4, 0x01, 0x8b, 0xb8, 0xd2, 0xc0, 0x8c, + 0x99, 0x49, 0x22, 0x86, 0x8b, 0x4f, 0xd0, 0xb6, 0xcf, 0x61, 0x60, 0x09, 0x9b, 0x77, 0x41, 0x58, + 0x3d, 0x3b, 0xe8, 0x59, 0x3d, 0x18, 0x59, 0x40, 0x1d, 0xe6, 0x82, 0x2b, 0x4d, 0xcb, 0x98, 0xf9, + 0x08, 0x73, 0x29, 0x21, 0xe7, 0x76, 0xd0, 0x3b, 0x87, 0x91, 0x1e, 0xe7, 0xf1, 0x77, 0xe8, 0x0b, + 0x0a, 0xc3, 0xb7, 0xd2, 0x17, 0x24, 0xfd, 0x33, 0x0a, 0xc3, 0x57, 0xd9, 0x07, 0x68, 0x43, 0xde, + 0x3e, 0x7d, 0x0f, 0x0b, 0x3c, 0x5b, 0x1a, 0xb6, 0x18, 0x75, 0x0c, 0x83, 0xfa, 0xf8, 0x75, 0x74, + 0xcf, 0xc6, 0xdf, 0x20, 0x1c, 0x5d, 0x36, 0x87, 0x5e, 0x92, 0xe8, 0x75, 0x0a, 0xc3, 0x59, 0x70, + 0xf9, 0x5f, 0x05, 0x6d, 0x4b, 0x7b, 0x2a, 0xbe, 0xdf, 0x27, 0x8e, 0x9c, 0xb2, 0xc6, 0x00, 0x78, + 0xd2, 0xbb, 0x8b, 0xbf, 0x46, 0x59, 0x7b, 0x9a, 0xb2, 0x6c, 0xd7, 0xe5, 0x89, 0x3f, 0xeb, 0x33, + 0xf1, 0x8a, 0xeb, 0x72, 0x7c, 0x82, 0x56, 0x61, 0xe4, 0x83, 0x23, 0xc0, 0xb5, 0xda, 0x21, 0xa7, + 0xd2, 0x96, 0x95, 0xa3, 0xcf, 0xd5, 0x78, 0xa5, 0xa8, 0xd1, 0x4a, 0x51, 0x93, 0x95, 0xa2, 0xd6, + 0x18, 0xa1, 0xe6, 0x27, 0x63, 0x7c, 0x35, 0xe4, 0x14, 0x7f, 0x8f, 0xd6, 0xa0, 0xd3, 0x01, 0x47, + 0x90, 0x01, 0xc4, 0x02, 0x0b, 0xef, 0x13, 0x58, 0x9d, 0x10, 0x22, 0x85, 0xf2, 0xdf, 0x0a, 0xfa, + 0x72, 0xbe, 0x1b, 0x13, 0x88, 0xd7, 0x0e, 0x79, 0x90, 0x4c, 0xcf, 0x4d, 0x08, 0x81, 0xf8, 0x90, + 0xae, 0x9e, 0x8f, 0x46, 0x7a, 0x7e, 0x34, 0x64, 0x3a, 0x08, 0x22, 0x15, 0x32, 0x7e, 0xc9, 0x4c, + 0x12, 0x31, 0x5c, 0x7c, 0x88, 0x96, 0x6d, 0x8f, 0x85, 0xc9, 0x7c, 0xbf, 0xb3, 0x97, 0x04, 0xb8, + 0xff, 0x2b, 0xda, 0x7c, 0x75, 0x3f, 0xe0, 0x5d, 0xb4, 0xa3, 0xff, 0xdc, 0x34, 0xcc, 0xca, 0xa5, + 0xd1, 0xa8, 0x5b, 0xa6, 0x5e, 0x69, 0x35, 0xea, 0xd6, 0x55, 0xbd, 0xd5, 0xd4, 0x6b, 0xc6, 0x99, + 0xa1, 0x9f, 0x66, 0x53, 0x38, 0x87, 0x56, 0x9b, 0x66, 0xa3, 0x71, 0x66, 0x5d, 0x18, 0xad, 0x96, + 0x51, 0xff, 0x21, 0xab, 0x4c, 0x43, 0x46, 0xfd, 0xa7, 0xca, 0x8f, 0xc6, 0x69, 0x36, 0x5d, 0xbd, + 0xf8, 0xe7, 0xa1, 0xa0, 0xdc, 0x3d, 0x14, 0x94, 0xff, 0x1f, 0x0a, 0xca, 0xef, 0x8f, 0x85, 0xd4, + 0xdd, 0x63, 0x21, 0xf5, 0xdf, 0x63, 0x21, 0xf5, 0xcb, 0x71, 0x97, 0x88, 0x5e, 0xd8, 0x56, 0x1d, + 0xe6, 0x69, 0xd1, 0x0f, 0xf1, 0x80, 0x82, 0x18, 0x32, 0x7e, 0xad, 0x4d, 0x76, 0xf8, 0x68, 0xf6, + 0xdf, 0x44, 0xdc, 0xfa, 0x10, 0xb4, 0x97, 0xe5, 0x16, 0x3f, 0x7e, 0x13, 0x00, 0x00, 0xff, 0xff, + 0xe7, 0x04, 0xe0, 0xc6, 0x71, 0x06, 0x00, 0x00, } func (m *EventClaimExpired) Marshal() (dAtA []byte, err error) { @@ -602,6 +677,62 @@ func (m *EventApplicationOverserviced) MarshalToSizedBuffer(dAtA []byte) (int, e return len(dAtA) - i, nil } +func (m *EventApplicationReimbursementRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *EventApplicationReimbursementRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *EventApplicationReimbursementRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Amount != nil { + { + size, err := m.Amount.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvent(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + if len(m.SessionId) > 0 { + i -= len(m.SessionId) + copy(dAtA[i:], m.SessionId) + i = encodeVarintEvent(dAtA, i, uint64(len(m.SessionId))) + i-- + dAtA[i] = 0x1a + } + if len(m.ServiceId) > 0 { + i -= len(m.ServiceId) + copy(dAtA[i:], m.ServiceId) + i = encodeVarintEvent(dAtA, i, uint64(len(m.ServiceId))) + i-- + dAtA[i] = 0x12 + } + if len(m.ApplicationAddr) > 0 { + i -= len(m.ApplicationAddr) + copy(dAtA[i:], m.ApplicationAddr) + i = encodeVarintEvent(dAtA, i, uint64(len(m.ApplicationAddr))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintEvent(dAtA []byte, offset int, v uint64) int { offset -= sovEvent(v) base := offset @@ -705,6 +836,31 @@ func (m *EventApplicationOverserviced) Size() (n int) { return n } +func (m *EventApplicationReimbursementRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ApplicationAddr) + if l > 0 { + n += 1 + l + sovEvent(uint64(l)) + } + l = len(m.ServiceId) + if l > 0 { + n += 1 + l + sovEvent(uint64(l)) + } + l = len(m.SessionId) + if l > 0 { + n += 1 + l + sovEvent(uint64(l)) + } + if m.Amount != nil { + l = m.Amount.Size() + n += 1 + l + sovEvent(uint64(l)) + } + return n +} + func sovEvent(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -1335,6 +1491,188 @@ func (m *EventApplicationOverserviced) Unmarshal(dAtA []byte) error { } return nil } +func (m *EventApplicationReimbursementRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvent + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: EventApplicationReimbursementRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: EventApplicationReimbursementRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ApplicationAddr", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvent + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvent + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvent + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ApplicationAddr = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ServiceId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvent + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvent + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvent + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ServiceId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SessionId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvent + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvent + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvent + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SessionId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvent + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEvent + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvent + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Amount == nil { + m.Amount = &types1.Coin{} + } + if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipEvent(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthEvent + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipEvent(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/tokenomics/types/tx.pb.go b/x/tokenomics/types/tx.pb.go index 91f06eeff..5bc7d33e4 100644 --- a/x/tokenomics/types/tx.pb.go +++ b/x/tokenomics/types/tx.pb.go @@ -133,7 +133,6 @@ type MsgUpdateParam struct { // specified in the `Params` message in `proof/params.proto.` Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` // Types that are valid to be assigned to AsType: - // // *MsgUpdateParam_AsString // *MsgUpdateParam_AsInt64 // *MsgUpdateParam_AsBytes From c3a235a737817a215b0c29b66b713a6b95e7c336 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Tue, 20 Aug 2024 21:09:41 -0400 Subject: [PATCH 02/53] Checkpoint --- api/poktroll/application/params.pulsar.go | 3 + api/poktroll/tokenomics/event.pulsar.go | 4 +- .../protocol/architecture/_category_.json | 4 +- .../docs/protocol/architecture/network.md | 2 +- .../docs/protocol/tokenomics/_category_.json | 8 + .../docs/protocol/tokenomics/resources.md | 18 ++ .../tokenomics/token_logic_modules.md | 157 ++++++++++++++++++ .../docs/protocol/upgrades/_category_.json | 2 +- pkg/relayer/session/sessiontree.go | 7 +- proto/poktroll/shared/service.proto | 6 +- proto/poktroll/tokenomics/event.proto | 17 +- x/application/types/params.pb.go | 3 + x/session/keeper/session_hydrator.go | 1 + x/tokenomics/keeper/token_logic_modules.go | 84 +++++----- x/tokenomics/types/errors.go | 1 + x/tokenomics/types/event.pb.go | 4 +- 16 files changed, 268 insertions(+), 53 deletions(-) create mode 100644 docusaurus/docs/protocol/tokenomics/_category_.json create mode 100644 docusaurus/docs/protocol/tokenomics/resources.md create mode 100644 docusaurus/docs/protocol/tokenomics/token_logic_modules.md diff --git a/api/poktroll/application/params.pulsar.go b/api/poktroll/application/params.pulsar.go index d7854990e..f4918ce45 100644 --- a/api/poktroll/application/params.pulsar.go +++ b/api/poktroll/application/params.pulsar.go @@ -437,6 +437,9 @@ type Params struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + // max_delegated_gateways defines the maximum number of gateways that a single + // application can delegate to. This is used to prevent performance issues + // in case the relay ring signature becomes too large. MaxDelegatedGateways uint64 `protobuf:"varint,1,opt,name=max_delegated_gateways,json=maxDelegatedGateways,proto3" json:"max_delegated_gateways,omitempty"` } diff --git a/api/poktroll/tokenomics/event.pulsar.go b/api/poktroll/tokenomics/event.pulsar.go index ae7a1d67b..c0303e634 100644 --- a/api/poktroll/tokenomics/event.pulsar.go +++ b/api/poktroll/tokenomics/event.pulsar.go @@ -3330,8 +3330,8 @@ func (x *EventApplicationOverserviced) GetEffectiveBurn() *v1beta1.Coin { return nil } -// EventApplicationReimbursementRequest is emitted when an application requests a -// reimbursement +// EventApplicationReimbursementRequest is emitted when an application requests +// a reimbursement type EventApplicationReimbursementRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache diff --git a/docusaurus/docs/protocol/architecture/_category_.json b/docusaurus/docs/protocol/architecture/_category_.json index c4be422a5..985d17b7b 100644 --- a/docusaurus/docs/protocol/architecture/_category_.json +++ b/docusaurus/docs/protocol/architecture/_category_.json @@ -1,6 +1,6 @@ { - "label": "Architecture", - "position": 7, + "label": "[Outdated] Architecture", + "position": 6, "link": { "type": "generated-index", "description": "Documentation related to the high-level design, flows and components of the poktroll repo." diff --git a/docusaurus/docs/protocol/architecture/network.md b/docusaurus/docs/protocol/architecture/network.md index d0e25f1d3..b7949986e 100644 --- a/docusaurus/docs/protocol/architecture/network.md +++ b/docusaurus/docs/protocol/architecture/network.md @@ -1,5 +1,5 @@ --- -title: Pocket Actors, Nodes & Data Availability Network +title: Outdated - Pocket Actors, Nodes & Data Availability Network sidebar_position: 1 --- diff --git a/docusaurus/docs/protocol/tokenomics/_category_.json b/docusaurus/docs/protocol/tokenomics/_category_.json new file mode 100644 index 000000000..c23caaa17 --- /dev/null +++ b/docusaurus/docs/protocol/tokenomics/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "Tokenomics", + "position": 5, + "link": { + "type": "generated-index", + "description": "Documentation related to Pocket Network tokenomics." + } +} diff --git a/docusaurus/docs/protocol/tokenomics/resources.md b/docusaurus/docs/protocol/tokenomics/resources.md new file mode 100644 index 000000000..9b31e6ec1 --- /dev/null +++ b/docusaurus/docs/protocol/tokenomics/resources.md @@ -0,0 +1,18 @@ +--- +title: Tokenomics Resources +sidebar_position: 1 +--- + +# Tokenomics Resources + +The following resources serve as the foundation for the Shannon Upgrade Tokenomics. + +It is an active an ever evolving work, but the following resources are the best +starting references: + +- [Token Logic Module](https://docs.pokt.network/pokt-protocol/the-shannon-upgrade/proposed-tokenomics/token-logic-modules) design approach. +- [Shannon Tokenomics Static](https://github.com/pokt-network/shannon-tokenomics-static-tests) modeling & evaluation +- [Relay Mining](https://arxiv.org/abs/2305.10672) paper +- [Probabilistic Proofs](https://github.com/pokt-network/pocket-core/blob/staging/docs/proposals/probabilistic_proofs.md) design + +Thank you to [@Rama_stdout](https://x.com/Rama_stdout), [@shane8burger](https://x.com/shane8burger) and [@olshansky](https://x.com/olshansky) for the contributions! diff --git a/docusaurus/docs/protocol/tokenomics/token_logic_modules.md b/docusaurus/docs/protocol/tokenomics/token_logic_modules.md new file mode 100644 index 000000000..3fd36ddd0 --- /dev/null +++ b/docusaurus/docs/protocol/tokenomics/token_logic_modules.md @@ -0,0 +1,157 @@ +--- +title: Token Logic Modules +sidebar_position: 2 +--- + +# Token Logic Modules + +- [Introduction](#introduction) +- [Background: Relay Mining Payable Relay Accumulation](#background-relay-mining-payable-relay-accumulation) +- [TLM Pre-processor: Claim Settlement Limit](#tlm-pre-processor-claim-settlement-limit) +- [TLM: Mint=Burn (MEB)](#tlm-mintburn-meb) +- [TLM: Global Mint (GM)](#tlm-global-mint-gm) +- [TLM: Global Mint Reimbursement Request (GMRR)](#tlm-global-mint-reimbursement-request-gmrr) + +## Introduction + +:::warning + +Note that this is an active WIP and the [resources here](./resources.md) are the best starting references to learn more. + +::: + +Token Logic Modules (TLMs) processing involves: + +1. `TLM pre-processing` - A general pre-processor determining the amount of coins to settle per claim +2. `TLM processing` - Individual processing each TLM independent of the other + +## Background: Relay Mining Payable Relay Accumulation + +Per **Algorithm 1** of the [Relay Mining paper](https://arxiv.org/pdf/2305.10672), +the maximum amount a supplier can claim from an application in a single session is +proportional to the Application's stake divided by the number of nodes in the session +as see in the following image: + +![Algorithm 1](https://github.com/user-attachments/assets/d1a61535-aa31-447d-88ea-c8d14dcb20c6) + +## TLM Pre-processor: Claim Settlement Limit + +**Prior to** processing each individual TLM, we need to understand if the amount claimed +by the supplier adheres to the maximum allowed per the limits set by Relay Mining. + +Suppliers always have the option to over-service an application (**i.e. do free work**), +in exchange for providing a good service to the network, but their on-chain rewards +are still limited as a function of the application's stake before the session started +and the number of nodes in the session. + +:::note + +TODO_POST_MAINNET: After the Shannon upgrade, the team at Grove has a lot of ideas +related to [supplier gossipin](https://www.notion.so/buildwithgrove/Off-chain-Application-Stake-Tracking-6a8bebb107db4f7f9dc62cbe7ba555f7?pvs=4) but that +is out of scope for the initial implementation. + +::: + +```mermaid +--- +title: "Token Logic Modules Processor" +--- +flowchart TB + CSA(["Claim Settlement Amount (CSA)"]) + MCS(["MaxClaimPerSupplier (MCS)
= (AppStake / NumNodesPerSession)"]) + CC{"Is CSA > MCS?"} + Update(Set SA = MCS
Broadcast Event) + SOAE{{Application Overserviced
Event}} + TLMP[["TLM Processor (SA)"]] + + CSA -- CSA --> CC + MCS -- MCS --> CC + + Update -..-> SOAE + CC -- Yes --> Update + CC -- No
SA=CSA --> TLMP + Update -- SA=CSA --> TLMP + + TLMP --SA--> TLMBEM[[TLM: Burn Equals Mint]] + TLMP --SA--> TLMGI[[TLM: Global Inflation]] + TLMP --SA--> TLMGIRR[[TLM: Global Inflation Reimbursment Request]] + + classDef tlm fill:#54ebd5,stroke:#333,stroke-width:2px; + classDef question fill:#e3db6d,stroke:#333,stroke-width:2px; + classDef event fill:#e8b761,stroke:#333,stroke-width:2px; + + class TLMP,TLMBEM,TLMGI,TLMGIRR tlm; + class SOAE event; + class CC question; +``` + +## TLM: Mint=Burn (MEB) + +The `Mint=Burn` TLM is, _theoretically_, the only TLM necessary when the network +reaches equilibrium in the far future. + +Put simply, it is a transfer of tokens from the application to the supplier based on the +amount of work done by the supplier. + +The same amount of tokens that is minted in the supplier module is burned from the application module. +The stake of the application paying for work is reduced and the rewards are distributed to the supplier +and its revenue shareholder addresses. + +```mermaid +--- +title: "Token Logic Module: Mint=Burn" +--- +flowchart TD + SA(["Settlement Amount (SA)"]) + + SA -- Mint SA coins --> SM + SA -- Burn SA coins--> AM + + subgraph SO[Supplier Operations] + SM[[Supplier Module]] + SK[(Supplier Keeper)] + SD{Distribute SA coins} + OPA[Operator Address] + OA[Owner Address] + RSA[Revenue Share Addresses] + + SM -.- SK + SD -->|% Distribution
Increase Balance| OPA + SD -->|% Distribution
Increase Balance| OA + SD -->|% Distribution
Increase Balance| RSA + end + + subgraph AO[Application Operations] + AM[[Application Module]] + AK[(Application Keeper)] + AA[Application Address] + + AM -.- AK + AK -. Reduce Stake by CSA .-> AA + end + + SM --> SD + + + classDef module fill:#f9f,stroke:#333,stroke-width:2px; + classDef address fill:#bbf,stroke:#333,stroke-width:2px; + classDef question fill:#e3db6d,stroke:#333,stroke-width:2px; + classDef event fill:#e8b761,stroke:#333,stroke-width:2px; + + class SM,AM module; + class RSA,OA,OPA,AA address; +``` + +## TLM: Global Mint (GM) + +TLMGlobalMint is the token logic module that mints new tokens based on the +on global governance parameters in order to reward the participants providing +services while keeping inflation in check. + +## TLM: Global Mint Reimbursement Request (GMRR) + +TLMGlobalMintReimbursementRequest is the token logic module that complements +TLMGlobalMint to enable permissionless demand. In order to prevent self-dealing +attacks, applications will be overcharged by the amount equal to global inflation, +those funds will be sent to the DAO/PNF, and event will be emitted to be used +for reimbursements. diff --git a/docusaurus/docs/protocol/upgrades/_category_.json b/docusaurus/docs/protocol/upgrades/_category_.json index 5fe4a715b..2e80f4c80 100644 --- a/docusaurus/docs/protocol/upgrades/_category_.json +++ b/docusaurus/docs/protocol/upgrades/_category_.json @@ -1,6 +1,6 @@ { "label": "Upgrades", - "position": 7, + "position": 4, "link": { "type": "generated-index", "description": "Documentation related to Pocket Network protocol upgrades." diff --git a/pkg/relayer/session/sessiontree.go b/pkg/relayer/session/sessiontree.go index 843186b0d..d54992c82 100644 --- a/pkg/relayer/session/sessiontree.go +++ b/pkg/relayer/session/sessiontree.go @@ -19,7 +19,11 @@ import ( var _ relayer.SessionTree = (*sessionTree)(nil) // sessionTree is an implementation of the SessionTree interface. -// TODO_TEST: Add tests to the sessionTree. +// TODO_BETA(@red-0ne): Per the Relay Mining paper, we need to optimistically store +// the number of requests that an application can pay for. This needs to be tracked +// based on the app's stake in the beginning of a session and the number of nodes +// per session. An operator should be able to specify "overservicing_okay" whereby +// it keeps replying to requests even though it may not get paid for them. type sessionTree struct { // sessionMu is a mutex used to protect sessionTree operations from concurrent access. sessionMu *sync.Mutex @@ -65,6 +69,7 @@ type sessionTree struct { // NewSessionTree creates a new sessionTree from a Session and a storePrefix. It also takes a function // removeFromRelayerSessions that removes the sessionTree from the RelayerSessionsManager. // It returns an error if the KVStore fails to be created. +// TODO_BETA(@red-0ne): When starting a new session, check how many relays the app can handle. func NewSessionTree( sessionHeader *sessiontypes.SessionHeader, supplierOperatorAddress *cosmostypes.AccAddress, diff --git a/proto/poktroll/shared/service.proto b/proto/poktroll/shared/service.proto index 4777b0ccb..f6aa00d78 100644 --- a/proto/poktroll/shared/service.proto +++ b/proto/poktroll/shared/service.proto @@ -13,7 +13,7 @@ message Service { // For example, what if we want to request a session for a certain service but with some additional configs that identify it? string id = 1; // Unique identifier for the service - // TODO_MAINNET: Remove this. + // TODO_BETA: Either remove this or rename it to alias. string name = 2; // (Optional) Semantic human readable name for the service // The cost of a single relay for this service in terms of compute units. @@ -30,7 +30,7 @@ message Service { // ApplicationServiceConfig holds the service configuration the application stakes for message ApplicationServiceConfig { - // TODO_MAINNET: Avoid embedding the full Service because we just need the ID. + // TODO_BETA: Avoid embedding the full Service because we just need the ID. Service service = 1; // The Service for which the application is configured // TODO_MAINNET: There is an opportunity for applications to advertise the max @@ -40,7 +40,7 @@ message ApplicationServiceConfig { // SupplierServiceConfig holds the service configuration the supplier stakes for message SupplierServiceConfig { - // TODO_MAINNET: Avoid embedding the full Service because we just need the ID. + // TODO_BETA: Avoid embedding the full Service because we just need the ID. Service service = 1; // The Service for which the supplier is configured repeated SupplierEndpoint endpoints = 2; // List of endpoints for the service repeated ServiceRevenueShare rev_share = 3; // List of revenue share configurations for the service diff --git a/proto/poktroll/tokenomics/event.proto b/proto/poktroll/tokenomics/event.proto index 76ef86e5c..00a089f8f 100644 --- a/proto/poktroll/tokenomics/event.proto +++ b/proto/poktroll/tokenomics/event.proto @@ -44,16 +44,25 @@ message EventRelayMiningDifficultyUpdated { uint64 new_num_relays_ema = 5; } -// EventApplicationOverserviced is emitted when an application has less stake -// than the expected burn. +// EventApplicationOverserviced is emitted when an application has less stake than +// what a supplier is claiming (i.e. burn is not high enough). message EventApplicationOverserviced { string application_addr = 1; + string supplier_addr = 2; + cosmos.base.v1beta1.Coin expected_burn = 3; + cosmos.base.v1beta1.Coin effective_burn = 4; +} + +// EventSupplierExceededClaimableAmount is emitted when a supplier application has less stake +// than the expected burn. +message EventSupplierExceededClaimableAmount { + string supplier_addr = 1; cosmos.base.v1beta1.Coin expected_burn = 2; cosmos.base.v1beta1.Coin effective_burn = 3; } -// EventApplicationReimbursementRequest is emitted when an application requests a -// reimbursement +// EventApplicationReimbursementRequest is emitted when an application requests +// a reimbursement message EventApplicationReimbursementRequest { string application_addr = 1; string service_id = 2; diff --git a/x/application/types/params.pb.go b/x/application/types/params.pb.go index a2caf90b1..227e0f149 100644 --- a/x/application/types/params.pb.go +++ b/x/application/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 { + // max_delegated_gateways defines the maximum number of gateways that a single + // application can delegate to. This is used to prevent performance issues + // in case the relay ring signature becomes too large. MaxDelegatedGateways uint64 `protobuf:"varint,1,opt,name=max_delegated_gateways,json=maxDelegatedGateways,proto3" json:"max_delegated_gateways" yaml:"max_delegated_gateways"` } diff --git a/x/session/keeper/session_hydrator.go b/x/session/keeper/session_hydrator.go index e0711dd3a..60c292836 100644 --- a/x/session/keeper/session_hydrator.go +++ b/x/session/keeper/session_hydrator.go @@ -59,6 +59,7 @@ func NewSessionHydrator( // GetSession implements of the exposed `UtilityModule.GetSession` function // TECHDEBT(#519,#348): Add custom error types depending on the type of issue that occurred and assert on them in the unit tests. +// TODO_BETA: Consider returning an error if the application's stake has become very low. func (k Keeper) HydrateSession(ctx context.Context, sh *sessionHydrator) (*types.Session, error) { logger := k.Logger().With("method", "hydrateSession") diff --git a/x/tokenomics/keeper/token_logic_modules.go b/x/tokenomics/keeper/token_logic_modules.go index 0190d78b3..99cff2611 100644 --- a/x/tokenomics/keeper/token_logic_modules.go +++ b/x/tokenomics/keeper/token_logic_modules.go @@ -98,6 +98,7 @@ type TokenLogicModuleProcessor func( var tokenLogicModuleProcessorMap = map[TokenLogicModule]TokenLogicModuleProcessor{ TLMRelayBurnEqualsMint: Keeper.TokenLogicModuleRelayBurnEqualsMint, TLMGlobalMint: Keeper.TokenLogicModuleGlobalMint, + // TLMGlobalMintReimbursementRequest: Keeper.TokenLogicModuleGlobalMintReimbursementRequest, } func init() { @@ -107,9 +108,9 @@ func init() { } } -// ProcessTokenLogicModules is responsible for calling all of the token logic -// modules (i.e. post session claim accounting) necessary to burn, mint or transfer -// tokens as a result of the amount of work (i.e. compute units) done. +// ProcessTokenLogicModules is the main TLM processor. It is responsible for calling +// all of the token logic module necessary to limit, burn, mint or transfer tokens +// as a result of the amount of work (i.e. compute units) done and governance parameters. func (k Keeper) ProcessTokenLogicModules( ctx context.Context, claim *prooftypes.Claim, // IMPORTANT: It is assumed the proof for the claim has been validated BEFORE calling this function @@ -117,17 +118,17 @@ func (k Keeper) ProcessTokenLogicModules( logger := k.Logger().With("method", "ProcessTokenLogicModules") // Declaring variables that will be emitted by telemetry - settlementCoin := cosmostypes.NewCoin("upokt", math.NewInt(0)) + claimSettlementCoin := cosmostypes.NewCoin("upokt", math.NewInt(0)) isSuccessful := false // This is emitted only when the function returns (successful or not) defer telemetry.EventSuccessCounter( "process_token_logic_modules", func() float32 { - if settlementCoin.Amount.BigInt() == nil { + if claimSettlementCoin.Amount.BigInt() == nil { return 0 } - return float32(settlementCoin.Amount.Int64()) + return float32(claimSettlementCoin.Amount.Int64()) }, func() bool { return isSuccessful }, ) @@ -196,6 +197,7 @@ func (k Keeper) ProcessTokenLogicModules( if err != nil { return tokenomicstypes.ErrTokenomicsRootHashInvalid.Wrapf("%v", err) } + // TODO_POST_MAINNET: Because of how things have evolved, we are now using // root.Count (numRelays) instead of root.Sum (numComputeUnits) to determine // the amount of work done. This is because the compute_units_per_relay is @@ -207,7 +209,7 @@ func (k Keeper) ProcessTokenLogicModules( // Determine the total number of tokens that'll be used for settling the session. // When the network achieves equilibrium, this will be the mint & burn. - settlementCoin, err = k.numRelaysToCoin(ctx, numRelays, &service) + claimSettlementCoin, err = k.numRelaysToCoin(ctx, numRelays, &service) if err != nil { return err } @@ -230,18 +232,33 @@ func (k Keeper) ProcessTokenLogicModules( // Helpers for logging the same metadata throughout this function calls logger = logger.With( "num_relays", numRelays, - "num_settlement_upokt", settlementCoin.Amount, + "claim_settlement_upokt", claimSettlementCoin.Amount, "session_id", sessionHeader.GetSessionId(), "service_id", sessionHeader.GetService().Id, "supplier_operator", supplier.OperatorAddress, "application", application.Address, ) - logger.Info(fmt.Sprintf("About to start processing TLMs for (%d) relays equaling to (%s) coins", numRelays, settlementCoin)) + logger.Info(fmt.Sprintf("About to start processing TLMs for (%d) relays equaling to (%s) upokt claimed", numRelays, claimSettlementCoin)) + + maxClaimableAmount := application.GetStake().QuoUint64(uint64(relayMiningDifficulty.NumNodesPerSession)) + + // Reduce the settlement amount if the application was over-serviced + var actualSettlementCoin cosmostypes.Coin + if application.GetStake().IsLT(claimSettlementCoin) { + actualSettlementCoin, err = k.handleOverservicedApplication(ctx, &application, claimSettlementCoin) + if err != nil { + return err + } + logger.Warn(fmt.Sprintf("Application with address %s was over-serviced so the actual amount being settled is (%v) instead of the claimed amount (%v) ", application.Address, actualSettlementCoin, claimSettlementCoin)) + } else { + actualSettlementCoin = claimSettlementCoin + } + logger = logger.With("actual_settlement_upokt", actualSettlementCoin) // Execute all the token logic modules processors for tlm, tlmProcessor := range tokenLogicModuleProcessorMap { logger.Info(fmt.Sprintf("Starting to execute TLM %q", tlm)) - if err := tlmProcessor(k, ctx, &service, &application, &supplier, settlementCoin, &relayMiningDifficulty); err != nil { + if err := tlmProcessor(k, ctx, &service, claim.SessionHeader, &application, &supplier, actualSettlementCoin, &relayMiningDifficulty); err != nil { return err } logger.Info(fmt.Sprintf("Finished executing TLM %q", tlm)) @@ -277,7 +294,7 @@ func (k Keeper) TokenLogicModuleRelayBurnEqualsMint( return err } - // NB: We are doing a mint & burn + transfer, instead of a simple transfer + // DEV_NOTE: We are doing a mint & burn + transfer, instead of a simple transfer // of funds from the supplier to the application in order to enable second // order economic effects with more optionality. This could include funds // going to pnf, delegators, enabling bonuses/rebates, etc... @@ -305,19 +322,6 @@ func (k Keeper) TokenLogicModuleRelayBurnEqualsMint( } logger.Info(fmt.Sprintf("sent (%v) from the supplier module to the supplier account with address %q", settlementCoin, supplier.OperatorAddress)) - // TODO_MAINNET: Decide on the behaviour here when an app is over serviced. - // If an app has 10 POKT staked, but the supplier earned 20 POKT. We still - // end up minting 20 POKT but only burn 10 POKT from the app. There are - // questions and nuance here that needs to be addressed. - - // Verify that the application has enough uPOKT to pay for the services it consumed - if application.GetStake().IsLT(settlementCoin) { - settlementCoin, err = k.handleOverservicedApplication(ctx, application, settlementCoin) - if err != nil { - return err - } - } - // Burn uPOKT from the application module account which was held in escrow // on behalf of the application account. if err = k.bankKeeper.BurnCoins( @@ -404,8 +408,8 @@ func (k Keeper) TokenLogicModuleGlobalMint( // Check and log the total amount of coins distributed totalDistributedCoins := appCoin.Add(supplierCoin).Add(*daoCoin).Add(*serviceCoin).Add(*proposerCoin) - if totalDistributedCoins.Amount.BigInt().Cmp(settlementCoin.Amount.BigInt()) != 0 { - logger.Error(fmt.Sprintf("TODO_MAINNET: Verify why the total distributed coins (%v) do not equal the settlement coins (%v). Likely floating point arithmetic.", totalDistributedCoins, settlementCoin.Amount.BigInt())) + if totalDistributedCoins.Amount.BigInt().Cmp(newMintCoins[0].Amount.BigInt()) != 0 { + return tokenomictypes.ErrTokenomicsAmountMismatch.Wrapf("the total distributed coins (%v) do not equal the settlement coins (%v). Likely floating point arithmetic.", totalDistributedCoins, settlementCoin.Amount.BigInt()) } logger.Info(fmt.Sprintf("distributed (%v) coins to the application, supplier, DAO, source owner, and proposer", totalDistributedCoins)) @@ -435,15 +439,13 @@ func (k Keeper) TokenLogicModuleGlobalMintReimbursementRequest( settlementCoins cosmostypes.Coin, relayMiningDifficulty *tokenomictypes.RelayMiningDifficulty, ) error { - logger := k.Logger().With("method", "TokenLogicModuleGlobalMint") + // logger := k.Logger().With("method", "TokenLogicModuleGlobalMintReimbursementRequest") // Determine how much new uPOKT to mint based on global inflation newMintCoins, _ := calculateGlobalMintAllocationFromSettlementAmount(settlementCoins) - - // EventApplicationReimbursementRequest - reimbursementRequest := tokenomictypes.EventApplicationReimbursementRequest{ + reimbursementRequestEvent := tokenomictypes.EventApplicationReimbursementRequest{ ApplicationAddr: application.Address, ServiceId: service.Id, SessionId: sessionHeader.SessionId, @@ -451,7 +453,7 @@ func (k Keeper) TokenLogicModuleGlobalMintReimbursementRequest( } eventManager := cosmostypes.UnwrapSDKContext(ctx).EventManager() - if err := eventManager.EmitTypedEvent(&reimbursementRequest); err != nil { + if err := eventManager.EmitTypedEvent(&reimbursementRequestEvent); err != nil { return tokenomicstypes.ErrTokenomicsApplicationReimbursementRequestFailed.Wrapf( "application address: %s; service Id %s; session Id: %s; amount: %s", application.GetAddress(), @@ -496,20 +498,25 @@ func (k Keeper) sendRewardsToAccount( return &coinToAcc, nil } +// handleOverservicedApplication handles the case where an application has been over-serviced. +// Per Algorithm #1 in the Relay Mining paper, the maximum amount that a single supplier +// can claim in a session is AppStake/NumNodesPerSession. +// If this is not the case, then the supplier essentially did "free work" and the actual +// claim amount is less than what was claimed. +// Ref: https://arxiv.org/pdf/2305.10672 func (k Keeper) handleOverservicedApplication( ctx context.Context, application *apptypes.Application, - settlementCoins cosmostypes.Coin, + claimSettlementCoin cosmostypes.Coin, ) ( - newSettlementCoins cosmostypes.Coin, + actualSettlementCoins cosmostypes.Coin, err error, ) { logger := k.Logger().With("method", "handleOverservicedApplication") - // over-serviced application logger.Warn(fmt.Sprintf( "THIS SHOULD NEVER HAPPEN. Application with address %s needs to be charged more than it has staked: %v > %v", application.Address, - settlementCoins, + claimSettlementCoin, application.Stake, )) @@ -518,7 +525,7 @@ func (k Keeper) handleOverservicedApplication( // probabilistic proofs and add all the parameter logic. Do we touch the application balance? // Do we just let it go into debt? Do we penalize the application? Do we unstake it? Etc... // See this document from @red-0ne and @bryanchriswhite for more context: notion.so/buildwithgrove/Off-chain-Application-Stake-Tracking-6a8bebb107db4f7f9dc62cbe7ba555f7 - expectedBurn := settlementCoins + expectedBurn := claimSettlementCoin applicationOverservicedEvent := &tokenomicstypes.EventApplicationOverserviced{ ApplicationAddr: application.Address, @@ -535,6 +542,9 @@ func (k Keeper) handleOverservicedApplication( application.GetStake().String(), ) } + + // TODO(@red-0ne) + return *application.Stake, nil } @@ -592,7 +602,7 @@ func (k Keeper) distributeSupplierRewardsToShareHolders( shareAmountMap := GetShareAmountMap(serviceRevShare, amountToDistribute) for shareHolderAddress, shareAmount := range shareAmountMap { - // TODO_IN_THIS_PR: Why don't we use sendRewardsToAccount here? + // TODO_TECHDEBT(@red-0ne): Refactor to reuse the sendRewardsToAccount helper here. shareAmountCoin := cosmostypes.NewCoin(volatile.DenomuPOKT, math.NewInt(int64(shareAmount))) shareAmountCoins := cosmostypes.NewCoins(shareAmountCoin) shareHolderAccAddress, err := sdk.AccAddressFromBech32(shareHolderAddress) diff --git a/x/tokenomics/types/errors.go b/x/tokenomics/types/errors.go index 6e7c23a0d..91b2d761e 100644 --- a/x/tokenomics/types/errors.go +++ b/x/tokenomics/types/errors.go @@ -33,4 +33,5 @@ var ( ErrTokenomicsSupplierOwnerAddressInvalid = sdkerrors.Register(ModuleName, 1124, "the supplier owner address in the claim is not a valid bech32 address") ErrTokenomicsSupplierRevShareFailed = sdkerrors.Register(ModuleName, 1125, "failed to send rev share to supplier shareholders") ErrTokenomicsApplicationReimbursementRequestFailed = sdkerrors.Register(ModuleName, 1126, "failed to send application reimbursement request event") + ErrTokenomicsAmountMismatch = sdkerrors.Register(ModuleName, 1127, "an unexpected amount mismatch occurred") ) diff --git a/x/tokenomics/types/event.pb.go b/x/tokenomics/types/event.pb.go index 945d4ab97..1585b4fcf 100644 --- a/x/tokenomics/types/event.pb.go +++ b/x/tokenomics/types/event.pb.go @@ -335,8 +335,8 @@ func (m *EventApplicationOverserviced) GetEffectiveBurn() *types1.Coin { return nil } -// EventApplicationReimbursementRequest is emitted when an application requests a -// reimbursement +// EventApplicationReimbursementRequest is emitted when an application requests +// a reimbursement type EventApplicationReimbursementRequest struct { ApplicationAddr string `protobuf:"bytes,1,opt,name=application_addr,json=applicationAddr,proto3" json:"application_addr,omitempty"` ServiceId string `protobuf:"bytes,2,opt,name=service_id,json=serviceId,proto3" json:"service_id,omitempty"` From 846bc1d08f13d4b3903edbcb502ec9fcb03bc262 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Wed, 21 Aug 2024 14:55:06 -0400 Subject: [PATCH 03/53] Finished first version of the documentation --- api/poktroll/shared/service.pulsar.go | 6 +- api/poktroll/tokenomics/event.pulsar.go | 176 +++++++--- .../docs/protocol/tokenomics/resources.md | 9 +- .../tokenomics/token_logic_modules.md | 200 ++++++++++-- proto/poktroll/tokenomics/event.proto | 15 +- x/session/keeper/session_hydrator.go | 2 +- x/session/keeper/session_hydrator_test.go | 2 +- x/shared/types/service.pb.go | 6 +- x/tokenomics/keeper/token_logic_modules.go | 301 +++++++++--------- .../keeper/token_logic_modules_test.go | 3 + .../keeper/update_relay_mining_difficulty.go | 35 +- x/tokenomics/types/errors.go | 2 +- x/tokenomics/types/event.pb.go | 173 ++++++---- 13 files changed, 601 insertions(+), 329 deletions(-) diff --git a/api/poktroll/shared/service.pulsar.go b/api/poktroll/shared/service.pulsar.go index 9ca7b82a1..973ed5071 100644 --- a/api/poktroll/shared/service.pulsar.go +++ b/api/poktroll/shared/service.pulsar.go @@ -3420,7 +3420,7 @@ type Service struct { // For example, what if we want to request a session for a certain service but with some additional configs that identify it? Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // Unique identifier for the service - // TODO_MAINNET: Remove this. + // TODO_BETA: Either remove this or rename it to alias. Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` // (Optional) Semantic human readable name for the service // The cost of a single relay for this service in terms of compute units. // Must be used alongside the global 'compute_units_to_tokens_multipler' to calculate the cost of a relay for this service. @@ -3487,7 +3487,7 @@ type ApplicationServiceConfig struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // TODO_MAINNET: Avoid embedding the full Service because we just need the ID. + // TODO_BETA: Avoid embedding the full Service because we just need the ID. Service *Service `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"` // The Service for which the application is configured } @@ -3524,7 +3524,7 @@ type SupplierServiceConfig struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // TODO_MAINNET: Avoid embedding the full Service because we just need the ID. + // TODO_BETA: Avoid embedding the full Service because we just need the ID. Service *Service `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"` // The Service for which the supplier is configured Endpoints []*SupplierEndpoint `protobuf:"bytes,2,rep,name=endpoints,proto3" json:"endpoints,omitempty"` // List of endpoints for the service RevShare []*ServiceRevenueShare `protobuf:"bytes,3,rep,name=rev_share,json=revShare,proto3" json:"rev_share,omitempty"` // List of revenue share configurations for the service diff --git a/api/poktroll/tokenomics/event.pulsar.go b/api/poktroll/tokenomics/event.pulsar.go index c0303e634..52ef98cfa 100644 --- a/api/poktroll/tokenomics/event.pulsar.go +++ b/api/poktroll/tokenomics/event.pulsar.go @@ -1820,6 +1820,7 @@ func (x *fastReflection_EventRelayMiningDifficultyUpdated) ProtoMethods() *proto var ( md_EventApplicationOverserviced protoreflect.MessageDescriptor fd_EventApplicationOverserviced_application_addr protoreflect.FieldDescriptor + fd_EventApplicationOverserviced_supplier_addr protoreflect.FieldDescriptor fd_EventApplicationOverserviced_expected_burn protoreflect.FieldDescriptor fd_EventApplicationOverserviced_effective_burn protoreflect.FieldDescriptor ) @@ -1828,6 +1829,7 @@ func init() { file_poktroll_tokenomics_event_proto_init() md_EventApplicationOverserviced = File_poktroll_tokenomics_event_proto.Messages().ByName("EventApplicationOverserviced") fd_EventApplicationOverserviced_application_addr = md_EventApplicationOverserviced.Fields().ByName("application_addr") + fd_EventApplicationOverserviced_supplier_addr = md_EventApplicationOverserviced.Fields().ByName("supplier_addr") fd_EventApplicationOverserviced_expected_burn = md_EventApplicationOverserviced.Fields().ByName("expected_burn") fd_EventApplicationOverserviced_effective_burn = md_EventApplicationOverserviced.Fields().ByName("effective_burn") } @@ -1903,6 +1905,12 @@ func (x *fastReflection_EventApplicationOverserviced) Range(f func(protoreflect. return } } + if x.SupplierAddr != "" { + value := protoreflect.ValueOfString(x.SupplierAddr) + if !f(fd_EventApplicationOverserviced_supplier_addr, value) { + return + } + } if x.ExpectedBurn != nil { value := protoreflect.ValueOfMessage(x.ExpectedBurn.ProtoReflect()) if !f(fd_EventApplicationOverserviced_expected_burn, value) { @@ -1932,6 +1940,8 @@ func (x *fastReflection_EventApplicationOverserviced) Has(fd protoreflect.FieldD switch fd.FullName() { case "poktroll.tokenomics.EventApplicationOverserviced.application_addr": return x.ApplicationAddr != "" + case "poktroll.tokenomics.EventApplicationOverserviced.supplier_addr": + return x.SupplierAddr != "" case "poktroll.tokenomics.EventApplicationOverserviced.expected_burn": return x.ExpectedBurn != nil case "poktroll.tokenomics.EventApplicationOverserviced.effective_burn": @@ -1954,6 +1964,8 @@ func (x *fastReflection_EventApplicationOverserviced) Clear(fd protoreflect.Fiel switch fd.FullName() { case "poktroll.tokenomics.EventApplicationOverserviced.application_addr": x.ApplicationAddr = "" + case "poktroll.tokenomics.EventApplicationOverserviced.supplier_addr": + x.SupplierAddr = "" case "poktroll.tokenomics.EventApplicationOverserviced.expected_burn": x.ExpectedBurn = nil case "poktroll.tokenomics.EventApplicationOverserviced.effective_burn": @@ -1977,6 +1989,9 @@ func (x *fastReflection_EventApplicationOverserviced) Get(descriptor protoreflec case "poktroll.tokenomics.EventApplicationOverserviced.application_addr": value := x.ApplicationAddr return protoreflect.ValueOfString(value) + case "poktroll.tokenomics.EventApplicationOverserviced.supplier_addr": + value := x.SupplierAddr + return protoreflect.ValueOfString(value) case "poktroll.tokenomics.EventApplicationOverserviced.expected_burn": value := x.ExpectedBurn return protoreflect.ValueOfMessage(value.ProtoReflect()) @@ -2005,6 +2020,8 @@ func (x *fastReflection_EventApplicationOverserviced) Set(fd protoreflect.FieldD switch fd.FullName() { case "poktroll.tokenomics.EventApplicationOverserviced.application_addr": x.ApplicationAddr = value.Interface().(string) + case "poktroll.tokenomics.EventApplicationOverserviced.supplier_addr": + x.SupplierAddr = value.Interface().(string) case "poktroll.tokenomics.EventApplicationOverserviced.expected_burn": x.ExpectedBurn = value.Message().Interface().(*v1beta1.Coin) case "poktroll.tokenomics.EventApplicationOverserviced.effective_burn": @@ -2041,6 +2058,8 @@ func (x *fastReflection_EventApplicationOverserviced) Mutable(fd protoreflect.Fi return protoreflect.ValueOfMessage(x.EffectiveBurn.ProtoReflect()) case "poktroll.tokenomics.EventApplicationOverserviced.application_addr": panic(fmt.Errorf("field application_addr of message poktroll.tokenomics.EventApplicationOverserviced is not mutable")) + case "poktroll.tokenomics.EventApplicationOverserviced.supplier_addr": + panic(fmt.Errorf("field supplier_addr of message poktroll.tokenomics.EventApplicationOverserviced is not mutable")) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.tokenomics.EventApplicationOverserviced")) @@ -2056,6 +2075,8 @@ func (x *fastReflection_EventApplicationOverserviced) NewField(fd protoreflect.F switch fd.FullName() { case "poktroll.tokenomics.EventApplicationOverserviced.application_addr": return protoreflect.ValueOfString("") + case "poktroll.tokenomics.EventApplicationOverserviced.supplier_addr": + return protoreflect.ValueOfString("") case "poktroll.tokenomics.EventApplicationOverserviced.expected_burn": m := new(v1beta1.Coin) return protoreflect.ValueOfMessage(m.ProtoReflect()) @@ -2135,6 +2156,10 @@ func (x *fastReflection_EventApplicationOverserviced) ProtoMethods() *protoiface if l > 0 { n += 1 + l + runtime.Sov(uint64(l)) } + l = len(x.SupplierAddr) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } if x.ExpectedBurn != nil { l = options.Size(x.ExpectedBurn) n += 1 + l + runtime.Sov(uint64(l)) @@ -2184,7 +2209,7 @@ func (x *fastReflection_EventApplicationOverserviced) ProtoMethods() *protoiface copy(dAtA[i:], encoded) i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) i-- - dAtA[i] = 0x1a + dAtA[i] = 0x22 } if x.ExpectedBurn != nil { encoded, err := options.Marshal(x.ExpectedBurn) @@ -2198,6 +2223,13 @@ func (x *fastReflection_EventApplicationOverserviced) ProtoMethods() *protoiface copy(dAtA[i:], encoded) i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) i-- + dAtA[i] = 0x1a + } + if len(x.SupplierAddr) > 0 { + i -= len(x.SupplierAddr) + copy(dAtA[i:], x.SupplierAddr) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.SupplierAddr))) + i-- dAtA[i] = 0x12 } if len(x.ApplicationAddr) > 0 { @@ -2289,6 +2321,38 @@ func (x *fastReflection_EventApplicationOverserviced) ProtoMethods() *protoiface x.ApplicationAddr = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field SupplierAddr", wireType) + } + var stringLen uint64 + 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++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.SupplierAddr = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: if wireType != 2 { return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field ExpectedBurn", wireType) } @@ -2324,7 +2388,7 @@ func (x *fastReflection_EventApplicationOverserviced) ProtoMethods() *protoiface return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err } iNdEx = postIndex - case 3: + case 4: if wireType != 2 { return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field EffectiveBurn", wireType) } @@ -3277,16 +3341,24 @@ func (x *EventRelayMiningDifficultyUpdated) GetNewNumRelaysEma() uint64 { return 0 } -// EventApplicationOverserviced is emitted when an application has less stake -// than the expected burn. +// EventApplicationOverserviced is emitted when an application has less stake than +// what a supplier is claiming (i.e. burn is not high enough). type EventApplicationOverserviced struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - ApplicationAddr string `protobuf:"bytes,1,opt,name=application_addr,json=applicationAddr,proto3" json:"application_addr,omitempty"` - ExpectedBurn *v1beta1.Coin `protobuf:"bytes,2,opt,name=expected_burn,json=expectedBurn,proto3" json:"expected_burn,omitempty"` - EffectiveBurn *v1beta1.Coin `protobuf:"bytes,3,opt,name=effective_burn,json=effectiveBurn,proto3" json:"effective_burn,omitempty"` + ApplicationAddr string `protobuf:"bytes,1,opt,name=application_addr,json=applicationAddr,proto3" json:"application_addr,omitempty"` + SupplierAddr string `protobuf:"bytes,2,opt,name=supplier_addr,json=supplierAddr,proto3" json:"supplier_addr,omitempty"` + // Expected burn is the amount the supplier is claiming for work done + // to service the application during the session. + // This is usually the amount in the Claim object. + ExpectedBurn *v1beta1.Coin `protobuf:"bytes,3,opt,name=expected_burn,json=expectedBurn,proto3" json:"expected_burn,omitempty"` + // Effective burn is the amount that is actually being paid to the supplier + // for the work done. It is less than the expected burn (claim amount) and + // most likely equal to the application's stake divided by the number of suppliers + // in a session. + EffectiveBurn *v1beta1.Coin `protobuf:"bytes,4,opt,name=effective_burn,json=effectiveBurn,proto3" json:"effective_burn,omitempty"` } func (x *EventApplicationOverserviced) Reset() { @@ -3316,6 +3388,13 @@ func (x *EventApplicationOverserviced) GetApplicationAddr() string { return "" } +func (x *EventApplicationOverserviced) GetSupplierAddr() string { + if x != nil { + return x.SupplierAddr + } + return "" +} + func (x *EventApplicationOverserviced) GetExpectedBurn() *v1beta1.Coin { if x != nil { return x.ExpectedBurn @@ -3460,50 +3539,53 @@ var file_poktroll_tokenomics_event_proto_rawDesc = []byte{ 0x65, 0x6c, 0x61, 0x79, 0x73, 0x45, 0x6d, 0x61, 0x12, 0x2b, 0x0a, 0x12, 0x6e, 0x65, 0x77, 0x5f, 0x6e, 0x75, 0x6d, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x73, 0x5f, 0x65, 0x6d, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x6e, 0x65, 0x77, 0x4e, 0x75, 0x6d, 0x52, 0x65, 0x6c, 0x61, - 0x79, 0x73, 0x45, 0x6d, 0x61, 0x22, 0xcb, 0x01, 0x0a, 0x1c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x41, + 0x79, 0x73, 0x45, 0x6d, 0x61, 0x22, 0xf0, 0x01, 0x0a, 0x1c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x64, 0x12, 0x29, 0x0a, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x64, 0x64, - 0x72, 0x12, 0x3e, 0x0a, 0x0d, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x62, 0x75, - 0x72, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, - 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, - 0x6f, 0x69, 0x6e, 0x52, 0x0c, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x42, 0x75, 0x72, - 0x6e, 0x12, 0x40, 0x0a, 0x0e, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x62, - 0x75, 0x72, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x73, 0x6d, - 0x6f, 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, - 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x0d, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x42, - 0x75, 0x72, 0x6e, 0x22, 0xc2, 0x01, 0x0a, 0x24, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x41, 0x70, 0x70, - 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x69, 0x6d, 0x62, 0x75, 0x72, 0x73, - 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x29, 0x0a, 0x10, - 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x31, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, - 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x69, 0x6e, - 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x2a, 0x60, 0x0a, 0x15, 0x43, 0x6c, 0x61, 0x69, - 0x6d, 0x45, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x61, 0x73, 0x6f, - 0x6e, 0x12, 0x21, 0x0a, 0x1d, 0x45, 0x58, 0x50, 0x49, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, - 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, - 0x45, 0x44, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x52, 0x4f, 0x4f, 0x46, 0x5f, 0x4d, 0x49, - 0x53, 0x53, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x52, 0x4f, 0x4f, 0x46, - 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x02, 0x42, 0xb8, 0x01, 0x0a, 0x17, 0x63, - 0x6f, 0x6d, 0x2e, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x74, 0x6f, 0x6b, 0x65, - 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0x42, 0x0a, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, - 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x24, 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, - 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0xa2, 0x02, 0x03, 0x50, 0x54, 0x58, - 0xaa, 0x02, 0x13, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x54, 0x6f, 0x6b, 0x65, - 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0xca, 0x02, 0x13, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, - 0x6c, 0x5c, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0xe2, 0x02, 0x1f, 0x50, - 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, - 0x63, 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, - 0x14, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x3a, 0x3a, 0x54, 0x6f, 0x6b, 0x65, 0x6e, - 0x6f, 0x6d, 0x69, 0x63, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x5f, 0x61, 0x64, + 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x75, 0x70, 0x70, 0x6c, 0x69, + 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x12, 0x3e, 0x0a, 0x0d, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, + 0x65, 0x64, 0x5f, 0x62, 0x75, 0x72, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, + 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, + 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x0c, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, + 0x65, 0x64, 0x42, 0x75, 0x72, 0x6e, 0x12, 0x40, 0x0a, 0x0e, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, + 0x69, 0x76, 0x65, 0x5f, 0x62, 0x75, 0x72, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, + 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x62, + 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x0d, 0x65, 0x66, 0x66, 0x65, 0x63, + 0x74, 0x69, 0x76, 0x65, 0x42, 0x75, 0x72, 0x6e, 0x22, 0xc2, 0x01, 0x0a, 0x24, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x69, + 0x6d, 0x62, 0x75, 0x72, 0x73, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x29, 0x0a, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x61, 0x70, 0x70, + 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x12, 0x1d, 0x0a, 0x0a, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, + 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x31, 0x0a, 0x06, 0x61, 0x6d, + 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x73, + 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, + 0x2e, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x2a, 0x60, 0x0a, + 0x15, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x45, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x1d, 0x45, 0x58, 0x50, 0x49, 0x52, 0x41, + 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, + 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x52, 0x4f, + 0x4f, 0x46, 0x5f, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, + 0x50, 0x52, 0x4f, 0x4f, 0x46, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x02, 0x42, + 0xb8, 0x01, 0x0a, 0x17, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, + 0x2e, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0x42, 0x0a, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x24, 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, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0xa2, + 0x02, 0x03, 0x50, 0x54, 0x58, 0xaa, 0x02, 0x13, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, + 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0xca, 0x02, 0x13, 0x50, 0x6f, + 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, + 0x73, 0xe2, 0x02, 0x1f, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0xea, 0x02, 0x14, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x3a, 0x3a, + 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, } var ( diff --git a/docusaurus/docs/protocol/tokenomics/resources.md b/docusaurus/docs/protocol/tokenomics/resources.md index 9b31e6ec1..b652b0349 100644 --- a/docusaurus/docs/protocol/tokenomics/resources.md +++ b/docusaurus/docs/protocol/tokenomics/resources.md @@ -5,10 +5,13 @@ sidebar_position: 1 # Tokenomics Resources -The following resources serve as the foundation for the Shannon Upgrade Tokenomics. +:::warning + +This is an active an ever evolving work. We are working on a single source of truth. -It is an active an ever evolving work, but the following resources are the best -starting references: +::: + +The following resources serve as the foundation for the Shannon Upgrade Tokenomics. - [Token Logic Module](https://docs.pokt.network/pokt-protocol/the-shannon-upgrade/proposed-tokenomics/token-logic-modules) design approach. - [Shannon Tokenomics Static](https://github.com/pokt-network/shannon-tokenomics-static-tests) modeling & evaluation diff --git a/docusaurus/docs/protocol/tokenomics/token_logic_modules.md b/docusaurus/docs/protocol/tokenomics/token_logic_modules.md index 3fd36ddd0..fd70d0fe9 100644 --- a/docusaurus/docs/protocol/tokenomics/token_logic_modules.md +++ b/docusaurus/docs/protocol/tokenomics/token_logic_modules.md @@ -6,8 +6,8 @@ sidebar_position: 2 # Token Logic Modules - [Introduction](#introduction) -- [Background: Relay Mining Payable Relay Accumulation](#background-relay-mining-payable-relay-accumulation) -- [TLM Pre-processor: Claim Settlement Limit](#tlm-pre-processor-claim-settlement-limit) +- [Background: Max Claimable Amount](#background-max-claimable-amount) +- [TLM (pre) Processing](#tlm-pre-processing) - [TLM: Mint=Burn (MEB)](#tlm-mintburn-meb) - [TLM: Global Mint (GM)](#tlm-global-mint-gm) - [TLM: Global Mint Reimbursement Request (GMRR)](#tlm-global-mint-reimbursement-request-gmrr) @@ -22,50 +22,58 @@ Note that this is an active WIP and the [resources here](./resources.md) are the Token Logic Modules (TLMs) processing involves: -1. `TLM pre-processing` - A general pre-processor determining the amount of coins to settle per claim -2. `TLM processing` - Individual processing each TLM independent of the other +1. `TLM pre-processing` - A general pre-processor determining the amount of tokens to settle per claim. +2. `TLM processing` - Iteration through all of the TLMs one by one. +3. `TLM processor` - Individual processing each TLM independent of one another. -## Background: Relay Mining Payable Relay Accumulation +## Background: Max Claimable Amount + +_tl;dr Max Claimable Amount ∝ (Application Stake / Number of Suppliers per Session)_ Per **Algorithm 1** of the [Relay Mining paper](https://arxiv.org/pdf/2305.10672), the maximum amount a supplier can claim from an application in a single session is -proportional to the Application's stake divided by the number of nodes in the session -as see in the following image: +proportional to the Application's stake divided by the number of suppliers in the session. + +This is referred to as "Relay Mining Payable Relay Accumulation" in the paper and +can be seen in the following image: ![Algorithm 1](https://github.com/user-attachments/assets/d1a61535-aa31-447d-88ea-c8d14dcb20c6) -## TLM Pre-processor: Claim Settlement Limit +## TLM (pre) Processing + +_tl;dr Determine if the claim settlement amount is greater than the maximum claimable amount and then run each individual TLM._ **Prior to** processing each individual TLM, we need to understand if the amount claimed -by the supplier adheres to the maximum allowed per the limits set by Relay Mining. +by the supplier adheres to the optimistic maxima set per the limits of Relay Mining. Suppliers always have the option to over-service an application (**i.e. do free work**), -in exchange for providing a good service to the network, but their on-chain rewards +in exchange for providing a good service to the network. This may lead to offchain +reputation benefits (e.g. Gateways favoring them), but their on-chain rewards are still limited as a function of the application's stake before the session started -and the number of nodes in the session. +and the number of suppliers in the session. :::note TODO_POST_MAINNET: After the Shannon upgrade, the team at Grove has a lot of ideas -related to [supplier gossipin](https://www.notion.so/buildwithgrove/Off-chain-Application-Stake-Tracking-6a8bebb107db4f7f9dc62cbe7ba555f7?pvs=4) but that -is out of scope for the initial implementation. +related to on-chain reputation, [supplier gossiping](https://www.notion.so/buildwithgrove/Off-chain-Application-Stake-Tracking-6a8bebb107db4f7f9dc62cbe7ba555f7?pvs=4), and +much more, but that is out of scope for the initial implementation. ::: ```mermaid --- -title: "Token Logic Modules Processor" +title: "Token Logic Modules (pre) Processing" --- flowchart TB CSA(["Claim Settlement Amount (CSA)"]) - MCS(["MaxClaimPerSupplier (MCS)
= (AppStake / NumNodesPerSession)"]) - CC{"Is CSA > MCS?"} - Update(Set SA = MCS
Broadcast Event) + MCA(["MaxClaimPerSupplier (MCA)
= (AppStake / NumSuppliersPerSession)"]) + CC{"Is CSA > MCA?"} + Update(Set SA = MCA
Broadcast Event) SOAE{{Application Overserviced
Event}} TLMP[["TLM Processor (SA)"]] CSA -- CSA --> CC - MCS -- MCS --> CC + MCA -- MCA --> CC Update -..-> SOAE CC -- Yes --> Update @@ -74,7 +82,7 @@ flowchart TB TLMP --SA--> TLMBEM[[TLM: Burn Equals Mint]] TLMP --SA--> TLMGI[[TLM: Global Inflation]] - TLMP --SA--> TLMGIRR[[TLM: Global Inflation Reimbursment Request]] + TLMP --SA--> TLMGIRR[[TLM: Global Inflation Reimbursement Request]] classDef tlm fill:#54ebd5,stroke:#333,stroke-width:2px; classDef question fill:#e3db6d,stroke:#333,stroke-width:2px; @@ -87,15 +95,14 @@ flowchart TB ## TLM: Mint=Burn (MEB) +_tl;dr The transfer of tokens from the application to the supplier based on the amount of work received and provided respectively.._ + The `Mint=Burn` TLM is, _theoretically_, the only TLM necessary when the network reaches equilibrium in the far future. -Put simply, it is a transfer of tokens from the application to the supplier based on the -amount of work done by the supplier. - -The same amount of tokens that is minted in the supplier module is burned from the application module. -The stake of the application paying for work is reduced and the rewards are distributed to the supplier -and its revenue shareholder addresses. +The same amount of tokens that is minted in the **supplier module** is burned from +the **application module**. The stake of the application paying for work is reduced +and the rewards are distributed to the supplier and its revenue shareholder addresses. ```mermaid --- @@ -127,12 +134,12 @@ flowchart TD AA[Application Address] AM -.- AK - AK -. Reduce Stake by CSA .-> AA + AK -. Reduce Stake by SA .-> AA + AA -.- TODO{See TODO below} end SM --> SD - classDef module fill:#f9f,stroke:#333,stroke-width:2px; classDef address fill:#bbf,stroke:#333,stroke-width:2px; classDef question fill:#e3db6d,stroke:#333,stroke-width:2px; @@ -140,18 +147,141 @@ flowchart TD class SM,AM module; class RSA,OA,OPA,AA address; + class TODO question; ``` +:::note + +TODO_MAINNET: If the application stake has dropped to (near?) zero, should +we unstake it? Should we use it's balance? Should their be a payee of last resort? +Make sure to document whatever decision we come to. + +::: + ## TLM: Global Mint (GM) -TLMGlobalMint is the token logic module that mints new tokens based on the -on global governance parameters in order to reward the participants providing -services while keeping inflation in check. +_tl;dr Distributed newly minted coins on a per claim basis to all involved stakeholders._ + +The `Global Mint` TLM is, _theoretically_, going to reach `zero`the only when the network +reaches equilibrium in the far future. + +On a per claim basis, the network mints new tokens based on the the amount of work +claimed. The newly minted tokens are distributed to the supplier, DAO, service owner +and application based on the values of various governance params. + +```mermaid +--- +title: "Token Logic Module: Global Mint" +--- +flowchart TD + SC(["Settlement Coin (SC)"]) + PCI(["Per Claim Global Inflation
(Governance Parameter)"]) + IMC(["Inflation Mint Coin (IMC)"]) + + DA(["DAO Mint Allocation"]) + PA(["Proposer Mint Allocation"]) + SA(["Supplier Mint Allocation"]) + SOA(["Source Owner Mint Allocation"]) + AA(["Application Mint Allocation"]) + + + SC --> IMC + PCI --> IMC + IMC --> TO + + subgraph TO[Tokenomics Operations] + TM[[Tokenomics Module]] + TK[(Tokenomics Keeper)] + TM -..- TK + end + + + DA --> ID + PA --> ID + TO -- New Mint Coin (NMC)--> ID + SA --> ID + AA --> ID + + subgraph ID[Inflation Distribution] + NMC["New Mint Coin (NMC)"] + APPA["Application Address"] + SPPA["Supplier Address"] + DAOA["DAO Address"] + SOA["Service Owner Address"] + PRA["Proposer Address"] + + NMC -->|% Mint Allocation| APPA + NMC -->|% Mint Allocation| SPPA + NMC -->|% Mint Allocation| DAOA + NMC -->|% Mint Allocation| SOA + NMC -->|% Mint Allocation| PRA + end + + classDef module fill:#f9f,stroke:#333,stroke-width:2px; + classDef address fill:#bbf,stroke:#333,stroke-width:2px; + classDef question fill:#e3db6d,stroke:#333,stroke-width:2px; + classDef govparam fill:#d04a36,stroke:#333,stroke-width:2px; + classDef event fill:#e8b761,stroke:#333,stroke-width:2px; + + class TM module; + class PCI,DA,PA,SA,AA govparam; + class APPA,SPPA,DAOA,SOA,PRA address; +``` ## TLM: Global Mint Reimbursement Request (GMRR) -TLMGlobalMintReimbursementRequest is the token logic module that complements -TLMGlobalMint to enable permissionless demand. In order to prevent self-dealing -attacks, applications will be overcharged by the amount equal to global inflation, -those funds will be sent to the DAO/PNF, and event will be emitted to be used -for reimbursements. +_tl;dr Prevent self-dealing by over-charging applications, sending the excess to the DAO/PNF, and emitting an event as a reimbursement request._ + +This TLM **MUST** be processed alongside the Global Mint TLM. + +This TLM can, **theoretically**, be removed if self-dealing attacks are not a concern, +or if the global mint per claim governance parameter is set to zero. + +The goal of the TLM is to overcharge applications equal to the global inflation amount +and send those funds to the DAO/PNF. This forces potentially self-dealing gateways to +"show face" in front of the DAO/PNF and request reimbursement. + +The event emitted creates an easy, onchain mechanism, to track reimbursement handled offchain. + +A side effect of this TLM is creating additional buy pressure of the token as Applications +and Gateways will be responsible for frequently "topping up" their balances and app stakes. + +```mermaid +--- +title: "Token Logic Module: Global Mint Reimbursement Request" +--- +flowchart TD + SC(["Settlement Coin (SC)"]) + PCI(["Per Claim Global Inflation
(Governance Parameter)"]) + IMC(["Inflation Mint Coin (IMC)"]) + ARRE{{Application Reimbursement
Request Event}} + + SC --> IMC + PCI --> IMC + IMC --IMC--> AO + + + subgraph AO[Application Operations] + AM[[Application Module]] + AK[(Application Keeper)] + AA[Application Address] + DA[DAO Address] + + AM -.- AK + AK -. Reduce Stake by IMC .-> AA + AM -..-> |Increase Balance by IMC| DA + end + + AO -. Emit Event.-> ARRE + + classDef module fill:#f9f,stroke:#333,stroke-width:2px; + classDef address fill:#bbf,stroke:#333,stroke-width:2px; + classDef question fill:#e3db6d,stroke:#333,stroke-width:2px; + classDef govparam fill:#d04a36,stroke:#333,stroke-width:2px; + classDef event fill:#e8b761,stroke:#333,stroke-width:2px; + + class AM module; + class ARRE event; + class PCI govparam; + class AA,DA address; +``` diff --git a/proto/poktroll/tokenomics/event.proto b/proto/poktroll/tokenomics/event.proto index 00a089f8f..e7f698aea 100644 --- a/proto/poktroll/tokenomics/event.proto +++ b/proto/poktroll/tokenomics/event.proto @@ -49,18 +49,17 @@ message EventRelayMiningDifficultyUpdated { message EventApplicationOverserviced { string application_addr = 1; string supplier_addr = 2; + // Expected burn is the amount the supplier is claiming for work done + // to service the application during the session. + // This is usually the amount in the Claim object. cosmos.base.v1beta1.Coin expected_burn = 3; + // Effective burn is the amount that is actually being paid to the supplier + // for the work done. It is less than the expected burn (claim amount) and + // most likely equal to the application's stake divided by the number of suppliers + // in a session. cosmos.base.v1beta1.Coin effective_burn = 4; } -// EventSupplierExceededClaimableAmount is emitted when a supplier application has less stake -// than the expected burn. -message EventSupplierExceededClaimableAmount { - string supplier_addr = 1; - cosmos.base.v1beta1.Coin expected_burn = 2; - cosmos.base.v1beta1.Coin effective_burn = 3; -} - // EventApplicationReimbursementRequest is emitted when an application requests // a reimbursement message EventApplicationReimbursementRequest { diff --git a/x/session/keeper/session_hydrator.go b/x/session/keeper/session_hydrator.go index 60c292836..bf7420e6d 100644 --- a/x/session/keeper/session_hydrator.go +++ b/x/session/keeper/session_hydrator.go @@ -20,8 +20,8 @@ import ( var SHA3HashLen = crypto.SHA3_256.Size() -// TODO_BLOCKER(@bryanchriswhite, #21): Make these configurable governance param const ( + // TODO_BETA(@bryanchriswhite): Make this a governance parameter NumSupplierPerSession = 15 SessionIDComponentDelimiter = "." ) diff --git a/x/session/keeper/session_hydrator_test.go b/x/session/keeper/session_hydrator_test.go index d70c148b7..f0b3cf0ad 100644 --- a/x/session/keeper/session_hydrator_test.go +++ b/x/session/keeper/session_hydrator_test.go @@ -289,7 +289,7 @@ func TestSession_HydrateSession_Application(t *testing.T) { // TODO_TEST: Expand these tests to account for supplier joining/leaving the network at different heights as well changing the services they support func TestSession_HydrateSession_Suppliers(t *testing.T) { - // TODO_TEST: Extend these tests once `NumBlocksPerSession` is configurable. + // TODO_BETA(@bryanchriswhite): Extend these tests once `NumBlocksPerSession` is configurable. // Currently assumes NumSupplierPerSession=15 tests := []struct { // Description diff --git a/x/shared/types/service.pb.go b/x/shared/types/service.pb.go index 3bbb2d31d..22ed750a8 100644 --- a/x/shared/types/service.pb.go +++ b/x/shared/types/service.pb.go @@ -93,7 +93,7 @@ func (ConfigOptions) EnumDescriptor() ([]byte, []int) { type Service struct { // For example, what if we want to request a session for a certain service but with some additional configs that identify it? Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - // TODO_MAINNET: Remove this. + // TODO_BETA: Either remove this or rename it to alias. Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` // The cost of a single relay for this service in terms of compute units. // Must be used alongside the global 'compute_units_to_tokens_multipler' to calculate the cost of a relay for this service. @@ -169,7 +169,7 @@ func (m *Service) GetOwnerAddress() string { // ApplicationServiceConfig holds the service configuration the application stakes for type ApplicationServiceConfig struct { - // TODO_MAINNET: Avoid embedding the full Service because we just need the ID. + // TODO_BETA: Avoid embedding the full Service because we just need the ID. Service *Service `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"` } @@ -215,7 +215,7 @@ func (m *ApplicationServiceConfig) GetService() *Service { // SupplierServiceConfig holds the service configuration the supplier stakes for type SupplierServiceConfig struct { - // TODO_MAINNET: Avoid embedding the full Service because we just need the ID. + // TODO_BETA: Avoid embedding the full Service because we just need the ID. Service *Service `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"` Endpoints []*SupplierEndpoint `protobuf:"bytes,2,rep,name=endpoints,proto3" json:"endpoints,omitempty"` RevShare []*ServiceRevenueShare `protobuf:"bytes,3,rep,name=rev_share,json=revShare,proto3" json:"rev_share,omitempty"` diff --git a/x/tokenomics/keeper/token_logic_modules.go b/x/tokenomics/keeper/token_logic_modules.go index 99cff2611..a05b1aee2 100644 --- a/x/tokenomics/keeper/token_logic_modules.go +++ b/x/tokenomics/keeper/token_logic_modules.go @@ -1,14 +1,11 @@ package keeper -// References: -// - https://docs.pokt.network/pokt-protocol/the-shannon-upgrade/proposed-tokenomics/token-logic-modules -// - https://github.com/pokt-network/shannon-tokenomics-static-tests - import ( "context" "fmt" "math/big" + "cosmossdk.io/log" "cosmossdk.io/math" cosmostypes "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -19,6 +16,7 @@ import ( "github.com/pokt-network/poktroll/telemetry" apptypes "github.com/pokt-network/poktroll/x/application/types" prooftypes "github.com/pokt-network/poktroll/x/proof/types" + sessionkeeper "github.com/pokt-network/poktroll/x/session/keeper" sessiontypes "github.com/pokt-network/poktroll/x/session/types" sharedtypes "github.com/pokt-network/poktroll/x/shared/types" suppliertypes "github.com/pokt-network/poktroll/x/supplier/types" @@ -28,11 +26,12 @@ import ( const ( // Governance parameters for the TLMGlobalMint module - // TODO_UPNEXT(@olshansk): Remove this. An ephemeral placeholder before + // TODO_BETA_TEST(@olshansk): Remove this. It is an ephemeral placeholder before // real values are introduced. When this is changed to a governance param, // make sure to also add the necessary unit tests. - MintGlobalInflation = 0.0000000 - // TODO_UPNEXT(@olshansk): Make all of the governance params + MintPerClaimGlobalInflation = 0.0000000 + + // TODO_BETA: Make all of the governance params MintAllocationDAO = 0.1 MintAllocationProposer = 0.05 MintAllocationSupplier = 0.7 @@ -44,8 +43,8 @@ type TokenLogicModule int const ( // TLMRelayBurnEqualsMint is the token logic module that burns the application's - // stake based on the amount of work done by the supplier. The same amount of - // tokens is minted and sent to the supplier. + // stake based on the amount of work done by the supplier. + // The same amount of tokens is minted and sent to the supplier. // When the network achieves equilibrium, this is theoretically the only TLM that will be necessary. TLMRelayBurnEqualsMint TokenLogicModule = iota @@ -57,8 +56,8 @@ const ( // TLMGlobalMintReimbursementRequest is the token logic module that complements // TLMGlobalMint to enable permissionless demand. In order to prevent self-dealing // attacks, applications will be overcharged by the amount equal to global inflation, - // those funds will be sent to the DAO/PNF, and event will be emitted to be used - // for reimbursements. + // those funds will be sent to the DAO/PNF, and an event will be emitted to track + // and send reimbursements; managed offchain by PNF. // TODO_POST_MAINNET: Introduce proper tokenomics based on the research done by @rawthil and @shane. TLMGlobalMintReimbursementRequest ) @@ -79,10 +78,10 @@ func (tlm TokenLogicModule) EnumIndex() int { // TokenLogicModuleProcessor is the method signature that all token logic modules // are expected to implement. -// IMPORTANT SIDE EFFECTS: Please note that TLMS may update the application and supplier -// objects, which is why they are passed in as pointers. However, this IS NOT persisted. -// The persistence to the keeper is currently done by ProcessTokenLogicModules only. -// This may be an interim state of the implementation and may change in the future. +// IMPORTANT_SIDE_EFFECTS: Please note that TLMs may update the application and supplier +// objects, which is why they are passed in as pointers. NOTE THAT THIS IS NOT PERSISTED. +// The persistence to the keeper is currently done by the TLM processor: ProcessTokenLogicModules. +// This design and separation of concerns may change in the future. type TokenLogicModuleProcessor func( Keeper, context.Context, @@ -94,10 +93,11 @@ type TokenLogicModuleProcessor func( *tokenomictypes.RelayMiningDifficulty, ) error -// tokenLogicModuleProcessorMap is a map of token logic modules to their respective processors. +// tokenLogicModuleProcessorMap is a map of TLMs to their respective independent processors. var tokenLogicModuleProcessorMap = map[TokenLogicModule]TokenLogicModuleProcessor{ TLMRelayBurnEqualsMint: Keeper.TokenLogicModuleRelayBurnEqualsMint, TLMGlobalMint: Keeper.TokenLogicModuleGlobalMint, + // TODO_BETA_UPNEXT(@Olshansky): Uncomment this and add tests. // TLMGlobalMintReimbursementRequest: Keeper.TokenLogicModuleGlobalMintReimbursementRequest, } @@ -108,16 +108,18 @@ func init() { } } -// ProcessTokenLogicModules is the main TLM processor. It is responsible for calling -// all of the token logic module necessary to limit, burn, mint or transfer tokens -// as a result of the amount of work (i.e. compute units) done and governance parameters. +// ProcessTokenLogicModules is the main TLM processor. It is responsible for running +// all of the independent TLMs necessary to limit, burn, mint or transfer tokens +// as a result of the amount of work (i.e. relays, compute units) done in proportion +// to the global governance parameters. +// IMPORTANT: It is assumed the proof for the claim has been validated BEFORE calling this function. func (k Keeper) ProcessTokenLogicModules( ctx context.Context, - claim *prooftypes.Claim, // IMPORTANT: It is assumed the proof for the claim has been validated BEFORE calling this function + claim *prooftypes.Claim, ) (err error) { logger := k.Logger().With("method", "ProcessTokenLogicModules") - // Declaring variables that will be emitted by telemetry + // Telemetry variable declaration to be emitted a the end of the function claimSettlementCoin := cosmostypes.NewCoin("upokt", math.NewInt(0)) isSuccessful := false @@ -133,7 +135,7 @@ func (k Keeper) ProcessTokenLogicModules( func() bool { return isSuccessful }, ) - // Ensure the claim is not nil + // Sanity check the claim is not nil. Validation of the claim is expected by the caller. if claim == nil { logger.Error("received a nil claim") return tokenomicstypes.ErrTokenomicsClaimNil @@ -150,22 +152,8 @@ func (k Keeper) ProcessTokenLogicModules( return tokenomicstypes.ErrTokenomicsSessionHeaderInvalid } - // Retrieve the supplier operator address that will be getting rewarded; providing services - supplierOperatorAddr, err := cosmostypes.AccAddressFromBech32(claim.GetSupplierOperatorAddress()) - if err != nil || supplierOperatorAddr == nil { - return tokenomicstypes.ErrTokenomicsSupplierOperatorAddressInvalid - } - - // Retrieve the application address that is being charged; getting services - applicationAddress, err := cosmostypes.AccAddressFromBech32(sessionHeader.GetApplicationAddress()) - if err != nil || applicationAddress == nil { - return tokenomicstypes.ErrTokenomicsApplicationAddressInvalid - } - - // Retrieve the root of the claim to determine the amount of work done + // Retrieve and validate the root of the claim to determine the amount of work done root := (smt.MerkleSumRoot)(claim.GetRootHash()) - - // Ensure the root hash is valid if !root.HasDigestSize(protocol.TrieHasherSize) { return tokenomicstypes.ErrTokenomicsRootHashInvalid.Wrapf( "root hash has invalid digest size (%d), expected (%d)", @@ -173,6 +161,29 @@ func (k Keeper) ProcessTokenLogicModules( ) } + // Retrieve the count (i.e. number of relays) to determine the amount of work done + numRelays, err := root.Count() + if err != nil { + return tokenomicstypes.ErrTokenomicsRootHashInvalid.Wrapf("%v", err) + } + + /* + TODO_POST_MAINNET: Because of how things have evolved, we are now using + root.Count (numRelays) instead of root.Sum (numComputeUnits) to determine + the amount of work done. This is because the compute_units_per_relay is + a service specific (not request specific) parameter that will be maintained + by the service owner to capture the average amount of resources (i.e. + compute, storage, bandwidth, electricity, etc...) per request. Modifying + this on a per request basis has been deemed too complex and not a mainnet + blocker. + */ + + // Retrieve the application address that is being charged; getting services and paying tokens + applicationAddress, err := cosmostypes.AccAddressFromBech32(sessionHeader.GetApplicationAddress()) + if err != nil || applicationAddress == nil { + return tokenomicstypes.ErrTokenomicsApplicationAddressInvalid + } + // Retrieve the on-chain staked application record application, isAppFound := k.applicationKeeper.GetApplication(ctx, applicationAddress.String()) if !isAppFound { @@ -180,6 +191,12 @@ func (k Keeper) ProcessTokenLogicModules( return tokenomicstypes.ErrTokenomicsApplicationNotFound } + // Retrieve the supplier operator address that will be getting rewarded; providing services and earning tokens + supplierOperatorAddr, err := cosmostypes.AccAddressFromBech32(claim.GetSupplierOperatorAddress()) + if err != nil || supplierOperatorAddr == nil { + return tokenomicstypes.ErrTokenomicsSupplierOperatorAddressInvalid + } + // Retrieve the on-chain staked supplier record supplier, isSupplierFound := k.supplierKeeper.GetSupplier(ctx, supplierOperatorAddr.String()) if !isSupplierFound { @@ -187,48 +204,20 @@ func (k Keeper) ProcessTokenLogicModules( return tokenomicstypes.ErrTokenomicsSupplierNotFound } + // Retrieve the service that the supplier is providing service, isServiceFound := k.serviceKeeper.GetService(ctx, sessionHeader.Service.Id) if !isServiceFound { return tokenomicstypes.ErrTokenomicsServiceNotFound.Wrapf("service with ID %q not found", sessionHeader.Service.Id) } - // Retrieve the count (i.e. number of relays) to determine the amount of work done - numRelays, err := root.Count() - if err != nil { - return tokenomicstypes.ErrTokenomicsRootHashInvalid.Wrapf("%v", err) - } - - // TODO_POST_MAINNET: Because of how things have evolved, we are now using - // root.Count (numRelays) instead of root.Sum (numComputeUnits) to determine - // the amount of work done. This is because the compute_units_per_relay is - /// a service specific (not request specific) parameter that will be maintained - // by the service owner to capture the average amount of resources (i.e. - // compute, storage, bandwidth, electricity, etc...) per request. Modifying - // this on a per request basis has been deemed too complex and not a mainnet - // blocker. - - // Determine the total number of tokens that'll be used for settling the session. - // When the network achieves equilibrium, this will be the mint & burn. + // Determine the total number of tokens being claimed (i.e. requested) + // by the supplier for the amount of work they did to service the application + // in the session. claimSettlementCoin, err = k.numRelaysToCoin(ctx, numRelays, &service) if err != nil { return err } - // Retrieving the relay mining difficulty for the service at hand - relayMiningDifficulty, found := k.GetRelayMiningDifficulty(ctx, service.Id) - if !found { - if err != nil { - return err - } - logger.Warn(fmt.Sprintf("relay mining difficulty for service %q not found. Using default difficulty", service.Id)) - relayMiningDifficulty = tokenomicstypes.RelayMiningDifficulty{ - ServiceId: service.Id, - BlockHeight: sdk.UnwrapSDKContext(ctx).BlockHeight(), - NumRelaysEma: numRelays, - TargetHash: prooftypes.DefaultRelayDifficultyTargetHash, - } - } - // Helpers for logging the same metadata throughout this function calls logger = logger.With( "num_relays", numRelays, @@ -238,37 +227,40 @@ func (k Keeper) ProcessTokenLogicModules( "supplier_operator", supplier.OperatorAddress, "application", application.Address, ) - logger.Info(fmt.Sprintf("About to start processing TLMs for (%d) relays equaling to (%s) upokt claimed", numRelays, claimSettlementCoin)) - maxClaimableAmount := application.GetStake().QuoUint64(uint64(relayMiningDifficulty.NumNodesPerSession)) + // Retrieving the relay mining difficulty for the service at hand + relayMiningDifficulty, found := k.GetRelayMiningDifficulty(ctx, service.Id) + if !found { + relayMiningDifficulty = newDefaultRelayMiningDifficulty(ctx, logger, service.Id, numRelays) + } - // Reduce the settlement amount if the application was over-serviced - var actualSettlementCoin cosmostypes.Coin - if application.GetStake().IsLT(claimSettlementCoin) { - actualSettlementCoin, err = k.handleOverservicedApplication(ctx, &application, claimSettlementCoin) - if err != nil { - return err - } - logger.Warn(fmt.Sprintf("Application with address %s was over-serviced so the actual amount being settled is (%v) instead of the claimed amount (%v) ", application.Address, actualSettlementCoin, claimSettlementCoin)) - } else { - actualSettlementCoin = claimSettlementCoin + // Ensure the claim amount is within the limits set by Relay Mining. + // Update the settlement amount if not and emit any necessary events in doing so. + actualSettlementCoin, err := k.ensureClaimAmountLimits(ctx, logger, &application, &supplier, claimSettlementCoin) + if err != nil { + return err } logger = logger.With("actual_settlement_upokt", actualSettlementCoin) + logger.Info(fmt.Sprintf("About to start processing TLMs for (%d) relays equaling to (%s) upokt claimed", numRelays, actualSettlementCoin)) // Execute all the token logic modules processors for tlm, tlmProcessor := range tokenLogicModuleProcessorMap { - logger.Info(fmt.Sprintf("Starting to execute TLM %q", tlm)) + logger.Info(fmt.Sprintf("Starting TLM processing: %q", tlm)) if err := tlmProcessor(k, ctx, &service, claim.SessionHeader, &application, &supplier, actualSettlementCoin, &relayMiningDifficulty); err != nil { return err } - logger.Info(fmt.Sprintf("Finished executing TLM %q", tlm)) + logger.Info(fmt.Sprintf("Finished TLM processing: %q", tlm)) } - // Update the application's on-chain record + // State mutation: update the application's on-chain record k.applicationKeeper.SetApplication(ctx, application) logger.Info(fmt.Sprintf("updated on-chain application record with address %q", application.Address)) - // Update the suppliers's on-chain record + // TODO_MAINNET: If the application stake has dropped to (near?) zero, should + // we unstake it? Should we use it's balance? Should their be a payee of last resort? + // Make sure to document whatever decision we come to. + + // State mutation: Update the suppliers's on-chain record k.supplierKeeper.SetSupplier(ctx, supplier) logger.Info(fmt.Sprintf("updated on-chain supplier record with address %q", supplier.OperatorAddress)) @@ -289,16 +281,16 @@ func (k Keeper) TokenLogicModuleRelayBurnEqualsMint( ) error { logger := k.Logger().With("method", "TokenLogicModuleRelayBurnEqualsMint") - ownerAddr, err := cosmostypes.AccAddressFromBech32(supplier.OwnerAddress) - if err != nil { - return err - } - // DEV_NOTE: We are doing a mint & burn + transfer, instead of a simple transfer // of funds from the supplier to the application in order to enable second // order economic effects with more optionality. This could include funds // going to pnf, delegators, enabling bonuses/rebates, etc... + ownerAddr, err := cosmostypes.AccAddressFromBech32(supplier.OwnerAddress) + if err != nil { + return err + } + // Mint new uPOKT to the supplier module account. // These funds will be transferred to the supplier below. if err = k.bankKeeper.MintCoins( @@ -312,8 +304,8 @@ func (k Keeper) TokenLogicModuleRelayBurnEqualsMint( } logger.Info(fmt.Sprintf("minted (%v) coins in the supplier module", settlementCoin)) - amount := settlementCoin.Amount.Uint64() - if err = k.distributeSupplierRewardsToShareHolders(ctx, ownerAddr.String(), service.Id, amount); err != nil { + // Distribute the rewards to the supplier's shareholders based on the rev share percentage. + if err = k.distributeSupplierRewardsToShareHolders(ctx, ownerAddr.String(), service.Id, settlementCoin.Amount.Uint64()); err != nil { return tokenomicstypes.ErrTokenomicsSupplierModuleMintFailed.Wrapf( "distributing rewards to supplier with operator address %s shareholders: %v", supplier.OperatorAddress, @@ -355,7 +347,7 @@ func (k Keeper) TokenLogicModuleGlobalMint( logger := k.Logger().With("method", "TokenLogicModuleGlobalMint") // Determine how much new uPOKT to mint based on global inflation - newMintCoins, newMintAmtFloat := calculateGlobalMintAllocationFromSettlementAmount(settlementCoin) + newMintCoins, newMintAmtFloat := calculateGlobalPerClaimMintInflationFromSettlementAmount(settlementCoin) // Mint new uPOKT to the tokenomics module account if err := k.bankKeeper.MintCoins(ctx, tokenomictypes.ModuleName, newMintCoins); err != nil { @@ -416,20 +408,7 @@ func (k Keeper) TokenLogicModuleGlobalMint( return nil } -// 1. Mint = Burn -// 2. Global Mint -// 4. Overcharge applications -// - Determine the amount send to suppliers -// - Determine the amount send to source owner -// - Overcharge application based on the sum of the two above -// - Send the overcharge to the PNF -// - Emit an event so we can track it -// - PNF manually reimburses the application at the end of the month -// - Prevents self dealing because application has to ask for reimbursement -// - Does not introduce friction to service owners getting rewarded -// - Does not introduce friction to suppliers getting rewarded -// - Ensure NewSession breaks if app stake is too low -// - Ensure relayminer has a toggle to prevent over charging +// TokenLogicModuleGlobalMintReimbursementRequest processes the business logic for the GlobalMintReimbursementRequest TLM. func (k Keeper) TokenLogicModuleGlobalMintReimbursementRequest( ctx context.Context, service *sharedtypes.Service, @@ -439,35 +418,29 @@ func (k Keeper) TokenLogicModuleGlobalMintReimbursementRequest( settlementCoins cosmostypes.Coin, relayMiningDifficulty *tokenomictypes.RelayMiningDifficulty, ) error { - // logger := k.Logger().With("method", "TokenLogicModuleGlobalMintReimbursementRequest") // Determine how much new uPOKT to mint based on global inflation - newMintCoins, _ := calculateGlobalMintAllocationFromSettlementAmount(settlementCoins) + newMintCoins, _ := calculateGlobalPerClaimMintInflationFromSettlementAmount(settlementCoins) + + /* + TODO_UPNEXT_BETA(@Olshansky): Finish implementing this: + 1. Overcharge the application (reduce stake and burn app module tokens) + 2. Send the overcharge to the DAO/PNF address + 3. Add extensive tests for this. + */ - // EventApplicationReimbursementRequest + // Prepare and emit the event for the application being overcharged reimbursementRequestEvent := tokenomictypes.EventApplicationReimbursementRequest{ ApplicationAddr: application.Address, ServiceId: service.Id, SessionId: sessionHeader.SessionId, Amount: &newMintCoins[0], } - eventManager := cosmostypes.UnwrapSDKContext(ctx).EventManager() if err := eventManager.EmitTypedEvent(&reimbursementRequestEvent); err != nil { - return tokenomicstypes.ErrTokenomicsApplicationReimbursementRequestFailed.Wrapf( - "application address: %s; service Id %s; session Id: %s; amount: %s", - application.GetAddress(), - service.Id, - sessionHeader.SessionId, - newMintCoins.String(), - ) + return tokenomicstypes.ErrTokenomicsEmittingEventFailed.Wrapf("error emitting event %v", reimbursementRequestEvent) } - // EventApplicationReimbursementRequest - // What if the application is overcharged? - // How do I enforce running both of them? - // Need to add a new governance parameter? - // Should we prevent new application sessions from starting if its too low? return nil } @@ -498,54 +471,64 @@ func (k Keeper) sendRewardsToAccount( return &coinToAcc, nil } -// handleOverservicedApplication handles the case where an application has been over-serviced. +// ensureClaimAmountLimits checks if the application was overserviced and handles +// the case if it was. // Per Algorithm #1 in the Relay Mining paper, the maximum amount that a single supplier -// can claim in a session is AppStake/NumNodesPerSession. -// If this is not the case, then the supplier essentially did "free work" and the actual -// claim amount is less than what was claimed. +// can claim in a session is AppStake/NumSuppliersPerSession. +// If this is not the case, then the supplier essentially did "free work" and the +// actual claim amount is less than what was claimed. // Ref: https://arxiv.org/pdf/2305.10672 -func (k Keeper) handleOverservicedApplication( +func (k Keeper) ensureClaimAmountLimits( ctx context.Context, + methodLogger log.Logger, application *apptypes.Application, + supplier *sharedtypes.Supplier, claimSettlementCoin cosmostypes.Coin, ) ( actualSettlementCoins cosmostypes.Coin, err error, ) { - logger := k.Logger().With("method", "handleOverservicedApplication") - logger.Warn(fmt.Sprintf( - "THIS SHOULD NEVER HAPPEN. Application with address %s needs to be charged more than it has staked: %v > %v", - application.Address, - claimSettlementCoin, - application.Stake, - )) - - // TODO_MAINNET(@Olshansk, @RawthiL): The application was over-serviced in the last session so it basically - // goes "into debt". Need to design a way to handle this when we implement - // probabilistic proofs and add all the parameter logic. Do we touch the application balance? - // Do we just let it go into debt? Do we penalize the application? Do we unstake it? Etc... - // See this document from @red-0ne and @bryanchriswhite for more context: notion.so/buildwithgrove/Off-chain-Application-Stake-Tracking-6a8bebb107db4f7f9dc62cbe7ba555f7 - expectedBurn := claimSettlementCoin + logger := methodLogger.With("helper", "ensureClaimAmountLimits") + + // TODO_BETA_OR_MAINNET(@red-0ne): The application stake gets reduced with every claim + // settlement. Relay miners use the appStake at the beginning of a session to determine + // the maximum amount they can claim. We need to somehow access and propagate this + // value (via context?) so it is the same for all TLM processors for each claim. + // Note that this will also need to incorporate MintPerClaimGlobalInflation because + // applications are being overcharged by that amount in the meantime. Whatever the + // solution and implementation ends up being, make sure to KISS. + appStake := application.GetStake() + + // Determine the max claimable amount for the supplier based on the application's stake + // in this session. + maxClaimableCoin := sdk.NewCoin(volatile.DenomuPOKT, appStake.Amount.Quo(math.NewInt(sessionkeeper.NumSupplierPerSession))) + + if maxClaimableCoin.Amount.GTE(claimSettlementCoin.Amount) { + logger.Info(fmt.Sprintf("Claim by supplier %s IS WITHIN LIMITS of servicing application %s. Max claimable amount < Claim amount: %v < %v", + supplier.OperatorAddress, application.Address, maxClaimableCoin, claimSettlementCoin.Amount)) + return claimSettlementCoin, nil + } + logger.Warn(fmt.Sprintf("Claim by supplier %s EXCEEDS LIMITS for application %s. Max claimable amount < Claim amount: %v < %v", + supplier.OperatorAddress, application.Address, maxClaimableCoin, claimSettlementCoin.Amount)) + + // Reduce the settlement amount if the application was over-serviced + actualSettlementCoins = maxClaimableCoin + + // Prepare and emit the event for the application being overserviced applicationOverservicedEvent := &tokenomicstypes.EventApplicationOverserviced{ ApplicationAddr: application.Address, - ExpectedBurn: &expectedBurn, - EffectiveBurn: application.GetStake(), + SupplierAddr: supplier.OperatorAddress, + ExpectedBurn: &claimSettlementCoin, + EffectiveBurn: &maxClaimableCoin, } eventManager := cosmostypes.UnwrapSDKContext(ctx).EventManager() if err := eventManager.EmitTypedEvent(applicationOverservicedEvent); err != nil { return cosmostypes.Coin{}, - tokenomicstypes.ErrTokenomicsApplicationOverservicedEvent.Wrapf( - "application address: %s; expected burn %s; effective burn: %s", - application.GetAddress(), - expectedBurn.String(), - application.GetStake().String(), - ) + tokenomicstypes.ErrTokenomicsEmittingEventFailed.Wrapf("error emitting event %v", applicationOverservicedEvent) } - // TODO(@red-0ne) - - return *application.Stake, nil + return actualSettlementCoins, nil } // numRelaysToCoin calculates the amount of uPOKT to mint based on the number of compute units. @@ -626,14 +609,14 @@ func (k Keeper) distributeSupplierRewardsToShareHolders( return nil } -// calculateGlobalMintAllocationFromSettlementAmount calculates the amount of uPOKT -// to mint based on the global inflation rate as a function of the settlement amount -// for a particular claim(s) or session(s). -func calculateGlobalMintAllocationFromSettlementAmount(settlementCoin sdk.Coin) (sdk.Coins, *big.Float) { - // Determine how much new uPOKT to mint based on global inflation +// calculateGlobalPerClaimMintInflationFromSettlementAmount calculates the amount +// of uPOKT to mint based on the global per claim inflation rate as a function of +// the settlement amount for a particular claim(s) or session(s). +func calculateGlobalPerClaimMintInflationFromSettlementAmount(settlementCoin sdk.Coin) (sdk.Coins, *big.Float) { + // Determine how much new uPOKT to mint based on global per claim inflation. // TODO_MAINNET: Consider using fixed point arithmetic for deterministic results. settlementAmtFloat := new(big.Float).SetUint64(settlementCoin.Amount.Uint64()) - newMintAmtFloat := new(big.Float).Mul(settlementAmtFloat, big.NewFloat(MintGlobalInflation)) + newMintAmtFloat := new(big.Float).Mul(settlementAmtFloat, big.NewFloat(MintPerClaimGlobalInflation)) newMintAmtInt, _ := newMintAmtFloat.Int64() mintAmtCoins := sdk.NewCoins(cosmostypes.NewCoin(volatile.DenomuPOKT, math.NewInt(newMintAmtInt))) return mintAmtCoins, newMintAmtFloat diff --git a/x/tokenomics/keeper/token_logic_modules_test.go b/x/tokenomics/keeper/token_logic_modules_test.go index eb2bea113..50fecad21 100644 --- a/x/tokenomics/keeper/token_logic_modules_test.go +++ b/x/tokenomics/keeper/token_logic_modules_test.go @@ -33,6 +33,9 @@ func init() { cmd.InitSDKConfig() } +// TODO_IN_THIS_PR: Tests to add or list +// claimSettlementAmount > maxClaimableAmount + func TestProcessTokenLogicModules_HandleAppGoingIntoDebt(t *testing.T) { keepers, ctx := testkeeper.NewTokenomicsModuleKeepers(t, nil) diff --git a/x/tokenomics/keeper/update_relay_mining_difficulty.go b/x/tokenomics/keeper/update_relay_mining_difficulty.go index 71f2b50fc..d563db86b 100644 --- a/x/tokenomics/keeper/update_relay_mining_difficulty.go +++ b/x/tokenomics/keeper/update_relay_mining_difficulty.go @@ -7,11 +7,13 @@ import ( "fmt" "math/big" + "cosmossdk.io/log" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/pokt-network/poktroll/pkg/crypto/protocol" prooftypes "github.com/pokt-network/poktroll/x/proof/types" "github.com/pokt-network/poktroll/x/tokenomics/types" + tokenomicstypes "github.com/pokt-network/poktroll/x/tokenomics/types" ) // TargetNumRelays is the target number of relays we want the network to mine for @@ -49,17 +51,7 @@ func (k Keeper) UpdateRelayMiningDifficulty( for serviceId, numRelays := range relaysPerServiceMap { prevDifficulty, found := k.GetRelayMiningDifficulty(ctx, serviceId) if !found { - logger.Warn(types.ErrTokenomicsMissingRelayMiningDifficulty.Wrapf( - "No previous relay mining difficulty found for service %s. Initializing with default difficulty %v", - serviceId, prevDifficulty.TargetHash, - ).Error()) - // If a previous difficulty for the service is not found, we initialize a default. - prevDifficulty = types.RelayMiningDifficulty{ - ServiceId: serviceId, - BlockHeight: sdkCtx.BlockHeight(), - NumRelaysEma: numRelays, - TargetHash: prooftypes.DefaultRelayDifficultyTargetHash, - } + prevDifficulty = newDefaultRelayMiningDifficulty(ctx, logger, serviceId, numRelays) } // TODO_MAINNET(@Olshansk): We could potentially compute the smoothing factor @@ -190,3 +182,24 @@ func computeEma(alpha *big.Float, prevEma, currValue uint64) uint64 { newEma, _ := new(big.Float).Add(weightedCurrentContribution, weightedPreviousContribution).Uint64() return newEma } + +func newDefaultRelayMiningDifficulty( + ctx context.Context, + methodLogger log.Logger, + serviceId string, + numRelays uint64, +) tokenomicstypes.RelayMiningDifficulty { + logger := methodLogger.With("helper", "newDefaultRelayMiningDifficulty") + logger.Warn(types.ErrTokenomicsMissingRelayMiningDifficulty.Wrapf( + "No previous relay mining difficulty found for service %s. Creating a temporary relay mining difficulty with %d relays and default target hash %x", + serviceId, numRelays, + ).Error()) + + return tokenomicstypes.RelayMiningDifficulty{ + ServiceId: serviceId, + BlockHeight: sdk.UnwrapSDKContext(ctx).BlockHeight(), + NumRelaysEma: numRelays, + TargetHash: prooftypes.DefaultRelayDifficultyTargetHash, + } + +} diff --git a/x/tokenomics/types/errors.go b/x/tokenomics/types/errors.go index 91b2d761e..24a16cd1b 100644 --- a/x/tokenomics/types/errors.go +++ b/x/tokenomics/types/errors.go @@ -25,7 +25,7 @@ var ( ErrTokenomicsUnmarshalInvalid = sdkerrors.Register(ModuleName, 1116, "failed to unmarshal the provided bytes") ErrTokenomicsDuplicateIndex = sdkerrors.Register(ModuleName, 1117, "cannot have a duplicate index") ErrTokenomicsMissingRelayMiningDifficulty = sdkerrors.Register(ModuleName, 1118, "missing relay mining difficulty") - ErrTokenomicsApplicationOverservicedEvent = sdkerrors.Register(ModuleName, 1119, "application overserviced event cannot be sent") + ErrTokenomicsEmittingEventFailed = sdkerrors.Register(ModuleName, 1119, "failed to emit event") ErrTokenomicsServiceNotFound = sdkerrors.Register(ModuleName, 1120, "service not found") ErrTokenomicsModuleMintFailed = sdkerrors.Register(ModuleName, 1121, "failed to mint uPOKT to tokenomics module account") ErrTokenomicsSendingMintRewards = sdkerrors.Register(ModuleName, 1122, "failed to send minted rewards") diff --git a/x/tokenomics/types/event.pb.go b/x/tokenomics/types/event.pb.go index 1585b4fcf..795d595a9 100644 --- a/x/tokenomics/types/event.pb.go +++ b/x/tokenomics/types/event.pb.go @@ -273,12 +273,20 @@ func (m *EventRelayMiningDifficultyUpdated) GetNewNumRelaysEma() uint64 { return 0 } -// EventApplicationOverserviced is emitted when an application has less stake -// than the expected burn. +// EventApplicationOverserviced is emitted when an application has less stake than +// what a supplier is claiming (i.e. burn is not high enough). type EventApplicationOverserviced struct { - ApplicationAddr string `protobuf:"bytes,1,opt,name=application_addr,json=applicationAddr,proto3" json:"application_addr,omitempty"` - ExpectedBurn *types1.Coin `protobuf:"bytes,2,opt,name=expected_burn,json=expectedBurn,proto3" json:"expected_burn,omitempty"` - EffectiveBurn *types1.Coin `protobuf:"bytes,3,opt,name=effective_burn,json=effectiveBurn,proto3" json:"effective_burn,omitempty"` + ApplicationAddr string `protobuf:"bytes,1,opt,name=application_addr,json=applicationAddr,proto3" json:"application_addr,omitempty"` + SupplierAddr string `protobuf:"bytes,2,opt,name=supplier_addr,json=supplierAddr,proto3" json:"supplier_addr,omitempty"` + // Expected burn is the amount the supplier is claiming for work done + // to service the application during the session. + // This is usually the amount in the Claim object. + ExpectedBurn *types1.Coin `protobuf:"bytes,3,opt,name=expected_burn,json=expectedBurn,proto3" json:"expected_burn,omitempty"` + // Effective burn is the amount that is actually being paid to the supplier + // for the work done. It is less than the expected burn (claim amount) and + // most likely equal to the application's stake divided by the number of suppliers + // in a session. + EffectiveBurn *types1.Coin `protobuf:"bytes,4,opt,name=effective_burn,json=effectiveBurn,proto3" json:"effective_burn,omitempty"` } func (m *EventApplicationOverserviced) Reset() { *m = EventApplicationOverserviced{} } @@ -321,6 +329,13 @@ func (m *EventApplicationOverserviced) GetApplicationAddr() string { return "" } +func (m *EventApplicationOverserviced) GetSupplierAddr() string { + if m != nil { + return m.SupplierAddr + } + return "" +} + func (m *EventApplicationOverserviced) GetExpectedBurn() *types1.Coin { if m != nil { return m.ExpectedBurn @@ -417,56 +432,57 @@ func init() { func init() { proto.RegisterFile("poktroll/tokenomics/event.proto", fileDescriptor_a78874bbf91a58c7) } var fileDescriptor_a78874bbf91a58c7 = []byte{ - // 776 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x55, 0xcd, 0x4e, 0xeb, 0x46, - 0x14, 0x8e, 0xc3, 0x8f, 0x94, 0xa1, 0x40, 0x32, 0x14, 0x35, 0xa5, 0x90, 0x84, 0xa8, 0xaa, 0x28, - 0x15, 0xb6, 0x00, 0xa9, 0xab, 0x0a, 0x35, 0x09, 0xa6, 0x58, 0x2a, 0x49, 0xe4, 0x40, 0x55, 0x75, - 0xe3, 0x3a, 0xf6, 0x49, 0x32, 0x25, 0x9e, 0x31, 0xe3, 0x71, 0x12, 0xde, 0xa2, 0x0f, 0xd0, 0x17, - 0xe8, 0xa2, 0x2f, 0xd1, 0x55, 0xa5, 0x6e, 0x58, 0x76, 0x85, 0x2a, 0xd8, 0xf1, 0x14, 0x57, 0x1e, - 0x3b, 0x3f, 0x04, 0xee, 0xbd, 0xba, 0xcb, 0xbb, 0x49, 0x46, 0xe7, 0x7c, 0xdf, 0x37, 0xe7, 0x7c, - 0x73, 0x72, 0x82, 0x8a, 0x3e, 0xbb, 0x16, 0x9c, 0xf5, 0xfb, 0x9a, 0x60, 0xd7, 0x40, 0x99, 0x47, - 0x9c, 0x40, 0x83, 0x01, 0x50, 0xa1, 0xfa, 0x9c, 0x09, 0x86, 0x37, 0xc6, 0x00, 0x75, 0x0a, 0xd8, - 0x2a, 0x38, 0x2c, 0xf0, 0x58, 0xa0, 0xb5, 0xed, 0x00, 0xb4, 0xc1, 0x61, 0x1b, 0x84, 0x7d, 0xa8, - 0x39, 0x8c, 0xd0, 0x98, 0xb4, 0xf5, 0x69, 0x97, 0x75, 0x99, 0x3c, 0x6a, 0xd1, 0x29, 0x89, 0x6e, - 0x4d, 0xee, 0xf2, 0x39, 0x63, 0x1d, 0xcd, 0xe9, 0xdb, 0xc4, 0x4b, 0x72, 0xa5, 0xb9, 0x1c, 0x87, - 0x9b, 0x90, 0x70, 0xf0, 0x26, 0x85, 0x94, 0xff, 0x4a, 0xa3, 0x9c, 0x1e, 0x15, 0x56, 0x8b, 0x68, - 0xfa, 0xc8, 0x27, 0x1c, 0x5c, 0xfc, 0x2d, 0x5a, 0x92, 0x32, 0x79, 0xa5, 0xa4, 0xec, 0xad, 0x1c, - 0x6d, 0xaa, 0x93, 0x72, 0xa5, 0x8e, 0x2a, 0xc1, 0xd5, 0xcc, 0xd3, 0x7d, 0x31, 0xc6, 0x99, 0xf1, - 0x17, 0x3e, 0x40, 0x88, 0x86, 0x9e, 0xc5, 0xa1, 0x6f, 0xdf, 0x06, 0xf9, 0x74, 0x49, 0xd9, 0x5b, - 0xac, 0xae, 0x3d, 0xdd, 0x17, 0x67, 0xa2, 0x66, 0x86, 0x86, 0x9e, 0x29, 0x8f, 0xb8, 0x82, 0x72, - 0x51, 0xc2, 0x61, 0x9e, 0x1f, 0x0a, 0xb0, 0x42, 0x4a, 0x44, 0x90, 0x5f, 0x90, 0xac, 0xcd, 0xa7, - 0xfb, 0xe2, 0xcb, 0xa4, 0xb9, 0x4e, 0x43, 0xaf, 0x16, 0x47, 0xae, 0xa2, 0x00, 0xa6, 0x28, 0x07, - 0x51, 0xd1, 0xb6, 0x20, 0x8c, 0x5a, 0x1c, 0xec, 0x80, 0xd1, 0xfc, 0x62, 0x49, 0xd9, 0x5b, 0x3b, - 0xda, 0x57, 0x5f, 0x31, 0x59, 0x9d, 0xf6, 0x29, 0x29, 0xa6, 0x64, 0xc4, 0xd7, 0xbd, 0x10, 0x32, - 0xb3, 0x30, 0x07, 0x2c, 0xff, 0xf9, 0xcc, 0xaf, 0x16, 0x08, 0xd1, 0xff, 0xa8, 0xfc, 0xfa, 0x0d, - 0xe5, 0x64, 0x49, 0xd6, 0xcc, 0x28, 0x24, 0x7e, 0x7d, 0x35, 0x5f, 0x75, 0x33, 0xfa, 0x34, 0xa7, - 0xb8, 0x59, 0xaf, 0x5e, 0x88, 0x98, 0x59, 0x7f, 0x0e, 0x5e, 0xfe, 0x23, 0x8d, 0x76, 0xa5, 0x57, - 0xb2, 0xfc, 0x0b, 0x42, 0x09, 0xed, 0x9e, 0x92, 0x4e, 0x87, 0x38, 0x61, 0x5f, 0xdc, 0x5e, 0xf9, - 0xae, 0x2d, 0xc0, 0xc5, 0x3b, 0x08, 0x05, 0xc0, 0x07, 0xc4, 0x01, 0x8b, 0xb8, 0xd2, 0xc0, 0x8c, - 0x99, 0x49, 0x22, 0x86, 0x8b, 0x4f, 0xd0, 0xb6, 0xcf, 0x61, 0x60, 0x09, 0x9b, 0x77, 0x41, 0x58, - 0x3d, 0x3b, 0xe8, 0x59, 0x3d, 0x18, 0x59, 0x40, 0x1d, 0xe6, 0x82, 0x2b, 0x4d, 0xcb, 0x98, 0xf9, - 0x08, 0x73, 0x29, 0x21, 0xe7, 0x76, 0xd0, 0x3b, 0x87, 0x91, 0x1e, 0xe7, 0xf1, 0x77, 0xe8, 0x0b, - 0x0a, 0xc3, 0xb7, 0xd2, 0x17, 0x24, 0xfd, 0x33, 0x0a, 0xc3, 0x57, 0xd9, 0x07, 0x68, 0x43, 0xde, - 0x3e, 0x7d, 0x0f, 0x0b, 0x3c, 0x5b, 0x1a, 0xb6, 0x18, 0x75, 0x0c, 0x83, 0xfa, 0xf8, 0x75, 0x74, - 0xcf, 0xc6, 0xdf, 0x20, 0x1c, 0x5d, 0x36, 0x87, 0x5e, 0x92, 0xe8, 0x75, 0x0a, 0xc3, 0x59, 0x70, - 0xf9, 0x5f, 0x05, 0x6d, 0x4b, 0x7b, 0x2a, 0xbe, 0xdf, 0x27, 0x8e, 0x9c, 0xb2, 0xc6, 0x00, 0x78, - 0xd2, 0xbb, 0x8b, 0xbf, 0x46, 0x59, 0x7b, 0x9a, 0xb2, 0x6c, 0xd7, 0xe5, 0x89, 0x3f, 0xeb, 0x33, - 0xf1, 0x8a, 0xeb, 0x72, 0x7c, 0x82, 0x56, 0x61, 0xe4, 0x83, 0x23, 0xc0, 0xb5, 0xda, 0x21, 0xa7, - 0xd2, 0x96, 0x95, 0xa3, 0xcf, 0xd5, 0x78, 0xa5, 0xa8, 0xd1, 0x4a, 0x51, 0x93, 0x95, 0xa2, 0xd6, - 0x18, 0xa1, 0xe6, 0x27, 0x63, 0x7c, 0x35, 0xe4, 0x14, 0x7f, 0x8f, 0xd6, 0xa0, 0xd3, 0x01, 0x47, - 0x90, 0x01, 0xc4, 0x02, 0x0b, 0xef, 0x13, 0x58, 0x9d, 0x10, 0x22, 0x85, 0xf2, 0xdf, 0x0a, 0xfa, - 0x72, 0xbe, 0x1b, 0x13, 0x88, 0xd7, 0x0e, 0x79, 0x90, 0x4c, 0xcf, 0x4d, 0x08, 0x81, 0xf8, 0x90, - 0xae, 0x9e, 0x8f, 0x46, 0x7a, 0x7e, 0x34, 0x64, 0x3a, 0x08, 0x22, 0x15, 0x32, 0x7e, 0xc9, 0x4c, - 0x12, 0x31, 0x5c, 0x7c, 0x88, 0x96, 0x6d, 0x8f, 0x85, 0xc9, 0x7c, 0xbf, 0xb3, 0x97, 0x04, 0xb8, - 0xff, 0x2b, 0xda, 0x7c, 0x75, 0x3f, 0xe0, 0x5d, 0xb4, 0xa3, 0xff, 0xdc, 0x34, 0xcc, 0xca, 0xa5, - 0xd1, 0xa8, 0x5b, 0xa6, 0x5e, 0x69, 0x35, 0xea, 0xd6, 0x55, 0xbd, 0xd5, 0xd4, 0x6b, 0xc6, 0x99, - 0xa1, 0x9f, 0x66, 0x53, 0x38, 0x87, 0x56, 0x9b, 0x66, 0xa3, 0x71, 0x66, 0x5d, 0x18, 0xad, 0x96, - 0x51, 0xff, 0x21, 0xab, 0x4c, 0x43, 0x46, 0xfd, 0xa7, 0xca, 0x8f, 0xc6, 0x69, 0x36, 0x5d, 0xbd, - 0xf8, 0xe7, 0xa1, 0xa0, 0xdc, 0x3d, 0x14, 0x94, 0xff, 0x1f, 0x0a, 0xca, 0xef, 0x8f, 0x85, 0xd4, - 0xdd, 0x63, 0x21, 0xf5, 0xdf, 0x63, 0x21, 0xf5, 0xcb, 0x71, 0x97, 0x88, 0x5e, 0xd8, 0x56, 0x1d, - 0xe6, 0x69, 0xd1, 0x0f, 0xf1, 0x80, 0x82, 0x18, 0x32, 0x7e, 0xad, 0x4d, 0x76, 0xf8, 0x68, 0xf6, - 0xdf, 0x44, 0xdc, 0xfa, 0x10, 0xb4, 0x97, 0xe5, 0x16, 0x3f, 0x7e, 0x13, 0x00, 0x00, 0xff, 0xff, - 0xe7, 0x04, 0xe0, 0xc6, 0x71, 0x06, 0x00, 0x00, + // 793 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x55, 0x4f, 0x6f, 0xe3, 0x44, + 0x14, 0x8f, 0xb3, 0xd9, 0x95, 0x32, 0xbb, 0x69, 0x93, 0x59, 0x2a, 0x42, 0xd9, 0x4d, 0xb2, 0x01, + 0xa1, 0xb2, 0xa8, 0xb6, 0xda, 0x95, 0x38, 0xa1, 0x8a, 0x24, 0x75, 0xa9, 0x25, 0x9a, 0x44, 0x4e, + 0x8b, 0x10, 0x17, 0xe3, 0xd8, 0x2f, 0xc9, 0xd0, 0x78, 0xc6, 0x9d, 0x19, 0x27, 0xe9, 0xb7, 0xe0, + 0x03, 0xf0, 0x05, 0x38, 0xf0, 0x25, 0x38, 0x71, 0xec, 0x91, 0x53, 0x85, 0xda, 0x5b, 0x4f, 0x7c, + 0x04, 0xe4, 0xb1, 0xf3, 0xa7, 0x69, 0x01, 0x71, 0xe4, 0xd2, 0x8e, 0x7e, 0xef, 0xf7, 0x7b, 0xf3, + 0xde, 0x6f, 0x9e, 0x5f, 0x50, 0x35, 0x64, 0xe7, 0x92, 0xb3, 0xf1, 0xd8, 0x90, 0xec, 0x1c, 0x28, + 0x0b, 0x88, 0x27, 0x0c, 0x98, 0x00, 0x95, 0x7a, 0xc8, 0x99, 0x64, 0xf8, 0xe5, 0x9c, 0xa0, 0x2f, + 0x09, 0xdb, 0x15, 0x8f, 0x89, 0x80, 0x09, 0xa3, 0xef, 0x0a, 0x30, 0x26, 0x7b, 0x7d, 0x90, 0xee, + 0x9e, 0xe1, 0x31, 0x42, 0x13, 0xd1, 0xf6, 0x7b, 0x43, 0x36, 0x64, 0xea, 0x68, 0xc4, 0xa7, 0x14, + 0xdd, 0x5e, 0xdc, 0x15, 0x72, 0xc6, 0x06, 0x86, 0x37, 0x76, 0x49, 0x90, 0xc6, 0x6a, 0x6b, 0x31, + 0x0e, 0x17, 0x11, 0xe1, 0x10, 0x2c, 0x0a, 0xa9, 0xff, 0x92, 0x45, 0x25, 0x33, 0x2e, 0xac, 0x15, + 0xcb, 0xcc, 0x59, 0x48, 0x38, 0xf8, 0xf8, 0x73, 0xf4, 0x54, 0xa5, 0x29, 0x6b, 0x35, 0x6d, 0xe7, + 0xf9, 0xfe, 0x96, 0xbe, 0x28, 0x57, 0xe5, 0xd1, 0x15, 0xb9, 0x99, 0xbf, 0xbb, 0xae, 0x26, 0x3c, + 0x3b, 0xf9, 0x87, 0x77, 0x11, 0xa2, 0x51, 0xe0, 0x70, 0x18, 0xbb, 0x97, 0xa2, 0x9c, 0xad, 0x69, + 0x3b, 0xb9, 0xe6, 0xc6, 0xdd, 0x75, 0x75, 0x05, 0xb5, 0xf3, 0x34, 0x0a, 0x6c, 0x75, 0xc4, 0x0d, + 0x54, 0x8a, 0x03, 0x1e, 0x0b, 0xc2, 0x48, 0x82, 0x13, 0x51, 0x22, 0x45, 0xf9, 0x89, 0x52, 0x6d, + 0xdd, 0x5d, 0x57, 0x1f, 0x06, 0xed, 0x4d, 0x1a, 0x05, 0xad, 0x04, 0x39, 0x8b, 0x01, 0x4c, 0x51, + 0x09, 0xe2, 0xa2, 0x5d, 0x49, 0x18, 0x75, 0x38, 0xb8, 0x82, 0xd1, 0x72, 0xae, 0xa6, 0xed, 0x6c, + 0xec, 0xbf, 0xd5, 0x1f, 0x31, 0x59, 0x5f, 0xf6, 0xa9, 0x24, 0xb6, 0x52, 0x24, 0xd7, 0x3d, 0x48, + 0x64, 0x17, 0x61, 0x8d, 0x58, 0xff, 0xf9, 0x9e, 0x5f, 0x3d, 0x90, 0x72, 0xfc, 0xbf, 0xf2, 0xeb, + 0x07, 0x54, 0x52, 0x25, 0x39, 0x2b, 0xa3, 0x90, 0xfa, 0xf5, 0xc9, 0x7a, 0xd5, 0xdd, 0xf8, 0xaf, + 0xbd, 0xe4, 0xad, 0x7a, 0xf5, 0x20, 0x89, 0x5d, 0x0c, 0xd7, 0xe8, 0xf5, 0x9f, 0xb2, 0xe8, 0x8d, + 0xf2, 0x4a, 0x95, 0x7f, 0x42, 0x28, 0xa1, 0xc3, 0x43, 0x32, 0x18, 0x10, 0x2f, 0x1a, 0xcb, 0xcb, + 0xb3, 0xd0, 0x77, 0x25, 0xf8, 0xf8, 0x35, 0x42, 0x02, 0xf8, 0x84, 0x78, 0xe0, 0x10, 0x5f, 0x19, + 0x98, 0xb7, 0xf3, 0x29, 0x62, 0xf9, 0xf8, 0x00, 0xbd, 0x0a, 0x39, 0x4c, 0x1c, 0xe9, 0xf2, 0x21, + 0x48, 0x67, 0xe4, 0x8a, 0x91, 0x33, 0x82, 0x99, 0x03, 0xd4, 0x63, 0x3e, 0xf8, 0xca, 0xb4, 0xbc, + 0x5d, 0x8e, 0x39, 0xa7, 0x8a, 0x72, 0xec, 0x8a, 0xd1, 0x31, 0xcc, 0xcc, 0x24, 0x8e, 0xbf, 0x40, + 0x1f, 0x52, 0x98, 0xfe, 0xad, 0xfc, 0x89, 0x92, 0xbf, 0x4f, 0x61, 0xfa, 0xa8, 0x7a, 0x17, 0xbd, + 0x54, 0xb7, 0x2f, 0xdf, 0xc3, 0x81, 0xc0, 0x55, 0x86, 0xe5, 0xe2, 0x8e, 0x61, 0xd2, 0x9e, 0xbf, + 0x8e, 0x19, 0xb8, 0xf8, 0x33, 0x84, 0xe3, 0xcb, 0xd6, 0xd8, 0x4f, 0x15, 0x7b, 0x93, 0xc2, 0x74, + 0x95, 0x5c, 0xff, 0x53, 0x43, 0xaf, 0x94, 0x3d, 0x8d, 0x30, 0x1c, 0x13, 0x4f, 0x4d, 0x59, 0x67, + 0x02, 0x3c, 0xed, 0xdd, 0xc7, 0x9f, 0xa2, 0xa2, 0xbb, 0x0c, 0x39, 0xae, 0xef, 0xf3, 0xd4, 0x9f, + 0xcd, 0x15, 0xbc, 0xe1, 0xfb, 0x1c, 0x7f, 0x84, 0x0a, 0x22, 0x8a, 0x31, 0xe0, 0x09, 0x2f, 0xb1, + 0xe5, 0xc5, 0x1c, 0x54, 0xa4, 0x03, 0x54, 0x80, 0x59, 0x08, 0x9e, 0x04, 0xdf, 0xe9, 0x47, 0x9c, + 0xaa, 0xe6, 0x9f, 0xef, 0x7f, 0xa0, 0x27, 0x7b, 0x47, 0x8f, 0xf7, 0x8e, 0x9e, 0xee, 0x1d, 0xbd, + 0xc5, 0x08, 0xb5, 0x5f, 0xcc, 0xf9, 0xcd, 0x88, 0x53, 0xfc, 0x25, 0xda, 0x80, 0xc1, 0x00, 0x3c, + 0x49, 0x26, 0x90, 0x24, 0xc8, 0xfd, 0x5b, 0x82, 0xc2, 0x42, 0x10, 0x67, 0xa8, 0xff, 0xaa, 0xa1, + 0x8f, 0xd7, 0x5b, 0xb6, 0x81, 0x04, 0xfd, 0x88, 0x8b, 0x74, 0xc4, 0x2e, 0x22, 0x10, 0xf2, 0xbf, + 0xb4, 0x7e, 0x7f, 0x7e, 0xb2, 0xeb, 0xf3, 0xa3, 0xc2, 0x42, 0xc4, 0x59, 0xc8, 0xfc, 0xb9, 0xf3, + 0x29, 0x62, 0xf9, 0x78, 0x0f, 0x3d, 0x73, 0x03, 0x16, 0xa5, 0x1f, 0xc1, 0x3f, 0xf6, 0x92, 0x12, + 0xdf, 0x7e, 0x8f, 0xb6, 0x1e, 0x5d, 0x22, 0xf8, 0x0d, 0x7a, 0x6d, 0x7e, 0xdb, 0xb5, 0xec, 0xc6, + 0xa9, 0xd5, 0x69, 0x3b, 0xb6, 0xd9, 0xe8, 0x75, 0xda, 0xce, 0x59, 0xbb, 0xd7, 0x35, 0x5b, 0xd6, + 0x91, 0x65, 0x1e, 0x16, 0x33, 0xb8, 0x84, 0x0a, 0x5d, 0xbb, 0xd3, 0x39, 0x72, 0x4e, 0xac, 0x5e, + 0xcf, 0x6a, 0x7f, 0x55, 0xd4, 0x96, 0x90, 0xd5, 0xfe, 0xa6, 0xf1, 0xb5, 0x75, 0x58, 0xcc, 0x36, + 0x4f, 0x7e, 0xbb, 0xa9, 0x68, 0x57, 0x37, 0x15, 0xed, 0x8f, 0x9b, 0x8a, 0xf6, 0xe3, 0x6d, 0x25, + 0x73, 0x75, 0x5b, 0xc9, 0xfc, 0x7e, 0x5b, 0xc9, 0x7c, 0xf7, 0x6e, 0x48, 0xe4, 0x28, 0xea, 0xeb, + 0x1e, 0x0b, 0x8c, 0xf8, 0x6b, 0xdd, 0xa5, 0x20, 0xa7, 0x8c, 0x9f, 0x1b, 0x8b, 0x45, 0x3f, 0x5b, + 0xfd, 0xc9, 0x91, 0x97, 0x21, 0x88, 0xfe, 0x33, 0xb5, 0xea, 0xdf, 0xfd, 0x15, 0x00, 0x00, 0xff, + 0xff, 0x37, 0x47, 0xc1, 0x88, 0x96, 0x06, 0x00, 0x00, } func (m *EventClaimExpired) Marshal() (dAtA []byte, err error) { @@ -653,7 +669,7 @@ func (m *EventApplicationOverserviced) MarshalToSizedBuffer(dAtA []byte) (int, e i = encodeVarintEvent(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x1a + dAtA[i] = 0x22 } if m.ExpectedBurn != nil { { @@ -665,6 +681,13 @@ func (m *EventApplicationOverserviced) MarshalToSizedBuffer(dAtA []byte) (int, e i = encodeVarintEvent(dAtA, i, uint64(size)) } i-- + dAtA[i] = 0x1a + } + if len(m.SupplierAddr) > 0 { + i -= len(m.SupplierAddr) + copy(dAtA[i:], m.SupplierAddr) + i = encodeVarintEvent(dAtA, i, uint64(len(m.SupplierAddr))) + i-- dAtA[i] = 0x12 } if len(m.ApplicationAddr) > 0 { @@ -825,6 +848,10 @@ func (m *EventApplicationOverserviced) Size() (n int) { if l > 0 { n += 1 + l + sovEvent(uint64(l)) } + l = len(m.SupplierAddr) + if l > 0 { + n += 1 + l + sovEvent(uint64(l)) + } if m.ExpectedBurn != nil { l = m.ExpectedBurn.Size() n += 1 + l + sovEvent(uint64(l)) @@ -1399,6 +1426,38 @@ func (m *EventApplicationOverserviced) Unmarshal(dAtA []byte) error { m.ApplicationAddr = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SupplierAddr", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvent + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvent + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvent + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SupplierAddr = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field ExpectedBurn", wireType) } @@ -1434,7 +1493,7 @@ func (m *EventApplicationOverserviced) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 3: + case 4: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field EffectiveBurn", wireType) } From 98736f3c81b0126b0b4795007d32bb18133c40c4 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Wed, 21 Aug 2024 15:11:50 -0400 Subject: [PATCH 04/53] Revert tokenomic docs --- .../protocol/architecture/_category_.json | 4 +- .../docs/protocol/architecture/network.md | 2 +- .../docs/protocol/tokenomics/_category_.json | 8 - .../docs/protocol/tokenomics/resources.md | 21 -- .../tokenomics/token_logic_modules.md | 287 ------------------ .../docs/protocol/upgrades/_category_.json | 2 +- 6 files changed, 4 insertions(+), 320 deletions(-) delete mode 100644 docusaurus/docs/protocol/tokenomics/_category_.json delete mode 100644 docusaurus/docs/protocol/tokenomics/resources.md delete mode 100644 docusaurus/docs/protocol/tokenomics/token_logic_modules.md diff --git a/docusaurus/docs/protocol/architecture/_category_.json b/docusaurus/docs/protocol/architecture/_category_.json index 985d17b7b..c4be422a5 100644 --- a/docusaurus/docs/protocol/architecture/_category_.json +++ b/docusaurus/docs/protocol/architecture/_category_.json @@ -1,6 +1,6 @@ { - "label": "[Outdated] Architecture", - "position": 6, + "label": "Architecture", + "position": 7, "link": { "type": "generated-index", "description": "Documentation related to the high-level design, flows and components of the poktroll repo." diff --git a/docusaurus/docs/protocol/architecture/network.md b/docusaurus/docs/protocol/architecture/network.md index b7949986e..d0e25f1d3 100644 --- a/docusaurus/docs/protocol/architecture/network.md +++ b/docusaurus/docs/protocol/architecture/network.md @@ -1,5 +1,5 @@ --- -title: Outdated - Pocket Actors, Nodes & Data Availability Network +title: Pocket Actors, Nodes & Data Availability Network sidebar_position: 1 --- diff --git a/docusaurus/docs/protocol/tokenomics/_category_.json b/docusaurus/docs/protocol/tokenomics/_category_.json deleted file mode 100644 index c23caaa17..000000000 --- a/docusaurus/docs/protocol/tokenomics/_category_.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "label": "Tokenomics", - "position": 5, - "link": { - "type": "generated-index", - "description": "Documentation related to Pocket Network tokenomics." - } -} diff --git a/docusaurus/docs/protocol/tokenomics/resources.md b/docusaurus/docs/protocol/tokenomics/resources.md deleted file mode 100644 index b652b0349..000000000 --- a/docusaurus/docs/protocol/tokenomics/resources.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -title: Tokenomics Resources -sidebar_position: 1 ---- - -# Tokenomics Resources - -:::warning - -This is an active an ever evolving work. We are working on a single source of truth. - -::: - -The following resources serve as the foundation for the Shannon Upgrade Tokenomics. - -- [Token Logic Module](https://docs.pokt.network/pokt-protocol/the-shannon-upgrade/proposed-tokenomics/token-logic-modules) design approach. -- [Shannon Tokenomics Static](https://github.com/pokt-network/shannon-tokenomics-static-tests) modeling & evaluation -- [Relay Mining](https://arxiv.org/abs/2305.10672) paper -- [Probabilistic Proofs](https://github.com/pokt-network/pocket-core/blob/staging/docs/proposals/probabilistic_proofs.md) design - -Thank you to [@Rama_stdout](https://x.com/Rama_stdout), [@shane8burger](https://x.com/shane8burger) and [@olshansky](https://x.com/olshansky) for the contributions! diff --git a/docusaurus/docs/protocol/tokenomics/token_logic_modules.md b/docusaurus/docs/protocol/tokenomics/token_logic_modules.md deleted file mode 100644 index fd70d0fe9..000000000 --- a/docusaurus/docs/protocol/tokenomics/token_logic_modules.md +++ /dev/null @@ -1,287 +0,0 @@ ---- -title: Token Logic Modules -sidebar_position: 2 ---- - -# Token Logic Modules - -- [Introduction](#introduction) -- [Background: Max Claimable Amount](#background-max-claimable-amount) -- [TLM (pre) Processing](#tlm-pre-processing) -- [TLM: Mint=Burn (MEB)](#tlm-mintburn-meb) -- [TLM: Global Mint (GM)](#tlm-global-mint-gm) -- [TLM: Global Mint Reimbursement Request (GMRR)](#tlm-global-mint-reimbursement-request-gmrr) - -## Introduction - -:::warning - -Note that this is an active WIP and the [resources here](./resources.md) are the best starting references to learn more. - -::: - -Token Logic Modules (TLMs) processing involves: - -1. `TLM pre-processing` - A general pre-processor determining the amount of tokens to settle per claim. -2. `TLM processing` - Iteration through all of the TLMs one by one. -3. `TLM processor` - Individual processing each TLM independent of one another. - -## Background: Max Claimable Amount - -_tl;dr Max Claimable Amount ∝ (Application Stake / Number of Suppliers per Session)_ - -Per **Algorithm 1** of the [Relay Mining paper](https://arxiv.org/pdf/2305.10672), -the maximum amount a supplier can claim from an application in a single session is -proportional to the Application's stake divided by the number of suppliers in the session. - -This is referred to as "Relay Mining Payable Relay Accumulation" in the paper and -can be seen in the following image: - -![Algorithm 1](https://github.com/user-attachments/assets/d1a61535-aa31-447d-88ea-c8d14dcb20c6) - -## TLM (pre) Processing - -_tl;dr Determine if the claim settlement amount is greater than the maximum claimable amount and then run each individual TLM._ - -**Prior to** processing each individual TLM, we need to understand if the amount claimed -by the supplier adheres to the optimistic maxima set per the limits of Relay Mining. - -Suppliers always have the option to over-service an application (**i.e. do free work**), -in exchange for providing a good service to the network. This may lead to offchain -reputation benefits (e.g. Gateways favoring them), but their on-chain rewards -are still limited as a function of the application's stake before the session started -and the number of suppliers in the session. - -:::note - -TODO_POST_MAINNET: After the Shannon upgrade, the team at Grove has a lot of ideas -related to on-chain reputation, [supplier gossiping](https://www.notion.so/buildwithgrove/Off-chain-Application-Stake-Tracking-6a8bebb107db4f7f9dc62cbe7ba555f7?pvs=4), and -much more, but that is out of scope for the initial implementation. - -::: - -```mermaid ---- -title: "Token Logic Modules (pre) Processing" ---- -flowchart TB - CSA(["Claim Settlement Amount (CSA)"]) - MCA(["MaxClaimPerSupplier (MCA)
= (AppStake / NumSuppliersPerSession)"]) - CC{"Is CSA > MCA?"} - Update(Set SA = MCA
Broadcast Event) - SOAE{{Application Overserviced
Event}} - TLMP[["TLM Processor (SA)"]] - - CSA -- CSA --> CC - MCA -- MCA --> CC - - Update -..-> SOAE - CC -- Yes --> Update - CC -- No
SA=CSA --> TLMP - Update -- SA=CSA --> TLMP - - TLMP --SA--> TLMBEM[[TLM: Burn Equals Mint]] - TLMP --SA--> TLMGI[[TLM: Global Inflation]] - TLMP --SA--> TLMGIRR[[TLM: Global Inflation Reimbursement Request]] - - classDef tlm fill:#54ebd5,stroke:#333,stroke-width:2px; - classDef question fill:#e3db6d,stroke:#333,stroke-width:2px; - classDef event fill:#e8b761,stroke:#333,stroke-width:2px; - - class TLMP,TLMBEM,TLMGI,TLMGIRR tlm; - class SOAE event; - class CC question; -``` - -## TLM: Mint=Burn (MEB) - -_tl;dr The transfer of tokens from the application to the supplier based on the amount of work received and provided respectively.._ - -The `Mint=Burn` TLM is, _theoretically_, the only TLM necessary when the network -reaches equilibrium in the far future. - -The same amount of tokens that is minted in the **supplier module** is burned from -the **application module**. The stake of the application paying for work is reduced -and the rewards are distributed to the supplier and its revenue shareholder addresses. - -```mermaid ---- -title: "Token Logic Module: Mint=Burn" ---- -flowchart TD - SA(["Settlement Amount (SA)"]) - - SA -- Mint SA coins --> SM - SA -- Burn SA coins--> AM - - subgraph SO[Supplier Operations] - SM[[Supplier Module]] - SK[(Supplier Keeper)] - SD{Distribute SA coins} - OPA[Operator Address] - OA[Owner Address] - RSA[Revenue Share Addresses] - - SM -.- SK - SD -->|% Distribution
Increase Balance| OPA - SD -->|% Distribution
Increase Balance| OA - SD -->|% Distribution
Increase Balance| RSA - end - - subgraph AO[Application Operations] - AM[[Application Module]] - AK[(Application Keeper)] - AA[Application Address] - - AM -.- AK - AK -. Reduce Stake by SA .-> AA - AA -.- TODO{See TODO below} - end - - SM --> SD - - classDef module fill:#f9f,stroke:#333,stroke-width:2px; - classDef address fill:#bbf,stroke:#333,stroke-width:2px; - classDef question fill:#e3db6d,stroke:#333,stroke-width:2px; - classDef event fill:#e8b761,stroke:#333,stroke-width:2px; - - class SM,AM module; - class RSA,OA,OPA,AA address; - class TODO question; -``` - -:::note - -TODO_MAINNET: If the application stake has dropped to (near?) zero, should -we unstake it? Should we use it's balance? Should their be a payee of last resort? -Make sure to document whatever decision we come to. - -::: - -## TLM: Global Mint (GM) - -_tl;dr Distributed newly minted coins on a per claim basis to all involved stakeholders._ - -The `Global Mint` TLM is, _theoretically_, going to reach `zero`the only when the network -reaches equilibrium in the far future. - -On a per claim basis, the network mints new tokens based on the the amount of work -claimed. The newly minted tokens are distributed to the supplier, DAO, service owner -and application based on the values of various governance params. - -```mermaid ---- -title: "Token Logic Module: Global Mint" ---- -flowchart TD - SC(["Settlement Coin (SC)"]) - PCI(["Per Claim Global Inflation
(Governance Parameter)"]) - IMC(["Inflation Mint Coin (IMC)"]) - - DA(["DAO Mint Allocation"]) - PA(["Proposer Mint Allocation"]) - SA(["Supplier Mint Allocation"]) - SOA(["Source Owner Mint Allocation"]) - AA(["Application Mint Allocation"]) - - - SC --> IMC - PCI --> IMC - IMC --> TO - - subgraph TO[Tokenomics Operations] - TM[[Tokenomics Module]] - TK[(Tokenomics Keeper)] - TM -..- TK - end - - - DA --> ID - PA --> ID - TO -- New Mint Coin (NMC)--> ID - SA --> ID - AA --> ID - - subgraph ID[Inflation Distribution] - NMC["New Mint Coin (NMC)"] - APPA["Application Address"] - SPPA["Supplier Address"] - DAOA["DAO Address"] - SOA["Service Owner Address"] - PRA["Proposer Address"] - - NMC -->|% Mint Allocation| APPA - NMC -->|% Mint Allocation| SPPA - NMC -->|% Mint Allocation| DAOA - NMC -->|% Mint Allocation| SOA - NMC -->|% Mint Allocation| PRA - end - - classDef module fill:#f9f,stroke:#333,stroke-width:2px; - classDef address fill:#bbf,stroke:#333,stroke-width:2px; - classDef question fill:#e3db6d,stroke:#333,stroke-width:2px; - classDef govparam fill:#d04a36,stroke:#333,stroke-width:2px; - classDef event fill:#e8b761,stroke:#333,stroke-width:2px; - - class TM module; - class PCI,DA,PA,SA,AA govparam; - class APPA,SPPA,DAOA,SOA,PRA address; -``` - -## TLM: Global Mint Reimbursement Request (GMRR) - -_tl;dr Prevent self-dealing by over-charging applications, sending the excess to the DAO/PNF, and emitting an event as a reimbursement request._ - -This TLM **MUST** be processed alongside the Global Mint TLM. - -This TLM can, **theoretically**, be removed if self-dealing attacks are not a concern, -or if the global mint per claim governance parameter is set to zero. - -The goal of the TLM is to overcharge applications equal to the global inflation amount -and send those funds to the DAO/PNF. This forces potentially self-dealing gateways to -"show face" in front of the DAO/PNF and request reimbursement. - -The event emitted creates an easy, onchain mechanism, to track reimbursement handled offchain. - -A side effect of this TLM is creating additional buy pressure of the token as Applications -and Gateways will be responsible for frequently "topping up" their balances and app stakes. - -```mermaid ---- -title: "Token Logic Module: Global Mint Reimbursement Request" ---- -flowchart TD - SC(["Settlement Coin (SC)"]) - PCI(["Per Claim Global Inflation
(Governance Parameter)"]) - IMC(["Inflation Mint Coin (IMC)"]) - ARRE{{Application Reimbursement
Request Event}} - - SC --> IMC - PCI --> IMC - IMC --IMC--> AO - - - subgraph AO[Application Operations] - AM[[Application Module]] - AK[(Application Keeper)] - AA[Application Address] - DA[DAO Address] - - AM -.- AK - AK -. Reduce Stake by IMC .-> AA - AM -..-> |Increase Balance by IMC| DA - end - - AO -. Emit Event.-> ARRE - - classDef module fill:#f9f,stroke:#333,stroke-width:2px; - classDef address fill:#bbf,stroke:#333,stroke-width:2px; - classDef question fill:#e3db6d,stroke:#333,stroke-width:2px; - classDef govparam fill:#d04a36,stroke:#333,stroke-width:2px; - classDef event fill:#e8b761,stroke:#333,stroke-width:2px; - - class AM module; - class ARRE event; - class PCI govparam; - class AA,DA address; -``` diff --git a/docusaurus/docs/protocol/upgrades/_category_.json b/docusaurus/docs/protocol/upgrades/_category_.json index 2e80f4c80..5fe4a715b 100644 --- a/docusaurus/docs/protocol/upgrades/_category_.json +++ b/docusaurus/docs/protocol/upgrades/_category_.json @@ -1,6 +1,6 @@ { "label": "Upgrades", - "position": 4, + "position": 7, "link": { "type": "generated-index", "description": "Documentation related to Pocket Network protocol upgrades." From eeabb30c17d82ad363619fc19231483dd303f006 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Wed, 21 Aug 2024 15:33:06 -0400 Subject: [PATCH 05/53] Performed self review --- e2e/tests/0_settlement.feature | 3 +++ pkg/relayer/session/sessiontree.go | 1 + x/tokenomics/keeper/token_logic_modules.go | 12 +++++------- x/tokenomics/keeper/token_logic_modules_test.go | 7 +++++-- .../keeper/update_relay_mining_difficulty.go | 6 ++++-- 5 files changed, 18 insertions(+), 11 deletions(-) diff --git a/e2e/tests/0_settlement.feature b/e2e/tests/0_settlement.feature index 358d2cd27..b4eaf2441 100644 --- a/e2e/tests/0_settlement.feature +++ b/e2e/tests/0_settlement.feature @@ -26,6 +26,9 @@ Feature: Tokenomics Namespace Then the account balance of "supplier1" should be "420" uPOKT "more" than before And the "application" stake of "app1" should be "420" uPOKT "less" than before + # TODO_IN_THIS_PR: Add the following test + # Scenario: Supplier overservices an application and gets paid for less work than claimed + # TODO_ADDTEST: Implement the following scenarios # Scenario: Emissions equals burn when a claim is created and a valid proof is submitted but not required # Scenario: No emissions or burn when a claim is created and an invalid proof is submitted diff --git a/pkg/relayer/session/sessiontree.go b/pkg/relayer/session/sessiontree.go index d54992c82..1a45883e1 100644 --- a/pkg/relayer/session/sessiontree.go +++ b/pkg/relayer/session/sessiontree.go @@ -70,6 +70,7 @@ type sessionTree struct { // removeFromRelayerSessions that removes the sessionTree from the RelayerSessionsManager. // It returns an error if the KVStore fails to be created. // TODO_BETA(@red-0ne): When starting a new session, check how many relays the app can handle. +// See the TODO next to the `sessionTree` struct definition for more details. func NewSessionTree( sessionHeader *sessiontypes.SessionHeader, supplierOperatorAddress *cosmostypes.AccAddress, diff --git a/x/tokenomics/keeper/token_logic_modules.go b/x/tokenomics/keeper/token_logic_modules.go index a05b1aee2..72c5bf2b7 100644 --- a/x/tokenomics/keeper/token_logic_modules.go +++ b/x/tokenomics/keeper/token_logic_modules.go @@ -26,12 +26,10 @@ import ( const ( // Governance parameters for the TLMGlobalMint module - // TODO_BETA_TEST(@olshansk): Remove this. It is an ephemeral placeholder before - // real values are introduced. When this is changed to a governance param, - // make sure to also add the necessary unit tests. + // TODO_UPNEXT(@olshansk, #732): Make this a governance parameter and give it a non-zero value + tests. MintPerClaimGlobalInflation = 0.0000000 - // TODO_BETA: Make all of the governance params + // TODO_BETA(@bryanchriswhite): Make all of the governance params MintAllocationDAO = 0.1 MintAllocationProposer = 0.05 MintAllocationSupplier = 0.7 @@ -97,7 +95,7 @@ type TokenLogicModuleProcessor func( var tokenLogicModuleProcessorMap = map[TokenLogicModule]TokenLogicModuleProcessor{ TLMRelayBurnEqualsMint: Keeper.TokenLogicModuleRelayBurnEqualsMint, TLMGlobalMint: Keeper.TokenLogicModuleGlobalMint, - // TODO_BETA_UPNEXT(@Olshansky): Uncomment this and add tests. + // TODO_UPNEXT(@olshansk, #732): Uncomment this, finish implementation, and add tests. // TLMGlobalMintReimbursementRequest: Keeper.TokenLogicModuleGlobalMintReimbursementRequest, } @@ -423,10 +421,10 @@ func (k Keeper) TokenLogicModuleGlobalMintReimbursementRequest( newMintCoins, _ := calculateGlobalPerClaimMintInflationFromSettlementAmount(settlementCoins) /* - TODO_UPNEXT_BETA(@Olshansky): Finish implementing this: + TODO_UPNEXT(@olshansk, #732): Finish implementing this: 1. Overcharge the application (reduce stake and burn app module tokens) 2. Send the overcharge to the DAO/PNF address - 3. Add extensive tests for this. + 3. Add necessary tests. */ // Prepare and emit the event for the application being overcharged diff --git a/x/tokenomics/keeper/token_logic_modules_test.go b/x/tokenomics/keeper/token_logic_modules_test.go index 50fecad21..e842abe59 100644 --- a/x/tokenomics/keeper/token_logic_modules_test.go +++ b/x/tokenomics/keeper/token_logic_modules_test.go @@ -33,8 +33,11 @@ func init() { cmd.InitSDKConfig() } -// TODO_IN_THIS_PR: Tests to add or list -// claimSettlementAmount > maxClaimableAmount +// TODO_IN_THIS_PR: Add these tests or update existing tests to account for it. +// func TestProcessTokenLogicModules_HandleMaxClaimGreaterActualClaim(t *testing.T) {...} +// TODO_UPNEXT(@olshansk, #732): Add the following tests +// func TestProcessTokenLogicModules_ValidateAppOverServicingEvent(t *testing.T) {...} +// func TestProcessTokenLogicModules_ValidateAppReimbursedRequestEvent(t *testing.T) {...} func TestProcessTokenLogicModules_HandleAppGoingIntoDebt(t *testing.T) { keepers, ctx := testkeeper.NewTokenomicsModuleKeepers(t, nil) diff --git a/x/tokenomics/keeper/update_relay_mining_difficulty.go b/x/tokenomics/keeper/update_relay_mining_difficulty.go index d563db86b..e93b1574d 100644 --- a/x/tokenomics/keeper/update_relay_mining_difficulty.go +++ b/x/tokenomics/keeper/update_relay_mining_difficulty.go @@ -183,6 +183,9 @@ func computeEma(alpha *big.Float, prevEma, currValue uint64) uint64 { return newEma } +// newDefaultRelayMiningDifficulty is a helper that creates a new RelayMiningDifficulty +// structure if one is not available. It is often used to set the default when a service's +// difficulty is being initialized for the first time. func newDefaultRelayMiningDifficulty( ctx context.Context, methodLogger log.Logger, @@ -192,8 +195,7 @@ func newDefaultRelayMiningDifficulty( logger := methodLogger.With("helper", "newDefaultRelayMiningDifficulty") logger.Warn(types.ErrTokenomicsMissingRelayMiningDifficulty.Wrapf( "No previous relay mining difficulty found for service %s. Creating a temporary relay mining difficulty with %d relays and default target hash %x", - serviceId, numRelays, - ).Error()) + serviceId, numRelays, prooftypes.DefaultRelayDifficultyTargetHash).Error()) return tokenomicstypes.RelayMiningDifficulty{ ServiceId: serviceId, From 0e725a44a0daba5368af781215926d50e233dc29 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Thu, 22 Aug 2024 16:53:10 -0400 Subject: [PATCH 06/53] Remove everything related to TLMGlobalMintReimbursementRequest --- api/poktroll/tokenomics/event.pulsar.go | 792 +-------------------- proto/poktroll/tokenomics/event.proto | 11 +- x/tokenomics/keeper/token_logic_modules.go | 47 -- x/tokenomics/types/event.pb.go | 432 ++--------- 4 files changed, 87 insertions(+), 1195 deletions(-) diff --git a/api/poktroll/tokenomics/event.pulsar.go b/api/poktroll/tokenomics/event.pulsar.go index afb700d4a..25caeaa82 100644 --- a/api/poktroll/tokenomics/event.pulsar.go +++ b/api/poktroll/tokenomics/event.pulsar.go @@ -2459,633 +2459,6 @@ func (x *fastReflection_EventApplicationOverserviced) ProtoMethods() *protoiface } } -var ( - md_EventApplicationReimbursementRequest protoreflect.MessageDescriptor - fd_EventApplicationReimbursementRequest_application_addr protoreflect.FieldDescriptor - fd_EventApplicationReimbursementRequest_service_id protoreflect.FieldDescriptor - fd_EventApplicationReimbursementRequest_session_id protoreflect.FieldDescriptor - fd_EventApplicationReimbursementRequest_amount protoreflect.FieldDescriptor -) - -func init() { - file_poktroll_tokenomics_event_proto_init() - md_EventApplicationReimbursementRequest = File_poktroll_tokenomics_event_proto.Messages().ByName("EventApplicationReimbursementRequest") - fd_EventApplicationReimbursementRequest_application_addr = md_EventApplicationReimbursementRequest.Fields().ByName("application_addr") - fd_EventApplicationReimbursementRequest_service_id = md_EventApplicationReimbursementRequest.Fields().ByName("service_id") - fd_EventApplicationReimbursementRequest_session_id = md_EventApplicationReimbursementRequest.Fields().ByName("session_id") - fd_EventApplicationReimbursementRequest_amount = md_EventApplicationReimbursementRequest.Fields().ByName("amount") -} - -var _ protoreflect.Message = (*fastReflection_EventApplicationReimbursementRequest)(nil) - -type fastReflection_EventApplicationReimbursementRequest EventApplicationReimbursementRequest - -func (x *EventApplicationReimbursementRequest) ProtoReflect() protoreflect.Message { - return (*fastReflection_EventApplicationReimbursementRequest)(x) -} - -func (x *EventApplicationReimbursementRequest) slowProtoReflect() protoreflect.Message { - mi := &file_poktroll_tokenomics_event_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -var _fastReflection_EventApplicationReimbursementRequest_messageType fastReflection_EventApplicationReimbursementRequest_messageType -var _ protoreflect.MessageType = fastReflection_EventApplicationReimbursementRequest_messageType{} - -type fastReflection_EventApplicationReimbursementRequest_messageType struct{} - -func (x fastReflection_EventApplicationReimbursementRequest_messageType) Zero() protoreflect.Message { - return (*fastReflection_EventApplicationReimbursementRequest)(nil) -} -func (x fastReflection_EventApplicationReimbursementRequest_messageType) New() protoreflect.Message { - return new(fastReflection_EventApplicationReimbursementRequest) -} -func (x fastReflection_EventApplicationReimbursementRequest_messageType) Descriptor() protoreflect.MessageDescriptor { - return md_EventApplicationReimbursementRequest -} - -// Descriptor returns message descriptor, which contains only the protobuf -// type information for the message. -func (x *fastReflection_EventApplicationReimbursementRequest) Descriptor() protoreflect.MessageDescriptor { - return md_EventApplicationReimbursementRequest -} - -// Type returns the message type, which encapsulates both Go and protobuf -// type information. If the Go type information is not needed, -// it is recommended that the message descriptor be used instead. -func (x *fastReflection_EventApplicationReimbursementRequest) Type() protoreflect.MessageType { - return _fastReflection_EventApplicationReimbursementRequest_messageType -} - -// New returns a newly allocated and mutable empty message. -func (x *fastReflection_EventApplicationReimbursementRequest) New() protoreflect.Message { - return new(fastReflection_EventApplicationReimbursementRequest) -} - -// Interface unwraps the message reflection interface and -// returns the underlying ProtoMessage interface. -func (x *fastReflection_EventApplicationReimbursementRequest) Interface() protoreflect.ProtoMessage { - return (*EventApplicationReimbursementRequest)(x) -} - -// Range iterates over every populated field in an undefined order, -// calling f for each field descriptor and value encountered. -// Range returns immediately if f returns false. -// While iterating, mutating operations may only be performed -// on the current field descriptor. -func (x *fastReflection_EventApplicationReimbursementRequest) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { - if x.ApplicationAddr != "" { - value := protoreflect.ValueOfString(x.ApplicationAddr) - if !f(fd_EventApplicationReimbursementRequest_application_addr, value) { - return - } - } - if x.ServiceId != "" { - value := protoreflect.ValueOfString(x.ServiceId) - if !f(fd_EventApplicationReimbursementRequest_service_id, value) { - return - } - } - if x.SessionId != "" { - value := protoreflect.ValueOfString(x.SessionId) - if !f(fd_EventApplicationReimbursementRequest_session_id, value) { - return - } - } - if x.Amount != nil { - value := protoreflect.ValueOfMessage(x.Amount.ProtoReflect()) - if !f(fd_EventApplicationReimbursementRequest_amount, value) { - return - } - } -} - -// Has reports whether a field is populated. -// -// Some fields have the property of nullability where it is possible to -// distinguish between the default value of a field and whether the field -// was explicitly populated with the default value. Singular message fields, -// member fields of a oneof, and proto2 scalar fields are nullable. Such -// fields are populated only if explicitly set. -// -// In other cases (aside from the nullable cases above), -// a proto3 scalar field is populated if it contains a non-zero value, and -// a repeated field is populated if it is non-empty. -func (x *fastReflection_EventApplicationReimbursementRequest) Has(fd protoreflect.FieldDescriptor) bool { - switch fd.FullName() { - case "poktroll.tokenomics.EventApplicationReimbursementRequest.application_addr": - return x.ApplicationAddr != "" - case "poktroll.tokenomics.EventApplicationReimbursementRequest.service_id": - return x.ServiceId != "" - case "poktroll.tokenomics.EventApplicationReimbursementRequest.session_id": - return x.SessionId != "" - case "poktroll.tokenomics.EventApplicationReimbursementRequest.amount": - return x.Amount != nil - default: - if fd.IsExtension() { - panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.tokenomics.EventApplicationReimbursementRequest")) - } - panic(fmt.Errorf("message poktroll.tokenomics.EventApplicationReimbursementRequest does not contain field %s", fd.FullName())) - } -} - -// Clear clears the field such that a subsequent Has call reports false. -// -// Clearing an extension field clears both the extension type and value -// associated with the given field number. -// -// Clear is a mutating operation and unsafe for concurrent use. -func (x *fastReflection_EventApplicationReimbursementRequest) Clear(fd protoreflect.FieldDescriptor) { - switch fd.FullName() { - case "poktroll.tokenomics.EventApplicationReimbursementRequest.application_addr": - x.ApplicationAddr = "" - case "poktroll.tokenomics.EventApplicationReimbursementRequest.service_id": - x.ServiceId = "" - case "poktroll.tokenomics.EventApplicationReimbursementRequest.session_id": - x.SessionId = "" - case "poktroll.tokenomics.EventApplicationReimbursementRequest.amount": - x.Amount = nil - default: - if fd.IsExtension() { - panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.tokenomics.EventApplicationReimbursementRequest")) - } - panic(fmt.Errorf("message poktroll.tokenomics.EventApplicationReimbursementRequest does not contain field %s", fd.FullName())) - } -} - -// Get retrieves the value for a field. -// -// For unpopulated scalars, it returns the default value, where -// the default value of a bytes scalar is guaranteed to be a copy. -// For unpopulated composite types, it returns an empty, read-only view -// of the value; to obtain a mutable reference, use Mutable. -func (x *fastReflection_EventApplicationReimbursementRequest) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { - switch descriptor.FullName() { - case "poktroll.tokenomics.EventApplicationReimbursementRequest.application_addr": - value := x.ApplicationAddr - return protoreflect.ValueOfString(value) - case "poktroll.tokenomics.EventApplicationReimbursementRequest.service_id": - value := x.ServiceId - return protoreflect.ValueOfString(value) - case "poktroll.tokenomics.EventApplicationReimbursementRequest.session_id": - value := x.SessionId - return protoreflect.ValueOfString(value) - case "poktroll.tokenomics.EventApplicationReimbursementRequest.amount": - value := x.Amount - return protoreflect.ValueOfMessage(value.ProtoReflect()) - default: - if descriptor.IsExtension() { - panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.tokenomics.EventApplicationReimbursementRequest")) - } - panic(fmt.Errorf("message poktroll.tokenomics.EventApplicationReimbursementRequest does not contain field %s", descriptor.FullName())) - } -} - -// Set stores the value for a field. -// -// For a field belonging to a oneof, it implicitly clears any other field -// that may be currently set within the same oneof. -// For extension fields, it implicitly stores the provided ExtensionType. -// When setting a composite type, it is unspecified whether the stored value -// aliases the source's memory in any way. If the composite value is an -// empty, read-only value, then it panics. -// -// Set is a mutating operation and unsafe for concurrent use. -func (x *fastReflection_EventApplicationReimbursementRequest) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { - switch fd.FullName() { - case "poktroll.tokenomics.EventApplicationReimbursementRequest.application_addr": - x.ApplicationAddr = value.Interface().(string) - case "poktroll.tokenomics.EventApplicationReimbursementRequest.service_id": - x.ServiceId = value.Interface().(string) - case "poktroll.tokenomics.EventApplicationReimbursementRequest.session_id": - x.SessionId = value.Interface().(string) - case "poktroll.tokenomics.EventApplicationReimbursementRequest.amount": - x.Amount = value.Message().Interface().(*v1beta1.Coin) - default: - if fd.IsExtension() { - panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.tokenomics.EventApplicationReimbursementRequest")) - } - panic(fmt.Errorf("message poktroll.tokenomics.EventApplicationReimbursementRequest does not contain field %s", fd.FullName())) - } -} - -// Mutable returns a mutable reference to a composite type. -// -// If the field is unpopulated, it may allocate a composite value. -// For a field belonging to a oneof, it implicitly clears any other field -// that may be currently set within the same oneof. -// For extension fields, it implicitly stores the provided ExtensionType -// if not already stored. -// It panics if the field does not contain a composite type. -// -// Mutable is a mutating operation and unsafe for concurrent use. -func (x *fastReflection_EventApplicationReimbursementRequest) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { - switch fd.FullName() { - case "poktroll.tokenomics.EventApplicationReimbursementRequest.amount": - if x.Amount == nil { - x.Amount = new(v1beta1.Coin) - } - return protoreflect.ValueOfMessage(x.Amount.ProtoReflect()) - case "poktroll.tokenomics.EventApplicationReimbursementRequest.application_addr": - panic(fmt.Errorf("field application_addr of message poktroll.tokenomics.EventApplicationReimbursementRequest is not mutable")) - case "poktroll.tokenomics.EventApplicationReimbursementRequest.service_id": - panic(fmt.Errorf("field service_id of message poktroll.tokenomics.EventApplicationReimbursementRequest is not mutable")) - case "poktroll.tokenomics.EventApplicationReimbursementRequest.session_id": - panic(fmt.Errorf("field session_id of message poktroll.tokenomics.EventApplicationReimbursementRequest is not mutable")) - default: - if fd.IsExtension() { - panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.tokenomics.EventApplicationReimbursementRequest")) - } - panic(fmt.Errorf("message poktroll.tokenomics.EventApplicationReimbursementRequest does not contain field %s", fd.FullName())) - } -} - -// NewField returns a new value that is assignable to the field -// for the given descriptor. For scalars, this returns the default value. -// For lists, maps, and messages, this returns a new, empty, mutable value. -func (x *fastReflection_EventApplicationReimbursementRequest) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { - switch fd.FullName() { - case "poktroll.tokenomics.EventApplicationReimbursementRequest.application_addr": - return protoreflect.ValueOfString("") - case "poktroll.tokenomics.EventApplicationReimbursementRequest.service_id": - return protoreflect.ValueOfString("") - case "poktroll.tokenomics.EventApplicationReimbursementRequest.session_id": - return protoreflect.ValueOfString("") - case "poktroll.tokenomics.EventApplicationReimbursementRequest.amount": - m := new(v1beta1.Coin) - return protoreflect.ValueOfMessage(m.ProtoReflect()) - default: - if fd.IsExtension() { - panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.tokenomics.EventApplicationReimbursementRequest")) - } - panic(fmt.Errorf("message poktroll.tokenomics.EventApplicationReimbursementRequest does not contain field %s", fd.FullName())) - } -} - -// WhichOneof reports which field within the oneof is populated, -// returning nil if none are populated. -// It panics if the oneof descriptor does not belong to this message. -func (x *fastReflection_EventApplicationReimbursementRequest) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { - switch d.FullName() { - default: - panic(fmt.Errorf("%s is not a oneof field in poktroll.tokenomics.EventApplicationReimbursementRequest", d.FullName())) - } - panic("unreachable") -} - -// GetUnknown retrieves the entire list of unknown fields. -// The caller may only mutate the contents of the RawFields -// if the mutated bytes are stored back into the message with SetUnknown. -func (x *fastReflection_EventApplicationReimbursementRequest) GetUnknown() protoreflect.RawFields { - return x.unknownFields -} - -// SetUnknown stores an entire list of unknown fields. -// The raw fields must be syntactically valid according to the wire format. -// An implementation may panic if this is not the case. -// Once stored, the caller must not mutate the content of the RawFields. -// An empty RawFields may be passed to clear the fields. -// -// SetUnknown is a mutating operation and unsafe for concurrent use. -func (x *fastReflection_EventApplicationReimbursementRequest) SetUnknown(fields protoreflect.RawFields) { - x.unknownFields = fields -} - -// IsValid reports whether the message is valid. -// -// An invalid message is an empty, read-only value. -// -// An invalid message often corresponds to a nil pointer of the concrete -// message type, but the details are implementation dependent. -// Validity is not part of the protobuf data model, and may not -// be preserved in marshaling or other operations. -func (x *fastReflection_EventApplicationReimbursementRequest) IsValid() bool { - return x != nil -} - -// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. -// This method may return nil. -// -// The returned methods type is identical to -// "google.golang.org/protobuf/runtime/protoiface".Methods. -// Consult the protoiface package documentation for details. -func (x *fastReflection_EventApplicationReimbursementRequest) ProtoMethods() *protoiface.Methods { - size := func(input protoiface.SizeInput) protoiface.SizeOutput { - x := input.Message.Interface().(*EventApplicationReimbursementRequest) - if x == nil { - return protoiface.SizeOutput{ - NoUnkeyedLiterals: input.NoUnkeyedLiterals, - Size: 0, - } - } - options := runtime.SizeInputToOptions(input) - _ = options - var n int - var l int - _ = l - l = len(x.ApplicationAddr) - if l > 0 { - n += 1 + l + runtime.Sov(uint64(l)) - } - l = len(x.ServiceId) - if l > 0 { - n += 1 + l + runtime.Sov(uint64(l)) - } - l = len(x.SessionId) - if l > 0 { - n += 1 + l + runtime.Sov(uint64(l)) - } - if x.Amount != nil { - l = options.Size(x.Amount) - n += 1 + l + runtime.Sov(uint64(l)) - } - if x.unknownFields != nil { - n += len(x.unknownFields) - } - return protoiface.SizeOutput{ - NoUnkeyedLiterals: input.NoUnkeyedLiterals, - Size: n, - } - } - - marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { - x := input.Message.Interface().(*EventApplicationReimbursementRequest) - if x == nil { - return protoiface.MarshalOutput{ - NoUnkeyedLiterals: input.NoUnkeyedLiterals, - Buf: input.Buf, - }, nil - } - options := runtime.MarshalInputToOptions(input) - _ = options - size := options.Size(x) - dAtA := make([]byte, size) - i := len(dAtA) - _ = i - var l int - _ = l - if x.unknownFields != nil { - i -= len(x.unknownFields) - copy(dAtA[i:], x.unknownFields) - } - if x.Amount != nil { - encoded, err := options.Marshal(x.Amount) - if err != nil { - return protoiface.MarshalOutput{ - NoUnkeyedLiterals: input.NoUnkeyedLiterals, - Buf: input.Buf, - }, err - } - i -= len(encoded) - copy(dAtA[i:], encoded) - i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) - i-- - dAtA[i] = 0x22 - } - if len(x.SessionId) > 0 { - i -= len(x.SessionId) - copy(dAtA[i:], x.SessionId) - i = runtime.EncodeVarint(dAtA, i, uint64(len(x.SessionId))) - i-- - dAtA[i] = 0x1a - } - if len(x.ServiceId) > 0 { - i -= len(x.ServiceId) - copy(dAtA[i:], x.ServiceId) - i = runtime.EncodeVarint(dAtA, i, uint64(len(x.ServiceId))) - i-- - dAtA[i] = 0x12 - } - if len(x.ApplicationAddr) > 0 { - i -= len(x.ApplicationAddr) - copy(dAtA[i:], x.ApplicationAddr) - i = runtime.EncodeVarint(dAtA, i, uint64(len(x.ApplicationAddr))) - i-- - dAtA[i] = 0xa - } - if input.Buf != nil { - input.Buf = append(input.Buf, dAtA...) - } else { - input.Buf = dAtA - } - return protoiface.MarshalOutput{ - NoUnkeyedLiterals: input.NoUnkeyedLiterals, - Buf: input.Buf, - }, nil - } - unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { - x := input.Message.Interface().(*EventApplicationReimbursementRequest) - if x == nil { - return protoiface.UnmarshalOutput{ - NoUnkeyedLiterals: input.NoUnkeyedLiterals, - Flags: input.Flags, - }, nil - } - options := runtime.UnmarshalInputToOptions(input) - _ = options - dAtA := input.Buf - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - 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++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: EventApplicationReimbursementRequest: wiretype end group for non-group") - } - if fieldNum <= 0 { - return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: EventApplicationReimbursementRequest: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field ApplicationAddr", wireType) - } - var stringLen uint64 - 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++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength - } - if postIndex > l { - return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF - } - x.ApplicationAddr = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field ServiceId", wireType) - } - var stringLen uint64 - 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++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength - } - if postIndex > l { - return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF - } - x.ServiceId = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 2 { - return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field SessionId", wireType) - } - var stringLen uint64 - 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++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength - } - if postIndex > l { - return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF - } - x.SessionId = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 4: - if wireType != 2 { - return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) - } - var msglen int - 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++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength - } - if postIndex > l { - return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF - } - if x.Amount == nil { - x.Amount = &v1beta1.Coin{} - } - if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.Amount); err != nil { - return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := runtime.Skip(dAtA[iNdEx:]) - if err != nil { - return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength - } - if (iNdEx + skippy) > l { - return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF - } - if !options.DiscardUnknown { - x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) - } - iNdEx += skippy - } - } - - if iNdEx > l { - return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF - } - return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil - } - return &protoiface.Methods{ - NoUnkeyedLiterals: struct{}{}, - Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, - Size: size, - Marshal: marshal, - Unmarshal: unmarshal, - Merge: nil, - CheckInitialized: nil, - } -} - // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.27.0 @@ -3409,67 +2782,6 @@ func (x *EventApplicationOverserviced) GetEffectiveBurn() *v1beta1.Coin { return nil } -// EventApplicationReimbursementRequest is emitted when an application requests -// a reimbursement -type EventApplicationReimbursementRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - ApplicationAddr string `protobuf:"bytes,1,opt,name=application_addr,json=applicationAddr,proto3" json:"application_addr,omitempty"` - ServiceId string `protobuf:"bytes,2,opt,name=service_id,json=serviceId,proto3" json:"service_id,omitempty"` - SessionId string `protobuf:"bytes,3,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"` - Amount *v1beta1.Coin `protobuf:"bytes,4,opt,name=amount,proto3" json:"amount,omitempty"` -} - -func (x *EventApplicationReimbursementRequest) Reset() { - *x = EventApplicationReimbursementRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_poktroll_tokenomics_event_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *EventApplicationReimbursementRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*EventApplicationReimbursementRequest) ProtoMessage() {} - -// Deprecated: Use EventApplicationReimbursementRequest.ProtoReflect.Descriptor instead. -func (*EventApplicationReimbursementRequest) Descriptor() ([]byte, []int) { - return file_poktroll_tokenomics_event_proto_rawDescGZIP(), []int{4} -} - -func (x *EventApplicationReimbursementRequest) GetApplicationAddr() string { - if x != nil { - return x.ApplicationAddr - } - return "" -} - -func (x *EventApplicationReimbursementRequest) GetServiceId() string { - if x != nil { - return x.ServiceId - } - return "" -} - -func (x *EventApplicationReimbursementRequest) GetSessionId() string { - if x != nil { - return x.SessionId - } - return "" -} - -func (x *EventApplicationReimbursementRequest) GetAmount() *v1beta1.Coin { - if x != nil { - return x.Amount - } - return nil -} - var File_poktroll_tokenomics_event_proto protoreflect.FileDescriptor var file_poktroll_tokenomics_event_proto_rawDesc = []byte{ @@ -3552,37 +2864,25 @@ var file_poktroll_tokenomics_event_proto_rawDesc = []byte{ 0x65, 0x5f, 0x62, 0x75, 0x72, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x0d, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, - 0x76, 0x65, 0x42, 0x75, 0x72, 0x6e, 0x22, 0xc2, 0x01, 0x0a, 0x24, 0x45, 0x76, 0x65, 0x6e, 0x74, - 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x69, 0x6d, 0x62, - 0x75, 0x72, 0x73, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x29, 0x0a, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x61, - 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x61, 0x70, 0x70, 0x6c, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, - 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x31, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, - 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, - 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, - 0x6f, 0x69, 0x6e, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x2a, 0x60, 0x0a, 0x15, 0x43, - 0x6c, 0x61, 0x69, 0x6d, 0x45, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x1d, 0x45, 0x58, 0x50, 0x49, 0x52, 0x41, 0x54, 0x49, - 0x4f, 0x4e, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, - 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x52, 0x4f, 0x4f, 0x46, - 0x5f, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x52, - 0x4f, 0x4f, 0x46, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x02, 0x42, 0xb8, 0x01, - 0x0a, 0x17, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x74, - 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0x42, 0x0a, 0x45, 0x76, 0x65, 0x6e, 0x74, - 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x24, 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, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0xa2, 0x02, 0x03, - 0x50, 0x54, 0x58, 0xaa, 0x02, 0x13, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x54, - 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0xca, 0x02, 0x13, 0x50, 0x6f, 0x6b, 0x74, - 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0xe2, - 0x02, 0x1f, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x54, 0x6f, 0x6b, 0x65, 0x6e, - 0x6f, 0x6d, 0x69, 0x63, 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0xea, 0x02, 0x14, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x3a, 0x3a, 0x54, 0x6f, - 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x76, 0x65, 0x42, 0x75, 0x72, 0x6e, 0x2a, 0x60, 0x0a, 0x15, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x45, + 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, + 0x21, 0x0a, 0x1d, 0x45, 0x58, 0x50, 0x49, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x52, 0x45, + 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, + 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x52, 0x4f, 0x4f, 0x46, 0x5f, 0x4d, 0x49, 0x53, 0x53, + 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x52, 0x4f, 0x4f, 0x46, 0x5f, 0x49, + 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x02, 0x42, 0xb8, 0x01, 0x0a, 0x17, 0x63, 0x6f, 0x6d, + 0x2e, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, + 0x6d, 0x69, 0x63, 0x73, 0x42, 0x0a, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, + 0x50, 0x01, 0x5a, 0x24, 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, 0x74, 0x6f, + 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0xa2, 0x02, 0x03, 0x50, 0x54, 0x58, 0xaa, 0x02, + 0x13, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, + 0x6d, 0x69, 0x63, 0x73, 0xca, 0x02, 0x13, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, + 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0xe2, 0x02, 0x1f, 0x50, 0x6f, 0x6b, + 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, + 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x14, 0x50, + 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x3a, 0x3a, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, + 0x69, 0x63, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -3598,31 +2898,29 @@ func file_poktroll_tokenomics_event_proto_rawDescGZIP() []byte { } var file_poktroll_tokenomics_event_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_poktroll_tokenomics_event_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_poktroll_tokenomics_event_proto_msgTypes = make([]protoimpl.MessageInfo, 4) var file_poktroll_tokenomics_event_proto_goTypes = []interface{}{ - (ClaimExpirationReason)(0), // 0: poktroll.tokenomics.ClaimExpirationReason - (*EventClaimExpired)(nil), // 1: poktroll.tokenomics.EventClaimExpired - (*EventClaimSettled)(nil), // 2: poktroll.tokenomics.EventClaimSettled - (*EventRelayMiningDifficultyUpdated)(nil), // 3: poktroll.tokenomics.EventRelayMiningDifficultyUpdated - (*EventApplicationOverserviced)(nil), // 4: poktroll.tokenomics.EventApplicationOverserviced - (*EventApplicationReimbursementRequest)(nil), // 5: poktroll.tokenomics.EventApplicationReimbursementRequest - (*proof.Claim)(nil), // 6: poktroll.proof.Claim - (proof.ProofRequirementReason)(0), // 7: poktroll.proof.ProofRequirementReason - (*v1beta1.Coin)(nil), // 8: cosmos.base.v1beta1.Coin + (ClaimExpirationReason)(0), // 0: poktroll.tokenomics.ClaimExpirationReason + (*EventClaimExpired)(nil), // 1: poktroll.tokenomics.EventClaimExpired + (*EventClaimSettled)(nil), // 2: poktroll.tokenomics.EventClaimSettled + (*EventRelayMiningDifficultyUpdated)(nil), // 3: poktroll.tokenomics.EventRelayMiningDifficultyUpdated + (*EventApplicationOverserviced)(nil), // 4: poktroll.tokenomics.EventApplicationOverserviced + (*proof.Claim)(nil), // 5: poktroll.proof.Claim + (proof.ProofRequirementReason)(0), // 6: poktroll.proof.ProofRequirementReason + (*v1beta1.Coin)(nil), // 7: cosmos.base.v1beta1.Coin } var file_poktroll_tokenomics_event_proto_depIdxs = []int32{ - 6, // 0: poktroll.tokenomics.EventClaimExpired.claim:type_name -> poktroll.proof.Claim + 5, // 0: poktroll.tokenomics.EventClaimExpired.claim:type_name -> poktroll.proof.Claim 0, // 1: poktroll.tokenomics.EventClaimExpired.expiration_reason:type_name -> poktroll.tokenomics.ClaimExpirationReason - 6, // 2: poktroll.tokenomics.EventClaimSettled.claim:type_name -> poktroll.proof.Claim - 7, // 3: poktroll.tokenomics.EventClaimSettled.proof_requirement:type_name -> poktroll.proof.ProofRequirementReason - 8, // 4: poktroll.tokenomics.EventApplicationOverserviced.expected_burn:type_name -> cosmos.base.v1beta1.Coin - 8, // 5: poktroll.tokenomics.EventApplicationOverserviced.effective_burn:type_name -> cosmos.base.v1beta1.Coin - 8, // 6: poktroll.tokenomics.EventApplicationReimbursementRequest.amount:type_name -> cosmos.base.v1beta1.Coin - 7, // [7:7] is the sub-list for method output_type - 7, // [7:7] is the sub-list for method input_type - 7, // [7:7] is the sub-list for extension type_name - 7, // [7:7] is the sub-list for extension extendee - 0, // [0:7] is the sub-list for field type_name + 5, // 2: poktroll.tokenomics.EventClaimSettled.claim:type_name -> poktroll.proof.Claim + 6, // 3: poktroll.tokenomics.EventClaimSettled.proof_requirement:type_name -> poktroll.proof.ProofRequirementReason + 7, // 4: poktroll.tokenomics.EventApplicationOverserviced.expected_burn:type_name -> cosmos.base.v1beta1.Coin + 7, // 5: poktroll.tokenomics.EventApplicationOverserviced.effective_burn:type_name -> cosmos.base.v1beta1.Coin + 6, // [6:6] is the sub-list for method output_type + 6, // [6:6] is the sub-list for method input_type + 6, // [6:6] is the sub-list for extension type_name + 6, // [6:6] is the sub-list for extension extendee + 0, // [0:6] is the sub-list for field type_name } func init() { file_poktroll_tokenomics_event_proto_init() } @@ -3679,18 +2977,6 @@ func file_poktroll_tokenomics_event_proto_init() { return nil } } - file_poktroll_tokenomics_event_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*EventApplicationReimbursementRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } } type x struct{} out := protoimpl.TypeBuilder{ @@ -3698,7 +2984,7 @@ func file_poktroll_tokenomics_event_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_poktroll_tokenomics_event_proto_rawDesc, NumEnums: 1, - NumMessages: 5, + NumMessages: 4, NumExtensions: 0, NumServices: 0, }, diff --git a/proto/poktroll/tokenomics/event.proto b/proto/poktroll/tokenomics/event.proto index f5af15a76..9b07d8ae1 100644 --- a/proto/poktroll/tokenomics/event.proto +++ b/proto/poktroll/tokenomics/event.proto @@ -57,13 +57,4 @@ message EventApplicationOverserviced { // most likely equal to the application's stake divided by the number of suppliers // in a session. cosmos.base.v1beta1.Coin effective_burn = 4; -} - -// EventApplicationReimbursementRequest is emitted when an application requests -// a reimbursement -message EventApplicationReimbursementRequest { - string application_addr = 1; - string service_id = 2; - string session_id = 3; - cosmos.base.v1beta1.Coin amount = 4; -} +} \ No newline at end of file diff --git a/x/tokenomics/keeper/token_logic_modules.go b/x/tokenomics/keeper/token_logic_modules.go index 72c5bf2b7..3db0c9b41 100644 --- a/x/tokenomics/keeper/token_logic_modules.go +++ b/x/tokenomics/keeper/token_logic_modules.go @@ -50,20 +50,11 @@ const ( // on global governance parameters in order to reward the participants providing // services while keeping inflation in check. TLMGlobalMint - - // TLMGlobalMintReimbursementRequest is the token logic module that complements - // TLMGlobalMint to enable permissionless demand. In order to prevent self-dealing - // attacks, applications will be overcharged by the amount equal to global inflation, - // those funds will be sent to the DAO/PNF, and an event will be emitted to track - // and send reimbursements; managed offchain by PNF. - // TODO_POST_MAINNET: Introduce proper tokenomics based on the research done by @rawthil and @shane. - TLMGlobalMintReimbursementRequest ) var tokenLogicModuleStrings = [...]string{ "TLMRelayBurnEqualsMint", "TLMGlobalMint", - "TLMGlobalMintReimbursementRequest", } func (tlm TokenLogicModule) String() string { @@ -95,8 +86,6 @@ type TokenLogicModuleProcessor func( var tokenLogicModuleProcessorMap = map[TokenLogicModule]TokenLogicModuleProcessor{ TLMRelayBurnEqualsMint: Keeper.TokenLogicModuleRelayBurnEqualsMint, TLMGlobalMint: Keeper.TokenLogicModuleGlobalMint, - // TODO_UPNEXT(@olshansk, #732): Uncomment this, finish implementation, and add tests. - // TLMGlobalMintReimbursementRequest: Keeper.TokenLogicModuleGlobalMintReimbursementRequest, } func init() { @@ -406,42 +395,6 @@ func (k Keeper) TokenLogicModuleGlobalMint( return nil } -// TokenLogicModuleGlobalMintReimbursementRequest processes the business logic for the GlobalMintReimbursementRequest TLM. -func (k Keeper) TokenLogicModuleGlobalMintReimbursementRequest( - ctx context.Context, - service *sharedtypes.Service, - sessionHeader *sessiontypes.SessionHeader, - application *apptypes.Application, - supplier *sharedtypes.Supplier, - settlementCoins cosmostypes.Coin, - relayMiningDifficulty *tokenomictypes.RelayMiningDifficulty, -) error { - - // Determine how much new uPOKT to mint based on global inflation - newMintCoins, _ := calculateGlobalPerClaimMintInflationFromSettlementAmount(settlementCoins) - - /* - TODO_UPNEXT(@olshansk, #732): Finish implementing this: - 1. Overcharge the application (reduce stake and burn app module tokens) - 2. Send the overcharge to the DAO/PNF address - 3. Add necessary tests. - */ - - // Prepare and emit the event for the application being overcharged - reimbursementRequestEvent := tokenomictypes.EventApplicationReimbursementRequest{ - ApplicationAddr: application.Address, - ServiceId: service.Id, - SessionId: sessionHeader.SessionId, - Amount: &newMintCoins[0], - } - eventManager := cosmostypes.UnwrapSDKContext(ctx).EventManager() - if err := eventManager.EmitTypedEvent(&reimbursementRequestEvent); err != nil { - return tokenomicstypes.ErrTokenomicsEmittingEventFailed.Wrapf("error emitting event %v", reimbursementRequestEvent) - } - - return nil -} - // sendRewardsToAccount sends (settlementAmtFloat * allocation) tokens from the // tokenomics module account to the specified address. func (k Keeper) sendRewardsToAccount( diff --git a/x/tokenomics/types/event.pb.go b/x/tokenomics/types/event.pb.go index 27a0d9614..648c6afbb 100644 --- a/x/tokenomics/types/event.pb.go +++ b/x/tokenomics/types/event.pb.go @@ -350,139 +350,64 @@ func (m *EventApplicationOverserviced) GetEffectiveBurn() *types1.Coin { return nil } -// EventApplicationReimbursementRequest is emitted when an application requests -// a reimbursement -type EventApplicationReimbursementRequest struct { - ApplicationAddr string `protobuf:"bytes,1,opt,name=application_addr,json=applicationAddr,proto3" json:"application_addr,omitempty"` - ServiceId string `protobuf:"bytes,2,opt,name=service_id,json=serviceId,proto3" json:"service_id,omitempty"` - SessionId string `protobuf:"bytes,3,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"` - Amount *types1.Coin `protobuf:"bytes,4,opt,name=amount,proto3" json:"amount,omitempty"` -} - -func (m *EventApplicationReimbursementRequest) Reset() { *m = EventApplicationReimbursementRequest{} } -func (m *EventApplicationReimbursementRequest) String() string { return proto.CompactTextString(m) } -func (*EventApplicationReimbursementRequest) ProtoMessage() {} -func (*EventApplicationReimbursementRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_a78874bbf91a58c7, []int{4} -} -func (m *EventApplicationReimbursementRequest) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *EventApplicationReimbursementRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_EventApplicationReimbursementRequest.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *EventApplicationReimbursementRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_EventApplicationReimbursementRequest.Merge(m, src) -} -func (m *EventApplicationReimbursementRequest) XXX_Size() int { - return m.Size() -} -func (m *EventApplicationReimbursementRequest) XXX_DiscardUnknown() { - xxx_messageInfo_EventApplicationReimbursementRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_EventApplicationReimbursementRequest proto.InternalMessageInfo - -func (m *EventApplicationReimbursementRequest) GetApplicationAddr() string { - if m != nil { - return m.ApplicationAddr - } - return "" -} - -func (m *EventApplicationReimbursementRequest) GetServiceId() string { - if m != nil { - return m.ServiceId - } - return "" -} - -func (m *EventApplicationReimbursementRequest) GetSessionId() string { - if m != nil { - return m.SessionId - } - return "" -} - -func (m *EventApplicationReimbursementRequest) GetAmount() *types1.Coin { - if m != nil { - return m.Amount - } - return nil -} - func init() { proto.RegisterEnum("poktroll.tokenomics.ClaimExpirationReason", ClaimExpirationReason_name, ClaimExpirationReason_value) proto.RegisterType((*EventClaimExpired)(nil), "poktroll.tokenomics.EventClaimExpired") proto.RegisterType((*EventClaimSettled)(nil), "poktroll.tokenomics.EventClaimSettled") proto.RegisterType((*EventRelayMiningDifficultyUpdated)(nil), "poktroll.tokenomics.EventRelayMiningDifficultyUpdated") proto.RegisterType((*EventApplicationOverserviced)(nil), "poktroll.tokenomics.EventApplicationOverserviced") - proto.RegisterType((*EventApplicationReimbursementRequest)(nil), "poktroll.tokenomics.EventApplicationReimbursementRequest") } func init() { proto.RegisterFile("poktroll/tokenomics/event.proto", fileDescriptor_a78874bbf91a58c7) } var fileDescriptor_a78874bbf91a58c7 = []byte{ - // 786 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x55, 0xcd, 0x6e, 0xeb, 0x44, - 0x14, 0x8e, 0x73, 0x73, 0xaf, 0x94, 0xb9, 0x37, 0x6d, 0x32, 0x97, 0x8a, 0x50, 0xee, 0x4d, 0x7a, - 0x03, 0x42, 0xa5, 0xa8, 0xb6, 0xda, 0x4a, 0xac, 0x50, 0x45, 0x92, 0xba, 0xd4, 0x12, 0x4d, 0x22, - 0xa7, 0x45, 0x88, 0x8d, 0x71, 0xec, 0x93, 0x64, 0x68, 0x3c, 0xe3, 0xce, 0x8c, 0x93, 0xf4, 0x2d, - 0x78, 0x00, 0x5e, 0x80, 0x05, 0x2f, 0xc1, 0x8a, 0x65, 0x97, 0xac, 0x2a, 0xd4, 0xee, 0xba, 0xe2, - 0x11, 0x90, 0xc7, 0xce, 0x4f, 0xd3, 0x02, 0x62, 0xc9, 0x26, 0x99, 0x7c, 0xe7, 0x3b, 0x7f, 0xdf, - 0x9c, 0x39, 0x41, 0xd5, 0x90, 0x5d, 0x48, 0xce, 0x46, 0x23, 0x43, 0xb2, 0x0b, 0xa0, 0x2c, 0x20, - 0x9e, 0x30, 0x60, 0x0c, 0x54, 0xea, 0x21, 0x67, 0x92, 0xe1, 0xd7, 0x33, 0x82, 0xbe, 0x20, 0x6c, - 0x56, 0x3c, 0x26, 0x02, 0x26, 0x8c, 0x9e, 0x2b, 0xc0, 0x18, 0xef, 0xf5, 0x40, 0xba, 0x7b, 0x86, - 0xc7, 0x08, 0x4d, 0x9c, 0x36, 0xdf, 0x1b, 0xb0, 0x01, 0x53, 0x47, 0x23, 0x3e, 0xa5, 0xe8, 0xe6, - 0x3c, 0x57, 0xc8, 0x19, 0xeb, 0x1b, 0xf2, 0x2a, 0x04, 0x91, 0xd8, 0x6a, 0xbf, 0x64, 0x51, 0xc9, - 0x8c, 0xd3, 0x36, 0x47, 0x2e, 0x09, 0xcc, 0x69, 0x48, 0x38, 0xf8, 0xf8, 0x73, 0xf4, 0xdc, 0x8b, - 0x7f, 0x97, 0xb5, 0x2d, 0x6d, 0xfb, 0xe5, 0xfe, 0x86, 0x3e, 0x2f, 0x46, 0x45, 0xd0, 0x15, 0xb9, - 0x91, 0xbf, 0xbf, 0xa9, 0x26, 0x3c, 0x3b, 0xf9, 0xc2, 0xbb, 0x08, 0xd1, 0x28, 0x70, 0x38, 0x8c, - 0xdc, 0x2b, 0x51, 0xce, 0x6e, 0x69, 0xdb, 0xb9, 0xc6, 0xda, 0xfd, 0x4d, 0x75, 0x09, 0xb5, 0xf3, - 0x34, 0x0a, 0x6c, 0x75, 0xc4, 0x75, 0x54, 0x8a, 0x0d, 0x1e, 0x0b, 0xc2, 0x48, 0x82, 0x13, 0x51, - 0x22, 0x45, 0xf9, 0x99, 0xf2, 0xda, 0xb8, 0xbf, 0xa9, 0x3e, 0x36, 0xda, 0xeb, 0x34, 0x0a, 0x9a, - 0x09, 0x72, 0x1e, 0x03, 0x98, 0xa2, 0x12, 0xc4, 0x45, 0xbb, 0x92, 0x30, 0xea, 0x70, 0x70, 0x05, - 0xa3, 0xe5, 0xdc, 0x96, 0xb6, 0xbd, 0xb6, 0xbf, 0xa3, 0x3f, 0x21, 0xa1, 0xbe, 0xe8, 0x53, 0xb9, - 0xd8, 0xca, 0x23, 0x49, 0xf7, 0x28, 0x90, 0x5d, 0x84, 0x15, 0x62, 0xed, 0xe7, 0x07, 0x7a, 0x75, - 0x41, 0xca, 0xd1, 0xff, 0x4a, 0xaf, 0x1f, 0x50, 0x49, 0x95, 0xe4, 0x70, 0xb8, 0x8c, 0x08, 0x87, - 0x00, 0xa8, 0x4c, 0xf5, 0xfa, 0x64, 0xb5, 0xea, 0x4e, 0xfc, 0x69, 0x2f, 0x78, 0xcb, 0x5a, 0x3d, - 0x0a, 0x62, 0x17, 0xc3, 0x15, 0x7a, 0xed, 0xa7, 0x2c, 0x7a, 0xa7, 0xb4, 0x52, 0xe5, 0x9f, 0x12, - 0x4a, 0xe8, 0xe0, 0x88, 0xf4, 0xfb, 0xc4, 0x8b, 0x46, 0xf2, 0xea, 0x3c, 0xf4, 0x5d, 0x09, 0x3e, - 0x7e, 0x8b, 0x90, 0x00, 0x3e, 0x26, 0x1e, 0x38, 0xc4, 0x57, 0x02, 0xe6, 0xed, 0x7c, 0x8a, 0x58, - 0x3e, 0x3e, 0x44, 0x6f, 0x42, 0x0e, 0x63, 0x47, 0xba, 0x7c, 0x00, 0xd2, 0x19, 0xba, 0x62, 0xe8, - 0x0c, 0x61, 0xea, 0x00, 0xf5, 0x98, 0x0f, 0xbe, 0x12, 0x2d, 0x6f, 0x97, 0x63, 0xce, 0x99, 0xa2, - 0x9c, 0xb8, 0x62, 0x78, 0x02, 0x53, 0x33, 0xb1, 0xe3, 0x2f, 0xd0, 0x87, 0x14, 0x26, 0x7f, 0xeb, - 0xfe, 0x4c, 0xb9, 0xbf, 0x4f, 0x61, 0xf2, 0xa4, 0xf7, 0x2e, 0x7a, 0xad, 0xb2, 0x2f, 0xee, 0xc3, - 0x81, 0xc0, 0x55, 0x82, 0xe5, 0xe2, 0x8e, 0x61, 0xdc, 0x9a, 0xdd, 0x8e, 0x19, 0xb8, 0xf8, 0x33, - 0x84, 0xe3, 0x64, 0x2b, 0xec, 0xe7, 0x8a, 0xbd, 0x4e, 0x61, 0xb2, 0x4c, 0xae, 0xfd, 0xa9, 0xa1, - 0x37, 0x4a, 0x9e, 0x7a, 0x18, 0x8e, 0x88, 0xa7, 0xa6, 0xac, 0x3d, 0x06, 0x9e, 0xf6, 0xee, 0xe3, - 0x4f, 0x51, 0xd1, 0x5d, 0x98, 0x1c, 0xd7, 0xf7, 0x79, 0xaa, 0xcf, 0xfa, 0x12, 0x5e, 0xf7, 0x7d, - 0x8e, 0x3f, 0x42, 0x05, 0x11, 0xc5, 0x18, 0xf0, 0x84, 0x97, 0xc8, 0xf2, 0x6a, 0x06, 0x2a, 0xd2, - 0x21, 0x2a, 0xc0, 0x34, 0x04, 0x4f, 0x82, 0xef, 0xf4, 0x22, 0x4e, 0x55, 0xf3, 0x2f, 0xf7, 0x3f, - 0xd0, 0x93, 0xad, 0xa2, 0xc7, 0x5b, 0x45, 0x4f, 0xb7, 0x8a, 0xde, 0x64, 0x84, 0xda, 0xaf, 0x66, - 0xfc, 0x46, 0xc4, 0x29, 0xfe, 0x12, 0xad, 0x41, 0xbf, 0x0f, 0x9e, 0x24, 0x63, 0x48, 0x02, 0xe4, - 0xfe, 0x2d, 0x40, 0x61, 0xee, 0x10, 0x47, 0xa8, 0xfd, 0xaa, 0xa1, 0x8f, 0x57, 0x5b, 0xb6, 0x81, - 0x04, 0xbd, 0x88, 0x8b, 0x74, 0xc4, 0x2e, 0x23, 0x10, 0xf2, 0xbf, 0xb4, 0xfe, 0x70, 0x7e, 0xb2, - 0xab, 0xf3, 0xa3, 0xcc, 0x42, 0xc4, 0x51, 0xc8, 0xec, 0xba, 0xf3, 0x29, 0x62, 0xf9, 0x78, 0x0f, - 0xbd, 0x70, 0x03, 0x16, 0xa5, 0x8f, 0xe0, 0x1f, 0x7b, 0x49, 0x89, 0x3b, 0xdf, 0xa3, 0x8d, 0x27, - 0x97, 0x08, 0x7e, 0x87, 0xde, 0x9a, 0xdf, 0x76, 0x2c, 0xbb, 0x7e, 0x66, 0xb5, 0x5b, 0x8e, 0x6d, - 0xd6, 0xbb, 0xed, 0x96, 0x73, 0xde, 0xea, 0x76, 0xcc, 0xa6, 0x75, 0x6c, 0x99, 0x47, 0xc5, 0x0c, - 0x2e, 0xa1, 0x42, 0xc7, 0x6e, 0xb7, 0x8f, 0x9d, 0x53, 0xab, 0xdb, 0xb5, 0x5a, 0x5f, 0x15, 0xb5, - 0x05, 0x64, 0xb5, 0xbe, 0xa9, 0x7f, 0x6d, 0x1d, 0x15, 0xb3, 0x8d, 0xd3, 0xdf, 0x6e, 0x2b, 0xda, - 0xf5, 0x6d, 0x45, 0xfb, 0xe3, 0xb6, 0xa2, 0xfd, 0x78, 0x57, 0xc9, 0x5c, 0xdf, 0x55, 0x32, 0xbf, - 0xdf, 0x55, 0x32, 0xdf, 0x1d, 0x0c, 0x88, 0x1c, 0x46, 0x3d, 0xdd, 0x63, 0x81, 0x11, 0xbf, 0xd6, - 0x5d, 0x0a, 0x72, 0xc2, 0xf8, 0x85, 0x31, 0x5f, 0xf1, 0xd3, 0xe5, 0x3f, 0x14, 0xb5, 0xe9, 0x7b, - 0x2f, 0xd4, 0xaa, 0x3f, 0xf8, 0x2b, 0x00, 0x00, 0xff, 0xff, 0xed, 0x40, 0xd7, 0x5c, 0x74, 0x06, - 0x00, 0x00, + // 730 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x54, 0x4d, 0x4f, 0xdb, 0x48, + 0x18, 0x8e, 0x43, 0x58, 0x29, 0x03, 0x81, 0xc4, 0x2c, 0xda, 0x2c, 0x0b, 0x09, 0x64, 0xa5, 0x15, + 0xcb, 0x0a, 0x5b, 0x80, 0xb4, 0xa7, 0x15, 0xda, 0x24, 0x98, 0xc5, 0xd2, 0x92, 0x44, 0x0e, 0x54, + 0x55, 0x2f, 0x53, 0xc7, 0x7e, 0x93, 0x4c, 0x89, 0x67, 0xdc, 0xf1, 0x38, 0x09, 0xff, 0xa2, 0x3f, + 0xa0, 0x7f, 0xa0, 0x87, 0xfe, 0x8f, 0x1e, 0x39, 0xf6, 0x84, 0x2a, 0xb8, 0x71, 0xea, 0x4f, 0xa8, + 0x3c, 0xce, 0x57, 0x03, 0x55, 0xcf, 0xbd, 0x24, 0x93, 0xe7, 0x7d, 0x9e, 0xf7, 0xe3, 0x99, 0xc9, + 0x8b, 0x8a, 0x3e, 0xbb, 0x12, 0x9c, 0xf5, 0x7a, 0xba, 0x60, 0x57, 0x40, 0x99, 0x47, 0x9c, 0x40, + 0x87, 0x3e, 0x50, 0xa1, 0xf9, 0x9c, 0x09, 0xa6, 0xae, 0x8d, 0x09, 0xda, 0x94, 0xb0, 0x51, 0x70, + 0x58, 0xe0, 0xb1, 0x40, 0x6f, 0xd9, 0x01, 0xe8, 0xfd, 0x83, 0x16, 0x08, 0xfb, 0x40, 0x77, 0x18, + 0xa1, 0xb1, 0x68, 0xe3, 0xe7, 0x0e, 0xeb, 0x30, 0x79, 0xd4, 0xa3, 0xd3, 0x08, 0xdd, 0x98, 0xd4, + 0xf2, 0x39, 0x63, 0x6d, 0x5d, 0x5c, 0xfb, 0x10, 0xc4, 0xb1, 0xd2, 0xfb, 0x24, 0xca, 0x19, 0x51, + 0xd9, 0x6a, 0xcf, 0x26, 0x9e, 0x31, 0xf4, 0x09, 0x07, 0x57, 0xfd, 0x1b, 0x2d, 0x3a, 0xd1, 0xef, + 0xbc, 0xb2, 0xad, 0xec, 0x2e, 0x1d, 0xae, 0x6b, 0x93, 0x66, 0x64, 0x06, 0x4d, 0x92, 0x2b, 0xe9, + 0x87, 0xdb, 0x62, 0xcc, 0xb3, 0xe2, 0x2f, 0x75, 0x1f, 0x21, 0x1a, 0x7a, 0x98, 0x43, 0xcf, 0xbe, + 0x0e, 0xf2, 0xc9, 0x6d, 0x65, 0x37, 0x55, 0x59, 0x79, 0xb8, 0x2d, 0xce, 0xa0, 0x56, 0x9a, 0x86, + 0x9e, 0x25, 0x8f, 0x6a, 0x19, 0xe5, 0xa2, 0x80, 0xc3, 0x3c, 0x3f, 0x14, 0x80, 0x43, 0x4a, 0x44, + 0x90, 0x5f, 0x90, 0xaa, 0xf5, 0x87, 0xdb, 0xe2, 0xe3, 0xa0, 0xb5, 0x4a, 0x43, 0xaf, 0x1a, 0x23, + 0x97, 0x11, 0xa0, 0x52, 0x94, 0x83, 0xa8, 0x69, 0x5b, 0x10, 0x46, 0x31, 0x07, 0x3b, 0x60, 0x34, + 0x9f, 0xda, 0x56, 0x76, 0x57, 0x0e, 0xf7, 0xb4, 0x27, 0x2c, 0xd4, 0xa6, 0x73, 0x4a, 0x89, 0x25, + 0x15, 0x71, 0xb9, 0x47, 0x89, 0xac, 0x2c, 0xcc, 0x11, 0x4b, 0xef, 0xbe, 0xf2, 0xab, 0x09, 0x42, + 0xf4, 0x7e, 0x28, 0xbf, 0x5e, 0xa1, 0x9c, 0x6c, 0x09, 0x73, 0x78, 0x1d, 0x12, 0x0e, 0x1e, 0x50, + 0x31, 0xf2, 0xeb, 0x8f, 0xf9, 0xae, 0x1b, 0xd1, 0xa7, 0x35, 0xe5, 0xcd, 0x7a, 0xf5, 0x28, 0x89, + 0x95, 0xf5, 0xe7, 0xe8, 0xa5, 0xb7, 0x49, 0xb4, 0x23, 0xbd, 0x92, 0xed, 0x9f, 0x13, 0x4a, 0x68, + 0xe7, 0x84, 0xb4, 0xdb, 0xc4, 0x09, 0x7b, 0xe2, 0xfa, 0xd2, 0x77, 0x6d, 0x01, 0xae, 0xba, 0x85, + 0x50, 0x00, 0xbc, 0x4f, 0x1c, 0xc0, 0xc4, 0x95, 0x06, 0xa6, 0xad, 0xf4, 0x08, 0x31, 0x5d, 0xf5, + 0x18, 0x6d, 0xfa, 0x1c, 0xfa, 0x58, 0xd8, 0xbc, 0x03, 0x02, 0x77, 0xed, 0xa0, 0x8b, 0xbb, 0x30, + 0xc4, 0x40, 0x1d, 0xe6, 0x82, 0x2b, 0x4d, 0x4b, 0x5b, 0xf9, 0x88, 0x73, 0x21, 0x29, 0x67, 0x76, + 0xd0, 0x3d, 0x83, 0xa1, 0x11, 0xc7, 0xd5, 0x7f, 0xd0, 0x6f, 0x14, 0x06, 0xdf, 0x94, 0x2f, 0x48, + 0xf9, 0x2f, 0x14, 0x06, 0x4f, 0xaa, 0xf7, 0xd1, 0x9a, 0xac, 0x3e, 0xbd, 0x0f, 0x0c, 0x9e, 0x2d, + 0x0d, 0x4b, 0x45, 0x13, 0x43, 0xbf, 0x36, 0xbe, 0x1d, 0xc3, 0xb3, 0xd5, 0xbf, 0x90, 0x1a, 0x15, + 0x9b, 0x63, 0x2f, 0x4a, 0xf6, 0x2a, 0x85, 0xc1, 0x2c, 0xb9, 0xf4, 0x59, 0x41, 0x9b, 0xd2, 0x9e, + 0xb2, 0xef, 0xf7, 0x88, 0x23, 0x5f, 0x59, 0xbd, 0x0f, 0x7c, 0x34, 0xbb, 0xab, 0xfe, 0x89, 0xb2, + 0xf6, 0x34, 0x84, 0x6d, 0xd7, 0xe5, 0x23, 0x7f, 0x56, 0x67, 0xf0, 0xb2, 0xeb, 0x72, 0xf5, 0x77, + 0x94, 0x09, 0xc2, 0x08, 0x03, 0x1e, 0xf3, 0x62, 0x5b, 0x96, 0xc7, 0xa0, 0x24, 0x1d, 0xa3, 0x0c, + 0x0c, 0x7d, 0x70, 0x04, 0xb8, 0xb8, 0x15, 0x72, 0x2a, 0x87, 0x5f, 0x3a, 0xfc, 0x55, 0x8b, 0xb7, + 0x8a, 0x16, 0x6d, 0x15, 0x6d, 0xb4, 0x55, 0xb4, 0x2a, 0x23, 0xd4, 0x5a, 0x1e, 0xf3, 0x2b, 0x21, + 0xa7, 0xea, 0xbf, 0x68, 0x05, 0xda, 0x6d, 0x70, 0x04, 0xe9, 0x43, 0x9c, 0x20, 0xf5, 0xbd, 0x04, + 0x99, 0x89, 0x20, 0xca, 0xb0, 0xf7, 0x12, 0xad, 0x3f, 0xf9, 0xff, 0x53, 0x77, 0xd0, 0x96, 0xf1, + 0xbc, 0x61, 0x5a, 0xe5, 0x0b, 0xb3, 0x5e, 0xc3, 0x96, 0x51, 0x6e, 0xd6, 0x6b, 0xf8, 0xb2, 0xd6, + 0x6c, 0x18, 0x55, 0xf3, 0xd4, 0x34, 0x4e, 0xb2, 0x09, 0x35, 0x87, 0x32, 0x0d, 0xab, 0x5e, 0x3f, + 0xc5, 0xe7, 0x66, 0xb3, 0x69, 0xd6, 0xfe, 0xcb, 0x2a, 0x53, 0xc8, 0xac, 0x3d, 0x2b, 0xff, 0x6f, + 0x9e, 0x64, 0x93, 0x95, 0xf3, 0x0f, 0x77, 0x05, 0xe5, 0xe6, 0xae, 0xa0, 0x7c, 0xba, 0x2b, 0x28, + 0x6f, 0xee, 0x0b, 0x89, 0x9b, 0xfb, 0x42, 0xe2, 0xe3, 0x7d, 0x21, 0xf1, 0xe2, 0xa8, 0x43, 0x44, + 0x37, 0x6c, 0x69, 0x0e, 0xf3, 0xf4, 0xe8, 0xa1, 0xef, 0x53, 0x10, 0x03, 0xc6, 0xaf, 0xf4, 0xc9, + 0x76, 0x1c, 0xce, 0xee, 0x62, 0xb9, 0x24, 0x5b, 0x3f, 0xc9, 0x2d, 0x79, 0xf4, 0x25, 0x00, 0x00, + 0xff, 0xff, 0x0c, 0xdb, 0x5a, 0x92, 0xaf, 0x05, 0x00, 0x00, } func (m *EventClaimExpired) Marshal() (dAtA []byte, err error) { @@ -700,62 +625,6 @@ func (m *EventApplicationOverserviced) MarshalToSizedBuffer(dAtA []byte) (int, e return len(dAtA) - i, nil } -func (m *EventApplicationReimbursementRequest) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *EventApplicationReimbursementRequest) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *EventApplicationReimbursementRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Amount != nil { - { - size, err := m.Amount.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintEvent(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x22 - } - if len(m.SessionId) > 0 { - i -= len(m.SessionId) - copy(dAtA[i:], m.SessionId) - i = encodeVarintEvent(dAtA, i, uint64(len(m.SessionId))) - i-- - dAtA[i] = 0x1a - } - if len(m.ServiceId) > 0 { - i -= len(m.ServiceId) - copy(dAtA[i:], m.ServiceId) - i = encodeVarintEvent(dAtA, i, uint64(len(m.ServiceId))) - i-- - dAtA[i] = 0x12 - } - if len(m.ApplicationAddr) > 0 { - i -= len(m.ApplicationAddr) - copy(dAtA[i:], m.ApplicationAddr) - i = encodeVarintEvent(dAtA, i, uint64(len(m.ApplicationAddr))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - func encodeVarintEvent(dAtA []byte, offset int, v uint64) int { offset -= sovEvent(v) base := offset @@ -863,31 +732,6 @@ func (m *EventApplicationOverserviced) Size() (n int) { return n } -func (m *EventApplicationReimbursementRequest) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.ApplicationAddr) - if l > 0 { - n += 1 + l + sovEvent(uint64(l)) - } - l = len(m.ServiceId) - if l > 0 { - n += 1 + l + sovEvent(uint64(l)) - } - l = len(m.SessionId) - if l > 0 { - n += 1 + l + sovEvent(uint64(l)) - } - if m.Amount != nil { - l = m.Amount.Size() - n += 1 + l + sovEvent(uint64(l)) - } - return n -} - func sovEvent(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -1550,188 +1394,6 @@ func (m *EventApplicationOverserviced) Unmarshal(dAtA []byte) error { } return nil } -func (m *EventApplicationReimbursementRequest) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowEvent - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: EventApplicationReimbursementRequest: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: EventApplicationReimbursementRequest: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ApplicationAddr", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowEvent - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthEvent - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthEvent - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ApplicationAddr = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ServiceId", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowEvent - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthEvent - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthEvent - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ServiceId = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field SessionId", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowEvent - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthEvent - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthEvent - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.SessionId = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowEvent - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthEvent - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthEvent - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.Amount == nil { - m.Amount = &types1.Coin{} - } - if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipEvent(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthEvent - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} func skipEvent(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 From bbe2366126da7220a96be17804acd4d58976ee11 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Fri, 23 Aug 2024 11:55:46 -0400 Subject: [PATCH 07/53] WIP --- config.yml | 18 +++ e2e/tests/0_settlement.feature | 24 +++- .../keeper/token_logic_modules_test.go | 126 +++++++++--------- 3 files changed, 99 insertions(+), 69 deletions(-) diff --git a/config.yml b/config.yml index 188eef958..2a945a92a 100644 --- a/config.yml +++ b/config.yml @@ -27,6 +27,10 @@ accounts: mnemonic: "involve clean slab term real human green immune valid swing protect talk silent unique cart few ice era right thunder again drop among bounce" coins: - 300000000upokt + - name: apptiny + mnemonic: "worry pupil rival such jump pitch flame prosper tattoo eternal round receive cube crowd remove afraid garment brand toy nut guitar toy sausage fragile" + coins: + - 1000000upokt # 1 POKT - name: supplier1 mnemonic: "cool industry busy tumble funny relax error state height like board wing goat emerge visual idle never unveil announce hill primary okay spatial frog" coins: @@ -169,6 +173,20 @@ genesis: # `supplier1_stake_config.yaml` so that the stake command causes a state change. amount: "1000068" denom: upokt + - address: pokt1ad28jdap2zfanjd7hpkh984yveney6k9a42man + delegatee_gateway_addresses: [] + service_configs: + - service: + id: anvil + - service: + id: rest + - service: + id: ollama + stake: + # NB: This value should be exactly 1upokt smaller than the value in + # `supplier1_stake_config.yaml` so that the stake command causes a state change. + amount: "1000068" + denom: upokt supplier: supplierList: - owner_address: pokt19a3t4yunp0dlpfjrp7qwnzwlrzd5fzs2gjaaaj diff --git a/e2e/tests/0_settlement.feature b/e2e/tests/0_settlement.feature index b4eaf2441..89ab2527c 100644 --- a/e2e/tests/0_settlement.feature +++ b/e2e/tests/0_settlement.feature @@ -7,30 +7,42 @@ Feature: Tokenomics Namespace - Scenario: Emissions equals burn when a claim is created and a valid proof is submitted and required - # Baseline + Scenario: Mint equals burn when a claim is created and a valid proof is submitted and required Given the user has the pocketd binary installed - # Network preparation + # Network preparation and validation And an account exists for "supplier1" And the "supplier" account for "supplier1" is staked And an account exists for "app1" And the "application" account for "app1" is staked And the service "anvil" registered for application "app1" has a compute units per relay of "1" - # Start servicing + # Start servicing relays When the supplier "supplier1" has serviced a session with "10" relays for service "anvil" for application "app1" # Wait for the Claim & Proof lifecycle And the user should wait for the "proof" module "CreateClaim" Message to be submitted And the user should wait for the "proof" module "SubmitProof" Message to be submitted And the user should wait for the "tokenomics" module "ClaimSettled" end block event to be broadcast - # Validate the results + # Validate that mint equals burn Then the account balance of "supplier1" should be "420" uPOKT "more" than before And the "application" stake of "app1" should be "420" uPOKT "less" than before + Scenario: + Given the user has the pocketd binary installed + # Network preparation + And an account exists for "supplier1" + And the "supplier" account for "supplier1" is staked + And an account exists for "app1" + And the "application" account for "app1" is staked + And the service "anvil" registered for application "app1" has a compute units per relay of "1" + # Start servicing relays + When the supplier "supplier1" has serviced a session with "10" relays for service "anvil" for application "app1" + # Wait for the Claim & Proof lifecycle + And the user should wait for the "tokenomics" module "ClaimSettled" end block event to be broadcast + # TODO_IN_THIS_PR: Add the following test # Scenario: Supplier overservices an application and gets paid for less work than claimed # TODO_ADDTEST: Implement the following scenarios - # Scenario: Emissions equals burn when a claim is created and a valid proof is submitted but not required + # Scenario: Mint equals burn when a claim is created and a valid proof is submitted but not required # Scenario: No emissions or burn when a claim is created and an invalid proof is submitted # Scenario: No emissions or burn when a claim is created and a proof is required but is not submitted # Scenario: No emissions or burn when no claim is created \ No newline at end of file diff --git a/x/tokenomics/keeper/token_logic_modules_test.go b/x/tokenomics/keeper/token_logic_modules_test.go index e842abe59..849146091 100644 --- a/x/tokenomics/keeper/token_logic_modules_test.go +++ b/x/tokenomics/keeper/token_logic_modules_test.go @@ -39,68 +39,7 @@ func init() { // func TestProcessTokenLogicModules_ValidateAppOverServicingEvent(t *testing.T) {...} // func TestProcessTokenLogicModules_ValidateAppReimbursedRequestEvent(t *testing.T) {...} -func TestProcessTokenLogicModules_HandleAppGoingIntoDebt(t *testing.T) { - keepers, ctx := testkeeper.NewTokenomicsModuleKeepers(t, nil) - - // Create a service that can be registered in the application and used in the claims - service := &sharedtypes.Service{ - Id: "svc1", - Name: "svcName1", - ComputeUnitsPerRelay: 1, - OwnerAddress: sample.AccAddress(), - } - keepers.SetService(ctx, *service) - - // Add a new application - appStake := cosmostypes.NewCoin("upokt", math.NewInt(1000000)) - app := apptypes.Application{ - Address: sample.AccAddress(), - Stake: &appStake, - ServiceConfigs: []*sharedtypes.ApplicationServiceConfig{{Service: service}}, - } - keepers.SetApplication(ctx, app) - - // Add a new supplier - supplierOwnerAddress := sample.AccAddress() - supplierStake := cosmostypes.NewCoin("upokt", math.NewInt(1000000)) - supplier := sharedtypes.Supplier{ - OwnerAddress: supplierOwnerAddress, - OperatorAddress: supplierOwnerAddress, - Stake: &supplierStake, - Services: []*sharedtypes.SupplierServiceConfig{ - { - Service: service, - RevShare: []*sharedtypes.ServiceRevenueShare{ - { - Address: supplierOwnerAddress, - RevSharePercentage: 100, - }, - }, - }, - }, - } - keepers.SetSupplier(ctx, supplier) - - // The base claim whose root will be customized for testing purposes - numRelays := appStake.Amount.Uint64() + 1 // More than the app stake - numComputeUnits := numRelays * service.ComputeUnitsPerRelay - claim := prooftypes.Claim{ - SupplierOperatorAddress: supplier.OperatorAddress, - SessionHeader: &sessiontypes.SessionHeader{ - ApplicationAddress: app.Address, - Service: service, - SessionId: "session_id", - SessionStartBlockHeight: 1, - SessionEndBlockHeight: testsession.GetSessionEndHeightWithDefaultParams(1), - }, - RootHash: testproof.SmstRootWithSumAndCount(numComputeUnits, numRelays), - } - - err := keepers.ProcessTokenLogicModules(ctx, &claim) - require.NoError(t, err) -} - -func TestProcessTokenLogicModules_ValidAccounting(t *testing.T) { +func TestProcessTokenLogicModules_ValidateBurnEqualsMintValidAccounting(t *testing.T) { // Create a service that can be registered in the application and used in the claims service := &sharedtypes.Service{ Id: "svc1", @@ -228,7 +167,9 @@ func TestProcessTokenLogicModules_ValidAccounting(t *testing.T) { require.EqualValues(t, supplierModuleStartBalance, supplierModuleEndBalance) } -func TestProcessTokenLogicModules_AppStakeTooLow(t *testing.T) { +func TestProcessTokenLogicModules_HandleAppGoingIntoDebt(t *testing.T) { + keepers, ctx := testkeeper.NewTokenomicsModuleKeepers(t, nil) + // Create a service that can be registered in the application and used in the claims service := &sharedtypes.Service{ Id: "svc1", @@ -236,10 +177,69 @@ func TestProcessTokenLogicModules_AppStakeTooLow(t *testing.T) { ComputeUnitsPerRelay: 1, OwnerAddress: sample.AccAddress(), } + keepers.SetService(ctx, *service) + + // Add a new application + appStake := cosmostypes.NewCoin("upokt", math.NewInt(1000000)) + app := apptypes.Application{ + Address: sample.AccAddress(), + Stake: &appStake, + ServiceConfigs: []*sharedtypes.ApplicationServiceConfig{{Service: service}}, + } + keepers.SetApplication(ctx, app) + // Add a new supplier + supplierOwnerAddress := sample.AccAddress() + supplierStake := cosmostypes.NewCoin("upokt", math.NewInt(1000000)) + supplier := sharedtypes.Supplier{ + OwnerAddress: supplierOwnerAddress, + OperatorAddress: supplierOwnerAddress, + Stake: &supplierStake, + Services: []*sharedtypes.SupplierServiceConfig{ + { + Service: service, + RevShare: []*sharedtypes.ServiceRevenueShare{ + { + Address: supplierOwnerAddress, + RevSharePercentage: 100, + }, + }, + }, + }, + } + keepers.SetSupplier(ctx, supplier) + + // The base claim whose root will be customized for testing purposes + numRelays := appStake.Amount.Uint64() + 1 // More than the app stake + numComputeUnits := numRelays * service.ComputeUnitsPerRelay + claim := prooftypes.Claim{ + SupplierOperatorAddress: supplier.OperatorAddress, + SessionHeader: &sessiontypes.SessionHeader{ + ApplicationAddress: app.Address, + Service: service, + SessionId: "session_id", + SessionStartBlockHeight: 1, + SessionEndBlockHeight: testsession.GetSessionEndHeightWithDefaultParams(1), + }, + RootHash: testproof.SmstRootWithSumAndCount(numComputeUnits, numRelays), + } + + err := keepers.ProcessTokenLogicModules(ctx, &claim) + require.NoError(t, err) +} + +func TestProcessTokenLogicModules_AppStakeTooLow(t *testing.T) { + // Create a service that can be registered in the application and used in the claims + service := &sharedtypes.Service{ + Id: "svc1", + Name: "svcName1", + ComputeUnitsPerRelay: 1, + OwnerAddress: sample.AccAddress(), + } keepers, ctx := testkeeper.NewTokenomicsModuleKeepers(t, nil, testkeeper.WithService(*service)) keepers.SetService(ctx, *service) + // Retrieve the app and supplier module addresses appModuleAddress := authtypes.NewModuleAddress(apptypes.ModuleName).String() supplierModuleAddress := authtypes.NewModuleAddress(suppliertypes.ModuleName).String() From ad70e7071ecbe8fd5cad37168cf04cbee0946002 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Fri, 23 Aug 2024 15:44:10 -0400 Subject: [PATCH 08/53] Fixed the TestProcessTokenLogicModules_TLMBurnEqualsMintValid test --- testutil/keeper/tokenomics.go | 3 + x/tokenomics/keeper/token_logic_modules.go | 83 ++++--- .../keeper/token_logic_modules_test.go | 208 ++++++++---------- x/tokenomics/types/errors.go | 2 +- x/tokenomics/types/expected_keepers.go | 1 + 5 files changed, 152 insertions(+), 145 deletions(-) diff --git a/testutil/keeper/tokenomics.go b/testutil/keeper/tokenomics.go index 089913a36..6ec0e64df 100644 --- a/testutil/keeper/tokenomics.go +++ b/testutil/keeper/tokenomics.go @@ -186,6 +186,9 @@ func TokenomicsKeeperWithActorAddrs(t testing.TB) ( mockBankKeeper.EXPECT(). SendCoinsFromModuleToAccount(gomock.Any(), tokenomicstypes.ModuleName, gomock.Any(), gomock.Any()). AnyTimes() + mockBankKeeper.EXPECT(). + SendCoinsFromModuleToModule(gomock.Any(), tokenomicstypes.ModuleName, suppliertypes.ModuleName, gomock.Any()). + AnyTimes() // Mock the account keeper mockAccountKeeper := mocks.NewMockAccountKeeper(ctrl) diff --git a/x/tokenomics/keeper/token_logic_modules.go b/x/tokenomics/keeper/token_logic_modules.go index 3db0c9b41..33f24e618 100644 --- a/x/tokenomics/keeper/token_logic_modules.go +++ b/x/tokenomics/keeper/token_logic_modules.go @@ -24,11 +24,13 @@ import ( tokenomictypes "github.com/pokt-network/poktroll/x/tokenomics/types" ) -const ( +var ( // Governance parameters for the TLMGlobalMint module // TODO_UPNEXT(@olshansk, #732): Make this a governance parameter and give it a non-zero value + tests. - MintPerClaimGlobalInflation = 0.0000000 + MintPerClaimGlobalInflation = 0.1 +) +const ( // TODO_BETA(@bryanchriswhite): Make all of the governance params MintAllocationDAO = 0.1 MintAllocationProposer = 0.05 @@ -333,18 +335,23 @@ func (k Keeper) TokenLogicModuleGlobalMint( ) error { logger := k.Logger().With("method", "TokenLogicModuleGlobalMint") + if MintPerClaimGlobalInflation == 0 { + logger.Warn("global inflation is set to zero. Skipping Global Mint TLM.") + return nil + } + // Determine how much new uPOKT to mint based on global inflation - newMintCoins, newMintAmtFloat := calculateGlobalPerClaimMintInflationFromSettlementAmount(settlementCoin) + newMintCoin, newMintAmtFloat := calculateGlobalPerClaimMintInflationFromSettlementAmount(settlementCoin) // Mint new uPOKT to the tokenomics module account - if err := k.bankKeeper.MintCoins(ctx, tokenomictypes.ModuleName, newMintCoins); err != nil { + if err := k.bankKeeper.MintCoins(ctx, tokenomictypes.ModuleName, sdk.NewCoins(newMintCoin)); err != nil { return tokenomicstypes.ErrTokenomicsModuleMintFailed.Wrapf( - "minting %s to the tokenomics module account: %v", newMintCoins, err) + "minting %s to the tokenomics module account: %v", newMintCoin, err) } - logger.Info(fmt.Sprintf("minted (%v) coins in the tokenomics module", newMintCoins)) + logger.Info(fmt.Sprintf("minted (%v) coins in the tokenomics module", newMintCoin)) // Send a portion of the rewards to the application - appCoin, err := k.sendRewardsToAccount(ctx, application.Address, newMintAmtFloat, MintAllocationApplication) + appCoin, err := k.sendRewardsToAccount(ctx, tokenomictypes.ModuleName, application.Address, newMintAmtFloat, MintAllocationApplication) if err != nil { return tokenomictypes.ErrTokenomicsSendingMintRewards.Wrapf("sending rewards to application: %v", err) } @@ -353,6 +360,15 @@ func (k Keeper) TokenLogicModuleGlobalMint( // Send a portion of the rewards to the supplier shareholders. supplierCoinsToShareAmt := calculateAllocationAmount(newMintAmtFloat, MintAllocationSupplier) supplierCoin := cosmostypes.NewCoin(volatile.DenomuPOKT, math.NewInt(supplierCoinsToShareAmt)) + // Send funds from the tokenomics module to the supplier module account + if err = k.bankKeeper.SendCoinsFromModuleToModule(ctx, tokenomicstypes.ModuleName, suppliertypes.ModuleName, sdk.NewCoins(supplierCoin)); err != nil { + return tokenomicstypes.ErrTokenomicsSupplierModuleSendFailed.Wrapf( + "sending %s from the tokenomics module to the supplier module account: %v", + supplierCoin, + err, + ) + } + // Distribute the rewards from within the supplier's module account. if err = k.distributeSupplierRewardsToShareHolders(ctx, supplier.OperatorAddress, service.Id, uint64(supplierCoinsToShareAmt)); err != nil { return tokenomicstypes.ErrTokenomicsSupplierModuleMintFailed.Wrapf( "distributing rewards to supplier with operator address %s shareholders: %v", @@ -364,14 +380,14 @@ func (k Keeper) TokenLogicModuleGlobalMint( logger.Debug(fmt.Sprintf("sent (%v) newley minted coins from the tokenomics module to the supplier with address %q", supplierCoin, supplier.OperatorAddress)) // Send a portion of the rewards to the DAO - daoCoin, err := k.sendRewardsToAccount(ctx, k.GetAuthority(), newMintAmtFloat, MintAllocationDAO) + daoCoin, err := k.sendRewardsToAccount(ctx, tokenomictypes.ModuleName, k.GetAuthority(), newMintAmtFloat, MintAllocationDAO) if err != nil { return tokenomictypes.ErrTokenomicsSendingMintRewards.Wrapf("sending rewards to DAO: %v", err) } logger.Debug(fmt.Sprintf("sent (%v) newley minted coins from the tokenomics module to the DAO with address %q", daoCoin, k.GetAuthority())) // Send a portion of the rewards to the source owner - serviceCoin, err := k.sendRewardsToAccount(ctx, service.OwnerAddress, newMintAmtFloat, MintAllocationSourceOwner) + serviceCoin, err := k.sendRewardsToAccount(ctx, tokenomictypes.ModuleName, service.OwnerAddress, newMintAmtFloat, MintAllocationSourceOwner) if err != nil { return tokenomictypes.ErrTokenomicsSendingMintRewards.Wrapf("sending rewards to source owner: %v", err) } @@ -379,18 +395,30 @@ func (k Keeper) TokenLogicModuleGlobalMint( // Send a portion of the rewards to the block proposer proposerAddr := cosmostypes.AccAddress(sdk.UnwrapSDKContext(ctx).BlockHeader().ProposerAddress).String() - proposerCoin, err := k.sendRewardsToAccount(ctx, proposerAddr, newMintAmtFloat, MintAllocationProposer) + proposerCoin, err := k.sendRewardsToAccount(ctx, tokenomictypes.ModuleName, proposerAddr, newMintAmtFloat, MintAllocationProposer) if err != nil { return tokenomictypes.ErrTokenomicsSendingMintRewards.Wrapf("sending rewards to proposer: %v", err) } logger.Debug(fmt.Sprintf("sent (%v) newley minted coins from the tokenomics module to the proposer with address %q", proposerCoin, proposerAddr)) // Check and log the total amount of coins distributed - totalDistributedCoins := appCoin.Add(supplierCoin).Add(*daoCoin).Add(*serviceCoin).Add(*proposerCoin) - if totalDistributedCoins.Amount.BigInt().Cmp(newMintCoins[0].Amount.BigInt()) != 0 { - return tokenomictypes.ErrTokenomicsAmountMismatch.Wrapf("the total distributed coins (%v) do not equal the settlement coins (%v). Likely floating point arithmetic.", totalDistributedCoins, settlementCoin.Amount.BigInt()) - } - logger.Info(fmt.Sprintf("distributed (%v) coins to the application, supplier, DAO, source owner, and proposer", totalDistributedCoins)) + totalMintDistributedCoin := appCoin.Add(supplierCoin).Add(*daoCoin).Add(*serviceCoin).Add(*proposerCoin) + coinDifference := new(big.Int).Sub(totalMintDistributedCoin.Amount.BigInt(), newMintCoin.Amount.BigInt()) + coinDifference = coinDifference.Abs(coinDifference) + percentDifference := new(big.Float).Quo(new(big.Float).SetInt(coinDifference), new(big.Float).SetInt(newMintCoin.Amount.BigInt())) + if percentDifference.Cmp(big.NewFloat(0.01)) > 0 { + return tokenomictypes.ErrTokenomicsAmountMismatchTooLarge.Wrapf( + "the total distributed coins (%v) do not equal the amount of new minted coins (%v). Likely floating point arithmetic.\n"+ + "appCoin: %v, supplierCoin: %v, daoCoin: %v, serviceCoin: %v, proposerCoin: %v", + totalMintDistributedCoin, newMintCoin, + appCoin, supplierCoin, daoCoin, serviceCoin, proposerCoin) + } else if coinDifference.Cmp(big.NewInt(0)) > 0 { + logger.Warn(fmt.Sprintf("Floating point arithmetic led to a discrepancy of %v (%f) between the total distributed coins (%v) and the amount of new minted coins (%v).\n"+ + "appCoin: %v, supplierCoin: %v, daoCoin: %v, serviceCoin: %v, proposerCoin: %v", + coinDifference, percentDifference, totalMintDistributedCoin, newMintCoin, + appCoin, supplierCoin, daoCoin, serviceCoin, proposerCoin)) + } + logger.Info(fmt.Sprintf("distributed (%v) coins to the application, supplier, DAO, source owner, and proposer", totalMintDistributedCoin)) return nil } @@ -399,13 +427,14 @@ func (k Keeper) TokenLogicModuleGlobalMint( // tokenomics module account to the specified address. func (k Keeper) sendRewardsToAccount( ctx context.Context, - addr string, + srcModule string, + destAdr string, settlementAmtFloat *big.Float, allocation float64, ) (*sdk.Coin, error) { logger := k.Logger().With("method", "mintRewardsToAccount") - accountAddr, err := cosmostypes.AccAddressFromBech32(addr) + accountAddr, err := cosmostypes.AccAddressFromBech32(destAdr) if err != nil { return nil, err } @@ -413,11 +442,11 @@ func (k Keeper) sendRewardsToAccount( coinsToAccAmt := calculateAllocationAmount(settlementAmtFloat, allocation) coinToAcc := cosmostypes.NewCoin(volatile.DenomuPOKT, math.NewInt(coinsToAccAmt)) if err := k.bankKeeper.SendCoinsFromModuleToAccount( - ctx, suppliertypes.ModuleName, accountAddr, sdk.NewCoins(coinToAcc), + ctx, srcModule, accountAddr, sdk.NewCoins(coinToAcc), ); err != nil { return nil, err } - logger.Info(fmt.Sprintf("sent (%v) coins from the tokenomics module to the account with address %q", coinToAcc, addr)) + logger.Info(fmt.Sprintf("sent (%v) coins from the tokenomics module to the account with address %q", coinToAcc, destAdr)) return &coinToAcc, nil } @@ -504,17 +533,17 @@ func (k Keeper) numRelaysToCoin( // shareholders based on the rev share percentage of the supplier service config. func (k Keeper) distributeSupplierRewardsToShareHolders( ctx context.Context, - supplierAddr string, + supplierOperatorAddr string, serviceId string, amountToDistribute uint64, ) error { logger := k.Logger().With("method", "distributeSupplierRewardsToShareHolders") - supplier, supplierFound := k.supplierKeeper.GetSupplier(ctx, supplierAddr) + supplier, supplierFound := k.supplierKeeper.GetSupplier(ctx, supplierOperatorAddr) if !supplierFound { return tokenomicstypes.ErrTokenomicsSupplierRevShareFailed.Wrapf( "supplier with address %q not found", - supplierAddr, + supplierOperatorAddr, ) } @@ -552,10 +581,10 @@ func (k Keeper) distributeSupplierRewardsToShareHolders( return err } - logger.Info(fmt.Sprintf("sent %s from the supplier module to the supplier shareholder with address %q", shareAmountCoin, supplierAddr)) + logger.Info(fmt.Sprintf("sent %s from the supplier module to the supplier shareholder with address %q", shareAmountCoin, supplierOperatorAddr)) } - logger.Info(fmt.Sprintf("distributed %d uPOKT to supplier %q shareholders", amountToDistribute, supplierAddr)) + logger.Info(fmt.Sprintf("distributed %d uPOKT to supplier %q shareholders", amountToDistribute, supplierOperatorAddr)) return nil } @@ -563,14 +592,14 @@ func (k Keeper) distributeSupplierRewardsToShareHolders( // calculateGlobalPerClaimMintInflationFromSettlementAmount calculates the amount // of uPOKT to mint based on the global per claim inflation rate as a function of // the settlement amount for a particular claim(s) or session(s). -func calculateGlobalPerClaimMintInflationFromSettlementAmount(settlementCoin sdk.Coin) (sdk.Coins, *big.Float) { +func calculateGlobalPerClaimMintInflationFromSettlementAmount(settlementCoin sdk.Coin) (sdk.Coin, *big.Float) { // Determine how much new uPOKT to mint based on global per claim inflation. // TODO_MAINNET: Consider using fixed point arithmetic for deterministic results. settlementAmtFloat := new(big.Float).SetUint64(settlementCoin.Amount.Uint64()) newMintAmtFloat := new(big.Float).Mul(settlementAmtFloat, big.NewFloat(MintPerClaimGlobalInflation)) newMintAmtInt, _ := newMintAmtFloat.Int64() - mintAmtCoins := sdk.NewCoins(cosmostypes.NewCoin(volatile.DenomuPOKT, math.NewInt(newMintAmtInt))) - return mintAmtCoins, newMintAmtFloat + mintAmtCoin := cosmostypes.NewCoin(volatile.DenomuPOKT, math.NewInt(newMintAmtInt)) + return mintAmtCoin, newMintAmtFloat } // calculateAllocationAmount does big float arithmetic to determine the absolute diff --git a/x/tokenomics/keeper/token_logic_modules_test.go b/x/tokenomics/keeper/token_logic_modules_test.go index 849146091..e2db9c5c3 100644 --- a/x/tokenomics/keeper/token_logic_modules_test.go +++ b/x/tokenomics/keeper/token_logic_modules_test.go @@ -9,11 +9,13 @@ import ( "cosmossdk.io/math" "github.com/cometbft/cometbft/libs/json" cosmostypes "github.com/cosmos/cosmos-sdk/types" + sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/pokt-network/smt" "github.com/stretchr/testify/require" + "github.com/pokt-network/poktroll/app/volatile" "github.com/pokt-network/poktroll/cmd/poktrolld/cmd" "github.com/pokt-network/poktroll/pkg/crypto/protocol" testkeeper "github.com/pokt-network/poktroll/testutil/keeper" @@ -22,10 +24,11 @@ import ( testsession "github.com/pokt-network/poktroll/testutil/session" apptypes "github.com/pokt-network/poktroll/x/application/types" prooftypes "github.com/pokt-network/poktroll/x/proof/types" + sessionkeeper "github.com/pokt-network/poktroll/x/session/keeper" sessiontypes "github.com/pokt-network/poktroll/x/session/types" sharedtypes "github.com/pokt-network/poktroll/x/shared/types" suppliertypes "github.com/pokt-network/poktroll/x/supplier/types" - "github.com/pokt-network/poktroll/x/tokenomics/keeper" + tokenomicskeeper "github.com/pokt-network/poktroll/x/tokenomics/keeper" tokenomicstypes "github.com/pokt-network/poktroll/x/tokenomics/types" ) @@ -39,31 +42,49 @@ func init() { // func TestProcessTokenLogicModules_ValidateAppOverServicingEvent(t *testing.T) {...} // func TestProcessTokenLogicModules_ValidateAppReimbursedRequestEvent(t *testing.T) {...} -func TestProcessTokenLogicModules_ValidateBurnEqualsMintValidAccounting(t *testing.T) { +func TestProcessTokenLogicModules_TLMBurnEqualsMintValid(t *testing.T) { + // Test Parameters + appInitialStake := math.NewInt(1000000) + supplierInitialStake := math.NewInt(1000000) + supplierRevShareRatios := []float32{12.5, 37.5, 50} + globalComputeUnitsToTokensMultiplier := uint64(1) + serviceComputeUnitsPerRelay := uint64(1) + numRelays := uint64(1000) + + // Ensure the claim is within relay mining bounds + numTokensClaimed := int64(numRelays * serviceComputeUnitsPerRelay * globalComputeUnitsToTokensMultiplier) + maxClaimableAmount := appInitialStake.Quo(math.NewInt(sessionkeeper.NumSupplierPerSession)) + require.GreaterOrEqual(t, maxClaimableAmount.Int64(), numTokensClaimed) + // Create a service that can be registered in the application and used in the claims service := &sharedtypes.Service{ Id: "svc1", Name: "svcName1", - ComputeUnitsPerRelay: 1, + ComputeUnitsPerRelay: serviceComputeUnitsPerRelay, OwnerAddress: sample.AccAddress(), } - keepers, ctx := testkeeper.NewTokenomicsModuleKeepers(t, nil, testkeeper.WithService(*service)) keepers.SetService(ctx, *service) + // Retrieve the app and supplier module addresses appModuleAddress := authtypes.NewModuleAddress(apptypes.ModuleName).String() supplierModuleAddress := authtypes.NewModuleAddress(suppliertypes.ModuleName).String() - // Set compute_units_to_tokens_multiplier to 1 to simplify expectation calculations. + // Set compute_units_to_tokens_multiplier to simplify expectation calculations. err := keepers.Keeper.SetParams(ctx, tokenomicstypes.Params{ - ComputeUnitsToTokensMultiplier: 1, + ComputeUnitsToTokensMultiplier: globalComputeUnitsToTokensMultiplier, }) require.NoError(t, err) + // TODO_TECHDEBT: Setting inflation to zero so we are testing the BurnEqualsMint logic exclusively. + // Once it is a governance param, update it using the keeper above. + prevInflationValue := tokenomicskeeper.MintPerClaimGlobalInflation + tokenomicskeeper.MintPerClaimGlobalInflation = 0 + t.Cleanup(func() { + tokenomicskeeper.MintPerClaimGlobalInflation = prevInflationValue + }) // Add a new application with non-zero app stake end balance to assert against. - appStake := cosmostypes.NewCoin("upokt", math.NewInt(1000000)) - expectedAppEndStakeAmount := cosmostypes.NewCoin("upokt", math.NewInt(420)) - expectedAppBurn := appStake.Sub(expectedAppEndStakeAmount) + appStake := cosmostypes.NewCoin(volatile.DenomuPOKT, appInitialStake) app := apptypes.Application{ Address: sample.AccAddress(), Stake: &appStake, @@ -71,55 +92,38 @@ func TestProcessTokenLogicModules_ValidateBurnEqualsMintValidAccounting(t *testi } keepers.SetApplication(ctx, app) - shareRatios := []float32{12.5, 37.5, 50} - revShares := make([]*sharedtypes.ServiceRevenueShare, len(shareRatios)) - for i := range revShares { + // Determine the expected app end stake amount and the expected app burn + expectedAppBurn := math.NewInt(numTokensClaimed) + expectedAppEndStakeAmount := appInitialStake.Sub(expectedAppBurn) + + // Prepare the supplier revenue shares + supplierRevShares := make([]*sharedtypes.ServiceRevenueShare, len(supplierRevShareRatios)) + for i := range supplierRevShares { shareHolderAddress := sample.AccAddress() - revShares[i] = &sharedtypes.ServiceRevenueShare{ + supplierRevShares[i] = &sharedtypes.ServiceRevenueShare{ Address: shareHolderAddress, - RevSharePercentage: shareRatios[i], + RevSharePercentage: supplierRevShareRatios[i], } } // Add a new supplier. - supplierStake := cosmostypes.NewCoin("upokt", math.NewInt(1000000)) + supplierStake := cosmostypes.NewCoin(volatile.DenomuPOKT, supplierInitialStake) supplier := sharedtypes.Supplier{ // Make the first shareholder the supplier itself. - OwnerAddress: revShares[0].Address, - OperatorAddress: revShares[0].Address, + OwnerAddress: supplierRevShares[0].Address, + OperatorAddress: supplierRevShares[0].Address, Stake: &supplierStake, - Services: []*sharedtypes.SupplierServiceConfig{ - { - Service: service, - RevShare: revShares, - }, - }, + Services: []*sharedtypes.SupplierServiceConfig{{Service: service, RevShare: supplierRevShares}}, } keepers.SetSupplier(ctx, supplier) - // Query application balance prior to the accounting. + // Query the account and module start balances appStartBalance := getBalance(t, ctx, keepers, app.GetAddress()) - // Query application module balance prior to the accounting. appModuleStartBalance := getBalance(t, ctx, keepers, appModuleAddress) - - // Query supplier module balance prior to the accounting. supplierModuleStartBalance := getBalance(t, ctx, keepers, supplierModuleAddress) - // Assumes ComputeUnitToTokenMultiplier is 1 - numComputeUnits := expectedAppBurn.Amount.Uint64() - numRelays := numComputeUnits / service.ComputeUnitsPerRelay - // The base claim whose root will be customized for testing purposes - claim := prooftypes.Claim{ - SupplierOperatorAddress: supplier.OperatorAddress, - SessionHeader: &sessiontypes.SessionHeader{ - ApplicationAddress: app.Address, - Service: service, - SessionId: "session_id", - SessionStartBlockHeight: 1, - SessionEndBlockHeight: testsession.GetSessionEndHeightWithDefaultParams(1), - }, - RootHash: testproof.SmstRootWithSumAndCount(numComputeUnits, numRelays), - } + // Prepare the claim for which the supplier did work for the application + claim := prepareClaim(numRelays, service, &app, &supplier) // Process the token logic modules err = keepers.ProcessTokenLogicModules(ctx, &claim) @@ -132,29 +136,16 @@ func TestProcessTokenLogicModules_ValidateBurnEqualsMintValidAccounting(t *testi // Assert that `applicationAddress` staked balance has decreased by the appropriate amount app, appIsFound := keepers.GetApplication(ctx, app.GetAddress()) require.True(t, appIsFound) - require.Equal(t, &expectedAppEndStakeAmount, app.GetStake()) + require.Equal(t, expectedAppEndStakeAmount, app.GetStake().Amount) - // Assert that `apptypes.ModuleName` account module balance is *decreased* by the appropriate amount + // Assert that app module balance is *decreased* by the appropriate amount // NB: The application module account burns the amount of uPOKT that was held in escrow // on behalf of the applications which were serviced in a given session. + expectedAppModuleEndBalance := appModuleStartBalance.Sub(sdk.NewCoin(volatile.DenomuPOKT, expectedAppBurn)) appModuleEndBalance := getBalance(t, ctx, keepers, appModuleAddress) - expectedAppModuleEndBalance := appModuleStartBalance.Sub(expectedAppBurn) require.NotNil(t, appModuleEndBalance) require.EqualValues(t, &expectedAppModuleEndBalance, appModuleEndBalance) - // Assert that the supplier shareholders account balances have *increased* by - // the appropriate amount. - mintAmountInt := expectedAppBurn.Amount.Uint64() - shareAmounts := keeper.GetShareAmountMap(supplier.Services[0].RevShare, mintAmountInt) - for shareHolder, expectedShareAmount := range shareAmounts { - shareHolderBalance := getBalance(t, ctx, keepers, shareHolder) - - require.Equal(t, - int64(expectedShareAmount), - shareHolderBalance.Amount.Int64(), - ) - } - // Assert that `supplierOperatorAddress` staked balance is *unchanged* supplier, supplierIsFound := keepers.GetSupplier(ctx, supplier.GetOperatorAddress()) require.True(t, supplierIsFound) @@ -165,70 +156,24 @@ func TestProcessTokenLogicModules_ValidateBurnEqualsMintValidAccounting(t *testi // distributed to the supplier accounts which provided service in a given session. supplierModuleEndBalance := getBalance(t, ctx, keepers, supplierModuleAddress) require.EqualValues(t, supplierModuleStartBalance, supplierModuleEndBalance) -} - -func TestProcessTokenLogicModules_HandleAppGoingIntoDebt(t *testing.T) { - keepers, ctx := testkeeper.NewTokenomicsModuleKeepers(t, nil) - - // Create a service that can be registered in the application and used in the claims - service := &sharedtypes.Service{ - Id: "svc1", - Name: "svcName1", - ComputeUnitsPerRelay: 1, - OwnerAddress: sample.AccAddress(), - } - keepers.SetService(ctx, *service) - - // Add a new application - appStake := cosmostypes.NewCoin("upokt", math.NewInt(1000000)) - app := apptypes.Application{ - Address: sample.AccAddress(), - Stake: &appStake, - ServiceConfigs: []*sharedtypes.ApplicationServiceConfig{{Service: service}}, - } - keepers.SetApplication(ctx, app) - // Add a new supplier - supplierOwnerAddress := sample.AccAddress() - supplierStake := cosmostypes.NewCoin("upokt", math.NewInt(1000000)) - supplier := sharedtypes.Supplier{ - OwnerAddress: supplierOwnerAddress, - OperatorAddress: supplierOwnerAddress, - Stake: &supplierStake, - Services: []*sharedtypes.SupplierServiceConfig{ - { - Service: service, - RevShare: []*sharedtypes.ServiceRevenueShare{ - { - Address: supplierOwnerAddress, - RevSharePercentage: 100, - }, - }, - }, - }, - } - keepers.SetSupplier(ctx, supplier) - - // The base claim whose root will be customized for testing purposes - numRelays := appStake.Amount.Uint64() + 1 // More than the app stake - numComputeUnits := numRelays * service.ComputeUnitsPerRelay - claim := prooftypes.Claim{ - SupplierOperatorAddress: supplier.OperatorAddress, - SessionHeader: &sessiontypes.SessionHeader{ - ApplicationAddress: app.Address, - Service: service, - SessionId: "session_id", - SessionStartBlockHeight: 1, - SessionEndBlockHeight: testsession.GetSessionEndHeightWithDefaultParams(1), - }, - RootHash: testproof.SmstRootWithSumAndCount(numComputeUnits, numRelays), + // Assert that the supplier shareholders account balances have *increased* by + // the appropriate amount w.r.t token distribution. + shareAmounts := tokenomicskeeper.GetShareAmountMap(supplierRevShares, expectedAppBurn.Uint64()) + for shareHolderAddr, expectedShareAmount := range shareAmounts { + shareHolderBalance := getBalance(t, ctx, keepers, shareHolderAddr) + require.Equal(t, int64(expectedShareAmount), shareHolderBalance.Amount.Int64()) } - - err := keepers.ProcessTokenLogicModules(ctx, &claim) - require.NoError(t, err) } func TestProcessTokenLogicModules_AppStakeTooLow(t *testing.T) { + // Test Parameters + // appInitialStake := math.NewInt(1000000) + // appEndStake := math.NewInt(420) + // supplierInitialStake := math.NewInt(1000000) + // supplierRevShareRatios := []float32{12.5, 37.5, 50} + // computeUnitsToTokensMultiplier := uint64(1) + // Create a service that can be registered in the application and used in the claims service := &sharedtypes.Service{ Id: "svc1", @@ -346,6 +291,14 @@ func TestProcessTokenLogicModules_AppStakeTooLow(t *testing.T) { require.EqualValues(t, supplierModuleStartBalance, supplierModuleEndBalance) // Check that the expected burn >> effective burn because application is overserviced + + // events := sdkCtx.EventManager().Events() + // relayMiningEvents := testutilevents.FilterEvents[*tokenomicstypes.EventRelayMiningDifficultyUpdated](t, + // events, "poktroll.tokenomics.EventRelayMiningDifficultyUpdated") + // require.Len(t, relayMiningEvents, 1, "unexpected number of relay mining difficulty updated events") + // relayMiningEvent := relayMiningEvents[0] + // require.Equal(t, "svc1", relayMiningEvent.ServiceId) + events := cosmostypes.UnwrapSDKContext(ctx).EventManager().Events() appAddrAttribute, _ := events.GetAttributes("application_addr") expectedBurnAttribute, _ := events.GetAttributes("expected_burn") @@ -576,6 +529,27 @@ func TestProcessTokenLogicModules_InvalidClaim(t *testing.T) { } } +func prepareClaim( + numRelays uint64, + service *sharedtypes.Service, + app *apptypes.Application, + supplier *sharedtypes.Supplier, +) prooftypes.Claim { + numComputeUnits := numRelays * service.ComputeUnitsPerRelay + return prooftypes.Claim{ + SupplierOperatorAddress: supplier.OperatorAddress, + SessionHeader: &sessiontypes.SessionHeader{ + ApplicationAddress: app.Address, + Service: service, + SessionId: "session_id", + SessionStartBlockHeight: 1, + SessionEndBlockHeight: testsession.GetSessionEndHeightWithDefaultParams(1), + }, + RootHash: testproof.SmstRootWithSumAndCount(numComputeUnits, numRelays), + } + +} + func getBalance( t *testing.T, ctx context.Context, diff --git a/x/tokenomics/types/errors.go b/x/tokenomics/types/errors.go index 24a16cd1b..018c44601 100644 --- a/x/tokenomics/types/errors.go +++ b/x/tokenomics/types/errors.go @@ -33,5 +33,5 @@ var ( ErrTokenomicsSupplierOwnerAddressInvalid = sdkerrors.Register(ModuleName, 1124, "the supplier owner address in the claim is not a valid bech32 address") ErrTokenomicsSupplierRevShareFailed = sdkerrors.Register(ModuleName, 1125, "failed to send rev share to supplier shareholders") ErrTokenomicsApplicationReimbursementRequestFailed = sdkerrors.Register(ModuleName, 1126, "failed to send application reimbursement request event") - ErrTokenomicsAmountMismatch = sdkerrors.Register(ModuleName, 1127, "an unexpected amount mismatch occurred") + ErrTokenomicsAmountMismatchTooLarge = sdkerrors.Register(ModuleName, 1127, "an unexpected amount mismatch occurred") ) diff --git a/x/tokenomics/types/expected_keepers.go b/x/tokenomics/types/expected_keepers.go index a267cbb18..b6e07314a 100644 --- a/x/tokenomics/types/expected_keepers.go +++ b/x/tokenomics/types/expected_keepers.go @@ -35,6 +35,7 @@ type BankKeeper interface { // than "delegate" funds from one account to another which is more closely // linked to staking. SendCoinsFromModuleToAccount(ctx context.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error + SendCoinsFromModuleToModule(ctx context.Context, senderModule, recipientModule string, amt sdk.Coins) error Balance(context.Context, *banktypes.QueryBalanceRequest) (*banktypes.QueryBalanceResponse, error) } From b02ef24676b3eb145a6520e077ab619e8e21541b Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Fri, 23 Aug 2024 22:23:30 -0400 Subject: [PATCH 09/53] WIP --- .../keeper/token_logic_modules_test.go | 170 ++++++++++-------- 1 file changed, 91 insertions(+), 79 deletions(-) diff --git a/x/tokenomics/keeper/token_logic_modules_test.go b/x/tokenomics/keeper/token_logic_modules_test.go index e2db9c5c3..4bae90d8e 100644 --- a/x/tokenomics/keeper/token_logic_modules_test.go +++ b/x/tokenomics/keeper/token_logic_modules_test.go @@ -18,6 +18,7 @@ import ( "github.com/pokt-network/poktroll/app/volatile" "github.com/pokt-network/poktroll/cmd/poktrolld/cmd" "github.com/pokt-network/poktroll/pkg/crypto/protocol" + testutilevents "github.com/pokt-network/poktroll/testutil/events" testkeeper "github.com/pokt-network/poktroll/testutil/keeper" testproof "github.com/pokt-network/poktroll/testutil/proof" "github.com/pokt-network/poktroll/testutil/sample" @@ -49,12 +50,12 @@ func TestProcessTokenLogicModules_TLMBurnEqualsMintValid(t *testing.T) { supplierRevShareRatios := []float32{12.5, 37.5, 50} globalComputeUnitsToTokensMultiplier := uint64(1) serviceComputeUnitsPerRelay := uint64(1) - numRelays := uint64(1000) + numRelays := uint64(1000) // By supplier for application in this session // Ensure the claim is within relay mining bounds numTokensClaimed := int64(numRelays * serviceComputeUnitsPerRelay * globalComputeUnitsToTokensMultiplier) - maxClaimableAmount := appInitialStake.Quo(math.NewInt(sessionkeeper.NumSupplierPerSession)) - require.GreaterOrEqual(t, maxClaimableAmount.Int64(), numTokensClaimed) + maxClaimableAmountPerSupplier := appInitialStake.Quo(math.NewInt(sessionkeeper.NumSupplierPerSession)) + require.GreaterOrEqual(t, maxClaimableAmountPerSupplier.Int64(), numTokensClaimed) // Create a service that can be registered in the application and used in the claims service := &sharedtypes.Service{ @@ -92,10 +93,6 @@ func TestProcessTokenLogicModules_TLMBurnEqualsMintValid(t *testing.T) { } keepers.SetApplication(ctx, app) - // Determine the expected app end stake amount and the expected app burn - expectedAppBurn := math.NewInt(numTokensClaimed) - expectedAppEndStakeAmount := appInitialStake.Sub(expectedAppBurn) - // Prepare the supplier revenue shares supplierRevShares := make([]*sharedtypes.ServiceRevenueShare, len(supplierRevShareRatios)) for i := range supplierRevShares { @@ -133,10 +130,15 @@ func TestProcessTokenLogicModules_TLMBurnEqualsMintValid(t *testing.T) { appEndBalance := getBalance(t, ctx, keepers, app.GetAddress()) require.EqualValues(t, appStartBalance, appEndBalance) + // Determine the expected app end stake amount and the expected app burn + expectedAppBurn := math.NewInt(numTokensClaimed) + expectedAppEndStakeAmount := appInitialStake.Sub(expectedAppBurn) + // Assert that `applicationAddress` staked balance has decreased by the appropriate amount app, appIsFound := keepers.GetApplication(ctx, app.GetAddress()) + actualAppEndStakeAmount := app.GetStake().Amount require.True(t, appIsFound) - require.Equal(t, expectedAppEndStakeAmount, app.GetStake().Amount) + require.Equal(t, expectedAppEndStakeAmount, actualAppEndStakeAmount) // Assert that app module balance is *decreased* by the appropriate amount // NB: The application module account burns the amount of uPOKT that was held in escrow @@ -166,19 +168,32 @@ func TestProcessTokenLogicModules_TLMBurnEqualsMintValid(t *testing.T) { } } -func TestProcessTokenLogicModules_AppStakeTooLow(t *testing.T) { +// DEV_NOTE: Most of the setup here is a copy-paste of TLMBurnEqualsMintValid +// except that the application stake is calculated to explicitly be too low to +// handle all the relays completed. +func TestProcessTokenLogicModules_TLMBurnEqualsMintInvalid_SupplierExceedsMaxClaimableAmount(t *testing.T) { // Test Parameters - // appInitialStake := math.NewInt(1000000) - // appEndStake := math.NewInt(420) - // supplierInitialStake := math.NewInt(1000000) - // supplierRevShareRatios := []float32{12.5, 37.5, 50} - // computeUnitsToTokensMultiplier := uint64(1) + globalComputeUnitsToTokensMultiplier := uint64(1) + serviceComputeUnitsPerRelay := uint64(1) + numRelays := uint64(1000) // By a single supplier for application in this session + supplierInitialStake := math.NewInt(1000000) + supplierRevShareRatios := []float32{12.5, 37.5, 50} + + // Set up the relays to exceed the max claimable amount + // Determine the max a supplier can claim + maxClaimableAmountPerSupplier := int64(numRelays * serviceComputeUnitsPerRelay * globalComputeUnitsToTokensMultiplier) + // Figure out what the app's initial stake should be to cover the max claimable amount + appInitialStake := math.NewInt(maxClaimableAmountPerSupplier*sessionkeeper.NumSupplierPerSession + 1) + // Increase the number of relay such that the supplier did "free work" and would + // be able to claim more than the max claimable amount. + numRelays *= 5 + numTokensClaimed := int64(numRelays * serviceComputeUnitsPerRelay * globalComputeUnitsToTokensMultiplier) // Create a service that can be registered in the application and used in the claims service := &sharedtypes.Service{ Id: "svc1", Name: "svcName1", - ComputeUnitsPerRelay: 1, + ComputeUnitsPerRelay: serviceComputeUnitsPerRelay, OwnerAddress: sample.AccAddress(), } keepers, ctx := testkeeper.NewTokenomicsModuleKeepers(t, nil, testkeeper.WithService(*service)) @@ -188,16 +203,21 @@ func TestProcessTokenLogicModules_AppStakeTooLow(t *testing.T) { appModuleAddress := authtypes.NewModuleAddress(apptypes.ModuleName).String() supplierModuleAddress := authtypes.NewModuleAddress(suppliertypes.ModuleName).String() - // Set compute_units_to_tokens_multiplier to 1 to simplify expectation calculations. + // Set compute_units_to_tokens_multiplier to simplify expectation calculations. err := keepers.Keeper.SetParams(ctx, tokenomicstypes.Params{ - ComputeUnitsToTokensMultiplier: 1, + ComputeUnitsToTokensMultiplier: globalComputeUnitsToTokensMultiplier, }) require.NoError(t, err) + // TODO_TECHDEBT: Setting inflation to zero so we are testing the BurnEqualsMint logic exclusively. + // Once it is a governance param, update it using the keeper above. + prevInflationValue := tokenomicskeeper.MintPerClaimGlobalInflation + tokenomicskeeper.MintPerClaimGlobalInflation = 0 + t.Cleanup(func() { + tokenomicskeeper.MintPerClaimGlobalInflation = prevInflationValue + }) - // Add a new application - appStake := cosmostypes.NewCoin("upokt", math.NewInt(40000)) - expectedAppEndStakeZeroAmount := cosmostypes.NewCoin("upokt", math.NewInt(0)) - expectedAppBurn := appStake.AddAmount(math.NewInt(2000)) + // Add a new application with non-zero app stake end balance to assert against. + appStake := cosmostypes.NewCoin(volatile.DenomuPOKT, appInitialStake) app := apptypes.Application{ Address: sample.AccAddress(), Stake: &appStake, @@ -205,55 +225,34 @@ func TestProcessTokenLogicModules_AppStakeTooLow(t *testing.T) { } keepers.SetApplication(ctx, app) - // Query application balance prior to the accounting. - appStartBalance := getBalance(t, ctx, keepers, app.GetAddress()) - // Query application module balance prior to the accounting. - appModuleStartBalance := getBalance(t, ctx, keepers, appModuleAddress) + // Prepare the supplier revenue shares + supplierRevShares := make([]*sharedtypes.ServiceRevenueShare, len(supplierRevShareRatios)) + for i := range supplierRevShares { + shareHolderAddress := sample.AccAddress() + supplierRevShares[i] = &sharedtypes.ServiceRevenueShare{ + Address: shareHolderAddress, + RevSharePercentage: supplierRevShareRatios[i], + } + } // Add a new supplier. - supplierOwnerAddress := sample.AccAddress() - supplierStake := cosmostypes.NewCoin("upokt", math.NewInt(1000000)) + supplierStake := cosmostypes.NewCoin(volatile.DenomuPOKT, supplierInitialStake) supplier := sharedtypes.Supplier{ - OwnerAddress: supplierOwnerAddress, - OperatorAddress: supplierOwnerAddress, + // Make the first shareholder the supplier itself. + OwnerAddress: supplierRevShares[0].Address, + OperatorAddress: supplierRevShares[0].Address, Stake: &supplierStake, - Services: []*sharedtypes.SupplierServiceConfig{ - { - Service: service, - RevShare: []*sharedtypes.ServiceRevenueShare{ - { - Address: supplierOwnerAddress, - RevSharePercentage: 100, - }, - }, - }, - }, + Services: []*sharedtypes.SupplierServiceConfig{{Service: service, RevShare: supplierRevShares}}, } keepers.SetSupplier(ctx, supplier) - // Query supplier owner balance prior to the accounting. - supplierOwnerStartBalance := getBalance(t, ctx, keepers, supplier.GetOwnerAddress()) - - // Query supplier module balance prior to the accounting. + // Query the account and module start balances + appStartBalance := getBalance(t, ctx, keepers, app.GetAddress()) + appModuleStartBalance := getBalance(t, ctx, keepers, appModuleAddress) supplierModuleStartBalance := getBalance(t, ctx, keepers, supplierModuleAddress) - // Determine the number of relays to use up the application's entire stake - sharedParams := keepers.Keeper.GetParams(ctx) - numComputeUnits := expectedAppBurn.Amount.Uint64() / sharedParams.ComputeUnitsToTokensMultiplier - numRelays := numComputeUnits / service.ComputeUnitsPerRelay - - // The base claim whose root will be customized for testing purposes - claim := prooftypes.Claim{ - SupplierOperatorAddress: supplier.OperatorAddress, - SessionHeader: &sessiontypes.SessionHeader{ - ApplicationAddress: app.Address, - Service: service, - SessionId: "session_id", - SessionStartBlockHeight: 1, - SessionEndBlockHeight: testsession.GetSessionEndHeightWithDefaultParams(1), - }, - RootHash: testproof.SmstRootWithSumAndCount(numComputeUnits, numRelays), - } + // Prepare the claim for which the supplier did work for the application + claim := prepareClaim(numRelays, service, &app, &supplier) // Process the token logic modules err = keepers.ProcessTokenLogicModules(ctx, &claim) @@ -263,41 +262,54 @@ func TestProcessTokenLogicModules_AppStakeTooLow(t *testing.T) { appEndBalance := getBalance(t, ctx, keepers, app.GetAddress()) require.EqualValues(t, appStartBalance, appEndBalance) - // Assert that `applicationAddress` staked balance has gone to zero + // Determine the expected app end stake amount and the expected app burn + expectedAppBurn := math.NewInt(maxClaimableAmountPerSupplier) + expectedAppEndStakeAmount := appInitialStake.Sub(expectedAppBurn) + + // Assert that `applicationAddress` staked balance has decreased by the max claimable amount app, appIsFound := keepers.GetApplication(ctx, app.GetAddress()) + actualAppEndStakeAmount := app.GetStake().Amount require.True(t, appIsFound) - require.Equal(t, &expectedAppEndStakeZeroAmount, app.GetStake()) + require.Equal(t, expectedAppEndStakeAmount, actualAppEndStakeAmount) - // Assert that `apptypes.ModuleName` account module balance is *decreased* by the appropriate amount + // Sanity + require.Less(t, maxClaimableAmountPerSupplier, numTokensClaimed) + + // Assert that app module balance is *decreased* by the appropriate amount + // NB: The application module account burns the amount of uPOKT that was held in escrow + // on behalf of the applications which were serviced in a given session. + expectedAppModuleEndBalance := appModuleStartBalance.Sub(sdk.NewCoin(volatile.DenomuPOKT, expectedAppBurn)) appModuleEndBalance := getBalance(t, ctx, keepers, appModuleAddress) - expectedAppModuleEndBalance := appModuleStartBalance.Sub(appStake) require.NotNil(t, appModuleEndBalance) require.EqualValues(t, &expectedAppModuleEndBalance, appModuleEndBalance) - // Assert that `supplierOwnerAddress` account balance has *increased* by the appropriate amount - supplierOwnerEndBalance := getBalance(t, ctx, keepers, supplier.GetOwnerAddress()) - require.NotNil(t, supplierOwnerEndBalance) - - expectedSupplierBalance := supplierOwnerStartBalance.Add(expectedAppBurn) - require.EqualValues(t, &expectedSupplierBalance, supplierOwnerEndBalance) - // Assert that `supplierOperatorAddress` staked balance is *unchanged* supplier, supplierIsFound := keepers.GetSupplier(ctx, supplier.GetOperatorAddress()) require.True(t, supplierIsFound) require.Equal(t, &supplierStake, supplier.GetStake()) // Assert that `suppliertypes.ModuleName` account module balance is *unchanged* + // NB: Supplier rewards are minted to the supplier module account but then immediately + // distributed to the supplier accounts which provided service in a given session. supplierModuleEndBalance := getBalance(t, ctx, keepers, supplierModuleAddress) require.EqualValues(t, supplierModuleStartBalance, supplierModuleEndBalance) + // Assert that the supplier shareholders account balances have *increased* by + // the appropriate amount w.r.t token distribution. + shareAmounts := tokenomicskeeper.GetShareAmountMap(supplierRevShares, expectedAppBurn.Uint64()) + for shareHolderAddr, expectedShareAmount := range shareAmounts { + shareHolderBalance := getBalance(t, ctx, keepers, shareHolderAddr) + require.Equal(t, int64(expectedShareAmount), shareHolderBalance.Amount.Int64()) + } + // Check that the expected burn >> effective burn because application is overserviced - // events := sdkCtx.EventManager().Events() - // relayMiningEvents := testutilevents.FilterEvents[*tokenomicstypes.EventRelayMiningDifficultyUpdated](t, - // events, "poktroll.tokenomics.EventRelayMiningDifficultyUpdated") - // require.Len(t, relayMiningEvents, 1, "unexpected number of relay mining difficulty updated events") - // relayMiningEvent := relayMiningEvents[0] - // require.Equal(t, "svc1", relayMiningEvent.ServiceId) + sdkCtx := sdk.UnwrapSDKContext(ctx) + events := sdkCtx.EventManager().Events() + appOverservicedEvents := testutilevents.FilterEvents[*tokenomicstypes.EventApplicationOverserviced](t, + events, "poktroll.tokenomics.EventApplicationOverserviced") + require.Len(t, appOverservicedEvents, 1, "unexpected number of event overserviced events") + appOverservicedEvent := appOverservicedEvents[0] events := cosmostypes.UnwrapSDKContext(ctx).EventManager().Events() appAddrAttribute, _ := events.GetAttributes("application_addr") @@ -313,7 +325,7 @@ func TestProcessTokenLogicModules_AppStakeTooLow(t *testing.T) { err = json.Unmarshal([]byte(effectiveBurnAttribute[0].Value), &effectiveBurnEventCoin) require.NoError(t, err) - require.EqualValues(t, expectedAppBurn, expectedBurnEventCoin) + // require.EqualValues(t, expectedAppBurn, expectedBurnEventCoin) require.Greater(t, expectedBurnEventCoin.Amount.Uint64(), effectiveBurnEventCoin.Amount.Uint64()) } From 8663fac6cf2573347699e956edb9c168e6c17b73 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Sun, 25 Aug 2024 13:00:54 -0400 Subject: [PATCH 10/53] Finished implementing TestProcessTokenLogicModules_TLMBurnEqualsMint_Invalid_SupplierExceedsMaxClaimableAmount --- api/poktroll/tokenomics/event.pulsar.go | 127 +++++++++--------- proto/poktroll/tokenomics/event.proto | 8 +- x/tokenomics/keeper/token_logic_modules.go | 28 +++- .../keeper/token_logic_modules_test.go | 105 +++++++-------- x/tokenomics/types/event.pb.go | 123 ++++++++--------- 5 files changed, 196 insertions(+), 195 deletions(-) diff --git a/api/poktroll/tokenomics/event.pulsar.go b/api/poktroll/tokenomics/event.pulsar.go index 25caeaa82..944d6be99 100644 --- a/api/poktroll/tokenomics/event.pulsar.go +++ b/api/poktroll/tokenomics/event.pulsar.go @@ -1818,18 +1818,18 @@ func (x *fastReflection_EventRelayMiningDifficultyUpdated) ProtoMethods() *proto } var ( - md_EventApplicationOverserviced protoreflect.MessageDescriptor - fd_EventApplicationOverserviced_application_addr protoreflect.FieldDescriptor - fd_EventApplicationOverserviced_supplier_addr protoreflect.FieldDescriptor - fd_EventApplicationOverserviced_expected_burn protoreflect.FieldDescriptor - fd_EventApplicationOverserviced_effective_burn protoreflect.FieldDescriptor + md_EventApplicationOverserviced protoreflect.MessageDescriptor + fd_EventApplicationOverserviced_application_addr protoreflect.FieldDescriptor + fd_EventApplicationOverserviced_supplier_operator_addr protoreflect.FieldDescriptor + fd_EventApplicationOverserviced_expected_burn protoreflect.FieldDescriptor + fd_EventApplicationOverserviced_effective_burn protoreflect.FieldDescriptor ) func init() { file_poktroll_tokenomics_event_proto_init() md_EventApplicationOverserviced = File_poktroll_tokenomics_event_proto.Messages().ByName("EventApplicationOverserviced") fd_EventApplicationOverserviced_application_addr = md_EventApplicationOverserviced.Fields().ByName("application_addr") - fd_EventApplicationOverserviced_supplier_addr = md_EventApplicationOverserviced.Fields().ByName("supplier_addr") + fd_EventApplicationOverserviced_supplier_operator_addr = md_EventApplicationOverserviced.Fields().ByName("supplier_operator_addr") fd_EventApplicationOverserviced_expected_burn = md_EventApplicationOverserviced.Fields().ByName("expected_burn") fd_EventApplicationOverserviced_effective_burn = md_EventApplicationOverserviced.Fields().ByName("effective_burn") } @@ -1905,9 +1905,9 @@ func (x *fastReflection_EventApplicationOverserviced) Range(f func(protoreflect. return } } - if x.SupplierAddr != "" { - value := protoreflect.ValueOfString(x.SupplierAddr) - if !f(fd_EventApplicationOverserviced_supplier_addr, value) { + if x.SupplierOperatorAddr != "" { + value := protoreflect.ValueOfString(x.SupplierOperatorAddr) + if !f(fd_EventApplicationOverserviced_supplier_operator_addr, value) { return } } @@ -1940,8 +1940,8 @@ func (x *fastReflection_EventApplicationOverserviced) Has(fd protoreflect.FieldD switch fd.FullName() { case "poktroll.tokenomics.EventApplicationOverserviced.application_addr": return x.ApplicationAddr != "" - case "poktroll.tokenomics.EventApplicationOverserviced.supplier_addr": - return x.SupplierAddr != "" + case "poktroll.tokenomics.EventApplicationOverserviced.supplier_operator_addr": + return x.SupplierOperatorAddr != "" case "poktroll.tokenomics.EventApplicationOverserviced.expected_burn": return x.ExpectedBurn != nil case "poktroll.tokenomics.EventApplicationOverserviced.effective_burn": @@ -1964,8 +1964,8 @@ func (x *fastReflection_EventApplicationOverserviced) Clear(fd protoreflect.Fiel switch fd.FullName() { case "poktroll.tokenomics.EventApplicationOverserviced.application_addr": x.ApplicationAddr = "" - case "poktroll.tokenomics.EventApplicationOverserviced.supplier_addr": - x.SupplierAddr = "" + case "poktroll.tokenomics.EventApplicationOverserviced.supplier_operator_addr": + x.SupplierOperatorAddr = "" case "poktroll.tokenomics.EventApplicationOverserviced.expected_burn": x.ExpectedBurn = nil case "poktroll.tokenomics.EventApplicationOverserviced.effective_burn": @@ -1989,8 +1989,8 @@ func (x *fastReflection_EventApplicationOverserviced) Get(descriptor protoreflec case "poktroll.tokenomics.EventApplicationOverserviced.application_addr": value := x.ApplicationAddr return protoreflect.ValueOfString(value) - case "poktroll.tokenomics.EventApplicationOverserviced.supplier_addr": - value := x.SupplierAddr + case "poktroll.tokenomics.EventApplicationOverserviced.supplier_operator_addr": + value := x.SupplierOperatorAddr return protoreflect.ValueOfString(value) case "poktroll.tokenomics.EventApplicationOverserviced.expected_burn": value := x.ExpectedBurn @@ -2020,8 +2020,8 @@ func (x *fastReflection_EventApplicationOverserviced) Set(fd protoreflect.FieldD switch fd.FullName() { case "poktroll.tokenomics.EventApplicationOverserviced.application_addr": x.ApplicationAddr = value.Interface().(string) - case "poktroll.tokenomics.EventApplicationOverserviced.supplier_addr": - x.SupplierAddr = value.Interface().(string) + case "poktroll.tokenomics.EventApplicationOverserviced.supplier_operator_addr": + x.SupplierOperatorAddr = value.Interface().(string) case "poktroll.tokenomics.EventApplicationOverserviced.expected_burn": x.ExpectedBurn = value.Message().Interface().(*v1beta1.Coin) case "poktroll.tokenomics.EventApplicationOverserviced.effective_burn": @@ -2058,8 +2058,8 @@ func (x *fastReflection_EventApplicationOverserviced) Mutable(fd protoreflect.Fi return protoreflect.ValueOfMessage(x.EffectiveBurn.ProtoReflect()) case "poktroll.tokenomics.EventApplicationOverserviced.application_addr": panic(fmt.Errorf("field application_addr of message poktroll.tokenomics.EventApplicationOverserviced is not mutable")) - case "poktroll.tokenomics.EventApplicationOverserviced.supplier_addr": - panic(fmt.Errorf("field supplier_addr of message poktroll.tokenomics.EventApplicationOverserviced is not mutable")) + case "poktroll.tokenomics.EventApplicationOverserviced.supplier_operator_addr": + panic(fmt.Errorf("field supplier_operator_addr of message poktroll.tokenomics.EventApplicationOverserviced is not mutable")) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.tokenomics.EventApplicationOverserviced")) @@ -2075,7 +2075,7 @@ func (x *fastReflection_EventApplicationOverserviced) NewField(fd protoreflect.F switch fd.FullName() { case "poktroll.tokenomics.EventApplicationOverserviced.application_addr": return protoreflect.ValueOfString("") - case "poktroll.tokenomics.EventApplicationOverserviced.supplier_addr": + case "poktroll.tokenomics.EventApplicationOverserviced.supplier_operator_addr": return protoreflect.ValueOfString("") case "poktroll.tokenomics.EventApplicationOverserviced.expected_burn": m := new(v1beta1.Coin) @@ -2156,7 +2156,7 @@ func (x *fastReflection_EventApplicationOverserviced) ProtoMethods() *protoiface if l > 0 { n += 1 + l + runtime.Sov(uint64(l)) } - l = len(x.SupplierAddr) + l = len(x.SupplierOperatorAddr) if l > 0 { n += 1 + l + runtime.Sov(uint64(l)) } @@ -2225,10 +2225,10 @@ func (x *fastReflection_EventApplicationOverserviced) ProtoMethods() *protoiface i-- dAtA[i] = 0x1a } - if len(x.SupplierAddr) > 0 { - i -= len(x.SupplierAddr) - copy(dAtA[i:], x.SupplierAddr) - i = runtime.EncodeVarint(dAtA, i, uint64(len(x.SupplierAddr))) + if len(x.SupplierOperatorAddr) > 0 { + i -= len(x.SupplierOperatorAddr) + copy(dAtA[i:], x.SupplierOperatorAddr) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.SupplierOperatorAddr))) i-- dAtA[i] = 0x12 } @@ -2322,7 +2322,7 @@ func (x *fastReflection_EventApplicationOverserviced) ProtoMethods() *protoiface iNdEx = postIndex case 2: if wireType != 2 { - return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field SupplierAddr", wireType) + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field SupplierOperatorAddr", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -2350,7 +2350,7 @@ func (x *fastReflection_EventApplicationOverserviced) ProtoMethods() *protoiface if postIndex > l { return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF } - x.SupplierAddr = string(dAtA[iNdEx:postIndex]) + x.SupplierOperatorAddr = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 3: if wireType != 2 { @@ -2721,16 +2721,16 @@ type EventApplicationOverserviced struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - ApplicationAddr string `protobuf:"bytes,1,opt,name=application_addr,json=applicationAddr,proto3" json:"application_addr,omitempty"` - SupplierAddr string `protobuf:"bytes,2,opt,name=supplier_addr,json=supplierAddr,proto3" json:"supplier_addr,omitempty"` + ApplicationAddr string `protobuf:"bytes,1,opt,name=application_addr,json=applicationAddr,proto3" json:"application_addr,omitempty"` + SupplierOperatorAddr string `protobuf:"bytes,2,opt,name=supplier_operator_addr,json=supplierOperatorAddr,proto3" json:"supplier_operator_addr,omitempty"` // Expected burn is the amount the supplier is claiming for work done // to service the application during the session. - // This is usually the amount in the Claim object. + // This is usually the amount in the Claim submitted. ExpectedBurn *v1beta1.Coin `protobuf:"bytes,3,opt,name=expected_burn,json=expectedBurn,proto3" json:"expected_burn,omitempty"` // Effective burn is the amount that is actually being paid to the supplier // for the work done. It is less than the expected burn (claim amount) and - // most likely equal to the application's stake divided by the number of suppliers - // in a session. + // is a function of the relay mining algorithm. + // E.g. Te application's stake divided by the number of suppliers in a session. EffectiveBurn *v1beta1.Coin `protobuf:"bytes,4,opt,name=effective_burn,json=effectiveBurn,proto3" json:"effective_burn,omitempty"` } @@ -2761,9 +2761,9 @@ func (x *EventApplicationOverserviced) GetApplicationAddr() string { return "" } -func (x *EventApplicationOverserviced) GetSupplierAddr() string { +func (x *EventApplicationOverserviced) GetSupplierOperatorAddr() string { if x != nil { - return x.SupplierAddr + return x.SupplierOperatorAddr } return "" } @@ -2849,40 +2849,41 @@ var file_poktroll_tokenomics_event_proto_rawDesc = []byte{ 0x61, 0x79, 0x73, 0x45, 0x6d, 0x61, 0x12, 0x2b, 0x0a, 0x12, 0x6e, 0x65, 0x77, 0x5f, 0x6e, 0x75, 0x6d, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x73, 0x5f, 0x65, 0x6d, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x6e, 0x65, 0x77, 0x4e, 0x75, 0x6d, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x73, - 0x45, 0x6d, 0x61, 0x22, 0xf0, 0x01, 0x0a, 0x1c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x41, 0x70, 0x70, + 0x45, 0x6d, 0x61, 0x22, 0x81, 0x02, 0x0a, 0x1c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x64, 0x12, 0x29, 0x0a, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x12, - 0x23, 0x0a, 0x0d, 0x73, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, - 0x41, 0x64, 0x64, 0x72, 0x12, 0x3e, 0x0a, 0x0d, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, - 0x5f, 0x62, 0x75, 0x72, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, - 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, - 0x31, 0x2e, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x0c, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, - 0x42, 0x75, 0x72, 0x6e, 0x12, 0x40, 0x0a, 0x0e, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, - 0x65, 0x5f, 0x62, 0x75, 0x72, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, + 0x34, 0x0a, 0x16, 0x73, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x5f, 0x6f, 0x70, 0x65, 0x72, + 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x14, 0x73, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, + 0x72, 0x41, 0x64, 0x64, 0x72, 0x12, 0x3e, 0x0a, 0x0d, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, + 0x64, 0x5f, 0x62, 0x75, 0x72, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, - 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x0d, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, - 0x76, 0x65, 0x42, 0x75, 0x72, 0x6e, 0x2a, 0x60, 0x0a, 0x15, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x45, - 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, - 0x21, 0x0a, 0x1d, 0x45, 0x58, 0x50, 0x49, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x52, 0x45, - 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, - 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x52, 0x4f, 0x4f, 0x46, 0x5f, 0x4d, 0x49, 0x53, 0x53, - 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x52, 0x4f, 0x4f, 0x46, 0x5f, 0x49, - 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x02, 0x42, 0xb8, 0x01, 0x0a, 0x17, 0x63, 0x6f, 0x6d, - 0x2e, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, - 0x6d, 0x69, 0x63, 0x73, 0x42, 0x0a, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, - 0x50, 0x01, 0x5a, 0x24, 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, 0x74, 0x6f, - 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0xa2, 0x02, 0x03, 0x50, 0x54, 0x58, 0xaa, 0x02, - 0x13, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, - 0x6d, 0x69, 0x63, 0x73, 0xca, 0x02, 0x13, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, - 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0xe2, 0x02, 0x1f, 0x50, 0x6f, 0x6b, - 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, - 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x14, 0x50, - 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x3a, 0x3a, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, - 0x69, 0x63, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x0c, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, + 0x64, 0x42, 0x75, 0x72, 0x6e, 0x12, 0x40, 0x0a, 0x0e, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, + 0x76, 0x65, 0x5f, 0x62, 0x75, 0x72, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, + 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, + 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x0d, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, + 0x69, 0x76, 0x65, 0x42, 0x75, 0x72, 0x6e, 0x2a, 0x60, 0x0a, 0x15, 0x43, 0x6c, 0x61, 0x69, 0x6d, + 0x45, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, + 0x12, 0x21, 0x0a, 0x1d, 0x45, 0x58, 0x50, 0x49, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x52, + 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, + 0x44, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x52, 0x4f, 0x4f, 0x46, 0x5f, 0x4d, 0x49, 0x53, + 0x53, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x52, 0x4f, 0x4f, 0x46, 0x5f, + 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x02, 0x42, 0xb8, 0x01, 0x0a, 0x17, 0x63, 0x6f, + 0x6d, 0x2e, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x74, 0x6f, 0x6b, 0x65, 0x6e, + 0x6f, 0x6d, 0x69, 0x63, 0x73, 0x42, 0x0a, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x74, + 0x6f, 0x50, 0x01, 0x5a, 0x24, 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, 0x74, + 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0xa2, 0x02, 0x03, 0x50, 0x54, 0x58, 0xaa, + 0x02, 0x13, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, + 0x6f, 0x6d, 0x69, 0x63, 0x73, 0xca, 0x02, 0x13, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, + 0x5c, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0xe2, 0x02, 0x1f, 0x50, 0x6f, + 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, + 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x14, + 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x3a, 0x3a, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, + 0x6d, 0x69, 0x63, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/proto/poktroll/tokenomics/event.proto b/proto/poktroll/tokenomics/event.proto index 9b07d8ae1..a536a1ae6 100644 --- a/proto/poktroll/tokenomics/event.proto +++ b/proto/poktroll/tokenomics/event.proto @@ -47,14 +47,14 @@ message EventRelayMiningDifficultyUpdated { // what a supplier is claiming (i.e. burn is not high enough). message EventApplicationOverserviced { string application_addr = 1; - string supplier_addr = 2; + string supplier_operator_addr = 2; // Expected burn is the amount the supplier is claiming for work done // to service the application during the session. - // This is usually the amount in the Claim object. + // This is usually the amount in the Claim submitted. cosmos.base.v1beta1.Coin expected_burn = 3; // Effective burn is the amount that is actually being paid to the supplier // for the work done. It is less than the expected burn (claim amount) and - // most likely equal to the application's stake divided by the number of suppliers - // in a session. + // is a function of the relay mining algorithm. + // E.g. Te application's stake divided by the number of suppliers in a session. cosmos.base.v1beta1.Coin effective_burn = 4; } \ No newline at end of file diff --git a/x/tokenomics/keeper/token_logic_modules.go b/x/tokenomics/keeper/token_logic_modules.go index 33f24e618..2d0a4aabc 100644 --- a/x/tokenomics/keeper/token_logic_modules.go +++ b/x/tokenomics/keeper/token_logic_modules.go @@ -37,6 +37,15 @@ const ( MintAllocationSupplier = 0.7 MintAllocationSourceOwner = 0.15 MintAllocationApplication = 0.0 + + // The percent difference that is allowable between the number of minted + // tokens in the tokenomics module and what is distributed to pocket network + // participants. + // This internal constant SHOULD ONLY be used in TokenLogicModuleGlobalMint. + // Due to floating point arithmetic, the total amount of minted coins may be slightly + // larger than what is distributed to pocket network participants + // TODO_MAINNET: Figure out if we can avoid this tolerance and use fixed point arithmetic. + mintDistributionAllowableTolerance = 0.02 ) type TokenLogicModule int @@ -155,6 +164,9 @@ func (k Keeper) ProcessTokenLogicModules( if err != nil { return tokenomicstypes.ErrTokenomicsRootHashInvalid.Wrapf("%v", err) } + if numRelays == 0 { + return tokenomicstypes.ErrTokenomicsRootHashInvalid.Wrap("root hash has zero relays") + } /* TODO_POST_MAINNET: Because of how things have evolved, we are now using @@ -343,6 +355,8 @@ func (k Keeper) TokenLogicModuleGlobalMint( // Determine how much new uPOKT to mint based on global inflation newMintCoin, newMintAmtFloat := calculateGlobalPerClaimMintInflationFromSettlementAmount(settlementCoin) + fmt.Println("OLSH ", newMintCoin, MintPerClaimGlobalInflation, settlementCoin) + // Mint new uPOKT to the tokenomics module account if err := k.bankKeeper.MintCoins(ctx, tokenomictypes.ModuleName, sdk.NewCoins(newMintCoin)); err != nil { return tokenomicstypes.ErrTokenomicsModuleMintFailed.Wrapf( @@ -406,11 +420,11 @@ func (k Keeper) TokenLogicModuleGlobalMint( coinDifference := new(big.Int).Sub(totalMintDistributedCoin.Amount.BigInt(), newMintCoin.Amount.BigInt()) coinDifference = coinDifference.Abs(coinDifference) percentDifference := new(big.Float).Quo(new(big.Float).SetInt(coinDifference), new(big.Float).SetInt(newMintCoin.Amount.BigInt())) - if percentDifference.Cmp(big.NewFloat(0.01)) > 0 { + if percentDifference.Cmp(big.NewFloat(mintDistributionAllowableTolerance)) > 0 { return tokenomictypes.ErrTokenomicsAmountMismatchTooLarge.Wrapf( - "the total distributed coins (%v) do not equal the amount of new minted coins (%v). Likely floating point arithmetic.\n"+ + "the total distributed coins (%v) do not equal the amount of newly minted coins (%v) with a percent difference of (%f). Likely floating point arithmetic.\n"+ "appCoin: %v, supplierCoin: %v, daoCoin: %v, serviceCoin: %v, proposerCoin: %v", - totalMintDistributedCoin, newMintCoin, + totalMintDistributedCoin, newMintCoin, percentDifference, appCoin, supplierCoin, daoCoin, serviceCoin, proposerCoin) } else if coinDifference.Cmp(big.NewInt(0)) > 0 { logger.Warn(fmt.Sprintf("Floating point arithmetic led to a discrepancy of %v (%f) between the total distributed coins (%v) and the amount of new minted coins (%v).\n"+ @@ -497,10 +511,10 @@ func (k Keeper) ensureClaimAmountLimits( // Prepare and emit the event for the application being overserviced applicationOverservicedEvent := &tokenomicstypes.EventApplicationOverserviced{ - ApplicationAddr: application.Address, - SupplierAddr: supplier.OperatorAddress, - ExpectedBurn: &claimSettlementCoin, - EffectiveBurn: &maxClaimableCoin, + ApplicationAddr: application.Address, + SupplierOperatorAddr: supplier.OperatorAddress, + ExpectedBurn: &claimSettlementCoin, + EffectiveBurn: &maxClaimableCoin, } eventManager := cosmostypes.UnwrapSDKContext(ctx).EventManager() if err := eventManager.EmitTypedEvent(applicationOverservicedEvent); err != nil { diff --git a/x/tokenomics/keeper/token_logic_modules_test.go b/x/tokenomics/keeper/token_logic_modules_test.go index 4bae90d8e..6174ca72c 100644 --- a/x/tokenomics/keeper/token_logic_modules_test.go +++ b/x/tokenomics/keeper/token_logic_modules_test.go @@ -7,7 +7,6 @@ import ( "testing" "cosmossdk.io/math" - "github.com/cometbft/cometbft/libs/json" cosmostypes "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -37,36 +36,25 @@ func init() { cmd.InitSDKConfig() } -// TODO_IN_THIS_PR: Add these tests or update existing tests to account for it. -// func TestProcessTokenLogicModules_HandleMaxClaimGreaterActualClaim(t *testing.T) {...} -// TODO_UPNEXT(@olshansk, #732): Add the following tests -// func TestProcessTokenLogicModules_ValidateAppOverServicingEvent(t *testing.T) {...} -// func TestProcessTokenLogicModules_ValidateAppReimbursedRequestEvent(t *testing.T) {...} - -func TestProcessTokenLogicModules_TLMBurnEqualsMintValid(t *testing.T) { +func TestProcessTokenLogicModules_TLMBurnEqualsMint_Valid(t *testing.T) { // Test Parameters appInitialStake := math.NewInt(1000000) supplierInitialStake := math.NewInt(1000000) supplierRevShareRatios := []float32{12.5, 37.5, 50} globalComputeUnitsToTokensMultiplier := uint64(1) serviceComputeUnitsPerRelay := uint64(1) + service := prepareTestService(serviceComputeUnitsPerRelay) numRelays := uint64(1000) // By supplier for application in this session + // Prepare the keepers + keepers, ctx := testkeeper.NewTokenomicsModuleKeepers(t, nil, testkeeper.WithService(*service)) + keepers.SetService(ctx, *service) + // Ensure the claim is within relay mining bounds numTokensClaimed := int64(numRelays * serviceComputeUnitsPerRelay * globalComputeUnitsToTokensMultiplier) maxClaimableAmountPerSupplier := appInitialStake.Quo(math.NewInt(sessionkeeper.NumSupplierPerSession)) require.GreaterOrEqual(t, maxClaimableAmountPerSupplier.Int64(), numTokensClaimed) - // Create a service that can be registered in the application and used in the claims - service := &sharedtypes.Service{ - Id: "svc1", - Name: "svcName1", - ComputeUnitsPerRelay: serviceComputeUnitsPerRelay, - OwnerAddress: sample.AccAddress(), - } - keepers, ctx := testkeeper.NewTokenomicsModuleKeepers(t, nil, testkeeper.WithService(*service)) - keepers.SetService(ctx, *service) - // Retrieve the app and supplier module addresses appModuleAddress := authtypes.NewModuleAddress(apptypes.ModuleName).String() supplierModuleAddress := authtypes.NewModuleAddress(suppliertypes.ModuleName).String() @@ -120,7 +108,7 @@ func TestProcessTokenLogicModules_TLMBurnEqualsMintValid(t *testing.T) { supplierModuleStartBalance := getBalance(t, ctx, keepers, supplierModuleAddress) // Prepare the claim for which the supplier did work for the application - claim := prepareClaim(numRelays, service, &app, &supplier) + claim := prepareTestClaim(numRelays, service, &app, &supplier) // Process the token logic modules err = keepers.ProcessTokenLogicModules(ctx, &claim) @@ -131,8 +119,8 @@ func TestProcessTokenLogicModules_TLMBurnEqualsMintValid(t *testing.T) { require.EqualValues(t, appStartBalance, appEndBalance) // Determine the expected app end stake amount and the expected app burn - expectedAppBurn := math.NewInt(numTokensClaimed) - expectedAppEndStakeAmount := appInitialStake.Sub(expectedAppBurn) + appBurn := math.NewInt(numTokensClaimed) + expectedAppEndStakeAmount := appInitialStake.Sub(appBurn) // Assert that `applicationAddress` staked balance has decreased by the appropriate amount app, appIsFound := keepers.GetApplication(ctx, app.GetAddress()) @@ -143,7 +131,7 @@ func TestProcessTokenLogicModules_TLMBurnEqualsMintValid(t *testing.T) { // Assert that app module balance is *decreased* by the appropriate amount // NB: The application module account burns the amount of uPOKT that was held in escrow // on behalf of the applications which were serviced in a given session. - expectedAppModuleEndBalance := appModuleStartBalance.Sub(sdk.NewCoin(volatile.DenomuPOKT, expectedAppBurn)) + expectedAppModuleEndBalance := appModuleStartBalance.Sub(sdk.NewCoin(volatile.DenomuPOKT, appBurn)) appModuleEndBalance := getBalance(t, ctx, keepers, appModuleAddress) require.NotNil(t, appModuleEndBalance) require.EqualValues(t, &expectedAppModuleEndBalance, appModuleEndBalance) @@ -161,7 +149,7 @@ func TestProcessTokenLogicModules_TLMBurnEqualsMintValid(t *testing.T) { // Assert that the supplier shareholders account balances have *increased* by // the appropriate amount w.r.t token distribution. - shareAmounts := tokenomicskeeper.GetShareAmountMap(supplierRevShares, expectedAppBurn.Uint64()) + shareAmounts := tokenomicskeeper.GetShareAmountMap(supplierRevShares, appBurn.Uint64()) for shareHolderAddr, expectedShareAmount := range shareAmounts { shareHolderBalance := getBalance(t, ctx, keepers, shareHolderAddr) require.Equal(t, int64(expectedShareAmount), shareHolderBalance.Amount.Int64()) @@ -171,14 +159,19 @@ func TestProcessTokenLogicModules_TLMBurnEqualsMintValid(t *testing.T) { // DEV_NOTE: Most of the setup here is a copy-paste of TLMBurnEqualsMintValid // except that the application stake is calculated to explicitly be too low to // handle all the relays completed. -func TestProcessTokenLogicModules_TLMBurnEqualsMintInvalid_SupplierExceedsMaxClaimableAmount(t *testing.T) { +func TestProcessTokenLogicModules_TLMBurnEqualsMint_Invalid_SupplierExceedsMaxClaimableAmount(t *testing.T) { // Test Parameters globalComputeUnitsToTokensMultiplier := uint64(1) serviceComputeUnitsPerRelay := uint64(1) + service := prepareTestService(serviceComputeUnitsPerRelay) numRelays := uint64(1000) // By a single supplier for application in this session supplierInitialStake := math.NewInt(1000000) supplierRevShareRatios := []float32{12.5, 37.5, 50} + // Prepare the keepers + keepers, ctx := testkeeper.NewTokenomicsModuleKeepers(t, nil, testkeeper.WithService(*service)) + keepers.SetService(ctx, *service) + // Set up the relays to exceed the max claimable amount // Determine the max a supplier can claim maxClaimableAmountPerSupplier := int64(numRelays * serviceComputeUnitsPerRelay * globalComputeUnitsToTokensMultiplier) @@ -189,16 +182,6 @@ func TestProcessTokenLogicModules_TLMBurnEqualsMintInvalid_SupplierExceedsMaxCla numRelays *= 5 numTokensClaimed := int64(numRelays * serviceComputeUnitsPerRelay * globalComputeUnitsToTokensMultiplier) - // Create a service that can be registered in the application and used in the claims - service := &sharedtypes.Service{ - Id: "svc1", - Name: "svcName1", - ComputeUnitsPerRelay: serviceComputeUnitsPerRelay, - OwnerAddress: sample.AccAddress(), - } - keepers, ctx := testkeeper.NewTokenomicsModuleKeepers(t, nil, testkeeper.WithService(*service)) - keepers.SetService(ctx, *service) - // Retrieve the app and supplier module addresses appModuleAddress := authtypes.NewModuleAddress(apptypes.ModuleName).String() supplierModuleAddress := authtypes.NewModuleAddress(suppliertypes.ModuleName).String() @@ -252,7 +235,7 @@ func TestProcessTokenLogicModules_TLMBurnEqualsMintInvalid_SupplierExceedsMaxCla supplierModuleStartBalance := getBalance(t, ctx, keepers, supplierModuleAddress) // Prepare the claim for which the supplier did work for the application - claim := prepareClaim(numRelays, service, &app, &supplier) + claim := prepareTestClaim(numRelays, service, &app, &supplier) // Process the token logic modules err = keepers.ProcessTokenLogicModules(ctx, &claim) @@ -263,8 +246,9 @@ func TestProcessTokenLogicModules_TLMBurnEqualsMintInvalid_SupplierExceedsMaxCla require.EqualValues(t, appStartBalance, appEndBalance) // Determine the expected app end stake amount and the expected app burn - expectedAppBurn := math.NewInt(maxClaimableAmountPerSupplier) - expectedAppEndStakeAmount := appInitialStake.Sub(expectedAppBurn) + appBurn := math.NewInt(maxClaimableAmountPerSupplier) + appBurnCoin := sdk.NewCoin(volatile.DenomuPOKT, appBurn) + expectedAppEndStakeAmount := appInitialStake.Sub(appBurn) // Assert that `applicationAddress` staked balance has decreased by the max claimable amount app, appIsFound := keepers.GetApplication(ctx, app.GetAddress()) @@ -278,7 +262,7 @@ func TestProcessTokenLogicModules_TLMBurnEqualsMintInvalid_SupplierExceedsMaxCla // Assert that app module balance is *decreased* by the appropriate amount // NB: The application module account burns the amount of uPOKT that was held in escrow // on behalf of the applications which were serviced in a given session. - expectedAppModuleEndBalance := appModuleStartBalance.Sub(sdk.NewCoin(volatile.DenomuPOKT, expectedAppBurn)) + expectedAppModuleEndBalance := appModuleStartBalance.Sub(appBurnCoin) appModuleEndBalance := getBalance(t, ctx, keepers, appModuleAddress) require.NotNil(t, appModuleEndBalance) require.EqualValues(t, &expectedAppModuleEndBalance, appModuleEndBalance) @@ -296,7 +280,7 @@ func TestProcessTokenLogicModules_TLMBurnEqualsMintInvalid_SupplierExceedsMaxCla // Assert that the supplier shareholders account balances have *increased* by // the appropriate amount w.r.t token distribution. - shareAmounts := tokenomicskeeper.GetShareAmountMap(supplierRevShares, expectedAppBurn.Uint64()) + shareAmounts := tokenomicskeeper.GetShareAmountMap(supplierRevShares, appBurn.Uint64()) for shareHolderAddr, expectedShareAmount := range shareAmounts { shareHolderBalance := getBalance(t, ctx, keepers, shareHolderAddr) require.Equal(t, int64(expectedShareAmount), shareHolderBalance.Amount.Int64()) @@ -311,22 +295,14 @@ func TestProcessTokenLogicModules_TLMBurnEqualsMintInvalid_SupplierExceedsMaxCla require.Len(t, appOverservicedEvents, 1, "unexpected number of event overserviced events") appOverservicedEvent := appOverservicedEvents[0] - events := cosmostypes.UnwrapSDKContext(ctx).EventManager().Events() - appAddrAttribute, _ := events.GetAttributes("application_addr") - expectedBurnAttribute, _ := events.GetAttributes("expected_burn") - effectiveBurnAttribute, _ := events.GetAttributes("effective_burn") - - require.Equal(t, 1, len(appAddrAttribute)) - require.Equal(t, fmt.Sprintf("\"%s\"", app.GetAddress()), appAddrAttribute[0].Value) - - var expectedBurnEventCoin, effectiveBurnEventCoin cosmostypes.Coin - err = json.Unmarshal([]byte(expectedBurnAttribute[0].Value), &expectedBurnEventCoin) - require.NoError(t, err) - err = json.Unmarshal([]byte(effectiveBurnAttribute[0].Value), &effectiveBurnEventCoin) - require.NoError(t, err) + require.Equal(t, app.GetAddress(), appOverservicedEvent.ApplicationAddr) + require.Equal(t, supplier.GetOperatorAddress(), appOverservicedEvent.SupplierOperatorAddr) + require.Equal(t, numTokensClaimed, appOverservicedEvent.ExpectedBurn.Amount.Int64()) + require.Equal(t, appBurn, appOverservicedEvent.EffectiveBurn.Amount) + require.Less(t, appBurn.Int64(), numTokensClaimed) +} - // require.EqualValues(t, expectedAppBurn, expectedBurnEventCoin) - require.Greater(t, expectedBurnEventCoin.Amount.Uint64(), effectiveBurnEventCoin.Amount.Uint64()) +func TestProcessTokenLogicModules_TLMGlobalMint_Valid_CorrectMintDistribution(t *testing.T) { } func TestProcessTokenLogicModules_AppNotFound(t *testing.T) { @@ -361,10 +337,8 @@ func TestProcessTokenLogicModules_ServiceNotFound(t *testing.T) { claim := prooftypes.Claim{ SupplierOperatorAddress: supplierOperatorAddr, SessionHeader: &sessiontypes.SessionHeader{ - ApplicationAddress: appAddr, - Service: &sharedtypes.Service{ - Id: "non_existent_svc", - }, + ApplicationAddress: appAddr, + Service: &sharedtypes.Service{Id: "non_existent_svc"}, SessionId: "session_id", SessionStartBlockHeight: 1, SessionEndBlockHeight: testsession.GetSessionEndHeightWithDefaultParams(1), @@ -410,7 +384,7 @@ func TestProcessTokenLogicModules_InvalidRoot(t *testing.T) { root := make([]byte, protocol.TrieRootSize) // All 0s return root[:] }(), - errExpected: false, + errExpected: true, }, { desc: "correct size but invalid value", @@ -541,7 +515,9 @@ func TestProcessTokenLogicModules_InvalidClaim(t *testing.T) { } } -func prepareClaim( +// prepareTestClaim uses the given number of relays and compute unit per relay in the +// service provided to set up the test claim correctly. +func prepareTestClaim( numRelays uint64, service *sharedtypes.Service, app *apptypes.Application, @@ -559,7 +535,16 @@ func prepareClaim( }, RootHash: testproof.SmstRootWithSumAndCount(numComputeUnits, numRelays), } +} +// prepareTestService creates a service with the given compute units per relay. +func prepareTestService(serviceComputeUnitsPerRelay uint64) *sharedtypes.Service { + return &sharedtypes.Service{ + Id: "svc1", + Name: "svcName1", + ComputeUnitsPerRelay: serviceComputeUnitsPerRelay, + OwnerAddress: sample.AccAddress(), + } } func getBalance( diff --git a/x/tokenomics/types/event.pb.go b/x/tokenomics/types/event.pb.go index 648c6afbb..24d3052c8 100644 --- a/x/tokenomics/types/event.pb.go +++ b/x/tokenomics/types/event.pb.go @@ -276,16 +276,16 @@ func (m *EventRelayMiningDifficultyUpdated) GetNewNumRelaysEma() uint64 { // EventApplicationOverserviced is emitted when an application has less stake than // what a supplier is claiming (i.e. burn is not high enough). type EventApplicationOverserviced struct { - ApplicationAddr string `protobuf:"bytes,1,opt,name=application_addr,json=applicationAddr,proto3" json:"application_addr,omitempty"` - SupplierAddr string `protobuf:"bytes,2,opt,name=supplier_addr,json=supplierAddr,proto3" json:"supplier_addr,omitempty"` + ApplicationAddr string `protobuf:"bytes,1,opt,name=application_addr,json=applicationAddr,proto3" json:"application_addr,omitempty"` + SupplierOperatorAddr string `protobuf:"bytes,2,opt,name=supplier_operator_addr,json=supplierOperatorAddr,proto3" json:"supplier_operator_addr,omitempty"` // Expected burn is the amount the supplier is claiming for work done // to service the application during the session. - // This is usually the amount in the Claim object. + // This is usually the amount in the Claim submitted. ExpectedBurn *types1.Coin `protobuf:"bytes,3,opt,name=expected_burn,json=expectedBurn,proto3" json:"expected_burn,omitempty"` // Effective burn is the amount that is actually being paid to the supplier // for the work done. It is less than the expected burn (claim amount) and - // most likely equal to the application's stake divided by the number of suppliers - // in a session. + // is a function of the relay mining algorithm. + // E.g. Te application's stake divided by the number of suppliers in a session. EffectiveBurn *types1.Coin `protobuf:"bytes,4,opt,name=effective_burn,json=effectiveBurn,proto3" json:"effective_burn,omitempty"` } @@ -329,9 +329,9 @@ func (m *EventApplicationOverserviced) GetApplicationAddr() string { return "" } -func (m *EventApplicationOverserviced) GetSupplierAddr() string { +func (m *EventApplicationOverserviced) GetSupplierOperatorAddr() string { if m != nil { - return m.SupplierAddr + return m.SupplierOperatorAddr } return "" } @@ -361,53 +361,54 @@ func init() { func init() { proto.RegisterFile("poktroll/tokenomics/event.proto", fileDescriptor_a78874bbf91a58c7) } var fileDescriptor_a78874bbf91a58c7 = []byte{ - // 730 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x54, 0x4d, 0x4f, 0xdb, 0x48, - 0x18, 0x8e, 0x43, 0x58, 0x29, 0x03, 0x81, 0xc4, 0x2c, 0xda, 0x2c, 0x0b, 0x09, 0x64, 0xa5, 0x15, - 0xcb, 0x0a, 0x5b, 0x80, 0xb4, 0xa7, 0x15, 0xda, 0x24, 0x98, 0xc5, 0xd2, 0x92, 0x44, 0x0e, 0x54, - 0x55, 0x2f, 0x53, 0xc7, 0x7e, 0x93, 0x4c, 0x89, 0x67, 0xdc, 0xf1, 0x38, 0x09, 0xff, 0xa2, 0x3f, - 0xa0, 0x7f, 0xa0, 0x87, 0xfe, 0x8f, 0x1e, 0x39, 0xf6, 0x84, 0x2a, 0xb8, 0x71, 0xea, 0x4f, 0xa8, - 0x3c, 0xce, 0x57, 0x03, 0x55, 0xcf, 0xbd, 0x24, 0x93, 0xe7, 0x7d, 0x9e, 0xf7, 0xe3, 0x99, 0xc9, - 0x8b, 0x8a, 0x3e, 0xbb, 0x12, 0x9c, 0xf5, 0x7a, 0xba, 0x60, 0x57, 0x40, 0x99, 0x47, 0x9c, 0x40, - 0x87, 0x3e, 0x50, 0xa1, 0xf9, 0x9c, 0x09, 0xa6, 0xae, 0x8d, 0x09, 0xda, 0x94, 0xb0, 0x51, 0x70, - 0x58, 0xe0, 0xb1, 0x40, 0x6f, 0xd9, 0x01, 0xe8, 0xfd, 0x83, 0x16, 0x08, 0xfb, 0x40, 0x77, 0x18, - 0xa1, 0xb1, 0x68, 0xe3, 0xe7, 0x0e, 0xeb, 0x30, 0x79, 0xd4, 0xa3, 0xd3, 0x08, 0xdd, 0x98, 0xd4, - 0xf2, 0x39, 0x63, 0x6d, 0x5d, 0x5c, 0xfb, 0x10, 0xc4, 0xb1, 0xd2, 0xfb, 0x24, 0xca, 0x19, 0x51, - 0xd9, 0x6a, 0xcf, 0x26, 0x9e, 0x31, 0xf4, 0x09, 0x07, 0x57, 0xfd, 0x1b, 0x2d, 0x3a, 0xd1, 0xef, - 0xbc, 0xb2, 0xad, 0xec, 0x2e, 0x1d, 0xae, 0x6b, 0x93, 0x66, 0x64, 0x06, 0x4d, 0x92, 0x2b, 0xe9, - 0x87, 0xdb, 0x62, 0xcc, 0xb3, 0xe2, 0x2f, 0x75, 0x1f, 0x21, 0x1a, 0x7a, 0x98, 0x43, 0xcf, 0xbe, - 0x0e, 0xf2, 0xc9, 0x6d, 0x65, 0x37, 0x55, 0x59, 0x79, 0xb8, 0x2d, 0xce, 0xa0, 0x56, 0x9a, 0x86, - 0x9e, 0x25, 0x8f, 0x6a, 0x19, 0xe5, 0xa2, 0x80, 0xc3, 0x3c, 0x3f, 0x14, 0x80, 0x43, 0x4a, 0x44, - 0x90, 0x5f, 0x90, 0xaa, 0xf5, 0x87, 0xdb, 0xe2, 0xe3, 0xa0, 0xb5, 0x4a, 0x43, 0xaf, 0x1a, 0x23, - 0x97, 0x11, 0xa0, 0x52, 0x94, 0x83, 0xa8, 0x69, 0x5b, 0x10, 0x46, 0x31, 0x07, 0x3b, 0x60, 0x34, - 0x9f, 0xda, 0x56, 0x76, 0x57, 0x0e, 0xf7, 0xb4, 0x27, 0x2c, 0xd4, 0xa6, 0x73, 0x4a, 0x89, 0x25, - 0x15, 0x71, 0xb9, 0x47, 0x89, 0xac, 0x2c, 0xcc, 0x11, 0x4b, 0xef, 0xbe, 0xf2, 0xab, 0x09, 0x42, - 0xf4, 0x7e, 0x28, 0xbf, 0x5e, 0xa1, 0x9c, 0x6c, 0x09, 0x73, 0x78, 0x1d, 0x12, 0x0e, 0x1e, 0x50, - 0x31, 0xf2, 0xeb, 0x8f, 0xf9, 0xae, 0x1b, 0xd1, 0xa7, 0x35, 0xe5, 0xcd, 0x7a, 0xf5, 0x28, 0x89, - 0x95, 0xf5, 0xe7, 0xe8, 0xa5, 0xb7, 0x49, 0xb4, 0x23, 0xbd, 0x92, 0xed, 0x9f, 0x13, 0x4a, 0x68, - 0xe7, 0x84, 0xb4, 0xdb, 0xc4, 0x09, 0x7b, 0xe2, 0xfa, 0xd2, 0x77, 0x6d, 0x01, 0xae, 0xba, 0x85, - 0x50, 0x00, 0xbc, 0x4f, 0x1c, 0xc0, 0xc4, 0x95, 0x06, 0xa6, 0xad, 0xf4, 0x08, 0x31, 0x5d, 0xf5, - 0x18, 0x6d, 0xfa, 0x1c, 0xfa, 0x58, 0xd8, 0xbc, 0x03, 0x02, 0x77, 0xed, 0xa0, 0x8b, 0xbb, 0x30, - 0xc4, 0x40, 0x1d, 0xe6, 0x82, 0x2b, 0x4d, 0x4b, 0x5b, 0xf9, 0x88, 0x73, 0x21, 0x29, 0x67, 0x76, - 0xd0, 0x3d, 0x83, 0xa1, 0x11, 0xc7, 0xd5, 0x7f, 0xd0, 0x6f, 0x14, 0x06, 0xdf, 0x94, 0x2f, 0x48, - 0xf9, 0x2f, 0x14, 0x06, 0x4f, 0xaa, 0xf7, 0xd1, 0x9a, 0xac, 0x3e, 0xbd, 0x0f, 0x0c, 0x9e, 0x2d, - 0x0d, 0x4b, 0x45, 0x13, 0x43, 0xbf, 0x36, 0xbe, 0x1d, 0xc3, 0xb3, 0xd5, 0xbf, 0x90, 0x1a, 0x15, - 0x9b, 0x63, 0x2f, 0x4a, 0xf6, 0x2a, 0x85, 0xc1, 0x2c, 0xb9, 0xf4, 0x59, 0x41, 0x9b, 0xd2, 0x9e, - 0xb2, 0xef, 0xf7, 0x88, 0x23, 0x5f, 0x59, 0xbd, 0x0f, 0x7c, 0x34, 0xbb, 0xab, 0xfe, 0x89, 0xb2, - 0xf6, 0x34, 0x84, 0x6d, 0xd7, 0xe5, 0x23, 0x7f, 0x56, 0x67, 0xf0, 0xb2, 0xeb, 0x72, 0xf5, 0x77, - 0x94, 0x09, 0xc2, 0x08, 0x03, 0x1e, 0xf3, 0x62, 0x5b, 0x96, 0xc7, 0xa0, 0x24, 0x1d, 0xa3, 0x0c, - 0x0c, 0x7d, 0x70, 0x04, 0xb8, 0xb8, 0x15, 0x72, 0x2a, 0x87, 0x5f, 0x3a, 0xfc, 0x55, 0x8b, 0xb7, - 0x8a, 0x16, 0x6d, 0x15, 0x6d, 0xb4, 0x55, 0xb4, 0x2a, 0x23, 0xd4, 0x5a, 0x1e, 0xf3, 0x2b, 0x21, - 0xa7, 0xea, 0xbf, 0x68, 0x05, 0xda, 0x6d, 0x70, 0x04, 0xe9, 0x43, 0x9c, 0x20, 0xf5, 0xbd, 0x04, - 0x99, 0x89, 0x20, 0xca, 0xb0, 0xf7, 0x12, 0xad, 0x3f, 0xf9, 0xff, 0x53, 0x77, 0xd0, 0x96, 0xf1, - 0xbc, 0x61, 0x5a, 0xe5, 0x0b, 0xb3, 0x5e, 0xc3, 0x96, 0x51, 0x6e, 0xd6, 0x6b, 0xf8, 0xb2, 0xd6, - 0x6c, 0x18, 0x55, 0xf3, 0xd4, 0x34, 0x4e, 0xb2, 0x09, 0x35, 0x87, 0x32, 0x0d, 0xab, 0x5e, 0x3f, - 0xc5, 0xe7, 0x66, 0xb3, 0x69, 0xd6, 0xfe, 0xcb, 0x2a, 0x53, 0xc8, 0xac, 0x3d, 0x2b, 0xff, 0x6f, - 0x9e, 0x64, 0x93, 0x95, 0xf3, 0x0f, 0x77, 0x05, 0xe5, 0xe6, 0xae, 0xa0, 0x7c, 0xba, 0x2b, 0x28, - 0x6f, 0xee, 0x0b, 0x89, 0x9b, 0xfb, 0x42, 0xe2, 0xe3, 0x7d, 0x21, 0xf1, 0xe2, 0xa8, 0x43, 0x44, - 0x37, 0x6c, 0x69, 0x0e, 0xf3, 0xf4, 0xe8, 0xa1, 0xef, 0x53, 0x10, 0x03, 0xc6, 0xaf, 0xf4, 0xc9, - 0x76, 0x1c, 0xce, 0xee, 0x62, 0xb9, 0x24, 0x5b, 0x3f, 0xc9, 0x2d, 0x79, 0xf4, 0x25, 0x00, 0x00, - 0xff, 0xff, 0x0c, 0xdb, 0x5a, 0x92, 0xaf, 0x05, 0x00, 0x00, + // 740 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x54, 0x4f, 0x4f, 0xdb, 0x48, + 0x14, 0x8f, 0x43, 0x58, 0x29, 0xc3, 0x02, 0x89, 0x81, 0xdd, 0x2c, 0x0b, 0x09, 0xe4, 0xb0, 0x62, + 0x59, 0x61, 0x0b, 0x58, 0xed, 0x69, 0x85, 0x9a, 0x04, 0x53, 0x2c, 0x95, 0x24, 0x72, 0xa0, 0xaa, + 0x7a, 0x99, 0x3a, 0xf6, 0x4b, 0x32, 0x25, 0x9e, 0x71, 0xc7, 0xe3, 0x24, 0x1c, 0xfb, 0x0d, 0xfa, + 0x01, 0xfa, 0x05, 0x7a, 0xe8, 0xf7, 0xe8, 0x91, 0x63, 0x4f, 0xa8, 0x82, 0x1b, 0x9f, 0xa2, 0xf2, + 0x38, 0xff, 0x1a, 0xa8, 0x7a, 0xee, 0xc5, 0x1e, 0xff, 0xde, 0xef, 0xf7, 0xde, 0x9b, 0xdf, 0x8c, + 0x1f, 0x2a, 0xf8, 0xec, 0x52, 0x70, 0xd6, 0xed, 0xea, 0x82, 0x5d, 0x02, 0x65, 0x1e, 0x71, 0x02, + 0x1d, 0x7a, 0x40, 0x85, 0xe6, 0x73, 0x26, 0x98, 0xba, 0x32, 0x22, 0x68, 0x13, 0xc2, 0x7a, 0xde, + 0x61, 0x81, 0xc7, 0x02, 0xbd, 0x69, 0x07, 0xa0, 0xf7, 0xf6, 0x9b, 0x20, 0xec, 0x7d, 0xdd, 0x61, + 0x84, 0xc6, 0xa2, 0xf5, 0xd5, 0x36, 0x6b, 0x33, 0xb9, 0xd4, 0xa3, 0xd5, 0x10, 0x5d, 0x1f, 0xd7, + 0xf2, 0x39, 0x63, 0x2d, 0x5d, 0x5c, 0xf9, 0x10, 0xc4, 0xb1, 0xe2, 0xc7, 0x24, 0xca, 0x1a, 0x51, + 0xd9, 0x4a, 0xd7, 0x26, 0x9e, 0x31, 0xf0, 0x09, 0x07, 0x57, 0xfd, 0x0f, 0xcd, 0x3b, 0xd1, 0x77, + 0x4e, 0xd9, 0x52, 0x76, 0x16, 0x0e, 0xd6, 0xb4, 0x71, 0x33, 0x32, 0x83, 0x26, 0xc9, 0xe5, 0xf4, + 0xfd, 0x4d, 0x21, 0xe6, 0x59, 0xf1, 0x4b, 0xdd, 0x43, 0x88, 0x86, 0x1e, 0xe6, 0xd0, 0xb5, 0xaf, + 0x82, 0x5c, 0x72, 0x4b, 0xd9, 0x49, 0x95, 0x97, 0xee, 0x6f, 0x0a, 0x53, 0xa8, 0x95, 0xa6, 0xa1, + 0x67, 0xc9, 0xa5, 0x5a, 0x42, 0xd9, 0x28, 0xe0, 0x30, 0xcf, 0x0f, 0x05, 0xe0, 0x90, 0x12, 0x11, + 0xe4, 0xe6, 0xa4, 0x6a, 0xed, 0xfe, 0xa6, 0xf0, 0x30, 0x68, 0x2d, 0xd3, 0xd0, 0xab, 0xc4, 0xc8, + 0x45, 0x04, 0xa8, 0x14, 0x65, 0x21, 0x6a, 0xda, 0x16, 0x84, 0x51, 0xcc, 0xc1, 0x0e, 0x18, 0xcd, + 0xa5, 0xb6, 0x94, 0x9d, 0xa5, 0x83, 0x5d, 0xed, 0x11, 0x0b, 0xb5, 0xc9, 0x3e, 0xa5, 0xc4, 0x92, + 0x8a, 0xb8, 0xdc, 0x83, 0x44, 0x56, 0x06, 0x66, 0x88, 0xc5, 0x0f, 0xdf, 0xf8, 0xd5, 0x00, 0x21, + 0xba, 0x3f, 0x95, 0x5f, 0xaf, 0x51, 0x56, 0xb6, 0x84, 0x39, 0xbc, 0x09, 0x09, 0x07, 0x0f, 0xa8, + 0x18, 0xfa, 0xf5, 0xd7, 0x6c, 0xd7, 0xf5, 0xe8, 0x69, 0x4d, 0x78, 0xd3, 0x5e, 0x3d, 0x48, 0x62, + 0x65, 0xfc, 0x19, 0x7a, 0xf1, 0x7d, 0x12, 0x6d, 0x4b, 0xaf, 0x64, 0xfb, 0x67, 0x84, 0x12, 0xda, + 0x3e, 0x26, 0xad, 0x16, 0x71, 0xc2, 0xae, 0xb8, 0xba, 0xf0, 0x5d, 0x5b, 0x80, 0xab, 0x6e, 0x22, + 0x14, 0x00, 0xef, 0x11, 0x07, 0x30, 0x71, 0xa5, 0x81, 0x69, 0x2b, 0x3d, 0x44, 0x4c, 0x57, 0x3d, + 0x42, 0x1b, 0x3e, 0x87, 0x1e, 0x16, 0x36, 0x6f, 0x83, 0xc0, 0x1d, 0x3b, 0xe8, 0xe0, 0x0e, 0x0c, + 0x30, 0x50, 0x87, 0xb9, 0xe0, 0x4a, 0xd3, 0xd2, 0x56, 0x2e, 0xe2, 0x9c, 0x4b, 0xca, 0xa9, 0x1d, + 0x74, 0x4e, 0x61, 0x60, 0xc4, 0x71, 0xf5, 0x7f, 0xf4, 0x27, 0x85, 0xfe, 0x77, 0xe5, 0x73, 0x52, + 0xfe, 0x3b, 0x85, 0xfe, 0xa3, 0xea, 0x3d, 0xb4, 0x22, 0xab, 0x4f, 0xce, 0x03, 0x83, 0x67, 0x4b, + 0xc3, 0x52, 0xd1, 0x8e, 0xa1, 0x57, 0x1d, 0x9d, 0x8e, 0xe1, 0xd9, 0xea, 0x3f, 0x48, 0x8d, 0x8a, + 0xcd, 0xb0, 0xe7, 0x25, 0x7b, 0x99, 0x42, 0x7f, 0x9a, 0x5c, 0x7c, 0x9b, 0x44, 0x1b, 0xd2, 0x9e, + 0x92, 0xef, 0x77, 0x89, 0x23, 0x6f, 0x59, 0xad, 0x07, 0x7c, 0xb8, 0x77, 0x57, 0xfd, 0x1b, 0x65, + 0xec, 0x49, 0x08, 0xdb, 0xae, 0xcb, 0x87, 0xfe, 0x2c, 0x4f, 0xe1, 0x25, 0xd7, 0xe5, 0xea, 0xbf, + 0xe8, 0xb7, 0x20, 0x8c, 0x30, 0xe0, 0x98, 0xf9, 0xc0, 0x6d, 0xc1, 0x78, 0x2c, 0x88, 0xfd, 0x59, + 0x1d, 0x45, 0x6b, 0xc3, 0xa0, 0x54, 0x1d, 0xa1, 0x45, 0x18, 0xf8, 0xe0, 0x08, 0x70, 0x71, 0x33, + 0xe4, 0x54, 0xba, 0xb1, 0x70, 0xf0, 0x87, 0x16, 0x8f, 0x19, 0x2d, 0x1a, 0x33, 0xda, 0x70, 0xcc, + 0x68, 0x15, 0x46, 0xa8, 0xf5, 0xeb, 0x88, 0x5f, 0x0e, 0x39, 0x55, 0x9f, 0xa0, 0x25, 0x68, 0xb5, + 0xc0, 0x11, 0xa4, 0x07, 0x71, 0x82, 0xd4, 0x8f, 0x12, 0x2c, 0x8e, 0x05, 0x51, 0x86, 0xdd, 0x57, + 0x68, 0xed, 0xd1, 0x1f, 0x52, 0xdd, 0x46, 0x9b, 0xc6, 0x8b, 0xba, 0x69, 0x95, 0xce, 0xcd, 0x5a, + 0x15, 0x5b, 0x46, 0xa9, 0x51, 0xab, 0xe2, 0x8b, 0x6a, 0xa3, 0x6e, 0x54, 0xcc, 0x13, 0xd3, 0x38, + 0xce, 0x24, 0xd4, 0x2c, 0x5a, 0xac, 0x5b, 0xb5, 0xda, 0x09, 0x3e, 0x33, 0x1b, 0x0d, 0xb3, 0xfa, + 0x34, 0xa3, 0x4c, 0x20, 0xb3, 0xfa, 0xbc, 0xf4, 0xcc, 0x3c, 0xce, 0x24, 0xcb, 0x67, 0x9f, 0x6e, + 0xf3, 0xca, 0xf5, 0x6d, 0x5e, 0xf9, 0x72, 0x9b, 0x57, 0xde, 0xdd, 0xe5, 0x13, 0xd7, 0x77, 0xf9, + 0xc4, 0xe7, 0xbb, 0x7c, 0xe2, 0xe5, 0x61, 0x9b, 0x88, 0x4e, 0xd8, 0xd4, 0x1c, 0xe6, 0xe9, 0xd1, + 0xcd, 0xdf, 0xa3, 0x20, 0xfa, 0x8c, 0x5f, 0xea, 0xe3, 0x71, 0x39, 0x98, 0x1e, 0xce, 0x72, 0x6a, + 0x36, 0x7f, 0x91, 0x63, 0xf3, 0xf0, 0x6b, 0x00, 0x00, 0x00, 0xff, 0xff, 0xb1, 0x9c, 0x4b, 0x68, + 0xc0, 0x05, 0x00, 0x00, } func (m *EventClaimExpired) Marshal() (dAtA []byte, err error) { @@ -608,10 +609,10 @@ func (m *EventApplicationOverserviced) MarshalToSizedBuffer(dAtA []byte) (int, e i-- dAtA[i] = 0x1a } - if len(m.SupplierAddr) > 0 { - i -= len(m.SupplierAddr) - copy(dAtA[i:], m.SupplierAddr) - i = encodeVarintEvent(dAtA, i, uint64(len(m.SupplierAddr))) + if len(m.SupplierOperatorAddr) > 0 { + i -= len(m.SupplierOperatorAddr) + copy(dAtA[i:], m.SupplierOperatorAddr) + i = encodeVarintEvent(dAtA, i, uint64(len(m.SupplierOperatorAddr))) i-- dAtA[i] = 0x12 } @@ -717,7 +718,7 @@ func (m *EventApplicationOverserviced) Size() (n int) { if l > 0 { n += 1 + l + sovEvent(uint64(l)) } - l = len(m.SupplierAddr) + l = len(m.SupplierOperatorAddr) if l > 0 { n += 1 + l + sovEvent(uint64(l)) } @@ -1271,7 +1272,7 @@ func (m *EventApplicationOverserviced) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field SupplierAddr", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field SupplierOperatorAddr", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1299,7 +1300,7 @@ func (m *EventApplicationOverserviced) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.SupplierAddr = string(dAtA[iNdEx:postIndex]) + m.SupplierOperatorAddr = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 3: if wireType != 2 { From 085d13487fd22de9288817a7456d78b87bcc548d Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Sun, 25 Aug 2024 15:09:51 -0400 Subject: [PATCH 11/53] Implemented TestProcessTokenLogicModules_TLMGlobalMint_Valid_MintDistributionCorrect --- testutil/keeper/tokenomics.go | 13 ++ testutil/sample/sample.go | 23 ++-- .../keeper_settle_pending_claims_test.go | 2 +- x/tokenomics/keeper/token_logic_modules.go | 31 +++-- .../keeper/token_logic_modules_test.go | 129 +++++++++++++++++- x/tokenomics/types/errors.go | 1 + 6 files changed, 167 insertions(+), 32 deletions(-) diff --git a/testutil/keeper/tokenomics.go b/testutil/keeper/tokenomics.go index 6ec0e64df..008b29be2 100644 --- a/testutil/keeper/tokenomics.go +++ b/testutil/keeper/tokenomics.go @@ -460,3 +460,16 @@ func WithService(service sharedtypes.Service) TokenomicsModuleKeepersOpt { return ctx } } + +func WithProposerAddr(addr string) TokenomicsModuleKeepersOpt { + return func(ctx context.Context, keepers *TokenomicsModuleKeepers) context.Context { + valAddr, err := cosmostypes.ValAddressFromBech32(addr) + if err != nil { + panic(err) + } + consensusAddr := cosmostypes.ConsAddress(valAddr) + sdkCtx := sdk.UnwrapSDKContext(ctx) + sdkCtx = sdkCtx.WithProposer(consensusAddr) + return sdkCtx + } +} diff --git a/testutil/sample/sample.go b/testutil/sample/sample.go index 7bf7a7d3c..c9b91d874 100644 --- a/testutil/sample/sample.go +++ b/testutil/sample/sample.go @@ -1,6 +1,8 @@ package sample import ( + "encoding/hex" + "github.com/cometbft/cometbft/crypto/tmhash" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" @@ -17,25 +19,28 @@ func AccAddressAndPubKey() (string, cryptotypes.PubKey) { // AccAddress returns a sample account address func AccAddress() string { - // TODO_BETA(@olshansk): Change this to secp256k1 because that's what we'll - // use in production for all real accounts. + addr, _ := AccAddressAndPubKey() + return addr +} + +// AccAddressAndPubKeyEdd2519 returns a sample account address and public key +func AccAddressAndPubKeyEdd2519() (string, cryptotypes.PubKey) { pk := ed25519.GenPrivKey().PubKey() addr := pk.Address() - return sdk.AccAddress(addr).String() + return sdk.AccAddress(addr).String(), pk } // ConsAddress returns a sample consensus address, which has the prefix // of validators (i.e. consensus nodes) when converted to bech32. func ConsAddress() string { - pk := ed25519.GenPrivKey().PubKey() + _, pk := AccAddressAndPubKey() consensusAddress := tmhash.SumTruncated(pk.Address()) valAddress := sdk.ValAddress(consensusAddress) return valAddress.String() } -// AccAddressAndPubKeyEdd2519 returns a sample account address and public key -func AccAddressAndPubKeyEdd2519() (string, cryptotypes.PubKey) { - pk := ed25519.GenPrivKey().PubKey() - addr := pk.Address() - return sdk.AccAddress(addr).String(), pk +func AccAddressFromConsAddress(validatorConsAddr string) string { + valAddr, _ := sdk.ValAddressFromBech32(validatorConsAddr) + proposerAddress, _ := sdk.AccAddressFromHexUnsafe(hex.EncodeToString(valAddr.Bytes())) + return proposerAddress.String() } diff --git a/x/tokenomics/keeper/keeper_settle_pending_claims_test.go b/x/tokenomics/keeper/keeper_settle_pending_claims_test.go index cdb9d8e98..94f873791 100644 --- a/x/tokenomics/keeper/keeper_settle_pending_claims_test.go +++ b/x/tokenomics/keeper/keeper_settle_pending_claims_test.go @@ -141,7 +141,7 @@ func (s *TestSuite) SetupTest() { require.NoError(t, err) // Construct a valid session tree with 10 relays. - s.numRelays = uint64(10) + s.numRelays = uint64(100) sessionTree := testtree.NewFilledSessionTree( sdkCtx, t, s.numRelays, service.ComputeUnitsPerRelay, diff --git a/x/tokenomics/keeper/token_logic_modules.go b/x/tokenomics/keeper/token_logic_modules.go index 2d0a4aabc..c41b046fc 100644 --- a/x/tokenomics/keeper/token_logic_modules.go +++ b/x/tokenomics/keeper/token_logic_modules.go @@ -27,7 +27,7 @@ import ( var ( // Governance parameters for the TLMGlobalMint module // TODO_UPNEXT(@olshansk, #732): Make this a governance parameter and give it a non-zero value + tests. - MintPerClaimGlobalInflation = 0.1 + MintPerClaimedTokenGlobalInflation = 0.1 ) const ( @@ -45,7 +45,7 @@ const ( // Due to floating point arithmetic, the total amount of minted coins may be slightly // larger than what is distributed to pocket network participants // TODO_MAINNET: Figure out if we can avoid this tolerance and use fixed point arithmetic. - mintDistributionAllowableTolerance = 0.02 + MintDistributionAllowableTolerance = 0.02 ) type TokenLogicModule int @@ -347,15 +347,16 @@ func (k Keeper) TokenLogicModuleGlobalMint( ) error { logger := k.Logger().With("method", "TokenLogicModuleGlobalMint") - if MintPerClaimGlobalInflation == 0 { + if MintPerClaimedTokenGlobalInflation == 0 { logger.Warn("global inflation is set to zero. Skipping Global Mint TLM.") return nil } // Determine how much new uPOKT to mint based on global inflation newMintCoin, newMintAmtFloat := calculateGlobalPerClaimMintInflationFromSettlementAmount(settlementCoin) - - fmt.Println("OLSH ", newMintCoin, MintPerClaimGlobalInflation, settlementCoin) + if newMintCoin.Amount.Int64() == 0 { + return tokenomicstypes.ErrTokenomicsMintAmountZero + } // Mint new uPOKT to the tokenomics module account if err := k.bankKeeper.MintCoins(ctx, tokenomictypes.ModuleName, sdk.NewCoins(newMintCoin)); err != nil { @@ -365,14 +366,14 @@ func (k Keeper) TokenLogicModuleGlobalMint( logger.Info(fmt.Sprintf("minted (%v) coins in the tokenomics module", newMintCoin)) // Send a portion of the rewards to the application - appCoin, err := k.sendRewardsToAccount(ctx, tokenomictypes.ModuleName, application.Address, newMintAmtFloat, MintAllocationApplication) + appCoin, err := k.sendRewardsToAccount(ctx, tokenomictypes.ModuleName, application.Address, &newMintAmtFloat, MintAllocationApplication) if err != nil { return tokenomictypes.ErrTokenomicsSendingMintRewards.Wrapf("sending rewards to application: %v", err) } logger.Debug(fmt.Sprintf("sent (%v) newley minted coins from the tokenomics module to the application with address %q", appCoin, application.Address)) // Send a portion of the rewards to the supplier shareholders. - supplierCoinsToShareAmt := calculateAllocationAmount(newMintAmtFloat, MintAllocationSupplier) + supplierCoinsToShareAmt := calculateAllocationAmount(&newMintAmtFloat, MintAllocationSupplier) supplierCoin := cosmostypes.NewCoin(volatile.DenomuPOKT, math.NewInt(supplierCoinsToShareAmt)) // Send funds from the tokenomics module to the supplier module account if err = k.bankKeeper.SendCoinsFromModuleToModule(ctx, tokenomicstypes.ModuleName, suppliertypes.ModuleName, sdk.NewCoins(supplierCoin)); err != nil { @@ -394,14 +395,14 @@ func (k Keeper) TokenLogicModuleGlobalMint( logger.Debug(fmt.Sprintf("sent (%v) newley minted coins from the tokenomics module to the supplier with address %q", supplierCoin, supplier.OperatorAddress)) // Send a portion of the rewards to the DAO - daoCoin, err := k.sendRewardsToAccount(ctx, tokenomictypes.ModuleName, k.GetAuthority(), newMintAmtFloat, MintAllocationDAO) + daoCoin, err := k.sendRewardsToAccount(ctx, tokenomictypes.ModuleName, k.GetAuthority(), &newMintAmtFloat, MintAllocationDAO) if err != nil { return tokenomictypes.ErrTokenomicsSendingMintRewards.Wrapf("sending rewards to DAO: %v", err) } logger.Debug(fmt.Sprintf("sent (%v) newley minted coins from the tokenomics module to the DAO with address %q", daoCoin, k.GetAuthority())) // Send a portion of the rewards to the source owner - serviceCoin, err := k.sendRewardsToAccount(ctx, tokenomictypes.ModuleName, service.OwnerAddress, newMintAmtFloat, MintAllocationSourceOwner) + serviceCoin, err := k.sendRewardsToAccount(ctx, tokenomictypes.ModuleName, service.OwnerAddress, &newMintAmtFloat, MintAllocationSourceOwner) if err != nil { return tokenomictypes.ErrTokenomicsSendingMintRewards.Wrapf("sending rewards to source owner: %v", err) } @@ -409,7 +410,7 @@ func (k Keeper) TokenLogicModuleGlobalMint( // Send a portion of the rewards to the block proposer proposerAddr := cosmostypes.AccAddress(sdk.UnwrapSDKContext(ctx).BlockHeader().ProposerAddress).String() - proposerCoin, err := k.sendRewardsToAccount(ctx, tokenomictypes.ModuleName, proposerAddr, newMintAmtFloat, MintAllocationProposer) + proposerCoin, err := k.sendRewardsToAccount(ctx, tokenomictypes.ModuleName, proposerAddr, &newMintAmtFloat, MintAllocationProposer) if err != nil { return tokenomictypes.ErrTokenomicsSendingMintRewards.Wrapf("sending rewards to proposer: %v", err) } @@ -420,7 +421,7 @@ func (k Keeper) TokenLogicModuleGlobalMint( coinDifference := new(big.Int).Sub(totalMintDistributedCoin.Amount.BigInt(), newMintCoin.Amount.BigInt()) coinDifference = coinDifference.Abs(coinDifference) percentDifference := new(big.Float).Quo(new(big.Float).SetInt(coinDifference), new(big.Float).SetInt(newMintCoin.Amount.BigInt())) - if percentDifference.Cmp(big.NewFloat(mintDistributionAllowableTolerance)) > 0 { + if percentDifference.Cmp(big.NewFloat(MintDistributionAllowableTolerance)) > 0 { return tokenomictypes.ErrTokenomicsAmountMismatchTooLarge.Wrapf( "the total distributed coins (%v) do not equal the amount of newly minted coins (%v) with a percent difference of (%f). Likely floating point arithmetic.\n"+ "appCoin: %v, supplierCoin: %v, daoCoin: %v, serviceCoin: %v, proposerCoin: %v", @@ -498,7 +499,7 @@ func (k Keeper) ensureClaimAmountLimits( maxClaimableCoin := sdk.NewCoin(volatile.DenomuPOKT, appStake.Amount.Quo(math.NewInt(sessionkeeper.NumSupplierPerSession))) if maxClaimableCoin.Amount.GTE(claimSettlementCoin.Amount) { - logger.Info(fmt.Sprintf("Claim by supplier %s IS WITHIN LIMITS of servicing application %s. Max claimable amount < Claim amount: %v < %v", + logger.Info(fmt.Sprintf("Claim by supplier %s IS WITHIN LIMITS of servicing application %s. Max claimable amount >= Claim amount: %v >= %v", supplier.OperatorAddress, application.Address, maxClaimableCoin, claimSettlementCoin.Amount)) return claimSettlementCoin, nil } @@ -606,14 +607,14 @@ func (k Keeper) distributeSupplierRewardsToShareHolders( // calculateGlobalPerClaimMintInflationFromSettlementAmount calculates the amount // of uPOKT to mint based on the global per claim inflation rate as a function of // the settlement amount for a particular claim(s) or session(s). -func calculateGlobalPerClaimMintInflationFromSettlementAmount(settlementCoin sdk.Coin) (sdk.Coin, *big.Float) { +func calculateGlobalPerClaimMintInflationFromSettlementAmount(settlementCoin sdk.Coin) (sdk.Coin, big.Float) { // Determine how much new uPOKT to mint based on global per claim inflation. // TODO_MAINNET: Consider using fixed point arithmetic for deterministic results. settlementAmtFloat := new(big.Float).SetUint64(settlementCoin.Amount.Uint64()) - newMintAmtFloat := new(big.Float).Mul(settlementAmtFloat, big.NewFloat(MintPerClaimGlobalInflation)) + newMintAmtFloat := new(big.Float).Mul(settlementAmtFloat, big.NewFloat(MintPerClaimedTokenGlobalInflation)) newMintAmtInt, _ := newMintAmtFloat.Int64() mintAmtCoin := cosmostypes.NewCoin(volatile.DenomuPOKT, math.NewInt(newMintAmtInt)) - return mintAmtCoin, newMintAmtFloat + return mintAmtCoin, *newMintAmtFloat } // calculateAllocationAmount does big float arithmetic to determine the absolute diff --git a/x/tokenomics/keeper/token_logic_modules_test.go b/x/tokenomics/keeper/token_logic_modules_test.go index 6174ca72c..d8ac3ef5e 100644 --- a/x/tokenomics/keeper/token_logic_modules_test.go +++ b/x/tokenomics/keeper/token_logic_modules_test.go @@ -11,6 +11,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/pokt-network/smt" "github.com/stretchr/testify/require" @@ -36,6 +37,9 @@ func init() { cmd.InitSDKConfig() } +// TODO_IMPROVE: Consider using a TestSuite, similar to `x/tokenomics/keeper/keeper_settle_pending_claims_test.go` +// for the TLM based tests in this file. + func TestProcessTokenLogicModules_TLMBurnEqualsMint_Valid(t *testing.T) { // Test Parameters appInitialStake := math.NewInt(1000000) @@ -66,10 +70,10 @@ func TestProcessTokenLogicModules_TLMBurnEqualsMint_Valid(t *testing.T) { require.NoError(t, err) // TODO_TECHDEBT: Setting inflation to zero so we are testing the BurnEqualsMint logic exclusively. // Once it is a governance param, update it using the keeper above. - prevInflationValue := tokenomicskeeper.MintPerClaimGlobalInflation - tokenomicskeeper.MintPerClaimGlobalInflation = 0 + prevInflationValue := tokenomicskeeper.MintPerClaimedTokenGlobalInflation + tokenomicskeeper.MintPerClaimedTokenGlobalInflation = 0 t.Cleanup(func() { - tokenomicskeeper.MintPerClaimGlobalInflation = prevInflationValue + tokenomicskeeper.MintPerClaimedTokenGlobalInflation = prevInflationValue }) // Add a new application with non-zero app stake end balance to assert against. @@ -193,10 +197,10 @@ func TestProcessTokenLogicModules_TLMBurnEqualsMint_Invalid_SupplierExceedsMaxCl require.NoError(t, err) // TODO_TECHDEBT: Setting inflation to zero so we are testing the BurnEqualsMint logic exclusively. // Once it is a governance param, update it using the keeper above. - prevInflationValue := tokenomicskeeper.MintPerClaimGlobalInflation - tokenomicskeeper.MintPerClaimGlobalInflation = 0 + prevInflationValue := tokenomicskeeper.MintPerClaimedTokenGlobalInflation + tokenomicskeeper.MintPerClaimedTokenGlobalInflation = 0 t.Cleanup(func() { - tokenomicskeeper.MintPerClaimGlobalInflation = prevInflationValue + tokenomicskeeper.MintPerClaimedTokenGlobalInflation = prevInflationValue }) // Add a new application with non-zero app stake end balance to assert against. @@ -302,7 +306,118 @@ func TestProcessTokenLogicModules_TLMBurnEqualsMint_Invalid_SupplierExceedsMaxCl require.Less(t, appBurn.Int64(), numTokensClaimed) } -func TestProcessTokenLogicModules_TLMGlobalMint_Valid_CorrectMintDistribution(t *testing.T) { +func TestProcessTokenLogicModules_TLMGlobalMint_Valid_MintDistributionCorrect(t *testing.T) { + // Test Parameters + appInitialStake := math.NewInt(1000000) + supplierInitialStake := math.NewInt(1000000) + supplierRevShareRatios := []float32{12.5, 37.5, 50} + globalComputeUnitsToTokensMultiplier := uint64(1) + serviceComputeUnitsPerRelay := uint64(1) + service := prepareTestService(serviceComputeUnitsPerRelay) + numRelays := uint64(1000) // By supplier for application in this session + numTokensClaimed := float64(numRelays * serviceComputeUnitsPerRelay * globalComputeUnitsToTokensMultiplier) + validatorConsAddr := sample.ConsAddress() + + // Prepare the keepers + keepers, ctx := testkeeper.NewTokenomicsModuleKeepers(t, nil, testkeeper.WithService(*service), testkeeper.WithProposerAddr(validatorConsAddr)) + keepers.SetService(ctx, *service) + + // Set compute_units_to_tokens_multiplier to simplify expectation calculations. + err := keepers.Keeper.SetParams(ctx, tokenomicstypes.Params{ + ComputeUnitsToTokensMultiplier: globalComputeUnitsToTokensMultiplier, + }) + require.NoError(t, err) + + // Add a new application with non-zero app stake end balance to assert against. + appStake := cosmostypes.NewCoin(volatile.DenomuPOKT, appInitialStake) + app := apptypes.Application{ + Address: sample.AccAddress(), + Stake: &appStake, + ServiceConfigs: []*sharedtypes.ApplicationServiceConfig{{Service: service}}, + } + keepers.SetApplication(ctx, app) + + // Prepare the supplier revenue shares + supplierRevShares := make([]*sharedtypes.ServiceRevenueShare, len(supplierRevShareRatios)) + for i := range supplierRevShares { + shareHolderAddress := sample.AccAddress() + supplierRevShares[i] = &sharedtypes.ServiceRevenueShare{ + Address: shareHolderAddress, + RevSharePercentage: supplierRevShareRatios[i], + } + } + + // Add a new supplier. + supplierStake := cosmostypes.NewCoin(volatile.DenomuPOKT, supplierInitialStake) + supplier := sharedtypes.Supplier{ + // Make the first shareholder the supplier itself. + OwnerAddress: supplierRevShares[0].Address, + OperatorAddress: supplierRevShares[0].Address, + Stake: &supplierStake, + Services: []*sharedtypes.SupplierServiceConfig{{Service: service, RevShare: supplierRevShares}}, + } + keepers.SetSupplier(ctx, supplier) + + // Prepare the claim for which the supplier did work for the application + claim := prepareTestClaim(numRelays, service, &app, &supplier) + + // Prepare addresses + daoAddr := authtypes.NewModuleAddress(govtypes.ModuleName) + appAddress := app.Address + proposerAddress := sample.AccAddressFromConsAddress(validatorConsAddr) + // supplierOperatorAddr := supplier.OperatorAddress + + // Determine balances before inflation + daoBalanceBefore := getBalance(t, ctx, keepers, daoAddr.String()) + propBalanceBefore := getBalance(t, ctx, keepers, proposerAddress) + serviceOwnerBalanceBefore := getBalance(t, ctx, keepers, service.OwnerAddress) + appBalanceBefore := getBalance(t, ctx, keepers, appAddress) + supplierShareholderBalancesBefore := make(map[string]*sdk.Coin, len(supplierRevShares)) + for _, revShare := range supplierRevShares { + addr := revShare.Address + supplierShareholderBalancesBefore[addr] = getBalance(t, ctx, keepers, addr) + } + + // Process the token logic modules + err = keepers.ProcessTokenLogicModules(ctx, &claim) + require.NoError(t, err) + + // Determine balances after inflation + daoBalanceAfter := getBalance(t, ctx, keepers, daoAddr.String()) + propBalanceAfter := getBalance(t, ctx, keepers, proposerAddress) + serviceOwnerBalanceAfter := getBalance(t, ctx, keepers, service.OwnerAddress) + appBalanceAfter := getBalance(t, ctx, keepers, appAddress) + supplierShareholderBalancesAfter := make(map[string]*sdk.Coin, len(supplierRevShares)) + for _, revShare := range supplierRevShares { + addr := revShare.Address + supplierShareholderBalancesAfter[addr] = getBalance(t, ctx, keepers, addr) + } + + // Compute mint per actor + numTokensMinted := numTokensClaimed * tokenomicskeeper.MintPerClaimedTokenGlobalInflation + daoMint := math.NewInt(int64(numTokensMinted * tokenomicskeeper.MintAllocationDAO)) + propMint := math.NewInt(int64(numTokensMinted * tokenomicskeeper.MintAllocationProposer)) + serviceOwnerMint := math.NewInt(int64(numTokensMinted * tokenomicskeeper.MintAllocationSourceOwner)) + appMint := math.NewInt(int64(numTokensMinted * tokenomicskeeper.MintAllocationApplication)) + supplierMint := float32(numTokensMinted * tokenomicskeeper.MintAllocationSupplier) + + // Ensure the balance was increase be the appropriate amount + require.Equal(t, daoBalanceBefore.Amount.Add(daoMint), daoBalanceAfter.Amount) + require.Equal(t, propBalanceBefore.Amount.Add(propMint), propBalanceAfter.Amount) + require.Equal(t, serviceOwnerBalanceBefore.Amount.Add(serviceOwnerMint), serviceOwnerBalanceAfter.Amount) + require.Equal(t, appBalanceBefore.Amount.Add(appMint), appBalanceAfter.Amount) + for _, revShare := range supplierRevShares { + addr := revShare.Address + balanceBefore := supplierShareholderBalancesBefore[addr] + balanceAfter := supplierShareholderBalancesAfter[addr].Amount.Int64() + mintShare := int64(supplierMint * revShare.RevSharePercentage / 100) + rewardShare := int64(float32(numTokensClaimed) * revShare.RevSharePercentage / 100) + balanceIncrease := math.NewInt(mintShare + rewardShare) + expectedBalanceAfter := balanceBefore.Amount.Add(balanceIncrease).Int64() + // TODO_MAINNET: Remove the InDelta check and use the exact amount once the floating point arithmetic is fixed + acceptableRoundingDelta := tokenomicskeeper.MintDistributionAllowableTolerance * float64(balanceAfter) + require.InDelta(t, expectedBalanceAfter, balanceAfter, acceptableRoundingDelta) + } } func TestProcessTokenLogicModules_AppNotFound(t *testing.T) { diff --git a/x/tokenomics/types/errors.go b/x/tokenomics/types/errors.go index 018c44601..f5f1c7e1a 100644 --- a/x/tokenomics/types/errors.go +++ b/x/tokenomics/types/errors.go @@ -34,4 +34,5 @@ var ( ErrTokenomicsSupplierRevShareFailed = sdkerrors.Register(ModuleName, 1125, "failed to send rev share to supplier shareholders") ErrTokenomicsApplicationReimbursementRequestFailed = sdkerrors.Register(ModuleName, 1126, "failed to send application reimbursement request event") ErrTokenomicsAmountMismatchTooLarge = sdkerrors.Register(ModuleName, 1127, "an unexpected amount mismatch occurred") + ErrTokenomicsMintAmountZero = sdkerrors.Register(ModuleName, 1128, "mint amount cannot be zero") ) From 1de13ba277dc23c6a34faa29dec3f58f5c6cff7e Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Sun, 25 Aug 2024 15:16:30 -0400 Subject: [PATCH 12/53] Updated comments in e2e/tests/0_settlement.feature --- e2e/tests/0_settlement.feature | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/e2e/tests/0_settlement.feature b/e2e/tests/0_settlement.feature index 89ab2527c..ec7042940 100644 --- a/e2e/tests/0_settlement.feature +++ b/e2e/tests/0_settlement.feature @@ -7,7 +7,7 @@ Feature: Tokenomics Namespace - Scenario: Mint equals burn when a claim is created and a valid proof is submitted and required + Scenario: TLM Mint=Burn when a valid claim is within max limits Given the user has the pocketd binary installed # Network preparation and validation And an account exists for "supplier1" @@ -25,23 +25,12 @@ Feature: Tokenomics Namespace Then the account balance of "supplier1" should be "420" uPOKT "more" than before And the "application" stake of "app1" should be "420" uPOKT "less" than before - Scenario: - Given the user has the pocketd binary installed - # Network preparation - And an account exists for "supplier1" - And the "supplier" account for "supplier1" is staked - And an account exists for "app1" - And the "application" account for "app1" is staked - And the service "anvil" registered for application "app1" has a compute units per relay of "1" - # Start servicing relays - When the supplier "supplier1" has serviced a session with "10" relays for service "anvil" for application "app1" - # Wait for the Claim & Proof lifecycle - And the user should wait for the "tokenomics" module "ClaimSettled" end block event to be broadcast - - # TODO_IN_THIS_PR: Add the following test - # Scenario: Supplier overservices an application and gets paid for less work than claimed - # TODO_ADDTEST: Implement the following scenarios + # Scenario: Supplier revenue shares are properly distributedTestUpdateRelayMiningDifficulty_NewServiceSeenForTheFirstTime + # Scenario: TLM Mint=Burn when a valid claim is outside Max Limits + # - Ensure over serviced event is submitted + # Scenario: TLM GlobalMint properly distributes minted rewards to all actors + # - Ensure reimbursement request is submitted # Scenario: Mint equals burn when a claim is created and a valid proof is submitted but not required # Scenario: No emissions or burn when a claim is created and an invalid proof is submitted # Scenario: No emissions or burn when a claim is created and a proof is required but is not submitted From b8dff51a47556f6b65fc5cf081c50eb10b3e419e Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Sun, 25 Aug 2024 15:27:03 -0400 Subject: [PATCH 13/53] Fixed failing unit test --- e2e/tests/0_settlement.feature | 2 +- .../relay_mining_difficulty_test.go | 46 ++++++++++--------- testutil/integration/app.go | 7 +-- testutil/testrelayer/relays.go | 20 +++++++- 4 files changed, 48 insertions(+), 27 deletions(-) diff --git a/e2e/tests/0_settlement.feature b/e2e/tests/0_settlement.feature index ec7042940..2503b6a68 100644 --- a/e2e/tests/0_settlement.feature +++ b/e2e/tests/0_settlement.feature @@ -26,7 +26,7 @@ Feature: Tokenomics Namespace And the "application" stake of "app1" should be "420" uPOKT "less" than before # TODO_ADDTEST: Implement the following scenarios - # Scenario: Supplier revenue shares are properly distributedTestUpdateRelayMiningDifficulty_NewServiceSeenForTheFirstTime + # Scenario: Supplier revenue shares are properly distributed # Scenario: TLM Mint=Burn when a valid claim is outside Max Limits # - Ensure over serviced event is submitted # Scenario: TLM GlobalMint properly distributes minted rewards to all actors diff --git a/tests/integration/tokenomics/relay_mining_difficulty_test.go b/tests/integration/tokenomics/relay_mining_difficulty_test.go index 3b3a2d876..498486320 100644 --- a/tests/integration/tokenomics/relay_mining_difficulty_test.go +++ b/tests/integration/tokenomics/relay_mining_difficulty_test.go @@ -39,8 +39,9 @@ func TestUpdateRelayMiningDifficulty_NewServiceSeenForTheFirstTime(t *testing.T) session := getSession(t, integrationApp) sharedParams := getSharedParams(t, integrationApp) - // Prepare the trie with a single mined relay - trie := prepareSMST(t, sdkCtx, integrationApp, session) + // Prepare the trie with several mined relays + numRelays := uint64(100) + trie := prepareSMST(t, sdkCtx, integrationApp, session, numRelays) // Compute the number of blocks to wait between different events // TODO_BLOCKER(@bryanchriswhite): See this comment: https://github.com/pokt-network/poktroll/pull/610#discussion_r1645777322 @@ -118,8 +119,8 @@ func TestUpdateRelayMiningDifficulty_NewServiceSeenForTheFirstTime(t *testing.T) require.Equal(t, prooftypes.DefaultRelayDifficultyTargetHashHex, relayMiningEvent.NewTargetHashHexEncoded) // The previous EMA is the same as the current one if the service is new - require.Equal(t, uint64(1), relayMiningEvent.PrevNumRelaysEma) - require.Equal(t, uint64(1), relayMiningEvent.NewNumRelaysEma) + require.Equal(t, numRelays, relayMiningEvent.PrevNumRelaysEma) + require.Equal(t, numRelays, relayMiningEvent.NewNumRelaysEma) } func UpdateRelayMiningDifficulty_UpdatingMultipleServicesAtOnce(t *testing.T) {} @@ -164,11 +165,12 @@ func getSession(t *testing.T, integrationApp *testutil.App) *sessiontypes.Sessio return getSessionRes.Session } -// prepareSMST prepares an SMST with a single mined relay for the given session. +// prepareSMST prepares an SMST with a the number of mined relays specified. func prepareSMST( t *testing.T, ctx context.Context, integrationApp *testutil.App, session *sessiontypes.Session, + numRelays uint64, ) *smt.SMST { t.Helper() @@ -178,23 +180,25 @@ func prepareSMST( kvStore, err := pebble.NewKVStore("") require.NoError(t, err) - // NB: A signed mined relay is a MinedRelay type with the appropriate - // payload, signatures and metadata populated. - // - // It does not (as of writing) adhere to the actual on-chain difficulty (i.e. - // hash check) of the test service surrounding the scope of this test. - minedRelay := testrelayer.NewSignedMinedRelay(t, ctx, - session, - integrationApp.DefaultApplication.Address, - integrationApp.DefaultSupplier.OperatorAddress, - integrationApp.DefaultSupplierKeyringKeyringUid, - integrationApp.GetKeyRing(), - integrationApp.GetRingClient(), - ) - trie := smt.NewSparseMerkleSumTrie(kvStore, protocol.NewTrieHasher(), smt.WithValueHasher(nil)) - err = trie.Update(minedRelay.Hash, minedRelay.Bytes, 1) - require.NoError(t, err) + + for i := uint64(0); i < numRelays; i++ { + // DEV_NOTE: A signed mined relay is a MinedRelay type with the appropriate + // payload, signatures and metadata populated. + // It does not (as of writing) adhere to the actual on-chain difficulty (i.e. + // hash check) of the test service surrounding the scope of this test. + minedRelay := testrelayer.NewSignedMinedRelay(t, ctx, + session, + integrationApp.DefaultApplication.Address, + integrationApp.DefaultSupplier.OperatorAddress, + integrationApp.DefaultSupplierKeyringKeyringUid, + integrationApp.GetKeyRing(), + integrationApp.GetRingClient(), + ) + + err = trie.Update(minedRelay.Hash, minedRelay.Bytes, 1) + require.NoError(t, err) + } return trie } diff --git a/testutil/integration/app.go b/testutil/integration/app.go index ccd56beba..7f46755ca 100644 --- a/testutil/integration/app.go +++ b/testutil/integration/app.go @@ -509,9 +509,10 @@ func NewCompleteIntegrationApp(t *testing.T) *App { // Prepare a new default service defaultService := sharedtypes.Service{ - Id: "svc1", - Name: "svcName1", - OwnerAddress: sample.AccAddress(), + Id: "svc1", + Name: "svcName1", + ComputeUnitsPerRelay: 1, + OwnerAddress: sample.AccAddress(), } serviceKeeper.SetService(integrationApp.sdkCtx, defaultService) integrationApp.DefaultService = &defaultService diff --git a/testutil/testrelayer/relays.go b/testutil/testrelayer/relays.go index 14da2aace..83bc75ab4 100644 --- a/testutil/testrelayer/relays.go +++ b/testutil/testrelayer/relays.go @@ -5,11 +5,13 @@ import ( "fmt" "strings" "testing" + "time" "github.com/cosmos/cosmos-sdk/crypto/keyring" cosmostypes "github.com/cosmos/cosmos-sdk/types" signingtypes "github.com/cosmos/cosmos-sdk/types/tx/signing" "github.com/stretchr/testify/require" + "golang.org/x/exp/rand" "github.com/pokt-network/poktroll/pkg/crypto" "github.com/pokt-network/poktroll/pkg/crypto/protocol" @@ -93,13 +95,13 @@ func NewSignedMinedRelay( SessionHeader: session.Header, SupplierOperatorAddress: supplierOperatorAddr, }, - Payload: []byte("request_payload"), + Payload: randomPayload(), }, Res: &servicetypes.RelayResponse{ Meta: servicetypes.RelayResponseMetadata{ SessionHeader: session.Header, }, - Payload: []byte("response_payload"), + Payload: randomPayload(), }, } @@ -234,3 +236,17 @@ func NewEmptyRelay(reqHeader, resHeader *sessiontypes.SessionHeader, supplierOpe }, } } + +const ( + charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + payloadLength = 32 +) + +func randomPayload() []byte { + rand.Seed(uint64(time.Now().UnixNano())) + bz := make([]byte, payloadLength) + for i := range bz { + bz[i] = charset[rand.Intn(len(charset))] + } + return bz +} From 4c335e7dd53aa8f766d63cd9b854aa2fb29f15e3 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Mon, 26 Aug 2024 17:20:27 -0400 Subject: [PATCH 14/53] update compile proto --- x/tokenomics/types/tx.pb.go | 1 - 1 file changed, 1 deletion(-) diff --git a/x/tokenomics/types/tx.pb.go b/x/tokenomics/types/tx.pb.go index 91f06eeff..5bc7d33e4 100644 --- a/x/tokenomics/types/tx.pb.go +++ b/x/tokenomics/types/tx.pb.go @@ -133,7 +133,6 @@ type MsgUpdateParam struct { // specified in the `Params` message in `proof/params.proto.` Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` // Types that are valid to be assigned to AsType: - // // *MsgUpdateParam_AsString // *MsgUpdateParam_AsInt64 // *MsgUpdateParam_AsBytes From f7a0da7cfd613909db5985b9de393755cde7954d Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Thu, 19 Sep 2024 23:30:51 +0200 Subject: [PATCH 15/53] fix: Remove merge added lines --- config.yml | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/config.yml b/config.yml index 0a9041d5d..7921b0573 100644 --- a/config.yml +++ b/config.yml @@ -188,20 +188,6 @@ genesis: # `supplier1_stake_config.yaml` so that the stake command causes a state change. amount: "1000068" denom: upokt - - address: pokt1ad28jdap2zfanjd7hpkh984yveney6k9a42man - delegatee_gateway_addresses: [] - service_configs: - - service: - id: anvil - - service: - id: rest - - service: - id: ollama - stake: - # NB: This value should be exactly 1upokt smaller than the value in - # `supplier1_stake_config.yaml` so that the stake command causes a state change. - amount: "1000068" - denom: upokt supplier: supplierList: - owner_address: pokt19a3t4yunp0dlpfjrp7qwnzwlrzd5fzs2gjaaaj From 79ac3e66f9901587d5f3ddcb879ceb70ab24d68e Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Fri, 20 Sep 2024 22:55:26 +0200 Subject: [PATCH 16/53] feat: Add GMRR --- api/poktroll/tokenomics/event.pulsar.go | 798 +++++++++++++++++++-- proto/poktroll/tokenomics/event.proto | 9 + x/tokenomics/keeper/token_logic_modules.go | 113 ++- x/tokenomics/types/errors.go | 3 +- x/tokenomics/types/event.pb.go | 437 +++++++++-- 5 files changed, 1258 insertions(+), 102 deletions(-) diff --git a/api/poktroll/tokenomics/event.pulsar.go b/api/poktroll/tokenomics/event.pulsar.go index 0090b4632..fbeaf5572 100644 --- a/api/poktroll/tokenomics/event.pulsar.go +++ b/api/poktroll/tokenomics/event.pulsar.go @@ -3006,6 +3006,633 @@ func (x *fastReflection_EventSupplierSlashed) ProtoMethods() *protoiface.Methods } } +var ( + md_EventApplicationReimbursementRequest protoreflect.MessageDescriptor + fd_EventApplicationReimbursementRequest_application_addr protoreflect.FieldDescriptor + fd_EventApplicationReimbursementRequest_service_id protoreflect.FieldDescriptor + fd_EventApplicationReimbursementRequest_session_id protoreflect.FieldDescriptor + fd_EventApplicationReimbursementRequest_amount protoreflect.FieldDescriptor +) + +func init() { + file_poktroll_tokenomics_event_proto_init() + md_EventApplicationReimbursementRequest = File_poktroll_tokenomics_event_proto.Messages().ByName("EventApplicationReimbursementRequest") + fd_EventApplicationReimbursementRequest_application_addr = md_EventApplicationReimbursementRequest.Fields().ByName("application_addr") + fd_EventApplicationReimbursementRequest_service_id = md_EventApplicationReimbursementRequest.Fields().ByName("service_id") + fd_EventApplicationReimbursementRequest_session_id = md_EventApplicationReimbursementRequest.Fields().ByName("session_id") + fd_EventApplicationReimbursementRequest_amount = md_EventApplicationReimbursementRequest.Fields().ByName("amount") +} + +var _ protoreflect.Message = (*fastReflection_EventApplicationReimbursementRequest)(nil) + +type fastReflection_EventApplicationReimbursementRequest EventApplicationReimbursementRequest + +func (x *EventApplicationReimbursementRequest) ProtoReflect() protoreflect.Message { + return (*fastReflection_EventApplicationReimbursementRequest)(x) +} + +func (x *EventApplicationReimbursementRequest) slowProtoReflect() protoreflect.Message { + mi := &file_poktroll_tokenomics_event_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_EventApplicationReimbursementRequest_messageType fastReflection_EventApplicationReimbursementRequest_messageType +var _ protoreflect.MessageType = fastReflection_EventApplicationReimbursementRequest_messageType{} + +type fastReflection_EventApplicationReimbursementRequest_messageType struct{} + +func (x fastReflection_EventApplicationReimbursementRequest_messageType) Zero() protoreflect.Message { + return (*fastReflection_EventApplicationReimbursementRequest)(nil) +} +func (x fastReflection_EventApplicationReimbursementRequest_messageType) New() protoreflect.Message { + return new(fastReflection_EventApplicationReimbursementRequest) +} +func (x fastReflection_EventApplicationReimbursementRequest_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_EventApplicationReimbursementRequest +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_EventApplicationReimbursementRequest) Descriptor() protoreflect.MessageDescriptor { + return md_EventApplicationReimbursementRequest +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_EventApplicationReimbursementRequest) Type() protoreflect.MessageType { + return _fastReflection_EventApplicationReimbursementRequest_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_EventApplicationReimbursementRequest) New() protoreflect.Message { + return new(fastReflection_EventApplicationReimbursementRequest) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_EventApplicationReimbursementRequest) Interface() protoreflect.ProtoMessage { + return (*EventApplicationReimbursementRequest)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_EventApplicationReimbursementRequest) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.ApplicationAddr != "" { + value := protoreflect.ValueOfString(x.ApplicationAddr) + if !f(fd_EventApplicationReimbursementRequest_application_addr, value) { + return + } + } + if x.ServiceId != "" { + value := protoreflect.ValueOfString(x.ServiceId) + if !f(fd_EventApplicationReimbursementRequest_service_id, value) { + return + } + } + if x.SessionId != "" { + value := protoreflect.ValueOfString(x.SessionId) + if !f(fd_EventApplicationReimbursementRequest_session_id, value) { + return + } + } + if x.Amount != nil { + value := protoreflect.ValueOfMessage(x.Amount.ProtoReflect()) + if !f(fd_EventApplicationReimbursementRequest_amount, value) { + return + } + } +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_EventApplicationReimbursementRequest) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "poktroll.tokenomics.EventApplicationReimbursementRequest.application_addr": + return x.ApplicationAddr != "" + case "poktroll.tokenomics.EventApplicationReimbursementRequest.service_id": + return x.ServiceId != "" + case "poktroll.tokenomics.EventApplicationReimbursementRequest.session_id": + return x.SessionId != "" + case "poktroll.tokenomics.EventApplicationReimbursementRequest.amount": + return x.Amount != nil + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.tokenomics.EventApplicationReimbursementRequest")) + } + panic(fmt.Errorf("message poktroll.tokenomics.EventApplicationReimbursementRequest does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_EventApplicationReimbursementRequest) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "poktroll.tokenomics.EventApplicationReimbursementRequest.application_addr": + x.ApplicationAddr = "" + case "poktroll.tokenomics.EventApplicationReimbursementRequest.service_id": + x.ServiceId = "" + case "poktroll.tokenomics.EventApplicationReimbursementRequest.session_id": + x.SessionId = "" + case "poktroll.tokenomics.EventApplicationReimbursementRequest.amount": + x.Amount = nil + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.tokenomics.EventApplicationReimbursementRequest")) + } + panic(fmt.Errorf("message poktroll.tokenomics.EventApplicationReimbursementRequest does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_EventApplicationReimbursementRequest) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "poktroll.tokenomics.EventApplicationReimbursementRequest.application_addr": + value := x.ApplicationAddr + return protoreflect.ValueOfString(value) + case "poktroll.tokenomics.EventApplicationReimbursementRequest.service_id": + value := x.ServiceId + return protoreflect.ValueOfString(value) + case "poktroll.tokenomics.EventApplicationReimbursementRequest.session_id": + value := x.SessionId + return protoreflect.ValueOfString(value) + case "poktroll.tokenomics.EventApplicationReimbursementRequest.amount": + value := x.Amount + return protoreflect.ValueOfMessage(value.ProtoReflect()) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.tokenomics.EventApplicationReimbursementRequest")) + } + panic(fmt.Errorf("message poktroll.tokenomics.EventApplicationReimbursementRequest does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_EventApplicationReimbursementRequest) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "poktroll.tokenomics.EventApplicationReimbursementRequest.application_addr": + x.ApplicationAddr = value.Interface().(string) + case "poktroll.tokenomics.EventApplicationReimbursementRequest.service_id": + x.ServiceId = value.Interface().(string) + case "poktroll.tokenomics.EventApplicationReimbursementRequest.session_id": + x.SessionId = value.Interface().(string) + case "poktroll.tokenomics.EventApplicationReimbursementRequest.amount": + x.Amount = value.Message().Interface().(*v1beta1.Coin) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.tokenomics.EventApplicationReimbursementRequest")) + } + panic(fmt.Errorf("message poktroll.tokenomics.EventApplicationReimbursementRequest does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_EventApplicationReimbursementRequest) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "poktroll.tokenomics.EventApplicationReimbursementRequest.amount": + if x.Amount == nil { + x.Amount = new(v1beta1.Coin) + } + return protoreflect.ValueOfMessage(x.Amount.ProtoReflect()) + case "poktroll.tokenomics.EventApplicationReimbursementRequest.application_addr": + panic(fmt.Errorf("field application_addr of message poktroll.tokenomics.EventApplicationReimbursementRequest is not mutable")) + case "poktroll.tokenomics.EventApplicationReimbursementRequest.service_id": + panic(fmt.Errorf("field service_id of message poktroll.tokenomics.EventApplicationReimbursementRequest is not mutable")) + case "poktroll.tokenomics.EventApplicationReimbursementRequest.session_id": + panic(fmt.Errorf("field session_id of message poktroll.tokenomics.EventApplicationReimbursementRequest is not mutable")) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.tokenomics.EventApplicationReimbursementRequest")) + } + panic(fmt.Errorf("message poktroll.tokenomics.EventApplicationReimbursementRequest does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_EventApplicationReimbursementRequest) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "poktroll.tokenomics.EventApplicationReimbursementRequest.application_addr": + return protoreflect.ValueOfString("") + case "poktroll.tokenomics.EventApplicationReimbursementRequest.service_id": + return protoreflect.ValueOfString("") + case "poktroll.tokenomics.EventApplicationReimbursementRequest.session_id": + return protoreflect.ValueOfString("") + case "poktroll.tokenomics.EventApplicationReimbursementRequest.amount": + m := new(v1beta1.Coin) + return protoreflect.ValueOfMessage(m.ProtoReflect()) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.tokenomics.EventApplicationReimbursementRequest")) + } + panic(fmt.Errorf("message poktroll.tokenomics.EventApplicationReimbursementRequest does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_EventApplicationReimbursementRequest) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in poktroll.tokenomics.EventApplicationReimbursementRequest", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_EventApplicationReimbursementRequest) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_EventApplicationReimbursementRequest) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_EventApplicationReimbursementRequest) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_EventApplicationReimbursementRequest) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*EventApplicationReimbursementRequest) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + l = len(x.ApplicationAddr) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + l = len(x.ServiceId) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + l = len(x.SessionId) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.Amount != nil { + l = options.Size(x.Amount) + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*EventApplicationReimbursementRequest) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if x.Amount != nil { + encoded, err := options.Marshal(x.Amount) + if err != nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) + i-- + dAtA[i] = 0x22 + } + if len(x.SessionId) > 0 { + i -= len(x.SessionId) + copy(dAtA[i:], x.SessionId) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.SessionId))) + i-- + dAtA[i] = 0x1a + } + if len(x.ServiceId) > 0 { + i -= len(x.ServiceId) + copy(dAtA[i:], x.ServiceId) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.ServiceId))) + i-- + dAtA[i] = 0x12 + } + if len(x.ApplicationAddr) > 0 { + i -= len(x.ApplicationAddr) + copy(dAtA[i:], x.ApplicationAddr) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.ApplicationAddr))) + i-- + dAtA[i] = 0xa + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*EventApplicationReimbursementRequest) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + 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++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: EventApplicationReimbursementRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: EventApplicationReimbursementRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field ApplicationAddr", wireType) + } + var stringLen uint64 + 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++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.ApplicationAddr = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field ServiceId", wireType) + } + var stringLen uint64 + 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++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.ServiceId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field SessionId", wireType) + } + var stringLen uint64 + 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++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.SessionId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var msglen int + 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++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if x.Amount == nil { + x.Amount = &v1beta1.Coin{} + } + if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.Amount); err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.27.0 @@ -3386,6 +4013,67 @@ func (x *EventSupplierSlashed) GetSlashingAmount() *v1beta1.Coin { return nil } +// EventApplicationReimbursementRequest is emitted when an application requests +// a reimbursement +type EventApplicationReimbursementRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ApplicationAddr string `protobuf:"bytes,1,opt,name=application_addr,json=applicationAddr,proto3" json:"application_addr,omitempty"` + ServiceId string `protobuf:"bytes,2,opt,name=service_id,json=serviceId,proto3" json:"service_id,omitempty"` + SessionId string `protobuf:"bytes,3,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"` + Amount *v1beta1.Coin `protobuf:"bytes,4,opt,name=amount,proto3" json:"amount,omitempty"` +} + +func (x *EventApplicationReimbursementRequest) Reset() { + *x = EventApplicationReimbursementRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_poktroll_tokenomics_event_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EventApplicationReimbursementRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EventApplicationReimbursementRequest) ProtoMessage() {} + +// Deprecated: Use EventApplicationReimbursementRequest.ProtoReflect.Descriptor instead. +func (*EventApplicationReimbursementRequest) Descriptor() ([]byte, []int) { + return file_poktroll_tokenomics_event_proto_rawDescGZIP(), []int{5} +} + +func (x *EventApplicationReimbursementRequest) GetApplicationAddr() string { + if x != nil { + return x.ApplicationAddr + } + return "" +} + +func (x *EventApplicationReimbursementRequest) GetServiceId() string { + if x != nil { + return x.ServiceId + } + return "" +} + +func (x *EventApplicationReimbursementRequest) GetSessionId() string { + if x != nil { + return x.SessionId + } + return "" +} + +func (x *EventApplicationReimbursementRequest) GetAmount() *v1beta1.Coin { + if x != nil { + return x.Amount + } + return nil +} + var File_poktroll_tokenomics_event_proto protoreflect.FileDescriptor var file_poktroll_tokenomics_event_proto_rawDesc = []byte{ @@ -3481,26 +4169,38 @@ var file_poktroll_tokenomics_event_proto_rawDesc = []byte{ 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x0e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x69, - 0x6e, 0x67, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x2a, 0x60, 0x0a, 0x15, 0x43, 0x6c, 0x61, 0x69, - 0x6d, 0x45, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x61, 0x73, 0x6f, - 0x6e, 0x12, 0x21, 0x0a, 0x1d, 0x45, 0x58, 0x50, 0x49, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, - 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, - 0x45, 0x44, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x52, 0x4f, 0x4f, 0x46, 0x5f, 0x4d, 0x49, - 0x53, 0x53, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x52, 0x4f, 0x4f, 0x46, - 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x02, 0x42, 0xbc, 0x01, 0xd8, 0xe2, 0x1e, - 0x01, 0x0a, 0x17, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, - 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0x42, 0x0a, 0x45, 0x76, 0x65, 0x6e, - 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x24, 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, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0xa2, 0x02, - 0x03, 0x50, 0x54, 0x58, 0xaa, 0x02, 0x13, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, - 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0xca, 0x02, 0x13, 0x50, 0x6f, 0x6b, - 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, - 0xe2, 0x02, 0x1f, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x54, 0x6f, 0x6b, 0x65, - 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0xea, 0x02, 0x14, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x3a, 0x3a, 0x54, - 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, + 0x6e, 0x67, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0xc2, 0x01, 0x0a, 0x24, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x69, + 0x6d, 0x62, 0x75, 0x72, 0x73, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x29, 0x0a, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x61, 0x70, 0x70, + 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x12, 0x1d, 0x0a, 0x0a, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, + 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x31, 0x0a, 0x06, 0x61, 0x6d, + 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x73, + 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, + 0x2e, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x2a, 0x60, 0x0a, + 0x15, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x45, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x1d, 0x45, 0x58, 0x50, 0x49, 0x52, 0x41, + 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, + 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x52, 0x4f, + 0x4f, 0x46, 0x5f, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, + 0x50, 0x52, 0x4f, 0x4f, 0x46, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x02, 0x42, + 0xbc, 0x01, 0xd8, 0xe2, 0x1e, 0x01, 0x0a, 0x17, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x6f, 0x6b, 0x74, + 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0x42, + 0x0a, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x24, 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, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, + 0x69, 0x63, 0x73, 0xa2, 0x02, 0x03, 0x50, 0x54, 0x58, 0xaa, 0x02, 0x13, 0x50, 0x6f, 0x6b, 0x74, + 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0xca, + 0x02, 0x13, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x54, 0x6f, 0x6b, 0x65, 0x6e, + 0x6f, 0x6d, 0x69, 0x63, 0x73, 0xe2, 0x02, 0x1f, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, + 0x5c, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x14, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, + 0x6c, 0x6c, 0x3a, 0x3a, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -3516,31 +4216,33 @@ func file_poktroll_tokenomics_event_proto_rawDescGZIP() []byte { } var file_poktroll_tokenomics_event_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_poktroll_tokenomics_event_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_poktroll_tokenomics_event_proto_msgTypes = make([]protoimpl.MessageInfo, 6) var file_poktroll_tokenomics_event_proto_goTypes = []interface{}{ - (ClaimExpirationReason)(0), // 0: poktroll.tokenomics.ClaimExpirationReason - (*EventClaimExpired)(nil), // 1: poktroll.tokenomics.EventClaimExpired - (*EventClaimSettled)(nil), // 2: poktroll.tokenomics.EventClaimSettled - (*EventRelayMiningDifficultyUpdated)(nil), // 3: poktroll.tokenomics.EventRelayMiningDifficultyUpdated - (*EventApplicationOverserviced)(nil), // 4: poktroll.tokenomics.EventApplicationOverserviced - (*EventSupplierSlashed)(nil), // 5: poktroll.tokenomics.EventSupplierSlashed - (*proof.Claim)(nil), // 6: poktroll.proof.Claim - (proof.ProofRequirementReason)(0), // 7: poktroll.proof.ProofRequirementReason - (*v1beta1.Coin)(nil), // 8: cosmos.base.v1beta1.Coin + (ClaimExpirationReason)(0), // 0: poktroll.tokenomics.ClaimExpirationReason + (*EventClaimExpired)(nil), // 1: poktroll.tokenomics.EventClaimExpired + (*EventClaimSettled)(nil), // 2: poktroll.tokenomics.EventClaimSettled + (*EventRelayMiningDifficultyUpdated)(nil), // 3: poktroll.tokenomics.EventRelayMiningDifficultyUpdated + (*EventApplicationOverserviced)(nil), // 4: poktroll.tokenomics.EventApplicationOverserviced + (*EventSupplierSlashed)(nil), // 5: poktroll.tokenomics.EventSupplierSlashed + (*EventApplicationReimbursementRequest)(nil), // 6: poktroll.tokenomics.EventApplicationReimbursementRequest + (*proof.Claim)(nil), // 7: poktroll.proof.Claim + (proof.ProofRequirementReason)(0), // 8: poktroll.proof.ProofRequirementReason + (*v1beta1.Coin)(nil), // 9: cosmos.base.v1beta1.Coin } var file_poktroll_tokenomics_event_proto_depIdxs = []int32{ - 6, // 0: poktroll.tokenomics.EventClaimExpired.claim:type_name -> poktroll.proof.Claim + 7, // 0: poktroll.tokenomics.EventClaimExpired.claim:type_name -> poktroll.proof.Claim 0, // 1: poktroll.tokenomics.EventClaimExpired.expiration_reason:type_name -> poktroll.tokenomics.ClaimExpirationReason - 6, // 2: poktroll.tokenomics.EventClaimSettled.claim:type_name -> poktroll.proof.Claim - 7, // 3: poktroll.tokenomics.EventClaimSettled.proof_requirement:type_name -> poktroll.proof.ProofRequirementReason - 8, // 4: poktroll.tokenomics.EventApplicationOverserviced.expected_burn:type_name -> cosmos.base.v1beta1.Coin - 8, // 5: poktroll.tokenomics.EventApplicationOverserviced.effective_burn:type_name -> cosmos.base.v1beta1.Coin - 8, // 6: poktroll.tokenomics.EventSupplierSlashed.slashing_amount:type_name -> cosmos.base.v1beta1.Coin - 7, // [7:7] is the sub-list for method output_type - 7, // [7:7] is the sub-list for method input_type - 7, // [7:7] is the sub-list for extension type_name - 7, // [7:7] is the sub-list for extension extendee - 0, // [0:7] is the sub-list for field type_name + 7, // 2: poktroll.tokenomics.EventClaimSettled.claim:type_name -> poktroll.proof.Claim + 8, // 3: poktroll.tokenomics.EventClaimSettled.proof_requirement:type_name -> poktroll.proof.ProofRequirementReason + 9, // 4: poktroll.tokenomics.EventApplicationOverserviced.expected_burn:type_name -> cosmos.base.v1beta1.Coin + 9, // 5: poktroll.tokenomics.EventApplicationOverserviced.effective_burn:type_name -> cosmos.base.v1beta1.Coin + 9, // 6: poktroll.tokenomics.EventSupplierSlashed.slashing_amount:type_name -> cosmos.base.v1beta1.Coin + 9, // 7: poktroll.tokenomics.EventApplicationReimbursementRequest.amount:type_name -> cosmos.base.v1beta1.Coin + 8, // [8:8] is the sub-list for method output_type + 8, // [8:8] is the sub-list for method input_type + 8, // [8:8] is the sub-list for extension type_name + 8, // [8:8] is the sub-list for extension extendee + 0, // [0:8] is the sub-list for field type_name } func init() { file_poktroll_tokenomics_event_proto_init() } @@ -3609,6 +4311,18 @@ func file_poktroll_tokenomics_event_proto_init() { return nil } } + file_poktroll_tokenomics_event_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EventApplicationReimbursementRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -3616,7 +4330,7 @@ func file_poktroll_tokenomics_event_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_poktroll_tokenomics_event_proto_rawDesc, NumEnums: 1, - NumMessages: 5, + NumMessages: 6, NumExtensions: 0, NumServices: 0, }, diff --git a/proto/poktroll/tokenomics/event.proto b/proto/poktroll/tokenomics/event.proto index 4c6f319b5..5f80f4525 100644 --- a/proto/poktroll/tokenomics/event.proto +++ b/proto/poktroll/tokenomics/event.proto @@ -70,4 +70,13 @@ message EventSupplierSlashed { // Amount slashed from the supplier's stake due to the expired claims. // This is a function of the number of expired claims and proof missing penalty. cosmos.base.v1beta1.Coin slashing_amount = 3; +} + +// EventApplicationReimbursementRequest is emitted when an application requests +// a reimbursement +message EventApplicationReimbursementRequest { + string application_addr = 1; + string service_id = 2; + string session_id = 3; + cosmos.base.v1beta1.Coin amount = 4; } \ No newline at end of file diff --git a/x/tokenomics/keeper/token_logic_modules.go b/x/tokenomics/keeper/token_logic_modules.go index 0dfe69d39..333f88a5e 100644 --- a/x/tokenomics/keeper/token_logic_modules.go +++ b/x/tokenomics/keeper/token_logic_modules.go @@ -68,11 +68,20 @@ const ( // global governance parameters in order to reward the participants providing // services while keeping inflation in check. TLMGlobalMint + + // TLMGlobalMintReimbursementRequest is the token logic module that complements + // TLMGlobalMint to enable permissionless demand. + // In order to prevent self-dealing attacks, applications will be overcharged by + // the amount equal to global inflation, those funds will be sent to the DAO/PNF, + // and an event will be emitted to track and send reimbursements; managed offchain by PNF. + // TODO_POST_MAINNET: Introduce proper tokenomics based on the research done by @rawthil and @shane. + TLMGlobalMintReimbursementRequest ) var tokenLogicModuleStrings = [...]string{ "TLMRelayBurnEqualsMint", "TLMGlobalMint", + "TLMGlobalMintReimbursementRequest", } func (tlm TokenLogicModule) String() string { @@ -317,10 +326,11 @@ func (k Keeper) TokenLogicModuleRelayBurnEqualsMint( // Update the application's on-chain stake newAppStake, err := application.Stake.SafeSub(actualSettlementCoin) if err != nil { - return tokenomicstypes.ErrTokenomicsApplicationNewStakeInvalid.Wrapf("application %q stake cannot be reduced to a negative amount %v", application.Address, newAppStake) + amountDiffCoin := actualSettlementCoin.Amount.Sub(application.Stake.Amount) + return tokenomicstypes.ErrTokenomicsApplicationNewStakeInvalid.Wrapf("application %q stake cannot be reduced to a negative amount -%s", application.Address, amountDiffCoin) } application.Stake = &newAppStake - logger.Info(fmt.Sprintf("updated application %q stake to %v", application.Address, newAppStake)) + logger.Info(fmt.Sprintf("updated application %q stake to %s", application.Address, newAppStake)) // Burn uPOKT from the application module account which was held in escrow // on behalf of the application account. @@ -329,7 +339,7 @@ func (k Keeper) TokenLogicModuleRelayBurnEqualsMint( ); err != nil { return tokenomicstypes.ErrTokenomicsApplicationModuleBurn.Wrapf("burning %s from the application module account: %v", actualSettlementCoin, err) } - logger.Info(fmt.Sprintf("burned (%v) from the application module account", actualSettlementCoin)) + logger.Info(fmt.Sprintf("burned (%s) from the application module account", actualSettlementCoin)) // Mint new uPOKT to the supplier module account. // These funds will be transferred to the supplier's shareholders below. @@ -448,6 +458,89 @@ func (k Keeper) TokenLogicModuleGlobalMint( return nil } +// TokenLogicModuleGlobalMintReimbursementRequest processes the business logic +// for the GlobalMintReimbursementRequest TLM. +func (k Keeper) TokenLogicModuleGlobalMintReimbursementRequest( + ctx context.Context, + service *sharedtypes.Service, + sessionHeader *sessiontypes.SessionHeader, + application *apptypes.Application, + supplier *sharedtypes.Supplier, + actualSettlementCoin cosmostypes.Coin, + relayMiningDifficulty *tokenomictypes.RelayMiningDifficulty, +) error { + logger := k.Logger().With("method", "TokenLogicModuleGlobalMintReimbursementRequest") + + // Determine how much new uPOKT to mint based on global inflation + newMintCoin, _ := calculateGlobalPerClaimMintInflationFromSettlementAmount(actualSettlementCoin) + if newMintCoin.Amount.Int64() == 0 { + return tokenomicstypes.ErrTokenomicsMintAmountZero + } + + // Update the application's on-chain stake + newAppStake, err := application.Stake.SafeSub(newMintCoin) + if err != nil { + amountDiffCoin := actualSettlementCoin.Amount.Sub(application.Stake.Amount) + return tokenomicstypes.ErrTokenomicsApplicationReimbursementRequestFailed.Wrapf( + "application %q stake cannot be reduced to a negative amount -%s", + application.Address, amountDiffCoin, + ) + } + application.Stake = &newAppStake + logger.Info(fmt.Sprintf("updated application %q stake to %s", application.Address, newAppStake)) + + // Send the global per claim mint inflation uPOKT from the application module + // account to the tokenomics module account. + if err := k.bankKeeper.SendCoinsFromModuleToModule( + ctx, apptypes.ModuleName, tokenomicstypes.ModuleName, sdk.NewCoins(actualSettlementCoin), + ); err != nil { + return tokenomicstypes.ErrTokenomicsApplicationReimbursementRequestFailed.Wrapf( + "sending %s from the application module account to the tokenomics module account: %v", + actualSettlementCoin, err, + ) + } + logger.Info(fmt.Sprintf( + "sent (%s) from the application module account to the tokenomics module account", + actualSettlementCoin, + )) + + // Send the global per claim mint inflation uPOKT from the tokenomics module + // account to PNF/DAO. + daoAccountAddr, err := cosmostypes.AccAddressFromBech32(k.GetAuthority()) + if err != nil { + return tokenomictypes.ErrTokenomicsApplicationReimbursementRequestFailed.Wrapf( + "getting PNF/DAO address: %v", + err, + ) + } + if err := k.bankKeeper.SendCoinsFromModuleToAccount( + ctx, tokenomicstypes.ModuleName, daoAccountAddr, sdk.NewCoins(newMintCoin), + ); err != nil { + return tokenomicstypes.ErrTokenomicsApplicationReimbursementRequestFailed.Wrapf( + "sending %s from the tokenomics module account to the PNF/DAO account: %v", + newMintCoin, err, + ) + } + + // Prepare and emit the event for the application being overcharged. + reimbursementRequestEvent := &tokenomicstypes.EventApplicationReimbursementRequest{ + ApplicationAddr: application.Address, + ServiceId: service.Id, + SessionId: sessionHeader.SessionId, + Amount: &newMintCoin, + } + + eventManger := cosmostypes.UnwrapSDKContext(ctx).EventManager() + if err := eventManger.EmitTypedEvent(reimbursementRequestEvent); err != nil { + return tokenomicstypes.ErrTokenomicsEmittingEventFailed.Wrapf( + "error emitting event %v", + reimbursementRequestEvent, + ) + } + + return nil +} + func (k Keeper) ensureMintedCoinsAreDistributed( logger log.Logger, appCoin, supplierCoin, daoCoin, serviceCoin, proposerCoin, newMintCoin cosmostypes.Coin, @@ -537,13 +630,19 @@ func (k Keeper) ensureClaimAmountLimits( // settlement. Relay miners use the appStake at the beginning of a session to determine // the maximum amount they can claim. We need to somehow access and propagate this // value (via context?) so it is the same for all TLM processors for each claim. - // Note that this will also need to incorporate MintPerClaimGlobalInflation because - // applications are being overcharged by that amount in the meantime. Whatever the - // solution and implementation ends up being, make sure to KISS. + // Note that this also incorporates MintPerClaimGlobalInflation since applications + // are being overcharged by that amount and the funds are sent to the DAO/PNF + // before being reimbursed to the application in the future. appStake := application.GetStake() + // Global inflation per claim amount should be accounted for in the max claimable amount. + // The application should have this additional amount in its stake to account + // so it can be deducted and sent to the DAO/PNF. + globalInflationCoin, _ := calculateGlobalPerClaimMintInflationFromSettlementAmount(claimSettlementCoin) + maxCalibmableAmt := appStake.Amount.Quo(math.NewInt(sessionkeeper.NumSupplierPerSession)).Sub(globalInflationCoin.Amount) + // Determine the max claimable amount for the supplier based on the application's stake in this session. - maxClaimableCoin := sdk.NewCoin(volatile.DenomuPOKT, appStake.Amount.Quo(math.NewInt(sessionkeeper.NumSupplierPerSession))) + maxClaimableCoin := sdk.NewCoin(volatile.DenomuPOKT, maxCalibmableAmt) if maxClaimableCoin.Amount.GTE(claimSettlementCoin.Amount) { logger.Info(fmt.Sprintf("Claim by supplier %s IS WITHIN LIMITS of servicing application %s. Max claimable amount >= Claim amount: %v >= %v", diff --git a/x/tokenomics/types/errors.go b/x/tokenomics/types/errors.go index 05afa3e9e..f91b7ef84 100644 --- a/x/tokenomics/types/errors.go +++ b/x/tokenomics/types/errors.go @@ -32,9 +32,10 @@ var ( ErrTokenomicsSupplierModuleMintFailed = sdkerrors.Register(ModuleName, 1123, "failed to mint uPOKT to supplier module account") ErrTokenomicsSupplierOwnerAddressInvalid = sdkerrors.Register(ModuleName, 1124, "the supplier owner address in the claim is not a valid bech32 address") ErrTokenomicsSupplierRevShareFailed = sdkerrors.Register(ModuleName, 1125, "failed to send rev share to supplier shareholders") - ErrTokenomicsApplicationReimbursementRequestFailed = sdkerrors.Register(ModuleName, 1126, "failed to send application reimbursement request event") + ErrTokenomicsApplicationReimbursementRequestFailed = sdkerrors.Register(ModuleName, 1126, "failed to process application reimbursement request") ErrTokenomicsAmountMismatchTooLarge = sdkerrors.Register(ModuleName, 1127, "an unexpected amount mismatch occurred") ErrTokenomicsMintAmountZero = sdkerrors.Register(ModuleName, 1128, "mint amount cannot be zero") ErrTokenomicsTLMError = sdkerrors.Register(ModuleName, 1129, "failed to process TLM") ErrTokenomicsCalculation = sdkerrors.Register(ModuleName, 1130, "tokenomics calculation error") + ErrTokenomicsApplicationModuleSendFailed = sdkerrors.Register(ModuleName, 1131, "failed to send uPOKT from application module account") ) diff --git a/x/tokenomics/types/event.pb.go b/x/tokenomics/types/event.pb.go index 85e281f24..6d36d8183 100644 --- a/x/tokenomics/types/event.pb.go +++ b/x/tokenomics/types/event.pb.go @@ -396,6 +396,72 @@ func (m *EventSupplierSlashed) GetSlashingAmount() *types1.Coin { return nil } +// EventApplicationReimbursementRequest is emitted when an application requests +// a reimbursement +type EventApplicationReimbursementRequest struct { + ApplicationAddr string `protobuf:"bytes,1,opt,name=application_addr,json=applicationAddr,proto3" json:"application_addr,omitempty"` + ServiceId string `protobuf:"bytes,2,opt,name=service_id,json=serviceId,proto3" json:"service_id,omitempty"` + SessionId string `protobuf:"bytes,3,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"` + Amount *types1.Coin `protobuf:"bytes,4,opt,name=amount,proto3" json:"amount,omitempty"` +} + +func (m *EventApplicationReimbursementRequest) Reset() { *m = EventApplicationReimbursementRequest{} } +func (m *EventApplicationReimbursementRequest) String() string { return proto.CompactTextString(m) } +func (*EventApplicationReimbursementRequest) ProtoMessage() {} +func (*EventApplicationReimbursementRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_a78874bbf91a58c7, []int{5} +} +func (m *EventApplicationReimbursementRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *EventApplicationReimbursementRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *EventApplicationReimbursementRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_EventApplicationReimbursementRequest.Merge(m, src) +} +func (m *EventApplicationReimbursementRequest) XXX_Size() int { + return m.Size() +} +func (m *EventApplicationReimbursementRequest) XXX_DiscardUnknown() { + xxx_messageInfo_EventApplicationReimbursementRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_EventApplicationReimbursementRequest proto.InternalMessageInfo + +func (m *EventApplicationReimbursementRequest) GetApplicationAddr() string { + if m != nil { + return m.ApplicationAddr + } + return "" +} + +func (m *EventApplicationReimbursementRequest) GetServiceId() string { + if m != nil { + return m.ServiceId + } + return "" +} + +func (m *EventApplicationReimbursementRequest) GetSessionId() string { + if m != nil { + return m.SessionId + } + return "" +} + +func (m *EventApplicationReimbursementRequest) GetAmount() *types1.Coin { + if m != nil { + return m.Amount + } + return nil +} + func init() { proto.RegisterEnum("poktroll.tokenomics.ClaimExpirationReason", ClaimExpirationReason_name, ClaimExpirationReason_value) proto.RegisterType((*EventClaimExpired)(nil), "poktroll.tokenomics.EventClaimExpired") @@ -403,63 +469,67 @@ func init() { proto.RegisterType((*EventRelayMiningDifficultyUpdated)(nil), "poktroll.tokenomics.EventRelayMiningDifficultyUpdated") proto.RegisterType((*EventApplicationOverserviced)(nil), "poktroll.tokenomics.EventApplicationOverserviced") proto.RegisterType((*EventSupplierSlashed)(nil), "poktroll.tokenomics.EventSupplierSlashed") + proto.RegisterType((*EventApplicationReimbursementRequest)(nil), "poktroll.tokenomics.EventApplicationReimbursementRequest") } func init() { proto.RegisterFile("poktroll/tokenomics/event.proto", fileDescriptor_a78874bbf91a58c7) } var fileDescriptor_a78874bbf91a58c7 = []byte{ - // 809 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x55, 0xcf, 0x72, 0xdb, 0x44, - 0x18, 0x8f, 0xdc, 0x94, 0x19, 0x6f, 0x49, 0x62, 0x6f, 0x13, 0x30, 0xa1, 0x55, 0x52, 0x1f, 0x98, - 0x50, 0x88, 0x34, 0x4d, 0x19, 0x4e, 0x4c, 0x07, 0x3b, 0x51, 0xa9, 0x66, 0xa8, 0x1d, 0xe4, 0x86, - 0x61, 0xb8, 0x2c, 0x6b, 0xe9, 0xb3, 0xbd, 0x44, 0xda, 0x15, 0xab, 0x95, 0xe3, 0x1c, 0x79, 0x03, - 0x1e, 0x80, 0x17, 0xe0, 0xc0, 0x2b, 0x70, 0xe6, 0xd8, 0x63, 0x4f, 0x19, 0x26, 0xb9, 0xe5, 0x29, - 0x98, 0x5d, 0xc9, 0xb1, 0x71, 0x42, 0x73, 0xee, 0xc5, 0x5e, 0x7f, 0xdf, 0xef, 0xf7, 0xfd, 0xf9, - 0xc9, 0xfb, 0x13, 0xda, 0x4a, 0xc5, 0xb1, 0x92, 0x22, 0x8e, 0x5d, 0x25, 0x8e, 0x81, 0x8b, 0x84, - 0x85, 0x99, 0x0b, 0x63, 0xe0, 0xca, 0x49, 0xa5, 0x50, 0x02, 0xdf, 0x9f, 0x02, 0x9c, 0x19, 0x60, - 0xd3, 0x0e, 0x45, 0x96, 0x88, 0xcc, 0xed, 0xd3, 0x0c, 0xdc, 0xf1, 0x93, 0x3e, 0x28, 0xfa, 0xc4, - 0x0d, 0x05, 0xe3, 0x05, 0x69, 0x73, 0x7d, 0x28, 0x86, 0xc2, 0x1c, 0x5d, 0x7d, 0x2a, 0xa3, 0x9b, - 0x57, 0xbd, 0x52, 0x29, 0xc4, 0xc0, 0x55, 0xa7, 0x29, 0x64, 0x45, 0xae, 0xf9, 0x67, 0x05, 0xd5, - 0x3d, 0xdd, 0x76, 0x3f, 0xa6, 0x2c, 0xf1, 0x26, 0x29, 0x93, 0x10, 0xe1, 0x2f, 0xd1, 0xdd, 0x50, - 0xff, 0x6e, 0x58, 0xdb, 0xd6, 0xce, 0xbd, 0xbd, 0x0d, 0xe7, 0x6a, 0x18, 0x53, 0xc1, 0x31, 0xe0, - 0x76, 0xf5, 0xf2, 0x6c, 0xab, 0xc0, 0x05, 0xc5, 0x17, 0xde, 0x45, 0x88, 0xe7, 0x09, 0x91, 0x10, - 0xd3, 0xd3, 0xac, 0x51, 0xd9, 0xb6, 0x76, 0x96, 0xdb, 0xab, 0x97, 0x67, 0x5b, 0x73, 0xd1, 0xa0, - 0xca, 0xf3, 0x24, 0x30, 0x47, 0xdc, 0x42, 0x75, 0x9d, 0x08, 0x45, 0x92, 0xe6, 0x0a, 0x48, 0xce, - 0x99, 0xca, 0x1a, 0x77, 0x0c, 0x6b, 0xe3, 0xf2, 0x6c, 0xeb, 0x7a, 0x32, 0x58, 0xe3, 0x79, 0xb2, - 0x5f, 0x44, 0x8e, 0x74, 0x00, 0x73, 0x54, 0x07, 0x3d, 0x34, 0x55, 0x4c, 0x70, 0x22, 0x81, 0x66, - 0x82, 0x37, 0x96, 0xb7, 0xad, 0x9d, 0xd5, 0xbd, 0xc7, 0xce, 0x0d, 0x12, 0x3a, 0xb3, 0x3d, 0x0d, - 0x25, 0x30, 0x8c, 0xa2, 0xdd, 0xb5, 0x42, 0x41, 0x0d, 0x16, 0x80, 0xcd, 0x3f, 0xfe, 0xa3, 0x57, - 0x0f, 0x94, 0x8a, 0xdf, 0x29, 0xbd, 0x7e, 0x46, 0x75, 0x33, 0x12, 0x91, 0xf0, 0x4b, 0xce, 0x24, - 0x24, 0xc0, 0x55, 0xa9, 0xd7, 0x27, 0x8b, 0x53, 0x1f, 0xea, 0xcf, 0x60, 0x86, 0x9b, 0xd7, 0xea, - 0x5a, 0x91, 0xa0, 0x96, 0x2e, 0xc0, 0x9b, 0xbf, 0x57, 0xd0, 0x23, 0xa3, 0x95, 0x19, 0xff, 0x25, - 0xe3, 0x8c, 0x0f, 0x0f, 0xd8, 0x60, 0xc0, 0xc2, 0x3c, 0x56, 0xa7, 0x47, 0x69, 0x44, 0x15, 0x44, - 0xf8, 0x21, 0x42, 0x19, 0xc8, 0x31, 0x0b, 0x81, 0xb0, 0xc8, 0x08, 0x58, 0x0d, 0xaa, 0x65, 0xc4, - 0x8f, 0xf0, 0x33, 0xf4, 0x20, 0x95, 0x30, 0x26, 0x8a, 0xca, 0x21, 0x28, 0x32, 0xa2, 0xd9, 0x88, - 0x8c, 0x60, 0x42, 0x80, 0x87, 0x22, 0x82, 0xc8, 0x88, 0x56, 0x0d, 0x1a, 0x1a, 0xf3, 0xca, 0x40, - 0x5e, 0xd0, 0x6c, 0xf4, 0x02, 0x26, 0x5e, 0x91, 0xc7, 0x5f, 0xa1, 0x8f, 0x39, 0x9c, 0xfc, 0x2f, - 0xfd, 0x8e, 0xa1, 0x7f, 0xc8, 0xe1, 0xe4, 0x46, 0xf6, 0x2e, 0xba, 0x6f, 0xba, 0xcf, 0x9e, 0x07, - 0x81, 0x84, 0x1a, 0xc1, 0x96, 0xf5, 0xc6, 0x30, 0xee, 0x4c, 0x9f, 0x8e, 0x97, 0x50, 0xfc, 0x19, - 0xc2, 0xba, 0xd9, 0x02, 0xfa, 0xae, 0x41, 0xaf, 0x71, 0x38, 0x99, 0x07, 0x37, 0x7f, 0xad, 0xa0, - 0x07, 0x46, 0x9e, 0x56, 0x9a, 0xc6, 0x2c, 0x34, 0xff, 0xb2, 0xee, 0x18, 0x64, 0xb9, 0x7b, 0x84, - 0x3f, 0x45, 0x35, 0x3a, 0x4b, 0x11, 0x1a, 0x45, 0xb2, 0xd4, 0x67, 0x6d, 0x2e, 0xde, 0x8a, 0x22, - 0x89, 0xbf, 0x40, 0x1f, 0x64, 0xb9, 0x8e, 0x81, 0x24, 0x22, 0x05, 0x49, 0x95, 0x90, 0x05, 0xa1, - 0xd0, 0x67, 0x7d, 0x9a, 0xed, 0x96, 0x49, 0xc3, 0x7a, 0x86, 0x56, 0x60, 0x92, 0x42, 0xa8, 0x20, - 0x22, 0xfd, 0x5c, 0x72, 0xa3, 0xc6, 0xbd, 0xbd, 0x8f, 0x9c, 0xc2, 0x66, 0x1c, 0x6d, 0x33, 0x4e, - 0x69, 0x33, 0xce, 0xbe, 0x60, 0x3c, 0x78, 0x7f, 0x8a, 0x6f, 0xe7, 0x92, 0xe3, 0xaf, 0xd1, 0x2a, - 0x0c, 0x06, 0x10, 0x2a, 0x36, 0x86, 0xa2, 0xc0, 0xf2, 0x6d, 0x05, 0x56, 0xae, 0x08, 0xba, 0x42, - 0xf3, 0x2f, 0x0b, 0xad, 0x1b, 0x0d, 0x7a, 0xe5, 0x7c, 0xbd, 0x98, 0x66, 0x23, 0x88, 0xde, 0xb2, - 0x90, 0xf5, 0x96, 0x85, 0x3e, 0x47, 0x58, 0x6b, 0x0f, 0x85, 0x8d, 0x11, 0x73, 0xc9, 0xca, 0x7b, - 0x15, 0xd4, 0x78, 0x3e, 0xf5, 0x37, 0x73, 0x1d, 0x33, 0xdc, 0x46, 0x6b, 0x99, 0x6e, 0xc7, 0xf8, - 0x90, 0xd0, 0x44, 0xe4, 0x5c, 0xdd, 0x2e, 0xc0, 0xea, 0x94, 0xd1, 0x32, 0x84, 0xc7, 0x3f, 0xa1, - 0x8d, 0x1b, 0x1d, 0x05, 0x3f, 0x42, 0x0f, 0xbd, 0x1f, 0x0e, 0xfd, 0xa0, 0xf5, 0xca, 0xef, 0x76, - 0x48, 0xe0, 0xb5, 0x7a, 0xdd, 0x0e, 0x39, 0xea, 0xf4, 0x0e, 0xbd, 0x7d, 0xff, 0xb9, 0xef, 0x1d, - 0xd4, 0x96, 0x70, 0x1d, 0xad, 0x1c, 0x06, 0xdd, 0xee, 0x73, 0xf2, 0xd2, 0xef, 0xf5, 0xfc, 0xce, - 0x37, 0x35, 0x6b, 0x16, 0xf2, 0x3b, 0xdf, 0xb7, 0xbe, 0xf5, 0x0f, 0x6a, 0x95, 0xf6, 0x77, 0x7f, - 0x9f, 0xdb, 0xd6, 0xeb, 0x73, 0xdb, 0x7a, 0x73, 0x6e, 0x5b, 0xff, 0x9c, 0xdb, 0xd6, 0x6f, 0x17, - 0xf6, 0xd2, 0xeb, 0x0b, 0x7b, 0xe9, 0xcd, 0x85, 0xbd, 0xf4, 0xe3, 0xd3, 0x21, 0x53, 0xa3, 0xbc, - 0xef, 0x84, 0x22, 0x71, 0xf5, 0xf5, 0xdd, 0xe5, 0xa0, 0x4e, 0x84, 0x3c, 0x76, 0xaf, 0x3c, 0x7f, - 0x32, 0xff, 0x86, 0x31, 0xd6, 0xdf, 0x7f, 0xcf, 0x78, 0xff, 0xd3, 0x7f, 0x03, 0x00, 0x00, 0xff, - 0xff, 0x69, 0x2d, 0x41, 0xba, 0x85, 0x06, 0x00, 0x00, + // 862 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x55, 0x4f, 0x6f, 0x1b, 0x45, + 0x14, 0xcf, 0xba, 0x69, 0x25, 0x4f, 0x49, 0x62, 0x4f, 0x13, 0x30, 0xa1, 0x75, 0x52, 0x0b, 0xa1, + 0x50, 0xc8, 0xae, 0x92, 0x22, 0x4e, 0xa8, 0xc2, 0x4e, 0x5c, 0xba, 0x12, 0xb5, 0xc3, 0xba, 0x41, + 0x88, 0xcb, 0x30, 0xde, 0x7d, 0xb6, 0x87, 0x78, 0x67, 0xb6, 0x33, 0xb3, 0x8e, 0x73, 0xe4, 0x1b, + 0xf0, 0x01, 0xf8, 0x02, 0x1c, 0xf8, 0x0a, 0x1c, 0x38, 0x71, 0xec, 0xb1, 0xa7, 0x08, 0x25, 0xb7, + 0x7c, 0x0a, 0x34, 0xb3, 0xeb, 0xd8, 0x75, 0x42, 0x23, 0x8e, 0xbd, 0x24, 0xe3, 0xf7, 0x7e, 0xbf, + 0xf7, 0xe7, 0x37, 0xfb, 0xde, 0xa0, 0x8d, 0x44, 0x1c, 0x69, 0x29, 0x86, 0x43, 0x4f, 0x8b, 0x23, + 0xe0, 0x22, 0x66, 0xa1, 0xf2, 0x60, 0x04, 0x5c, 0xbb, 0x89, 0x14, 0x5a, 0xe0, 0x7b, 0x13, 0x80, + 0x3b, 0x05, 0xac, 0x57, 0x43, 0xa1, 0x62, 0xa1, 0xbc, 0x2e, 0x55, 0xe0, 0x8d, 0x76, 0xba, 0xa0, + 0xe9, 0x8e, 0x17, 0x0a, 0xc6, 0x33, 0xd2, 0xfa, 0x6a, 0x5f, 0xf4, 0x85, 0x3d, 0x7a, 0xe6, 0x94, + 0x5b, 0xd7, 0x2f, 0x73, 0x25, 0x52, 0x88, 0x9e, 0xa7, 0x4f, 0x12, 0x50, 0x99, 0xaf, 0xf6, 0x47, + 0x01, 0x95, 0x9b, 0x26, 0xed, 0xde, 0x90, 0xb2, 0xb8, 0x39, 0x4e, 0x98, 0x84, 0x08, 0x7f, 0x89, + 0x6e, 0x87, 0xe6, 0x77, 0xc5, 0xd9, 0x74, 0xb6, 0xee, 0xee, 0xae, 0xb9, 0x97, 0xc5, 0xd8, 0x08, + 0xae, 0x05, 0x37, 0x8a, 0x17, 0xa7, 0x1b, 0x19, 0x2e, 0xc8, 0xfe, 0xe1, 0x6d, 0x84, 0x78, 0x1a, + 0x13, 0x09, 0x43, 0x7a, 0xa2, 0x2a, 0x85, 0x4d, 0x67, 0x6b, 0xb1, 0xb1, 0x7c, 0x71, 0xba, 0x31, + 0x63, 0x0d, 0x8a, 0x3c, 0x8d, 0x03, 0x7b, 0xc4, 0x75, 0x54, 0x36, 0x8e, 0x50, 0xc4, 0x49, 0xaa, + 0x81, 0xa4, 0x9c, 0x69, 0x55, 0xb9, 0x65, 0x59, 0x6b, 0x17, 0xa7, 0x1b, 0x57, 0x9d, 0xc1, 0x0a, + 0x4f, 0xe3, 0xbd, 0xcc, 0x72, 0x68, 0x0c, 0x98, 0xa3, 0x32, 0x98, 0xa2, 0xa9, 0x66, 0x82, 0x13, + 0x09, 0x54, 0x09, 0x5e, 0x59, 0xdc, 0x74, 0xb6, 0x96, 0x77, 0x1f, 0xb9, 0xd7, 0x48, 0xe8, 0x4e, + 0xfb, 0xb4, 0x94, 0xc0, 0x32, 0xb2, 0x74, 0x57, 0x02, 0x05, 0x25, 0x98, 0x03, 0xd6, 0x7e, 0x7f, + 0x43, 0xaf, 0x0e, 0x68, 0x3d, 0x7c, 0xa7, 0xf4, 0xfa, 0x19, 0x95, 0x6d, 0x49, 0x44, 0xc2, 0xcb, + 0x94, 0x49, 0x88, 0x81, 0xeb, 0x5c, 0xaf, 0x4f, 0xe6, 0xab, 0x3e, 0x30, 0x7f, 0x83, 0x29, 0x6e, + 0x56, 0xab, 0x2b, 0x41, 0x82, 0x52, 0x32, 0x07, 0xaf, 0xfd, 0x56, 0x40, 0x0f, 0xad, 0x56, 0xb6, + 0xfc, 0xe7, 0x8c, 0x33, 0xde, 0xdf, 0x67, 0xbd, 0x1e, 0x0b, 0xd3, 0xa1, 0x3e, 0x39, 0x4c, 0x22, + 0xaa, 0x21, 0xc2, 0x0f, 0x10, 0x52, 0x20, 0x47, 0x2c, 0x04, 0xc2, 0x22, 0x2b, 0x60, 0x31, 0x28, + 0xe6, 0x16, 0x3f, 0xc2, 0x4f, 0xd0, 0xfd, 0x44, 0xc2, 0x88, 0x68, 0x2a, 0xfb, 0xa0, 0xc9, 0x80, + 0xaa, 0x01, 0x19, 0xc0, 0x98, 0x00, 0x0f, 0x45, 0x04, 0x91, 0x15, 0xad, 0x18, 0x54, 0x0c, 0xe6, + 0x85, 0x85, 0x3c, 0xa3, 0x6a, 0xf0, 0x0c, 0xc6, 0xcd, 0xcc, 0x8f, 0xbf, 0x42, 0x1f, 0x71, 0x38, + 0xfe, 0x4f, 0xfa, 0x2d, 0x4b, 0xff, 0x80, 0xc3, 0xf1, 0xb5, 0xec, 0x6d, 0x74, 0xcf, 0x66, 0x9f, + 0xde, 0x07, 0x81, 0x98, 0x5a, 0xc1, 0x16, 0x4d, 0xc7, 0x30, 0x6a, 0x4d, 0x6e, 0xa7, 0x19, 0x53, + 0xfc, 0x19, 0xc2, 0x26, 0xd9, 0x1c, 0xfa, 0xb6, 0x45, 0xaf, 0x70, 0x38, 0x9e, 0x05, 0xd7, 0x7e, + 0x29, 0xa0, 0xfb, 0x56, 0x9e, 0x7a, 0x92, 0x0c, 0x59, 0x68, 0xbf, 0xb2, 0xf6, 0x08, 0x64, 0xde, + 0x7b, 0x84, 0x3f, 0x45, 0x25, 0x3a, 0x75, 0x11, 0x1a, 0x45, 0x32, 0xd7, 0x67, 0x65, 0xc6, 0x5e, + 0x8f, 0x22, 0x89, 0xbf, 0x40, 0xef, 0xab, 0xd4, 0xd8, 0x40, 0x12, 0x91, 0x80, 0xa4, 0x5a, 0xc8, + 0x8c, 0x90, 0xe9, 0xb3, 0x3a, 0xf1, 0xb6, 0x73, 0xa7, 0x65, 0x3d, 0x41, 0x4b, 0x30, 0x4e, 0x20, + 0xd4, 0x10, 0x91, 0x6e, 0x2a, 0xb9, 0x55, 0xe3, 0xee, 0xee, 0x87, 0x6e, 0xb6, 0x66, 0x5c, 0xb3, + 0x66, 0xdc, 0x7c, 0xcd, 0xb8, 0x7b, 0x82, 0xf1, 0xe0, 0xbd, 0x09, 0xbe, 0x91, 0x4a, 0x8e, 0xbf, + 0x46, 0xcb, 0xd0, 0xeb, 0x41, 0xa8, 0xd9, 0x08, 0xb2, 0x00, 0x8b, 0x37, 0x05, 0x58, 0xba, 0x24, + 0x98, 0x08, 0xb5, 0x3f, 0x1d, 0xb4, 0x6a, 0x35, 0xe8, 0xe4, 0xf5, 0x75, 0x86, 0x54, 0x0d, 0x20, + 0x7a, 0x4b, 0x43, 0xce, 0x5b, 0x1a, 0xfa, 0x1c, 0x61, 0xa3, 0x3d, 0x64, 0x6b, 0x8c, 0xd8, 0x21, + 0xcb, 0xe7, 0x2a, 0x28, 0xf1, 0x74, 0xb2, 0xdf, 0xec, 0x38, 0x2a, 0xdc, 0x40, 0x2b, 0xca, 0xa4, + 0x63, 0xbc, 0x4f, 0x68, 0x2c, 0x52, 0xae, 0x6f, 0x16, 0x60, 0x79, 0xc2, 0xa8, 0x5b, 0x42, 0xed, + 0x2f, 0x07, 0x7d, 0x3c, 0x7f, 0x89, 0x01, 0xb0, 0xb8, 0x9b, 0x4a, 0x95, 0x0f, 0xcd, 0xcb, 0x14, + 0x94, 0xfe, 0x3f, 0x97, 0xf9, 0xe6, 0x44, 0x14, 0xe6, 0x27, 0xc2, 0xba, 0x95, 0x32, 0x51, 0xd8, + 0xe4, 0x03, 0x2e, 0xe6, 0x16, 0x3f, 0xc2, 0x3b, 0xe8, 0x4e, 0xde, 0xcc, 0x8d, 0x97, 0x91, 0x03, + 0x1f, 0xfd, 0x84, 0xd6, 0xae, 0x5d, 0x8b, 0xf8, 0x21, 0x7a, 0xd0, 0xfc, 0xe1, 0xc0, 0x0f, 0xea, + 0x2f, 0xfc, 0x76, 0x8b, 0x04, 0xcd, 0x7a, 0xa7, 0xdd, 0x22, 0x87, 0xad, 0xce, 0x41, 0x73, 0xcf, + 0x7f, 0xea, 0x37, 0xf7, 0x4b, 0x0b, 0xb8, 0x8c, 0x96, 0x0e, 0x82, 0x76, 0xfb, 0x29, 0x79, 0xee, + 0x77, 0x3a, 0x7e, 0xeb, 0x9b, 0x92, 0x33, 0x35, 0xf9, 0xad, 0xef, 0xeb, 0xdf, 0xfa, 0xfb, 0xa5, + 0x42, 0xe3, 0xbb, 0xbf, 0xcf, 0xaa, 0xce, 0xab, 0xb3, 0xaa, 0xf3, 0xfa, 0xac, 0xea, 0xfc, 0x73, + 0x56, 0x75, 0x7e, 0x3d, 0xaf, 0x2e, 0xbc, 0x3a, 0xaf, 0x2e, 0xbc, 0x3e, 0xaf, 0x2e, 0xfc, 0xf8, + 0xb8, 0xcf, 0xf4, 0x20, 0xed, 0xba, 0xa1, 0x88, 0x3d, 0xb3, 0x83, 0xb6, 0x39, 0xe8, 0x63, 0x21, + 0x8f, 0xbc, 0xcb, 0x87, 0x6b, 0x3c, 0xfb, 0x4c, 0xda, 0xf7, 0xab, 0x7b, 0xc7, 0x3e, 0x60, 0x8f, + 0xff, 0x0d, 0x00, 0x00, 0xff, 0xff, 0xea, 0x24, 0xad, 0x2e, 0x4a, 0x07, 0x00, 0x00, } func (m *EventClaimExpired) Marshal() (dAtA []byte, err error) { @@ -724,6 +794,62 @@ func (m *EventSupplierSlashed) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *EventApplicationReimbursementRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *EventApplicationReimbursementRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *EventApplicationReimbursementRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Amount != nil { + { + size, err := m.Amount.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvent(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + if len(m.SessionId) > 0 { + i -= len(m.SessionId) + copy(dAtA[i:], m.SessionId) + i = encodeVarintEvent(dAtA, i, uint64(len(m.SessionId))) + i-- + dAtA[i] = 0x1a + } + if len(m.ServiceId) > 0 { + i -= len(m.ServiceId) + copy(dAtA[i:], m.ServiceId) + i = encodeVarintEvent(dAtA, i, uint64(len(m.ServiceId))) + i-- + dAtA[i] = 0x12 + } + if len(m.ApplicationAddr) > 0 { + i -= len(m.ApplicationAddr) + copy(dAtA[i:], m.ApplicationAddr) + i = encodeVarintEvent(dAtA, i, uint64(len(m.ApplicationAddr))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintEvent(dAtA []byte, offset int, v uint64) int { offset -= sovEvent(v) base := offset @@ -851,6 +977,31 @@ func (m *EventSupplierSlashed) Size() (n int) { return n } +func (m *EventApplicationReimbursementRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ApplicationAddr) + if l > 0 { + n += 1 + l + sovEvent(uint64(l)) + } + l = len(m.ServiceId) + if l > 0 { + n += 1 + l + sovEvent(uint64(l)) + } + l = len(m.SessionId) + if l > 0 { + n += 1 + l + sovEvent(uint64(l)) + } + if m.Amount != nil { + l = m.Amount.Size() + n += 1 + l + sovEvent(uint64(l)) + } + return n +} + func sovEvent(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -1650,6 +1801,188 @@ func (m *EventSupplierSlashed) Unmarshal(dAtA []byte) error { } return nil } +func (m *EventApplicationReimbursementRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvent + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: EventApplicationReimbursementRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: EventApplicationReimbursementRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ApplicationAddr", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvent + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvent + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvent + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ApplicationAddr = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ServiceId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvent + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvent + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvent + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ServiceId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SessionId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvent + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvent + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvent + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SessionId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvent + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEvent + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvent + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Amount == nil { + m.Amount = &types1.Coin{} + } + if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipEvent(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthEvent + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipEvent(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 From 1befc5e85c5d1cc2f7743978cac55ce1ce6cc727 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Fri, 20 Sep 2024 23:03:46 +0200 Subject: [PATCH 17/53] fix: Skip GMRR if GMI is disabled --- x/tokenomics/keeper/token_logic_modules.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/x/tokenomics/keeper/token_logic_modules.go b/x/tokenomics/keeper/token_logic_modules.go index 333f88a5e..4536b0e7d 100644 --- a/x/tokenomics/keeper/token_logic_modules.go +++ b/x/tokenomics/keeper/token_logic_modules.go @@ -381,7 +381,6 @@ func (k Keeper) TokenLogicModuleGlobalMint( logger := k.Logger().With("method", "TokenLogicModuleGlobalMint") if MintPerClaimedTokenGlobalInflation == 0 { - // TODO_UPNEXT(@olshansk): Make sure to skip GMRR TLM in this case as well. logger.Warn("global inflation is set to zero. Skipping Global Mint TLM.") return nil } @@ -471,6 +470,11 @@ func (k Keeper) TokenLogicModuleGlobalMintReimbursementRequest( ) error { logger := k.Logger().With("method", "TokenLogicModuleGlobalMintReimbursementRequest") + if MintPerClaimedTokenGlobalInflation == 0 { + logger.Warn("global inflation is set to zero. Skipping Global Mint Reimbursement Request TLM.") + return nil + } + // Determine how much new uPOKT to mint based on global inflation newMintCoin, _ := calculateGlobalPerClaimMintInflationFromSettlementAmount(actualSettlementCoin) if newMintCoin.Amount.Int64() == 0 { @@ -491,7 +495,7 @@ func (k Keeper) TokenLogicModuleGlobalMintReimbursementRequest( // Send the global per claim mint inflation uPOKT from the application module // account to the tokenomics module account. - if err := k.bankKeeper.SendCoinsFromModuleToModule( + if err = k.bankKeeper.SendCoinsFromModuleToModule( ctx, apptypes.ModuleName, tokenomicstypes.ModuleName, sdk.NewCoins(actualSettlementCoin), ); err != nil { return tokenomicstypes.ErrTokenomicsApplicationReimbursementRequestFailed.Wrapf( From 197c5a0c69ca39bb60e24d05ee32d2f0cf4a2c4d Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Mon, 14 Oct 2024 12:12:10 +0200 Subject: [PATCH 18/53] fix: Activate GMRR TLM --- x/tokenomics/keeper/token_logic_modules.go | 31 +++++-------------- .../keeper/token_logic_modules_test.go | 10 +++++- 2 files changed, 16 insertions(+), 25 deletions(-) diff --git a/x/tokenomics/keeper/token_logic_modules.go b/x/tokenomics/keeper/token_logic_modules.go index a74f64d19..75af469ce 100644 --- a/x/tokenomics/keeper/token_logic_modules.go +++ b/x/tokenomics/keeper/token_logic_modules.go @@ -115,8 +115,9 @@ type TokenLogicModuleProcessor func( // tokenLogicModuleProcessorMap is a map of TLMs to their respective independent processors. var tokenLogicModuleProcessorMap = map[TokenLogicModule]TokenLogicModuleProcessor{ - TLMRelayBurnEqualsMint: Keeper.TokenLogicModuleRelayBurnEqualsMint, - TLMGlobalMint: Keeper.TokenLogicModuleGlobalMint, + TLMRelayBurnEqualsMint: Keeper.TokenLogicModuleRelayBurnEqualsMint, + TLMGlobalMint: Keeper.TokenLogicModuleGlobalMint, + TLMGlobalMintReimbursementRequest: Keeper.TokenLogicModuleGlobalMintReimbursementRequest, } func init() { @@ -332,24 +333,6 @@ func (k Keeper) TokenLogicModuleRelayBurnEqualsMint( // order economic effects with more optionality. This could include funds // going to pnf, delegators, enabling bonuses/rebates, etc... - // Update the application's on-chain stake - newAppStake, err := application.Stake.SafeSub(settlementCoin) - if err != nil { - amountDiffCoin := settlementCoin.Amount.Sub(application.Stake.Amount) - return tokenomicstypes.ErrTokenomicsApplicationNewStakeInvalid.Wrapf("application %q stake cannot be reduced to a negative amount -%s", application.Address, amountDiffCoin) - } - application.Stake = &newAppStake - logger.Info(fmt.Sprintf("updated application %q stake to %s", application.Address, newAppStake)) - - // Burn uPOKT from the application module account which was held in escrow - // on behalf of the application account. - if err := k.bankKeeper.BurnCoins( - ctx, apptypes.ModuleName, sdk.NewCoins(settlementCoin), - ); err != nil { - return tokenomicstypes.ErrTokenomicsApplicationModuleBurn.Wrapf("burning %s from the application module account: %v", settlementCoin, err) - } - logger.Info(fmt.Sprintf("burned (%s) from the application module account", settlementCoin)) - // Mint new uPOKT to the supplier module account. // These funds will be transferred to the supplier's shareholders below. // For reference, see operate/configs/supplier_staking_config.md. @@ -384,7 +367,7 @@ func (k Keeper) TokenLogicModuleRelayBurnEqualsMint( logger.Info(fmt.Sprintf("burned (%v) from the application module account", settlementCoin)) // Update the application's on-chain stake - newAppStake, err = application.Stake.SafeSub(settlementCoin) + newAppStake, err := application.Stake.SafeSub(settlementCoin) if err != nil { return tokenomicstypes.ErrTokenomicsApplicationNewStakeInvalid.Wrapf("application %q stake cannot be reduced to a negative amount %v", application.Address, newAppStake) } @@ -495,6 +478,7 @@ func (k Keeper) TokenLogicModuleGlobalMintReimbursementRequest( ) error { logger := k.Logger().With("method", "TokenLogicModuleGlobalMintReimbursementRequest") + // Do not process the reimbursement request if there is no global inflation. if MintPerClaimedTokenGlobalInflation == 0 { logger.Warn("global inflation is set to zero. Skipping Global Mint Reimbursement Request TLM.") return nil @@ -664,9 +648,8 @@ func (k Keeper) ensureClaimAmountLimits( // before being reimbursed to the application in the future. appStake := application.GetStake() - // Global inflation per claim amount should be accounted for in the max claimable amount. - // The application should have this additional amount in its stake to account - // so it can be deducted and sent to the DAO/PNF. + // The application should have enough stake to cover for the global mint reimbursement. + // This amount is deducted from the maximum claimable amount. globalInflationCoin, _ := calculateGlobalPerClaimMintInflationFromSettlementAmount(claimSettlementCoin) maxCalibmableAmt := appStake.Amount.Quo(math.NewInt(sessionkeeper.NumSupplierPerSession)).Sub(globalInflationCoin.Amount) diff --git a/x/tokenomics/keeper/token_logic_modules_test.go b/x/tokenomics/keeper/token_logic_modules_test.go index 812090ae7..df5c7a84c 100644 --- a/x/tokenomics/keeper/token_logic_modules_test.go +++ b/x/tokenomics/keeper/token_logic_modules_test.go @@ -400,6 +400,7 @@ func TestProcessTokenLogicModules_TLMGlobalMint_Valid_MintDistributionCorrect(t // Compute mint per actor numTokensMinted := numTokensClaimed * tokenomicskeeper.MintPerClaimedTokenGlobalInflation + numTokensMintedInt := math.NewIntFromUint64(uint64(numTokensMinted)) daoMint := math.NewInt(int64(numTokensMinted * tokenomicskeeper.MintAllocationDAO)) propMint := math.NewInt(int64(numTokensMinted * tokenomicskeeper.MintAllocationProposer)) serviceOwnerMint := math.NewInt(int64(numTokensMinted * tokenomicskeeper.MintAllocationSourceOwner)) @@ -407,7 +408,7 @@ func TestProcessTokenLogicModules_TLMGlobalMint_Valid_MintDistributionCorrect(t supplierMint := float32(numTokensMinted * tokenomicskeeper.MintAllocationSupplier) // Ensure the balance was increase be the appropriate amount - require.Equal(t, daoBalanceBefore.Amount.Add(daoMint), daoBalanceAfter.Amount) + require.Equal(t, daoBalanceBefore.Amount.Add(daoMint).Add(numTokensMintedInt), daoBalanceAfter.Amount) require.Equal(t, propBalanceBefore.Amount.Add(propMint), propBalanceAfter.Amount) require.Equal(t, serviceOwnerBalanceBefore.Amount.Add(serviceOwnerMint), serviceOwnerBalanceAfter.Amount) require.Equal(t, appBalanceBefore.Amount.Add(appMint), appBalanceAfter.Amount) @@ -423,6 +424,13 @@ func TestProcessTokenLogicModules_TLMGlobalMint_Valid_MintDistributionCorrect(t acceptableRoundingDelta := tokenomicskeeper.MintDistributionAllowableTolerancePercent * float64(balanceAfter) require.InDelta(t, expectedBalanceAfter, balanceAfter, acceptableRoundingDelta) } + + foundApp, appFound := keepers.GetApplication(ctx, appAddress) + require.True(t, appFound) + + appStakeAfter := foundApp.GetStake().Amount + numTokensClaimedInt := math.NewIntFromUint64(uint64(numTokensClaimed)) + require.Equal(t, appInitialStake.Sub(numTokensMintedInt).Sub(numTokensClaimedInt), appStakeAfter) } func TestProcessTokenLogicModules_AppNotFound(t *testing.T) { From 61a62fa4c5d1ed57e5e5a0c5ad3310405e77a40f Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Mon, 14 Oct 2024 12:14:35 +0200 Subject: [PATCH 19/53] chore: Add TODO for the relay miner to account for GMRR --- x/tokenomics/keeper/token_logic_modules.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/x/tokenomics/keeper/token_logic_modules.go b/x/tokenomics/keeper/token_logic_modules.go index 75af469ce..577be76fb 100644 --- a/x/tokenomics/keeper/token_logic_modules.go +++ b/x/tokenomics/keeper/token_logic_modules.go @@ -650,6 +650,8 @@ func (k Keeper) ensureClaimAmountLimits( // The application should have enough stake to cover for the global mint reimbursement. // This amount is deducted from the maximum claimable amount. + // TODO_BETA(red-0ne): Make sure that the relay miner logic also accounts for this + // when deciding to serve an application. globalInflationCoin, _ := calculateGlobalPerClaimMintInflationFromSettlementAmount(claimSettlementCoin) maxCalibmableAmt := appStake.Amount.Quo(math.NewInt(sessionkeeper.NumSupplierPerSession)).Sub(globalInflationCoin.Amount) From 13784b880fef8da335dbd502c467b6e74d5a6af3 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Mon, 14 Oct 2024 15:22:01 +0200 Subject: [PATCH 20/53] fix: Min stake tests --- .../integration/application/min_stake_test.go | 18 ++++++++++++++---- testutil/keeper/tokenomics.go | 3 +++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/tests/integration/application/min_stake_test.go b/tests/integration/application/min_stake_test.go index 0815dba96..d7a0c1683 100644 --- a/tests/integration/application/min_stake_test.go +++ b/tests/integration/application/min_stake_test.go @@ -2,10 +2,11 @@ package application import ( "context" + "math" "testing" cosmoslog "cosmossdk.io/log" - "cosmossdk.io/math" + sdkmath "cosmossdk.io/math" cosmostypes "github.com/cosmos/cosmos-sdk/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/stretchr/testify/require" @@ -22,6 +23,7 @@ import ( sessiontypes "github.com/pokt-network/poktroll/x/session/types" "github.com/pokt-network/poktroll/x/shared" sharedtypes "github.com/pokt-network/poktroll/x/shared/types" + tokenomicskeeper "github.com/pokt-network/poktroll/x/tokenomics/keeper" ) type applicationMinStakeTestSuite struct { @@ -83,6 +85,12 @@ func (s *applicationMinStakeTestSuite) TestAppIsUnbondedIfBelowMinStakeWhenSettl // Stake a supplier for service 1. s.stakeSupplier() + proofParams := s.keepers.ProofKeeper.GetParams(s.ctx) + proofParams.ProofRequestProbability = 0 + proofRequirementThreshold := cosmostypes.NewInt64Coin(volatile.DenomuPOKT, math.MaxInt64) + proofParams.ProofRequirementThreshold = &proofRequirementThreshold + s.keepers.ProofKeeper.SetParams(s.ctx, proofParams) + // Get the session header. sessionHeader := s.getSessionHeader() @@ -107,9 +115,11 @@ func (s *applicationMinStakeTestSuite) TestAppIsUnbondedIfBelowMinStakeWhenSettl _, isAppFound := s.keepers.ApplicationKeeper.GetApplication(s.ctx, s.appBech32) require.False(s.T(), isAppFound) - // Assert that the application's stake was returned to its bank balance. - expectedAppBurn := math.NewInt(int64(s.numRelays * s.numComputeUnitsPerRelay * sharedtypes.DefaultComputeUnitsToTokensMultiplier)) - expectedAppBalance := s.appStake.SubAmount(expectedAppBurn) + // Assert that the remaining application's stake was returned to its bank balance. + expectedAppBurn := sdkmath.NewInt(int64(s.numRelays * s.numComputeUnitsPerRelay * sharedtypes.DefaultComputeUnitsToTokensMultiplier)) + globalInflationAmount := float64(expectedAppBurn.Uint64()) * tokenomicskeeper.MintPerClaimedTokenGlobalInflation + globalInflationAmountInt := sdkmath.NewInt(int64(globalInflationAmount)) + expectedAppBalance := s.appStake.SubAmount(expectedAppBurn).SubAmount(globalInflationAmountInt) appBalance = s.getAppBalance() require.Equal(s.T(), expectedAppBalance.Amount.Int64(), appBalance.Amount.Int64()) diff --git a/testutil/keeper/tokenomics.go b/testutil/keeper/tokenomics.go index f9df12788..98e95bc96 100644 --- a/testutil/keeper/tokenomics.go +++ b/testutil/keeper/tokenomics.go @@ -195,6 +195,9 @@ func TokenomicsKeeperWithActorAddrs(t testing.TB) ( mockBankKeeper.EXPECT(). SendCoinsFromModuleToModule(gomock.Any(), tokenomicstypes.ModuleName, suppliertypes.ModuleName, gomock.Any()). AnyTimes() + mockBankKeeper.EXPECT(). + SendCoinsFromModuleToModule(gomock.Any(), apptypes.ModuleName, tokenomicstypes.ModuleName, gomock.Any()). + AnyTimes() // Mock the account keeper mockAccountKeeper := mocks.NewMockAccountKeeper(ctrl) From e91a20ebfd76a806accf90a173c1a833b0f44f6d Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Fri, 18 Oct 2024 15:10:30 +0200 Subject: [PATCH 21/53] feat: Add WithProofRequirement option --- api/poktroll/supplier/tx.pulsar.go | 2 +- .../integration/application/min_stake_test.go | 9 +---- .../relay_mining_integration_test.go | 9 +---- testutil/keeper/tokenomics.go | 33 ++++++++++++++++--- x/tokenomics/keeper/token_logic_modules.go | 29 ++++++++++++++-- x/tokenomics/types/expected_keepers.go | 1 + x/tokenomics/types/tx.pb.go | 1 - 7 files changed, 59 insertions(+), 25 deletions(-) diff --git a/api/poktroll/supplier/tx.pulsar.go b/api/poktroll/supplier/tx.pulsar.go index 7a709f7f0..1d2057b01 100644 --- a/api/poktroll/supplier/tx.pulsar.go +++ b/api/poktroll/supplier/tx.pulsar.go @@ -5,11 +5,11 @@ import ( _ "cosmossdk.io/api/amino" v1beta1 "cosmossdk.io/api/cosmos/base/v1beta1" _ "cosmossdk.io/api/cosmos/msg/v1" + shared "github.com/pokt-network/poktroll/api/poktroll/shared" fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" - shared "github.com/pokt-network/poktroll/api/poktroll/shared" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" diff --git a/tests/integration/application/min_stake_test.go b/tests/integration/application/min_stake_test.go index b05eb907a..c0f2f3d14 100644 --- a/tests/integration/application/min_stake_test.go +++ b/tests/integration/application/min_stake_test.go @@ -2,7 +2,6 @@ package application import ( "context" - "math" "testing" cosmoslog "cosmossdk.io/log" @@ -48,7 +47,7 @@ func TestApplicationMinStakeTestSuite(t *testing.T) { } func (s *applicationMinStakeTestSuite) SetupTest() { - s.keepers, s.ctx = keeper.NewTokenomicsModuleKeepers(s.T(), cosmoslog.NewNopLogger()) + s.keepers, s.ctx = keeper.NewTokenomicsModuleKeepers(s.T(), cosmoslog.NewNopLogger(), keeper.WithProofRequirement(false)) proofParams := prooftypes.DefaultParams() proofParams.ProofRequestProbability = 0 @@ -84,12 +83,6 @@ func (s *applicationMinStakeTestSuite) TestAppIsUnbondedIfBelowMinStakeWhenSettl // Stake a supplier for service 1. s.stakeSupplier() - proofParams := s.keepers.ProofKeeper.GetParams(s.ctx) - proofParams.ProofRequestProbability = 0 - proofRequirementThreshold := cosmostypes.NewInt64Coin(volatile.DenomuPOKT, math.MaxInt64) - proofParams.ProofRequirementThreshold = &proofRequirementThreshold - s.keepers.ProofKeeper.SetParams(s.ctx, proofParams) - // Get the session header. sessionHeader := s.getSessionHeader() diff --git a/tests/integration/tokenomics/relay_mining_integration_test.go b/tests/integration/tokenomics/relay_mining_integration_test.go index 2beeb2196..b97dc4b15 100644 --- a/tests/integration/tokenomics/relay_mining_integration_test.go +++ b/tests/integration/tokenomics/relay_mining_integration_test.go @@ -1,7 +1,6 @@ package integration_test import ( - "math" "math/big" "testing" @@ -84,6 +83,7 @@ func TestComputeNewDifficultyHash_RewardsReflectWorkCompleted(t *testing.T) { testutils.WithService(service), testutils.WithApplication(application), testutils.WithSupplier(supplier), + testutils.WithProofRequirement(false), ) sdkCtx := sdk.UnwrapSDKContext(ctx) sdkCtx = sdkCtx.WithBlockHeight(1) @@ -94,13 +94,6 @@ func TestComputeNewDifficultyHash_RewardsReflectWorkCompleted(t *testing.T) { err := keepers.SharedKeeper.SetParams(sdkCtx, sharedParams) require.NoError(t, err) - // Set the global proof params so we never need a proof (for simplicity of this test) - err = keepers.ProofKeeper.SetParams(sdkCtx, prooftypes.Params{ - ProofRequestProbability: 0, // we never need a proof randomly - ProofRequirementThreshold: &sdk.Coin{Denom: volatile.DenomuPOKT, Amount: sdkmath.NewInt(math.MaxInt64)}, // a VERY high threshold - }) - require.NoError(t, err) - // Update the relay mining difficulty so there's always a difficulty to retrieve // for the test service. _, err = keepers.ServiceKeeper.UpdateRelayMiningDifficulty(sdkCtx, map[string]uint64{service.Id: 1}) diff --git a/testutil/keeper/tokenomics.go b/testutil/keeper/tokenomics.go index 98e95bc96..31083c757 100644 --- a/testutil/keeper/tokenomics.go +++ b/testutil/keeper/tokenomics.go @@ -2,10 +2,11 @@ package keeper import ( "context" + "math" "testing" "cosmossdk.io/log" - "cosmossdk.io/math" + sdkmath "cosmossdk.io/math" "cosmossdk.io/store" "cosmossdk.io/store/metrics" storetypes "cosmossdk.io/store/types" @@ -29,6 +30,7 @@ import ( "github.com/stretchr/testify/require" "github.com/pokt-network/poktroll/app" + "github.com/pokt-network/poktroll/app/volatile" "github.com/pokt-network/poktroll/testutil/sample" "github.com/pokt-network/poktroll/testutil/tokenomics/mocks" appkeeper "github.com/pokt-network/poktroll/x/application/keeper" @@ -117,7 +119,7 @@ func TokenomicsKeeperWithActorAddrs(t testing.TB) ( // Prepare the test application. application := apptypes.Application{ Address: sample.AccAddress(), - Stake: &sdk.Coin{Denom: "upokt", Amount: math.NewInt(100000)}, + Stake: &sdk.Coin{Denom: "upokt", Amount: sdkmath.NewInt(100000)}, ServiceConfigs: []*sharedtypes.ApplicationServiceConfig{{ServiceId: service.Id}}, } @@ -126,7 +128,7 @@ func TokenomicsKeeperWithActorAddrs(t testing.TB) ( supplier := sharedtypes.Supplier{ OwnerAddress: supplierOwnerAddr, OperatorAddress: supplierOwnerAddr, - Stake: &sdk.Coin{Denom: "upokt", Amount: math.NewInt(100000)}, + Stake: &sdk.Coin{Denom: "upokt", Amount: sdkmath.NewInt(100000)}, Services: []*sharedtypes.SupplierServiceConfig{ { ServiceId: service.Id, @@ -345,9 +347,9 @@ func NewTokenomicsModuleKeepers( require.NoError(t, bankKeeper.SetParams(sdkCtx, banktypes.DefaultParams())) // Provide some initial funds to the suppliers & applications module accounts. - err = bankKeeper.MintCoins(sdkCtx, suppliertypes.ModuleName, sdk.NewCoins(sdk.NewCoin("upokt", math.NewInt(1000000000000)))) + err = bankKeeper.MintCoins(sdkCtx, suppliertypes.ModuleName, sdk.NewCoins(sdk.NewCoin("upokt", sdkmath.NewInt(1000000000000)))) require.NoError(t, err) - err = bankKeeper.MintCoins(sdkCtx, apptypes.ModuleName, sdk.NewCoins(sdk.NewCoin("upokt", math.NewInt(1000000000000)))) + err = bankKeeper.MintCoins(sdkCtx, apptypes.ModuleName, sdk.NewCoins(sdk.NewCoin("upokt", sdkmath.NewInt(1000000000000)))) require.NoError(t, err) // Construct a real shared keeper. @@ -511,3 +513,24 @@ func WithProposerAddr(addr string) TokenomicsModuleKeepersOpt { return sdkCtx } } + +// WithProofRequirement is an option to set the proof requirement in the tokenomics module keepers. +func WithProofRequirement(required bool) TokenomicsModuleKeepersOpt { + return func(ctx context.Context, keepers *TokenomicsModuleKeepers) context.Context { + + proofParams := keepers.ProofKeeper.GetParams(ctx) + if required { + proofParams.ProofRequestProbability = 1 + proofRequirementThreshold := cosmostypes.NewInt64Coin(volatile.DenomuPOKT, 0) + proofParams.ProofRequirementThreshold = &proofRequirementThreshold + } else { + proofParams.ProofRequestProbability = 0 + proofRequirementThreshold := cosmostypes.NewInt64Coin(volatile.DenomuPOKT, math.MaxInt64) + proofParams.ProofRequirementThreshold = &proofRequirementThreshold + } + + keepers.ProofKeeper.SetParams(ctx, proofParams) + + return ctx + } +} diff --git a/x/tokenomics/keeper/token_logic_modules.go b/x/tokenomics/keeper/token_logic_modules.go index 1f2bd1d84..b4ed4339b 100644 --- a/x/tokenomics/keeper/token_logic_modules.go +++ b/x/tokenomics/keeper/token_logic_modules.go @@ -660,13 +660,38 @@ func (k Keeper) ensureClaimAmountLimits( // before being reimbursed to the application in the future. appStake := application.GetStake() - // The application should have enough stake to cover for the global mint reimbursement. - // This amount is deducted from the maximum claimable amount. // TODO_BETA(red-0ne): Make sure that the relay miner logic also accounts for this // when deciding to serve an application. + + // The application should have enough stake to cover for the global mint reimbursement. + // This amount is deducted from the maximum claimable amount. globalInflationCoin, _ := calculateGlobalPerClaimMintInflationFromSettlementAmount(claimSettlementCoin) + + // TODO_BETA(@red-0ne): Introduce a session sliding window to account for potential consumption + // during the current session (i.e. Not the session being settled) such as: + // maxCalibmableAmt = (AppStake / (currSessNum - settlingSessNum + 1) / NumSuppliersPerSession) - GlobalInflation + // In conjunction with single service applications, this would make maxClaimableAmt + // effectively addressing the issue of over-servicing. + // Example: + // - Current session num: 3 + // - Settling session num: 2 + // - Application already requested work for session 3 + // Problem: + // - If the application consumes its entire stake in settlement of session 2 + // - Then over-servicing in session 3 (i.e. No stake left to consume) + // Solution: + // - By dividing the claimable stake by 2 (3 - 2 + 1), settling session 2 assumes that + // the application will consume its maxClaimableAmt the current session (3). + // - Off-chain actors could use this formula during the servicing of session num 3 + // and assume maxClaimableAmt will be settled in session 2. + // - Garantee no over-servicing at the cost of higher application stake requirements. maxCalibmableAmt := appStake.Amount.Quo(math.NewInt(sessionkeeper.NumSupplierPerSession)).Sub(globalInflationCoin.Amount) + if !maxCalibmableAmt.IsPositive() { + // TODO_CONSIDERATION: Should we stop processing if the app stake is not ehnough? + logger.Warn(fmt.Sprintf("Application %s stake (%s) cannot cover the global inflation %s", application.GetAddress(), appStake, globalInflationCoin)) + } + // Determine the max claimable amount for the supplier based on the application's stake in this session. maxClaimableCoin := sdk.NewCoin(volatile.DenomuPOKT, maxCalibmableAmt) diff --git a/x/tokenomics/types/expected_keepers.go b/x/tokenomics/types/expected_keepers.go index 6d198a320..ea1771845 100644 --- a/x/tokenomics/types/expected_keepers.go +++ b/x/tokenomics/types/expected_keepers.go @@ -45,6 +45,7 @@ type ApplicationKeeper interface { SetApplication(ctx context.Context, app apptypes.Application) GetAllApplications(ctx context.Context) []apptypes.Application UnbondApplication(ctx context.Context, app *apptypes.Application) error + GetParams(ctx context.Context) apptypes.Params } type ProofKeeper interface { diff --git a/x/tokenomics/types/tx.pb.go b/x/tokenomics/types/tx.pb.go index e4fec264c..9f18a148c 100644 --- a/x/tokenomics/types/tx.pb.go +++ b/x/tokenomics/types/tx.pb.go @@ -125,7 +125,6 @@ type MsgUpdateParam struct { // specified in the `Params` message in `proof/params.proto.` Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` // Types that are valid to be assigned to AsType: - // // *MsgUpdateParam_AsString // *MsgUpdateParam_AsInt64 // *MsgUpdateParam_AsBytes From 568ecb9b9753c764c794e139725c25f800a70f6c Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Thu, 24 Oct 2024 21:28:00 +0200 Subject: [PATCH 22/53] fix: ensure app stake is always enough --- x/tokenomics/keeper/settle_pending_claims.go | 18 ++++- x/tokenomics/keeper/token_logic_modules.go | 79 +++++++++++++------- 2 files changed, 70 insertions(+), 27 deletions(-) diff --git a/x/tokenomics/keeper/settle_pending_claims.go b/x/tokenomics/keeper/settle_pending_claims.go index 88aea8965..094cae7c0 100644 --- a/x/tokenomics/keeper/settle_pending_claims.go +++ b/x/tokenomics/keeper/settle_pending_claims.go @@ -37,6 +37,19 @@ func (k Keeper) SettlePendingClaims(ctx sdk.Context) ( return settledResult, expiredResult, err } + // Capture the applications initial stake which will be used to calculate the + // max share any claim could receive from the application stake. + applicationInitialStakeMap := make(map[string]sdk.Coin) + for _, claim := range expiringClaims { + app, isAppFound := k.applicationKeeper.GetApplication(ctx, claim.SessionHeader.ApplicationAddress) + if !isAppFound { + err := apptypes.ErrAppNotFound.Wrapf("application address: %q", claim.SessionHeader.ApplicationAddress) + return settledResult, expiredResult, err + } + + applicationInitialStakeMap[claim.SessionHeader.ApplicationAddress] = *app.GetStake() + } + blockHeight := ctx.BlockHeight() logger.Info(fmt.Sprintf("found %d expiring claims at block height %d", len(expiringClaims), blockHeight)) @@ -178,8 +191,11 @@ func (k Keeper) SettlePendingClaims(ctx sdk.Context) ( // 1. The claim does not require a proof. // 2. The claim requires a proof and a valid proof was found. + claimApplication := claim.SessionHeader.ApplicationAddress + applicationInitialStake := applicationInitialStakeMap[claimApplication] + // Manage the mint & burn accounting for the claim. - if err = k.ProcessTokenLogicModules(ctx, &claim); err != nil { + if err = k.ProcessTokenLogicModules(ctx, &claim, applicationInitialStake); err != nil { logger.Error(fmt.Sprintf("error processing token logic modules for claim %q: %v", claim.SessionHeader.SessionId, err)) return settledResult, expiredResult, err } diff --git a/x/tokenomics/keeper/token_logic_modules.go b/x/tokenomics/keeper/token_logic_modules.go index b4ed4339b..0cd63e101 100644 --- a/x/tokenomics/keeper/token_logic_modules.go +++ b/x/tokenomics/keeper/token_logic_modules.go @@ -141,6 +141,7 @@ func init() { func (k Keeper) ProcessTokenLogicModules( ctx context.Context, claim *prooftypes.Claim, + applicationInitialStake cosmostypes.Coin, ) (err error) { logger := k.Logger().With("method", "ProcessTokenLogicModules") @@ -286,7 +287,7 @@ func (k Keeper) ProcessTokenLogicModules( // Ensure the claim amount is within the limits set by Relay Mining. // If not, update the settlement amount and emit relevant events. - actualSettlementCoin, err := k.ensureClaimAmountLimits(ctx, logger, &application, &supplier, claimSettlementCoin) + actualSettlementCoin, err := k.ensureClaimAmountLimits(ctx, logger, &application, &supplier, claimSettlementCoin, applicationInitialStake) if err != nil { return err } @@ -517,7 +518,7 @@ func (k Keeper) TokenLogicModuleGlobalMintReimbursementRequest( // Send the global per claim mint inflation uPOKT from the application module // account to the tokenomics module account. if err = k.bankKeeper.SendCoinsFromModuleToModule( - ctx, apptypes.ModuleName, tokenomicstypes.ModuleName, sdk.NewCoins(actualSettlementCoin), + ctx, apptypes.ModuleName, tokenomicstypes.ModuleName, sdk.NewCoins(newMintCoin), ); err != nil { return tokenomicstypes.ErrTokenomicsApplicationReimbursementRequestFailed.Wrapf( "sending %s from the application module account to the tokenomics module account: %v", @@ -644,6 +645,7 @@ func (k Keeper) ensureClaimAmountLimits( logger log.Logger, application *apptypes.Application, supplier *sharedtypes.Supplier, + initialApplicationStake cosmostypes.Coin, claimSettlementCoin cosmostypes.Coin, ) ( actualSettlementCoins cosmostypes.Coin, @@ -651,25 +653,22 @@ func (k Keeper) ensureClaimAmountLimits( ) { logger = logger.With("helper", "ensureClaimAmountLimits") - // TODO_BETA_OR_MAINNET(@red-0ne): The application stake gets reduced with every claim - // settlement. Relay miners use the appStake at the beginning of a session to determine - // the maximum amount they can claim. We need to somehow access and propagate this - // value (via context?) so it is the same for all TLM processors for each claim. + // TODO_BETA(@red-0ne): Make relay miners use the appStake at the beginning + // of a session to determine the maximum amount they can claim. // Note that this also incorporates MintPerClaimGlobalInflation since applications // are being overcharged by that amount and the funds are sent to the DAO/PNF // before being reimbursed to the application in the future. - appStake := application.GetStake() - - // TODO_BETA(red-0ne): Make sure that the relay miner logic also accounts for this - // when deciding to serve an application. + appStake := initialApplicationStake // The application should have enough stake to cover for the global mint reimbursement. // This amount is deducted from the maximum claimable amount. globalInflationCoin, _ := calculateGlobalPerClaimMintInflationFromSettlementAmount(claimSettlementCoin) + globalInflationAmt := globalInflationCoin.Amount + stakeRequirementAmt := claimSettlementCoin.Amount.Add(globalInflationAmt) // TODO_BETA(@red-0ne): Introduce a session sliding window to account for potential consumption // during the current session (i.e. Not the session being settled) such as: - // maxCalibmableAmt = (AppStake / (currSessNum - settlingSessNum + 1) / NumSuppliersPerSession) - GlobalInflation + // maxCalibmableAmt = (AppStake / (currSessNum - settlingSessNum + 1) / NumSuppliersPerSession) // In conjunction with single service applications, this would make maxClaimableAmt // effectively addressing the issue of over-servicing. // Example: @@ -685,33 +684,46 @@ func (k Keeper) ensureClaimAmountLimits( // - Off-chain actors could use this formula during the servicing of session num 3 // and assume maxClaimableAmt will be settled in session 2. // - Garantee no over-servicing at the cost of higher application stake requirements. - maxCalibmableAmt := appStake.Amount.Quo(math.NewInt(sessionkeeper.NumSupplierPerSession)).Sub(globalInflationCoin.Amount) + maxClaimableAmt := appStake.Amount.Quo(math.NewInt(sessionkeeper.NumSupplierPerSession)) + maxClaimSettlementAmt := stakeToMaxSettlementAmount(maxClaimableAmt) + + // Check if the claimable amount is capped by the max claimable amount. + if stakeRequirementAmt.GT(maxClaimableAmt) { + logger.Warn(fmt.Sprintf("Claim by supplier %s EXCEEDS LIMITS for application %s. Max claimable amount < Claim amount: %v < %v", + supplier.GetOperatorAddress(), application.GetAddress(), maxClaimableAmt, claimSettlementCoin.Amount)) - if !maxCalibmableAmt.IsPositive() { - // TODO_CONSIDERATION: Should we stop processing if the app stake is not ehnough? - logger.Warn(fmt.Sprintf("Application %s stake (%s) cannot cover the global inflation %s", application.GetAddress(), appStake, globalInflationCoin)) + stakeRequirementAmt = maxClaimableAmt + maxClaimSettlementAmt = stakeToMaxSettlementAmount(stakeRequirementAmt) + globalInflationAmt = stakeRequirementAmt.Sub(maxClaimSettlementAmt) } - // Determine the max claimable amount for the supplier based on the application's stake in this session. - maxClaimableCoin := sdk.NewCoin(volatile.DenomuPOKT, maxCalibmableAmt) + // Check if the claimable amount should be capped by an insufficient application stake. + if maxClaimableAmt.LT(stakeRequirementAmt) { + logger.Warn(fmt.Sprintf("Claim by supplier %q EXCEEDS application %q claimable stake. Claim amount > App claimable stake: %v > %v", + supplier.GetOperatorAddress(), application.GetAddress(), claimSettlementCoin, maxClaimableAmt)) + stakeRequirementAmt = maxClaimableAmt + maxClaimSettlementAmt = stakeToMaxSettlementAmount(stakeRequirementAmt) + globalInflationAmt = stakeRequirementAmt.Sub(maxClaimSettlementAmt) + } - if maxClaimableCoin.Amount.GTE(claimSettlementCoin.Amount) { + // Nominal case: The claimable amount is within the limits set by Relay Mining. + if claimSettlementCoin.Amount.LTE(maxClaimSettlementAmt) { logger.Info(fmt.Sprintf("Claim by supplier %s IS WITHIN LIMITS of servicing application %s. Max claimable amount >= Claim amount: %v >= %v", - supplier.GetOperatorAddress(), application.GetAddress(), maxClaimableCoin, claimSettlementCoin.Amount)) + supplier.GetOperatorAddress(), application.GetAddress(), maxClaimSettlementAmt, claimSettlementCoin.Amount)) return claimSettlementCoin, nil } - logger.Warn(fmt.Sprintf("Claim by supplier %s EXCEEDS LIMITS for application %s. Max claimable amount < Claim amount: %v < %v", - supplier.GetOperatorAddress(), application.GetAddress(), maxClaimableCoin, claimSettlementCoin.Amount)) + // Claimable amount is capped by the max claimable amount or the application allocated stake. + // Determine the max claimable amount for the supplier based on the application's stake in this session. + maxClaimableCoin := sdk.NewCoin(volatile.DenomuPOKT, maxClaimSettlementAmt) - // Reduce the settlement amount if the application was over-serviced - actualSettlementCoins = maxClaimableCoin + stakeRequirementCoin := sdk.NewCoin(volatile.DenomuPOKT, stakeRequirementAmt) // Prepare and emit the event for the application being overserviced applicationOverservicedEvent := &tokenomicstypes.EventApplicationOverserviced{ - ApplicationAddr: application.Address, + ApplicationAddr: application.GetAddress(), SupplierOperatorAddr: supplier.GetOperatorAddress(), - ExpectedBurn: &claimSettlementCoin, + ExpectedBurn: &stakeRequirementCoin, EffectiveBurn: &maxClaimableCoin, } eventManager := cosmostypes.UnwrapSDKContext(ctx).EventManager() @@ -720,7 +732,7 @@ func (k Keeper) ensureClaimAmountLimits( tokenomicstypes.ErrTokenomicsEmittingEventFailed.Wrapf("error emitting event %v", applicationOverservicedEvent) } - return actualSettlementCoins, nil + return maxClaimableCoin, nil } // distributeSupplierRewardsToShareHolders distributes the supplier rewards to its @@ -797,6 +809,21 @@ func calculateGlobalPerClaimMintInflationFromSettlementAmount(settlementCoin sdk return mintAmtCoin, *newMintAmtFloat } +// stakeToMaxSettlementAmount calculates the max amount of uPOKT to that the supplier +// can claim based on the stake share and the global inflation allocation percentage. +// This is the inverse of calculateGlobalPerClaimMintInflationFromSettlementAmount. +// stake = maxSettlementAmt + globalInflationAmt +// stake = maxSettlementAmt + (maxSettlementAmt * MintPerClaimedTokenGlobalInflation) +// stake = maxSettlementAmt * (1 + MintPerClaimedTokenGlobalInflation) +// maxSettlementAmt = stake / (1 + MintPerClaimedTokenGlobalInflation) +func stakeToMaxSettlementAmount(stakeShare math.Int) math.Int { + stakeSahreFloat := big.NewFloat(0).SetInt(stakeShare.BigInt()) + maxSettlementAmountFloat := big.NewFloat(0).Quo(stakeSahreFloat, big.NewFloat(1+MintPerClaimedTokenGlobalInflation)) + + settlementAmount, _ := maxSettlementAmountFloat.Int(nil) + return math.NewIntFromBigInt(settlementAmount) +} + // calculateAllocationAmount does big float arithmetic to determine the absolute // amount from amountFloat based on the allocation percentage provided. // TODO_MAINNET(@bryanchriswhite): Measure and limit the precision loss here. From 6c836e73adbc4110094d9ffea132b18563a51307 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Thu, 24 Oct 2024 23:33:13 +0200 Subject: [PATCH 23/53] fix: Ensure no over-servicing --- api/poktroll/tokenomics/event.pulsar.go | 229 +++++++++++++++--- e2e/tests/0_settlement.feature | 6 +- proto/poktroll/tokenomics/event.proto | 8 +- testutil/keeper/tokenomics.go | 4 +- x/tokenomics/keeper/token_logic_modules.go | 39 ++- .../keeper/token_logic_modules_test.go | 17 +- x/tokenomics/types/event.pb.go | 222 ++++++++++++----- 7 files changed, 392 insertions(+), 133 deletions(-) diff --git a/api/poktroll/tokenomics/event.pulsar.go b/api/poktroll/tokenomics/event.pulsar.go index a4fe5e521..cf18db79d 100644 --- a/api/poktroll/tokenomics/event.pulsar.go +++ b/api/poktroll/tokenomics/event.pulsar.go @@ -2617,17 +2617,21 @@ func (x *fastReflection_EventSupplierSlashed) ProtoMethods() *protoiface.Methods } var ( - md_EventApplicationReimbursementRequest protoreflect.MessageDescriptor - fd_EventApplicationReimbursementRequest_application_addr protoreflect.FieldDescriptor - fd_EventApplicationReimbursementRequest_service_id protoreflect.FieldDescriptor - fd_EventApplicationReimbursementRequest_session_id protoreflect.FieldDescriptor - fd_EventApplicationReimbursementRequest_amount protoreflect.FieldDescriptor + md_EventApplicationReimbursementRequest protoreflect.MessageDescriptor + fd_EventApplicationReimbursementRequest_application_addr protoreflect.FieldDescriptor + fd_EventApplicationReimbursementRequest_supplier_operator_addr protoreflect.FieldDescriptor + fd_EventApplicationReimbursementRequest_supplier_owner_addr protoreflect.FieldDescriptor + fd_EventApplicationReimbursementRequest_service_id protoreflect.FieldDescriptor + fd_EventApplicationReimbursementRequest_session_id protoreflect.FieldDescriptor + fd_EventApplicationReimbursementRequest_amount protoreflect.FieldDescriptor ) func init() { file_poktroll_tokenomics_event_proto_init() md_EventApplicationReimbursementRequest = File_poktroll_tokenomics_event_proto.Messages().ByName("EventApplicationReimbursementRequest") fd_EventApplicationReimbursementRequest_application_addr = md_EventApplicationReimbursementRequest.Fields().ByName("application_addr") + fd_EventApplicationReimbursementRequest_supplier_operator_addr = md_EventApplicationReimbursementRequest.Fields().ByName("supplier_operator_addr") + fd_EventApplicationReimbursementRequest_supplier_owner_addr = md_EventApplicationReimbursementRequest.Fields().ByName("supplier_owner_addr") fd_EventApplicationReimbursementRequest_service_id = md_EventApplicationReimbursementRequest.Fields().ByName("service_id") fd_EventApplicationReimbursementRequest_session_id = md_EventApplicationReimbursementRequest.Fields().ByName("session_id") fd_EventApplicationReimbursementRequest_amount = md_EventApplicationReimbursementRequest.Fields().ByName("amount") @@ -2704,6 +2708,18 @@ func (x *fastReflection_EventApplicationReimbursementRequest) Range(f func(proto return } } + if x.SupplierOperatorAddr != "" { + value := protoreflect.ValueOfString(x.SupplierOperatorAddr) + if !f(fd_EventApplicationReimbursementRequest_supplier_operator_addr, value) { + return + } + } + if x.SupplierOwnerAddr != "" { + value := protoreflect.ValueOfString(x.SupplierOwnerAddr) + if !f(fd_EventApplicationReimbursementRequest_supplier_owner_addr, value) { + return + } + } if x.ServiceId != "" { value := protoreflect.ValueOfString(x.ServiceId) if !f(fd_EventApplicationReimbursementRequest_service_id, value) { @@ -2739,6 +2755,10 @@ func (x *fastReflection_EventApplicationReimbursementRequest) Has(fd protoreflec switch fd.FullName() { case "poktroll.tokenomics.EventApplicationReimbursementRequest.application_addr": return x.ApplicationAddr != "" + case "poktroll.tokenomics.EventApplicationReimbursementRequest.supplier_operator_addr": + return x.SupplierOperatorAddr != "" + case "poktroll.tokenomics.EventApplicationReimbursementRequest.supplier_owner_addr": + return x.SupplierOwnerAddr != "" case "poktroll.tokenomics.EventApplicationReimbursementRequest.service_id": return x.ServiceId != "" case "poktroll.tokenomics.EventApplicationReimbursementRequest.session_id": @@ -2763,6 +2783,10 @@ func (x *fastReflection_EventApplicationReimbursementRequest) Clear(fd protorefl switch fd.FullName() { case "poktroll.tokenomics.EventApplicationReimbursementRequest.application_addr": x.ApplicationAddr = "" + case "poktroll.tokenomics.EventApplicationReimbursementRequest.supplier_operator_addr": + x.SupplierOperatorAddr = "" + case "poktroll.tokenomics.EventApplicationReimbursementRequest.supplier_owner_addr": + x.SupplierOwnerAddr = "" case "poktroll.tokenomics.EventApplicationReimbursementRequest.service_id": x.ServiceId = "" case "poktroll.tokenomics.EventApplicationReimbursementRequest.session_id": @@ -2788,6 +2812,12 @@ func (x *fastReflection_EventApplicationReimbursementRequest) Get(descriptor pro case "poktroll.tokenomics.EventApplicationReimbursementRequest.application_addr": value := x.ApplicationAddr return protoreflect.ValueOfString(value) + case "poktroll.tokenomics.EventApplicationReimbursementRequest.supplier_operator_addr": + value := x.SupplierOperatorAddr + return protoreflect.ValueOfString(value) + case "poktroll.tokenomics.EventApplicationReimbursementRequest.supplier_owner_addr": + value := x.SupplierOwnerAddr + return protoreflect.ValueOfString(value) case "poktroll.tokenomics.EventApplicationReimbursementRequest.service_id": value := x.ServiceId return protoreflect.ValueOfString(value) @@ -2819,6 +2849,10 @@ func (x *fastReflection_EventApplicationReimbursementRequest) Set(fd protoreflec switch fd.FullName() { case "poktroll.tokenomics.EventApplicationReimbursementRequest.application_addr": x.ApplicationAddr = value.Interface().(string) + case "poktroll.tokenomics.EventApplicationReimbursementRequest.supplier_operator_addr": + x.SupplierOperatorAddr = value.Interface().(string) + case "poktroll.tokenomics.EventApplicationReimbursementRequest.supplier_owner_addr": + x.SupplierOwnerAddr = value.Interface().(string) case "poktroll.tokenomics.EventApplicationReimbursementRequest.service_id": x.ServiceId = value.Interface().(string) case "poktroll.tokenomics.EventApplicationReimbursementRequest.session_id": @@ -2852,6 +2886,10 @@ func (x *fastReflection_EventApplicationReimbursementRequest) Mutable(fd protore return protoreflect.ValueOfMessage(x.Amount.ProtoReflect()) case "poktroll.tokenomics.EventApplicationReimbursementRequest.application_addr": panic(fmt.Errorf("field application_addr of message poktroll.tokenomics.EventApplicationReimbursementRequest is not mutable")) + case "poktroll.tokenomics.EventApplicationReimbursementRequest.supplier_operator_addr": + panic(fmt.Errorf("field supplier_operator_addr of message poktroll.tokenomics.EventApplicationReimbursementRequest is not mutable")) + case "poktroll.tokenomics.EventApplicationReimbursementRequest.supplier_owner_addr": + panic(fmt.Errorf("field supplier_owner_addr of message poktroll.tokenomics.EventApplicationReimbursementRequest is not mutable")) case "poktroll.tokenomics.EventApplicationReimbursementRequest.service_id": panic(fmt.Errorf("field service_id of message poktroll.tokenomics.EventApplicationReimbursementRequest is not mutable")) case "poktroll.tokenomics.EventApplicationReimbursementRequest.session_id": @@ -2871,6 +2909,10 @@ func (x *fastReflection_EventApplicationReimbursementRequest) NewField(fd protor switch fd.FullName() { case "poktroll.tokenomics.EventApplicationReimbursementRequest.application_addr": return protoreflect.ValueOfString("") + case "poktroll.tokenomics.EventApplicationReimbursementRequest.supplier_operator_addr": + return protoreflect.ValueOfString("") + case "poktroll.tokenomics.EventApplicationReimbursementRequest.supplier_owner_addr": + return protoreflect.ValueOfString("") case "poktroll.tokenomics.EventApplicationReimbursementRequest.service_id": return protoreflect.ValueOfString("") case "poktroll.tokenomics.EventApplicationReimbursementRequest.session_id": @@ -2951,6 +2993,14 @@ func (x *fastReflection_EventApplicationReimbursementRequest) ProtoMethods() *pr if l > 0 { n += 1 + l + runtime.Sov(uint64(l)) } + l = len(x.SupplierOperatorAddr) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + l = len(x.SupplierOwnerAddr) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } l = len(x.ServiceId) if l > 0 { n += 1 + l + runtime.Sov(uint64(l)) @@ -3004,20 +3054,34 @@ func (x *fastReflection_EventApplicationReimbursementRequest) ProtoMethods() *pr copy(dAtA[i:], encoded) i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) i-- - dAtA[i] = 0x22 + dAtA[i] = 0x32 } if len(x.SessionId) > 0 { i -= len(x.SessionId) copy(dAtA[i:], x.SessionId) i = runtime.EncodeVarint(dAtA, i, uint64(len(x.SessionId))) i-- - dAtA[i] = 0x1a + dAtA[i] = 0x2a } if len(x.ServiceId) > 0 { i -= len(x.ServiceId) copy(dAtA[i:], x.ServiceId) i = runtime.EncodeVarint(dAtA, i, uint64(len(x.ServiceId))) i-- + dAtA[i] = 0x22 + } + if len(x.SupplierOwnerAddr) > 0 { + i -= len(x.SupplierOwnerAddr) + copy(dAtA[i:], x.SupplierOwnerAddr) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.SupplierOwnerAddr))) + i-- + dAtA[i] = 0x1a + } + if len(x.SupplierOperatorAddr) > 0 { + i -= len(x.SupplierOperatorAddr) + copy(dAtA[i:], x.SupplierOperatorAddr) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.SupplierOperatorAddr))) + i-- dAtA[i] = 0x12 } if len(x.ApplicationAddr) > 0 { @@ -3109,6 +3173,70 @@ func (x *fastReflection_EventApplicationReimbursementRequest) ProtoMethods() *pr x.ApplicationAddr = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field SupplierOperatorAddr", wireType) + } + var stringLen uint64 + 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++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.SupplierOperatorAddr = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field SupplierOwnerAddr", wireType) + } + var stringLen uint64 + 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++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.SupplierOwnerAddr = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: if wireType != 2 { return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field ServiceId", wireType) } @@ -3140,7 +3268,7 @@ func (x *fastReflection_EventApplicationReimbursementRequest) ProtoMethods() *pr } x.ServiceId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 3: + case 5: if wireType != 2 { return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field SessionId", wireType) } @@ -3172,7 +3300,7 @@ func (x *fastReflection_EventApplicationReimbursementRequest) ProtoMethods() *pr } x.SessionId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 4: + case 6: if wireType != 2 { return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) } @@ -3608,10 +3736,12 @@ type EventApplicationReimbursementRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - ApplicationAddr string `protobuf:"bytes,1,opt,name=application_addr,json=applicationAddr,proto3" json:"application_addr,omitempty"` - ServiceId string `protobuf:"bytes,2,opt,name=service_id,json=serviceId,proto3" json:"service_id,omitempty"` - SessionId string `protobuf:"bytes,3,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"` - Amount *v1beta1.Coin `protobuf:"bytes,4,opt,name=amount,proto3" json:"amount,omitempty"` + ApplicationAddr string `protobuf:"bytes,1,opt,name=application_addr,json=applicationAddr,proto3" json:"application_addr,omitempty"` + SupplierOperatorAddr string `protobuf:"bytes,2,opt,name=supplier_operator_addr,json=supplierOperatorAddr,proto3" json:"supplier_operator_addr,omitempty"` + SupplierOwnerAddr string `protobuf:"bytes,3,opt,name=supplier_owner_addr,json=supplierOwnerAddr,proto3" json:"supplier_owner_addr,omitempty"` + ServiceId string `protobuf:"bytes,4,opt,name=service_id,json=serviceId,proto3" json:"service_id,omitempty"` + SessionId string `protobuf:"bytes,5,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"` + Amount *v1beta1.Coin `protobuf:"bytes,6,opt,name=amount,proto3" json:"amount,omitempty"` } func (x *EventApplicationReimbursementRequest) Reset() { @@ -3641,6 +3771,20 @@ func (x *EventApplicationReimbursementRequest) GetApplicationAddr() string { return "" } +func (x *EventApplicationReimbursementRequest) GetSupplierOperatorAddr() string { + if x != nil { + return x.SupplierOperatorAddr + } + return "" +} + +func (x *EventApplicationReimbursementRequest) GetSupplierOwnerAddr() string { + if x != nil { + return x.SupplierOwnerAddr + } + return "" +} + func (x *EventApplicationReimbursementRequest) GetServiceId() string { if x != nil { return x.ServiceId @@ -3764,38 +3908,45 @@ var file_poktroll_tokenomics_event_proto_rawDesc = []byte{ 0x73, 0x68, 0x69, 0x6e, 0x67, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x0e, 0x73, - 0x6c, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0xc2, 0x01, + 0x6c, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0xa8, 0x02, 0x0a, 0x24, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x69, 0x6d, 0x62, 0x75, 0x72, 0x73, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x64, 0x64, - 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, - 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, - 0x31, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x19, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, - 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, - 0x6e, 0x74, 0x2a, 0x60, 0x0a, 0x15, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x45, 0x78, 0x70, 0x69, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x1d, 0x45, - 0x58, 0x50, 0x49, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, - 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x11, - 0x0a, 0x0d, 0x50, 0x52, 0x4f, 0x4f, 0x46, 0x5f, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4e, 0x47, 0x10, - 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x52, 0x4f, 0x4f, 0x46, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, - 0x49, 0x44, 0x10, 0x02, 0x42, 0xbc, 0x01, 0xd8, 0xe2, 0x1e, 0x01, 0x0a, 0x17, 0x63, 0x6f, 0x6d, - 0x2e, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, - 0x6d, 0x69, 0x63, 0x73, 0x42, 0x0a, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, - 0x50, 0x01, 0x5a, 0x24, 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, 0x74, 0x6f, - 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0xa2, 0x02, 0x03, 0x50, 0x54, 0x58, 0xaa, 0x02, - 0x13, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, - 0x6d, 0x69, 0x63, 0x73, 0xca, 0x02, 0x13, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, - 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0xe2, 0x02, 0x1f, 0x50, 0x6f, 0x6b, + 0x72, 0x12, 0x34, 0x0a, 0x16, 0x73, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x5f, 0x6f, 0x70, + 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x14, 0x73, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x4f, 0x70, 0x65, 0x72, 0x61, + 0x74, 0x6f, 0x72, 0x41, 0x64, 0x64, 0x72, 0x12, 0x2e, 0x0a, 0x13, 0x73, 0x75, 0x70, 0x70, 0x6c, + 0x69, 0x65, 0x72, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x73, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x4f, 0x77, + 0x6e, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x31, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, + 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x69, 0x6e, + 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x2a, 0x60, 0x0a, 0x15, 0x43, 0x6c, 0x61, 0x69, + 0x6d, 0x45, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x61, 0x73, 0x6f, + 0x6e, 0x12, 0x21, 0x0a, 0x1d, 0x45, 0x58, 0x50, 0x49, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, + 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, + 0x45, 0x44, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x52, 0x4f, 0x4f, 0x46, 0x5f, 0x4d, 0x49, + 0x53, 0x53, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x52, 0x4f, 0x4f, 0x46, + 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x02, 0x42, 0xbc, 0x01, 0xd8, 0xe2, 0x1e, + 0x01, 0x0a, 0x17, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, + 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0x42, 0x0a, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x24, 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, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0xa2, 0x02, + 0x03, 0x50, 0x54, 0x58, 0xaa, 0x02, 0x13, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, + 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0xca, 0x02, 0x13, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, - 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x14, 0x50, - 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x3a, 0x3a, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, - 0x69, 0x63, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0xe2, 0x02, 0x1f, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x54, 0x6f, 0x6b, 0x65, + 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0xea, 0x02, 0x14, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x3a, 0x3a, 0x54, + 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( diff --git a/e2e/tests/0_settlement.feature b/e2e/tests/0_settlement.feature index 0fe804d5a..26ae94691 100644 --- a/e2e/tests/0_settlement.feature +++ b/e2e/tests/0_settlement.feature @@ -38,7 +38,8 @@ Feature: Tokenomics Namespace # TODO_TECHDEBT: Update this test such the inflation is set and enforce that Mint=Burn # Then add a separate test that only validates that inflation is enforced correctly Then the account balance of "supplier1" should be "898" uPOKT "more" than before - And the "application" stake of "app1" should be "840" uPOKT "less" than before + # The application stake should be less 840 * (1 + glbal_inflation) = 840 * 1.1 = 924 + And the "application" stake of "app1" should be "924" uPOKT "less" than before Scenario: TLM Mint=Burn when a valid claim is create but not required # Baseline @@ -72,7 +73,8 @@ Feature: Tokenomics Namespace # Please note that supplier mint is > app burn because of inflation # TODO_TECHDEBT: Update this test such the inflation is set and enforce that Mint=Burn Then the account balance of "supplier1" should be "449" uPOKT "more" than before - And the "application" stake of "app1" should be "420" uPOKT "less" than before + # The application stake should be less 420 * (1 + glbal_inflation) = 420 * 1.1 = 462 + And the "application" stake of "app1" should be "462" uPOKT "less" than before # TODO_ADDTEST: Implement the following scenarios # Scenario: Supplier revenue shares are properly distributed diff --git a/proto/poktroll/tokenomics/event.proto b/proto/poktroll/tokenomics/event.proto index f75a8324c..c3751c60d 100644 --- a/proto/poktroll/tokenomics/event.proto +++ b/proto/poktroll/tokenomics/event.proto @@ -85,7 +85,9 @@ message EventSupplierSlashed { // a reimbursement message EventApplicationReimbursementRequest { string application_addr = 1; - string service_id = 2; - string session_id = 3; - cosmos.base.v1beta1.Coin amount = 4; + string supplier_operator_addr = 2; + string supplier_owner_addr = 3; + string service_id = 4; + string session_id = 5; + cosmos.base.v1beta1.Coin amount = 6; } \ No newline at end of file diff --git a/testutil/keeper/tokenomics.go b/testutil/keeper/tokenomics.go index 31083c757..79d3cb828 100644 --- a/testutil/keeper/tokenomics.go +++ b/testutil/keeper/tokenomics.go @@ -529,7 +529,9 @@ func WithProofRequirement(required bool) TokenomicsModuleKeepersOpt { proofParams.ProofRequirementThreshold = &proofRequirementThreshold } - keepers.ProofKeeper.SetParams(ctx, proofParams) + if err := keepers.ProofKeeper.SetParams(ctx, proofParams); err != nil { + panic(err) + } return ctx } diff --git a/x/tokenomics/keeper/token_logic_modules.go b/x/tokenomics/keeper/token_logic_modules.go index 0cd63e101..1d9ae4446 100644 --- a/x/tokenomics/keeper/token_logic_modules.go +++ b/x/tokenomics/keeper/token_logic_modules.go @@ -504,20 +504,16 @@ func (k Keeper) TokenLogicModuleGlobalMintReimbursementRequest( } // Update the application's on-chain stake - newAppStake, err := application.Stake.SafeSub(newMintCoin) - if err != nil { - amountDiffCoin := actualSettlementCoin.Amount.Sub(application.Stake.Amount) - return tokenomicstypes.ErrTokenomicsApplicationReimbursementRequestFailed.Wrapf( - "application %q stake cannot be reduced to a negative amount -%s", - application.Address, amountDiffCoin, - ) - } + // This should not fall below zero since `ensureClaimAmountLimits` should have + // already checked and adjusted the settlement amount so that the application + // stake covers the global inflation. + newAppStake := application.Stake.Sub(newMintCoin) application.Stake = &newAppStake logger.Info(fmt.Sprintf("updated application %q stake to %s", application.Address, newAppStake)) // Send the global per claim mint inflation uPOKT from the application module // account to the tokenomics module account. - if err = k.bankKeeper.SendCoinsFromModuleToModule( + if err := k.bankKeeper.SendCoinsFromModuleToModule( ctx, apptypes.ModuleName, tokenomicstypes.ModuleName, sdk.NewCoins(newMintCoin), ); err != nil { return tokenomicstypes.ErrTokenomicsApplicationReimbursementRequestFailed.Wrapf( @@ -550,17 +546,19 @@ func (k Keeper) TokenLogicModuleGlobalMintReimbursementRequest( // Prepare and emit the event for the application being overcharged. reimbursementRequestEvent := &tokenomicstypes.EventApplicationReimbursementRequest{ - ApplicationAddr: application.Address, - ServiceId: service.Id, - SessionId: sessionHeader.SessionId, - Amount: &newMintCoin, + ApplicationAddr: application.Address, + SupplierOperatorAddr: supplier.OperatorAddress, + SupplierOwnerAddr: supplier.OwnerAddress, + ServiceId: service.Id, + SessionId: sessionHeader.SessionId, + Amount: &newMintCoin, } eventManger := cosmostypes.UnwrapSDKContext(ctx).EventManager() if err := eventManger.EmitTypedEvent(reimbursementRequestEvent); err != nil { return tokenomicstypes.ErrTokenomicsEmittingEventFailed.Wrapf( - "error emitting event %v", - reimbursementRequestEvent, + "(%+v): %s", + reimbursementRequestEvent, err, ) } @@ -645,8 +643,8 @@ func (k Keeper) ensureClaimAmountLimits( logger log.Logger, application *apptypes.Application, supplier *sharedtypes.Supplier, - initialApplicationStake cosmostypes.Coin, claimSettlementCoin cosmostypes.Coin, + initialApplicationStake cosmostypes.Coin, ) ( actualSettlementCoins cosmostypes.Coin, err error, @@ -665,10 +663,11 @@ func (k Keeper) ensureClaimAmountLimits( globalInflationCoin, _ := calculateGlobalPerClaimMintInflationFromSettlementAmount(claimSettlementCoin) globalInflationAmt := globalInflationCoin.Amount stakeRequirementAmt := claimSettlementCoin.Amount.Add(globalInflationAmt) + totalClaimedCoin := sdk.NewCoin(volatile.DenomuPOKT, stakeRequirementAmt) // TODO_BETA(@red-0ne): Introduce a session sliding window to account for potential consumption // during the current session (i.e. Not the session being settled) such as: - // maxCalibmableAmt = (AppStake / (currSessNum - settlingSessNum + 1) / NumSuppliersPerSession) + // maxClaimableAmt = (AppStake / (currSessNum - settlingSessNum + 1) / NumSuppliersPerSession) // In conjunction with single service applications, this would make maxClaimableAmt // effectively addressing the issue of over-servicing. // Example: @@ -683,7 +682,7 @@ func (k Keeper) ensureClaimAmountLimits( // the application will consume its maxClaimableAmt the current session (3). // - Off-chain actors could use this formula during the servicing of session num 3 // and assume maxClaimableAmt will be settled in session 2. - // - Garantee no over-servicing at the cost of higher application stake requirements. + // - Guarantee no over-servicing at the cost of higher application stake requirements. maxClaimableAmt := appStake.Amount.Quo(math.NewInt(sessionkeeper.NumSupplierPerSession)) maxClaimSettlementAmt := stakeToMaxSettlementAmount(maxClaimableAmt) @@ -717,13 +716,11 @@ func (k Keeper) ensureClaimAmountLimits( // Determine the max claimable amount for the supplier based on the application's stake in this session. maxClaimableCoin := sdk.NewCoin(volatile.DenomuPOKT, maxClaimSettlementAmt) - stakeRequirementCoin := sdk.NewCoin(volatile.DenomuPOKT, stakeRequirementAmt) - // Prepare and emit the event for the application being overserviced applicationOverservicedEvent := &tokenomicstypes.EventApplicationOverserviced{ ApplicationAddr: application.GetAddress(), SupplierOperatorAddr: supplier.GetOperatorAddress(), - ExpectedBurn: &stakeRequirementCoin, + ExpectedBurn: &totalClaimedCoin, EffectiveBurn: &maxClaimableCoin, } eventManager := cosmostypes.UnwrapSDKContext(ctx).EventManager() diff --git a/x/tokenomics/keeper/token_logic_modules_test.go b/x/tokenomics/keeper/token_logic_modules_test.go index 2991cbfda..51bd4e46a 100644 --- a/x/tokenomics/keeper/token_logic_modules_test.go +++ b/x/tokenomics/keeper/token_logic_modules_test.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "fmt" + math2 "math" "testing" "cosmossdk.io/math" @@ -118,7 +119,7 @@ func TestProcessTokenLogicModules_TLMBurnEqualsMint_Valid(t *testing.T) { claim := prepareTestClaim(numRelays, service, &app, &supplier) // Process the token logic modules - err = keepers.ProcessTokenLogicModules(ctx, &claim) + err = keepers.ProcessTokenLogicModules(ctx, &claim, appStake) require.NoError(t, err) // Assert that `applicationAddress` account balance is *unchanged* @@ -166,7 +167,7 @@ func TestProcessTokenLogicModules_TLMBurnEqualsMint_Valid(t *testing.T) { // DEV_NOTE: Most of the setup here is a copy-paste of TLMBurnEqualsMintValid // except that the application stake is calculated to explicitly be too low to // handle all the relays completed. -func TestProcessTokenLogicModules_TLMBurnEqualsMint_Invalid_SupplierExceedsMaxClaimableAmount(t *testing.T) { +func TestProcessTokenLogicModules_TLMBurnEqualsMint_Valid_SupplierExceedsMaxClaimableAmount(t *testing.T) { // Test Parameters globalComputeUnitsToTokensMultiplier := uint64(1) serviceComputeUnitsPerRelay := uint64(100) @@ -248,7 +249,7 @@ func TestProcessTokenLogicModules_TLMBurnEqualsMint_Invalid_SupplierExceedsMaxCl claim := prepareTestClaim(numRelays, service, &app, &supplier) // Process the token logic modules - err = keepers.ProcessTokenLogicModules(ctx, &claim) + err = keepers.ProcessTokenLogicModules(ctx, &claim, appStake) require.NoError(t, err) // Assert that `applicationAddress` account balance is *unchanged* @@ -383,7 +384,7 @@ func TestProcessTokenLogicModules_TLMGlobalMint_Valid_MintDistributionCorrect(t } // Process the token logic modules - err = keepers.ProcessTokenLogicModules(ctx, &claim) + err = keepers.ProcessTokenLogicModules(ctx, &claim, appStake) require.NoError(t, err) // Determine balances after inflation @@ -451,7 +452,7 @@ func TestProcessTokenLogicModules_AppNotFound(t *testing.T) { } // Process the token logic modules - err := keeper.ProcessTokenLogicModules(ctx, &claim) + err := keeper.ProcessTokenLogicModules(ctx, &claim, uPOKTCoin(math2.MaxInt)) require.Error(t, err) require.ErrorIs(t, err, tokenomicstypes.ErrTokenomicsApplicationNotFound) } @@ -474,7 +475,7 @@ func TestProcessTokenLogicModules_ServiceNotFound(t *testing.T) { } // Execute test function - err := keeper.ProcessTokenLogicModules(ctx, &claim) + err := keeper.ProcessTokenLogicModules(ctx, &claim, uPOKTCoin(math2.MaxInt)) require.Error(t, err) require.ErrorIs(t, err, tokenomicstypes.ErrTokenomicsServiceNotFound) @@ -544,7 +545,7 @@ func TestProcessTokenLogicModules_InvalidRoot(t *testing.T) { claim.RootHash = smt.MerkleRoot(test.root[:]) // Execute test function - err := keeper.ProcessTokenLogicModules(ctx, &claim) + err := keeper.ProcessTokenLogicModules(ctx, &claim, uPOKTCoin(math2.MaxInt)) // Assert the error if test.errExpected { @@ -634,7 +635,7 @@ func TestProcessTokenLogicModules_InvalidClaim(t *testing.T) { err = fmt.Errorf("panic occurred: %v", r) } }() - return keeper.ProcessTokenLogicModules(ctx, test.claim) + return keeper.ProcessTokenLogicModules(ctx, test.claim, uPOKTCoin(math2.MaxInt)) }() // Assert the error diff --git a/x/tokenomics/types/event.pb.go b/x/tokenomics/types/event.pb.go index d852f7921..8570fd911 100644 --- a/x/tokenomics/types/event.pb.go +++ b/x/tokenomics/types/event.pb.go @@ -372,10 +372,12 @@ func (m *EventSupplierSlashed) GetSlashingAmount() *types1.Coin { // EventApplicationReimbursementRequest is emitted when an application requests // a reimbursement type EventApplicationReimbursementRequest struct { - ApplicationAddr string `protobuf:"bytes,1,opt,name=application_addr,json=applicationAddr,proto3" json:"application_addr,omitempty"` - ServiceId string `protobuf:"bytes,2,opt,name=service_id,json=serviceId,proto3" json:"service_id,omitempty"` - SessionId string `protobuf:"bytes,3,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"` - Amount *types1.Coin `protobuf:"bytes,4,opt,name=amount,proto3" json:"amount,omitempty"` + ApplicationAddr string `protobuf:"bytes,1,opt,name=application_addr,json=applicationAddr,proto3" json:"application_addr,omitempty"` + SupplierOperatorAddr string `protobuf:"bytes,2,opt,name=supplier_operator_addr,json=supplierOperatorAddr,proto3" json:"supplier_operator_addr,omitempty"` + SupplierOwnerAddr string `protobuf:"bytes,3,opt,name=supplier_owner_addr,json=supplierOwnerAddr,proto3" json:"supplier_owner_addr,omitempty"` + ServiceId string `protobuf:"bytes,4,opt,name=service_id,json=serviceId,proto3" json:"service_id,omitempty"` + SessionId string `protobuf:"bytes,5,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"` + Amount *types1.Coin `protobuf:"bytes,6,opt,name=amount,proto3" json:"amount,omitempty"` } func (m *EventApplicationReimbursementRequest) Reset() { *m = EventApplicationReimbursementRequest{} } @@ -414,6 +416,20 @@ func (m *EventApplicationReimbursementRequest) GetApplicationAddr() string { return "" } +func (m *EventApplicationReimbursementRequest) GetSupplierOperatorAddr() string { + if m != nil { + return m.SupplierOperatorAddr + } + return "" +} + +func (m *EventApplicationReimbursementRequest) GetSupplierOwnerAddr() string { + if m != nil { + return m.SupplierOwnerAddr + } + return "" +} + func (m *EventApplicationReimbursementRequest) GetServiceId() string { if m != nil { return m.ServiceId @@ -447,57 +463,59 @@ func init() { func init() { proto.RegisterFile("poktroll/tokenomics/event.proto", fileDescriptor_a78874bbf91a58c7) } var fileDescriptor_a78874bbf91a58c7 = []byte{ - // 799 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x55, 0x4d, 0x6f, 0x1b, 0x45, - 0x18, 0xce, 0xa6, 0x6e, 0x24, 0x0f, 0xb5, 0x6b, 0x2f, 0x49, 0xe5, 0x06, 0xb2, 0x1b, 0x2c, 0x84, - 0x42, 0x45, 0x77, 0x95, 0x16, 0x71, 0x44, 0xd8, 0xae, 0x8b, 0x56, 0x02, 0xdb, 0x1d, 0x13, 0x54, - 0x71, 0x60, 0x59, 0xef, 0xbe, 0x71, 0x87, 0x78, 0x67, 0xb6, 0x33, 0xb3, 0x26, 0x3d, 0xf2, 0x0f, - 0xf8, 0x45, 0x1c, 0x38, 0x71, 0xec, 0xb1, 0x27, 0x0b, 0x39, 0x37, 0x5f, 0x39, 0x70, 0x45, 0x33, - 0xbb, 0xfe, 0x88, 0x53, 0x1c, 0xa1, 0x5c, 0x7b, 0xb1, 0x77, 0xdf, 0xe7, 0x63, 0x3e, 0x9e, 0x77, - 0x76, 0x90, 0x9d, 0xb0, 0x33, 0xc9, 0xd9, 0x68, 0xe4, 0x4a, 0x76, 0x06, 0x94, 0xc5, 0x24, 0x14, - 0x2e, 0x8c, 0x81, 0x4a, 0x27, 0xe1, 0x4c, 0x32, 0xf3, 0xfd, 0x39, 0xc1, 0x59, 0x12, 0xf6, 0xad, - 0x90, 0x89, 0x98, 0x09, 0x77, 0x10, 0x08, 0x70, 0xc7, 0xc7, 0x03, 0x90, 0xc1, 0xb1, 0x1b, 0x32, - 0x42, 0x33, 0xd1, 0xfe, 0xee, 0x90, 0x0d, 0x99, 0x7e, 0x74, 0xd5, 0x53, 0x5e, 0xdd, 0x5f, 0x8c, - 0x95, 0x70, 0xc6, 0x4e, 0x5d, 0xf9, 0x2a, 0x01, 0x91, 0x61, 0xf5, 0x7f, 0x6e, 0xa1, 0x6a, 0x5b, - 0x0d, 0xdb, 0x1a, 0x05, 0x24, 0x6e, 0x9f, 0x27, 0x84, 0x43, 0x64, 0x7e, 0x81, 0x6e, 0x87, 0xea, - 0xbd, 0x66, 0x1c, 0x1a, 0x47, 0xef, 0x3d, 0xda, 0x73, 0x16, 0x93, 0xd1, 0x0e, 0x8e, 0x26, 0x37, - 0x8b, 0xb3, 0x89, 0x9d, 0xf1, 0x70, 0xf6, 0x67, 0x52, 0x54, 0x05, 0x65, 0x11, 0x48, 0xc2, 0xa8, - 0xcf, 0x21, 0x10, 0x8c, 0xd6, 0xb6, 0x0f, 0x8d, 0xa3, 0xf2, 0xa3, 0x07, 0xce, 0x5b, 0x16, 0xe4, - 0x2c, 0x47, 0xd5, 0x12, 0xac, 0x15, 0xcd, 0xbd, 0xd9, 0xc4, 0xbe, 0x6a, 0x84, 0x2b, 0xb0, 0x46, - 0x34, 0x1f, 0x22, 0x44, 0xd3, 0xd8, 0xe7, 0x30, 0x0a, 0x5e, 0x89, 0xda, 0xad, 0x43, 0xe3, 0xa8, - 0xd0, 0x2c, 0xcf, 0x26, 0xf6, 0x4a, 0x15, 0x17, 0x69, 0x1a, 0x63, 0xfd, 0x68, 0x3e, 0x47, 0xf7, - 0x15, 0xa0, 0xe7, 0x0a, 0x91, 0x1f, 0xb2, 0x38, 0x49, 0x25, 0xf8, 0x29, 0x25, 0x52, 0xd4, 0x0a, - 0x5a, 0x7d, 0x30, 0x9b, 0xd8, 0xff, 0x4d, 0xc2, 0xf7, 0x68, 0x1a, 0xb7, 0x32, 0xa4, 0x95, 0x01, - 0x27, 0xaa, 0x6e, 0xfe, 0x88, 0x3e, 0x50, 0x22, 0x10, 0x92, 0xc4, 0x81, 0xbc, 0xe2, 0x7d, 0x5b, - 0x7b, 0xdb, 0xb3, 0x89, 0xbd, 0x89, 0x86, 0x6b, 0x34, 0x8d, 0xdb, 0x73, 0xec, 0x92, 0xff, 0x33, - 0x54, 0x9a, 0x4f, 0x28, 0x55, 0xfb, 0x58, 0xdb, 0xd1, 0xc1, 0xdc, 0x77, 0xb2, 0x86, 0x70, 0x54, - 0x43, 0x38, 0x79, 0x43, 0x38, 0x2d, 0x46, 0x68, 0xb3, 0x3a, 0x9b, 0xd8, 0x97, 0x35, 0xf8, 0x4e, - 0xfe, 0x7a, 0xa2, 0xde, 0xea, 0x7f, 0x5f, 0x4a, 0xbe, 0x0f, 0x52, 0x8e, 0x6e, 0x90, 0xfc, 0xcf, - 0xa8, 0xaa, 0x09, 0x3e, 0x87, 0x97, 0x29, 0xe1, 0x10, 0x03, 0x95, 0x79, 0xf2, 0x9f, 0xac, 0x7b, - 0xf4, 0xd4, 0x2f, 0x5e, 0xf2, 0x56, 0x53, 0xbf, 0x62, 0x82, 0x2b, 0xc9, 0x1a, 0xfd, 0x5d, 0xea, - 0x37, 0x48, 0xfd, 0xd7, 0x6d, 0xf4, 0xa1, 0x4e, 0xbd, 0x91, 0x24, 0x23, 0x12, 0xea, 0xc3, 0xd4, - 0x1d, 0x03, 0x17, 0xc0, 0xc7, 0x24, 0x84, 0xc8, 0xfc, 0x14, 0x55, 0x82, 0x25, 0xe4, 0x07, 0x51, - 0xc4, 0x75, 0x2f, 0x14, 0xf1, 0xdd, 0x95, 0x7a, 0x23, 0x8a, 0xb8, 0xf9, 0x39, 0xba, 0x27, 0x52, - 0x55, 0x03, 0xee, 0xb3, 0x04, 0x78, 0x20, 0x19, 0xcf, 0x04, 0xdb, 0x5a, 0xb0, 0x3b, 0x47, 0xbb, - 0x39, 0xa8, 0x55, 0x5f, 0xa2, 0x12, 0x9c, 0x27, 0x10, 0xaa, 0x8d, 0x18, 0xa4, 0x9c, 0xea, 0x00, - 0x37, 0x2d, 0x0a, 0xdf, 0x99, 0xf3, 0x9b, 0x29, 0xa7, 0xe6, 0x57, 0xa8, 0x0c, 0xa7, 0xa7, 0x10, - 0x4a, 0x32, 0x86, 0xcc, 0xa0, 0x70, 0x9d, 0x41, 0x69, 0x21, 0x50, 0x0e, 0xf5, 0xdf, 0x0d, 0xb4, - 0xab, 0xf7, 0xa0, 0x9f, 0xcf, 0xaf, 0x3f, 0x0a, 0xc4, 0x0b, 0x88, 0x36, 0x2c, 0xc8, 0xd8, 0xb0, - 0xa0, 0xcf, 0x90, 0xa9, 0xe3, 0xcd, 0xbe, 0x9d, 0x59, 0x0b, 0x09, 0xbd, 0x05, 0x05, 0x5c, 0x51, - 0xd9, 0x66, 0x80, 0x6e, 0x20, 0x61, 0x36, 0xd1, 0x5d, 0xa1, 0x86, 0x23, 0x74, 0xe8, 0x07, 0x31, - 0x4b, 0xa9, 0xbc, 0x7e, 0x03, 0xca, 0x73, 0x45, 0x43, 0x0b, 0xea, 0x7f, 0x18, 0xe8, 0xe3, 0xf5, - 0x10, 0x31, 0x90, 0x78, 0x90, 0x72, 0x91, 0x9f, 0xa8, 0x97, 0x29, 0x08, 0xf9, 0x7f, 0xc2, 0x3c, - 0x40, 0x28, 0xef, 0x01, 0x9f, 0x44, 0x79, 0x80, 0xc5, 0xbc, 0xe2, 0x45, 0x19, 0x2c, 0x84, 0x72, - 0x21, 0x91, 0x9e, 0xb1, 0x86, 0x75, 0xc5, 0x8b, 0xcc, 0x63, 0xb4, 0x93, 0x2f, 0xe6, 0xda, 0x30, - 0x72, 0xe2, 0x83, 0x9f, 0xd0, 0xde, 0x5b, 0xbf, 0xfe, 0xe6, 0x47, 0xe8, 0xa0, 0xfd, 0xbc, 0xe7, - 0xe1, 0xc6, 0x77, 0x5e, 0xb7, 0xe3, 0xe3, 0x76, 0xa3, 0xdf, 0xed, 0xf8, 0x27, 0x9d, 0x7e, 0xaf, - 0xdd, 0xf2, 0x9e, 0x7a, 0xed, 0x27, 0x95, 0x2d, 0xb3, 0x8a, 0x4a, 0x3d, 0xdc, 0xed, 0x3e, 0xf5, - 0xbf, 0xf5, 0xfa, 0x7d, 0xaf, 0xf3, 0x75, 0xc5, 0x58, 0x96, 0xbc, 0xce, 0xf7, 0x8d, 0x6f, 0xbc, - 0x27, 0x95, 0xed, 0xe6, 0xb3, 0x3f, 0xa7, 0x96, 0xf1, 0x7a, 0x6a, 0x19, 0x6f, 0xa6, 0x96, 0xf1, - 0xd7, 0xd4, 0x32, 0x7e, 0xbb, 0xb0, 0xb6, 0x5e, 0x5f, 0x58, 0x5b, 0x6f, 0x2e, 0xac, 0xad, 0x1f, - 0x1e, 0x0f, 0x89, 0x7c, 0x91, 0x0e, 0x9c, 0x90, 0xc5, 0xae, 0x3a, 0x1a, 0x0f, 0x29, 0xc8, 0x5f, - 0x18, 0x3f, 0x73, 0x17, 0xb7, 0xe5, 0xf9, 0xea, 0xdd, 0xac, 0x2f, 0xcd, 0xc1, 0x8e, 0xbe, 0x35, - 0x1f, 0xff, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x5f, 0xc3, 0xae, 0x29, 0xbf, 0x07, 0x00, 0x00, + // 823 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x56, 0xcf, 0x6f, 0xdb, 0x36, + 0x14, 0x8e, 0x9c, 0x34, 0x80, 0xb9, 0xc6, 0xb5, 0xd5, 0xa4, 0x70, 0xb3, 0x45, 0xca, 0x8c, 0x61, + 0xc8, 0x8a, 0x55, 0x42, 0xda, 0x61, 0xc7, 0x61, 0xb6, 0xeb, 0x0e, 0x02, 0x36, 0xdb, 0xa5, 0x97, + 0xa1, 0xd8, 0x61, 0x9a, 0x2c, 0xbd, 0xb8, 0x5c, 0x2c, 0x52, 0x25, 0x29, 0x37, 0x3d, 0xee, 0x3f, + 0xd8, 0x9f, 0xb1, 0xbf, 0x62, 0xe7, 0x1d, 0x7b, 0xec, 0xc9, 0x18, 0x9c, 0x9b, 0xaf, 0x3b, 0xec, + 0x3a, 0x90, 0x92, 0x7f, 0xc4, 0xe9, 0x9c, 0x43, 0xb0, 0x5b, 0x2f, 0x36, 0xf9, 0xbe, 0xef, 0x7b, + 0x24, 0xdf, 0xf7, 0x68, 0x1a, 0xd9, 0x09, 0x3b, 0x93, 0x9c, 0x0d, 0x87, 0xae, 0x64, 0x67, 0x40, + 0x59, 0x4c, 0x42, 0xe1, 0xc2, 0x08, 0xa8, 0x74, 0x12, 0xce, 0x24, 0x33, 0xef, 0xce, 0x08, 0xce, + 0x82, 0xb0, 0x6f, 0x85, 0x4c, 0xc4, 0x4c, 0xb8, 0xfd, 0x40, 0x80, 0x3b, 0x3a, 0xee, 0x83, 0x0c, + 0x8e, 0xdd, 0x90, 0x11, 0x9a, 0x89, 0xf6, 0x77, 0x07, 0x6c, 0xc0, 0xf4, 0xd0, 0x55, 0xa3, 0x3c, + 0xba, 0x3f, 0x5f, 0x2b, 0xe1, 0x8c, 0x9d, 0xba, 0xf2, 0x75, 0x02, 0x22, 0xc3, 0x6a, 0xff, 0x6c, + 0xa2, 0x4a, 0x4b, 0x2d, 0xdb, 0x1c, 0x06, 0x24, 0x6e, 0x9d, 0x27, 0x84, 0x43, 0x64, 0x7e, 0x89, + 0x6e, 0x85, 0x6a, 0x5e, 0x35, 0x0e, 0x8d, 0xa3, 0x0f, 0x1e, 0xed, 0x39, 0xf3, 0xcd, 0xe8, 0x0c, + 0x8e, 0x26, 0x37, 0x8a, 0xd3, 0xb1, 0x9d, 0xf1, 0x70, 0xf6, 0x65, 0x52, 0x54, 0x01, 0x95, 0x22, + 0x90, 0x84, 0x51, 0x9f, 0x43, 0x20, 0x18, 0xad, 0x16, 0x0e, 0x8d, 0xa3, 0xd2, 0xa3, 0x07, 0xce, + 0x3b, 0x0e, 0xe4, 0x2c, 0x56, 0xd5, 0x12, 0xac, 0x15, 0x8d, 0xbd, 0xe9, 0xd8, 0xbe, 0x9a, 0x08, + 0x97, 0x61, 0x85, 0x68, 0x3e, 0x44, 0x88, 0xa6, 0xb1, 0xcf, 0x61, 0x18, 0xbc, 0x16, 0xd5, 0xcd, + 0x43, 0xe3, 0x68, 0xab, 0x51, 0x9a, 0x8e, 0xed, 0xa5, 0x28, 0x2e, 0xd2, 0x34, 0xc6, 0x7a, 0x68, + 0x3e, 0x47, 0xf7, 0x15, 0xa0, 0xf7, 0x0a, 0x91, 0x1f, 0xb2, 0x38, 0x49, 0x25, 0xf8, 0x29, 0x25, + 0x52, 0x54, 0xb7, 0xb4, 0xfa, 0x60, 0x3a, 0xb6, 0xff, 0x9b, 0x84, 0xef, 0xd1, 0x34, 0x6e, 0x66, + 0x48, 0x33, 0x03, 0x4e, 0x54, 0xdc, 0xfc, 0x09, 0x7d, 0xa8, 0x44, 0x20, 0x24, 0x89, 0x03, 0x79, + 0x25, 0xf7, 0x2d, 0x9d, 0xdb, 0x9e, 0x8e, 0xed, 0x75, 0x34, 0x5c, 0xa5, 0x69, 0xdc, 0x9a, 0x61, + 0x97, 0xf2, 0x3f, 0x43, 0x3b, 0xb3, 0x0d, 0xa5, 0xaa, 0x8e, 0xd5, 0x6d, 0x6d, 0xcc, 0x7d, 0x27, + 0x6b, 0x08, 0x47, 0x35, 0x84, 0x93, 0x37, 0x84, 0xd3, 0x64, 0x84, 0x36, 0x2a, 0xd3, 0xb1, 0x7d, + 0x59, 0x83, 0x6f, 0xe7, 0xd3, 0x13, 0x35, 0xab, 0xfd, 0x7d, 0xc9, 0xf9, 0x1e, 0x48, 0x39, 0xbc, + 0x81, 0xf3, 0xbf, 0xa0, 0x8a, 0x26, 0xf8, 0x1c, 0x5e, 0xa6, 0x84, 0x43, 0x0c, 0x54, 0xe6, 0xce, + 0x7f, 0xba, 0x9a, 0xa3, 0xab, 0x3e, 0xf1, 0x82, 0xb7, 0xec, 0xfa, 0x95, 0x24, 0xb8, 0x9c, 0xac, + 0xd0, 0xdf, 0xbb, 0x7e, 0x03, 0xd7, 0x7f, 0x2d, 0xa0, 0x8f, 0xb4, 0xeb, 0xf5, 0x24, 0x19, 0x92, + 0x50, 0x5f, 0xa6, 0xce, 0x08, 0xb8, 0x00, 0x3e, 0x22, 0x21, 0x44, 0xe6, 0x67, 0xa8, 0x1c, 0x2c, + 0x20, 0x3f, 0x88, 0x22, 0xae, 0x7b, 0xa1, 0x88, 0xef, 0x2c, 0xc5, 0xeb, 0x51, 0xc4, 0xcd, 0x2f, + 0xd0, 0x3d, 0x91, 0xaa, 0x18, 0x70, 0x9f, 0x25, 0xc0, 0x03, 0xc9, 0x78, 0x26, 0x28, 0x68, 0xc1, + 0xee, 0x0c, 0xed, 0xe4, 0xa0, 0x56, 0x7d, 0x85, 0x76, 0xe0, 0x3c, 0x81, 0x50, 0x15, 0xa2, 0x9f, + 0x72, 0xaa, 0x0d, 0x5c, 0x77, 0x28, 0x7c, 0x7b, 0xc6, 0x6f, 0xa4, 0x9c, 0x9a, 0x5f, 0xa3, 0x12, + 0x9c, 0x9e, 0x42, 0x28, 0xc9, 0x08, 0xb2, 0x04, 0x5b, 0xd7, 0x25, 0xd8, 0x99, 0x0b, 0x54, 0x86, + 0xda, 0x1f, 0x06, 0xda, 0xd5, 0x35, 0xe8, 0xe5, 0xfb, 0xeb, 0x0d, 0x03, 0xf1, 0x02, 0xa2, 0x35, + 0x07, 0x32, 0xd6, 0x1c, 0xe8, 0x73, 0x64, 0x6a, 0x7b, 0xb3, 0xdf, 0xce, 0xac, 0x85, 0x84, 0x2e, + 0xc1, 0x16, 0x2e, 0x2b, 0x6f, 0x33, 0x40, 0x37, 0x90, 0x30, 0x1b, 0xe8, 0x8e, 0x50, 0xcb, 0x11, + 0x3a, 0xf0, 0x83, 0x98, 0xa5, 0x54, 0x5e, 0x5f, 0x80, 0xd2, 0x4c, 0x51, 0xd7, 0x82, 0xda, 0xef, + 0x05, 0xf4, 0xc9, 0xaa, 0x89, 0x18, 0x48, 0xdc, 0x4f, 0xb9, 0xc8, 0x6f, 0xd4, 0xcb, 0x14, 0x84, + 0xfc, 0xff, 0xcd, 0x74, 0xd0, 0xdd, 0x85, 0xea, 0x15, 0x85, 0x5c, 0xb2, 0xa9, 0x25, 0x95, 0xb9, + 0x44, 0x21, 0x9a, 0x7f, 0x80, 0x50, 0xde, 0x69, 0x3e, 0x89, 0xb4, 0x71, 0x45, 0x5c, 0xcc, 0x23, + 0x5e, 0x94, 0xc1, 0x42, 0xa8, 0xbd, 0x92, 0x48, 0xdf, 0x1f, 0x0d, 0xeb, 0x88, 0x17, 0x99, 0xc7, + 0x68, 0x3b, 0x2f, 0xd9, 0x75, 0x17, 0x01, 0xe7, 0xc4, 0x07, 0x3f, 0xa3, 0xbd, 0x77, 0xbe, 0x31, + 0xe6, 0xc7, 0xe8, 0xa0, 0xf5, 0xbc, 0xeb, 0xe1, 0xfa, 0xf7, 0x5e, 0xa7, 0xed, 0xe3, 0x56, 0xbd, + 0xd7, 0x69, 0xfb, 0x27, 0xed, 0x5e, 0xb7, 0xd5, 0xf4, 0x9e, 0x7a, 0xad, 0x27, 0xe5, 0x0d, 0xb3, + 0x82, 0x76, 0xba, 0xb8, 0xd3, 0x79, 0xea, 0x7f, 0xe7, 0xf5, 0x7a, 0x5e, 0xfb, 0x9b, 0xb2, 0xb1, + 0x08, 0x79, 0xed, 0x1f, 0xea, 0xdf, 0x7a, 0x4f, 0xca, 0x85, 0xc6, 0xb3, 0x3f, 0x27, 0x96, 0xf1, + 0x66, 0x62, 0x19, 0x6f, 0x27, 0x96, 0xf1, 0xd7, 0xc4, 0x32, 0x7e, 0xbb, 0xb0, 0x36, 0xde, 0x5c, + 0x58, 0x1b, 0x6f, 0x2f, 0xac, 0x8d, 0x1f, 0x1f, 0x0f, 0x88, 0x7c, 0x91, 0xf6, 0x9d, 0x90, 0xc5, + 0xae, 0xba, 0x80, 0x0f, 0x29, 0xc8, 0x57, 0x8c, 0x9f, 0xb9, 0xf3, 0x37, 0xf9, 0x7c, 0xf9, 0x1f, + 0x80, 0x7e, 0x9a, 0xfb, 0xdb, 0xfa, 0x6d, 0x7e, 0xfc, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x8b, + 0xd5, 0xac, 0x44, 0x25, 0x08, 0x00, 0x00, } func (m *EventClaimExpired) Marshal() (dAtA []byte, err error) { @@ -772,20 +790,34 @@ func (m *EventApplicationReimbursementRequest) MarshalToSizedBuffer(dAtA []byte) i = encodeVarintEvent(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x22 + dAtA[i] = 0x32 } if len(m.SessionId) > 0 { i -= len(m.SessionId) copy(dAtA[i:], m.SessionId) i = encodeVarintEvent(dAtA, i, uint64(len(m.SessionId))) i-- - dAtA[i] = 0x1a + dAtA[i] = 0x2a } if len(m.ServiceId) > 0 { i -= len(m.ServiceId) copy(dAtA[i:], m.ServiceId) i = encodeVarintEvent(dAtA, i, uint64(len(m.ServiceId))) i-- + dAtA[i] = 0x22 + } + if len(m.SupplierOwnerAddr) > 0 { + i -= len(m.SupplierOwnerAddr) + copy(dAtA[i:], m.SupplierOwnerAddr) + i = encodeVarintEvent(dAtA, i, uint64(len(m.SupplierOwnerAddr))) + i-- + dAtA[i] = 0x1a + } + if len(m.SupplierOperatorAddr) > 0 { + i -= len(m.SupplierOperatorAddr) + copy(dAtA[i:], m.SupplierOperatorAddr) + i = encodeVarintEvent(dAtA, i, uint64(len(m.SupplierOperatorAddr))) + i-- dAtA[i] = 0x12 } if len(m.ApplicationAddr) > 0 { @@ -922,6 +954,14 @@ func (m *EventApplicationReimbursementRequest) Size() (n int) { if l > 0 { n += 1 + l + sovEvent(uint64(l)) } + l = len(m.SupplierOperatorAddr) + if l > 0 { + n += 1 + l + sovEvent(uint64(l)) + } + l = len(m.SupplierOwnerAddr) + if l > 0 { + n += 1 + l + sovEvent(uint64(l)) + } l = len(m.ServiceId) if l > 0 { n += 1 + l + sovEvent(uint64(l)) @@ -1724,6 +1764,70 @@ func (m *EventApplicationReimbursementRequest) Unmarshal(dAtA []byte) error { m.ApplicationAddr = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SupplierOperatorAddr", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvent + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvent + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvent + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SupplierOperatorAddr = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SupplierOwnerAddr", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvent + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvent + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvent + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SupplierOwnerAddr = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field ServiceId", wireType) } @@ -1755,7 +1859,7 @@ func (m *EventApplicationReimbursementRequest) Unmarshal(dAtA []byte) error { } m.ServiceId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 3: + case 5: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field SessionId", wireType) } @@ -1787,7 +1891,7 @@ func (m *EventApplicationReimbursementRequest) Unmarshal(dAtA []byte) error { } m.SessionId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 4: + case 6: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) } From fafd2f3be3eef85fa42a87a39afbd0ca69885c4b Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Fri, 25 Oct 2024 00:03:21 +0200 Subject: [PATCH 24/53] chore: Address reveiw change requests --- testutil/keeper/tokenomics.go | 4 ++-- x/tokenomics/keeper/token_logic_modules.go | 13 +++++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/testutil/keeper/tokenomics.go b/testutil/keeper/tokenomics.go index 79d3cb828..4fee376fd 100644 --- a/testutil/keeper/tokenomics.go +++ b/testutil/keeper/tokenomics.go @@ -515,11 +515,11 @@ func WithProposerAddr(addr string) TokenomicsModuleKeepersOpt { } // WithProofRequirement is an option to set the proof requirement in the tokenomics module keepers. -func WithProofRequirement(required bool) TokenomicsModuleKeepersOpt { +func WithProofRequirement(proofRequired bool) TokenomicsModuleKeepersOpt { return func(ctx context.Context, keepers *TokenomicsModuleKeepers) context.Context { proofParams := keepers.ProofKeeper.GetParams(ctx) - if required { + if proofRequired { proofParams.ProofRequestProbability = 1 proofRequirementThreshold := cosmostypes.NewInt64Coin(volatile.DenomuPOKT, 0) proofParams.ProofRequirementThreshold = &proofRequirementThreshold diff --git a/x/tokenomics/keeper/token_logic_modules.go b/x/tokenomics/keeper/token_logic_modules.go index 1d9ae4446..d998cdba5 100644 --- a/x/tokenomics/keeper/token_logic_modules.go +++ b/x/tokenomics/keeper/token_logic_modules.go @@ -125,8 +125,11 @@ func init() { panic("mint allocation percentages do not add to 1.0") } - // TODO_UPNEXT(@Olshansk): Ensure that if `TLMGlobalMint` is present in the map, - // then TLMGlobalMintReimbursementRequest will need to be there too. + _, hasGlobalMintTLM := tokenLogicModuleProcessorMap[TLMGlobalMint] + _, hasGlobalMintReimbursementRequestTLM := tokenLogicModuleProcessorMap[TLMGlobalMintReimbursementRequest] + if hasGlobalMintTLM != hasGlobalMintReimbursementRequestTLM { + panic("TLMGlobalMint and TLMGlobalMintReimbursementRequest must be activated together") + } } // ProcessTokenLogicModules is the entrypoint for all TLM processing. @@ -518,12 +521,12 @@ func (k Keeper) TokenLogicModuleGlobalMintReimbursementRequest( ); err != nil { return tokenomicstypes.ErrTokenomicsApplicationReimbursementRequestFailed.Wrapf( "sending %s from the application module account to the tokenomics module account: %v", - actualSettlementCoin, err, + newMintCoin, err, ) } logger.Info(fmt.Sprintf( "sent (%s) from the application module account to the tokenomics module account", - actualSettlementCoin, + newMintCoin, )) // Send the global per claim mint inflation uPOKT from the tokenomics module @@ -638,6 +641,8 @@ func (k Keeper) sendRewardsToAccount( // If this is not the case, then the supplier essentially did "free work" and the // actual claim amount is less than what was claimed. // Ref: https://arxiv.org/pdf/2305.10672 +// TODO_TEST: Add more tests for edge cases that exercise all the code paths +// actualSettlementCoins could be updated in this function. func (k Keeper) ensureClaimAmountLimits( ctx context.Context, logger log.Logger, From 3185741f43a691170ece3fad018ab7600ad9c0f2 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Fri, 25 Oct 2024 13:19:30 +0200 Subject: [PATCH 25/53] fix: Add globalmint to tests --- .../integration/application/min_stake_test.go | 20 +++++++++++++++++-- x/tokenomics/keeper/settle_pending_claims.go | 1 + 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/tests/integration/application/min_stake_test.go b/tests/integration/application/min_stake_test.go index fd6eae501..43c801a33 100644 --- a/tests/integration/application/min_stake_test.go +++ b/tests/integration/application/min_stake_test.go @@ -2,6 +2,7 @@ package application import ( "context" + "math/big" "testing" cosmoslog "cosmossdk.io/log" @@ -25,6 +26,7 @@ import ( sessiontypes "github.com/pokt-network/poktroll/x/session/types" sharedtypes "github.com/pokt-network/poktroll/x/shared/types" suppliertypes "github.com/pokt-network/poktroll/x/supplier/types" + tokenomicskeeper "github.com/pokt-network/poktroll/x/tokenomics/keeper" ) type applicationMinStakeTestSuite struct { @@ -235,7 +237,8 @@ func (s *applicationMinStakeTestSuite) getExpectedApp(claim *prooftypes.Claim) * expectedBurnCoin, err := claim.GetClaimeduPOKT(sharedParams, relayMiningDifficulty) require.NoError(s.T(), err) - expectedEndStake := s.appStake.Sub(expectedBurnCoin) + globalInflationAmt := calculateGlobalInflation(expectedBurnCoin.Amount) + expectedEndStake := s.appStake.Sub(expectedBurnCoin).SubAmount(globalInflationAmt) return &apptypes.Application{ Address: s.appBech32, Stake: &expectedEndStake, @@ -305,7 +308,20 @@ func (s *applicationMinStakeTestSuite) assertAppStakeIsReturnedToBalance() { s.T().Helper() expectedAppBurn := math.NewInt(int64(s.numRelays * s.numComputeUnitsPerRelay * sharedtypes.DefaultComputeUnitsToTokensMultiplier)) - expectedAppBalance := s.appStake.SubAmount(expectedAppBurn) + globalInflationAmt := calculateGlobalInflation(expectedAppBurn) + expectedAppBalance := s.appStake.SubAmount(expectedAppBurn).SubAmount(globalInflationAmt) + appBalance := s.getAppBalance() require.Equal(s.T(), expectedAppBalance.Amount.Int64(), appBalance.Amount.Int64()) } + +// calculateGlobalInflation calculates the global inflation for the given settlement amount. +func calculateGlobalInflation(settlementAmt math.Int) math.Int { + globalInflationFloat := new(big.Float).Mul( + new(big.Float).SetInt(settlementAmt.BigInt()), + big.NewFloat(tokenomicskeeper.MintPerClaimedTokenGlobalInflation), + ) + globalInflationInt, _ := globalInflationFloat.Int(nil) + + return math.NewIntFromBigInt(globalInflationInt) +} diff --git a/x/tokenomics/keeper/settle_pending_claims.go b/x/tokenomics/keeper/settle_pending_claims.go index c70773ff5..b6c284b30 100644 --- a/x/tokenomics/keeper/settle_pending_claims.go +++ b/x/tokenomics/keeper/settle_pending_claims.go @@ -8,6 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/types/query" "github.com/pokt-network/poktroll/app/volatile" + apptypes "github.com/pokt-network/poktroll/x/application/types" prooftypes "github.com/pokt-network/poktroll/x/proof/types" servicekeeper "github.com/pokt-network/poktroll/x/service/keeper" sharedtypes "github.com/pokt-network/poktroll/x/shared/types" From 1593bfbd3a5a50a40f14053361d8e8ea964bf5e0 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Fri, 25 Oct 2024 13:32:25 +0200 Subject: [PATCH 26/53] fix: Linting errors --- x/tokenomics/keeper/settle_pending_claims.go | 2 +- x/tokenomics/keeper/token_logic_modules.go | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/x/tokenomics/keeper/settle_pending_claims.go b/x/tokenomics/keeper/settle_pending_claims.go index b6c284b30..09a9fc26b 100644 --- a/x/tokenomics/keeper/settle_pending_claims.go +++ b/x/tokenomics/keeper/settle_pending_claims.go @@ -42,7 +42,7 @@ func (k Keeper) SettlePendingClaims(ctx sdk.Context) ( for _, claim := range expiringClaims { app, isAppFound := k.applicationKeeper.GetApplication(ctx, claim.SessionHeader.ApplicationAddress) if !isAppFound { - err := apptypes.ErrAppNotFound.Wrapf("application address: %q", claim.SessionHeader.ApplicationAddress) + err = apptypes.ErrAppNotFound.Wrapf("application address: %q", claim.SessionHeader.ApplicationAddress) return settledResult, expiredResult, err } diff --git a/x/tokenomics/keeper/token_logic_modules.go b/x/tokenomics/keeper/token_logic_modules.go index 0936064bf..657a2b5a7 100644 --- a/x/tokenomics/keeper/token_logic_modules.go +++ b/x/tokenomics/keeper/token_logic_modules.go @@ -712,7 +712,6 @@ func (k Keeper) ensureClaimAmountLimits( stakeRequirementAmt = maxClaimableAmt maxClaimSettlementAmt = stakeToMaxSettlementAmount(stakeRequirementAmt) - globalInflationAmt = stakeRequirementAmt.Sub(maxClaimSettlementAmt) } // Check if the claimable amount should be capped by an insufficient application stake. @@ -721,7 +720,6 @@ func (k Keeper) ensureClaimAmountLimits( supplier.GetOperatorAddress(), application.GetAddress(), claimSettlementCoin, maxClaimableAmt)) stakeRequirementAmt = maxClaimableAmt maxClaimSettlementAmt = stakeToMaxSettlementAmount(stakeRequirementAmt) - globalInflationAmt = stakeRequirementAmt.Sub(maxClaimSettlementAmt) } // Nominal case: The claimable amount is within the limits set by Relay Mining. From b2a14b2e81e33813dcf60bd816dc531df139eee9 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Fri, 25 Oct 2024 15:17:43 +0200 Subject: [PATCH 27/53] fix: Check cached stake before query --- x/tokenomics/keeper/settle_pending_claims.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/x/tokenomics/keeper/settle_pending_claims.go b/x/tokenomics/keeper/settle_pending_claims.go index 09a9fc26b..ca8d5d533 100644 --- a/x/tokenomics/keeper/settle_pending_claims.go +++ b/x/tokenomics/keeper/settle_pending_claims.go @@ -40,13 +40,18 @@ func (k Keeper) SettlePendingClaims(ctx sdk.Context) ( // max share any claim could receive from the application stake. applicationInitialStakeMap := make(map[string]sdk.Coin) for _, claim := range expiringClaims { - app, isAppFound := k.applicationKeeper.GetApplication(ctx, claim.SessionHeader.ApplicationAddress) + appAddress := claim.SessionHeader.ApplicationAddress + if _, isAppFound := applicationInitialStakeMap[appAddress]; isAppFound { + continue + } + + app, isAppFound := k.applicationKeeper.GetApplication(ctx, appAddress) if !isAppFound { - err = apptypes.ErrAppNotFound.Wrapf("application address: %q", claim.SessionHeader.ApplicationAddress) + err = apptypes.ErrAppNotFound.Wrapf("application address: %q", appAddress) return settledResult, expiredResult, err } - applicationInitialStakeMap[claim.SessionHeader.ApplicationAddress] = *app.GetStake() + applicationInitialStakeMap[appAddress] = *app.GetStake() } blockHeight := ctx.BlockHeight() From 5e6e514b3ef020b62780dbacaa2f30a651427d79 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Fri, 25 Oct 2024 15:35:05 +0200 Subject: [PATCH 28/53] fix: Remove redundant check --- x/tokenomics/keeper/settle_pending_claims.go | 2 ++ x/tokenomics/keeper/token_logic_modules.go | 8 -------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/x/tokenomics/keeper/settle_pending_claims.go b/x/tokenomics/keeper/settle_pending_claims.go index ca8d5d533..91b1afdba 100644 --- a/x/tokenomics/keeper/settle_pending_claims.go +++ b/x/tokenomics/keeper/settle_pending_claims.go @@ -38,6 +38,8 @@ func (k Keeper) SettlePendingClaims(ctx sdk.Context) ( // Capture the applications initial stake which will be used to calculate the // max share any claim could receive from the application stake. + // This ensures that each claim can calculate the maximum amount it can take + // from an application's stake. applicationInitialStakeMap := make(map[string]sdk.Coin) for _, claim := range expiringClaims { appAddress := claim.SessionHeader.ApplicationAddress diff --git a/x/tokenomics/keeper/token_logic_modules.go b/x/tokenomics/keeper/token_logic_modules.go index 657a2b5a7..0dac283f6 100644 --- a/x/tokenomics/keeper/token_logic_modules.go +++ b/x/tokenomics/keeper/token_logic_modules.go @@ -714,14 +714,6 @@ func (k Keeper) ensureClaimAmountLimits( maxClaimSettlementAmt = stakeToMaxSettlementAmount(stakeRequirementAmt) } - // Check if the claimable amount should be capped by an insufficient application stake. - if maxClaimableAmt.LT(stakeRequirementAmt) { - logger.Warn(fmt.Sprintf("Claim by supplier %q EXCEEDS application %q claimable stake. Claim amount > App claimable stake: %v > %v", - supplier.GetOperatorAddress(), application.GetAddress(), claimSettlementCoin, maxClaimableAmt)) - stakeRequirementAmt = maxClaimableAmt - maxClaimSettlementAmt = stakeToMaxSettlementAmount(stakeRequirementAmt) - } - // Nominal case: The claimable amount is within the limits set by Relay Mining. if claimSettlementCoin.Amount.LTE(maxClaimSettlementAmt) { logger.Info(fmt.Sprintf("Claim by supplier %s IS WITHIN LIMITS of servicing application %s. Max claimable amount >= Claim amount: %v >= %v", From 2b14babf87d12a92ac7b44692b11d17f6137ad5a Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Mon, 28 Oct 2024 17:31:14 +0100 Subject: [PATCH 29/53] feat: Supplier rate limiting --- pkg/relayer/interface.go | 14 + pkg/relayer/miner/miner.go | 6 +- pkg/relayer/miner/miner_test.go | 24 +- pkg/relayer/proxy/errors.go | 2 + pkg/relayer/proxy/proxy.go | 34 +- pkg/relayer/proxy/relay_meter.go | 301 ++++++++++++++++++ pkg/relayer/proxy/server_builder.go | 1 + pkg/relayer/proxy/synchronous.go | 14 + x/tokenomics/keeper/token_logic_modules.go | 31 +- .../keeper/token_logic_modules_test.go | 18 +- 10 files changed, 410 insertions(+), 35 deletions(-) create mode 100644 pkg/relayer/proxy/relay_meter.go diff --git a/pkg/relayer/interface.go b/pkg/relayer/interface.go index 1f231e7f1..b40432275 100644 --- a/pkg/relayer/interface.go +++ b/pkg/relayer/interface.go @@ -162,3 +162,17 @@ type SessionTree interface { // GetTrieSpec returns the trie spec of the SMST. GetTrieSpec() smt.TrieSpec } + +// RelayMeter is an interface that keeps track of the consumed stake for each application. +type RelayMeter interface { + // Start starts the relay meter. + Start(ctx context.Context) error + // ClaimRelayPrice claims the relay price for the given relay request. + // The relay price is claimed optimistically, assuming that the relay will be volume / reward + // applicable and the relay meter will be updated accordingly. + ClaimRelayPrice(ctx context.Context, relayRequestMeta servicetypes.RelayRequestMetadata) error + // UnclaimRelayPrice unlocks the relay price for the given relay request. + // This is used when the relay is not volume / reward applicable but was optimistically + // accounted for in the relay meter. + UnclaimRelayPrice(ctx context.Context, relayRequestMeta servicetypes.RelayRequestMetadata) error +} diff --git a/pkg/relayer/miner/miner.go b/pkg/relayer/miner/miner.go index b6ed55e0e..39ab423ef 100644 --- a/pkg/relayer/miner/miner.go +++ b/pkg/relayer/miner/miner.go @@ -27,6 +27,7 @@ type miner struct { // serviceQueryClient is used to query for the relay difficulty target hash of a service. // relay_difficulty is the target hash which a relay hash must be less than to be volume/reward applicable. serviceQueryClient client.ServiceQueryClient + relayMeter relayer.RelayMeter } // NewMiner creates a new miner from the given dependencies and options. It @@ -43,7 +44,7 @@ func NewMiner( ) (*miner, error) { mnr := &miner{} - if err := depinject.Inject(deps, &mnr.serviceQueryClient); err != nil { + if err := depinject.Inject(deps, &mnr.serviceQueryClient, &mnr.relayMeter); err != nil { return nil, err } @@ -88,6 +89,7 @@ func (mnr *miner) mapMineRelay( ) (_ either.Either[*relayer.MinedRelay], skip bool) { relayBz, err := relay.Marshal() if err != nil { + mnr.relayMeter.UnclaimRelayPrice(ctx, relay.GetReq().GetMeta()) return either.Error[*relayer.MinedRelay](err), false } relayHashArr := protocol.GetRelayHashFromBytes(relayBz) @@ -95,11 +97,13 @@ func (mnr *miner) mapMineRelay( relayDifficultyTargetHash, err := mnr.getServiceRelayDifficultyTargetHash(ctx, relay.Req) if err != nil { + mnr.relayMeter.UnclaimRelayPrice(ctx, relay.GetReq().GetMeta()) return either.Error[*relayer.MinedRelay](err), false } // The relay IS NOT volume / reward applicable if !protocol.IsRelayVolumeApplicable(relayHash, relayDifficultyTargetHash) { + mnr.relayMeter.UnclaimRelayPrice(ctx, relay.GetReq().GetMeta()) return either.Success[*relayer.MinedRelay](nil), true } diff --git a/pkg/relayer/miner/miner_test.go b/pkg/relayer/miner/miner_test.go index 7afbf69d2..caf1375cc 100644 --- a/pkg/relayer/miner/miner_test.go +++ b/pkg/relayer/miner/miner_test.go @@ -28,7 +28,10 @@ import ( // The fixtures generated by pkg/relayer/miner/gen/gen_fixtures.go use a const with the same name and value. const testSvcId = "svc1" -var testRelayMiningTargetHash, _ = hex.DecodeString("0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff") +var ( + testRelayMiningTargetHash, _ = hex.DecodeString("0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff") + _ relayer.RelayMeter = (*testRelayMeter)(nil) +) // TestMiner_MinedRelays constructs an observable of mined relays, through which // it pipes pre-mined relay fixtures. It asserts that the observable only emits @@ -48,8 +51,9 @@ func TestMiner_MinedRelays(t *testing.T) { testqueryclients.SetServiceRelayDifficultyTargetHash(t, testSvcId, testRelayMiningTargetHash) serviceQueryClientMock := testqueryclients.NewTestServiceQueryClient(t) + var testRelayMeter relayer.RelayMeter = &testRelayMeter{} - deps := depinject.Supply(serviceQueryClientMock) + deps := depinject.Supply(serviceQueryClientMock, testRelayMeter) mnr, err := miner.NewMiner(deps) require.NoError(t, err) @@ -154,3 +158,19 @@ func unmarshalHexMinedRelay( Hash: relayHash, } } + +// testRelayMeter is a dummy implementation of the RelayMeter interface. +// It is used to supply the miner with a relay meter but without any side effects. +type testRelayMeter struct{} + +func (trm *testRelayMeter) Start(_ context.Context) error { + return nil +} + +func (trm *testRelayMeter) UnclaimRelayPrice(ctx context.Context, meta servicetypes.RelayRequestMetadata) error { + return nil +} + +func (trm *testRelayMeter) ClaimRelayPrice(ctx context.Context, meta servicetypes.RelayRequestMetadata) error { + return nil +} diff --git a/pkg/relayer/proxy/errors.go b/pkg/relayer/proxy/errors.go index be2dbd95c..429ba9483 100644 --- a/pkg/relayer/proxy/errors.go +++ b/pkg/relayer/proxy/errors.go @@ -17,4 +17,6 @@ var ( ErrRelayerProxyUnsupportedTransportType = sdkerrors.Register(codespace, 9, "unsupported proxy transport type") ErrRelayerProxyInternalError = sdkerrors.Register(codespace, 10, "internal error") ErrRelayerProxyMissingSupplierOperatorAddress = sdkerrors.Register(codespace, 11, "supplier operator address is missing") + ErrRelayerProxyUnknownApplication = sdkerrors.Register(codespace, 12, "unknown application") + ErrRelayerProxyRateLimited = sdkerrors.Register(codespace, 13, "rate limited") ) diff --git a/pkg/relayer/proxy/proxy.go b/pkg/relayer/proxy/proxy.go index 0db1016f9..8bd2d39b5 100644 --- a/pkg/relayer/proxy/proxy.go +++ b/pkg/relayer/proxy/proxy.go @@ -78,6 +78,10 @@ type relayerProxy struct { // 1. Relay verification to check if the incoming relay matches the supplier hosted by the relay miner; // 2. Relay signing to resolve which keyring key name to use for signing; OperatorAddressToSigningKeyNameMap map[string]string + + // relayMeter is a struct that keeps track of the claimed relay prices for each application. + // It also configures over servicing allowance. + relayMeter relayer.RelayMeter } // NewRelayerProxy creates a new relayer proxy with the given dependencies or returns @@ -86,9 +90,15 @@ type relayerProxy struct { // Required dependencies: // - cosmosclient.Context // - client.BlockClient +// - crypto.RingCache +// - client.SupplierQueryClient // - client.SessionQueryClient // - client.SharedQueryClient -// - client.SupplierQueryClient +// - keyring.Keyring +// - client.SharedQueryClient +// - client.ApplicationQueryClient +// - client.ServiceQueryClient +// - client.EventsQueryClient // // Available options: // - WithSigningKeyNames @@ -112,6 +122,23 @@ func NewRelayerProxy( return nil, err } + rm := &ProxyRelayMeter{ + apps: make(map[string]*appRelayMeter), + overServicingAllowance: 0, + } + if err := depinject.Inject( + deps, + &rm.sharedQuerier, + &rm.applicationQuerier, + &rm.serviceQuerier, + &rm.blockQuerier, + &rm.eventsQueryClient, + ); err != nil { + return nil, err + } + + rp.relayMeter = rm + servedRelays, servedRelaysProducer := channel.NewObservable[*types.Relay]() rp.servedRelays = servedRelays @@ -143,6 +170,11 @@ func (rp *relayerProxy) Start(ctx context.Context) error { // Start the ring cache. rp.ringCache.Start(ctx) + // Start the relay meter. + if err := rp.relayMeter.Start(ctx); err != nil { + return err + } + startGroup, ctx := errgroup.WithContext(ctx) for _, relayServer := range rp.servers { diff --git a/pkg/relayer/proxy/relay_meter.go b/pkg/relayer/proxy/relay_meter.go new file mode 100644 index 000000000..fe72cbe98 --- /dev/null +++ b/pkg/relayer/proxy/relay_meter.go @@ -0,0 +1,301 @@ +package proxy + +import ( + "context" + "math/big" + "strings" + "sync" + + "cosmossdk.io/math" + cosmostypes "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/gogoproto/proto" + + "github.com/pokt-network/poktroll/app/volatile" + "github.com/pokt-network/poktroll/pkg/client" + "github.com/pokt-network/poktroll/pkg/client/tx" + "github.com/pokt-network/poktroll/pkg/crypto/protocol" + "github.com/pokt-network/poktroll/pkg/either" + "github.com/pokt-network/poktroll/pkg/observable" + "github.com/pokt-network/poktroll/pkg/observable/channel" + "github.com/pokt-network/poktroll/pkg/relayer" + apptypes "github.com/pokt-network/poktroll/x/application/types" + servicetypes "github.com/pokt-network/poktroll/x/service/types" + sessionkeeper "github.com/pokt-network/poktroll/x/session/keeper" + sharedtypes "github.com/pokt-network/poktroll/x/shared/types" +) + +var _ relayer.RelayMeter = (*ProxyRelayMeter)(nil) + +// appRelayMeter is the relay meter's internal representation of an application's +// max and consumed stake. +type appRelayMeter struct { + maxAmount cosmostypes.Coin + consumedAmount cosmostypes.Coin + app apptypes.Application +} + +// ProxyRelayMeter is the off-chain Supplier's rate limiter. +// It ensures that no application is over-serviced by the Supplier by maintaining +// the max amount of stake the supplier can consume per session and the amount of +// stake consumed by mined relays. +type ProxyRelayMeter struct { + // The known applications that have their stakes metered. + apps map[string]*appRelayMeter + // overServicingAllowance adjusts the max amount to allow for controlled over-servicing + // or, if negative, to create a stake buffer. + overServicingAllowance int64 + + applicationQuerier client.ApplicationQueryClient + serviceQuerier client.ServiceQueryClient + sharedQuerier client.SharedQueryClient + eventsQueryClient client.EventsQueryClient + blockQuerier client.BlockClient + + relayMeterMu sync.Mutex +} + +// Start starts the relay meter by observing application staked events and new sessions. +func (rmtr *ProxyRelayMeter) Start(ctx context.Context) error { + eventsObs, err := rmtr.eventsQueryClient.EventsBytes(ctx, "tm.event = 'Tx'") + if err != nil { + return err + } + + // Listen to application staked events and update known application stakes. + appStakedEvents := filterTypedEvents[*apptypes.EventApplicationStaked](ctx, eventsObs, nil) + channel.ForEach(ctx, appStakedEvents, rmtr.forEachEventApplicationStakedFn) + + // Listen to new blocks and reset the relay meter application stakes every new session. + committedBlocksSequence := rmtr.blockQuerier.CommittedBlocksSequence(ctx) + channel.ForEach(ctx, committedBlocksSequence, rmtr.forEachNewBlockFn) + + return nil +} + +// ClaimRelayPrice claims the relay price for the given relay request metadata. +// It deducts the relay cost from the application's stake and returns an error if +// the application has been rate limited. +func (rmtr *ProxyRelayMeter) ClaimRelayPrice(ctx context.Context, reqMeta servicetypes.RelayRequestMetadata) error { + rmtr.relayMeterMu.Lock() + defer rmtr.relayMeterMu.Unlock() + + sharedParams, err := rmtr.sharedQuerier.GetParams(ctx) + if err != nil { + return err + } + + service, err := rmtr.serviceQuerier.GetService(ctx, reqMeta.SessionHeader.ServiceId) + if err != nil { + return err + } + + serviceRelayDifficulty, err := rmtr.serviceQuerier.GetServiceRelayDifficulty(ctx, service.Id) + if err != nil { + return err + } + + appAddress := reqMeta.SessionHeader.ApplicationAddress + + appMetrics, ok := rmtr.apps[appAddress] + // If the application is seen for the first time in this session, calculate the + // max amount of stake the application can consume. + if !ok { + app, err := rmtr.applicationQuerier.GetApplication(ctx, appAddress) + if err != nil { + return err + } + + // calculate the max amount of stake the application can consume in the current session. + appStakeShare := getApplicationStakeShare(app.Stake, sharedParams) + maxAmount := appStakeShare.AddAmount(math.NewInt(rmtr.overServicingAllowance)) + appMetrics = &appRelayMeter{ + consumedAmount: cosmostypes.NewInt64Coin(volatile.DenomuPOKT, 0), + maxAmount: maxAmount, + app: app, + } + rmtr.apps[appAddress] = appMetrics + } + + // Get the cost of the relay based on the service and shared parameters. + relayCost, err := getMinedRelayCost(sharedParams, &service, serviceRelayDifficulty) + if err != nil { + return err + } + + // Increase the consumed stake amount by relay cost. + newConsumedAmount := appMetrics.consumedAmount.Add(relayCost) + + // If the consumed amount exceeds the max amount, return a rate limit error. + if appMetrics.maxAmount.IsLT(newConsumedAmount) { + return ErrRelayerProxyRateLimited.Wrapf( + "application has been rate limited, stake share: %s, expecting: %s", + appMetrics.consumedAmount.String(), + appMetrics.maxAmount.String(), + ) + } + + appMetrics.consumedAmount = newConsumedAmount + return nil +} + +// UnclaimRelayPrice releases the claimed relay price back to the application's stake. +// This is because ClaimRelayPrice is optimistic and has to check against the application +// stake before serving the relay or check if it is reward / volume applicable. +// This method is called when the relay is not mined. +func (rmtr *ProxyRelayMeter) UnclaimRelayPrice(ctx context.Context, reqMeta servicetypes.RelayRequestMetadata) error { + rmtr.relayMeterMu.Lock() + defer rmtr.relayMeterMu.Unlock() + + appAddress := reqMeta.SessionHeader.ApplicationAddress + + // Do not consider applications that have not been seen in this session. + appMetrics, ok := rmtr.apps[appAddress] + if !ok { + return ErrRelayerProxyUnknownApplication + } + + serviceId := reqMeta.SessionHeader.ServiceId + + sharedParams, err := rmtr.sharedQuerier.GetParams(ctx) + if err != nil { + return err + } + + service, err := rmtr.serviceQuerier.GetService(ctx, serviceId) + if err != nil { + return err + } + + difficulty, err := rmtr.serviceQuerier.GetServiceRelayDifficulty(ctx, serviceId) + + // Get the cost of the relay based on the service and shared parameters. + relayCost, err := getMinedRelayCost(sharedParams, &service, difficulty) + if err != nil { + return err + } + + // Decrease the consumed stake amount by relay cost. + newConsumedAmount := appMetrics.consumedAmount.Sub(relayCost) + + appMetrics.consumedAmount = newConsumedAmount + return nil +} + +// forEachNewBlockFn is a callback function that is called every time a new block is committed. +// It resets the relay meter's application stakes every new session so that new +// application stakes can be metered. +func (rmtr *ProxyRelayMeter) forEachNewBlockFn(ctx context.Context, block client.Block) { + rmtr.relayMeterMu.Lock() + defer rmtr.relayMeterMu.Unlock() + + sharedParams, err := rmtr.sharedQuerier.GetParams(ctx) + if err != nil { + return + } + numBlocksPerSession := int64(sharedParams.GetNumBlocksPerSession()) + + if block.Height()%numBlocksPerSession == 0 { + rmtr.apps = make(map[string]*appRelayMeter) + } +} + +// forEachEventApplicationStakedFn is a callback function that is called every time +// an application staked event is observed. It updates the relay meter's known +// application stakes. +func (rmtr *ProxyRelayMeter) forEachEventApplicationStakedFn(ctx context.Context, event *apptypes.EventApplicationStaked) { + rmtr.relayMeterMu.Lock() + defer rmtr.relayMeterMu.Unlock() + + app := event.GetApplication() + if _, ok := rmtr.apps[app.GetAddress()]; !ok { + return + } + + rmtr.apps[app.GetAddress()].app.Stake = app.GetStake() +} + +// filterTypedEvents filters the provided events bytes for the typed event T. +// T is then filtered by the provided filter function. +func filterTypedEvents[T proto.Message]( + ctx context.Context, + eventBzObs client.EventsBytesObservable, + filterFn func(T) bool, +) observable.Observable[T] { + eventObs, eventCh := channel.NewObservable[T]() + channel.ForEach(ctx, eventBzObs, func(ctx context.Context, maybeTxBz either.Bytes) { + if maybeTxBz.IsError() { + return + } + txBz, _ := maybeTxBz.ValueOrError() + + // Try to deserialize the provided bytes into an abci.TxResult. + txResult, err := tx.UnmarshalTxResult(txBz) + if err != nil { + return + } + + for _, event := range txResult.Result.Events { + eventApplicationStakedType := cosmostypes.MsgTypeURL(*new(T)) + if strings.Trim(event.GetType(), "/") != strings.Trim(eventApplicationStakedType, "/") { + continue + } + + typedEvent, err := cosmostypes.ParseTypedEvent(event) + if err != nil { + return + } + + castedEvent, ok := typedEvent.(T) + if !ok { + return + } + + // Apply the filter function to the typed event. + if filterFn == nil || filterFn(castedEvent) { + eventCh <- castedEvent + return + } + } + }) + + return eventObs +} + +// getMinedRelayCost returns the cost of a relay based on the shared parameters and the service. +// relayCost = CUPR * CUTTM * relayDifficultyMultiplier +func getMinedRelayCost( + sharedParams *sharedtypes.Params, + service *sharedtypes.Service, + relayMiningDifficulty servicetypes.RelayMiningDifficulty, +) (cosmostypes.Coin, error) { + // Get the difficulty multiplier based on the relay mining difficulty. + difficultyTargetHash := relayMiningDifficulty.GetTargetHash() + difficultyMultiplier := protocol.GetRelayDifficultyMultiplier(difficultyTargetHash) + + // Get the estimated cost of the relay if it gets mined. + relayCostAmt := service.ComputeUnitsPerRelay * sharedParams.GetComputeUnitsToTokensMultiplier() + relayCostRat := big.NewRat(int64(relayCostAmt), 1) + estimatedRelayCostRat := big.NewRat(0, 1).Mul(relayCostRat, difficultyMultiplier) + estimatedRelayCost := big.NewInt(0).Quo(estimatedRelayCostRat.Num(), estimatedRelayCostRat.Denom()) + + return cosmostypes.NewCoin(volatile.DenomuPOKT, math.NewIntFromBigInt(estimatedRelayCost)), nil +} + +// getMinedRelayCost returns the share of the application's stake that can be consumed +// per supplier per session. +func getApplicationStakeShare( + stake *cosmostypes.Coin, + sharedParams *sharedtypes.Params, +) cosmostypes.Coin { + maxRelayers := int64(sessionkeeper.NumSupplierPerSession) + appStakePerSupplier := stake.Amount.Quo(math.NewInt(maxRelayers)) + + // Calculate the number of pending sessions that might consume the application's stake. + numBlocksPerSession := int64(sharedParams.GetNumBlocksPerSession()) + pendingBlocks := sharedtypes.GetSessionEndToProofWindowCloseBlocks(sharedParams) + pendingSessions := (pendingBlocks + numBlocksPerSession - 1) / numBlocksPerSession + + appStakePerSupplierSession := appStakePerSupplier.Quo(math.NewInt(pendingSessions)) + + return cosmostypes.NewCoin(volatile.DenomuPOKT, appStakePerSupplierSession) +} diff --git a/pkg/relayer/proxy/server_builder.go b/pkg/relayer/proxy/server_builder.go index b59b1d490..e386aa68d 100644 --- a/pkg/relayer/proxy/server_builder.go +++ b/pkg/relayer/proxy/server_builder.go @@ -128,6 +128,7 @@ func (rp *relayerProxy) initializeProxyServers() (proxyServerMap map[string]rela serverConfig, rp.servedRelaysPublishCh, rp, + rp.relayMeter, ) default: return nil, ErrRelayerProxyUnsupportedTransportType diff --git a/pkg/relayer/proxy/synchronous.go b/pkg/relayer/proxy/synchronous.go index e3767eef6..4e62f1cf5 100644 --- a/pkg/relayer/proxy/synchronous.go +++ b/pkg/relayer/proxy/synchronous.go @@ -47,6 +47,10 @@ type synchronousRPCServer struct { // servedRelaysProducer is a channel that emits the relays that have been served, allowing // the servedRelays observable to fan-out notifications to its subscribers. servedRelaysProducer chan<- *types.Relay + + // relayMeter is the relay meter that the server uses to meter the relays and claim the relay price. + // It is used to ensure that the relays are metered and priced correctly. + relayMeter relayer.RelayMeter } // NewSynchronousServer creates a new HTTP server that listens for incoming @@ -61,6 +65,7 @@ func NewSynchronousServer( serverConfig *config.RelayMinerServerConfig, servedRelaysProducer chan<- *types.Relay, proxy relayer.RelayerProxy, + relayMeter relayer.RelayMeter, ) relayer.RelayServer { return &synchronousRPCServer{ logger: logger, @@ -68,6 +73,7 @@ func NewSynchronousServer( relayerProxy: proxy, servedRelaysProducer: servedRelaysProducer, serverConfig: serverConfig, + relayMeter: relayMeter, } } @@ -237,6 +243,14 @@ func (sync *synchronousRPCServer) serveHTTP( return nil, err } + // Optimistically claim the relay price before serving the relay. + // The relay price will be deducted from the application's stake before the relay is served. + // If the relay comes out to be not reward / volume applicable, the miner will refund the + // claimed price back to the application. + if err := sync.relayMeter.ClaimRelayPrice(ctx, relayRequest.Meta); err != nil { + return nil, err + } + // Deserialize the relay request payload to get the upstream HTTP request. poktHTTPRequest, err := sdktypes.DeserializeHTTPRequest(relayRequest.Payload) if err != nil { diff --git a/x/tokenomics/keeper/token_logic_modules.go b/x/tokenomics/keeper/token_logic_modules.go index 0dac283f6..f8e3f7caa 100644 --- a/x/tokenomics/keeper/token_logic_modules.go +++ b/x/tokenomics/keeper/token_logic_modules.go @@ -290,7 +290,7 @@ func (k Keeper) ProcessTokenLogicModules( // Ensure the claim amount is within the limits set by Relay Mining. // If not, update the settlement amount and emit relevant events. - actualSettlementCoin, err := k.ensureClaimAmountLimits(ctx, logger, &application, &supplier, claimSettlementCoin, applicationInitialStake) + actualSettlementCoin, err := k.ensureClaimAmountLimits(ctx, logger, &sharedParams, &application, &supplier, claimSettlementCoin, applicationInitialStake) if err != nil { return err } @@ -660,6 +660,7 @@ func (k Keeper) sendRewardsToAccount( func (k Keeper) ensureClaimAmountLimits( ctx context.Context, logger log.Logger, + sharedParams *sharedtypes.Params, application *apptypes.Application, supplier *sharedtypes.Supplier, claimSettlementCoin cosmostypes.Coin, @@ -670,8 +671,6 @@ func (k Keeper) ensureClaimAmountLimits( ) { logger = logger.With("helper", "ensureClaimAmountLimits") - // TODO_BETA(@red-0ne): Make relay miners use the appStake at the beginning - // of a session to determine the maximum amount they can claim. // Note that this also incorporates MintPerClaimGlobalInflation since applications // are being overcharged by that amount and the funds are sent to the DAO/PNF // before being reimbursed to the application in the future. @@ -684,25 +683,13 @@ func (k Keeper) ensureClaimAmountLimits( stakeRequirementAmt := claimSettlementCoin.Amount.Add(globalInflationAmt) totalClaimedCoin := sdk.NewCoin(volatile.DenomuPOKT, stakeRequirementAmt) - // TODO_BETA(@red-0ne): Introduce a session sliding window to account for potential consumption - // during the current session (i.e. Not the session being settled) such as: - // maxClaimableAmt = (AppStake / (currSessNum - settlingSessNum + 1) / NumSuppliersPerSession) - // In conjunction with single service applications, this would make maxClaimableAmt - // effectively addressing the issue of over-servicing. - // Example: - // - Current session num: 3 - // - Settling session num: 2 - // - Application already requested work for session 3 - // Problem: - // - If the application consumes its entire stake in settlement of session 2 - // - Then over-servicing in session 3 (i.e. No stake left to consume) - // Solution: - // - By dividing the claimable stake by 2 (3 - 2 + 1), settling session 2 assumes that - // the application will consume its maxClaimableAmt the current session (3). - // - Off-chain actors could use this formula during the servicing of session num 3 - // and assume maxClaimableAmt will be settled in session 2. - // - Guarantee no over-servicing at the cost of higher application stake requirements. - maxClaimableAmt := appStake.Amount.Quo(math.NewInt(sessionkeeper.NumSupplierPerSession)) + numBlocksPerSession := int64(sharedParams.GetNumBlocksPerSession()) + pendingBlocks := sharedtypes.GetSessionEndToProofWindowCloseBlocks(sharedParams) + pendingSessions := (pendingBlocks + numBlocksPerSession - 1) / numBlocksPerSession + + maxClaimableAmt := appStake.Amount. + Quo(math.NewInt(sessionkeeper.NumSupplierPerSession)). + Quo(math.NewInt(pendingSessions)) maxClaimSettlementAmt := stakeToMaxSettlementAmount(maxClaimableAmt) // Check if the claimable amount is capped by the max claimable amount. diff --git a/x/tokenomics/keeper/token_logic_modules_test.go b/x/tokenomics/keeper/token_logic_modules_test.go index 51bd4e46a..9eef0f1e1 100644 --- a/x/tokenomics/keeper/token_logic_modules_test.go +++ b/x/tokenomics/keeper/token_logic_modules_test.go @@ -65,9 +65,9 @@ func TestProcessTokenLogicModules_TLMBurnEqualsMint_Valid(t *testing.T) { supplierModuleAddress := authtypes.NewModuleAddress(suppliertypes.ModuleName).String() // Set compute_units_to_tokens_multiplier to simplify expectation calculations. - err := keepers.SharedKeeper.SetParams(ctx, sharedtypes.Params{ - ComputeUnitsToTokensMultiplier: globalComputeUnitsToTokensMultiplier, - }) + sharedParams := keepers.SharedKeeper.GetParams(ctx) + sharedParams.ComputeUnitsToTokensMultiplier = globalComputeUnitsToTokensMultiplier + err := keepers.SharedKeeper.SetParams(ctx, sharedParams) require.NoError(t, err) // TODO_TECHDEBT: Setting inflation to zero so we are testing the BurnEqualsMint logic exclusively. // Once it is a governance param, update it using the keeper above. @@ -195,9 +195,9 @@ func TestProcessTokenLogicModules_TLMBurnEqualsMint_Valid_SupplierExceedsMaxClai supplierModuleAddress := authtypes.NewModuleAddress(suppliertypes.ModuleName).String() // Set compute_units_to_tokens_multiplier to simplify expectation calculations. - err := keepers.SharedKeeper.SetParams(ctx, sharedtypes.Params{ - ComputeUnitsToTokensMultiplier: globalComputeUnitsToTokensMultiplier, - }) + sharedParams := keepers.SharedKeeper.GetParams(ctx) + sharedParams.ComputeUnitsToTokensMultiplier = globalComputeUnitsToTokensMultiplier + err := keepers.SharedKeeper.SetParams(ctx, sharedParams) require.NoError(t, err) // TODO_TECHDEBT: Setting inflation to zero so we are testing the BurnEqualsMint logic exclusively. // Once it is a governance param, update it using the keeper above. @@ -329,9 +329,9 @@ func TestProcessTokenLogicModules_TLMGlobalMint_Valid_MintDistributionCorrect(t keepers.SetService(ctx, *service) // Set compute_units_to_tokens_multiplier to simplify expectation calculations. - err := keepers.SharedKeeper.SetParams(ctx, sharedtypes.Params{ - ComputeUnitsToTokensMultiplier: globalComputeUnitsToTokensMultiplier, - }) + sharedParams := keepers.SharedKeeper.GetParams(ctx) + sharedParams.ComputeUnitsToTokensMultiplier = globalComputeUnitsToTokensMultiplier + err := keepers.SharedKeeper.SetParams(ctx, sharedParams) require.NoError(t, err) // Add a new application with non-zero app stake end balance to assert against. From f050d8c285dbf7404c1ec91a3b44cc3c5184b152 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Mon, 28 Oct 2024 17:57:18 +0100 Subject: [PATCH 30/53] fix: Cmd dependencies --- pkg/relayer/cmd/cmd.go | 18 +++++++++++++++++- pkg/relayer/proxy/proxy.go | 18 +----------------- pkg/relayer/proxy/relay_meter.go | 22 ++++++++++++++++++++++ 3 files changed, 40 insertions(+), 18 deletions(-) diff --git a/pkg/relayer/cmd/cmd.go b/pkg/relayer/cmd/cmd.go index c8f0df94e..f936b5021 100644 --- a/pkg/relayer/cmd/cmd.go +++ b/pkg/relayer/cmd/cmd.go @@ -195,10 +195,11 @@ func setupRelayerDependencies( config.NewSupplyDelegationClientFn(), // leaf config.NewSupplySharedQueryClientFn(), // leaf config.NewSupplyServiceQueryClientFn(), + config.NewSupplyApplicationQuerierFn(), + supplyRelayMeter, supplyMiner, config.NewSupplyAccountQuerierFn(), config.NewSupplyBankQuerierFn(), - config.NewSupplyApplicationQuerierFn(), config.NewSupplySupplierQuerierFn(), config.NewSupplySessionQuerierFn(), config.NewSupplyProofQueryClientFn(), @@ -228,6 +229,21 @@ func supplyMiner( return depinject.Configs(deps, depinject.Supply(mnr)), nil } +// supplyRelayMeter constructs a RelayMeter instance and returns a new +// depinject.Config which is supplied with the given deps and the new RelayMeter. +func supplyRelayMeter( + _ context.Context, + deps depinject.Config, + _ *cobra.Command, +) (depinject.Config, error) { + rm, err := proxy.NewRelayMeter(deps) + if err != nil { + return nil, err + } + + return depinject.Configs(deps, depinject.Supply(rm)), nil +} + // supplyTxFactory constructs a cosmostx.Factory instance and returns a new // depinject.Config which is supplied with the given deps and the new // cosmostx.Factory. diff --git a/pkg/relayer/proxy/proxy.go b/pkg/relayer/proxy/proxy.go index 8bd2d39b5..cab9aa4ca 100644 --- a/pkg/relayer/proxy/proxy.go +++ b/pkg/relayer/proxy/proxy.go @@ -118,27 +118,11 @@ func NewRelayerProxy( &rp.sessionQuerier, &rp.sharedQuerier, &rp.keyring, + &rp.relayMeter, ); err != nil { return nil, err } - rm := &ProxyRelayMeter{ - apps: make(map[string]*appRelayMeter), - overServicingAllowance: 0, - } - if err := depinject.Inject( - deps, - &rm.sharedQuerier, - &rm.applicationQuerier, - &rm.serviceQuerier, - &rm.blockQuerier, - &rm.eventsQueryClient, - ); err != nil { - return nil, err - } - - rp.relayMeter = rm - servedRelays, servedRelaysProducer := channel.NewObservable[*types.Relay]() rp.servedRelays = servedRelays diff --git a/pkg/relayer/proxy/relay_meter.go b/pkg/relayer/proxy/relay_meter.go index fe72cbe98..08bbe4060 100644 --- a/pkg/relayer/proxy/relay_meter.go +++ b/pkg/relayer/proxy/relay_meter.go @@ -6,6 +6,7 @@ import ( "strings" "sync" + "cosmossdk.io/depinject" "cosmossdk.io/math" cosmostypes "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/gogoproto/proto" @@ -43,6 +44,7 @@ type ProxyRelayMeter struct { apps map[string]*appRelayMeter // overServicingAllowance adjusts the max amount to allow for controlled over-servicing // or, if negative, to create a stake buffer. + // TODO_TECHDEBT(@red-0ne): Expose overServicingAllowance as a configuration parameter. overServicingAllowance int64 applicationQuerier client.ApplicationQueryClient @@ -54,6 +56,26 @@ type ProxyRelayMeter struct { relayMeterMu sync.Mutex } +func NewRelayMeter(deps depinject.Config) (relayer.RelayMeter, error) { + rm := &ProxyRelayMeter{ + apps: make(map[string]*appRelayMeter), + overServicingAllowance: 0, + } + + if err := depinject.Inject( + deps, + &rm.sharedQuerier, + &rm.applicationQuerier, + &rm.serviceQuerier, + &rm.blockQuerier, + &rm.eventsQueryClient, + ); err != nil { + return nil, err + } + + return rm, nil +} + // Start starts the relay meter by observing application staked events and new sessions. func (rmtr *ProxyRelayMeter) Start(ctx context.Context) error { eventsObs, err := rmtr.eventsQueryClient.EventsBytes(ctx, "tm.event = 'Tx'") From 196c2fa31ef03b71d05149d81539c0f24f488ed4 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Mon, 28 Oct 2024 18:22:49 +0100 Subject: [PATCH 31/53] fix: Hidden error --- pkg/relayer/miner/miner.go | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/pkg/relayer/miner/miner.go b/pkg/relayer/miner/miner.go index 39ab423ef..c62b81f7e 100644 --- a/pkg/relayer/miner/miner.go +++ b/pkg/relayer/miner/miner.go @@ -89,7 +89,10 @@ func (mnr *miner) mapMineRelay( ) (_ either.Either[*relayer.MinedRelay], skip bool) { relayBz, err := relay.Marshal() if err != nil { - mnr.relayMeter.UnclaimRelayPrice(ctx, relay.GetReq().GetMeta()) + meteringError := mnr.relayMeter.UnclaimRelayPrice(ctx, relay.GetReq().GetMeta()) + if meteringError != nil { + return either.Error[*relayer.MinedRelay](fmt.Errorf("failed to unclaim relay price: %w", meteringError)), false + } return either.Error[*relayer.MinedRelay](err), false } relayHashArr := protocol.GetRelayHashFromBytes(relayBz) @@ -97,13 +100,19 @@ func (mnr *miner) mapMineRelay( relayDifficultyTargetHash, err := mnr.getServiceRelayDifficultyTargetHash(ctx, relay.Req) if err != nil { - mnr.relayMeter.UnclaimRelayPrice(ctx, relay.GetReq().GetMeta()) + meteringError := mnr.relayMeter.UnclaimRelayPrice(ctx, relay.GetReq().GetMeta()) + if meteringError != nil { + return either.Error[*relayer.MinedRelay](fmt.Errorf("failed to unclaim relay price: %w", meteringError)), false + } return either.Error[*relayer.MinedRelay](err), false } // The relay IS NOT volume / reward applicable if !protocol.IsRelayVolumeApplicable(relayHash, relayDifficultyTargetHash) { - mnr.relayMeter.UnclaimRelayPrice(ctx, relay.GetReq().GetMeta()) + meteringError := mnr.relayMeter.UnclaimRelayPrice(ctx, relay.GetReq().GetMeta()) + if meteringError != nil { + return either.Error[*relayer.MinedRelay](fmt.Errorf("failed to unclaim relay price: %w", meteringError)), false + } return either.Success[*relayer.MinedRelay](nil), true } From 6fea32f6c183c23c73877115df4c3f24870e3b6a Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Mon, 28 Oct 2024 18:32:54 +0100 Subject: [PATCH 32/53] fix: Ineffectual assignement --- pkg/relayer/proxy/relay_meter.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pkg/relayer/proxy/relay_meter.go b/pkg/relayer/proxy/relay_meter.go index 08bbe4060..8c4491991 100644 --- a/pkg/relayer/proxy/relay_meter.go +++ b/pkg/relayer/proxy/relay_meter.go @@ -122,7 +122,8 @@ func (rmtr *ProxyRelayMeter) ClaimRelayPrice(ctx context.Context, reqMeta servic // If the application is seen for the first time in this session, calculate the // max amount of stake the application can consume. if !ok { - app, err := rmtr.applicationQuerier.GetApplication(ctx, appAddress) + var app apptypes.Application + app, err = rmtr.applicationQuerier.GetApplication(ctx, appAddress) if err != nil { return err } @@ -189,6 +190,9 @@ func (rmtr *ProxyRelayMeter) UnclaimRelayPrice(ctx context.Context, reqMeta serv } difficulty, err := rmtr.serviceQuerier.GetServiceRelayDifficulty(ctx, serviceId) + if err != nil { + return err + } // Get the cost of the relay based on the service and shared parameters. relayCost, err := getMinedRelayCost(sharedParams, &service, difficulty) From 7bd60586ba3a41ada906662c50453e36b5abd048 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Tue, 29 Oct 2024 01:22:29 +0100 Subject: [PATCH 33/53] chore: Address review change requests --- proto/poktroll/tokenomics/event.proto | 2 +- .../integration/application/min_stake_test.go | 24 ++--- testutil/keeper/tokenomics.go | 19 ++-- x/tokenomics/keeper/settle_pending_claims.go | 57 +++++++---- x/tokenomics/keeper/token_logic_modules.go | 99 +++++++++++-------- .../keeper/token_logic_modules_test.go | 70 +++++++------ 6 files changed, 158 insertions(+), 113 deletions(-) diff --git a/proto/poktroll/tokenomics/event.proto b/proto/poktroll/tokenomics/event.proto index c3751c60d..23c4f8e10 100644 --- a/proto/poktroll/tokenomics/event.proto +++ b/proto/poktroll/tokenomics/event.proto @@ -82,7 +82,7 @@ message EventSupplierSlashed { } // EventApplicationReimbursementRequest is emitted when an application requests -// a reimbursement +// a reimbursement. message EventApplicationReimbursementRequest { string application_addr = 1; string supplier_operator_addr = 2; diff --git a/tests/integration/application/min_stake_test.go b/tests/integration/application/min_stake_test.go index 43c801a33..52bc57912 100644 --- a/tests/integration/application/min_stake_test.go +++ b/tests/integration/application/min_stake_test.go @@ -2,11 +2,9 @@ package application import ( "context" - "math/big" "testing" cosmoslog "cosmossdk.io/log" - "cosmossdk.io/math" cosmostypes "github.com/cosmos/cosmos-sdk/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/stretchr/testify/require" @@ -237,8 +235,8 @@ func (s *applicationMinStakeTestSuite) getExpectedApp(claim *prooftypes.Claim) * expectedBurnCoin, err := claim.GetClaimeduPOKT(sharedParams, relayMiningDifficulty) require.NoError(s.T(), err) - globalInflationAmt := calculateGlobalInflation(expectedBurnCoin.Amount) - expectedEndStake := s.appStake.Sub(expectedBurnCoin).SubAmount(globalInflationAmt) + globalInflationAmt, _ := tokenomicskeeper.CalculateGlobalPerClaimMintInflationFromSettlementAmount(expectedBurnCoin) + expectedEndStake := s.appStake.Sub(expectedBurnCoin).Sub(globalInflationAmt) return &apptypes.Application{ Address: s.appBech32, Stake: &expectedEndStake, @@ -307,21 +305,11 @@ func (s *applicationMinStakeTestSuite) assertUnbondingEndEventObserved(expectedA func (s *applicationMinStakeTestSuite) assertAppStakeIsReturnedToBalance() { s.T().Helper() - expectedAppBurn := math.NewInt(int64(s.numRelays * s.numComputeUnitsPerRelay * sharedtypes.DefaultComputeUnitsToTokensMultiplier)) - globalInflationAmt := calculateGlobalInflation(expectedAppBurn) - expectedAppBalance := s.appStake.SubAmount(expectedAppBurn).SubAmount(globalInflationAmt) + expectedAppBurn := int64(s.numRelays * s.numComputeUnitsPerRelay * sharedtypes.DefaultComputeUnitsToTokensMultiplier) + expectedAppBurnCoin := cosmostypes.NewInt64Coin(volatile.DenomuPOKT, expectedAppBurn) + globalInflationCoin, _ := tokenomicskeeper.CalculateGlobalPerClaimMintInflationFromSettlementAmount(expectedAppBurnCoin) + expectedAppBalance := s.appStake.Sub(expectedAppBurnCoin).Sub(globalInflationCoin) appBalance := s.getAppBalance() require.Equal(s.T(), expectedAppBalance.Amount.Int64(), appBalance.Amount.Int64()) } - -// calculateGlobalInflation calculates the global inflation for the given settlement amount. -func calculateGlobalInflation(settlementAmt math.Int) math.Int { - globalInflationFloat := new(big.Float).Mul( - new(big.Float).SetInt(settlementAmt.BigInt()), - big.NewFloat(tokenomicskeeper.MintPerClaimedTokenGlobalInflation), - ) - globalInflationInt, _ := globalInflationFloat.Int(nil) - - return math.NewIntFromBigInt(globalInflationInt) -} diff --git a/testutil/keeper/tokenomics.go b/testutil/keeper/tokenomics.go index e170117ab..73d6f8a05 100644 --- a/testutil/keeper/tokenomics.go +++ b/testutil/keeper/tokenomics.go @@ -6,7 +6,7 @@ import ( "testing" "cosmossdk.io/log" - sdkmath "cosmossdk.io/math" + cosmosmath "cosmossdk.io/math" "cosmossdk.io/store" "cosmossdk.io/store/metrics" storetypes "cosmossdk.io/store/types" @@ -119,7 +119,7 @@ func TokenomicsKeeperWithActorAddrs(t testing.TB) ( // Prepare the test application. application := apptypes.Application{ Address: sample.AccAddress(), - Stake: &sdk.Coin{Denom: "upokt", Amount: sdkmath.NewInt(100000)}, + Stake: &sdk.Coin{Denom: "upokt", Amount: cosmosmath.NewInt(100000)}, ServiceConfigs: []*sharedtypes.ApplicationServiceConfig{{ServiceId: service.Id}}, } @@ -128,7 +128,7 @@ func TokenomicsKeeperWithActorAddrs(t testing.TB) ( supplier := sharedtypes.Supplier{ OwnerAddress: supplierOwnerAddr, OperatorAddress: supplierOwnerAddr, - Stake: &sdk.Coin{Denom: "upokt", Amount: sdkmath.NewInt(100000)}, + Stake: &sdk.Coin{Denom: "upokt", Amount: cosmosmath.NewInt(100000)}, Services: []*sharedtypes.SupplierServiceConfig{ { ServiceId: service.Id, @@ -351,9 +351,9 @@ func NewTokenomicsModuleKeepers( require.NoError(t, bankKeeper.SetParams(sdkCtx, banktypes.DefaultParams())) // Provide some initial funds to the suppliers & applications module accounts. - err = bankKeeper.MintCoins(sdkCtx, suppliertypes.ModuleName, sdk.NewCoins(sdk.NewCoin("upokt", sdkmath.NewInt(1000000000000)))) + err = bankKeeper.MintCoins(sdkCtx, suppliertypes.ModuleName, sdk.NewCoins(sdk.NewCoin("upokt", cosmosmath.NewInt(1000000000000)))) require.NoError(t, err) - err = bankKeeper.MintCoins(sdkCtx, apptypes.ModuleName, sdk.NewCoins(sdk.NewCoin("upokt", sdkmath.NewInt(1000000000000)))) + err = bankKeeper.MintCoins(sdkCtx, apptypes.ModuleName, sdk.NewCoins(sdk.NewCoin("upokt", cosmosmath.NewInt(1000000000000)))) require.NoError(t, err) // Construct a real shared keeper. @@ -519,17 +519,24 @@ func WithProposerAddr(addr string) TokenomicsModuleKeepersOpt { } } -// WithProofRequirement is an option to set the proof requirement in the tokenomics module keepers. +// WithProofRequirement is an option to enable or disable the proof requirement +// in the tokenomics module keepers by setting the proof request probability to +// 1 or 0, respectively whie setting the proof requirement threshold to 0 or +// MaxInt64, respectively. func WithProofRequirement(proofRequired bool) TokenomicsModuleKeepersOpt { return func(ctx context.Context, keepers *TokenomicsModuleKeepers) context.Context { proofParams := keepers.ProofKeeper.GetParams(ctx) if proofRequired { + // Require a proof 100% of the time probabilistically speaking. proofParams.ProofRequestProbability = 1 + // Require a proof of any claim amount (i.e. anything greater than 0). proofRequirementThreshold := cosmostypes.NewInt64Coin(volatile.DenomuPOKT, 0) proofParams.ProofRequirementThreshold = &proofRequirementThreshold } else { + // Never require a proof probabilistically speaking. proofParams.ProofRequestProbability = 0 + // Require a proof for MaxInt64 claim amount (i.e. should never trigger). proofRequirementThreshold := cosmostypes.NewInt64Coin(volatile.DenomuPOKT, math.MaxInt64) proofParams.ProofRequirementThreshold = &proofRequirementThreshold } diff --git a/x/tokenomics/keeper/settle_pending_claims.go b/x/tokenomics/keeper/settle_pending_claims.go index 91b1afdba..5bf90a83d 100644 --- a/x/tokenomics/keeper/settle_pending_claims.go +++ b/x/tokenomics/keeper/settle_pending_claims.go @@ -1,6 +1,7 @@ package keeper import ( + "context" "fmt" "cosmossdk.io/math" @@ -37,23 +38,12 @@ func (k Keeper) SettlePendingClaims(ctx sdk.Context) ( } // Capture the applications initial stake which will be used to calculate the - // max share any claim could receive from the application stake. - // This ensures that each claim can calculate the maximum amount it can take + // max share any claim could burn from the application stake. + // This ensures that each supplier can calculate the maximum amount it can take // from an application's stake. - applicationInitialStakeMap := make(map[string]sdk.Coin) - for _, claim := range expiringClaims { - appAddress := claim.SessionHeader.ApplicationAddress - if _, isAppFound := applicationInitialStakeMap[appAddress]; isAppFound { - continue - } - - app, isAppFound := k.applicationKeeper.GetApplication(ctx, appAddress) - if !isAppFound { - err = apptypes.ErrAppNotFound.Wrapf("application address: %q", appAddress) - return settledResult, expiredResult, err - } - - applicationInitialStakeMap[appAddress] = *app.GetStake() + applicationInitialStakeMap, err := k.getApplicationInitialStakeMap(ctx, expiringClaims) + if err != nil { + return settledResult, expiredResult, err } blockHeight := ctx.BlockHeight() @@ -197,8 +187,8 @@ func (k Keeper) SettlePendingClaims(ctx sdk.Context) ( // 1. The claim does not require a proof. // 2. The claim requires a proof and a valid proof was found. - claimApplication := claim.SessionHeader.ApplicationAddress - applicationInitialStake := applicationInitialStakeMap[claimApplication] + appAddress := claim.GetSessionHeader().GetApplicationAddress() + applicationInitialStake := applicationInitialStakeMap[appAddress] // Manage the mint & burn accounting for the claim. if err = k.ProcessTokenLogicModules(ctx, &claim, applicationInitialStake); err != nil { @@ -426,3 +416,34 @@ func (k Keeper) slashSupplierStake( return nil } + +// getApplicationInitialStakeMap returns a map from an application address to the +// initial stake of the application. This is used to calculate the maximum share +// any claim could burn from the application stake. +func (k Keeper) getApplicationInitialStakeMap( + ctx context.Context, + expiringClaims []prooftypes.Claim, +) (applicationInitialStakeMap map[string]sdk.Coin, err error) { + applicationInitialStakeMap = make(map[string]sdk.Coin) + for _, claim := range expiringClaims { + appAddress := claim.SessionHeader.ApplicationAddress + // The same application is participating in other claims being settled, + // so we already capture its initial stake. + if _, isAppFound := applicationInitialStakeMap[appAddress]; isAppFound { + continue + } + + app, isAppFound := k.applicationKeeper.GetApplication(ctx, appAddress) + if !isAppFound { + err := apptypes.ErrAppNotFound.Wrapf( + "trying to settle a claim for an application that does not exist (which should never happen) with address: %q", + appAddress, + ) + return nil, err + } + + applicationInitialStakeMap[appAddress] = *app.GetStake() + } + + return applicationInitialStakeMap, nil +} diff --git a/x/tokenomics/keeper/token_logic_modules.go b/x/tokenomics/keeper/token_logic_modules.go index 0dac283f6..53aca833b 100644 --- a/x/tokenomics/keeper/token_logic_modules.go +++ b/x/tokenomics/keeper/token_logic_modules.go @@ -27,8 +27,10 @@ import ( var ( // Governance parameters for the TLMGlobalMint module - // TODO_UPNEXT(@olshansk, #732): Make this a governance parameter and give it a non-zero value + tests. - MintPerClaimedTokenGlobalInflation = 0.1 + // TODO_BETA(@red-0ne, #732): Make this a governance parameter and give it a non-zero value + tests. + // GlobalInflationPerClaim is the percentage of the claim amount that is minted + // by TLMGlobalMint to reward the actors in the network. + GlobalInflationPerClaim = 0.1 ) const ( @@ -128,7 +130,7 @@ func init() { _, hasGlobalMintTLM := tokenLogicModuleProcessorMap[TLMGlobalMint] _, hasGlobalMintReimbursementRequestTLM := tokenLogicModuleProcessorMap[TLMGlobalMintReimbursementRequest] if hasGlobalMintTLM != hasGlobalMintReimbursementRequestTLM { - panic("TLMGlobalMint and TLMGlobalMintReimbursementRequest must be activated together") + panic("TLMGlobalMint and TLMGlobalMintReimbursementRequest must be (de-)activated together") } } @@ -419,13 +421,13 @@ func (k Keeper) TokenLogicModuleGlobalMint( ) error { logger := k.Logger().With("method", "TokenLogicModuleGlobalMint") - if MintPerClaimedTokenGlobalInflation == 0 { + if GlobalInflationPerClaim == 0 { logger.Warn("global inflation is set to zero. Skipping Global Mint TLM.") return nil } // Determine how much new uPOKT to mint based on global inflation - newMintCoin, newMintAmtFloat := calculateGlobalPerClaimMintInflationFromSettlementAmount(settlementCoin) + newMintCoin, newMintAmtFloat := CalculateGlobalPerClaimMintInflationFromSettlementAmount(settlementCoin) if newMintCoin.Amount.Int64() == 0 { return tokenomicstypes.ErrTokenomicsMintAmountZero } @@ -509,29 +511,43 @@ func (k Keeper) TokenLogicModuleGlobalMintReimbursementRequest( logger := k.Logger().With("method", "TokenLogicModuleGlobalMintReimbursementRequest") // Do not process the reimbursement request if there is no global inflation. - if MintPerClaimedTokenGlobalInflation == 0 { + if GlobalInflationPerClaim == 0 { logger.Warn("global inflation is set to zero. Skipping Global Mint Reimbursement Request TLM.") return nil } // Determine how much new uPOKT to mint based on global inflation - newMintCoin, _ := calculateGlobalPerClaimMintInflationFromSettlementAmount(actualSettlementCoin) + newMintCoin, _ := CalculateGlobalPerClaimMintInflationFromSettlementAmount(actualSettlementCoin) if newMintCoin.Amount.Int64() == 0 { return tokenomicstypes.ErrTokenomicsMintAmountZero } - // Update the application's on-chain stake - // This should not fall below zero since `ensureClaimAmountLimits` should have - // already checked and adjusted the settlement amount so that the application - // stake covers the global inflation. - newAppStake := application.Stake.Sub(newMintCoin) + newAppStake, err := application.Stake.SafeSub(newMintCoin) + // This should THEORETICALLY NEVER fall below zero. + // `ensureClaimAmountLimits` should have already checked and adjusted the settlement + // amount so that the application stake covers the global inflation. + if err != nil { + return err + } application.Stake = &newAppStake logger.Info(fmt.Sprintf("updated application %q stake to %s", application.Address, newAppStake)) + globalInflationMintedCoinsForClaim := sdk.NewCoins(newMintCoin) + + // Send the global per claim mint inflation uPOKT from the tokenomics module + // account to PNF/DAO. + daoAccountAddr, err := cosmostypes.AccAddressFromBech32(k.GetAuthority()) + if err != nil { + return tokenomicstypes.ErrTokenomicsApplicationReimbursementRequestFailed.Wrapf( + "getting PNF/DAO address: %v", + err, + ) + } + // Send the global per claim mint inflation uPOKT from the application module - // account to the tokenomics module account. + // account to the tokenomics module account as an intermediary step. if err := k.bankKeeper.SendCoinsFromModuleToModule( - ctx, apptypes.ModuleName, tokenomicstypes.ModuleName, sdk.NewCoins(newMintCoin), + ctx, apptypes.ModuleName, tokenomicstypes.ModuleName, globalInflationMintedCoinsForClaim, ); err != nil { return tokenomicstypes.ErrTokenomicsApplicationReimbursementRequestFailed.Wrapf( "sending %s from the application module account to the tokenomics module account: %v", @@ -544,16 +560,10 @@ func (k Keeper) TokenLogicModuleGlobalMintReimbursementRequest( )) // Send the global per claim mint inflation uPOKT from the tokenomics module - // account to PNF/DAO. - daoAccountAddr, err := cosmostypes.AccAddressFromBech32(k.GetAuthority()) - if err != nil { - return tokenomicstypes.ErrTokenomicsApplicationReimbursementRequestFailed.Wrapf( - "getting PNF/DAO address: %v", - err, - ) - } + // for second order economic effects. + // See: https://discord.com/channels/824324475256438814/997192534168182905/1299372745632649408 if err := k.bankKeeper.SendCoinsFromModuleToAccount( - ctx, tokenomicstypes.ModuleName, daoAccountAddr, sdk.NewCoins(newMintCoin), + ctx, tokenomicstypes.ModuleName, daoAccountAddr, globalInflationMintedCoinsForClaim, ); err != nil { return tokenomicstypes.ErrTokenomicsApplicationReimbursementRequestFailed.Wrapf( "sending %s from the tokenomics module account to the PNF/DAO account: %v", @@ -561,7 +571,9 @@ func (k Keeper) TokenLogicModuleGlobalMintReimbursementRequest( ) } - // Prepare and emit the event for the application being overcharged. + // Prepare and emit the event for the application that'll required reimbursement. + // Recall that it is being overcharged to compoensate for global inflation while + // preventing self-dealing attacks. reimbursementRequestEvent := &tokenomicstypes.EventApplicationReimbursementRequest{ ApplicationAddr: application.Address, SupplierOperatorAddr: supplier.OperatorAddress, @@ -573,10 +585,13 @@ func (k Keeper) TokenLogicModuleGlobalMintReimbursementRequest( eventManger := cosmostypes.UnwrapSDKContext(ctx).EventManager() if err := eventManger.EmitTypedEvent(reimbursementRequestEvent); err != nil { - return tokenomicstypes.ErrTokenomicsEmittingEventFailed.Wrapf( + err = tokenomicstypes.ErrTokenomicsEmittingEventFailed.Wrapf( "(%+v): %s", reimbursementRequestEvent, err, ) + + logger.Error(err.Error()) + return err } return nil @@ -655,8 +670,6 @@ func (k Keeper) sendRewardsToAccount( // If this is not the case, then the supplier essentially did "free work" and the // actual claim amount is less than what was claimed. // Ref: https://arxiv.org/pdf/2305.10672 -// TODO_TEST: Add more tests for edge cases that exercise all the code paths -// actualSettlementCoins could be updated in this function. func (k Keeper) ensureClaimAmountLimits( ctx context.Context, logger log.Logger, @@ -679,10 +692,10 @@ func (k Keeper) ensureClaimAmountLimits( // The application should have enough stake to cover for the global mint reimbursement. // This amount is deducted from the maximum claimable amount. - globalInflationCoin, _ := calculateGlobalPerClaimMintInflationFromSettlementAmount(claimSettlementCoin) + globalInflationCoin, _ := CalculateGlobalPerClaimMintInflationFromSettlementAmount(claimSettlementCoin) globalInflationAmt := globalInflationCoin.Amount - stakeRequirementAmt := claimSettlementCoin.Amount.Add(globalInflationAmt) - totalClaimedCoin := sdk.NewCoin(volatile.DenomuPOKT, stakeRequirementAmt) + minRequiredAppStakeAmt := claimSettlementCoin.Amount.Add(globalInflationAmt) + totalClaimedCoin := sdk.NewCoin(volatile.DenomuPOKT, minRequiredAppStakeAmt) // TODO_BETA(@red-0ne): Introduce a session sliding window to account for potential consumption // during the current session (i.e. Not the session being settled) such as: @@ -703,15 +716,18 @@ func (k Keeper) ensureClaimAmountLimits( // and assume maxClaimableAmt will be settled in session 2. // - Guarantee no over-servicing at the cost of higher application stake requirements. maxClaimableAmt := appStake.Amount.Quo(math.NewInt(sessionkeeper.NumSupplierPerSession)) - maxClaimSettlementAmt := stakeToMaxSettlementAmount(maxClaimableAmt) + maxClaimSettlementAmt := stakeShareToMaxSettlementAmount(maxClaimableAmt) // Check if the claimable amount is capped by the max claimable amount. - if stakeRequirementAmt.GT(maxClaimableAmt) { + // As per the Relay Mining paper, the Supplier claim MUST NO exceed the application's + // allocated stake. If it does, the claim is capped by the application's allocated stake + // and the supplier is effectively "overserviced". + if minRequiredAppStakeAmt.GT(maxClaimableAmt) { logger.Warn(fmt.Sprintf("Claim by supplier %s EXCEEDS LIMITS for application %s. Max claimable amount < Claim amount: %v < %v", supplier.GetOperatorAddress(), application.GetAddress(), maxClaimableAmt, claimSettlementCoin.Amount)) - stakeRequirementAmt = maxClaimableAmt - maxClaimSettlementAmt = stakeToMaxSettlementAmount(stakeRequirementAmt) + minRequiredAppStakeAmt = maxClaimableAmt + maxClaimSettlementAmt = stakeShareToMaxSettlementAmount(minRequiredAppStakeAmt) } // Nominal case: The claimable amount is within the limits set by Relay Mining. @@ -797,14 +813,15 @@ func (k Keeper) distributeSupplierRewardsToShareHolders( return nil } -// calculateGlobalPerClaimMintInflationFromSettlementAmount calculates the amount +// CalculateGlobalPerClaimMintInflationFromSettlementAmount calculates the amount // of uPOKT to mint based on the global per claim inflation rate as a function of // the settlement amount for a particular claim(s) or session(s). -func calculateGlobalPerClaimMintInflationFromSettlementAmount(settlementCoin sdk.Coin) (sdk.Coin, big.Float) { +// DEV_NOTE: This function is publically exposed to be used in the tests. +func CalculateGlobalPerClaimMintInflationFromSettlementAmount(settlementCoin sdk.Coin) (sdk.Coin, big.Float) { // Determine how much new uPOKT to mint based on global per claim inflation. // TODO_MAINNET: Consider using fixed point arithmetic for deterministic results. settlementAmtFloat := new(big.Float).SetUint64(settlementCoin.Amount.Uint64()) - newMintAmtFloat := new(big.Float).Mul(settlementAmtFloat, big.NewFloat(MintPerClaimedTokenGlobalInflation)) + newMintAmtFloat := new(big.Float).Mul(settlementAmtFloat, big.NewFloat(GlobalInflationPerClaim)) // DEV_NOTE: If new mint is less than 1 and more than 0, ceil it to 1 so that // we never expect to process a claim with 0 minted tokens. if newMintAmtFloat.Cmp(big.NewFloat(1)) < 0 && newMintAmtFloat.Cmp(big.NewFloat(0)) > 0 { @@ -815,16 +832,16 @@ func calculateGlobalPerClaimMintInflationFromSettlementAmount(settlementCoin sdk return mintAmtCoin, *newMintAmtFloat } -// stakeToMaxSettlementAmount calculates the max amount of uPOKT to that the supplier +// stakeShareToMaxSettlementAmount calculates the max amount of uPOKT to that the supplier // can claim based on the stake share and the global inflation allocation percentage. -// This is the inverse of calculateGlobalPerClaimMintInflationFromSettlementAmount. +// This is the inverse of CalculateGlobalPerClaimMintInflationFromSettlementAmount: // stake = maxSettlementAmt + globalInflationAmt // stake = maxSettlementAmt + (maxSettlementAmt * MintPerClaimedTokenGlobalInflation) // stake = maxSettlementAmt * (1 + MintPerClaimedTokenGlobalInflation) // maxSettlementAmt = stake / (1 + MintPerClaimedTokenGlobalInflation) -func stakeToMaxSettlementAmount(stakeShare math.Int) math.Int { +func stakeShareToMaxSettlementAmount(stakeShare math.Int) math.Int { stakeSahreFloat := big.NewFloat(0).SetInt(stakeShare.BigInt()) - maxSettlementAmountFloat := big.NewFloat(0).Quo(stakeSahreFloat, big.NewFloat(1+MintPerClaimedTokenGlobalInflation)) + maxSettlementAmountFloat := big.NewFloat(0).Quo(stakeSahreFloat, big.NewFloat(1+GlobalInflationPerClaim)) settlementAmount, _ := maxSettlementAmountFloat.Int(nil) return math.NewIntFromBigInt(settlementAmount) diff --git a/x/tokenomics/keeper/token_logic_modules_test.go b/x/tokenomics/keeper/token_logic_modules_test.go index 51bd4e46a..817442d01 100644 --- a/x/tokenomics/keeper/token_logic_modules_test.go +++ b/x/tokenomics/keeper/token_logic_modules_test.go @@ -4,10 +4,10 @@ import ( "bytes" "context" "fmt" - math2 "math" + "math" "testing" - "cosmossdk.io/math" + cosmosmath "cosmossdk.io/math" cosmostypes "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -43,8 +43,8 @@ func init() { func TestProcessTokenLogicModules_TLMBurnEqualsMint_Valid(t *testing.T) { // Test Parameters - appInitialStake := apptypes.DefaultMinStake.Amount.Mul(math.NewInt(2)) - supplierInitialStake := math.NewInt(1000000) + appInitialStake := apptypes.DefaultMinStake.Amount.Mul(cosmosmath.NewInt(2)) + supplierInitialStake := cosmosmath.NewInt(1000000) supplierRevShareRatios := []float32{12.5, 37.5, 50} globalComputeUnitsToTokensMultiplier := uint64(1) serviceComputeUnitsPerRelay := uint64(1) @@ -57,7 +57,7 @@ func TestProcessTokenLogicModules_TLMBurnEqualsMint_Valid(t *testing.T) { // Ensure the claim is within relay mining bounds numTokensClaimed := int64(numRelays * serviceComputeUnitsPerRelay * globalComputeUnitsToTokensMultiplier) - maxClaimableAmountPerSupplier := appInitialStake.Quo(math.NewInt(sessionkeeper.NumSupplierPerSession)) + maxClaimableAmountPerSupplier := appInitialStake.Quo(cosmosmath.NewInt(sessionkeeper.NumSupplierPerSession)) require.GreaterOrEqual(t, maxClaimableAmountPerSupplier.Int64(), numTokensClaimed) // Retrieve the app and supplier module addresses @@ -71,10 +71,10 @@ func TestProcessTokenLogicModules_TLMBurnEqualsMint_Valid(t *testing.T) { require.NoError(t, err) // TODO_TECHDEBT: Setting inflation to zero so we are testing the BurnEqualsMint logic exclusively. // Once it is a governance param, update it using the keeper above. - prevInflationValue := tokenomicskeeper.MintPerClaimedTokenGlobalInflation - tokenomicskeeper.MintPerClaimedTokenGlobalInflation = 0 + prevInflationValue := tokenomicskeeper.GlobalInflationPerClaim + tokenomicskeeper.GlobalInflationPerClaim = 0 t.Cleanup(func() { - tokenomicskeeper.MintPerClaimedTokenGlobalInflation = prevInflationValue + tokenomicskeeper.GlobalInflationPerClaim = prevInflationValue }) // Add a new application with non-zero app stake end balance to assert against. @@ -127,7 +127,7 @@ func TestProcessTokenLogicModules_TLMBurnEqualsMint_Valid(t *testing.T) { require.EqualValues(t, appStartBalance, appEndBalance) // Determine the expected app end stake amount and the expected app burn - appBurn := math.NewInt(numTokensClaimed) + appBurn := cosmosmath.NewInt(numTokensClaimed) expectedAppEndStakeAmount := appInitialStake.Sub(appBurn) // Assert that `applicationAddress` staked balance has decreased by the appropriate amount @@ -173,7 +173,7 @@ func TestProcessTokenLogicModules_TLMBurnEqualsMint_Valid_SupplierExceedsMaxClai serviceComputeUnitsPerRelay := uint64(100) service := prepareTestService(serviceComputeUnitsPerRelay) numRelays := uint64(1000) // By a single supplier for application in this session - supplierInitialStake := math.NewInt(1000000) + supplierInitialStake := cosmosmath.NewInt(1000000) supplierRevShareRatios := []float32{12.5, 37.5, 50} // Prepare the keepers @@ -184,7 +184,7 @@ func TestProcessTokenLogicModules_TLMBurnEqualsMint_Valid_SupplierExceedsMaxClai // Determine the max a supplier can claim maxClaimableAmountPerSupplier := int64(numRelays * serviceComputeUnitsPerRelay * globalComputeUnitsToTokensMultiplier) // Figure out what the app's initial stake should be to cover the max claimable amount - appInitialStake := math.NewInt(maxClaimableAmountPerSupplier*sessionkeeper.NumSupplierPerSession + 1) + appInitialStake := cosmosmath.NewInt(maxClaimableAmountPerSupplier*sessionkeeper.NumSupplierPerSession + 1) // Increase the number of relay such that the supplier did "free work" and would // be able to claim more than the max claimable amount. numRelays *= 5 @@ -201,10 +201,10 @@ func TestProcessTokenLogicModules_TLMBurnEqualsMint_Valid_SupplierExceedsMaxClai require.NoError(t, err) // TODO_TECHDEBT: Setting inflation to zero so we are testing the BurnEqualsMint logic exclusively. // Once it is a governance param, update it using the keeper above. - prevInflationValue := tokenomicskeeper.MintPerClaimedTokenGlobalInflation - tokenomicskeeper.MintPerClaimedTokenGlobalInflation = 0 + prevInflationValue := tokenomicskeeper.GlobalInflationPerClaim + tokenomicskeeper.GlobalInflationPerClaim = 0 t.Cleanup(func() { - tokenomicskeeper.MintPerClaimedTokenGlobalInflation = prevInflationValue + tokenomicskeeper.GlobalInflationPerClaim = prevInflationValue }) // Add a new application with non-zero app stake end balance to assert against. @@ -257,7 +257,7 @@ func TestProcessTokenLogicModules_TLMBurnEqualsMint_Valid_SupplierExceedsMaxClai require.EqualValues(t, appStartBalance, appEndBalance) // Determine the expected app end stake amount and the expected app burn - appBurn := math.NewInt(maxClaimableAmountPerSupplier) + appBurn := cosmosmath.NewInt(maxClaimableAmountPerSupplier) appBurnCoin := sdk.NewCoin(volatile.DenomuPOKT, appBurn) expectedAppEndStakeAmount := appInitialStake.Sub(appBurn) @@ -314,8 +314,8 @@ func TestProcessTokenLogicModules_TLMBurnEqualsMint_Valid_SupplierExceedsMaxClai func TestProcessTokenLogicModules_TLMGlobalMint_Valid_MintDistributionCorrect(t *testing.T) { // Test Parameters - appInitialStake := apptypes.DefaultMinStake.Amount.Mul(math.NewInt(2)) - supplierInitialStake := math.NewInt(1000000) + appInitialStake := apptypes.DefaultMinStake.Amount.Mul(cosmosmath.NewInt(2)) + supplierInitialStake := cosmosmath.NewInt(1000000) supplierRevShareRatios := []float32{12.5, 37.5, 50} globalComputeUnitsToTokensMultiplier := uint64(1) serviceComputeUnitsPerRelay := uint64(1) @@ -399,12 +399,12 @@ func TestProcessTokenLogicModules_TLMGlobalMint_Valid_MintDistributionCorrect(t } // Compute mint per actor - numTokensMinted := numTokensClaimed * tokenomicskeeper.MintPerClaimedTokenGlobalInflation - numTokensMintedInt := math.NewIntFromUint64(uint64(numTokensMinted)) - daoMint := math.NewInt(int64(numTokensMinted * tokenomicskeeper.MintAllocationDAO)) - propMint := math.NewInt(int64(numTokensMinted * tokenomicskeeper.MintAllocationProposer)) - serviceOwnerMint := math.NewInt(int64(numTokensMinted * tokenomicskeeper.MintAllocationSourceOwner)) - appMint := math.NewInt(int64(numTokensMinted * tokenomicskeeper.MintAllocationApplication)) + numTokensMinted := numTokensClaimed * tokenomicskeeper.GlobalInflationPerClaim + numTokensMintedInt := cosmosmath.NewIntFromUint64(uint64(numTokensMinted)) + daoMint := cosmosmath.NewInt(int64(numTokensMinted * tokenomicskeeper.MintAllocationDAO)) + propMint := cosmosmath.NewInt(int64(numTokensMinted * tokenomicskeeper.MintAllocationProposer)) + serviceOwnerMint := cosmosmath.NewInt(int64(numTokensMinted * tokenomicskeeper.MintAllocationSourceOwner)) + appMint := cosmosmath.NewInt(int64(numTokensMinted * tokenomicskeeper.MintAllocationApplication)) supplierMint := float32(numTokensMinted * tokenomicskeeper.MintAllocationSupplier) // Ensure the balance was increase be the appropriate amount @@ -418,7 +418,7 @@ func TestProcessTokenLogicModules_TLMGlobalMint_Valid_MintDistributionCorrect(t balanceAfter := supplierShareholderBalancesAfter[addr].Amount.Int64() mintShare := int64(supplierMint * revShare.RevSharePercentage / 100) rewardShare := int64(float32(numTokensClaimed) * revShare.RevSharePercentage / 100) - balanceIncrease := math.NewInt(mintShare + rewardShare) + balanceIncrease := cosmosmath.NewInt(mintShare + rewardShare) expectedBalanceAfter := balanceBefore.Amount.Add(balanceIncrease).Int64() // TODO_MAINNET: Remove the InDelta check and use the exact amount once the floating point arithmetic is fixed acceptableRoundingDelta := tokenomicskeeper.MintDistributionAllowableTolerancePercent * float64(balanceAfter) @@ -429,7 +429,7 @@ func TestProcessTokenLogicModules_TLMGlobalMint_Valid_MintDistributionCorrect(t require.True(t, appFound) appStakeAfter := foundApp.GetStake().Amount - numTokensClaimedInt := math.NewIntFromUint64(uint64(numTokensClaimed)) + numTokensClaimedInt := cosmosmath.NewIntFromUint64(uint64(numTokensClaimed)) require.Equal(t, appInitialStake.Sub(numTokensMintedInt).Sub(numTokensClaimedInt), appStakeAfter) } @@ -452,7 +452,7 @@ func TestProcessTokenLogicModules_AppNotFound(t *testing.T) { } // Process the token logic modules - err := keeper.ProcessTokenLogicModules(ctx, &claim, uPOKTCoin(math2.MaxInt)) + err := keeper.ProcessTokenLogicModules(ctx, &claim, uPOKTCoin(math.MaxInt)) require.Error(t, err) require.ErrorIs(t, err, tokenomicstypes.ErrTokenomicsApplicationNotFound) } @@ -475,7 +475,7 @@ func TestProcessTokenLogicModules_ServiceNotFound(t *testing.T) { } // Execute test function - err := keeper.ProcessTokenLogicModules(ctx, &claim, uPOKTCoin(math2.MaxInt)) + err := keeper.ProcessTokenLogicModules(ctx, &claim, uPOKTCoin(math.MaxInt)) require.Error(t, err) require.ErrorIs(t, err, tokenomicstypes.ErrTokenomicsServiceNotFound) @@ -545,7 +545,7 @@ func TestProcessTokenLogicModules_InvalidRoot(t *testing.T) { claim.RootHash = smt.MerkleRoot(test.root[:]) // Execute test function - err := keeper.ProcessTokenLogicModules(ctx, &claim, uPOKTCoin(math2.MaxInt)) + err := keeper.ProcessTokenLogicModules(ctx, &claim, uPOKTCoin(math.MaxInt)) // Assert the error if test.errExpected { @@ -635,7 +635,7 @@ func TestProcessTokenLogicModules_InvalidClaim(t *testing.T) { err = fmt.Errorf("panic occurred: %v", r) } }() - return keeper.ProcessTokenLogicModules(ctx, test.claim, uPOKTCoin(math2.MaxInt)) + return keeper.ProcessTokenLogicModules(ctx, test.claim, uPOKTCoin(math.MaxInt)) }() // Assert the error @@ -649,6 +649,18 @@ func TestProcessTokenLogicModules_InvalidClaim(t *testing.T) { } } +func TestProcessTokenLogicModules_AppStakeMissingGlobalInflationAmount(t *testing.T) { + t.Skip("TODO: Test application stake that does not cover the global inflation amount") +} + +func TestProcessTokenLogicModules_ZeroAppStakeShareDueToPrecisionLoss(t *testing.T) { + t.Skip("TODO: Test application stake that is low enough to have a zero share due to precision loss") +} + +func TestProcessTokenLogicModules_AppStakeGoesBelowMinStake(t *testing.T) { + t.Skip("TODO: Test application stake that goes min stake") +} + // prepareTestClaim uses the given number of relays and compute unit per relay in the // service provided to set up the test claim correctly. func prepareTestClaim( From f304c879eed244b60b08d00d49c13735a8be738a Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Tue, 29 Oct 2024 19:43:26 +0100 Subject: [PATCH 34/53] feat: Add overservicing allowance --- api/poktroll/application/types.pulsar.go | 14 ++++++-------- config.yml | 6 +++--- pkg/relayer/proxy/relay_meter.go | 6 +++--- x/application/types/types.pb.go | 14 ++++++-------- 4 files changed, 18 insertions(+), 22 deletions(-) diff --git a/api/poktroll/application/types.pulsar.go b/api/poktroll/application/types.pulsar.go index 4a7751438..d1f8f492f 100644 --- a/api/poktroll/application/types.pulsar.go +++ b/api/poktroll/application/types.pulsar.go @@ -2190,14 +2190,12 @@ type Application struct { Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` // The Bech32 address of the application. Stake *v1beta1.Coin `protobuf:"bytes,2,opt,name=stake,proto3" json:"stake,omitempty"` // The total amount of uPOKT the application has staked - // As per this discussion: - // https://github.com/pokt-network/poktroll/pull/750#discussion_r1735025033 - // The number of service_configs is limited to 1 per service. - // This is to ensure that an application could not over service by making multiple - // claims settelments compete to burn the same stake. - // A slice of service_configs is still maintained to allow for future multi-service - // capabilities to be added, such as off-chain application stake tracking by suppliers: - // https://www.notion.so/buildwithgrove/Off-chain-Application-Stake-Tracking-6a8bebb107db4f7f9dc62cbe7ba555f7 + // CRITICAL_DEV_NOTE: The number of service_configs must be EXACTLY ONE. + // This prevents applications from over-servicing. + // The field is kept repeated (a list) for both legacy and future logic reaosns. + // References: + // - https://github.com/pokt-network/poktroll/pull/750#discussion_r1735025033 + // - https://www.notion.so/buildwithgrove/Off-chain-Application-Stake-Tracking-6a8bebb107db4f7f9dc62cbe7ba555f7 ServiceConfigs []*shared.ApplicationServiceConfig `protobuf:"bytes,3,rep,name=service_configs,json=serviceConfigs,proto3" json:"service_configs,omitempty"` // The list of services this appliccation is configured to request service for // TODO_BETA: Rename `delegatee_gateway_addresses` to `gateway_addresses_delegated_to`. // Ensure to rename all relevant configs, comments, variables, function names, etc as well. diff --git a/config.yml b/config.yml index 942614aca..6b6315465 100644 --- a/config.yml +++ b/config.yml @@ -139,13 +139,13 @@ genesis: denom: upokt bank: supply: - - amount: "1003000204" + - amount: "1102000204" denom: upokt balances: # Application module - address: pokt1rl3gjgzexmplmds3tq3r3yk84zlwdl6djzgsvm coins: - - amount: "1000068" # Equals to the total of all app stakes below + - amount: "100000068" # Equals to the total of all app stakes below denom: upokt # Supplier module - address: pokt1j40dzzmn6cn9kxku7a5tjnud6hv37vesr5ccaa @@ -252,7 +252,7 @@ genesis: serviceList: - id: anvil name: "anvil" - compute_units_per_relay: 1 + compute_units_per_relay: 100 owner_address: pokt1cwnu460557x0z78jv3hhc7356hhkrgc86c87q5 - id: ollama name: "ollama" diff --git a/pkg/relayer/proxy/relay_meter.go b/pkg/relayer/proxy/relay_meter.go index 8c4491991..1cc9d0575 100644 --- a/pkg/relayer/proxy/relay_meter.go +++ b/pkg/relayer/proxy/relay_meter.go @@ -59,7 +59,7 @@ type ProxyRelayMeter struct { func NewRelayMeter(deps depinject.Config) (relayer.RelayMeter, error) { rm := &ProxyRelayMeter{ apps: make(map[string]*appRelayMeter), - overServicingAllowance: 0, + overServicingAllowance: 1000000, } if err := depinject.Inject( @@ -151,8 +151,8 @@ func (rmtr *ProxyRelayMeter) ClaimRelayPrice(ctx context.Context, reqMeta servic // If the consumed amount exceeds the max amount, return a rate limit error. if appMetrics.maxAmount.IsLT(newConsumedAmount) { return ErrRelayerProxyRateLimited.Wrapf( - "application has been rate limited, stake share: %s, expecting: %s", - appMetrics.consumedAmount.String(), + "application has been rate limited, stake needed: %s, has: %s, ", + newConsumedAmount.String(), appMetrics.maxAmount.String(), ) } diff --git a/x/application/types/types.pb.go b/x/application/types/types.pb.go index 9e5b8ff6c..32bc0cc13 100644 --- a/x/application/types/types.pb.go +++ b/x/application/types/types.pb.go @@ -31,14 +31,12 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type Application 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"` - // As per this discussion: - // https://github.com/pokt-network/poktroll/pull/750#discussion_r1735025033 - // The number of service_configs is limited to 1 per service. - // This is to ensure that an application could not over service by making multiple - // claims settelments compete to burn the same stake. - // A slice of service_configs is still maintained to allow for future multi-service - // capabilities to be added, such as off-chain application stake tracking by suppliers: - // https://www.notion.so/buildwithgrove/Off-chain-Application-Stake-Tracking-6a8bebb107db4f7f9dc62cbe7ba555f7 + // CRITICAL_DEV_NOTE: The number of service_configs must be EXACTLY ONE. + // This prevents applications from over-servicing. + // The field is kept repeated (a list) for both legacy and future logic reaosns. + // References: + // - https://github.com/pokt-network/poktroll/pull/750#discussion_r1735025033 + // - https://www.notion.so/buildwithgrove/Off-chain-Application-Stake-Tracking-6a8bebb107db4f7f9dc62cbe7ba555f7 ServiceConfigs []*types1.ApplicationServiceConfig `protobuf:"bytes,3,rep,name=service_configs,json=serviceConfigs,proto3" json:"service_configs,omitempty"` // TODO_BETA: Rename `delegatee_gateway_addresses` to `gateway_addresses_delegated_to`. // Ensure to rename all relevant configs, comments, variables, function names, etc as well. From 2ee84487cfd827759a9350c050774086bb6a10cb Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Tue, 29 Oct 2024 19:49:17 +0100 Subject: [PATCH 35/53] fix: Merge error --- x/tokenomics/keeper/token_logic_modules.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/tokenomics/keeper/token_logic_modules.go b/x/tokenomics/keeper/token_logic_modules.go index 1729d2390..06c9d047d 100644 --- a/x/tokenomics/keeper/token_logic_modules.go +++ b/x/tokenomics/keeper/token_logic_modules.go @@ -703,7 +703,7 @@ func (k Keeper) ensureClaimAmountLimits( maxClaimableAmt := appStake.Amount. Quo(math.NewInt(sessionkeeper.NumSupplierPerSession)). Quo(math.NewInt(pendingSessions)) - maxClaimSettlementAmt := stakeToMaxSettlementAmount(maxClaimableAmt) + maxClaimSettlementAmt := stakeShareToMaxSettlementAmount(maxClaimableAmt) // Check if the claimable amount is capped by the max claimable amount. // As per the Relay Mining paper, the Supplier claim MUST NO exceed the application's From 6170a45289d2e927642199a20481e12efc64cc4e Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Wed, 30 Oct 2024 18:22:47 +0100 Subject: [PATCH 36/53] improve: Add per relayer app meter --- config.yml | 2 +- pkg/relayer/interface.go | 14 +- pkg/relayer/miner/miner.go | 6 +- pkg/relayer/miner/miner_test.go | 29 ++-- pkg/relayer/proxy/errors.go | 4 +- pkg/relayer/proxy/proxy.go | 6 +- pkg/relayer/proxy/relay_meter.go | 252 +++++++++++++++++++------------ pkg/relayer/proxy/synchronous.go | 6 +- 8 files changed, 188 insertions(+), 131 deletions(-) diff --git a/config.yml b/config.yml index 6b6315465..6c8534d9d 100644 --- a/config.yml +++ b/config.yml @@ -252,7 +252,7 @@ genesis: serviceList: - id: anvil name: "anvil" - compute_units_per_relay: 100 + compute_units_per_relay: 1 owner_address: pokt1cwnu460557x0z78jv3hhc7356hhkrgc86c87q5 - id: ollama name: "ollama" diff --git a/pkg/relayer/interface.go b/pkg/relayer/interface.go index b40432275..b8723ab70 100644 --- a/pkg/relayer/interface.go +++ b/pkg/relayer/interface.go @@ -1,6 +1,7 @@ //go:generate mockgen -destination=../../testutil/mockrelayer/relayer_proxy_mock.go -package=mockrelayer . RelayerProxy //go:generate mockgen -destination=../../testutil/mockrelayer/miner_mock.go -package=mockrelayer . Miner //go:generate mockgen -destination=../../testutil/mockrelayer/relayer_sessions_manager_mock.go -package=mockrelayer . RelayerSessionsManager +//go:generate mockgen -destination=../../testutil/mockrelayer/relay_meter_mock.go -package=mockrelayer . RelayMeter package relayer @@ -167,12 +168,13 @@ type SessionTree interface { type RelayMeter interface { // Start starts the relay meter. Start(ctx context.Context) error - // ClaimRelayPrice claims the relay price for the given relay request. - // The relay price is claimed optimistically, assuming that the relay will be volume / reward - // applicable and the relay meter will be updated accordingly. - ClaimRelayPrice(ctx context.Context, relayRequestMeta servicetypes.RelayRequestMetadata) error - // UnclaimRelayPrice unlocks the relay price for the given relay request. + // AccumulateRelayReward accumulates the relay reward for the given relay request. + // The relay cost is added optimistically, assuming that the relay will be volume / reward + // applicable and the relay meter would remain up to date. + AccumulateRelayReward(ctx context.Context, relayRequestMeta servicetypes.RelayRequestMetadata) error + // SetNonApplicableRelayReward updates the relay meter to make the relay reward for + // the given relay request as non-applicable. // This is used when the relay is not volume / reward applicable but was optimistically // accounted for in the relay meter. - UnclaimRelayPrice(ctx context.Context, relayRequestMeta servicetypes.RelayRequestMetadata) error + SetNonApplicableRelayReward(ctx context.Context, relayRequestMeta servicetypes.RelayRequestMetadata) error } diff --git a/pkg/relayer/miner/miner.go b/pkg/relayer/miner/miner.go index c62b81f7e..4c309ff2f 100644 --- a/pkg/relayer/miner/miner.go +++ b/pkg/relayer/miner/miner.go @@ -89,7 +89,7 @@ func (mnr *miner) mapMineRelay( ) (_ either.Either[*relayer.MinedRelay], skip bool) { relayBz, err := relay.Marshal() if err != nil { - meteringError := mnr.relayMeter.UnclaimRelayPrice(ctx, relay.GetReq().GetMeta()) + meteringError := mnr.relayMeter.SetNonApplicableRelayReward(ctx, relay.GetReq().GetMeta()) if meteringError != nil { return either.Error[*relayer.MinedRelay](fmt.Errorf("failed to unclaim relay price: %w", meteringError)), false } @@ -100,7 +100,7 @@ func (mnr *miner) mapMineRelay( relayDifficultyTargetHash, err := mnr.getServiceRelayDifficultyTargetHash(ctx, relay.Req) if err != nil { - meteringError := mnr.relayMeter.UnclaimRelayPrice(ctx, relay.GetReq().GetMeta()) + meteringError := mnr.relayMeter.SetNonApplicableRelayReward(ctx, relay.GetReq().GetMeta()) if meteringError != nil { return either.Error[*relayer.MinedRelay](fmt.Errorf("failed to unclaim relay price: %w", meteringError)), false } @@ -109,7 +109,7 @@ func (mnr *miner) mapMineRelay( // The relay IS NOT volume / reward applicable if !protocol.IsRelayVolumeApplicable(relayHash, relayDifficultyTargetHash) { - meteringError := mnr.relayMeter.UnclaimRelayPrice(ctx, relay.GetReq().GetMeta()) + meteringError := mnr.relayMeter.SetNonApplicableRelayReward(ctx, relay.GetReq().GetMeta()) if meteringError != nil { return either.Error[*relayer.MinedRelay](fmt.Errorf("failed to unclaim relay price: %w", meteringError)), false } diff --git a/pkg/relayer/miner/miner_test.go b/pkg/relayer/miner/miner_test.go index caf1375cc..e3881309c 100644 --- a/pkg/relayer/miner/miner_test.go +++ b/pkg/relayer/miner/miner_test.go @@ -13,12 +13,14 @@ import ( "time" "cosmossdk.io/depinject" + gomock "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" "github.com/pokt-network/poktroll/pkg/crypto/protocol" "github.com/pokt-network/poktroll/pkg/observable/channel" "github.com/pokt-network/poktroll/pkg/relayer" "github.com/pokt-network/poktroll/pkg/relayer/miner" + "github.com/pokt-network/poktroll/testutil/mockrelayer" "github.com/pokt-network/poktroll/testutil/testclient/testqueryclients" servicetypes "github.com/pokt-network/poktroll/x/service/types" ) @@ -28,10 +30,7 @@ import ( // The fixtures generated by pkg/relayer/miner/gen/gen_fixtures.go use a const with the same name and value. const testSvcId = "svc1" -var ( - testRelayMiningTargetHash, _ = hex.DecodeString("0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff") - _ relayer.RelayMeter = (*testRelayMeter)(nil) -) +var testRelayMiningTargetHash, _ = hex.DecodeString("0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff") // TestMiner_MinedRelays constructs an observable of mined relays, through which // it pipes pre-mined relay fixtures. It asserts that the observable only emits @@ -51,7 +50,7 @@ func TestMiner_MinedRelays(t *testing.T) { testqueryclients.SetServiceRelayDifficultyTargetHash(t, testSvcId, testRelayMiningTargetHash) serviceQueryClientMock := testqueryclients.NewTestServiceQueryClient(t) - var testRelayMeter relayer.RelayMeter = &testRelayMeter{} + testRelayMeter := mockRelayMeter(t) deps := depinject.Supply(serviceQueryClientMock, testRelayMeter) mnr, err := miner.NewMiner(deps) @@ -159,18 +158,16 @@ func unmarshalHexMinedRelay( } } -// testRelayMeter is a dummy implementation of the RelayMeter interface. -// It is used to supply the miner with a relay meter but without any side effects. -type testRelayMeter struct{} +// mockRelayMeter returns a mock RelayMeter that is used by the relay miner to claim and unclaim relays. +func mockRelayMeter(t *testing.T) relayer.RelayMeter { + t.Helper() -func (trm *testRelayMeter) Start(_ context.Context) error { - return nil -} + ctrl := gomock.NewController(t) + relayMeter := mockrelayer.NewMockRelayMeter(ctrl) -func (trm *testRelayMeter) UnclaimRelayPrice(ctx context.Context, meta servicetypes.RelayRequestMetadata) error { - return nil -} + relayMeter.EXPECT().Start(gomock.Any()).Return(nil).AnyTimes() + relayMeter.EXPECT().AccumulateRelayReward(gomock.Any(), gomock.Any()).Return(nil).AnyTimes() + relayMeter.EXPECT().SetNonApplicableRelayReward(gomock.Any(), gomock.Any()).Return(nil).AnyTimes() -func (trm *testRelayMeter) ClaimRelayPrice(ctx context.Context, meta servicetypes.RelayRequestMetadata) error { - return nil + return relayMeter } diff --git a/pkg/relayer/proxy/errors.go b/pkg/relayer/proxy/errors.go index 429ba9483..b8c9d86b2 100644 --- a/pkg/relayer/proxy/errors.go +++ b/pkg/relayer/proxy/errors.go @@ -17,6 +17,6 @@ var ( ErrRelayerProxyUnsupportedTransportType = sdkerrors.Register(codespace, 9, "unsupported proxy transport type") ErrRelayerProxyInternalError = sdkerrors.Register(codespace, 10, "internal error") ErrRelayerProxyMissingSupplierOperatorAddress = sdkerrors.Register(codespace, 11, "supplier operator address is missing") - ErrRelayerProxyUnknownApplication = sdkerrors.Register(codespace, 12, "unknown application") - ErrRelayerProxyRateLimited = sdkerrors.Register(codespace, 13, "rate limited") + ErrRelayerProxyUnknownApplication = sdkerrors.Register(codespace, 12, "relayer proxy encountered unknown application") + ErrRelayerProxyRateLimited = sdkerrors.Register(codespace, 13, "offchain rate limit hit by relayer proxy") ) diff --git a/pkg/relayer/proxy/proxy.go b/pkg/relayer/proxy/proxy.go index cab9aa4ca..e14c68aad 100644 --- a/pkg/relayer/proxy/proxy.go +++ b/pkg/relayer/proxy/proxy.go @@ -79,7 +79,7 @@ type relayerProxy struct { // 2. Relay signing to resolve which keyring key name to use for signing; OperatorAddressToSigningKeyNameMap map[string]string - // relayMeter is a struct that keeps track of the claimed relay prices for each application. + // relayMeter is a struct that keeps track of the claimed relay rewards for each application. // It also configures over servicing allowance. relayMeter relayer.RelayMeter } @@ -154,7 +154,9 @@ func (rp *relayerProxy) Start(ctx context.Context) error { // Start the ring cache. rp.ringCache.Start(ctx) - // Start the relay meter. + // Start the relay meter by subscribing to the on-chain events. + // This function is non-blocking and the subscription cancellation is handled + // by the context passed to the Start method. if err := rp.relayMeter.Start(ctx); err != nil { return err } diff --git a/pkg/relayer/proxy/relay_meter.go b/pkg/relayer/proxy/relay_meter.go index 1cc9d0575..1b10264d7 100644 --- a/pkg/relayer/proxy/relay_meter.go +++ b/pkg/relayer/proxy/relay_meter.go @@ -22,6 +22,7 @@ import ( apptypes "github.com/pokt-network/poktroll/x/application/types" servicetypes "github.com/pokt-network/poktroll/x/service/types" sessionkeeper "github.com/pokt-network/poktroll/x/session/keeper" + sessiontypes "github.com/pokt-network/poktroll/x/session/types" sharedtypes "github.com/pokt-network/poktroll/x/shared/types" ) @@ -30,36 +31,57 @@ var _ relayer.RelayMeter = (*ProxyRelayMeter)(nil) // appRelayMeter is the relay meter's internal representation of an application's // max and consumed stake. type appRelayMeter struct { - maxAmount cosmostypes.Coin - consumedAmount cosmostypes.Coin - app apptypes.Application + // The onchain application the relay meter is for. + app apptypes.Application + // The maximum uPOKT an application can pay this relayer for a given session. + maxCoin cosmostypes.Coin + // The amount of uPOKT a specific application has consumed from this relayer in the given session. + consumedCoin cosmostypes.Coin + // The current sessionHeader the application is metered in. + sessionHeader *sessiontypes.SessionHeader + + // sharedParams, service and serviceRelayDifficulty are used to calculate the relay cost + // that increments the consumedAmount. + // They are cached at each session to avoid querying the blockchain for each relay. + // TODO_TECHDEBT(#543): Remove once the query clients start handling caching and invalidation. + sharedParams *sharedtypes.Params + service *sharedtypes.Service + serviceRelayDifficulty servicetypes.RelayMiningDifficulty } -// ProxyRelayMeter is the off-chain Supplier's rate limiter. -// It ensures that no application is over-serviced by the Supplier by maintaining -// the max amount of stake the supplier can consume per session and the amount of -// stake consumed by mined relays. +// ProxyRelayMeter is the offchain Supplier's rate limiter. +// It ensures that no Application is over-serviced by the Supplier per session. +// This is done by maintaining the max amount of stake the supplier can consume +// per session and the amount of stake consumed by mined relays. type ProxyRelayMeter struct { - // The known applications that have their stakes metered. - apps map[string]*appRelayMeter - // overServicingAllowance adjusts the max amount to allow for controlled over-servicing - // or, if negative, to create a stake buffer. - // TODO_TECHDEBT(@red-0ne): Expose overServicingAllowance as a configuration parameter. - overServicingAllowance int64 + // supplierToAppMetricsMap is a map of supplier addresses to application address + // to the application's relay meter. + // Only known applications (i.e. have already requested relaying) that have their stakes metered. + // This map gets reset every new session in order to meter new applications, since the old + // ones might have another Supplier set for their sessions. + supplierToAppMetricsMap map[string]map[string]*appRelayMeter + // overServicingAllowanceCoins allows Suppliers to overservice applications. + // This entails providing a free service, to mine for relays, that they will not be paid for. + // This is a common by some to build goodwill and receive a higher quality-of-service rating. + // If negative, allow infinite overservicing. + // TODO_MAINNET(@red-0ne): Expose overServicingAllowanceCoins as a configuration parameter. + overServicingAllowanceCoins cosmostypes.Coin + + // relayMeterMu ensures that relay meter operations are thread-safe. + relayMeterMu sync.Mutex applicationQuerier client.ApplicationQueryClient serviceQuerier client.ServiceQueryClient sharedQuerier client.SharedQueryClient eventsQueryClient client.EventsQueryClient blockQuerier client.BlockClient - - relayMeterMu sync.Mutex } func NewRelayMeter(deps depinject.Config) (relayer.RelayMeter, error) { + overservicingAllowanceCoins := cosmostypes.NewInt64Coin(volatile.DenomuPOKT, 1000000) rm := &ProxyRelayMeter{ - apps: make(map[string]*appRelayMeter), - overServicingAllowance: 1000000, + supplierToAppMetricsMap: make(map[string]map[string]*appRelayMeter), + overServicingAllowanceCoins: overservicingAllowanceCoins, } if err := depinject.Inject( @@ -78,12 +100,20 @@ func NewRelayMeter(deps depinject.Config) (relayer.RelayMeter, error) { // Start starts the relay meter by observing application staked events and new sessions. func (rmtr *ProxyRelayMeter) Start(ctx context.Context) error { + // Listen to transaction events to filter application staked events. + // TODO_BETA(@red-0ne): refactor this listener to be shared across all query clients + // and remove the need to listen to events in the relay meter. eventsObs, err := rmtr.eventsQueryClient.EventsBytes(ctx, "tm.event = 'Tx'") if err != nil { return err } // Listen to application staked events and update known application stakes. + // Since an applications might upstake (not downstake) during a session, this + // stake increase is guaranteed to be available at settlement so it must be updated. + // This also allows applications to adjust their stake mid-session and avoid + // being rate limited or need to wait for the next session. + // Stake updates take effect immediately. appStakedEvents := filterTypedEvents[*apptypes.EventApplicationStaked](ctx, eventsObs, nil) channel.ForEach(ctx, appStakedEvents, rmtr.forEachEventApplicationStakedFn) @@ -94,116 +124,73 @@ func (rmtr *ProxyRelayMeter) Start(ctx context.Context) error { return nil } -// ClaimRelayPrice claims the relay price for the given relay request metadata. -// It deducts the relay cost from the application's stake and returns an error if -// the application has been rate limited. -func (rmtr *ProxyRelayMeter) ClaimRelayPrice(ctx context.Context, reqMeta servicetypes.RelayRequestMetadata) error { +// AccumulateRelayReward accumulates the relay reward for the given relay request. +// The relay reward is added optimistically, assuming that the relay will be volume / reward +// applicable and the relay meter would remain up to date. +func (rmtr *ProxyRelayMeter) AccumulateRelayReward(ctx context.Context, reqMeta servicetypes.RelayRequestMetadata) error { rmtr.relayMeterMu.Lock() defer rmtr.relayMeterMu.Unlock() - sharedParams, err := rmtr.sharedQuerier.GetParams(ctx) - if err != nil { - return err - } - - service, err := rmtr.serviceQuerier.GetService(ctx, reqMeta.SessionHeader.ServiceId) + // Create a metric if it does not exist. + appMetrics, err := rmtr.ensureRequestAppMetrics(ctx, reqMeta, true) if err != nil { return err } - serviceRelayDifficulty, err := rmtr.serviceQuerier.GetServiceRelayDifficulty(ctx, service.Id) - if err != nil { - return err - } - - appAddress := reqMeta.SessionHeader.ApplicationAddress - - appMetrics, ok := rmtr.apps[appAddress] - // If the application is seen for the first time in this session, calculate the - // max amount of stake the application can consume. - if !ok { - var app apptypes.Application - app, err = rmtr.applicationQuerier.GetApplication(ctx, appAddress) - if err != nil { - return err - } - - // calculate the max amount of stake the application can consume in the current session. - appStakeShare := getApplicationStakeShare(app.Stake, sharedParams) - maxAmount := appStakeShare.AddAmount(math.NewInt(rmtr.overServicingAllowance)) - appMetrics = &appRelayMeter{ - consumedAmount: cosmostypes.NewInt64Coin(volatile.DenomuPOKT, 0), - maxAmount: maxAmount, - app: app, - } - rmtr.apps[appAddress] = appMetrics - } - // Get the cost of the relay based on the service and shared parameters. - relayCost, err := getMinedRelayCost(sharedParams, &service, serviceRelayDifficulty) + relayCostCoin, err := getMinedRelayCostCoin( + appMetrics.sharedParams, + appMetrics.service, + appMetrics.serviceRelayDifficulty, + ) if err != nil { return err } // Increase the consumed stake amount by relay cost. - newConsumedAmount := appMetrics.consumedAmount.Add(relayCost) + newConsumedCoin := appMetrics.consumedCoin.Add(relayCostCoin) // If the consumed amount exceeds the max amount, return a rate limit error. - if appMetrics.maxAmount.IsLT(newConsumedAmount) { + overServicingLimited := !rmtr.overServicingAllowanceCoins.IsNegative() + if overServicingLimited && appMetrics.maxCoin.IsLT(newConsumedCoin) { return ErrRelayerProxyRateLimited.Wrapf( "application has been rate limited, stake needed: %s, has: %s, ", - newConsumedAmount.String(), - appMetrics.maxAmount.String(), + newConsumedCoin.String(), + appMetrics.maxCoin.String(), ) } - appMetrics.consumedAmount = newConsumedAmount + appMetrics.consumedCoin = newConsumedCoin return nil } -// UnclaimRelayPrice releases the claimed relay price back to the application's stake. -// This is because ClaimRelayPrice is optimistic and has to check against the application -// stake before serving the relay or check if it is reward / volume applicable. -// This method is called when the relay is not mined. -func (rmtr *ProxyRelayMeter) UnclaimRelayPrice(ctx context.Context, reqMeta servicetypes.RelayRequestMetadata) error { +// SetNonApplicableRelayReward updates the relay meter to make the relay reward for +// the given relay request as non-applicable. +// This is used when the relay is not volume / reward applicable but was optimistically +// accounted for in the relay meter. +func (rmtr *ProxyRelayMeter) SetNonApplicableRelayReward(ctx context.Context, reqMeta servicetypes.RelayRequestMetadata) error { rmtr.relayMeterMu.Lock() defer rmtr.relayMeterMu.Unlock() - appAddress := reqMeta.SessionHeader.ApplicationAddress - - // Do not consider applications that have not been seen in this session. - appMetrics, ok := rmtr.apps[appAddress] - if !ok { - return ErrRelayerProxyUnknownApplication - } - - serviceId := reqMeta.SessionHeader.ServiceId - - sharedParams, err := rmtr.sharedQuerier.GetParams(ctx) - if err != nil { - return err - } - - service, err := rmtr.serviceQuerier.GetService(ctx, serviceId) - if err != nil { - return err - } - - difficulty, err := rmtr.serviceQuerier.GetServiceRelayDifficulty(ctx, serviceId) + appMetrics, err := rmtr.ensureRequestAppMetrics(ctx, reqMeta, false) if err != nil { return err } // Get the cost of the relay based on the service and shared parameters. - relayCost, err := getMinedRelayCost(sharedParams, &service, difficulty) + relayCost, err := getMinedRelayCostCoin( + appMetrics.sharedParams, + appMetrics.service, + appMetrics.serviceRelayDifficulty, + ) if err != nil { return err } // Decrease the consumed stake amount by relay cost. - newConsumedAmount := appMetrics.consumedAmount.Sub(relayCost) + newConsumedAmount := appMetrics.consumedCoin.Sub(relayCost) - appMetrics.consumedAmount = newConsumedAmount + appMetrics.consumedCoin = newConsumedAmount return nil } @@ -220,24 +207,93 @@ func (rmtr *ProxyRelayMeter) forEachNewBlockFn(ctx context.Context, block client } numBlocksPerSession := int64(sharedParams.GetNumBlocksPerSession()) + // If the block observed is the last of the session, reset the relay meter's + // to process next session's application requests. if block.Height()%numBlocksPerSession == 0 { - rmtr.apps = make(map[string]*appRelayMeter) + rmtr.supplierToAppMetricsMap = make(map[string]map[string]*appRelayMeter) } } // forEachEventApplicationStakedFn is a callback function that is called every time -// an application staked event is observed. It updates the relay meter's known -// application stakes. +// an application staked event is observed. It updates the relay meter known applications. func (rmtr *ProxyRelayMeter) forEachEventApplicationStakedFn(ctx context.Context, event *apptypes.EventApplicationStaked) { rmtr.relayMeterMu.Lock() defer rmtr.relayMeterMu.Unlock() app := event.GetApplication() - if _, ok := rmtr.apps[app.GetAddress()]; !ok { - return + + // Since lean clients are supported, multiple suppliers might share the same RelayMiner. + // Loop over all the suppliers that have metered the application and update their + // max amount of stake they can consume. + for supplierAddress := range rmtr.supplierToAppMetricsMap { + appMetrics, ok := rmtr.supplierToAppMetricsMap[supplierAddress][app.GetAddress()] + if !ok { + continue + } + appMetrics.app.Stake = app.GetStake() + appStakeShare := getApplicationStakeShare(app.GetStake(), appMetrics.sharedParams) + appMetrics.maxCoin = appStakeShare.Add(rmtr.overServicingAllowanceCoins) + } +} + +func (rmtr *ProxyRelayMeter) ensureRequestAppMetrics(ctx context.Context, reqMeta servicetypes.RelayRequestMetadata, createMetric bool) (*appRelayMeter, error) { + appAddress := reqMeta.GetSessionHeader().GetApplicationAddress() + supplierAddress := reqMeta.GetSupplierOperatorAddress() + + supplierApps, ok := rmtr.supplierToAppMetricsMap[supplierAddress] + if !ok { + rmtr.supplierToAppMetricsMap[supplierAddress] = make(map[string]*appRelayMeter) + supplierApps = rmtr.supplierToAppMetricsMap[supplierAddress] + } + + // Do not consider applications that have not been seen in this session. + appMetrics, ok := supplierApps[appAddress] + + // If the application is seen for the first time in this session, calculate the + // max amount of stake the application can consume. + if !ok { + var app apptypes.Application + app, err := rmtr.applicationQuerier.GetApplication(ctx, appAddress) + if err != nil { + return nil, err + } + + sharedParams, err := rmtr.sharedQuerier.GetParams(ctx) + if err != nil { + return nil, err + } + + service, err := rmtr.serviceQuerier.GetService(ctx, reqMeta.SessionHeader.ServiceId) + if err != nil { + return nil, err + } + + serviceRelayDifficulty, err := rmtr.serviceQuerier.GetServiceRelayDifficulty(ctx, service.Id) + if err != nil { + return nil, err + } + + if !createMetric { + return nil, ErrRelayerProxyUnknownApplication.Wrap("required metric not found") + } + + // calculate the max amount of stake the application can consume in the current session. + appStakeShare := getApplicationStakeShare(app.Stake, sharedParams) + maxAmount := appStakeShare.Add(rmtr.overServicingAllowanceCoins) + appMetrics = &appRelayMeter{ + app: app, + consumedCoin: cosmostypes.NewInt64Coin(volatile.DenomuPOKT, 0), + maxCoin: maxAmount, + sessionHeader: reqMeta.SessionHeader, + sharedParams: sharedParams, + service: &service, + serviceRelayDifficulty: serviceRelayDifficulty, + } + + rmtr.supplierToAppMetricsMap[supplierAddress][appAddress] = appMetrics } - rmtr.apps[app.GetAddress()].app.Stake = app.GetStake() + return appMetrics, nil } // filterTypedEvents filters the provided events bytes for the typed event T. @@ -287,9 +343,9 @@ func filterTypedEvents[T proto.Message]( return eventObs } -// getMinedRelayCost returns the cost of a relay based on the shared parameters and the service. +// getMinedRelayCostCoin returns the cost of a relay based on the shared parameters and the service. // relayCost = CUPR * CUTTM * relayDifficultyMultiplier -func getMinedRelayCost( +func getMinedRelayCostCoin( sharedParams *sharedtypes.Params, service *sharedtypes.Service, relayMiningDifficulty servicetypes.RelayMiningDifficulty, diff --git a/pkg/relayer/proxy/synchronous.go b/pkg/relayer/proxy/synchronous.go index 4e62f1cf5..52b8c8e2a 100644 --- a/pkg/relayer/proxy/synchronous.go +++ b/pkg/relayer/proxy/synchronous.go @@ -48,7 +48,7 @@ type synchronousRPCServer struct { // the servedRelays observable to fan-out notifications to its subscribers. servedRelaysProducer chan<- *types.Relay - // relayMeter is the relay meter that the server uses to meter the relays and claim the relay price. + // relayMeter is the relay meter that the RelayServer uses to meter the relays and claim the relay price. // It is used to ensure that the relays are metered and priced correctly. relayMeter relayer.RelayMeter } @@ -243,11 +243,11 @@ func (sync *synchronousRPCServer) serveHTTP( return nil, err } - // Optimistically claim the relay price before serving the relay. + // Optimistically accumulate the relay reward before actually serving the relay. // The relay price will be deducted from the application's stake before the relay is served. // If the relay comes out to be not reward / volume applicable, the miner will refund the // claimed price back to the application. - if err := sync.relayMeter.ClaimRelayPrice(ctx, relayRequest.Meta); err != nil { + if err := sync.relayMeter.AccumulateRelayReward(ctx, relayRequest.Meta); err != nil { return nil, err } From 2bd72405fa1e95af1ec50169513459bba60bd97d Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Wed, 30 Oct 2024 19:17:12 +0100 Subject: [PATCH 37/53] chore: Address review change requests --- x/tokenomics/keeper/token_logic_modules.go | 14 ++++++++------ x/tokenomics/keeper/token_logic_modules_test.go | 12 ++++++------ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/x/tokenomics/keeper/token_logic_modules.go b/x/tokenomics/keeper/token_logic_modules.go index db3b48dbb..8eca626a9 100644 --- a/x/tokenomics/keeper/token_logic_modules.go +++ b/x/tokenomics/keeper/token_logic_modules.go @@ -525,6 +525,7 @@ func (k Keeper) TokenLogicModuleGlobalMintReimbursementRequest( // This should THEORETICALLY NEVER fall below zero. // `ensureClaimAmountLimits` should have already checked and adjusted the settlement // amount so that the application stake covers the global inflation. + // TODO_POST_MAINNET: Consider removing this since it should never happen just to simplify the code if err != nil { return err } @@ -715,10 +716,10 @@ func (k Keeper) ensureClaimAmountLimits( // and assume maxClaimableAmt will be settled in session 2. // - Guarantee no over-servicing at the cost of higher application stake requirements. maxClaimableAmt := appStake.Amount.Quo(math.NewInt(sessionkeeper.NumSupplierPerSession)) - maxClaimSettlementAmt := stakeShareToMaxSettlementAmount(maxClaimableAmt) + maxClaimSettlementAmt := supplierAppStakeToMaxSettlementAmount(maxClaimableAmt) // Check if the claimable amount is capped by the max claimable amount. - // As per the Relay Mining paper, the Supplier claim MUST NO exceed the application's + // As per the Relay Mining paper, the Supplier claim MUST NOT exceed the application's // allocated stake. If it does, the claim is capped by the application's allocated stake // and the supplier is effectively "overserviced". if minRequiredAppStakeAmt.GT(maxClaimableAmt) { @@ -726,7 +727,7 @@ func (k Keeper) ensureClaimAmountLimits( supplier.GetOperatorAddress(), application.GetAddress(), maxClaimableAmt, claimSettlementCoin.Amount)) minRequiredAppStakeAmt = maxClaimableAmt - maxClaimSettlementAmt = stakeShareToMaxSettlementAmount(minRequiredAppStakeAmt) + maxClaimSettlementAmt = supplierAppStakeToMaxSettlementAmount(minRequiredAppStakeAmt) } // Nominal case: The claimable amount is within the limits set by Relay Mining. @@ -831,14 +832,15 @@ func CalculateGlobalPerClaimMintInflationFromSettlementAmount(settlementCoin sdk return mintAmtCoin, *newMintAmtFloat } -// stakeShareToMaxSettlementAmount calculates the max amount of uPOKT to that the supplier -// can claim based on the stake share and the global inflation allocation percentage. +// supplierAppStakeToMaxSettlementAmount calculates the max amount of uPOKT the supplier +// can claim based on the stake allocated to the supplier and the global inflation +// allocation percentage. // This is the inverse of CalculateGlobalPerClaimMintInflationFromSettlementAmount: // stake = maxSettlementAmt + globalInflationAmt // stake = maxSettlementAmt + (maxSettlementAmt * MintPerClaimedTokenGlobalInflation) // stake = maxSettlementAmt * (1 + MintPerClaimedTokenGlobalInflation) // maxSettlementAmt = stake / (1 + MintPerClaimedTokenGlobalInflation) -func stakeShareToMaxSettlementAmount(stakeShare math.Int) math.Int { +func supplierAppStakeToMaxSettlementAmount(stakeShare math.Int) math.Int { stakeSahreFloat := big.NewFloat(0).SetInt(stakeShare.BigInt()) maxSettlementAmountFloat := big.NewFloat(0).Quo(stakeSahreFloat, big.NewFloat(1+GlobalInflationPerClaim)) diff --git a/x/tokenomics/keeper/token_logic_modules_test.go b/x/tokenomics/keeper/token_logic_modules_test.go index 817442d01..db5aa8320 100644 --- a/x/tokenomics/keeper/token_logic_modules_test.go +++ b/x/tokenomics/keeper/token_logic_modules_test.go @@ -649,16 +649,16 @@ func TestProcessTokenLogicModules_InvalidClaim(t *testing.T) { } } -func TestProcessTokenLogicModules_AppStakeMissingGlobalInflationAmount(t *testing.T) { - t.Skip("TODO: Test application stake that does not cover the global inflation amount") +func TestProcessTokenLogicModules_AppStakeInsufficientToCoverGlobalInflationAmount(t *testing.T) { + t.Skip("TODO_MAINNET(@red-0ne): Test application stake that is insufficient to cover the global inflation amount, for reimbursment and the max claim should scale down proportionally") } -func TestProcessTokenLogicModules_ZeroAppStakeShareDueToPrecisionLoss(t *testing.T) { - t.Skip("TODO: Test application stake that is low enough to have a zero share due to precision loss") +func TestProcessTokenLogicModules_AppStakeTooLowRoundingToZero(t *testing.T) { + t.Skip("TODO_MAINNET(@red-0ne): Test application stake that is too low which results in stake/num_suppliers rounding down to zero") } -func TestProcessTokenLogicModules_AppStakeGoesBelowMinStake(t *testing.T) { - t.Skip("TODO: Test application stake that goes min stake") +func TestProcessTokenLogicModules_AppStakeDropsBelowMinStakeAfterSession(t *testing.T) { + t.Skip("TODO_MAINNET(@red-0ne): Test that application stake being auto-unbonding after the stake drops below the required minimum when settling session accounting") } // prepareTestClaim uses the given number of relays and compute unit per relay in the From ee93efa3b281a35010aeb48b7073cdd246770013 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Wed, 30 Oct 2024 20:23:16 +0100 Subject: [PATCH 38/53] fix: Rename supplier app stake retrieval fn --- pkg/relayer/proxy/relay_meter.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/relayer/proxy/relay_meter.go b/pkg/relayer/proxy/relay_meter.go index 1b10264d7..d1a27cb4c 100644 --- a/pkg/relayer/proxy/relay_meter.go +++ b/pkg/relayer/proxy/relay_meter.go @@ -231,7 +231,7 @@ func (rmtr *ProxyRelayMeter) forEachEventApplicationStakedFn(ctx context.Context continue } appMetrics.app.Stake = app.GetStake() - appStakeShare := getApplicationStakeShare(app.GetStake(), appMetrics.sharedParams) + appStakeShare := getSupplierAppStake(app.GetStake(), appMetrics.sharedParams) appMetrics.maxCoin = appStakeShare.Add(rmtr.overServicingAllowanceCoins) } } @@ -278,8 +278,8 @@ func (rmtr *ProxyRelayMeter) ensureRequestAppMetrics(ctx context.Context, reqMet } // calculate the max amount of stake the application can consume in the current session. - appStakeShare := getApplicationStakeShare(app.Stake, sharedParams) - maxAmount := appStakeShare.Add(rmtr.overServicingAllowanceCoins) + supplierAppStake := getSupplierAppStake(app.Stake, sharedParams) + maxAmount := supplierAppStake.Add(rmtr.overServicingAllowanceCoins) appMetrics = &appRelayMeter{ app: app, consumedCoin: cosmostypes.NewInt64Coin(volatile.DenomuPOKT, 0), @@ -365,7 +365,7 @@ func getMinedRelayCostCoin( // getMinedRelayCost returns the share of the application's stake that can be consumed // per supplier per session. -func getApplicationStakeShare( +func getSupplierAppStake( stake *cosmostypes.Coin, sharedParams *sharedtypes.Params, ) cosmostypes.Coin { From 15504753f81779dfefd0e8b03bab2ae4e76d0d73 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Wed, 30 Oct 2024 20:24:50 +0100 Subject: [PATCH 39/53] fix: Update godoc comment --- pkg/relayer/proxy/relay_meter.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/relayer/proxy/relay_meter.go b/pkg/relayer/proxy/relay_meter.go index d1a27cb4c..4951a0a06 100644 --- a/pkg/relayer/proxy/relay_meter.go +++ b/pkg/relayer/proxy/relay_meter.go @@ -363,7 +363,7 @@ func getMinedRelayCostCoin( return cosmostypes.NewCoin(volatile.DenomuPOKT, math.NewIntFromBigInt(estimatedRelayCost)), nil } -// getMinedRelayCost returns the share of the application's stake that can be consumed +// getSupplierAppStake returns the portion of the application stake that can be consumed // per supplier per session. func getSupplierAppStake( stake *cosmostypes.Coin, From cd45da6dc134c69ceeaa64f9b6891971d5e9060e Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Wed, 30 Oct 2024 23:55:37 +0100 Subject: [PATCH 40/53] chore: Address reivew change requests --- pkg/relayer/interface.go | 24 ++++++++++++++-------- pkg/relayer/proxy/proxy.go | 3 ++- pkg/relayer/proxy/relay_meter.go | 17 +++++++-------- x/tokenomics/keeper/token_logic_modules.go | 9 ++++++++ 4 files changed, 36 insertions(+), 17 deletions(-) diff --git a/pkg/relayer/interface.go b/pkg/relayer/interface.go index b8723ab70..4f552e4bc 100644 --- a/pkg/relayer/interface.go +++ b/pkg/relayer/interface.go @@ -164,17 +164,25 @@ type SessionTree interface { GetTrieSpec() smt.TrieSpec } -// RelayMeter is an interface that keeps track of the consumed stake for each application. +// RelayMeter is an interface that keeps track of the amount of stake consumed between +// a single onchain Application and a single onchain Supplier over the course of a single session. +// It enables the RelayMiner t orate limit the number of requests handled offchain as a function +// of the optimistic onchain rate limits. type RelayMeter interface { // Start starts the relay meter. Start(ctx context.Context) error - // AccumulateRelayReward accumulates the relay reward for the given relay request. - // The relay cost is added optimistically, assuming that the relay will be volume / reward - // applicable and the relay meter would remain up to date. + + // AccumulateRelayReward adds the relay reward from the incoming request to session's accumulator. + // The relay cost is added optimistically, assuming that the relay WILL be volume / reward applicable. + // The reason why optimistic AccumulateRelayReward + SetNonApplicableRelayReward is used instead of + // a simpler AccumulateVolumeApplicableRelayReward is that when the relay is first seen + // we don't know if it will be volume / reward applicable until it is served. + // Since the check of whether we allow the relay to be served or not is done before. + // To rate limit or not the current relay, we need to optimistically account + // for it as volume / reward applicable. AccumulateRelayReward(ctx context.Context, relayRequestMeta servicetypes.RelayRequestMetadata) error - // SetNonApplicableRelayReward updates the relay meter to make the relay reward for - // the given relay request as non-applicable. - // This is used when the relay is not volume / reward applicable but was optimistically - // accounted for in the relay meter. + + // SetNonApplicableRelayReward updates the relay meter for the given relay request as + // non-applicable between a single Application and a single Supplier for a single session. SetNonApplicableRelayReward(ctx context.Context, relayRequestMeta servicetypes.RelayRequestMetadata) error } diff --git a/pkg/relayer/proxy/proxy.go b/pkg/relayer/proxy/proxy.go index e14c68aad..1d8cde74f 100644 --- a/pkg/relayer/proxy/proxy.go +++ b/pkg/relayer/proxy/proxy.go @@ -79,7 +79,8 @@ type relayerProxy struct { // 2. Relay signing to resolve which keyring key name to use for signing; OperatorAddressToSigningKeyNameMap map[string]string - // relayMeter is a struct that keeps track of the claimed relay rewards for each application. + // relayMeter keeps track of the total amount of stake an onchhain Application + // will owe an onchain Supplier (backed by this RelayMiner) once the session settles. // It also configures over servicing allowance. relayMeter relayer.RelayMeter } diff --git a/pkg/relayer/proxy/relay_meter.go b/pkg/relayer/proxy/relay_meter.go index 4951a0a06..a8d90d4cd 100644 --- a/pkg/relayer/proxy/relay_meter.go +++ b/pkg/relayer/proxy/relay_meter.go @@ -28,16 +28,18 @@ import ( var _ relayer.RelayMeter = (*ProxyRelayMeter)(nil) -// appRelayMeter is the relay meter's internal representation of an application's -// max and consumed stake. +// appRelayMeter is the relay meter's internal representation of an onchain +// Application's max and consumed stake. type appRelayMeter struct { // The onchain application the relay meter is for. app apptypes.Application // The maximum uPOKT an application can pay this relayer for a given session. + // This is a fraction of the Application's overall stake. maxCoin cosmostypes.Coin // The amount of uPOKT a specific application has consumed from this relayer in the given session. consumedCoin cosmostypes.Coin - // The current sessionHeader the application is metered in. + // The header for the session the Application and Supplier (backed by the relayer) + // are exchanging services in. sessionHeader *sessiontypes.SessionHeader // sharedParams, service and serviceRelayDifficulty are used to calculate the relay cost @@ -56,13 +58,12 @@ type appRelayMeter struct { type ProxyRelayMeter struct { // supplierToAppMetricsMap is a map of supplier addresses to application address // to the application's relay meter. - // Only known applications (i.e. have already requested relaying) that have their stakes metered. - // This map gets reset every new session in order to meter new applications, since the old - // ones might have another Supplier set for their sessions. + // Only known applications (i.e. have sent at least one relay) that have their stakes metered. + // This map gets reset every new session in order to meter new applications. supplierToAppMetricsMap map[string]map[string]*appRelayMeter // overServicingAllowanceCoins allows Suppliers to overservice applications. - // This entails providing a free service, to mine for relays, that they will not be paid for. - // This is a common by some to build goodwill and receive a higher quality-of-service rating. + // This entails providing a free service (i.e. mine for relays), that they will not be paid for onchain. + // This is common by some suppliers to build goodwill and receive a higher offchain quality-of-service rating. // If negative, allow infinite overservicing. // TODO_MAINNET(@red-0ne): Expose overServicingAllowanceCoins as a configuration parameter. overServicingAllowanceCoins cosmostypes.Coin diff --git a/x/tokenomics/keeper/token_logic_modules.go b/x/tokenomics/keeper/token_logic_modules.go index 90e06f59e..6e6936713 100644 --- a/x/tokenomics/keeper/token_logic_modules.go +++ b/x/tokenomics/keeper/token_logic_modules.go @@ -698,8 +698,17 @@ func (k Keeper) ensureClaimAmountLimits( numBlocksPerSession := int64(sharedParams.GetNumBlocksPerSession()) pendingBlocks := sharedtypes.GetSessionEndToProofWindowCloseBlocks(sharedParams) + // We are addding numBlocksPerSession - 1 to round up the integer division + // so that pending sessions are all the sessions that have their end height at least + // `pendingBlocks` old pendingSessions := (pendingBlocks + numBlocksPerSession - 1) / numBlocksPerSession + // The maximum any single supplier can claim is a fraction of the app's total stake + // divided by the number of suppliers per session. + // Re decentralization - This ensures the app biases towards using all suppliers in a session. + // Re costs - This is an easy way to split the stake evenly. + // TODO_FUTURE: See if there's a way to let the application to pick a single (the best) supplier + // in a session while maintaining a simple solution to implement this. maxClaimableAmt := appStake.Amount. Quo(math.NewInt(sessionkeeper.NumSupplierPerSession)). Quo(math.NewInt(pendingSessions)) From e7c288bf432a9ff0792dc98295b367e8b188d048 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Thu, 31 Oct 2024 13:19:37 +0100 Subject: [PATCH 41/53] fix: Total supply --- config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.yml b/config.yml index c27d5c990..afca86692 100644 --- a/config.yml +++ b/config.yml @@ -143,7 +143,7 @@ genesis: denom: upokt bank: supply: - - amount: "1102000204" + - amount: "1103000204" denom: upokt balances: # Application module From 44a5b199e262c2239e143542f1076add555adaff Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Thu, 31 Oct 2024 13:39:30 +0100 Subject: [PATCH 42/53] fix: Add all apps suply --- config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.yml b/config.yml index afca86692..7d3a2c93f 100644 --- a/config.yml +++ b/config.yml @@ -143,13 +143,13 @@ genesis: denom: upokt bank: supply: - - amount: "1103000204" + - amount: "1202000272" denom: upokt balances: # Application module - address: pokt1rl3gjgzexmplmds3tq3r3yk84zlwdl6djzgsvm coins: - - amount: "200000068" # MUST BE equal to the total of all app stakes below + - amount: "200000136" # MUST BE equal to the total of all app stakes below denom: upokt # Supplier module - address: pokt1j40dzzmn6cn9kxku7a5tjnud6hv37vesr5ccaa From c5a3c2089b910155b905882a00f0802d5279287d Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Wed, 6 Nov 2024 00:15:33 +0100 Subject: [PATCH 43/53] Empty commit From 1146aba9bd6dccab359e1d7afe8bc583f0e19e36 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Wed, 6 Nov 2024 17:02:57 +0100 Subject: [PATCH 44/53] chore: Address review change requests --- api/poktroll/application/types.pulsar.go | 2 +- api/poktroll/service/tx.pulsar.go | 1 - api/poktroll/shared/service.pulsar.go | 2 +- config.yml | 1 + pkg/relayer/interface.go | 11 +- pkg/relayer/proxy/errors.go | 2 +- pkg/relayer/proxy/relay_meter.go | 220 ++++++++++++++--------- x/application/types/types.pb.go | 2 +- x/service/types/tx.pb.go | 1 - x/shared/types/service.pb.go | 2 +- 10 files changed, 150 insertions(+), 94 deletions(-) diff --git a/api/poktroll/application/types.pulsar.go b/api/poktroll/application/types.pulsar.go index d1f8f492f..f482e77bb 100644 --- a/api/poktroll/application/types.pulsar.go +++ b/api/poktroll/application/types.pulsar.go @@ -2197,7 +2197,7 @@ type Application struct { // - https://github.com/pokt-network/poktroll/pull/750#discussion_r1735025033 // - https://www.notion.so/buildwithgrove/Off-chain-Application-Stake-Tracking-6a8bebb107db4f7f9dc62cbe7ba555f7 ServiceConfigs []*shared.ApplicationServiceConfig `protobuf:"bytes,3,rep,name=service_configs,json=serviceConfigs,proto3" json:"service_configs,omitempty"` // The list of services this appliccation is configured to request service for - // TODO_BETA: Rename `delegatee_gateway_addresses` to `gateway_addresses_delegated_to`. + // TODO_BETA(@bryanchriswhite): Rename `delegatee_gateway_addresses` to `gateway_addresses_delegated_to`. // Ensure to rename all relevant configs, comments, variables, function names, etc as well. DelegateeGatewayAddresses []string `protobuf:"bytes,4,rep,name=delegatee_gateway_addresses,json=delegateeGatewayAddresses,proto3" json:"delegatee_gateway_addresses,omitempty"` // The Bech32 encoded addresses for all delegatee Gateways, in a non-nullable slice // A map from sessionEndHeights to a list of Gateways. diff --git a/api/poktroll/service/tx.pulsar.go b/api/poktroll/service/tx.pulsar.go index 6a68413aa..ae03ea849 100644 --- a/api/poktroll/service/tx.pulsar.go +++ b/api/poktroll/service/tx.pulsar.go @@ -2968,7 +2968,6 @@ func (x *MsgUpdateParamResponse) GetParams() *Params { // MsgAddService defines a message for adding a new message to the network. // Services can be added by any actor in the network making them truly // permissionless. -// TODO_BETA: Add Champions / Sources once its fully defined. type MsgAddService struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache diff --git a/api/poktroll/shared/service.pulsar.go b/api/poktroll/shared/service.pulsar.go index 680123e30..60a1e6c85 100644 --- a/api/poktroll/shared/service.pulsar.go +++ b/api/poktroll/shared/service.pulsar.go @@ -3391,7 +3391,7 @@ type Service struct { // For example, what if we want to request a session for a certain service but with some additional configs that identify it? Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // Unique identifier for the service - // TODO_BETA: Either remove this or rename it to alias. + // TODO_BETA(@bryanchriswhite): Either remove this or rename it to alias. Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` // (Optional) Semantic human readable name for the service // The cost of a single relay for this service in terms of compute units. // Must be used alongside the global 'compute_units_to_tokens_multipler' to calculate the cost of a relay for this service. diff --git a/config.yml b/config.yml index 9cce885ea..b98f4229d 100644 --- a/config.yml +++ b/config.yml @@ -147,6 +147,7 @@ genesis: # Application module - address: pokt1rl3gjgzexmplmds3tq3r3yk84zlwdl6djzgsvm coins: + # TODO_MAINNET: Pass config.yml into ChatGPT to build a script that ensures the amounts line up - amount: "200000136" # MUST BE equal to the total of all app stakes below denom: upokt # Supplier module diff --git a/pkg/relayer/interface.go b/pkg/relayer/interface.go index 4f552e4bc..766dcb5ce 100644 --- a/pkg/relayer/interface.go +++ b/pkg/relayer/interface.go @@ -166,7 +166,7 @@ type SessionTree interface { // RelayMeter is an interface that keeps track of the amount of stake consumed between // a single onchain Application and a single onchain Supplier over the course of a single session. -// It enables the RelayMiner t orate limit the number of requests handled offchain as a function +// It enables the RelayMiner to rate limit the number of requests handled offchain as a function // of the optimistic onchain rate limits. type RelayMeter interface { // Start starts the relay meter. @@ -174,15 +174,18 @@ type RelayMeter interface { // AccumulateRelayReward adds the relay reward from the incoming request to session's accumulator. // The relay cost is added optimistically, assuming that the relay WILL be volume / reward applicable. + // // The reason why optimistic AccumulateRelayReward + SetNonApplicableRelayReward is used instead of // a simpler AccumulateVolumeApplicableRelayReward is that when the relay is first seen // we don't know if it will be volume / reward applicable until it is served. - // Since the check of whether we allow the relay to be served or not is done before. - // To rate limit or not the current relay, we need to optimistically account - // for it as volume / reward applicable. + // + // To rate limit or not the current relay, we need to always optimistically account all relays as being + // volume / reward applicable. AccumulateRelayReward(ctx context.Context, relayRequestMeta servicetypes.RelayRequestMetadata) error // SetNonApplicableRelayReward updates the relay meter for the given relay request as // non-applicable between a single Application and a single Supplier for a single session. + // The volume / reward applicability of the relay is unknown to the relay miner + // until the relay is served and the relay response signed. SetNonApplicableRelayReward(ctx context.Context, relayRequestMeta servicetypes.RelayRequestMetadata) error } diff --git a/pkg/relayer/proxy/errors.go b/pkg/relayer/proxy/errors.go index b8c9d86b2..9a258b293 100644 --- a/pkg/relayer/proxy/errors.go +++ b/pkg/relayer/proxy/errors.go @@ -17,6 +17,6 @@ var ( ErrRelayerProxyUnsupportedTransportType = sdkerrors.Register(codespace, 9, "unsupported proxy transport type") ErrRelayerProxyInternalError = sdkerrors.Register(codespace, 10, "internal error") ErrRelayerProxyMissingSupplierOperatorAddress = sdkerrors.Register(codespace, 11, "supplier operator address is missing") - ErrRelayerProxyUnknownApplication = sdkerrors.Register(codespace, 12, "relayer proxy encountered unknown application") + ErrRelayerProxyUnknownSession = sdkerrors.Register(codespace, 12, "relayer proxy encountered unknown session") ErrRelayerProxyRateLimited = sdkerrors.Register(codespace, 13, "offchain rate limit hit by relayer proxy") ) diff --git a/pkg/relayer/proxy/relay_meter.go b/pkg/relayer/proxy/relay_meter.go index a8d90d4cd..e4d405a46 100644 --- a/pkg/relayer/proxy/relay_meter.go +++ b/pkg/relayer/proxy/relay_meter.go @@ -18,6 +18,7 @@ import ( "github.com/pokt-network/poktroll/pkg/either" "github.com/pokt-network/poktroll/pkg/observable" "github.com/pokt-network/poktroll/pkg/observable/channel" + "github.com/pokt-network/poktroll/pkg/polylog" "github.com/pokt-network/poktroll/pkg/relayer" apptypes "github.com/pokt-network/poktroll/x/application/types" servicetypes "github.com/pokt-network/poktroll/x/service/types" @@ -28,19 +29,22 @@ import ( var _ relayer.RelayMeter = (*ProxyRelayMeter)(nil) -// appRelayMeter is the relay meter's internal representation of an onchain +// sessionRelayMeter is the relay meter's internal representation of an onchain // Application's max and consumed stake. -type appRelayMeter struct { +type sessionRelayMeter struct { // The onchain application the relay meter is for. app apptypes.Application // The maximum uPOKT an application can pay this relayer for a given session. - // This is a fraction of the Application's overall stake. + // This is a fraction of the Application's overall stake in proportion. maxCoin cosmostypes.Coin // The amount of uPOKT a specific application has consumed from this relayer in the given session. consumedCoin cosmostypes.Coin // The header for the session the Application and Supplier (backed by the relayer) // are exchanging services in. sessionHeader *sessiontypes.SessionHeader + // numOverServicedRelays is the number of relays that have been over-serviced + // by the relayer for the application. + numOverServicedRelays int // sharedParams, service and serviceRelayDifficulty are used to calculate the relay cost // that increments the consumedAmount. @@ -56,11 +60,10 @@ type appRelayMeter struct { // This is done by maintaining the max amount of stake the supplier can consume // per session and the amount of stake consumed by mined relays. type ProxyRelayMeter struct { - // supplierToAppMetricsMap is a map of supplier addresses to application address - // to the application's relay meter. - // Only known applications (i.e. have sent at least one relay) that have their stakes metered. + // sessionToRelayMeterMap is a map of session IDs to their corresponding session relay meter. + // Only known applications (i.e. have sent at least one relay) have their stakes metered. // This map gets reset every new session in order to meter new applications. - supplierToAppMetricsMap map[string]map[string]*appRelayMeter + sessionToRelayMeterMap map[string]*sessionRelayMeter // overServicingAllowanceCoins allows Suppliers to overservice applications. // This entails providing a free service (i.e. mine for relays), that they will not be paid for onchain. // This is common by some suppliers to build goodwill and receive a higher offchain quality-of-service rating. @@ -71,17 +74,20 @@ type ProxyRelayMeter struct { // relayMeterMu ensures that relay meter operations are thread-safe. relayMeterMu sync.Mutex + // Clients to query onchain data. applicationQuerier client.ApplicationQueryClient serviceQuerier client.ServiceQueryClient sharedQuerier client.SharedQueryClient eventsQueryClient client.EventsQueryClient blockQuerier client.BlockClient + + logger polylog.Logger } func NewRelayMeter(deps depinject.Config) (relayer.RelayMeter, error) { overservicingAllowanceCoins := cosmostypes.NewInt64Coin(volatile.DenomuPOKT, 1000000) rm := &ProxyRelayMeter{ - supplierToAppMetricsMap: make(map[string]map[string]*appRelayMeter), + sessionToRelayMeterMap: make(map[string]*sessionRelayMeter), overServicingAllowanceCoins: overservicingAllowanceCoins, } @@ -92,6 +98,7 @@ func NewRelayMeter(deps depinject.Config) (relayer.RelayMeter, error) { &rm.serviceQuerier, &rm.blockQuerier, &rm.eventsQueryClient, + &rm.logger, ); err != nil { return nil, err } @@ -109,12 +116,14 @@ func (rmtr *ProxyRelayMeter) Start(ctx context.Context) error { return err } - // Listen to application staked events and update known application stakes. - // Since an applications might upstake (not downstake) during a session, this - // stake increase is guaranteed to be available at settlement so it must be updated. - // This also allows applications to adjust their stake mid-session and avoid - // being rate limited or need to wait for the next session. + // Listen for application staked events and update known application stakes. + // + // Since an applications might upstake (never downstake) during a session, this + // stake increase is guaranteed to be available at settlement. // Stake updates take effect immediately. + // + // This enables applications to adjust their stake mid-session and increase + // their rate limits without needing to wait for the next session to start. appStakedEvents := filterTypedEvents[*apptypes.EventApplicationStaked](ctx, eventsObs, nil) channel.ForEach(ctx, appStakedEvents, rmtr.forEachEventApplicationStakedFn) @@ -129,39 +138,74 @@ func (rmtr *ProxyRelayMeter) Start(ctx context.Context) error { // The relay reward is added optimistically, assuming that the relay will be volume / reward // applicable and the relay meter would remain up to date. func (rmtr *ProxyRelayMeter) AccumulateRelayReward(ctx context.Context, reqMeta servicetypes.RelayRequestMetadata) error { + // TODO_MAINNET: Locking the relay serving flow to ensure that the relay meter is updated + // might be a bottleneck since ensureRequestAppMetrics is performing multiple + // sequential queries to the Pocket Network node. + // Re-evaluate when caching and invalidation is implemented. rmtr.relayMeterMu.Lock() defer rmtr.relayMeterMu.Unlock() - // Create a metric if it does not exist. - appMetrics, err := rmtr.ensureRequestAppMetrics(ctx, reqMeta, true) + // Ensure that the served application has a relay meter and update the consumed + // stake amount. + appRelayMeter, err := rmtr.ensureRequestSessionRelayMeter(ctx, reqMeta) if err != nil { return err } // Get the cost of the relay based on the service and shared parameters. - relayCostCoin, err := getMinedRelayCostCoin( - appMetrics.sharedParams, - appMetrics.service, - appMetrics.serviceRelayDifficulty, + relayCostCoin, err := getSingleMinedRelayCostCoin( + appRelayMeter.sharedParams, + appRelayMeter.service, + appRelayMeter.serviceRelayDifficulty, ) if err != nil { return err } // Increase the consumed stake amount by relay cost. - newConsumedCoin := appMetrics.consumedCoin.Add(relayCostCoin) - - // If the consumed amount exceeds the max amount, return a rate limit error. - overServicingLimited := !rmtr.overServicingAllowanceCoins.IsNegative() - if overServicingLimited && appMetrics.maxCoin.IsLT(newConsumedCoin) { - return ErrRelayerProxyRateLimited.Wrapf( - "application has been rate limited, stake needed: %s, has: %s, ", - newConsumedCoin.String(), - appMetrics.maxCoin.String(), + newConsumedCoin := appRelayMeter.consumedCoin.Add(relayCostCoin) + + isAppOverServiced := appRelayMeter.maxCoin.IsLT(newConsumedCoin) + + if !isAppOverServiced { + appRelayMeter.consumedCoin = newConsumedCoin + return nil + } + + // Check if the supplier is allowing unlimited over-servicing (i.e. negative value) + allowUnlimitedOverServicing := rmtr.overServicingAllowanceCoins.IsNegative() + + // The application is over-servicing, if unlimited over-servicing is not allowed + // and the newConsumedCoin is greater than the maxCoin + overServicingAllowanceCoins, + // then return a rate limit error. + overServicingCoin := appRelayMeter.consumedCoin.Sub(appRelayMeter.maxCoin) + + // In case Allowance is positive, add it to the maxCoin to allow no or limited over-servicing. + if !allowUnlimitedOverServicing { + maxAllowedOverServicing := appRelayMeter.maxCoin.Add(rmtr.overServicingAllowanceCoins) + if maxAllowedOverServicing.IsLT(newConsumedCoin) { + return ErrRelayerProxyRateLimited.Wrapf( + "application has been rate limited, stake needed: %s, has: %s, ", + newConsumedCoin.String(), + appRelayMeter.maxCoin.String(), + ) + } + } + + appRelayMeter.numOverServicedRelays++ + numOverServicedRelays := appRelayMeter.numOverServicedRelays + + // Exponential backoff: log only when numOverServicedRelays is a power of 2 + isPowerOfTwo := (numOverServicedRelays & (numOverServicedRelays - 1)) == 0 + + // Log the over-servicing warning. + if isPowerOfTwo { + rmtr.logger.Warn().Msgf( + "overservicing enabled, application %q over-serviced %s", + overServicingCoin, ) } - appMetrics.consumedCoin = newConsumedCoin return nil } @@ -173,25 +217,29 @@ func (rmtr *ProxyRelayMeter) SetNonApplicableRelayReward(ctx context.Context, re rmtr.relayMeterMu.Lock() defer rmtr.relayMeterMu.Unlock() - appMetrics, err := rmtr.ensureRequestAppMetrics(ctx, reqMeta, false) - if err != nil { - return err + sessionRelayMeter, ok := rmtr.sessionToRelayMeterMap[reqMeta.GetSessionHeader().GetSessionId()] + if !ok { + return ErrRelayerProxyUnknownSession.Wrap("session relay meter not found") } // Get the cost of the relay based on the service and shared parameters. - relayCost, err := getMinedRelayCostCoin( - appMetrics.sharedParams, - appMetrics.service, - appMetrics.serviceRelayDifficulty, + relayCost, err := getSingleMinedRelayCostCoin( + sessionRelayMeter.sharedParams, + sessionRelayMeter.service, + sessionRelayMeter.serviceRelayDifficulty, ) if err != nil { return err } + if sessionRelayMeter.numOverServicedRelays > 0 { + return nil + } + // Decrease the consumed stake amount by relay cost. - newConsumedAmount := appMetrics.consumedCoin.Sub(relayCost) + newConsumedAmount := sessionRelayMeter.consumedCoin.Sub(relayCost) - appMetrics.consumedCoin = newConsumedAmount + sessionRelayMeter.consumedCoin = newConsumedAmount return nil } @@ -206,12 +254,17 @@ func (rmtr *ProxyRelayMeter) forEachNewBlockFn(ctx context.Context, block client if err != nil { return } - numBlocksPerSession := int64(sharedParams.GetNumBlocksPerSession()) - // If the block observed is the last of the session, reset the relay meter's - // to process next session's application requests. - if block.Height()%numBlocksPerSession == 0 { - rmtr.supplierToAppMetricsMap = make(map[string]map[string]*appRelayMeter) + // Delete the relay meters that correspond to settled sessions. + for _, sessionRelayMeter := range rmtr.sessionToRelayMeterMap { + sessionEndHeight := sessionRelayMeter.sessionHeader.GetSessionEndBlockHeight() + sessionClaimOpenHeight := sessionEndHeight + int64(sharedParams.GetClaimWindowOpenOffsetBlocks()) + + if block.Height() >= sessionClaimOpenHeight { + // The session started its claim phase and the corresponding session relay meter + // is no longer needed. + delete(rmtr.sessionToRelayMeterMap, sessionRelayMeter.sessionHeader.GetSessionId()) + } } } @@ -226,30 +279,23 @@ func (rmtr *ProxyRelayMeter) forEachEventApplicationStakedFn(ctx context.Context // Since lean clients are supported, multiple suppliers might share the same RelayMiner. // Loop over all the suppliers that have metered the application and update their // max amount of stake they can consume. - for supplierAddress := range rmtr.supplierToAppMetricsMap { - appMetrics, ok := rmtr.supplierToAppMetricsMap[supplierAddress][app.GetAddress()] - if !ok { + for _, sessionRelayMeter := range rmtr.sessionToRelayMeterMap { + if sessionRelayMeter.app.Address != app.Address { continue } - appMetrics.app.Stake = app.GetStake() - appStakeShare := getSupplierAppStake(app.GetStake(), appMetrics.sharedParams) - appMetrics.maxCoin = appStakeShare.Add(rmtr.overServicingAllowanceCoins) + sessionRelayMeter.app.Stake = app.GetStake() + appStakeShare := getAppStakePortionPayableToSessionSupplier(app.GetStake(), sessionRelayMeter.sharedParams) + sessionRelayMeter.maxCoin = appStakeShare } } -func (rmtr *ProxyRelayMeter) ensureRequestAppMetrics(ctx context.Context, reqMeta servicetypes.RelayRequestMetadata, createMetric bool) (*appRelayMeter, error) { +// ensureRequestSessionRelayMeter ensures that the relay miner has a relay meter +// ready for monitoring the requests's application's consumption. +func (rmtr *ProxyRelayMeter) ensureRequestSessionRelayMeter(ctx context.Context, reqMeta servicetypes.RelayRequestMetadata) (*sessionRelayMeter, error) { appAddress := reqMeta.GetSessionHeader().GetApplicationAddress() - supplierAddress := reqMeta.GetSupplierOperatorAddress() - - supplierApps, ok := rmtr.supplierToAppMetricsMap[supplierAddress] - if !ok { - rmtr.supplierToAppMetricsMap[supplierAddress] = make(map[string]*appRelayMeter) - supplierApps = rmtr.supplierToAppMetricsMap[supplierAddress] - } - - // Do not consider applications that have not been seen in this session. - appMetrics, ok := supplierApps[appAddress] + sessionId := reqMeta.GetSessionHeader().GetSessionId() + relayMeter, ok := rmtr.sessionToRelayMeterMap[sessionId] // If the application is seen for the first time in this session, calculate the // max amount of stake the application can consume. if !ok { @@ -259,6 +305,16 @@ func (rmtr *ProxyRelayMeter) ensureRequestAppMetrics(ctx context.Context, reqMet return nil, err } + // In order to prevent over-servicing, the protocol must split the application's stake + // among all the suppliers that are serving it. + if len(app.ServiceConfigs) != 1 { + return nil, ErrRelayerProxyInvalidSession.Wrapf( + "application %q has %d service configs, expected 1", + appAddress, + len(app.ServiceConfigs), + ) + } + sharedParams, err := rmtr.sharedQuerier.GetParams(ctx) if err != nil { return nil, err @@ -274,27 +330,22 @@ func (rmtr *ProxyRelayMeter) ensureRequestAppMetrics(ctx context.Context, reqMet return nil, err } - if !createMetric { - return nil, ErrRelayerProxyUnknownApplication.Wrap("required metric not found") - } - // calculate the max amount of stake the application can consume in the current session. - supplierAppStake := getSupplierAppStake(app.Stake, sharedParams) - maxAmount := supplierAppStake.Add(rmtr.overServicingAllowanceCoins) - appMetrics = &appRelayMeter{ + supplierAppStake := getAppStakePortionPayableToSessionSupplier(app.Stake, sharedParams) + relayMeter = &sessionRelayMeter{ app: app, consumedCoin: cosmostypes.NewInt64Coin(volatile.DenomuPOKT, 0), - maxCoin: maxAmount, + maxCoin: supplierAppStake, sessionHeader: reqMeta.SessionHeader, sharedParams: sharedParams, service: &service, serviceRelayDifficulty: serviceRelayDifficulty, } - rmtr.supplierToAppMetricsMap[supplierAddress][appAddress] = appMetrics + rmtr.sessionToRelayMeterMap[sessionId] = relayMeter } - return appMetrics, nil + return relayMeter, nil } // filterTypedEvents filters the provided events bytes for the typed event T. @@ -344,9 +395,9 @@ func filterTypedEvents[T proto.Message]( return eventObs } -// getMinedRelayCostCoin returns the cost of a relay based on the shared parameters and the service. -// relayCost = CUPR * CUTTM * relayDifficultyMultiplier -func getMinedRelayCostCoin( +// getSingleMinedRelayCostCoin returns the cost of a relay based on the shared parameters and the service. +// relayCost = Compute Units Per Relay (CUPR) * Compute Units To Token Multiplier (CUTTM) * relayDifficultyMultiplier +func getSingleMinedRelayCostCoin( sharedParams *sharedtypes.Params, service *sharedtypes.Service, relayMiningDifficulty servicetypes.RelayMiningDifficulty, @@ -361,24 +412,27 @@ func getMinedRelayCostCoin( estimatedRelayCostRat := big.NewRat(0, 1).Mul(relayCostRat, difficultyMultiplier) estimatedRelayCost := big.NewInt(0).Quo(estimatedRelayCostRat.Num(), estimatedRelayCostRat.Denom()) - return cosmostypes.NewCoin(volatile.DenomuPOKT, math.NewIntFromBigInt(estimatedRelayCost)), nil + estimatedRelayCostCoin := cosmostypes.NewCoin(volatile.DenomuPOKT, math.NewIntFromBigInt(estimatedRelayCost)) + + return estimatedRelayCostCoin, nil } -// getSupplierAppStake returns the portion of the application stake that can be consumed -// per supplier per session. -func getSupplierAppStake( +// getAppStakePortionPayableToSessionSupplier returns the portion of the application +// stake that can be consumed per supplier per session. +func getAppStakePortionPayableToSessionSupplier( stake *cosmostypes.Coin, sharedParams *sharedtypes.Params, ) cosmostypes.Coin { - maxRelayers := int64(sessionkeeper.NumSupplierPerSession) - appStakePerSupplier := stake.Amount.Quo(math.NewInt(maxRelayers)) + maxSuppliers := int64(sessionkeeper.NumSupplierPerSession) + appStakePerSupplier := stake.Amount.Quo(math.NewInt(maxSuppliers)) // Calculate the number of pending sessions that might consume the application's stake. numBlocksPerSession := int64(sharedParams.GetNumBlocksPerSession()) - pendingBlocks := sharedtypes.GetSessionEndToProofWindowCloseBlocks(sharedParams) - pendingSessions := (pendingBlocks + numBlocksPerSession - 1) / numBlocksPerSession + numBlocksUntilProofWindowCloses := sharedtypes.GetSessionEndToProofWindowCloseBlocks(sharedParams) + pendingSessions := (numBlocksUntilProofWindowCloses + numBlocksPerSession - 1) / numBlocksPerSession - appStakePerSupplierSession := appStakePerSupplier.Quo(math.NewInt(pendingSessions)) + appStakePerSessionSupplier := appStakePerSupplier.Quo(math.NewInt(pendingSessions)) + appStakePerSessionSupplierCoin := cosmostypes.NewCoin(volatile.DenomuPOKT, appStakePerSessionSupplier) - return cosmostypes.NewCoin(volatile.DenomuPOKT, appStakePerSupplierSession) + return appStakePerSessionSupplierCoin } diff --git a/x/application/types/types.pb.go b/x/application/types/types.pb.go index 32bc0cc13..7d154dd9f 100644 --- a/x/application/types/types.pb.go +++ b/x/application/types/types.pb.go @@ -38,7 +38,7 @@ type Application struct { // - https://github.com/pokt-network/poktroll/pull/750#discussion_r1735025033 // - https://www.notion.so/buildwithgrove/Off-chain-Application-Stake-Tracking-6a8bebb107db4f7f9dc62cbe7ba555f7 ServiceConfigs []*types1.ApplicationServiceConfig `protobuf:"bytes,3,rep,name=service_configs,json=serviceConfigs,proto3" json:"service_configs,omitempty"` - // TODO_BETA: Rename `delegatee_gateway_addresses` to `gateway_addresses_delegated_to`. + // TODO_BETA(@bryanchriswhite): Rename `delegatee_gateway_addresses` to `gateway_addresses_delegated_to`. // Ensure to rename all relevant configs, comments, variables, function names, etc as well. DelegateeGatewayAddresses []string `protobuf:"bytes,4,rep,name=delegatee_gateway_addresses,json=delegateeGatewayAddresses,proto3" json:"delegatee_gateway_addresses,omitempty"` // A map from sessionEndHeights to a list of Gateways. diff --git a/x/service/types/tx.pb.go b/x/service/types/tx.pb.go index cbfd2f131..098020211 100644 --- a/x/service/types/tx.pb.go +++ b/x/service/types/tx.pb.go @@ -252,7 +252,6 @@ func (m *MsgUpdateParamResponse) GetParams() *Params { // MsgAddService defines a message for adding a new message to the network. // Services can be added by any actor in the network making them truly // permissionless. -// TODO_BETA: Add Champions / Sources once its fully defined. type MsgAddService struct { OwnerAddress string `protobuf:"bytes,1,opt,name=owner_address,json=ownerAddress,proto3" json:"owner_address,omitempty"` Service types1.Service `protobuf:"bytes,2,opt,name=service,proto3" json:"service"` diff --git a/x/shared/types/service.pb.go b/x/shared/types/service.pb.go index 1a2538f90..d5998637f 100644 --- a/x/shared/types/service.pb.go +++ b/x/shared/types/service.pb.go @@ -94,7 +94,7 @@ func (ConfigOptions) EnumDescriptor() ([]byte, []int) { type Service struct { // For example, what if we want to request a session for a certain service but with some additional configs that identify it? Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - // TODO_BETA: Either remove this or rename it to alias. + // TODO_BETA(@bryanchriswhite): Either remove this or rename it to alias. Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` // The cost of a single relay for this service in terms of compute units. // Must be used alongside the global 'compute_units_to_tokens_multipler' to calculate the cost of a relay for this service. From 7b8998e9b56c3409be6e8ddaf3287c9bdb5226ef Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Wed, 6 Nov 2024 23:01:33 +0100 Subject: [PATCH 45/53] fix: Do not process 0 claim amounts --- x/tokenomics/keeper/settle_pending_claims.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/x/tokenomics/keeper/settle_pending_claims.go b/x/tokenomics/keeper/settle_pending_claims.go index 1f028c365..2144b8487 100644 --- a/x/tokenomics/keeper/settle_pending_claims.go +++ b/x/tokenomics/keeper/settle_pending_claims.go @@ -203,6 +203,12 @@ func (k Keeper) SettlePendingClaims(ctx sdk.Context) ( appAddress := claim.GetSessionHeader().GetApplicationAddress() applicationInitialStake := applicationInitialStakeMap[appAddress] + if applicationInitialStake.IsZero() { + logger.Error(fmt.Sprintf("application %q has a zero initial stake", appAddress)) + + continue + } + // Manage the mint & burn accounting for the claim. if err = k.ProcessTokenLogicModules(ctx, &claim, applicationInitialStake); err != nil { logger.Error(fmt.Sprintf("error processing token logic modules for claim %q: %v", claim.SessionHeader.SessionId, err)) From 88a3d4560560951fa830f4f5b4362199469a3b44 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Thu, 7 Nov 2024 00:20:27 +0100 Subject: [PATCH 46/53] Empty commit From 4b043539f1fb738783294076f2748f7f38927c7d Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Thu, 7 Nov 2024 13:21:46 +0100 Subject: [PATCH 47/53] fix: Prevent 0 settlement due to int div --- x/tokenomics/keeper/token_logic_modules.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/x/tokenomics/keeper/token_logic_modules.go b/x/tokenomics/keeper/token_logic_modules.go index 871de7fd9..564e9b733 100644 --- a/x/tokenomics/keeper/token_logic_modules.go +++ b/x/tokenomics/keeper/token_logic_modules.go @@ -299,6 +299,14 @@ func (k Keeper) ProcessTokenLogicModules( logger = logger.With("actual_settlement_upokt", actualSettlementCoin) logger.Info(fmt.Sprintf("About to start processing TLMs for (%d) compute units, equal to (%s) claimed", numClaimComputeUnits, actualSettlementCoin)) + if actualSettlementCoin.Amount.IsZero() { + logger.Warn(fmt.Sprintf( + "actual settlement coin is zero, skipping TLM processing, application %q stake %s", + application.Address, application.Stake, + )) + return nil + } + // Execute all the token logic modules processors for tlm, tlmProcessor := range tokenLogicModuleProcessorMap { logger.Info(fmt.Sprintf("Starting TLM processing: %q", tlm)) From 331654fa846cfcf33d6c28fcc4261a6c12de62a3 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Thu, 7 Nov 2024 16:04:13 +0100 Subject: [PATCH 48/53] fix: consumed coin calculation --- pkg/relayer/proxy/relay_meter.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pkg/relayer/proxy/relay_meter.go b/pkg/relayer/proxy/relay_meter.go index e4d405a46..9c8101edd 100644 --- a/pkg/relayer/proxy/relay_meter.go +++ b/pkg/relayer/proxy/relay_meter.go @@ -178,7 +178,7 @@ func (rmtr *ProxyRelayMeter) AccumulateRelayReward(ctx context.Context, reqMeta // The application is over-servicing, if unlimited over-servicing is not allowed // and the newConsumedCoin is greater than the maxCoin + overServicingAllowanceCoins, // then return a rate limit error. - overServicingCoin := appRelayMeter.consumedCoin.Sub(appRelayMeter.maxCoin) + overServicingCoin := newConsumedCoin.Sub(appRelayMeter.maxCoin) // In case Allowance is positive, add it to the maxCoin to allow no or limited over-servicing. if !allowUnlimitedOverServicing { @@ -196,12 +196,13 @@ func (rmtr *ProxyRelayMeter) AccumulateRelayReward(ctx context.Context, reqMeta numOverServicedRelays := appRelayMeter.numOverServicedRelays // Exponential backoff: log only when numOverServicedRelays is a power of 2 - isPowerOfTwo := (numOverServicedRelays & (numOverServicedRelays - 1)) == 0 + shouldLog := (numOverServicedRelays & (numOverServicedRelays - 1)) == 0 // Log the over-servicing warning. - if isPowerOfTwo { + if shouldLog { rmtr.logger.Warn().Msgf( "overservicing enabled, application %q over-serviced %s", + appRelayMeter.app.GetAddress(), overServicingCoin, ) } From 54381639669f1ea2b0fc375c24ee5d953b615fca Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Mon, 11 Nov 2024 13:52:39 +0100 Subject: [PATCH 49/53] wip: update expected balances --- .../tests/relays_stress_helpers_test.go | 423 +++++++++++------- ... => relays_stress_signle_supplier.feature} | 0 load-testing/tests/relays_stress_test.go | 187 +++++++- pkg/client/interface.go | 2 + pkg/client/query/appquerier.go | 10 + pkg/relayer/session/sessiontree.go | 16 - x/proof/keeper/proof_validation.go | 4 - x/proof/types/application_query_client.go | 6 + x/proof/types/expected_keepers.go | 1 + x/tokenomics/types/event.pb.go | 1 + 10 files changed, 454 insertions(+), 196 deletions(-) rename load-testing/tests/{relays_stress_single_suppier.feature => relays_stress_signle_supplier.feature} (100%) diff --git a/load-testing/tests/relays_stress_helpers_test.go b/load-testing/tests/relays_stress_helpers_test.go index 97d5b1339..f4f4b2ef4 100644 --- a/load-testing/tests/relays_stress_helpers_test.go +++ b/load-testing/tests/relays_stress_helpers_test.go @@ -9,6 +9,7 @@ import ( "net/url" "os" "path/filepath" + "slices" "strings" "sync" "testing" @@ -25,14 +26,17 @@ import ( "github.com/cosmos/cosmos-sdk/x/authz" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/cosmos/gogoproto/proto" "github.com/regen-network/gocuke" "github.com/stretchr/testify/require" "github.com/pokt-network/poktroll/load-testing/config" "github.com/pokt-network/poktroll/pkg/client" + "github.com/pokt-network/poktroll/pkg/client/block" "github.com/pokt-network/poktroll/pkg/client/events" "github.com/pokt-network/poktroll/pkg/client/query" "github.com/pokt-network/poktroll/pkg/client/tx" + "github.com/pokt-network/poktroll/pkg/observable" "github.com/pokt-network/poktroll/pkg/observable/channel" "github.com/pokt-network/poktroll/pkg/sync2" testsession "github.com/pokt-network/poktroll/testutil/session" @@ -40,8 +44,10 @@ import ( "github.com/pokt-network/poktroll/testutil/testclient/testeventsquery" apptypes "github.com/pokt-network/poktroll/x/application/types" gatewaytypes "github.com/pokt-network/poktroll/x/gateway/types" + prooftypes "github.com/pokt-network/poktroll/x/proof/types" sharedtypes "github.com/pokt-network/poktroll/x/shared/types" suppliertypes "github.com/pokt-network/poktroll/x/supplier/types" + tokenomicstypes "github.com/pokt-network/poktroll/x/tokenomics/types" ) // actorLoadTestIncrementPlans is a struct that holds the parameters for incrementing @@ -81,7 +87,7 @@ func (s *relaysSuite) setupTxEventListeners() { eventsQueryClient := testeventsquery.NewLocalnetClient(s.TestingT.(*testing.T)) deps := depinject.Supply(eventsQueryClient) - eventsReplayClient, err := events.NewEventsReplayClient( + txEventsReplayClient, err := events.NewEventsReplayClient( s.ctx, deps, newTxEventSubscriptionQuery, @@ -90,13 +96,35 @@ func (s *relaysSuite) setupTxEventListeners() { ) require.NoError(s, err) + eventsObs, eventsObsCh := channel.NewObservable[[]types.Event]() + s.eventsObs = eventsObs + // Map the eventsReplayClient.EventsSequence which is a replay observable // to a regular observable to avoid replaying txResults from old blocks. - s.newTxEventsObs = channel.Map( + channel.ForEach( s.ctx, - eventsReplayClient.EventsSequence(s.ctx), - func(ctx context.Context, txResult *types.TxResult) (*types.TxResult, bool) { - return txResult, false + txEventsReplayClient.EventsSequence(s.ctx), + func(ctx context.Context, txResult *types.TxResult) { + eventsObsCh <- txResult.Result.Events + }, + ) + + blockEventsReplayClient, err := events.NewEventsReplayClient( + s.ctx, + deps, + newBlockEventSubscriptionQuery, + block.UnmarshalNewBlockEvent, + eventsReplayClientBufferSize, + ) + require.NoError(s, err) + + // Map the eventsReplayClient.EventsSequence which is a replay observable + // to a regular observable to avoid replaying txResults from old blocks. + channel.ForEach( + s.ctx, + blockEventsReplayClient.EventsSequence(s.ctx), + func(ctx context.Context, block *block.CometNewBlockEvent) { + eventsObsCh <- block.Data.Value.ResultFinalizeBlock.Events }, ) } @@ -457,16 +485,15 @@ func (s *relaysSuite) mapSessionInfoWhenStakingNewSuppliersAndGatewaysFn() chann // For each notification received, it waits for the new actors' staking/funding // txs to be committed before sending staking & delegation txs for new applications. func (s *relaysSuite) mapStakingInfoWhenStakingAndDelegatingNewApps( - _ context.Context, + ctx context.Context, notif *stakingInfoNotif, ) (*stakingInfoNotif, bool) { // Ensure that new gateways and suppliers are staked. // Ensure that new applications are funded and have an account entry on-chain // so that they can stake and delegate in the next block. - txResults := s.waitForTxsToBeCommitted() - s.ensureFundedActors(txResults, notif.newApps) - s.ensureStakedActors(txResults, EventActionMsgStakeGateway, notif.newGateways) - s.ensureStakedActors(txResults, EventActionMsgStakeSupplier, notif.newSuppliers) + fundedActors := append(notif.newGateways, notif.newSuppliers...) + fundedActors = append(fundedActors, notif.newApps...) + s.ensureFundedActors(ctx, fundedActors) // Update the list of staked suppliers. s.activeSuppliers = append(s.activeSuppliers, notif.newSuppliers...) @@ -632,6 +659,7 @@ func (s *relaysSuite) getAppFundingAmount(currentBlockHeight int64) sdk.Coin { // be enough, but probabilistic and time based mechanisms make it hard // to predict exactly. appFundingAmount := s.relayRatePerApp * s.relayCoinAmountCost * currentTestDuration * blockDuration * 2 + appFundingAmount = math.Max(appFundingAmount, s.appParams.MinStake.Amount.Int64()*2) return sdk.NewCoin("upokt", math.NewInt(appFundingAmount)) } @@ -798,6 +826,12 @@ func (s *relaysSuite) addPendingStakeSupplierMsg(supplier *accountInfo) { RpcType: sharedtypes.RPCType_JSON_RPC, }, }, + RevShare: []*sharedtypes.ServiceRevenueShare{ + { + RevSharePercentage: 100, + Address: supplier.address, + }, + }, }, }, )) @@ -973,33 +1007,6 @@ func (s *relaysSuite) sendPendingMsgsTx(actor *accountInfo) { }() } -// waitForTxsToBeCommitted waits for transactions to be observed on-chain. -// It is used to ensure that the transactions are committed before taking -// dependent actions. -func (s *relaysSuite) waitForTxsToBeCommitted() (txResults []*types.TxResult) { - ctx, cancel := context.WithCancel(s.ctx) - defer cancel() - - ch := s.newTxEventsObs.Subscribe(ctx).Ch() - for { - txResult := <-ch - txResults = append(txResults, txResult) - - // The number of transactions to be observed is not available in the TxResult - // event, so this number is taken from the last block event. - // The block received from s.latestBlock may be the previous one, it is - // necessary to wait until the block matching the txResult height is received - // in order to get the right number of transaction events to collect. - numTxs := s.waitUntilLatestBlockHeightEquals(txResult.Height) - - // If all transactions are observed, break the loop. - if len(txResults) == numTxs { - break - } - } - return txResults -} - // waitUntilLatestBlockHeightEquals blocks until s.latestBlock.Height() equals the targetHeight. // NB: s.latestBlock is updated asynchronously via a subscription to the block client observable. func (s *relaysSuite) waitUntilLatestBlockHeightEquals(targetHeight int64) int { @@ -1064,118 +1071,142 @@ func (s *relaysSuite) sendRelay(iteration uint64, relayPayload string) (appAddre // ensureFundedActors checks if the actors are funded by observing the transfer events // in the transactions results. func (s *relaysSuite) ensureFundedActors( - txResults []*types.TxResult, + ctx context.Context, actors []*accountInfo, ) { - for _, actor := range actors { - actorFunded := false - for _, txResult := range txResults { - for _, event := range txResult.Result.Events { - // Skip non-relevant events. - if event.Type != "transfer" { - continue - } - - attrs := event.Attributes - // Check if the actor is the recipient of the transfer event. - if actorFunded = hasEventAttr(attrs, "recipient", actor.address); actorFunded { - break - } + fundedActors := make(map[string]struct{}) + + ctx, cancel := context.WithCancel(ctx) + abciEventsObs := eventsObsWithNumBlocksTimeout(ctx, s.eventsObs, 3, cancel) + channel.ForEach(ctx, abciEventsObs, func(ctx context.Context, events []types.Event) { + for _, event := range events { + // Skip non-relevant events. + if event.GetType() != "transfer" { + continue } - // If the actor is funded, no need to check the other transactions. - if actorFunded { - break + attrs := event.GetAttributes() + // Check if the actor is the recipient of the transfer event. + if fundedActorAddr, ok := getEventAttr(attrs, "recipient"); ok { + fundedActors[fundedActorAddr] = struct{}{} } } - // If no transfer event is found for the actor, the test is canceled. - if !actorFunded { - s.logAndAbortTest(txResults, "actor not funded") - return + if allActorsFunded(actors, fundedActors) { + cancel() } + }) + + <-ctx.Done() + if !allActorsFunded(actors, fundedActors) { + s.logAndAbortTest("actor not funded") } } +func allActorsFunded(expectedActors []*accountInfo, fundedActors map[string]struct{}) bool { + for _, actor := range expectedActors { + if _, ok := fundedActors[actor.address]; !ok { + return false + } + } + + return true +} + // ensureStakedActors checks if the actors are staked by observing the message events // in the transactions results. func (s *relaysSuite) ensureStakedActors( - txResults []*types.TxResult, - msg string, + ctx context.Context, actors []*accountInfo, ) { - for _, actor := range actors { - actorStaked := false - for _, txResult := range txResults { - for _, event := range txResult.Result.Events { - // Skip non-relevant events. - if event.Type != "message" { - continue - } - - attrs := event.Attributes - // Check if the actor is the sender of the message event. - if hasEventAttr(attrs, "action", msg) && hasEventAttr(attrs, "sender", actor.address) { - actorStaked = true - break - } + stakedActors := make(map[string]struct{}) + + ctx, cancel := context.WithCancel(ctx) + abciEventsObs := eventsObsWithNumBlocksTimeout(ctx, s.eventsObs, 3, cancel) + typedEventsObs := abciEventsToTypedEvents(ctx, abciEventsObs) + channel.ForEach(ctx, typedEventsObs, func(ctx context.Context, blockEvents []proto.Message) { + for _, event := range blockEvents { + switch e := event.(type) { + case *suppliertypes.EventSupplierStaked: + stakedActors[e.Supplier.GetOperatorAddress()] = struct{}{} + case *gatewaytypes.EventGatewayStaked: + stakedActors[e.Gateway.GetAddress()] = struct{}{} + case *apptypes.EventApplicationStaked: + stakedActors[e.Application.GetAddress()] = struct{}{} } + } - // If the actor is staked, no need to check the other transactions. - if actorStaked { - break - } + if allActorsStaked(actors, stakedActors) { + cancel() } + }) + + <-ctx.Done() + if !allActorsStaked(actors, stakedActors) { + s.logAndAbortTest("actor not staked") + return + } +} - // If no message event is found for the actor, log the transaction results - // and cancel the test. - if !actorStaked { - s.logAndAbortTest(txResults, fmt.Sprintf("actor not staked: %s", actor.address)) - return +func allActorsStaked(expectedActors []*accountInfo, stakedActors map[string]struct{}) bool { + for _, actor := range expectedActors { + if _, ok := stakedActors[actor.address]; !ok { + return false } } + + return true } // ensureDelegatedActors checks if the actors are delegated by observing the // delegation events in the transactions results. func (s *relaysSuite) ensureDelegatedApps( - txResults []*types.TxResult, + ctx context.Context, applications, gateways []*accountInfo, ) { - for _, application := range applications { - numDelegatees := 0 - for _, txResult := range txResults { - for _, event := range txResult.Result.Events { - // Skip non-EventDelegation events. - if event.Type != EventTypeRedelegation { - continue - } + appsToGateways := make(map[string][]string) + + ctx, cancel := context.WithCancel(ctx) + abciEventsObs := eventsObsWithNumBlocksTimeout(ctx, s.eventsObs, 3, cancel) + typedEventsObs := abciEventsToTypedEvents(ctx, abciEventsObs) + channel.ForEach(ctx, typedEventsObs, func(ctx context.Context, blockEvents []proto.Message) { + for _, event := range blockEvents { + redelegationEvent, ok := event.(*apptypes.EventRedelegation) + if ok { + app := redelegationEvent.GetApplication() + appsToGateways[app.GetAddress()] = app.GetDelegateeGatewayAddresses() + } + } - attrs := event.Attributes - appAddr := fmt.Sprintf("%q", application.address) - // Skip the event if the application is not the delegator. - if !hasEventAttr(attrs, "app_address", appAddr) { - break - } + if allAppsDelegatedToAllGateways(applications, gateways, appsToGateways) { + cancel() + } + }) - // Check if the application is delegated to each of the gateways. - for _, gateway := range gateways { - gwAddr := fmt.Sprintf("%q", gateway.address) - if hasEventAttr(attrs, "gateway_address", gwAddr) { - numDelegatees++ - break - } - } - } + <-ctx.Done() + if !allAppsDelegatedToAllGateways(applications, gateways, appsToGateways) { + s.logAndAbortTest("applications not delegated to all gateways") + return + } +} + +func allAppsDelegatedToAllGateways( + applications, gateways []*accountInfo, + appsToGateways map[string][]string, +) bool { + for _, app := range applications { + if _, ok := appsToGateways[app.address]; !ok { + return false } - // If the number of delegatees is not equal to the number of gateways, - // the test is canceled. - if numDelegatees != len(gateways) { - s.logAndAbortTest(txResults, "applications not delegated to all gateways") - return + for _, gateway := range gateways { + if !slices.Contains(appsToGateways[app.address], gateway.address) { + return false + } } } + + return true } // getRelayCost fetches the relay cost from the tokenomics module. @@ -1188,6 +1219,7 @@ func (s *relaysSuite) getRelayCost() int64 { res, err := sharedClient.Params(s.ctx, &sharedtypes.QueryParamsRequest{}) require.NoError(s, err) + // multiply by the CUPR return int64(res.Params.ComputeUnitsToTokensMultiplier) } @@ -1242,15 +1274,15 @@ func (s *relaysSuite) activatePreparedActors(notif *sessionInfoNotif) { } } -// hasEventAttr checks if the event attributes contain a given key-value pair. -func hasEventAttr(attributes []types.EventAttribute, key, value string) bool { +// getEventAttr returns the event attribute value corresponding to the provided key. +func getEventAttr(attributes []types.EventAttribute, key string) (value string, found bool) { for _, attribute := range attributes { - if attribute.Key == key && attribute.Value == value { - return true + if attribute.Key == key { + return value, true } } - return false + return "", false } // sendAdjustMaxDelegationsParamTx sends a transaction to adjust the max_delegated_gateways @@ -1258,20 +1290,17 @@ func hasEventAttr(attributes []types.EventAttribute, key, value string) bool { func (s *relaysSuite) sendAdjustMaxDelegationsParamTx(maxGateways int64) { authority := authtypes.NewModuleAddress(govtypes.ModuleName).String() - appMsgUpdateParams := &apptypes.MsgUpdateParams{ + appMsgUpdateMaxDelegatedGatewaysParam := &apptypes.MsgUpdateParam{ Authority: authority, - Params: apptypes.Params{ - // Set the max_delegated_gateways parameter to the number of gateways - // that are currently used in the test. - MaxDelegatedGateways: uint64(maxGateways), - }, + Name: "max_delegated_gateways", + AsType: &apptypes.MsgUpdateParam_AsUint64{AsUint64: uint64(maxGateways)}, } - appMsgUpdateParamsAny, err := codectypes.NewAnyWithValue(appMsgUpdateParams) + appMsgUpdateParamAny, err := codectypes.NewAnyWithValue(appMsgUpdateMaxDelegatedGatewaysParam) require.NoError(s, err) authzExecMsg := &authz.MsgExec{ Grantee: s.fundingAccountInfo.address, - Msgs: []*codectypes.Any{appMsgUpdateParamsAny}, + Msgs: []*codectypes.Any{appMsgUpdateParamAny}, } s.fundingAccountInfo.addPendingMsg(authzExecMsg) @@ -1290,7 +1319,7 @@ func (s *relaysSuite) ensureUpdatedMaxDelegations(maxGateways int64) { res, err := appClient.Params(s.ctx, &apptypes.QueryParamsRequest{}) require.NoError(s, err) - if res.Params.MaxDelegatedGateways != uint64(maxGateways) { + if res.Params.MaxDelegatedGateways < uint64(maxGateways) { s.cancelCtx() s.Fatal("Failed to update max delegated gateways parameter") } @@ -1336,24 +1365,29 @@ func (s *relaysSuite) parseActorLoadTestIncrementPlans( // countClaimAndProofs asynchronously counts the number of claim and proof messages // in the observed transaction events. -func (s *relaysSuite) countClaimAndProofs() { +func (s *relaysSuite) forEachSettlement(ctx context.Context) { + typedEventsObs := abciEventsToTypedEvents(ctx, s.eventsObs) channel.ForEach( s.ctx, - s.newTxEventsObs, - func(ctx context.Context, txEvent *types.TxResult) { - for _, event := range txEvent.Result.Events { - if event.Type != "message" { - continue - } - - if hasEventAttr(event.Attributes, "action", EventActionMsgCreateClaim) { - s.currentClaimCount++ + typedEventsObs, + func(ctx context.Context, events []proto.Message) { + for _, event := range events { + switch e := event.(type) { + case *tokenomicstypes.EventApplicationOverserviced: + s.tokenomics.OverservicedApplications = append(s.tokenomics.OverservicedApplications, e) + case *tokenomicstypes.EventApplicationReimbursementRequest: + s.tokenomics.ReimbursementRequests = append(s.tokenomics.ReimbursementRequests, e) + case *tokenomicstypes.EventClaimExpired: + s.tokenomics.ExpiredClaims = append(s.tokenomics.ExpiredClaims, e) + case *tokenomicstypes.EventClaimSettled: + s.tokenomics.ClaimsSettled = append(s.tokenomics.ClaimsSettled, e) + case *tokenomicstypes.EventSupplierSlashed: + s.tokenomics.SuppliersSlashed = append(s.tokenomics.SuppliersSlashed, e) + case *prooftypes.EventClaimCreated: + s.tokenomics.ClaimsSubmitted = append(s.tokenomics.ClaimsSubmitted, e) + case *prooftypes.EventProofSubmitted: + s.tokenomics.ProofsSubmitted = append(s.tokenomics.ProofsSubmitted, e) } - - if hasEventAttr(event.Attributes, "action", EventActionMsgSubmitProof) { - s.currentProofCount++ - } - } }, ) @@ -1379,19 +1413,38 @@ func (s *relaysSuite) querySharedParams(queryNodeRPCURL string) { s.sharedParams = sharedParams } +// queryAppParams queries the current on-chain application module parameters for use +// over the duration of the test. +func (s *relaysSuite) queryAppParams(queryNodeRPCURL string) { + s.Helper() + + deps := depinject.Supply(s.txContext.GetClientCtx()) + + blockQueryClient, err := sdkclient.NewClientFromNode(queryNodeRPCURL) + require.NoError(s, err) + deps = depinject.Configs(deps, depinject.Supply(blockQueryClient)) + + appQueryclient, err := query.NewApplicationQuerier(deps) + require.NoError(s, err) + + appParams, err := appQueryclient.GetParams(s.ctx) + require.NoError(s, err) + + s.appParams = appParams +} + // forEachStakedAndDelegatedAppPrepareApp is a ForEachFn that waits for txs which // were broadcast in previous pipeline stages have been committed. It ensures that // new applications were successfully staked and all application actors are delegated // to all gateways. Then it adds the new application actors to the prepared set, to // be activated & used in the next session. -func (s *relaysSuite) forEachStakedAndDelegatedAppPrepareApp(_ context.Context, notif *stakingInfoNotif) { - // Wait for the next block to commit staking and delegation transactions - // and be able to send relay requests evenly distributed across all gateways. - txResults := s.waitForTxsToBeCommitted() - s.ensureStakedActors(txResults, EventActionMsgStakeApplication, notif.newApps) - s.ensureDelegatedApps(txResults, s.activeApplications, notif.newGateways) - s.ensureDelegatedApps(txResults, notif.newApps, notif.newGateways) - s.ensureDelegatedApps(txResults, notif.newApps, s.activeGateways) +func (s *relaysSuite) forEachStakedAndDelegatedAppPrepareApp(ctx context.Context, notif *stakingInfoNotif) { + s.WaitAll( + func() { s.ensureStakedActors(ctx, notif.newApps) }, + func() { s.ensureDelegatedApps(ctx, s.activeApplications, notif.newGateways) }, + func() { s.ensureDelegatedApps(ctx, notif.newApps, notif.newGateways) }, + func() { s.ensureDelegatedApps(ctx, notif.newApps, s.activeGateways) }, + ) // Add the new applications to the list of prepared applications to be activated in // the next session. @@ -1453,12 +1506,7 @@ func (s *relaysSuite) forEachRelayBatchSendBatch(_ context.Context, relayBatchIn batchWaitGroup.Wait() } -func (s *relaysSuite) logAndAbortTest(txResults []*types.TxResult, errorMsg string) { - for _, txResult := range txResults { - if txResult.Result.Log != "" { - logger.Error().Msgf("tx result log: %s", txResult.Result.Log) - } - } +func (s *relaysSuite) logAndAbortTest(errorMsg string) { s.cancelCtx() s.Fatal(errorMsg) } @@ -1479,3 +1527,64 @@ func (s *relaysSuite) populateWithKnownGateways() (gateways []*accountInfo) { return gateways } + +func (s *relaysSuite) WaitAll(waitFunc ...func()) { + wg := sync.WaitGroup{} + wg.Add(len(waitFunc)) + + for _, f := range waitFunc { + go func(f func()) { + f() + wg.Done() + }(f) + } + + wg.Wait() +} + +func eventsObsWithNumBlocksTimeout( + ctx context.Context, + eventsObs observable.Observable[[]types.Event], + numBlocksTimeout int, + cancel func(), +) observable.Observable[[]types.Event] { + return channel.Map(ctx, eventsObs, func(ctx context.Context, blockEvents []types.Event) ([]types.Event, bool) { + if numBlocksTimeout < 0 { + cancel() + } + + numBlocksTimeout-- + return blockEvents, false + }) +} + +func forEachTypedEventFn(fn func(ctx context.Context, blockEvents []proto.Message)) func(ctx context.Context, blockEvents []*types.Event) { + return func(ctx context.Context, blockEvents []*types.Event) { + var typedEvents []proto.Message + for _, event := range blockEvents { + typedEvent, err := sdk.ParseTypedEvent(*event) + if err != nil { + continue + } + + typedEvents = append(typedEvents, typedEvent) + } + fn(ctx, typedEvents) + } +} + +func abciEventsToTypedEvents(ctx context.Context, abciEventObs observable.Observable[[]types.Event]) observable.Observable[[]proto.Message] { + return channel.Map(ctx, abciEventObs, func(ctx context.Context, blockEvents []types.Event) ([]proto.Message, bool) { + var typedEvents []proto.Message + for _, event := range blockEvents { + typedEvent, err := sdk.ParseTypedEvent(event) + if err != nil { + continue + } + + typedEvents = append(typedEvents, typedEvent) + } + + return typedEvents, false + }) +} diff --git a/load-testing/tests/relays_stress_single_suppier.feature b/load-testing/tests/relays_stress_signle_supplier.feature similarity index 100% rename from load-testing/tests/relays_stress_single_suppier.feature rename to load-testing/tests/relays_stress_signle_supplier.feature diff --git a/load-testing/tests/relays_stress_test.go b/load-testing/tests/relays_stress_test.go index 5aa7fbb65..81e09dc35 100644 --- a/load-testing/tests/relays_stress_test.go +++ b/load-testing/tests/relays_stress_test.go @@ -4,6 +4,7 @@ package tests import ( "context" + "math/big" "net/url" "path/filepath" "runtime" @@ -18,6 +19,7 @@ import ( "github.com/regen-network/gocuke" "github.com/stretchr/testify/require" + "github.com/pokt-network/poktroll/app/volatile" "github.com/pokt-network/poktroll/cmd/signals" "github.com/pokt-network/poktroll/pkg/client" "github.com/pokt-network/poktroll/pkg/observable" @@ -25,7 +27,11 @@ import ( "github.com/pokt-network/poktroll/testutil/testclient" "github.com/pokt-network/poktroll/testutil/testclient/testblock" "github.com/pokt-network/poktroll/testutil/testclient/testtx" + apptypes "github.com/pokt-network/poktroll/x/application/types" + prooftypes "github.com/pokt-network/poktroll/x/proof/types" sharedtypes "github.com/pokt-network/poktroll/x/shared/types" + tokenomicskeeper "github.com/pokt-network/poktroll/x/tokenomics/keeper" + tokenomicstypes "github.com/pokt-network/poktroll/x/tokenomics/types" ) // The following constants are used to identify the different types of transactions, @@ -91,7 +97,8 @@ var ( blockDuration = int64(2) // newTxEventSubscriptionQuery is the format string which yields a subscription // query to listen for on-chain Tx events. - newTxEventSubscriptionQuery = "tm.event='Tx'" + newTxEventSubscriptionQuery = "tm.event='Tx'" + newBlockEventSubscriptionQuery = "tm.event='NewBlock'" // eventsReplayClientBufferSize is the buffer size for the events replay client // for the subscriptions above. eventsReplayClientBufferSize = 100 @@ -127,16 +134,16 @@ type relaysSuite struct { // batchInfoObs is the observable mapping session information to batch information. // It is used to determine when to send a batch of relay requests to the network. batchInfoObs observable.Observable[*relayBatchInfoNotif] - // newTxEventsObs is the observable that notifies the test suite of new - // transactions committed on-chain. - // It is used to check the results of the transactions sent by the test suite. - newTxEventsObs observable.Observable[*types.TxResult] // txContext is the transaction context used to sign and send transactions. txContext client.TxContext // sharedParams is the shared on-chain parameters used in the test. // It is queried at the beginning of the test. sharedParams *sharedtypes.Params + // appParams is the application on-chain parameters used in the test. + // It is queried at the beginning of the test. + appParams *apptypes.Params + // numRelaysSent is the number of relay requests sent during the test. numRelaysSent atomic.Uint64 // relayRatePerApp is the rate of relay requests sent per application per second. @@ -224,6 +231,46 @@ type relaysSuite struct { // isEphemeralChain is a flag that indicates whether the test is expected to be // run on ephemeral chain setups like localnet or long living ones (i.e. Test/DevNet). isEphemeralChain bool + + eventsObs observable.Observable[[]types.Event] + + tokenomics *tokenomics +} + +type tokenomics struct { + // OverservicedApplications is the list of applications that are overserviced. + OverservicedApplications []*tokenomicstypes.EventApplicationOverserviced + // SuppliersSlashed is the list of suppliers that are slashed. + SuppliersSlashed []*tokenomicstypes.EventSupplierSlashed + // ExpiredClaims is the list of claims that are expired. + ExpiredClaims []*tokenomicstypes.EventClaimExpired + // ReimbursementRequests is the list of reimbursement requests. + ReimbursementRequests []*tokenomicstypes.EventApplicationReimbursementRequest + // ClaimsSettled is the list of claims that are settled. + ClaimsSettled []*tokenomicstypes.EventClaimSettled + // ClaimsSubmitted is the list of claims that are submitted. + ClaimsSubmitted []*prooftypes.EventClaimCreated + // ProofsSubmitted is the list of proofs that are submitted. + ProofsSubmitted []*prooftypes.EventProofSubmitted + // ActorsBalances is the balances of the actors on-chain. + ActorsBalances actorsBalances +} + +type actorsBalances struct { + ApplicationBalances map[string]sdk.Coin + ApplicationStakes map[string]sdk.Coin + GatewaysBalances map[string]sdk.Coin + GatewaysStakes map[string]sdk.Coin + SupplierBalances map[string]sdk.Coin + SupplierStakes map[string]sdk.Coin + + ApplicationModuleAccountBalance sdk.Coin + SupplierModuleAccountBalance sdk.Coin + GatewayModuleAccountBalance sdk.Coin + TokenomicsModuleAccountBalance sdk.Coin + DAOAccountBalance sdk.Coin + ProposerAccountBalance sdk.Coin + SourceOwnerAccountBalance sdk.Coin } // accountInfo contains the account info needed to build and send transactions. @@ -271,7 +318,7 @@ func TestLoadRelays(t *testing.T) { } func TestLoadRelaysSingleSupplier(t *testing.T) { - gocuke.NewRunner(t, &relaysSuite{}).Path(filepath.Join(".", "relays_stress_single_suppier.feature")).Run() + gocuke.NewRunner(t, &relaysSuite{}).Path(filepath.Join(".", "relays_stress_single_supplier.feature")).Run() } func (s *relaysSuite) LocalnetIsRunning() { @@ -359,11 +406,14 @@ func (s *relaysSuite) LocalnetIsRunning() { s.initFundingAccount(loadTestParams.FundingAccountAddress) // Initialize the on-chain claims and proofs counter. - s.countClaimAndProofs() + s.forEachSettlement(s.ctx) // Query for the current shared on-chain params. s.querySharedParams(loadTestParams.TestNetNode) + // Query for the current app on-chain params. + s.queryAppParams(loadTestParams.TestNetNode) + // Some suppliers may already be staked at genesis, ensure that staking during // this test succeeds by increasing the sake amount. minStakeAmount := s.getProvisionedActorsCurrentStakedAmount() @@ -408,7 +458,6 @@ func (s *relaysSuite) MoreActorsAreStakedAsFollows(table gocuke.DataTable) { // This is to ensure that requests are distributed evenly across all gateways // at any given time. s.sendAdjustMaxDelegationsParamTx(s.plans.gateways.maxActorCount) - s.waitForTxsToBeCommitted() s.ensureUpdatedMaxDelegations(s.plans.gateways.maxActorCount) } @@ -418,10 +467,9 @@ func (s *relaysSuite) MoreActorsAreStakedAsFollows(table gocuke.DataTable) { fundedSuppliers, fundedGateways, fundedApplications := s.sendFundAvailableActorsTx() // Funding messages are sent in a single transaction by the funding account, // only one transaction is expected to be committed. - txResults := s.waitForTxsToBeCommitted() - s.ensureFundedActors(txResults, fundedSuppliers) - s.ensureFundedActors(txResults, fundedGateways) - s.ensureFundedActors(txResults, fundedApplications) + fundedActors := append(fundedSuppliers, fundedGateways...) + fundedActors = append(fundedActors, fundedApplications...) + s.ensureFundedActors(s.ctx, fundedActors) logger.Info().Msg("Actors funded") @@ -430,11 +478,11 @@ func (s *relaysSuite) MoreActorsAreStakedAsFollows(table gocuke.DataTable) { gateways := fundedGateways[:s.gatewayInitialCount] applications := fundedApplications[:s.appInitialCount] + stakedActors := append(suppliers, gateways...) + stakedActors = append(stakedActors, applications...) + s.sendInitialActorsStakeMsgs(suppliers, gateways, applications) - txResults = s.waitForTxsToBeCommitted() - s.ensureStakedActors(txResults, EventActionMsgStakeSupplier, suppliers) - s.ensureStakedActors(txResults, EventActionMsgStakeGateway, gateways) - s.ensureStakedActors(txResults, EventActionMsgStakeApplication, applications) + s.ensureStakedActors(s.ctx, stakedActors) logger.Info().Msg("Actors staked") @@ -450,8 +498,7 @@ func (s *relaysSuite) MoreActorsAreStakedAsFollows(table gocuke.DataTable) { // Delegate the initial applications to the initial gateways s.sendDelegateInitialAppsTxs(applications, gateways) - txResults = s.waitForTxsToBeCommitted() - s.ensureDelegatedApps(txResults, applications, gateways) + s.ensureDelegatedApps(s.ctx, applications, gateways) logger.Info().Msg("Apps delegated") @@ -508,7 +555,7 @@ func (s *relaysSuite) ALoadOfConcurrentRelayRequestsAreSentFromTheApplications() // Block the feature step until the test is done. <-s.ctx.Done() } -func (s *relaysSuite) TheCorrectPairsCountOfClaimAndProofMessagesShouldBeCommittedOnchain() { +func (s *relaysSuite) TheCorrectCountOfClaimsAndProofsSubmittedOnChain() { logger.Info(). Int("claims", s.currentClaimCount). Int("proofs", s.currentProofCount). @@ -534,3 +581,105 @@ func (s *relaysSuite) TheCorrectPairsCountOfClaimAndProofMessagesShouldBeCommitt // "unexpected claims and proofs count", //) } + +func (s *relaysSuite) OverServicingEventsIsObserved(numEvents int64) { + require.Equal(s, s.tokenomics.OverservicedApplications, numEvents) +} + +func (s *relaysSuite) SlashingEventsIsObserved(numEvents int64) { + require.Equal(s, s.tokenomics.SuppliersSlashed, numEvents) +} + +func (s *relaysSuite) SlashingExpiredClaimEventIsObserved(numEvents int64) { + require.Equal(s, s.tokenomics.ExpiredClaims, numEvents) +} + +func (s *relaysSuite) ThereIsAsManyReimbursmentRequestAsTheNumberOfSettledClaims() { + require.Equal(s, len(s.tokenomics.ReimbursementRequests), len(s.tokenomics.ClaimsSettled)) +} + +func (s *relaysSuite) TheNumberOfClaimsSubmittedAndClaimsSettledIsTheSame() { + require.Equal(s, len(s.tokenomics.ClaimsSettled), len(s.tokenomics.ClaimsSubmitted)) +} + +func (s *relaysSuite) TheNumberOfProofsSubmittedAndProofsRequiredIsTheSame() { + numProofRequiredObserved := 0 + for _, claimEvent := range s.tokenomics.ClaimsSettled { + if claimEvent.ProofRequirement != prooftypes.ProofRequirementReason_NOT_REQUIRED { + numProofRequiredObserved++ + } + } + + require.Len(s, s.tokenomics.ProofsSubmitted, numProofRequiredObserved) +} + +func (s *relaysSuite) TheActorsOnChainBalancesAreAsExpected() { + balances := s.tokenomics.ActorsBalances + + for _, claimSettlement := range s.tokenomics.ClaimsSettled { + settledUPOKT := claimSettlement.SettledUpokt + claim := claimSettlement.Claim + + claimSupplierAddr := claim.SupplierOperatorAddress + _, ok := balances.SupplierBalances[claimSupplierAddr] + require.True(s, ok, "supplier expected balance not found") + + claimAppAddr := claim.SessionHeader.ApplicationAddress + _, ok = balances.SupplierBalances[claimAppAddr] + require.True(s, ok, "application expected balance not found") + + // account for GMI + mintUPOKT := s.getGlobalInflationMintedUPOKT(settledUPOKT) + + // TODO_IN_THIS_PR: Should check with multiple supplier owners + supplierMintUPOKT := s.getGlobalInflationActorAllocation(mintUPOKT, tokenomicskeeper.MintAllocationSupplier) + balances.SupplierBalances[claimSupplierAddr] = balances.SupplierBalances[claimSupplierAddr]. + Add(*settledUPOKT). + Add(supplierMintUPOKT) + + applicationMintUPOKT := s.getGlobalInflationActorAllocation(mintUPOKT, tokenomicskeeper.MintAllocationApplication) + balances.ApplicationBalances[claimAppAddr] = balances.ApplicationBalances[claimAppAddr]. + Add(applicationMintUPOKT) + + balances.ApplicationStakes[claimAppAddr] = balances.ApplicationStakes[claimAppAddr]. + Sub(*settledUPOKT). + Sub(mintUPOKT) + + balances.ApplicationModuleAccountBalance = balances.ApplicationModuleAccountBalance. + Sub(*settledUPOKT). + Sub(mintUPOKT) + + daoMintUPOKT := s.getGlobalInflationActorAllocation(mintUPOKT, tokenomicskeeper.MintAllocationDAO) + balances.DAOAccountBalance = balances.DAOAccountBalance. + Add(daoMintUPOKT). + Add(mintUPOKT) + + proposerMintUPOKT := s.getGlobalInflationActorAllocation(mintUPOKT, tokenomicskeeper.MintAllocationProposer) + balances.ProposerAccountBalance = balances.ProposerAccountBalance. + Add(proposerMintUPOKT) + + sourceOwnerMintUPOKT := s.getGlobalInflationActorAllocation(mintUPOKT, tokenomicskeeper.MintAllocationSourceOwner) + balances.SourceOwnerAccountBalance = balances.SourceOwnerAccountBalance. + Add(sourceOwnerMintUPOKT) + } + + for _, proofSubmission := range s.tokenomics.ProofsSubmitted { + balances.SupplierBalances[proofSubmission.SupplierOperatorAddress] = balances.SupplierBalances[proofSubmission.SupplierOperatorAddress]. + } +} + +func (s *relaysSuite) getGlobalInflationMintedUPOKT(settledUPOKT *sdk.Coin) sdk.Coin { + settlementAmtFloat := new(big.Float).SetUint64(settledUPOKT.Amount.Uint64()) + newMintAmtFloat := new(big.Float).Mul(settlementAmtFloat, big.NewFloat(tokenomicskeeper.GlobalInflationPerClaim)) + newMintAmtInt, _ := newMintAmtFloat.Int64() + mintUPOKT := sdk.NewCoin(volatile.DenomuPOKT, math.NewInt(newMintAmtInt)) + return mintUPOKT +} + +func (s *relaysSuite) getGlobalInflationActorAllocation(mintUPOKT sdk.Coin, allocation float64) sdk.Coin { + mintAmtFloat := new(big.Float).SetInt(mintUPOKT.Amount.BigInt()) + actorAllocationFloat := new(big.Float).Mul(mintAmtFloat, big.NewFloat(allocation)) + actorAllocationInt, _ := actorAllocationFloat.Int64() + actorAllocation := sdk.NewCoin(volatile.DenomuPOKT, math.NewInt(actorAllocationInt)) + return actorAllocation +} diff --git a/pkg/client/interface.go b/pkg/client/interface.go index da564c1e2..f64d888ec 100644 --- a/pkg/client/interface.go +++ b/pkg/client/interface.go @@ -272,6 +272,8 @@ type ApplicationQueryClient interface { // GetAllApplications queries all on-chain applications GetAllApplications(ctx context.Context) ([]apptypes.Application, error) + + GetParams(ctx context.Context) (*apptypes.Params, error) } // SupplierQueryClient defines an interface that enables the querying of the diff --git a/pkg/client/query/appquerier.go b/pkg/client/query/appquerier.go index 9477c35f9..e4bb3149b 100644 --- a/pkg/client/query/appquerier.go +++ b/pkg/client/query/appquerier.go @@ -62,3 +62,13 @@ func (aq *appQuerier) GetAllApplications(ctx context.Context) ([]apptypes.Applic } return res.Applications, nil } + +// GetParams returns all staked applications +func (aq *appQuerier) GetParams(ctx context.Context) (*apptypes.Params, error) { + req := apptypes.QueryParamsRequest{} + res, err := aq.applicationQuerier.Params(ctx, &req) + if err != nil { + return &apptypes.Params{}, err + } + return &res.Params, nil +} diff --git a/pkg/relayer/session/sessiontree.go b/pkg/relayer/session/sessiontree.go index 243862218..bf83cf0ad 100644 --- a/pkg/relayer/session/sessiontree.go +++ b/pkg/relayer/session/sessiontree.go @@ -21,13 +21,6 @@ import ( var _ relayer.SessionTree = (*sessionTree)(nil) // sessionTree is an implementation of the SessionTree interface. -// TODO_BETA(@red-0ne): Per the Relay Mining paper, we need to optimistically store -// the number of requests that an application can pay for. This needs to be tracked -// based on the app's stake in the beginning of a session and the number of nodes -// per session. An operator should be able to specify "overservicing_compute_units_limit" -// whereby an upper bound on how much it can overserviced an application is set. The -// default value for this should be -1, implying "unlimited". -// Ref discussion: https://github.com/pokt-network/poktroll/pull/755#discussion_r1737287860 type sessionTree struct { logger polylog.Logger @@ -75,15 +68,6 @@ type sessionTree struct { // NewSessionTree creates a new sessionTree from a Session and a storePrefix. It also takes a function // removeFromRelayerSessions that removes the sessionTree from the RelayerSessionsManager. // It returns an error if the KVStore fails to be created. -// -// TODO_BETA(@red-0ne): When starting a new session, check what the MaxClaimableAmount -// (in uPOKT) by the Supplier as a function of -// (app_stake, compute_units_per_relay_for_service, global_compute_units_to_token_multiplier). -// TODO_CONFIG_NOTE: Whether or not the RelayMiner stop handling requests when the max is reached should be -// configurable by the operator. -// TODO_ERROR_NOTE: If overservicing is set to false, create a new error that the relay is rejected -// specifically because the supplier has reached the max claimable amount, so the caller should relay -// the request to another supplier. func NewSessionTree( sessionHeader *sessiontypes.SessionHeader, supplierOperatorAddress *cosmostypes.AccAddress, diff --git a/x/proof/keeper/proof_validation.go b/x/proof/keeper/proof_validation.go index 778d66d8c..850c97f5b 100644 --- a/x/proof/keeper/proof_validation.go +++ b/x/proof/keeper/proof_validation.go @@ -251,10 +251,6 @@ func (k Keeper) validateClosestPath( // be received before proceeding. proofPathSeedBlockHash := k.sessionKeeper.GetBlockHash(ctx, earliestSupplierProofCommitHeight-1) - // TODO_BETA(@red-0ne): Investigate "proof for the path provided does not match one expected by the on-chain protocol" - // error that may occur due to block height differing from the off-chain part. - k.logger.Info("E2E_DEBUG: height for block hash when verifying the proof", earliestSupplierProofCommitHeight, sessionHeader.GetSessionId()) - expectedProofPath := protocol.GetPathForProof(proofPathSeedBlockHash, sessionHeader.GetSessionId()) if !bytes.Equal(proof.Path, expectedProofPath) { return types.ErrProofInvalidProof.Wrapf( diff --git a/x/proof/types/application_query_client.go b/x/proof/types/application_query_client.go index 1cd887314..73bf5f5b7 100644 --- a/x/proof/types/application_query_client.go +++ b/x/proof/types/application_query_client.go @@ -42,3 +42,9 @@ func (appQueryClient *AppKeeperQueryClient) GetApplication( func (appQueryClient *AppKeeperQueryClient) GetAllApplications(ctx context.Context) ([]apptypes.Application, error) { return appQueryClient.keeper.GetAllApplications(ctx), nil } + +// GetAllApplications returns all the applications in the application store. +func (appQueryClient *AppKeeperQueryClient) GetParams(ctx context.Context) (*apptypes.Params, error) { + params := appQueryClient.keeper.GetParams(ctx) + return ¶ms, nil +} diff --git a/x/proof/types/expected_keepers.go b/x/proof/types/expected_keepers.go index 66103d2b8..9a89077f5 100644 --- a/x/proof/types/expected_keepers.go +++ b/x/proof/types/expected_keepers.go @@ -49,6 +49,7 @@ type ApplicationKeeper interface { GetApplication(ctx context.Context, address string) (app apptypes.Application, found bool) GetAllApplications(ctx context.Context) []apptypes.Application SetApplication(context.Context, apptypes.Application) + GetParams(ctx context.Context) apptypes.Params } // SharedKeeper defines the expected interface needed to retrieve shared information. diff --git a/x/tokenomics/types/event.pb.go b/x/tokenomics/types/event.pb.go index 5e69f719f..756be750e 100644 --- a/x/tokenomics/types/event.pb.go +++ b/x/tokenomics/types/event.pb.go @@ -161,6 +161,7 @@ type EventClaimSettled struct { // The uPOKT coin claimed to be rewarded for the work done as a function of // the number of estimated compute units and the compute uints to token multiplier. ClaimedUpokt *types1.Coin `protobuf:"bytes,6,opt,name=claimed_upokt,json=claimedUpokt,proto3" json:"claimed_upokt"` + SettledUpokt *types1.Coin `protobuf:"bytes,6,opt,name=settled_upokt,json=claimedUpokt,proto3" json:"claimed_upokt"` } func (m *EventClaimSettled) Reset() { *m = EventClaimSettled{} } From 1cb995c6e17589e35a902b25112cc982c2679614 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Mon, 11 Nov 2024 16:16:34 +0100 Subject: [PATCH 50/53] chore: Address review change requests --- config.yml | 3 +- pkg/relayer/miner/miner.go | 27 +++++++++------ pkg/relayer/miner/miner_test.go | 8 ++--- pkg/relayer/proxy/errors.go | 1 + pkg/relayer/proxy/proxy.go | 2 +- pkg/relayer/proxy/relay_meter.go | 35 +++++++++++--------- x/shared/types/session.go | 10 ++++++ x/tokenomics/keeper/settle_pending_claims.go | 2 ++ x/tokenomics/keeper/token_logic_modules.go | 19 ++++++----- 9 files changed, 66 insertions(+), 41 deletions(-) diff --git a/config.yml b/config.yml index b98f4229d..31566e815 100644 --- a/config.yml +++ b/config.yml @@ -147,7 +147,8 @@ genesis: # Application module - address: pokt1rl3gjgzexmplmds3tq3r3yk84zlwdl6djzgsvm coins: - # TODO_MAINNET: Pass config.yml into ChatGPT to build a script that ensures the amounts line up + # TODO_MAINNET(@olshansk): Pass config.yml into ChatGPT to build a script + # that ensures the amounts line up - amount: "200000136" # MUST BE equal to the total of all app stakes below denom: upokt # Supplier module diff --git a/pkg/relayer/miner/miner.go b/pkg/relayer/miner/miner.go index 4c309ff2f..83cd4a8a8 100644 --- a/pkg/relayer/miner/miner.go +++ b/pkg/relayer/miner/miner.go @@ -89,9 +89,8 @@ func (mnr *miner) mapMineRelay( ) (_ either.Either[*relayer.MinedRelay], skip bool) { relayBz, err := relay.Marshal() if err != nil { - meteringError := mnr.relayMeter.SetNonApplicableRelayReward(ctx, relay.GetReq().GetMeta()) - if meteringError != nil { - return either.Error[*relayer.MinedRelay](fmt.Errorf("failed to unclaim relay price: %w", meteringError)), false + if relayMeteringResult := mnr.unclaimRelayUPOKT(ctx, *relay); relayMeteringResult.IsError() { + return relayMeteringResult, false } return either.Error[*relayer.MinedRelay](err), false } @@ -100,18 +99,16 @@ func (mnr *miner) mapMineRelay( relayDifficultyTargetHash, err := mnr.getServiceRelayDifficultyTargetHash(ctx, relay.Req) if err != nil { - meteringError := mnr.relayMeter.SetNonApplicableRelayReward(ctx, relay.GetReq().GetMeta()) - if meteringError != nil { - return either.Error[*relayer.MinedRelay](fmt.Errorf("failed to unclaim relay price: %w", meteringError)), false + if relayMeteringResult := mnr.unclaimRelayUPOKT(ctx, *relay); relayMeteringResult.IsError() { + return relayMeteringResult, true } - return either.Error[*relayer.MinedRelay](err), false + return either.Error[*relayer.MinedRelay](err), true } // The relay IS NOT volume / reward applicable if !protocol.IsRelayVolumeApplicable(relayHash, relayDifficultyTargetHash) { - meteringError := mnr.relayMeter.SetNonApplicableRelayReward(ctx, relay.GetReq().GetMeta()) - if meteringError != nil { - return either.Error[*relayer.MinedRelay](fmt.Errorf("failed to unclaim relay price: %w", meteringError)), false + if eitherMeteringResult := mnr.unclaimRelayUPOKT(ctx, *relay); eitherMeteringResult.IsError() { + return eitherMeteringResult, true } return either.Success[*relayer.MinedRelay](nil), true } @@ -148,3 +145,13 @@ func (mnr *miner) getServiceRelayDifficultyTargetHash(ctx context.Context, req * return serviceRelayDifficulty.GetTargetHash(), nil } + +// unclaimRelayUPOKT unclaims the relay UPOKT reward for the relay. +// It returns an either.Error if the relay UPOKT reward could not be unclaimed. +func (mnr *miner) unclaimRelayUPOKT(ctx context.Context, relay servicetypes.Relay) either.Either[*relayer.MinedRelay] { + if err := mnr.relayMeter.SetNonApplicableRelayReward(ctx, relay.GetReq().GetMeta()); err != nil { + return either.Error[*relayer.MinedRelay](err) + } + + return either.Success[*relayer.MinedRelay](nil) +} diff --git a/pkg/relayer/miner/miner_test.go b/pkg/relayer/miner/miner_test.go index e3881309c..1aaf6d318 100644 --- a/pkg/relayer/miner/miner_test.go +++ b/pkg/relayer/miner/miner_test.go @@ -50,9 +50,9 @@ func TestMiner_MinedRelays(t *testing.T) { testqueryclients.SetServiceRelayDifficultyTargetHash(t, testSvcId, testRelayMiningTargetHash) serviceQueryClientMock := testqueryclients.NewTestServiceQueryClient(t) - testRelayMeter := mockRelayMeter(t) + relayMeterMock := newMockRelayMeter(t) - deps := depinject.Supply(serviceQueryClientMock, testRelayMeter) + deps := depinject.Supply(serviceQueryClientMock, relayMeterMock) mnr, err := miner.NewMiner(deps) require.NoError(t, err) @@ -158,8 +158,8 @@ func unmarshalHexMinedRelay( } } -// mockRelayMeter returns a mock RelayMeter that is used by the relay miner to claim and unclaim relays. -func mockRelayMeter(t *testing.T) relayer.RelayMeter { +// newMockRelayMeter returns a mock RelayMeter that is used by the relay miner to claim and unclaim relays. +func newMockRelayMeter(t *testing.T) relayer.RelayMeter { t.Helper() ctrl := gomock.NewController(t) diff --git a/pkg/relayer/proxy/errors.go b/pkg/relayer/proxy/errors.go index 9a258b293..ff2fc285f 100644 --- a/pkg/relayer/proxy/errors.go +++ b/pkg/relayer/proxy/errors.go @@ -19,4 +19,5 @@ var ( ErrRelayerProxyMissingSupplierOperatorAddress = sdkerrors.Register(codespace, 11, "supplier operator address is missing") ErrRelayerProxyUnknownSession = sdkerrors.Register(codespace, 12, "relayer proxy encountered unknown session") ErrRelayerProxyRateLimited = sdkerrors.Register(codespace, 13, "offchain rate limit hit by relayer proxy") + ErrRelayerProxyUnclaimRelayPrice = sdkerrors.Register(codespace, 14, "failed to unclaim relay price") ) diff --git a/pkg/relayer/proxy/proxy.go b/pkg/relayer/proxy/proxy.go index 1d8cde74f..ad69a587b 100644 --- a/pkg/relayer/proxy/proxy.go +++ b/pkg/relayer/proxy/proxy.go @@ -81,7 +81,7 @@ type relayerProxy struct { // relayMeter keeps track of the total amount of stake an onchhain Application // will owe an onchain Supplier (backed by this RelayMiner) once the session settles. - // It also configures over servicing allowance. + // It also configures application over-servicing allowance. relayMeter relayer.RelayMeter } diff --git a/pkg/relayer/proxy/relay_meter.go b/pkg/relayer/proxy/relay_meter.go index 9c8101edd..18f0f650a 100644 --- a/pkg/relayer/proxy/relay_meter.go +++ b/pkg/relayer/proxy/relay_meter.go @@ -44,7 +44,10 @@ type sessionRelayMeter struct { sessionHeader *sessiontypes.SessionHeader // numOverServicedRelays is the number of relays that have been over-serviced // by the relayer for the application. - numOverServicedRelays int + numOverServicedRelays uint64 + // numOverservicedComputeUnits is the number of compute units that have been + // over-serviced by the relayer for the application. + numOverServicedComputeUnits uint64 // sharedParams, service and serviceRelayDifficulty are used to calculate the relay cost // that increments the consumedAmount. @@ -59,6 +62,8 @@ type sessionRelayMeter struct { // It ensures that no Application is over-serviced by the Supplier per session. // This is done by maintaining the max amount of stake the supplier can consume // per session and the amount of stake consumed by mined relays. +// TODO_POST_MAINNET(@red-0ne): Consider making the relay meter a light client, +// since it's already receiving all committed blocks and events. type ProxyRelayMeter struct { // sessionToRelayMeterMap is a map of session IDs to their corresponding session relay meter. // Only known applications (i.e. have sent at least one relay) have their stakes metered. @@ -138,7 +143,7 @@ func (rmtr *ProxyRelayMeter) Start(ctx context.Context) error { // The relay reward is added optimistically, assuming that the relay will be volume / reward // applicable and the relay meter would remain up to date. func (rmtr *ProxyRelayMeter) AccumulateRelayReward(ctx context.Context, reqMeta servicetypes.RelayRequestMetadata) error { - // TODO_MAINNET: Locking the relay serving flow to ensure that the relay meter is updated + // TODO_MAINNET(@adshmh): Locking the relay serving flow to ensure that the relay meter is updated // might be a bottleneck since ensureRequestAppMetrics is performing multiple // sequential queries to the Pocket Network node. // Re-evaluate when caching and invalidation is implemented. @@ -166,7 +171,6 @@ func (rmtr *ProxyRelayMeter) AccumulateRelayReward(ctx context.Context, reqMeta newConsumedCoin := appRelayMeter.consumedCoin.Add(relayCostCoin) isAppOverServiced := appRelayMeter.maxCoin.IsLT(newConsumedCoin) - if !isAppOverServiced { appRelayMeter.consumedCoin = newConsumedCoin return nil @@ -180,12 +184,12 @@ func (rmtr *ProxyRelayMeter) AccumulateRelayReward(ctx context.Context, reqMeta // then return a rate limit error. overServicingCoin := newConsumedCoin.Sub(appRelayMeter.maxCoin) - // In case Allowance is positive, add it to the maxCoin to allow no or limited over-servicing. + // In case Allowance is positive, add it to maxCoin to allow no or limited over-servicing. if !allowUnlimitedOverServicing { maxAllowedOverServicing := appRelayMeter.maxCoin.Add(rmtr.overServicingAllowanceCoins) if maxAllowedOverServicing.IsLT(newConsumedCoin) { return ErrRelayerProxyRateLimited.Wrapf( - "application has been rate limited, stake needed: %s, has: %s, ", + "application has been rate limited, stake needed: %s, has: %s", newConsumedCoin.String(), appRelayMeter.maxCoin.String(), ) @@ -193,13 +197,10 @@ func (rmtr *ProxyRelayMeter) AccumulateRelayReward(ctx context.Context, reqMeta } appRelayMeter.numOverServicedRelays++ - numOverServicedRelays := appRelayMeter.numOverServicedRelays - - // Exponential backoff: log only when numOverServicedRelays is a power of 2 - shouldLog := (numOverServicedRelays & (numOverServicedRelays - 1)) == 0 + appRelayMeter.numOverServicedComputeUnits += appRelayMeter.service.ComputeUnitsPerRelay - // Log the over-servicing warning. - if shouldLog { + // Exponential backoff, only log over-servicing when numOverServicedRelays is a power of 2 + if shouldLogOverServicing(appRelayMeter.numOverServicedRelays) { rmtr.logger.Warn().Msgf( "overservicing enabled, application %q over-serviced %s", appRelayMeter.app.GetAddress(), @@ -230,11 +231,7 @@ func (rmtr *ProxyRelayMeter) SetNonApplicableRelayReward(ctx context.Context, re sessionRelayMeter.serviceRelayDifficulty, ) if err != nil { - return err - } - - if sessionRelayMeter.numOverServicedRelays > 0 { - return nil + return ErrRelayerProxyUnclaimRelayPrice.Wrapf("%s", err) } // Decrease the consumed stake amount by relay cost. @@ -437,3 +434,9 @@ func getAppStakePortionPayableToSessionSupplier( return appStakePerSessionSupplierCoin } + +// shouldLogOverServicing returns true if the number of occurrences is a power of 2. +// This is used to log the over-servicing warning with an exponential backoff. +func shouldLogOverServicing(occurrence uint64) bool { + return (occurrence & (occurrence - 1)) == 0 +} diff --git a/x/shared/types/session.go b/x/shared/types/session.go index ea75a0e3b..9d90a5a60 100644 --- a/x/shared/types/session.go +++ b/x/shared/types/session.go @@ -176,3 +176,13 @@ func GetSettlementSessionEndHeight(sharedParams *Params, queryHeight int64) int6 return GetSessionEndToProofWindowCloseBlocks(sharedParams) + GetSessionEndHeight(sharedParams, queryHeight) + 1 } + +// GetNumPendingSessions returns the number of pending sessions (i.e. that have not +// yet been settled) at the time of queryHeight. +func GetNumPendingSessions(sharedParams *Params) int64 { + numBlocksPerSession := int64(sharedParams.GetNumBlocksPerSession()) + pendingBlocks := GetSessionEndToProofWindowCloseBlocks(sharedParams) + // numBlocksPerSession - 1 is added to round up the integer division so that pending + // sessions are all the sessions that have their end height at least `pendingBlocks` old + return (pendingBlocks + numBlocksPerSession - 1) / numBlocksPerSession +} diff --git a/x/tokenomics/keeper/settle_pending_claims.go b/x/tokenomics/keeper/settle_pending_claims.go index 2144b8487..cc660f152 100644 --- a/x/tokenomics/keeper/settle_pending_claims.go +++ b/x/tokenomics/keeper/settle_pending_claims.go @@ -203,6 +203,8 @@ func (k Keeper) SettlePendingClaims(ctx sdk.Context) ( appAddress := claim.GetSessionHeader().GetApplicationAddress() applicationInitialStake := applicationInitialStakeMap[appAddress] + // TODO_MAINNET(@red-0ne): Add tests to ensure that a zero application stake + // is handled correctly. if applicationInitialStake.IsZero() { logger.Error(fmt.Sprintf("application %q has a zero initial stake", appAddress)) diff --git a/x/tokenomics/keeper/token_logic_modules.go b/x/tokenomics/keeper/token_logic_modules.go index 564e9b733..00c081316 100644 --- a/x/tokenomics/keeper/token_logic_modules.go +++ b/x/tokenomics/keeper/token_logic_modules.go @@ -292,6 +292,8 @@ func (k Keeper) ProcessTokenLogicModules( // Ensure the claim amount is within the limits set by Relay Mining. // If not, update the settlement amount and emit relevant events. + // TODO_MAINNET(@red-0ne): Consider pulling this out of Keeper#ProcessTokenLogicModules + // and ensure claim amount limits are enforced before TLM processing. actualSettlementCoin, err := k.ensureClaimAmountLimits(ctx, logger, &sharedParams, &application, &supplier, claimSettlementCoin, applicationInitialStake) if err != nil { return err @@ -299,6 +301,8 @@ func (k Keeper) ProcessTokenLogicModules( logger = logger.With("actual_settlement_upokt", actualSettlementCoin) logger.Info(fmt.Sprintf("About to start processing TLMs for (%d) compute units, equal to (%s) claimed", numClaimComputeUnits, actualSettlementCoin)) + // TODO_MAINNET(@red-0ne): Add tests to ensure that a zero settlement coin + // due to integer division rounding is handled correctly. if actualSettlementCoin.Amount.IsZero() { logger.Warn(fmt.Sprintf( "actual settlement coin is zero, skipping TLM processing, application %q stake %s", @@ -724,22 +728,19 @@ func (k Keeper) ensureClaimAmountLimits( minRequiredAppStakeAmt := claimSettlementCoin.Amount.Add(globalInflationAmt) totalClaimedCoin := sdk.NewCoin(volatile.DenomuPOKT, minRequiredAppStakeAmt) - numBlocksPerSession := int64(sharedParams.GetNumBlocksPerSession()) - pendingBlocks := sharedtypes.GetSessionEndToProofWindowCloseBlocks(sharedParams) - // We are addding numBlocksPerSession - 1 to round up the integer division - // so that pending sessions are all the sessions that have their end height at least - // `pendingBlocks` old - pendingSessions := (pendingBlocks + numBlocksPerSession - 1) / numBlocksPerSession + // get the number of pending sessions that share the application stake at claim time + // This is used to calculate the maximum claimable amount for the supplier within a session. + numPendingSessions := sharedtypes.GetNumPendingSessions(sharedParams) // The maximum any single supplier can claim is a fraction of the app's total stake // divided by the number of suppliers per session. // Re decentralization - This ensures the app biases towards using all suppliers in a session. // Re costs - This is an easy way to split the stake evenly. - // TODO_FUTURE: See if there's a way to let the application to pick a single (the best) supplier - // in a session while maintaining a simple solution to implement this. + // TODO_FUTURE: See if there's a way to let the application prefer (the best) + // supplier(s) in a session while maintaining a simple solution to implement this. maxClaimableAmt := appStake.Amount. Quo(math.NewInt(sessionkeeper.NumSupplierPerSession)). - Quo(math.NewInt(pendingSessions)) + Quo(math.NewInt(numPendingSessions)) maxClaimSettlementAmt := supplierAppStakeToMaxSettlementAmount(maxClaimableAmt) // Check if the claimable amount is capped by the max claimable amount. From a39d5b2696a08f6f0d7392f5498322c23955b5b0 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Mon, 11 Nov 2024 18:04:23 +0100 Subject: [PATCH 51/53] fix: Remove wrong param comment --- x/shared/types/session.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/x/shared/types/session.go b/x/shared/types/session.go index 9d90a5a60..355d83c1e 100644 --- a/x/shared/types/session.go +++ b/x/shared/types/session.go @@ -178,11 +178,14 @@ func GetSettlementSessionEndHeight(sharedParams *Params, queryHeight int64) int6 } // GetNumPendingSessions returns the number of pending sessions (i.e. that have not -// yet been settled) at the time of queryHeight. +// yet been settled). func GetNumPendingSessions(sharedParams *Params) int64 { + // Get the number of blocks between the end of a session and the block height + // at which the session claim is settled. + numPendingSessionsBlocks := GetSessionEndToProofWindowCloseBlocks(sharedParams) + // Use the number of blocks per session to calculate the number of pending sessions. numBlocksPerSession := int64(sharedParams.GetNumBlocksPerSession()) - pendingBlocks := GetSessionEndToProofWindowCloseBlocks(sharedParams) // numBlocksPerSession - 1 is added to round up the integer division so that pending - // sessions are all the sessions that have their end height at least `pendingBlocks` old - return (pendingBlocks + numBlocksPerSession - 1) / numBlocksPerSession + // sessions are all the sessions that have their end height at least `pendingBlocks` old. + return (numPendingSessionsBlocks + numBlocksPerSession - 1) / numBlocksPerSession } From a2dd72238bcd0c960b6048dcf5d822bdd120630a Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Mon, 11 Nov 2024 18:21:30 +0100 Subject: [PATCH 52/53] chore: Remove already tackled TODOs --- pkg/relayer/session/sessiontree.go | 16 ---------------- x/proof/keeper/proof_validation.go | 4 ---- 2 files changed, 20 deletions(-) diff --git a/pkg/relayer/session/sessiontree.go b/pkg/relayer/session/sessiontree.go index 243862218..bf83cf0ad 100644 --- a/pkg/relayer/session/sessiontree.go +++ b/pkg/relayer/session/sessiontree.go @@ -21,13 +21,6 @@ import ( var _ relayer.SessionTree = (*sessionTree)(nil) // sessionTree is an implementation of the SessionTree interface. -// TODO_BETA(@red-0ne): Per the Relay Mining paper, we need to optimistically store -// the number of requests that an application can pay for. This needs to be tracked -// based on the app's stake in the beginning of a session and the number of nodes -// per session. An operator should be able to specify "overservicing_compute_units_limit" -// whereby an upper bound on how much it can overserviced an application is set. The -// default value for this should be -1, implying "unlimited". -// Ref discussion: https://github.com/pokt-network/poktroll/pull/755#discussion_r1737287860 type sessionTree struct { logger polylog.Logger @@ -75,15 +68,6 @@ type sessionTree struct { // NewSessionTree creates a new sessionTree from a Session and a storePrefix. It also takes a function // removeFromRelayerSessions that removes the sessionTree from the RelayerSessionsManager. // It returns an error if the KVStore fails to be created. -// -// TODO_BETA(@red-0ne): When starting a new session, check what the MaxClaimableAmount -// (in uPOKT) by the Supplier as a function of -// (app_stake, compute_units_per_relay_for_service, global_compute_units_to_token_multiplier). -// TODO_CONFIG_NOTE: Whether or not the RelayMiner stop handling requests when the max is reached should be -// configurable by the operator. -// TODO_ERROR_NOTE: If overservicing is set to false, create a new error that the relay is rejected -// specifically because the supplier has reached the max claimable amount, so the caller should relay -// the request to another supplier. func NewSessionTree( sessionHeader *sessiontypes.SessionHeader, supplierOperatorAddress *cosmostypes.AccAddress, diff --git a/x/proof/keeper/proof_validation.go b/x/proof/keeper/proof_validation.go index 778d66d8c..850c97f5b 100644 --- a/x/proof/keeper/proof_validation.go +++ b/x/proof/keeper/proof_validation.go @@ -251,10 +251,6 @@ func (k Keeper) validateClosestPath( // be received before proceeding. proofPathSeedBlockHash := k.sessionKeeper.GetBlockHash(ctx, earliestSupplierProofCommitHeight-1) - // TODO_BETA(@red-0ne): Investigate "proof for the path provided does not match one expected by the on-chain protocol" - // error that may occur due to block height differing from the off-chain part. - k.logger.Info("E2E_DEBUG: height for block hash when verifying the proof", earliestSupplierProofCommitHeight, sessionHeader.GetSessionId()) - expectedProofPath := protocol.GetPathForProof(proofPathSeedBlockHash, sessionHeader.GetSessionId()) if !bytes.Equal(proof.Path, expectedProofPath) { return types.ErrProofInvalidProof.Wrapf( From ed2f6d05b88cb1e7a49419d1c231d647f751e88c Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Thu, 14 Nov 2024 21:14:34 +0100 Subject: [PATCH 53/53] wip: revamp tx submission --- api/poktroll/tokenomics/event.pulsar.go | 237 ++++++++++++------ .../tests/relays_stress_helpers_test.go | 141 ++++++++--- ... => relays_stress_single_supplier.feature} | 8 +- load-testing/tests/relays_stress_test.go | 64 +++-- pkg/client/interface.go | 21 +- pkg/client/query/tokenomicsquerier.go | 50 ++++ proto/poktroll/tokenomics/event.proto | 1 + testutil/keeper/tokenomics.go | 4 + x/tokenomics/keeper/settle_pending_claims.go | 47 +++- x/tokenomics/keeper/token_logic_modules.go | 35 +-- .../keeper/token_logic_modules_test.go | 27 +- x/tokenomics/types/event.pb.go | 167 ++++++++---- x/tokenomics/types/expected_keepers.go | 1 + 13 files changed, 577 insertions(+), 226 deletions(-) rename load-testing/tests/{relays_stress_signle_supplier.feature => relays_stress_single_supplier.feature} (65%) create mode 100644 pkg/client/query/tokenomicsquerier.go diff --git a/api/poktroll/tokenomics/event.pulsar.go b/api/poktroll/tokenomics/event.pulsar.go index 4a8a3c0e5..f0ad8553a 100644 --- a/api/poktroll/tokenomics/event.pulsar.go +++ b/api/poktroll/tokenomics/event.pulsar.go @@ -729,6 +729,7 @@ var ( fd_EventClaimSettled_num_claimed_compute_units protoreflect.FieldDescriptor fd_EventClaimSettled_num_estimated_compute_units protoreflect.FieldDescriptor fd_EventClaimSettled_claimed_upokt protoreflect.FieldDescriptor + fd_EventClaimSettled_settled_upokt protoreflect.FieldDescriptor ) func init() { @@ -740,6 +741,7 @@ func init() { fd_EventClaimSettled_num_claimed_compute_units = md_EventClaimSettled.Fields().ByName("num_claimed_compute_units") fd_EventClaimSettled_num_estimated_compute_units = md_EventClaimSettled.Fields().ByName("num_estimated_compute_units") fd_EventClaimSettled_claimed_upokt = md_EventClaimSettled.Fields().ByName("claimed_upokt") + fd_EventClaimSettled_settled_upokt = md_EventClaimSettled.Fields().ByName("settled_upokt") } var _ protoreflect.Message = (*fastReflection_EventClaimSettled)(nil) @@ -843,6 +845,12 @@ func (x *fastReflection_EventClaimSettled) Range(f func(protoreflect.FieldDescri return } } + if x.SettledUpokt != nil { + value := protoreflect.ValueOfMessage(x.SettledUpokt.ProtoReflect()) + if !f(fd_EventClaimSettled_settled_upokt, value) { + return + } + } } // Has reports whether a field is populated. @@ -870,6 +878,8 @@ func (x *fastReflection_EventClaimSettled) Has(fd protoreflect.FieldDescriptor) return x.NumEstimatedComputeUnits != uint64(0) case "poktroll.tokenomics.EventClaimSettled.claimed_upokt": return x.ClaimedUpokt != nil + case "poktroll.tokenomics.EventClaimSettled.settled_upokt": + return x.SettledUpokt != nil default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.tokenomics.EventClaimSettled")) @@ -898,6 +908,8 @@ func (x *fastReflection_EventClaimSettled) Clear(fd protoreflect.FieldDescriptor x.NumEstimatedComputeUnits = uint64(0) case "poktroll.tokenomics.EventClaimSettled.claimed_upokt": x.ClaimedUpokt = nil + case "poktroll.tokenomics.EventClaimSettled.settled_upokt": + x.SettledUpokt = nil default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.tokenomics.EventClaimSettled")) @@ -932,6 +944,9 @@ func (x *fastReflection_EventClaimSettled) Get(descriptor protoreflect.FieldDesc case "poktroll.tokenomics.EventClaimSettled.claimed_upokt": value := x.ClaimedUpokt return protoreflect.ValueOfMessage(value.ProtoReflect()) + case "poktroll.tokenomics.EventClaimSettled.settled_upokt": + value := x.SettledUpokt + return protoreflect.ValueOfMessage(value.ProtoReflect()) default: if descriptor.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.tokenomics.EventClaimSettled")) @@ -964,6 +979,8 @@ func (x *fastReflection_EventClaimSettled) Set(fd protoreflect.FieldDescriptor, x.NumEstimatedComputeUnits = value.Uint() case "poktroll.tokenomics.EventClaimSettled.claimed_upokt": x.ClaimedUpokt = value.Message().Interface().(*v1beta1.Coin) + case "poktroll.tokenomics.EventClaimSettled.settled_upokt": + x.SettledUpokt = value.Message().Interface().(*v1beta1.Coin) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.tokenomics.EventClaimSettled")) @@ -994,6 +1011,11 @@ func (x *fastReflection_EventClaimSettled) Mutable(fd protoreflect.FieldDescript x.ClaimedUpokt = new(v1beta1.Coin) } return protoreflect.ValueOfMessage(x.ClaimedUpokt.ProtoReflect()) + case "poktroll.tokenomics.EventClaimSettled.settled_upokt": + if x.SettledUpokt == nil { + x.SettledUpokt = new(v1beta1.Coin) + } + return protoreflect.ValueOfMessage(x.SettledUpokt.ProtoReflect()) case "poktroll.tokenomics.EventClaimSettled.proof_requirement": panic(fmt.Errorf("field proof_requirement of message poktroll.tokenomics.EventClaimSettled is not mutable")) case "poktroll.tokenomics.EventClaimSettled.num_relays": @@ -1029,6 +1051,9 @@ func (x *fastReflection_EventClaimSettled) NewField(fd protoreflect.FieldDescrip case "poktroll.tokenomics.EventClaimSettled.claimed_upokt": m := new(v1beta1.Coin) return protoreflect.ValueOfMessage(m.ProtoReflect()) + case "poktroll.tokenomics.EventClaimSettled.settled_upokt": + m := new(v1beta1.Coin) + return protoreflect.ValueOfMessage(m.ProtoReflect()) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.tokenomics.EventClaimSettled")) @@ -1118,6 +1143,10 @@ func (x *fastReflection_EventClaimSettled) ProtoMethods() *protoiface.Methods { l = options.Size(x.ClaimedUpokt) n += 1 + l + runtime.Sov(uint64(l)) } + if x.SettledUpokt != nil { + l = options.Size(x.SettledUpokt) + n += 1 + l + runtime.Sov(uint64(l)) + } if x.unknownFields != nil { n += len(x.unknownFields) } @@ -1147,6 +1176,20 @@ func (x *fastReflection_EventClaimSettled) ProtoMethods() *protoiface.Methods { i -= len(x.unknownFields) copy(dAtA[i:], x.unknownFields) } + if x.SettledUpokt != nil { + encoded, err := options.Marshal(x.SettledUpokt) + if err != nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) + i-- + dAtA[i] = 0x3a + } if x.ClaimedUpokt != nil { encoded, err := options.Marshal(x.ClaimedUpokt) if err != nil { @@ -1392,6 +1435,42 @@ func (x *fastReflection_EventClaimSettled) ProtoMethods() *protoiface.Methods { return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err } iNdEx = postIndex + case 7: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field SettledUpokt", wireType) + } + var msglen int + 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++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if x.SettledUpokt == nil { + x.SettledUpokt = &v1beta1.Coin{} + } + if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.SettledUpokt); err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := runtime.Skip(dAtA[iNdEx:]) @@ -3540,6 +3619,7 @@ type EventClaimSettled struct { // The uPOKT coin claimed to be rewarded for the work done as a function of // the number of estimated compute units and the compute uints to token multiplier. ClaimedUpokt *v1beta1.Coin `protobuf:"bytes,6,opt,name=claimed_upokt,json=claimedUpokt,proto3" json:"claimed_upokt,omitempty"` + SettledUpokt *v1beta1.Coin `protobuf:"bytes,7,opt,name=settled_upokt,json=settledUpokt,proto3" json:"settled_upokt,omitempty"` } func (x *EventClaimSettled) Reset() { @@ -3604,6 +3684,13 @@ func (x *EventClaimSettled) GetClaimedUpokt() *v1beta1.Coin { return nil } +func (x *EventClaimSettled) GetSettledUpokt() *v1beta1.Coin { + if x != nil { + return x.SettledUpokt + } + return nil +} + // EventApplicationOverserviced is emitted when an application has less stake than // what a supplier is claiming (i.e. amount available for burning is insufficient). // This means the following will ALWAYS be strictly true: effective_burn < expected_burn. @@ -3849,7 +3936,7 @@ var file_poktroll_tokenomics_event_proto_rawDesc = []byte{ 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x69, 0x6e, 0x42, 0x11, 0xea, 0xde, 0x1f, 0x0d, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x65, 0x64, 0x5f, 0x75, 0x70, 0x6f, 0x6b, 0x74, 0x52, 0x0c, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x65, 0x64, 0x55, 0x70, 0x6f, - 0x6b, 0x74, 0x22, 0xf3, 0x03, 0x0a, 0x11, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x43, 0x6c, 0x61, 0x69, + 0x6b, 0x74, 0x22, 0xc6, 0x04, 0x0a, 0x11, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x53, 0x65, 0x74, 0x74, 0x6c, 0x65, 0x64, 0x12, 0x36, 0x0a, 0x05, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x2e, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x42, 0x09, @@ -3880,73 +3967,78 @@ var file_poktroll_tokenomics_event_proto_rawDesc = []byte{ 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x69, 0x6e, 0x42, 0x11, 0xea, 0xde, 0x1f, 0x0d, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x65, 0x64, 0x5f, 0x75, 0x70, 0x6f, 0x6b, 0x74, 0x52, 0x0c, 0x63, 0x6c, 0x61, 0x69, - 0x6d, 0x65, 0x64, 0x55, 0x70, 0x6f, 0x6b, 0x74, 0x22, 0x81, 0x02, 0x0a, 0x1c, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65, - 0x72, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x64, 0x12, 0x29, 0x0a, 0x10, 0x61, 0x70, 0x70, + 0x6d, 0x65, 0x64, 0x55, 0x70, 0x6f, 0x6b, 0x74, 0x12, 0x51, 0x0a, 0x0d, 0x73, 0x65, 0x74, 0x74, + 0x6c, 0x65, 0x64, 0x5f, 0x75, 0x70, 0x6f, 0x6b, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x19, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, + 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x69, 0x6e, 0x42, 0x11, 0xea, 0xde, 0x1f, 0x0d, + 0x73, 0x65, 0x74, 0x74, 0x6c, 0x65, 0x64, 0x5f, 0x75, 0x70, 0x6f, 0x6b, 0x74, 0x52, 0x0c, 0x73, + 0x65, 0x74, 0x74, 0x6c, 0x65, 0x64, 0x55, 0x70, 0x6f, 0x6b, 0x74, 0x22, 0x81, 0x02, 0x0a, 0x1c, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x4f, 0x76, 0x65, 0x72, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x64, 0x12, 0x29, 0x0a, 0x10, + 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x12, 0x34, 0x0a, 0x16, 0x73, 0x75, 0x70, 0x70, 0x6c, + 0x69, 0x65, 0x72, 0x5f, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, 0x64, + 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x73, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, + 0x72, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x41, 0x64, 0x64, 0x72, 0x12, 0x3e, 0x0a, + 0x0d, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x72, 0x6e, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, + 0x73, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x69, 0x6e, 0x52, + 0x0c, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x42, 0x75, 0x72, 0x6e, 0x12, 0x40, 0x0a, + 0x0e, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x62, 0x75, 0x72, 0x6e, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, + 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x69, 0x6e, + 0x52, 0x0d, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x42, 0x75, 0x72, 0x6e, 0x22, + 0xbe, 0x01, 0x0a, 0x14, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, + 0x72, 0x53, 0x6c, 0x61, 0x73, 0x68, 0x65, 0x64, 0x12, 0x34, 0x0a, 0x16, 0x73, 0x75, 0x70, 0x70, + 0x6c, 0x69, 0x65, 0x72, 0x5f, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, + 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x73, 0x75, 0x70, 0x70, 0x6c, 0x69, + 0x65, 0x72, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x41, 0x64, 0x64, 0x72, 0x12, 0x2c, + 0x0a, 0x12, 0x6e, 0x75, 0x6d, 0x5f, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x64, 0x5f, 0x63, 0x6c, + 0x61, 0x69, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x6e, 0x75, 0x6d, 0x45, + 0x78, 0x70, 0x69, 0x72, 0x65, 0x64, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x73, 0x12, 0x42, 0x0a, 0x0f, + 0x73, 0x6c, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, + 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x69, 0x6e, + 0x52, 0x0e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, + 0x22, 0xa8, 0x02, 0x0a, 0x24, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x69, 0x6d, 0x62, 0x75, 0x72, 0x73, 0x65, 0x6d, 0x65, + 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x12, 0x34, 0x0a, 0x16, 0x73, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x5f, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x73, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x4f, 0x70, - 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x41, 0x64, 0x64, 0x72, 0x12, 0x3e, 0x0a, 0x0d, 0x65, 0x78, - 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x72, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, - 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x0c, 0x65, 0x78, - 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x42, 0x75, 0x72, 0x6e, 0x12, 0x40, 0x0a, 0x0e, 0x65, 0x66, - 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x62, 0x75, 0x72, 0x6e, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, - 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x0d, 0x65, - 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x42, 0x75, 0x72, 0x6e, 0x22, 0xbe, 0x01, 0x0a, - 0x14, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x53, 0x6c, - 0x61, 0x73, 0x68, 0x65, 0x64, 0x12, 0x34, 0x0a, 0x16, 0x73, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, - 0x72, 0x5f, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x73, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x4f, - 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x41, 0x64, 0x64, 0x72, 0x12, 0x2c, 0x0a, 0x12, 0x6e, - 0x75, 0x6d, 0x5f, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x64, 0x5f, 0x63, 0x6c, 0x61, 0x69, 0x6d, - 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x6e, 0x75, 0x6d, 0x45, 0x78, 0x70, 0x69, - 0x72, 0x65, 0x64, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x73, 0x12, 0x42, 0x0a, 0x0f, 0x73, 0x6c, 0x61, - 0x73, 0x68, 0x69, 0x6e, 0x67, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, - 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x0e, 0x73, - 0x6c, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0xa8, 0x02, - 0x0a, 0x24, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x65, 0x69, 0x6d, 0x62, 0x75, 0x72, 0x73, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x64, 0x64, - 0x72, 0x12, 0x34, 0x0a, 0x16, 0x73, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x5f, 0x6f, 0x70, - 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x14, 0x73, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x4f, 0x70, 0x65, 0x72, 0x61, - 0x74, 0x6f, 0x72, 0x41, 0x64, 0x64, 0x72, 0x12, 0x2e, 0x0a, 0x13, 0x73, 0x75, 0x70, 0x70, 0x6c, - 0x69, 0x65, 0x72, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x73, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x4f, 0x77, - 0x6e, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x31, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, - 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x69, 0x6e, - 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x2a, 0x60, 0x0a, 0x15, 0x43, 0x6c, 0x61, 0x69, - 0x6d, 0x45, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x61, 0x73, 0x6f, - 0x6e, 0x12, 0x21, 0x0a, 0x1d, 0x45, 0x58, 0x50, 0x49, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, - 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, - 0x45, 0x44, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x52, 0x4f, 0x4f, 0x46, 0x5f, 0x4d, 0x49, - 0x53, 0x53, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x52, 0x4f, 0x4f, 0x46, - 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x02, 0x42, 0xbc, 0x01, 0xd8, 0xe2, 0x1e, - 0x01, 0x0a, 0x17, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, - 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0x42, 0x0a, 0x45, 0x76, 0x65, 0x6e, - 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x24, 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, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0xa2, 0x02, - 0x03, 0x50, 0x54, 0x58, 0xaa, 0x02, 0x13, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, - 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0xca, 0x02, 0x13, 0x50, 0x6f, 0x6b, - 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, - 0xe2, 0x02, 0x1f, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x54, 0x6f, 0x6b, 0x65, - 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0xea, 0x02, 0x14, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x3a, 0x3a, 0x54, - 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, + 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x41, 0x64, 0x64, 0x72, 0x12, 0x2e, 0x0a, 0x13, 0x73, 0x75, + 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x64, + 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x73, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, + 0x72, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, + 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x31, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, + 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, + 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, + 0x6f, 0x69, 0x6e, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x2a, 0x60, 0x0a, 0x15, 0x43, + 0x6c, 0x61, 0x69, 0x6d, 0x45, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x1d, 0x45, 0x58, 0x50, 0x49, 0x52, 0x41, 0x54, 0x49, + 0x4f, 0x4e, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, + 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x52, 0x4f, 0x4f, 0x46, + 0x5f, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x52, + 0x4f, 0x4f, 0x46, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x02, 0x42, 0xbc, 0x01, + 0xd8, 0xe2, 0x1e, 0x01, 0x0a, 0x17, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, + 0x6c, 0x6c, 0x2e, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0x42, 0x0a, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x24, 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, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, + 0x73, 0xa2, 0x02, 0x03, 0x50, 0x54, 0x58, 0xaa, 0x02, 0x13, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, + 0x6c, 0x6c, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0xca, 0x02, 0x13, + 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, + 0x69, 0x63, 0x73, 0xe2, 0x02, 0x1f, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x54, + 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x14, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, + 0x3a, 0x3a, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x73, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -3981,15 +4073,16 @@ var file_poktroll_tokenomics_event_proto_depIdxs = []int32{ 6, // 3: poktroll.tokenomics.EventClaimSettled.claim:type_name -> poktroll.proof.Claim 8, // 4: poktroll.tokenomics.EventClaimSettled.proof_requirement:type_name -> poktroll.proof.ProofRequirementReason 7, // 5: poktroll.tokenomics.EventClaimSettled.claimed_upokt:type_name -> cosmos.base.v1beta1.Coin - 7, // 6: poktroll.tokenomics.EventApplicationOverserviced.expected_burn:type_name -> cosmos.base.v1beta1.Coin - 7, // 7: poktroll.tokenomics.EventApplicationOverserviced.effective_burn:type_name -> cosmos.base.v1beta1.Coin - 7, // 8: poktroll.tokenomics.EventSupplierSlashed.slashing_amount:type_name -> cosmos.base.v1beta1.Coin - 7, // 9: poktroll.tokenomics.EventApplicationReimbursementRequest.amount:type_name -> cosmos.base.v1beta1.Coin - 10, // [10:10] is the sub-list for method output_type - 10, // [10:10] is the sub-list for method input_type - 10, // [10:10] is the sub-list for extension type_name - 10, // [10:10] is the sub-list for extension extendee - 0, // [0:10] is the sub-list for field type_name + 7, // 6: poktroll.tokenomics.EventClaimSettled.settled_upokt:type_name -> cosmos.base.v1beta1.Coin + 7, // 7: poktroll.tokenomics.EventApplicationOverserviced.expected_burn:type_name -> cosmos.base.v1beta1.Coin + 7, // 8: poktroll.tokenomics.EventApplicationOverserviced.effective_burn:type_name -> cosmos.base.v1beta1.Coin + 7, // 9: poktroll.tokenomics.EventSupplierSlashed.slashing_amount:type_name -> cosmos.base.v1beta1.Coin + 7, // 10: poktroll.tokenomics.EventApplicationReimbursementRequest.amount:type_name -> cosmos.base.v1beta1.Coin + 11, // [11:11] is the sub-list for method output_type + 11, // [11:11] is the sub-list for method input_type + 11, // [11:11] is the sub-list for extension type_name + 11, // [11:11] is the sub-list for extension extendee + 0, // [0:11] is the sub-list for field type_name } func init() { file_poktroll_tokenomics_event_proto_init() } diff --git a/load-testing/tests/relays_stress_helpers_test.go b/load-testing/tests/relays_stress_helpers_test.go index f4f4b2ef4..b656ba2c3 100644 --- a/load-testing/tests/relays_stress_helpers_test.go +++ b/load-testing/tests/relays_stress_helpers_test.go @@ -101,11 +101,23 @@ func (s *relaysSuite) setupTxEventListeners() { // Map the eventsReplayClient.EventsSequence which is a replay observable // to a regular observable to avoid replaying txResults from old blocks. + blockHeightToEvents := make(map[int64][]types.Event, 0) + blockHeightToEventsMu := sync.Mutex{} channel.ForEach( s.ctx, txEventsReplayClient.EventsSequence(s.ctx), func(ctx context.Context, txResult *types.TxResult) { - eventsObsCh <- txResult.Result.Events + blockHeightToEventsMu.Lock() + defer blockHeightToEventsMu.Unlock() + + blockHeight := txResult.Height + events := txResult.Result.Events + + if _, ok := blockHeightToEvents[blockHeight]; !ok { + blockHeightToEvents[blockHeight] = make([]types.Event, 0) + } + + blockHeightToEvents[blockHeight] = append(blockHeightToEvents[blockHeight], events...) }, ) @@ -124,7 +136,35 @@ func (s *relaysSuite) setupTxEventListeners() { s.ctx, blockEventsReplayClient.EventsSequence(s.ctx), func(ctx context.Context, block *block.CometNewBlockEvent) { - eventsObsCh <- block.Data.Value.ResultFinalizeBlock.Events + blockHeightToEventsMu.Lock() + defer blockHeightToEventsMu.Unlock() + + blockHeight := block.Data.Value.Block.Height + events := block.Data.Value.ResultFinalizeBlock.Events + + if _, ok := blockHeightToEvents[blockHeight]; !ok { + blockHeightToEvents[blockHeight] = make([]types.Event, 0) + } + + blockHeightToEvents[blockHeight] = append(blockHeightToEvents[blockHeight], events...) + }, + ) + + channel.ForEach( + s.ctx, + s.blockClient.CommittedBlocksSequence(s.ctx), + func(ctx context.Context, block client.Block) { + blockHeightToEventsMu.Lock() + defer blockHeightToEventsMu.Unlock() + + if _, ok := blockHeightToEvents[block.Height()]; ok { + for eventsHeight, events := range blockHeightToEvents { + if eventsHeight < block.Height() { + eventsObsCh <- events + delete(blockHeightToEvents, eventsHeight) + } + } + } }, ) } @@ -977,7 +1017,7 @@ func (s *relaysSuite) sendPendingMsgsTx(actor *accountInfo) { err := txBuilder.SetMsgs(actor.pendingMsgs...) require.NoError(s, err) - txBuilder.SetTimeoutHeight(uint64(s.latestBlock.Height() + 1)) + txBuilder.SetTimeoutHeight(uint64(s.latestBlock.Height() + 2)) txBuilder.SetGasLimit(690000042) accAddress := sdk.MustAccAddressFromBech32(actor.address) @@ -1001,6 +1041,7 @@ func (s *relaysSuite) sendPendingMsgsTx(actor *accountInfo) { // txContext.BroadcastTx uses the async mode, if this method changes in the future // to be synchronous, make sure to keep this async to avoid blocking the test. go func() { + time.Sleep(2 * time.Second) r, err := s.txContext.BroadcastTx(txBz) require.NoError(s, err) require.NotNil(s, r) @@ -1076,9 +1117,13 @@ func (s *relaysSuite) ensureFundedActors( ) { fundedActors := make(map[string]struct{}) + actorsAddrs := make([]string, len(actors)) + for i, actor := range actors { + actorsAddrs[i] = actor.address + } + ctx, cancel := context.WithCancel(ctx) - abciEventsObs := eventsObsWithNumBlocksTimeout(ctx, s.eventsObs, 3, cancel) - channel.ForEach(ctx, abciEventsObs, func(ctx context.Context, events []types.Event) { + channel.ForEach(ctx, s.eventsObs, func(ctx context.Context, events []types.Event) { for _, event := range events { // Skip non-relevant events. if event.GetType() != "transfer" { @@ -1087,9 +1132,16 @@ func (s *relaysSuite) ensureFundedActors( attrs := event.GetAttributes() // Check if the actor is the recipient of the transfer event. - if fundedActorAddr, ok := getEventAttr(attrs, "recipient"); ok { - fundedActors[fundedActorAddr] = struct{}{} + fundedActorAddr, ok := getEventAttr(attrs, "recipient") + if !ok { + continue + } + + if !slices.Contains(actorsAddrs, fundedActorAddr) { + continue } + + fundedActors[fundedActorAddr] = struct{}{} } if allActorsFunded(actors, fundedActors) { @@ -1099,7 +1151,8 @@ func (s *relaysSuite) ensureFundedActors( <-ctx.Done() if !allActorsFunded(actors, fundedActors) { - s.logAndAbortTest("actor not funded") + fmt.Println(fundedActors) + s.logAndAbortTest("actors not funded") } } @@ -1122,8 +1175,7 @@ func (s *relaysSuite) ensureStakedActors( stakedActors := make(map[string]struct{}) ctx, cancel := context.WithCancel(ctx) - abciEventsObs := eventsObsWithNumBlocksTimeout(ctx, s.eventsObs, 3, cancel) - typedEventsObs := abciEventsToTypedEvents(ctx, abciEventsObs) + typedEventsObs := abciEventsToTypedEvents(ctx, s.eventsObs) channel.ForEach(ctx, typedEventsObs, func(ctx context.Context, blockEvents []proto.Message) { for _, event := range blockEvents { switch e := event.(type) { @@ -1143,7 +1195,7 @@ func (s *relaysSuite) ensureStakedActors( <-ctx.Done() if !allActorsStaked(actors, stakedActors) { - s.logAndAbortTest("actor not staked") + s.logAndAbortTest("actors not staked") return } } @@ -1167,8 +1219,7 @@ func (s *relaysSuite) ensureDelegatedApps( appsToGateways := make(map[string][]string) ctx, cancel := context.WithCancel(ctx) - abciEventsObs := eventsObsWithNumBlocksTimeout(ctx, s.eventsObs, 3, cancel) - typedEventsObs := abciEventsToTypedEvents(ctx, abciEventsObs) + typedEventsObs := abciEventsToTypedEvents(ctx, s.eventsObs) channel.ForEach(ctx, typedEventsObs, func(ctx context.Context, blockEvents []proto.Message) { for _, event := range blockEvents { redelegationEvent, ok := event.(*apptypes.EventRedelegation) @@ -1278,7 +1329,7 @@ func (s *relaysSuite) activatePreparedActors(notif *sessionInfoNotif) { func getEventAttr(attributes []types.EventAttribute, key string) (value string, found bool) { for _, attribute := range attributes { if attribute.Key == key { - return value, true + return attribute.Value, true } } @@ -1433,6 +1484,52 @@ func (s *relaysSuite) queryAppParams(queryNodeRPCURL string) { s.appParams = appParams } +// queryProofParams queries the current on-chain proof module parameters for use +// over the duration of the test. +func (s *relaysSuite) queryProofParams(queryNodeRPCURL string) { + s.Helper() + + deps := depinject.Supply(s.txContext.GetClientCtx()) + + blockQueryClient, err := sdkclient.NewClientFromNode(queryNodeRPCURL) + require.NoError(s, err) + deps = depinject.Configs(deps, depinject.Supply(blockQueryClient)) + + proofQueryclient, err := query.NewProofQuerier(deps) + require.NoError(s, err) + + params, err := proofQueryclient.GetParams(s.ctx) + require.NoError(s, err) + + proofParams, ok := params.(*prooftypes.Params) + require.True(s, ok) + + s.proofParams = proofParams +} + +// queryTokenomicsParams queries the current on-chain tokenomics module parameters for use +// over the duration of the test. +func (s *relaysSuite) queryTokenomicsParams(queryNodeRPCURL string) { + s.Helper() + + deps := depinject.Supply(s.txContext.GetClientCtx()) + + blockQueryClient, err := sdkclient.NewClientFromNode(queryNodeRPCURL) + require.NoError(s, err) + deps = depinject.Configs(deps, depinject.Supply(blockQueryClient)) + + tokenomicsQueryclient, err := query.NewTokenomicsQuerier(deps) + require.NoError(s, err) + + params, err := tokenomicsQueryclient.GetParams(s.ctx) + require.NoError(s, err) + + tokenomicsParams, ok := params.(*tokenomicstypes.Params) + require.True(s, ok) + + s.tokenomicsParams = tokenomicsParams +} + // forEachStakedAndDelegatedAppPrepareApp is a ForEachFn that waits for txs which // were broadcast in previous pipeline stages have been committed. It ensures that // new applications were successfully staked and all application actors are delegated @@ -1542,22 +1639,6 @@ func (s *relaysSuite) WaitAll(waitFunc ...func()) { wg.Wait() } -func eventsObsWithNumBlocksTimeout( - ctx context.Context, - eventsObs observable.Observable[[]types.Event], - numBlocksTimeout int, - cancel func(), -) observable.Observable[[]types.Event] { - return channel.Map(ctx, eventsObs, func(ctx context.Context, blockEvents []types.Event) ([]types.Event, bool) { - if numBlocksTimeout < 0 { - cancel() - } - - numBlocksTimeout-- - return blockEvents, false - }) -} - func forEachTypedEventFn(fn func(ctx context.Context, blockEvents []proto.Message)) func(ctx context.Context, blockEvents []*types.Event) { return func(ctx context.Context, blockEvents []*types.Event) { var typedEvents []proto.Message diff --git a/load-testing/tests/relays_stress_signle_supplier.feature b/load-testing/tests/relays_stress_single_supplier.feature similarity index 65% rename from load-testing/tests/relays_stress_signle_supplier.feature rename to load-testing/tests/relays_stress_single_supplier.feature index 253b82615..c3208d968 100644 --- a/load-testing/tests/relays_stress_signle_supplier.feature +++ b/load-testing/tests/relays_stress_single_supplier.feature @@ -14,4 +14,10 @@ Feature: Loading gateway server with relays | gateway | 1 | 10 | 3 | | supplier | 1 | 10 | 1 | When a load of concurrent relay requests are sent from the applications - Then the correct pairs count of claim and proof messages should be committed on-chain \ No newline at end of file + Then "0" over servicing events are observed + And "0" slashing events are observed + And "0" expired claim event are observed + And there is as many reimbursment requests as the number of settled claims + And the number of claims submitted and claims settled is the same + And the number of proofs submitted and proofs required is the same + And the actors onchain balances are as expected \ No newline at end of file diff --git a/load-testing/tests/relays_stress_test.go b/load-testing/tests/relays_stress_test.go index 81e09dc35..76870f730 100644 --- a/load-testing/tests/relays_stress_test.go +++ b/load-testing/tests/relays_stress_test.go @@ -144,6 +144,9 @@ type relaysSuite struct { // It is queried at the beginning of the test. appParams *apptypes.Params + proofParams *prooftypes.Params + tokenomicsParams *tokenomicstypes.Params + // numRelaysSent is the number of relay requests sent during the test. numRelaysSent atomic.Uint64 // relayRatePerApp is the rate of relay requests sent per application per second. @@ -318,12 +321,31 @@ func TestLoadRelays(t *testing.T) { } func TestLoadRelaysSingleSupplier(t *testing.T) { + gocuke.NewRunner(t, &relaysSuite{}).Path(filepath.Join(".", "relays_stress_single_supplier.feature")).Run() } func (s *relaysSuite) LocalnetIsRunning() { s.ctx, s.cancelCtx = context.WithCancel(context.Background()) + s.tokenomics = &tokenomics{ + OverservicedApplications: make([]*tokenomicstypes.EventApplicationOverserviced, 0), + SuppliersSlashed: make([]*tokenomicstypes.EventSupplierSlashed, 0), + ExpiredClaims: make([]*tokenomicstypes.EventClaimExpired, 0), + ReimbursementRequests: make([]*tokenomicstypes.EventApplicationReimbursementRequest, 0), + ClaimsSettled: make([]*tokenomicstypes.EventClaimSettled, 0), + ClaimsSubmitted: make([]*prooftypes.EventClaimCreated, 0), + ProofsSubmitted: make([]*prooftypes.EventProofSubmitted, 0), + ActorsBalances: actorsBalances{ + ApplicationBalances: make(map[string]sdk.Coin), + ApplicationStakes: make(map[string]sdk.Coin), + GatewaysBalances: make(map[string]sdk.Coin), + GatewaysStakes: make(map[string]sdk.Coin), + SupplierBalances: make(map[string]sdk.Coin), + SupplierStakes: make(map[string]sdk.Coin), + }, + } + // Cancel the context if this process is interrupted or exits. // Delete the keyring entries for the application accounts since they are // not persisted across test runs. @@ -414,6 +436,9 @@ func (s *relaysSuite) LocalnetIsRunning() { // Query for the current app on-chain params. s.queryAppParams(loadTestParams.TestNetNode) + // Quer for the current proof on-chain params. + s.queryProofParams(loadTestParams.TestNetNode) + // Some suppliers may already be staked at genesis, ensure that staking during // this test succeeds by increasing the sake amount. minStakeAmount := s.getProvisionedActorsCurrentStakedAmount() @@ -452,15 +477,6 @@ func (s *relaysSuite) MoreActorsAreStakedAsFollows(table gocuke.DataTable) { // increment the actor count to the maximum. s.relayLoadDurationBlocks = s.plans.maxActorBlocksToFinalIncrementEnd() - if s.isEphemeralChain { - // Adjust the max delegations parameter to the max gateways to permit all - // applications to delegate to all gateways. - // This is to ensure that requests are distributed evenly across all gateways - // at any given time. - s.sendAdjustMaxDelegationsParamTx(s.plans.gateways.maxActorCount) - s.ensureUpdatedMaxDelegations(s.plans.gateways.maxActorCount) - } - // Fund all the provisioned suppliers and gateways since their addresses are // known and they are not created on the fly, while funding only the initially // created applications. @@ -582,19 +598,19 @@ func (s *relaysSuite) TheCorrectCountOfClaimsAndProofsSubmittedOnChain() { //) } -func (s *relaysSuite) OverServicingEventsIsObserved(numEvents int64) { - require.Equal(s, s.tokenomics.OverservicedApplications, numEvents) +func (s *relaysSuite) OverServicingEventsAreObserved(numEvents int64) { + require.Len(s, s.tokenomics.OverservicedApplications, int(numEvents)) } -func (s *relaysSuite) SlashingEventsIsObserved(numEvents int64) { - require.Equal(s, s.tokenomics.SuppliersSlashed, numEvents) +func (s *relaysSuite) SlashingEventsAreObserved(numEvents int64) { + require.Len(s, s.tokenomics.SuppliersSlashed, int(numEvents)) } -func (s *relaysSuite) SlashingExpiredClaimEventIsObserved(numEvents int64) { - require.Equal(s, s.tokenomics.ExpiredClaims, numEvents) +func (s *relaysSuite) ExpiredClaimEventAreObserved(numEvents int64) { + require.Len(s, s.tokenomics.ExpiredClaims, int(numEvents)) } -func (s *relaysSuite) ThereIsAsManyReimbursmentRequestAsTheNumberOfSettledClaims() { +func (s *relaysSuite) ThereIsAsManyReimbursmentRequestsAsTheNumberOfSettledClaims() { require.Equal(s, len(s.tokenomics.ReimbursementRequests), len(s.tokenomics.ClaimsSettled)) } @@ -613,7 +629,7 @@ func (s *relaysSuite) TheNumberOfProofsSubmittedAndProofsRequiredIsTheSame() { require.Len(s, s.tokenomics.ProofsSubmitted, numProofRequiredObserved) } -func (s *relaysSuite) TheActorsOnChainBalancesAreAsExpected() { +func (s *relaysSuite) TheActorsOnchainBalancesAreAsExpected() { balances := s.tokenomics.ActorsBalances for _, claimSettlement := range s.tokenomics.ClaimsSettled { @@ -632,12 +648,12 @@ func (s *relaysSuite) TheActorsOnChainBalancesAreAsExpected() { mintUPOKT := s.getGlobalInflationMintedUPOKT(settledUPOKT) // TODO_IN_THIS_PR: Should check with multiple supplier owners - supplierMintUPOKT := s.getGlobalInflationActorAllocation(mintUPOKT, tokenomicskeeper.MintAllocationSupplier) + supplierMintUPOKT := s.getGlobalInflationActorAllocation(mintUPOKT, s.tokenomicsParams.MintAllocationSupplier) balances.SupplierBalances[claimSupplierAddr] = balances.SupplierBalances[claimSupplierAddr]. Add(*settledUPOKT). Add(supplierMintUPOKT) - applicationMintUPOKT := s.getGlobalInflationActorAllocation(mintUPOKT, tokenomicskeeper.MintAllocationApplication) + applicationMintUPOKT := s.getGlobalInflationActorAllocation(mintUPOKT, s.tokenomicsParams.MintAllocationApplication) balances.ApplicationBalances[claimAppAddr] = balances.ApplicationBalances[claimAppAddr]. Add(applicationMintUPOKT) @@ -649,22 +665,24 @@ func (s *relaysSuite) TheActorsOnChainBalancesAreAsExpected() { Sub(*settledUPOKT). Sub(mintUPOKT) - daoMintUPOKT := s.getGlobalInflationActorAllocation(mintUPOKT, tokenomicskeeper.MintAllocationDAO) + daoMintUPOKT := s.getGlobalInflationActorAllocation(mintUPOKT, s.tokenomicsParams.MintAllocationDao) balances.DAOAccountBalance = balances.DAOAccountBalance. Add(daoMintUPOKT). Add(mintUPOKT) - proposerMintUPOKT := s.getGlobalInflationActorAllocation(mintUPOKT, tokenomicskeeper.MintAllocationProposer) + proposerMintUPOKT := s.getGlobalInflationActorAllocation(mintUPOKT, s.tokenomicsParams.MintAllocationProposer) balances.ProposerAccountBalance = balances.ProposerAccountBalance. Add(proposerMintUPOKT) - sourceOwnerMintUPOKT := s.getGlobalInflationActorAllocation(mintUPOKT, tokenomicskeeper.MintAllocationSourceOwner) + sourceOwnerMintUPOKT := s.getGlobalInflationActorAllocation(mintUPOKT, s.tokenomicsParams.MintAllocationSourceOwner) balances.SourceOwnerAccountBalance = balances.SourceOwnerAccountBalance. Add(sourceOwnerMintUPOKT) } for _, proofSubmission := range s.tokenomics.ProofsSubmitted { - balances.SupplierBalances[proofSubmission.SupplierOperatorAddress] = balances.SupplierBalances[proofSubmission.SupplierOperatorAddress]. + operatorAddr := proofSubmission.Claim.SupplierOperatorAddress + balances.SupplierBalances[operatorAddr] = balances.SupplierBalances[operatorAddr]. + Sub(*s.proofParams.ProofSubmissionFee) } } diff --git a/pkg/client/interface.go b/pkg/client/interface.go index 2dc0b9c87..fee9dfc0e 100644 --- a/pkg/client/interface.go +++ b/pkg/client/interface.go @@ -9,6 +9,7 @@ //go:generate mockgen -destination=../../testutil/mockclient/session_query_client_mock.go -package=mockclient . SessionQueryClient //go:generate mockgen -destination=../../testutil/mockclient/shared_query_client_mock.go -package=mockclient . SharedQueryClient //go:generate mockgen -destination=../../testutil/mockclient/proof_query_client_mock.go -package=mockclient . ProofQueryClient +//go:generate mockgen -destination=../../testutil/mockclient/tokenomics_query_client_mock.go -package=mockclient . TokenomicsQueryClient //go:generate mockgen -destination=../../testutil/mockclient/service_query_client_mock.go -package=mockclient . ServiceQueryClient //go:generate mockgen -destination=../../testutil/mockclient/bank_query_client_mock.go -package=mockclient . BankQueryClient //go:generate mockgen -destination=../../testutil/mockclient/cosmos_tx_builder_mock.go -package=mockclient github.com/cosmos/cosmos-sdk/client TxBuilder @@ -344,10 +345,28 @@ type ProofParams interface { // ProofQueryClient defines an interface that enables the querying of the // on-chain proof module params. type ProofQueryClient interface { - // GetParams queries the chain for the current shared module parameters. + // GetParams queries the chain for the current proof module parameters. GetParams(ctx context.Context) (ProofParams, error) } +// TokenomicsParams is a go interface type which corresponds to the poktroll.tokenomics.Params +// protobuf message. Since the generated go types don't include interface types, this +// is necessary to prevent dependency cycles. +type TokenomicsParams interface { + GetMintAllocationDao() float64 + GetMintAllocationProposer() float64 + GetMintAllocationSupplier() float64 + GetMintAllocationSourceOwner() float64 + GetMintAllocationApplication() float64 +} + +// TokenomicsQueryClient defines an interface that enables the querying of the +// on-chain tokenomics module params. +type TokenomicsQueryClient interface { + // GetParams queries the chain for the current tokenomics module parameters. + GetParams(ctx context.Context) (TokenomicsParams, error) +} + // ServiceQueryClient defines an interface that enables the querying of the // on-chain service information type ServiceQueryClient interface { diff --git a/pkg/client/query/tokenomicsquerier.go b/pkg/client/query/tokenomicsquerier.go new file mode 100644 index 000000000..30f273833 --- /dev/null +++ b/pkg/client/query/tokenomicsquerier.go @@ -0,0 +1,50 @@ +package query + +import ( + "context" + + "cosmossdk.io/depinject" + "github.com/cosmos/gogoproto/grpc" + + "github.com/pokt-network/poktroll/pkg/client" + tokenomicstypes "github.com/pokt-network/poktroll/x/tokenomics/types" +) + +// tokenomicsQuerier is a wrapper around the tokenomics.QueryClient that enables the +// querying of on-chain tokenomics module params. +type tokenomicsQuerier struct { + clientConn grpc.ClientConn + tokenomicsQuerier tokenomicstypes.QueryClient +} + +// NewTokenomicsQuerier returns a new instance of a client.TokenomicsQueryClient by +// injecting the dependecies provided by the depinject.Config. +// +// Required dependencies: +// - grpc.ClientConn +func NewTokenomicsQuerier(deps depinject.Config) (client.TokenomicsQueryClient, error) { + querier := &tokenomicsQuerier{} + + if err := depinject.Inject( + deps, + &querier.clientConn, + ); err != nil { + return nil, err + } + + querier.tokenomicsQuerier = tokenomicstypes.NewQueryClient(querier.clientConn) + + return querier, nil +} + +// GetParams queries the chain for the current tokenomics module parameters. +func (pq *tokenomicsQuerier) GetParams( + ctx context.Context, +) (client.TokenomicsParams, error) { + req := &tokenomicstypes.QueryParamsRequest{} + res, err := pq.tokenomicsQuerier.Params(ctx, req) + if err != nil { + return nil, err + } + return &res.Params, nil +} diff --git a/proto/poktroll/tokenomics/event.proto b/proto/poktroll/tokenomics/event.proto index 23c4f8e10..6e1287cbc 100644 --- a/proto/poktroll/tokenomics/event.proto +++ b/proto/poktroll/tokenomics/event.proto @@ -51,6 +51,7 @@ message EventClaimSettled { // The uPOKT coin claimed to be rewarded for the work done as a function of // the number of estimated compute units and the compute uints to token multiplier. cosmos.base.v1beta1.Coin claimed_upokt = 6 [(gogoproto.jsontag) = "claimed_upokt"]; + cosmos.base.v1beta1.Coin settled_upokt = 7 [(gogoproto.jsontag) = "settled_upokt"]; } // EventApplicationOverserviced is emitted when an application has less stake than diff --git a/testutil/keeper/tokenomics.go b/testutil/keeper/tokenomics.go index acf9dc4b5..cc48c9843 100644 --- a/testutil/keeper/tokenomics.go +++ b/testutil/keeper/tokenomics.go @@ -170,6 +170,10 @@ func TokenomicsKeeperWithActorAddrs(t testing.TB) ( EndBlockerUnbondApplications(gomock.Any()). Return(nil). AnyTimes() + mockApplicationKeeper.EXPECT(). + GetParams(gomock.Any()). + Return(apptypes.DefaultParams()). + AnyTimes() // Mock the supplier keeper. mockSupplierKeeper := mocks.NewMockSupplierKeeper(ctrl) diff --git a/x/tokenomics/keeper/settle_pending_claims.go b/x/tokenomics/keeper/settle_pending_claims.go index cc660f152..694271fe4 100644 --- a/x/tokenomics/keeper/settle_pending_claims.go +++ b/x/tokenomics/keeper/settle_pending_claims.go @@ -211,8 +211,41 @@ func (k Keeper) SettlePendingClaims(ctx sdk.Context) ( continue } + // Retrieve the on-chain staked supplier record + operatorAddr := claim.GetSupplierOperatorAddress() + supplier, isSupplierFound := k.supplierKeeper.GetSupplier(ctx, operatorAddr) + if !isSupplierFound { + logger.Warn(fmt.Sprintf("supplier for claim with address %q not found", operatorAddr)) + return settledResult, expiredResult, tokenomicstypes.ErrTokenomicsSupplierNotFound + } + + // Retrieve the on-chain staked application record + application, isAppFound := k.applicationKeeper.GetApplication(ctx, appAddress) + if !isAppFound { + logger.Warn(fmt.Sprintf("application for claim with address %q not found", appAddress)) + return settledResult, expiredResult, tokenomicstypes.ErrTokenomicsApplicationNotFound + } + + claimSettlementCoin, err := claim.GetClaimeduPOKT(sharedParams, relayMiningDifficulty) + if err != nil { + return settledResult, expiredResult, err + } + + actualSettlementCoin, err := k.EnsureClaimAmountLimits(ctx, logger, &sharedParams, &application, &supplier, claimSettlementCoin, applicationInitialStake) + if err != nil { + return settledResult, expiredResult, err + } + + if actualSettlementCoin.Amount.IsZero() { + logger.Warn(fmt.Sprintf( + "actual settlement coin is zero, skipping TLM processing, application %q stake %s", + application.Address, application.Stake, + )) + continue + } + // Manage the mint & burn accounting for the claim. - if err = k.ProcessTokenLogicModules(ctx, &claim, applicationInitialStake); err != nil { + if err = k.ProcessTokenLogicModules(ctx, &claim, actualSettlementCoin); err != nil { logger.Error(fmt.Sprintf("error processing token logic modules for claim %q: %v", claim.SessionHeader.SessionId, err)) return settledResult, expiredResult, err } @@ -224,23 +257,13 @@ func (k Keeper) SettlePendingClaims(ctx sdk.Context) ( NumEstimatedComputeUnits: numEstimatedComputeUnits, ClaimedUpokt: &claimeduPOKT, ProofRequirement: proofRequirement, + SettledUpokt: &actualSettlementCoin, } if err = ctx.EventManager().EmitTypedEvent(&claimSettledEvent); err != nil { return settledResult, expiredResult, err } - if err = ctx.EventManager().EmitTypedEvent(&prooftypes.EventProofUpdated{ - Claim: &claim, - Proof: nil, - NumRelays: 0, - NumClaimedComputeUnits: 0, - NumEstimatedComputeUnits: numEstimatedComputeUnits, - ClaimedUpokt: &claimeduPOKT, - }); err != nil { - return settledResult, expiredResult, err - } - logger.Info("claim settled") // The claim & proof are no longer necessary, so there's no need for them diff --git a/x/tokenomics/keeper/token_logic_modules.go b/x/tokenomics/keeper/token_logic_modules.go index 25062481a..5d0c9a651 100644 --- a/x/tokenomics/keeper/token_logic_modules.go +++ b/x/tokenomics/keeper/token_logic_modules.go @@ -133,7 +133,7 @@ func init() { func (k Keeper) ProcessTokenLogicModules( ctx context.Context, claim *prooftypes.Claim, - applicationInitialStake cosmostypes.Coin, + actualSettlementCoin cosmostypes.Coin, ) (err error) { logger := k.Logger().With("method", "ProcessTokenLogicModules") @@ -277,27 +277,6 @@ func (k Keeper) ProcessTokenLogicModules( "application", application.Address, ) - // Ensure the claim amount is within the limits set by Relay Mining. - // If not, update the settlement amount and emit relevant events. - // TODO_MAINNET(@red-0ne): Consider pulling this out of Keeper#ProcessTokenLogicModules - // and ensure claim amount limits are enforced before TLM processing. - actualSettlementCoin, err := k.ensureClaimAmountLimits(ctx, logger, &sharedParams, &application, &supplier, claimSettlementCoin, applicationInitialStake) - if err != nil { - return err - } - logger = logger.With("actual_settlement_upokt", actualSettlementCoin) - logger.Info(fmt.Sprintf("About to start processing TLMs for (%d) compute units, equal to (%s) claimed", numClaimComputeUnits, actualSettlementCoin)) - - // TODO_MAINNET(@red-0ne): Add tests to ensure that a zero settlement coin - // due to integer division rounding is handled correctly. - if actualSettlementCoin.Amount.IsZero() { - logger.Warn(fmt.Sprintf( - "actual settlement coin is zero, skipping TLM processing, application %q stake %s", - application.Address, application.Stake, - )) - return nil - } - // Execute all the token logic modules processors for tlm, tlmProcessor := range tokenLogicModuleProcessorMap { logger.Info(fmt.Sprintf("Starting TLM processing: %q", tlm)) @@ -687,14 +666,14 @@ func (k Keeper) sendRewardsToAccount( return coinToAcc, nil } -// ensureClaimAmountLimits checks if the application was overserviced and handles +// EnsureClaimAmountLimits checks if the application was overserviced and handles // the case if it was. // Per Algorithm #1 in the Relay Mining paper, the maximum amount that a single supplier // can claim in a session is AppStake/NumSuppliersPerSession. // If this is not the case, then the supplier essentially did "free work" and the // actual claim amount is less than what was claimed. // Ref: https://arxiv.org/pdf/2305.10672 -func (k Keeper) ensureClaimAmountLimits( +func (k Keeper) EnsureClaimAmountLimits( ctx context.Context, logger log.Logger, sharedParams *sharedtypes.Params, @@ -734,7 +713,7 @@ func (k Keeper) ensureClaimAmountLimits( maxClaimableAmt := appStake.Amount. Quo(math.NewInt(numSuppliersPerSession)). Quo(math.NewInt(numPendingSessions)) - maxClaimSettlementAmt := supplierAppStakeToMaxSettlementAmount(maxClaimableAmt) + maxClaimSettlementAmt := SupplierAppStakeToMaxSettlementAmount(maxClaimableAmt) // Check if the claimable amount is capped by the max claimable amount. // As per the Relay Mining paper, the Supplier claim MUST NOT exceed the application's @@ -745,7 +724,7 @@ func (k Keeper) ensureClaimAmountLimits( supplier.GetOperatorAddress(), application.GetAddress(), maxClaimableAmt, claimSettlementCoin.Amount)) minRequiredAppStakeAmt = maxClaimableAmt - maxClaimSettlementAmt = supplierAppStakeToMaxSettlementAmount(minRequiredAppStakeAmt) + maxClaimSettlementAmt = SupplierAppStakeToMaxSettlementAmount(minRequiredAppStakeAmt) } // Nominal case: The claimable amount is within the limits set by Relay Mining. @@ -850,7 +829,7 @@ func CalculateGlobalPerClaimMintInflationFromSettlementAmount(settlementCoin sdk return mintAmtCoin, *newMintAmtFloat } -// supplierAppStakeToMaxSettlementAmount calculates the max amount of uPOKT the supplier +// SupplierAppStakeToMaxSettlementAmount calculates the max amount of uPOKT the supplier // can claim based on the stake allocated to the supplier and the global inflation // allocation percentage. // This is the inverse of CalculateGlobalPerClaimMintInflationFromSettlementAmount: @@ -858,7 +837,7 @@ func CalculateGlobalPerClaimMintInflationFromSettlementAmount(settlementCoin sdk // stake = maxSettlementAmt + (maxSettlementAmt * MintPerClaimedTokenGlobalInflation) // stake = maxSettlementAmt * (1 + MintPerClaimedTokenGlobalInflation) // maxSettlementAmt = stake / (1 + MintPerClaimedTokenGlobalInflation) -func supplierAppStakeToMaxSettlementAmount(stakeAmount math.Int) math.Int { +func SupplierAppStakeToMaxSettlementAmount(stakeAmount math.Int) math.Int { stakeAmountFloat := big.NewFloat(0).SetInt(stakeAmount.BigInt()) maxSettlementAmountFloat := big.NewFloat(0).Quo(stakeAmountFloat, big.NewFloat(1+GlobalInflationPerClaim)) diff --git a/x/tokenomics/keeper/token_logic_modules_test.go b/x/tokenomics/keeper/token_logic_modules_test.go index d4fedf314..a53e19954 100644 --- a/x/tokenomics/keeper/token_logic_modules_test.go +++ b/x/tokenomics/keeper/token_logic_modules_test.go @@ -118,8 +118,9 @@ func TestProcessTokenLogicModules_TLMBurnEqualsMint_Valid(t *testing.T) { // Prepare the claim for which the supplier did work for the application claim := prepareTestClaim(numRelays, service, &app, &supplier) + claimedCoin := cosmostypes.NewInt64Coin(volatile.DenomuPOKT, int64(numTokensClaimed)) // Process the token logic modules - err = keepers.ProcessTokenLogicModules(ctx, &claim, appStake) + err = keepers.ProcessTokenLogicModules(ctx, &claim, claimedCoin) require.NoError(t, err) // Assert that `applicationAddress` account balance is *unchanged* @@ -190,6 +191,7 @@ func TestProcessTokenLogicModules_TLMBurnEqualsMint_Valid_SupplierExceedsMaxClai // be able to claim more than the max claimable amount. numRelays *= 5 numTokensClaimed := int64(numRelays * serviceComputeUnitsPerRelay * globalComputeUnitsToTokensMultiplier) + claimCoin := sdk.NewInt64Coin(volatile.DenomuPOKT, numTokensClaimed) // Retrieve the app and supplier module addresses appModuleAddress := authtypes.NewModuleAddress(apptypes.ModuleName).String() @@ -249,8 +251,19 @@ func TestProcessTokenLogicModules_TLMBurnEqualsMint_Valid_SupplierExceedsMaxClai // Prepare the claim for which the supplier did work for the application claim := prepareTestClaim(numRelays, service, &app, &supplier) + claimedCoin, err := keepers.EnsureClaimAmountLimits( + ctx, + keepers.Logger(), + &sharedParams, + &app, + &supplier, + claimCoin, + *app.Stake, + ) + require.NoError(t, err) + // Process the token logic modules - err = keepers.ProcessTokenLogicModules(ctx, &claim, appStake) + err = keepers.ProcessTokenLogicModules(ctx, &claim, claimedCoin) require.NoError(t, err) // Assert that `applicationAddress` account balance is *unchanged* @@ -384,8 +397,10 @@ func TestProcessTokenLogicModules_TLMGlobalMint_Valid_MintDistributionCorrect(t supplierShareholderBalancesBefore[addr] = getBalance(t, ctx, keepers, addr) } + claimedCoin := cosmostypes.NewInt64Coin(volatile.DenomuPOKT, int64(numTokensClaimed)) + // Process the token logic modules - err = keepers.ProcessTokenLogicModules(ctx, &claim, appStake) + err = keepers.ProcessTokenLogicModules(ctx, &claim, claimedCoin) require.NoError(t, err) // Determine balances after inflation @@ -454,7 +469,7 @@ func TestProcessTokenLogicModules_AppNotFound(t *testing.T) { } // Process the token logic modules - err := keeper.ProcessTokenLogicModules(ctx, &claim, uPOKTCoin(math.MaxInt)) + err := keeper.ProcessTokenLogicModules(ctx, &claim, uPOKTCoin(1)) require.Error(t, err) require.ErrorIs(t, err, tokenomicstypes.ErrTokenomicsApplicationNotFound) } @@ -547,7 +562,7 @@ func TestProcessTokenLogicModules_InvalidRoot(t *testing.T) { claim.RootHash = smt.MerkleRoot(test.root[:]) // Execute test function - err := keeper.ProcessTokenLogicModules(ctx, &claim, uPOKTCoin(math.MaxInt)) + err := keeper.ProcessTokenLogicModules(ctx, &claim, uPOKTCoin(1)) // Assert the error if test.errExpected { @@ -637,7 +652,7 @@ func TestProcessTokenLogicModules_InvalidClaim(t *testing.T) { err = fmt.Errorf("panic occurred: %v", r) } }() - return keeper.ProcessTokenLogicModules(ctx, test.claim, uPOKTCoin(math.MaxInt)) + return keeper.ProcessTokenLogicModules(ctx, test.claim, uPOKTCoin(1)) }() // Assert the error diff --git a/x/tokenomics/types/event.pb.go b/x/tokenomics/types/event.pb.go index 5e69f719f..cf518377b 100644 --- a/x/tokenomics/types/event.pb.go +++ b/x/tokenomics/types/event.pb.go @@ -161,6 +161,7 @@ type EventClaimSettled struct { // The uPOKT coin claimed to be rewarded for the work done as a function of // the number of estimated compute units and the compute uints to token multiplier. ClaimedUpokt *types1.Coin `protobuf:"bytes,6,opt,name=claimed_upokt,json=claimedUpokt,proto3" json:"claimed_upokt"` + SettledUpokt *types1.Coin `protobuf:"bytes,7,opt,name=settled_upokt,json=settledUpokt,proto3" json:"settled_upokt"` } func (m *EventClaimSettled) Reset() { *m = EventClaimSettled{} } @@ -234,6 +235,13 @@ func (m *EventClaimSettled) GetClaimedUpokt() *types1.Coin { return nil } +func (m *EventClaimSettled) GetSettledUpokt() *types1.Coin { + if m != nil { + return m.SettledUpokt + } + return nil +} + // EventApplicationOverserviced is emitted when an application has less stake than // what a supplier is claiming (i.e. amount available for burning is insufficient). // This means the following will ALWAYS be strictly true: effective_burn < expected_burn. @@ -463,59 +471,60 @@ func init() { func init() { proto.RegisterFile("poktroll/tokenomics/event.proto", fileDescriptor_a78874bbf91a58c7) } var fileDescriptor_a78874bbf91a58c7 = []byte{ - // 823 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x56, 0xcf, 0x6f, 0xdb, 0x36, - 0x14, 0x8e, 0x9c, 0x34, 0x80, 0xb9, 0xc6, 0xb5, 0xd5, 0xa4, 0x70, 0xb3, 0x45, 0xca, 0x8c, 0x61, - 0xc8, 0x8a, 0x55, 0x42, 0xda, 0x61, 0xc7, 0x61, 0xb6, 0xeb, 0x0e, 0x02, 0x36, 0xdb, 0xa5, 0x97, - 0xa1, 0xd8, 0x61, 0x9a, 0x2c, 0xbd, 0xb8, 0x5c, 0x2c, 0x52, 0x25, 0x29, 0x37, 0x3d, 0xee, 0x3f, - 0xd8, 0x9f, 0xb1, 0xbf, 0x62, 0xe7, 0x1d, 0x7b, 0xec, 0xc9, 0x18, 0x9c, 0x9b, 0xaf, 0x3b, 0xec, - 0x3a, 0x90, 0x92, 0x7f, 0xc4, 0xe9, 0x9c, 0x43, 0xb0, 0x5b, 0x2f, 0x36, 0xf9, 0xbe, 0xef, 0x7b, - 0x24, 0xdf, 0xf7, 0x68, 0x1a, 0xd9, 0x09, 0x3b, 0x93, 0x9c, 0x0d, 0x87, 0xae, 0x64, 0x67, 0x40, - 0x59, 0x4c, 0x42, 0xe1, 0xc2, 0x08, 0xa8, 0x74, 0x12, 0xce, 0x24, 0x33, 0xef, 0xce, 0x08, 0xce, - 0x82, 0xb0, 0x6f, 0x85, 0x4c, 0xc4, 0x4c, 0xb8, 0xfd, 0x40, 0x80, 0x3b, 0x3a, 0xee, 0x83, 0x0c, - 0x8e, 0xdd, 0x90, 0x11, 0x9a, 0x89, 0xf6, 0x77, 0x07, 0x6c, 0xc0, 0xf4, 0xd0, 0x55, 0xa3, 0x3c, - 0xba, 0x3f, 0x5f, 0x2b, 0xe1, 0x8c, 0x9d, 0xba, 0xf2, 0x75, 0x02, 0x22, 0xc3, 0x6a, 0xff, 0x6c, - 0xa2, 0x4a, 0x4b, 0x2d, 0xdb, 0x1c, 0x06, 0x24, 0x6e, 0x9d, 0x27, 0x84, 0x43, 0x64, 0x7e, 0x89, - 0x6e, 0x85, 0x6a, 0x5e, 0x35, 0x0e, 0x8d, 0xa3, 0x0f, 0x1e, 0xed, 0x39, 0xf3, 0xcd, 0xe8, 0x0c, - 0x8e, 0x26, 0x37, 0x8a, 0xd3, 0xb1, 0x9d, 0xf1, 0x70, 0xf6, 0x65, 0x52, 0x54, 0x01, 0x95, 0x22, - 0x90, 0x84, 0x51, 0x9f, 0x43, 0x20, 0x18, 0xad, 0x16, 0x0e, 0x8d, 0xa3, 0xd2, 0xa3, 0x07, 0xce, - 0x3b, 0x0e, 0xe4, 0x2c, 0x56, 0xd5, 0x12, 0xac, 0x15, 0x8d, 0xbd, 0xe9, 0xd8, 0xbe, 0x9a, 0x08, - 0x97, 0x61, 0x85, 0x68, 0x3e, 0x44, 0x88, 0xa6, 0xb1, 0xcf, 0x61, 0x18, 0xbc, 0x16, 0xd5, 0xcd, - 0x43, 0xe3, 0x68, 0xab, 0x51, 0x9a, 0x8e, 0xed, 0xa5, 0x28, 0x2e, 0xd2, 0x34, 0xc6, 0x7a, 0x68, - 0x3e, 0x47, 0xf7, 0x15, 0xa0, 0xf7, 0x0a, 0x91, 0x1f, 0xb2, 0x38, 0x49, 0x25, 0xf8, 0x29, 0x25, - 0x52, 0x54, 0xb7, 0xb4, 0xfa, 0x60, 0x3a, 0xb6, 0xff, 0x9b, 0x84, 0xef, 0xd1, 0x34, 0x6e, 0x66, - 0x48, 0x33, 0x03, 0x4e, 0x54, 0xdc, 0xfc, 0x09, 0x7d, 0xa8, 0x44, 0x20, 0x24, 0x89, 0x03, 0x79, - 0x25, 0xf7, 0x2d, 0x9d, 0xdb, 0x9e, 0x8e, 0xed, 0x75, 0x34, 0x5c, 0xa5, 0x69, 0xdc, 0x9a, 0x61, - 0x97, 0xf2, 0x3f, 0x43, 0x3b, 0xb3, 0x0d, 0xa5, 0xaa, 0x8e, 0xd5, 0x6d, 0x6d, 0xcc, 0x7d, 0x27, - 0x6b, 0x08, 0x47, 0x35, 0x84, 0x93, 0x37, 0x84, 0xd3, 0x64, 0x84, 0x36, 0x2a, 0xd3, 0xb1, 0x7d, - 0x59, 0x83, 0x6f, 0xe7, 0xd3, 0x13, 0x35, 0xab, 0xfd, 0x7d, 0xc9, 0xf9, 0x1e, 0x48, 0x39, 0xbc, - 0x81, 0xf3, 0xbf, 0xa0, 0x8a, 0x26, 0xf8, 0x1c, 0x5e, 0xa6, 0x84, 0x43, 0x0c, 0x54, 0xe6, 0xce, - 0x7f, 0xba, 0x9a, 0xa3, 0xab, 0x3e, 0xf1, 0x82, 0xb7, 0xec, 0xfa, 0x95, 0x24, 0xb8, 0x9c, 0xac, - 0xd0, 0xdf, 0xbb, 0x7e, 0x03, 0xd7, 0x7f, 0x2d, 0xa0, 0x8f, 0xb4, 0xeb, 0xf5, 0x24, 0x19, 0x92, - 0x50, 0x5f, 0xa6, 0xce, 0x08, 0xb8, 0x00, 0x3e, 0x22, 0x21, 0x44, 0xe6, 0x67, 0xa8, 0x1c, 0x2c, - 0x20, 0x3f, 0x88, 0x22, 0xae, 0x7b, 0xa1, 0x88, 0xef, 0x2c, 0xc5, 0xeb, 0x51, 0xc4, 0xcd, 0x2f, - 0xd0, 0x3d, 0x91, 0xaa, 0x18, 0x70, 0x9f, 0x25, 0xc0, 0x03, 0xc9, 0x78, 0x26, 0x28, 0x68, 0xc1, - 0xee, 0x0c, 0xed, 0xe4, 0xa0, 0x56, 0x7d, 0x85, 0x76, 0xe0, 0x3c, 0x81, 0x50, 0x15, 0xa2, 0x9f, - 0x72, 0xaa, 0x0d, 0x5c, 0x77, 0x28, 0x7c, 0x7b, 0xc6, 0x6f, 0xa4, 0x9c, 0x9a, 0x5f, 0xa3, 0x12, - 0x9c, 0x9e, 0x42, 0x28, 0xc9, 0x08, 0xb2, 0x04, 0x5b, 0xd7, 0x25, 0xd8, 0x99, 0x0b, 0x54, 0x86, - 0xda, 0x1f, 0x06, 0xda, 0xd5, 0x35, 0xe8, 0xe5, 0xfb, 0xeb, 0x0d, 0x03, 0xf1, 0x02, 0xa2, 0x35, - 0x07, 0x32, 0xd6, 0x1c, 0xe8, 0x73, 0x64, 0x6a, 0x7b, 0xb3, 0xdf, 0xce, 0xac, 0x85, 0x84, 0x2e, - 0xc1, 0x16, 0x2e, 0x2b, 0x6f, 0x33, 0x40, 0x37, 0x90, 0x30, 0x1b, 0xe8, 0x8e, 0x50, 0xcb, 0x11, - 0x3a, 0xf0, 0x83, 0x98, 0xa5, 0x54, 0x5e, 0x5f, 0x80, 0xd2, 0x4c, 0x51, 0xd7, 0x82, 0xda, 0xef, - 0x05, 0xf4, 0xc9, 0xaa, 0x89, 0x18, 0x48, 0xdc, 0x4f, 0xb9, 0xc8, 0x6f, 0xd4, 0xcb, 0x14, 0x84, - 0xfc, 0xff, 0xcd, 0x74, 0xd0, 0xdd, 0x85, 0xea, 0x15, 0x85, 0x5c, 0xb2, 0xa9, 0x25, 0x95, 0xb9, - 0x44, 0x21, 0x9a, 0x7f, 0x80, 0x50, 0xde, 0x69, 0x3e, 0x89, 0xb4, 0x71, 0x45, 0x5c, 0xcc, 0x23, - 0x5e, 0x94, 0xc1, 0x42, 0xa8, 0xbd, 0x92, 0x48, 0xdf, 0x1f, 0x0d, 0xeb, 0x88, 0x17, 0x99, 0xc7, - 0x68, 0x3b, 0x2f, 0xd9, 0x75, 0x17, 0x01, 0xe7, 0xc4, 0x07, 0x3f, 0xa3, 0xbd, 0x77, 0xbe, 0x31, - 0xe6, 0xc7, 0xe8, 0xa0, 0xf5, 0xbc, 0xeb, 0xe1, 0xfa, 0xf7, 0x5e, 0xa7, 0xed, 0xe3, 0x56, 0xbd, - 0xd7, 0x69, 0xfb, 0x27, 0xed, 0x5e, 0xb7, 0xd5, 0xf4, 0x9e, 0x7a, 0xad, 0x27, 0xe5, 0x0d, 0xb3, - 0x82, 0x76, 0xba, 0xb8, 0xd3, 0x79, 0xea, 0x7f, 0xe7, 0xf5, 0x7a, 0x5e, 0xfb, 0x9b, 0xb2, 0xb1, - 0x08, 0x79, 0xed, 0x1f, 0xea, 0xdf, 0x7a, 0x4f, 0xca, 0x85, 0xc6, 0xb3, 0x3f, 0x27, 0x96, 0xf1, - 0x66, 0x62, 0x19, 0x6f, 0x27, 0x96, 0xf1, 0xd7, 0xc4, 0x32, 0x7e, 0xbb, 0xb0, 0x36, 0xde, 0x5c, - 0x58, 0x1b, 0x6f, 0x2f, 0xac, 0x8d, 0x1f, 0x1f, 0x0f, 0x88, 0x7c, 0x91, 0xf6, 0x9d, 0x90, 0xc5, - 0xae, 0xba, 0x80, 0x0f, 0x29, 0xc8, 0x57, 0x8c, 0x9f, 0xb9, 0xf3, 0x37, 0xf9, 0x7c, 0xf9, 0x1f, - 0x80, 0x7e, 0x9a, 0xfb, 0xdb, 0xfa, 0x6d, 0x7e, 0xfc, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x8b, - 0xd5, 0xac, 0x44, 0x25, 0x08, 0x00, 0x00, + // 842 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x56, 0x4f, 0x6f, 0x1b, 0x45, + 0x14, 0xcf, 0x3a, 0x6e, 0x90, 0x87, 0x24, 0xb5, 0xb7, 0x49, 0xe5, 0x06, 0xb2, 0x1b, 0x22, 0x84, + 0x42, 0x45, 0x77, 0x95, 0x16, 0x71, 0x44, 0xd8, 0xae, 0x8b, 0x56, 0x02, 0xdb, 0x1d, 0x13, 0x54, + 0x71, 0x60, 0x59, 0xef, 0xbe, 0xb8, 0x43, 0xbc, 0x33, 0xdb, 0x99, 0x59, 0x37, 0x3d, 0xf2, 0x0d, + 0xf8, 0x18, 0x7c, 0x0a, 0x8e, 0x88, 0x63, 0x8f, 0x3d, 0x59, 0xc8, 0xb9, 0xf9, 0x0b, 0x70, 0x45, + 0x33, 0xbb, 0xfe, 0x13, 0x27, 0x38, 0x08, 0xc4, 0xad, 0x17, 0x7b, 0xe6, 0xbd, 0xdf, 0xef, 0x37, + 0x33, 0xef, 0xfd, 0xc6, 0x63, 0x64, 0x27, 0xec, 0x4c, 0x72, 0x36, 0x18, 0xb8, 0x92, 0x9d, 0x01, + 0x65, 0x31, 0x09, 0x85, 0x0b, 0x43, 0xa0, 0xd2, 0x49, 0x38, 0x93, 0xcc, 0xbc, 0x33, 0x05, 0x38, + 0x73, 0xc0, 0x9e, 0x15, 0x32, 0x11, 0x33, 0xe1, 0xf6, 0x02, 0x01, 0xee, 0xf0, 0xb8, 0x07, 0x32, + 0x38, 0x76, 0x43, 0x46, 0x68, 0x46, 0xda, 0xdb, 0xe9, 0xb3, 0x3e, 0xd3, 0x43, 0x57, 0x8d, 0xf2, + 0xe8, 0xde, 0x6c, 0xad, 0x84, 0x33, 0x76, 0xea, 0xca, 0x57, 0x09, 0x88, 0x2c, 0x77, 0xf8, 0xe7, + 0x3a, 0xaa, 0x34, 0xd5, 0xb2, 0x8d, 0x41, 0x40, 0xe2, 0xe6, 0x79, 0x42, 0x38, 0x44, 0xe6, 0x67, + 0xe8, 0x56, 0xa8, 0xe6, 0x55, 0xe3, 0xc0, 0x38, 0x7a, 0xf7, 0xe1, 0xae, 0x33, 0xdb, 0x8c, 0x56, + 0x70, 0x34, 0xb8, 0x5e, 0x9a, 0x8c, 0xec, 0x0c, 0x87, 0xb3, 0x2f, 0x93, 0xa2, 0x0a, 0x28, 0x89, + 0x40, 0x12, 0x46, 0x7d, 0x0e, 0x81, 0x60, 0xb4, 0x5a, 0x38, 0x30, 0x8e, 0xb6, 0x1f, 0xde, 0x77, + 0xae, 0x39, 0x90, 0x33, 0x5f, 0x55, 0x53, 0xb0, 0x66, 0xd4, 0x77, 0x27, 0x23, 0xfb, 0xaa, 0x10, + 0x2e, 0xc3, 0x12, 0xd0, 0x7c, 0x80, 0x10, 0x4d, 0x63, 0x9f, 0xc3, 0x20, 0x78, 0x25, 0xaa, 0xeb, + 0x07, 0xc6, 0x51, 0xb1, 0xbe, 0x3d, 0x19, 0xd9, 0x0b, 0x51, 0x5c, 0xa2, 0x69, 0x8c, 0xf5, 0xd0, + 0x7c, 0x86, 0xee, 0xa9, 0x84, 0xde, 0x2b, 0x44, 0x7e, 0xc8, 0xe2, 0x24, 0x95, 0xe0, 0xa7, 0x94, + 0x48, 0x51, 0x2d, 0x6a, 0xf6, 0xfe, 0x64, 0x64, 0xff, 0x3d, 0x08, 0xdf, 0xa5, 0x69, 0xdc, 0xc8, + 0x32, 0x8d, 0x2c, 0x71, 0xa2, 0xe2, 0xe6, 0xf7, 0xe8, 0x3d, 0x45, 0x02, 0x21, 0x49, 0x1c, 0xc8, + 0x2b, 0xda, 0xb7, 0xb4, 0xb6, 0x3d, 0x19, 0xd9, 0xab, 0x60, 0xb8, 0x4a, 0xd3, 0xb8, 0x39, 0xcd, + 0x5d, 0xd2, 0x7f, 0x8a, 0xb6, 0xa6, 0x1b, 0x4a, 0x55, 0x1d, 0xab, 0x1b, 0xba, 0x31, 0xf7, 0x9c, + 0xcc, 0x10, 0x8e, 0x32, 0x84, 0x93, 0x1b, 0xc2, 0x69, 0x30, 0x42, 0xeb, 0x95, 0xc9, 0xc8, 0xbe, + 0xcc, 0xc1, 0x9b, 0xf9, 0xf4, 0x44, 0xcd, 0x0e, 0x7f, 0x2b, 0x2e, 0x76, 0xbe, 0x0b, 0x52, 0x0e, + 0xfe, 0x43, 0xe7, 0x7f, 0x44, 0x15, 0x0d, 0xf0, 0x39, 0xbc, 0x48, 0x09, 0x87, 0x18, 0xa8, 0xcc, + 0x3b, 0xff, 0xd1, 0xb2, 0x46, 0x47, 0x7d, 0xe2, 0x39, 0x6e, 0xb1, 0xeb, 0x57, 0x44, 0x70, 0x39, + 0x59, 0x82, 0xbf, 0xed, 0xfa, 0xbf, 0xef, 0xba, 0x92, 0x14, 0x59, 0xab, 0x73, 0xc9, 0x77, 0xfe, + 0x91, 0xe4, 0x25, 0x0e, 0xde, 0xcc, 0xa7, 0x99, 0x91, 0x7e, 0x2a, 0xa0, 0xf7, 0xb5, 0x91, 0x6a, + 0x49, 0x32, 0x20, 0xa1, 0xbe, 0x9f, 0xed, 0x21, 0x70, 0x01, 0x7c, 0x48, 0x42, 0x88, 0xcc, 0x8f, + 0x51, 0x39, 0x98, 0xa7, 0xfc, 0x20, 0x8a, 0xb8, 0xb6, 0x57, 0x09, 0xdf, 0x5e, 0x88, 0xd7, 0xa2, + 0x88, 0x9b, 0x9f, 0xa2, 0xbb, 0x22, 0x55, 0x31, 0xe0, 0x3e, 0x4b, 0x80, 0x07, 0x92, 0xf1, 0x8c, + 0x50, 0xd0, 0x84, 0x9d, 0x69, 0xb6, 0x9d, 0x27, 0x35, 0xeb, 0x73, 0xb4, 0x05, 0xe7, 0x09, 0x84, + 0xaa, 0xb6, 0xbd, 0x94, 0x53, 0xed, 0x89, 0x55, 0x87, 0xc2, 0x9b, 0x53, 0x7c, 0x3d, 0xe5, 0xd4, + 0xfc, 0x02, 0x6d, 0xc3, 0xe9, 0x29, 0x84, 0x92, 0x0c, 0x21, 0x13, 0x28, 0xde, 0x24, 0xb0, 0x35, + 0x23, 0x28, 0x85, 0xc3, 0x5f, 0x0d, 0xb4, 0xa3, 0x6b, 0xd0, 0xcd, 0xf7, 0xd7, 0x1d, 0x04, 0xe2, + 0x39, 0x44, 0x2b, 0x0e, 0x64, 0xac, 0x38, 0xd0, 0x27, 0xc8, 0xd4, 0x8e, 0xc9, 0x7e, 0x8e, 0x33, + 0x57, 0x0a, 0x5d, 0x82, 0x22, 0x2e, 0x2b, 0xbb, 0x64, 0x09, 0xed, 0x49, 0x61, 0xd6, 0xd1, 0x6d, + 0xa1, 0x96, 0x23, 0xb4, 0xef, 0x07, 0x31, 0x4b, 0xa9, 0xbc, 0xb9, 0x00, 0xdb, 0x53, 0x46, 0x4d, + 0x13, 0x0e, 0x7f, 0x29, 0xa0, 0x0f, 0x97, 0x9b, 0x88, 0x81, 0xc4, 0xbd, 0x94, 0x8b, 0xfc, 0x92, + 0xbe, 0x48, 0x41, 0xc8, 0xff, 0xbf, 0x99, 0x0e, 0xba, 0x33, 0x67, 0xbd, 0xa4, 0x90, 0x53, 0xd6, + 0x35, 0xa5, 0x32, 0xa3, 0xa8, 0x8c, 0xc6, 0xef, 0x23, 0x94, 0x3b, 0xcd, 0x27, 0x91, 0x6e, 0x5c, + 0x09, 0x97, 0xf2, 0x88, 0x17, 0x65, 0x69, 0x21, 0xd4, 0x5e, 0x49, 0xa4, 0xaf, 0xa4, 0x4e, 0xeb, + 0x88, 0x17, 0x99, 0xc7, 0x68, 0x23, 0x2f, 0xd9, 0x4d, 0x77, 0x0b, 0xe7, 0xc0, 0xfb, 0x3f, 0xa0, + 0xdd, 0x6b, 0x9f, 0x2d, 0xf3, 0x03, 0xb4, 0xdf, 0x7c, 0xd6, 0xf1, 0x70, 0xed, 0x1b, 0xaf, 0xdd, + 0xf2, 0x71, 0xb3, 0xd6, 0x6d, 0xb7, 0xfc, 0x93, 0x56, 0xb7, 0xd3, 0x6c, 0x78, 0x4f, 0xbc, 0xe6, + 0xe3, 0xf2, 0x9a, 0x59, 0x41, 0x5b, 0x1d, 0xdc, 0x6e, 0x3f, 0xf1, 0xbf, 0xf6, 0xba, 0x5d, 0xaf, + 0xf5, 0x65, 0xd9, 0x98, 0x87, 0xbc, 0xd6, 0xb7, 0xb5, 0xaf, 0xbc, 0xc7, 0xe5, 0x42, 0xfd, 0xe9, + 0xef, 0x63, 0xcb, 0x78, 0x3d, 0xb6, 0x8c, 0x37, 0x63, 0xcb, 0xf8, 0x63, 0x6c, 0x19, 0x3f, 0x5f, + 0x58, 0x6b, 0xaf, 0x2f, 0xac, 0xb5, 0x37, 0x17, 0xd6, 0xda, 0x77, 0x8f, 0xfa, 0x44, 0x3e, 0x4f, + 0x7b, 0x4e, 0xc8, 0x62, 0x57, 0x5d, 0xc0, 0x07, 0x14, 0xe4, 0x4b, 0xc6, 0xcf, 0xdc, 0xd9, 0x33, + 0x7f, 0xbe, 0xf8, 0xa7, 0x42, 0xbf, 0xf6, 0xbd, 0x0d, 0xfd, 0xdc, 0x3f, 0xfa, 0x2b, 0x00, 0x00, + 0xff, 0xff, 0x3e, 0x66, 0x2a, 0x25, 0x78, 0x08, 0x00, 0x00, } func (m *EventClaimExpired) Marshal() (dAtA []byte, err error) { @@ -605,6 +614,18 @@ func (m *EventClaimSettled) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.SettledUpokt != nil { + { + size, err := m.SettledUpokt.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvent(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3a + } if m.ClaimedUpokt != nil { { size, err := m.ClaimedUpokt.MarshalToSizedBuffer(dAtA[:i]) @@ -896,6 +917,10 @@ func (m *EventClaimSettled) Size() (n int) { l = m.ClaimedUpokt.Size() n += 1 + l + sovEvent(uint64(l)) } + if m.SettledUpokt != nil { + l = m.SettledUpokt.Size() + n += 1 + l + sovEvent(uint64(l)) + } return n } @@ -1358,6 +1383,42 @@ func (m *EventClaimSettled) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SettledUpokt", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvent + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEvent + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvent + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.SettledUpokt == nil { + m.SettledUpokt = &types1.Coin{} + } + if err := m.SettledUpokt.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipEvent(dAtA[iNdEx:]) diff --git a/x/tokenomics/types/expected_keepers.go b/x/tokenomics/types/expected_keepers.go index 38d6670b9..c4e5f5d63 100644 --- a/x/tokenomics/types/expected_keepers.go +++ b/x/tokenomics/types/expected_keepers.go @@ -46,6 +46,7 @@ type ApplicationKeeper interface { GetAllApplications(ctx context.Context) []apptypes.Application UnbondApplication(ctx context.Context, app *apptypes.Application) error EndBlockerUnbondApplications(ctx context.Context) error + GetParams(ctx context.Context) apptypes.Params } type ProofKeeper interface {