diff --git a/api/poktroll/proof/event.pulsar.go b/api/poktroll/proof/event.pulsar.go index 2954b58b7..fa9a83ea1 100644 --- a/api/poktroll/proof/event.pulsar.go +++ b/api/poktroll/proof/event.pulsar.go @@ -2804,6 +2804,601 @@ func (x *fastReflection_EventProofUpdated) ProtoMethods() *protoiface.Methods { } } +var ( + md_EventProofValidityChecked protoreflect.MessageDescriptor + fd_EventProofValidityChecked_proof protoreflect.FieldDescriptor + fd_EventProofValidityChecked_block_height protoreflect.FieldDescriptor + fd_EventProofValidityChecked_proof_status protoreflect.FieldDescriptor + fd_EventProofValidityChecked_reason protoreflect.FieldDescriptor +) + +func init() { + file_poktroll_proof_event_proto_init() + md_EventProofValidityChecked = File_poktroll_proof_event_proto.Messages().ByName("EventProofValidityChecked") + fd_EventProofValidityChecked_proof = md_EventProofValidityChecked.Fields().ByName("proof") + fd_EventProofValidityChecked_block_height = md_EventProofValidityChecked.Fields().ByName("block_height") + fd_EventProofValidityChecked_proof_status = md_EventProofValidityChecked.Fields().ByName("proof_status") + fd_EventProofValidityChecked_reason = md_EventProofValidityChecked.Fields().ByName("reason") +} + +var _ protoreflect.Message = (*fastReflection_EventProofValidityChecked)(nil) + +type fastReflection_EventProofValidityChecked EventProofValidityChecked + +func (x *EventProofValidityChecked) ProtoReflect() protoreflect.Message { + return (*fastReflection_EventProofValidityChecked)(x) +} + +func (x *EventProofValidityChecked) slowProtoReflect() protoreflect.Message { + mi := &file_poktroll_proof_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_EventProofValidityChecked_messageType fastReflection_EventProofValidityChecked_messageType +var _ protoreflect.MessageType = fastReflection_EventProofValidityChecked_messageType{} + +type fastReflection_EventProofValidityChecked_messageType struct{} + +func (x fastReflection_EventProofValidityChecked_messageType) Zero() protoreflect.Message { + return (*fastReflection_EventProofValidityChecked)(nil) +} +func (x fastReflection_EventProofValidityChecked_messageType) New() protoreflect.Message { + return new(fastReflection_EventProofValidityChecked) +} +func (x fastReflection_EventProofValidityChecked_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_EventProofValidityChecked +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_EventProofValidityChecked) Descriptor() protoreflect.MessageDescriptor { + return md_EventProofValidityChecked +} + +// 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_EventProofValidityChecked) Type() protoreflect.MessageType { + return _fastReflection_EventProofValidityChecked_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_EventProofValidityChecked) New() protoreflect.Message { + return new(fastReflection_EventProofValidityChecked) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_EventProofValidityChecked) Interface() protoreflect.ProtoMessage { + return (*EventProofValidityChecked)(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_EventProofValidityChecked) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.Proof != nil { + value := protoreflect.ValueOfMessage(x.Proof.ProtoReflect()) + if !f(fd_EventProofValidityChecked_proof, value) { + return + } + } + if x.BlockHeight != uint64(0) { + value := protoreflect.ValueOfUint64(x.BlockHeight) + if !f(fd_EventProofValidityChecked_block_height, value) { + return + } + } + if x.ProofStatus != 0 { + value := protoreflect.ValueOfEnum((protoreflect.EnumNumber)(x.ProofStatus)) + if !f(fd_EventProofValidityChecked_proof_status, value) { + return + } + } + if x.Reason != "" { + value := protoreflect.ValueOfString(x.Reason) + if !f(fd_EventProofValidityChecked_reason, 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_EventProofValidityChecked) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "poktroll.proof.EventProofValidityChecked.proof": + return x.Proof != nil + case "poktroll.proof.EventProofValidityChecked.block_height": + return x.BlockHeight != uint64(0) + case "poktroll.proof.EventProofValidityChecked.proof_status": + return x.ProofStatus != 0 + case "poktroll.proof.EventProofValidityChecked.reason": + return x.Reason != "" + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.proof.EventProofValidityChecked")) + } + panic(fmt.Errorf("message poktroll.proof.EventProofValidityChecked 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_EventProofValidityChecked) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "poktroll.proof.EventProofValidityChecked.proof": + x.Proof = nil + case "poktroll.proof.EventProofValidityChecked.block_height": + x.BlockHeight = uint64(0) + case "poktroll.proof.EventProofValidityChecked.proof_status": + x.ProofStatus = 0 + case "poktroll.proof.EventProofValidityChecked.reason": + x.Reason = "" + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.proof.EventProofValidityChecked")) + } + panic(fmt.Errorf("message poktroll.proof.EventProofValidityChecked 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_EventProofValidityChecked) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "poktroll.proof.EventProofValidityChecked.proof": + value := x.Proof + return protoreflect.ValueOfMessage(value.ProtoReflect()) + case "poktroll.proof.EventProofValidityChecked.block_height": + value := x.BlockHeight + return protoreflect.ValueOfUint64(value) + case "poktroll.proof.EventProofValidityChecked.proof_status": + value := x.ProofStatus + return protoreflect.ValueOfEnum((protoreflect.EnumNumber)(value)) + case "poktroll.proof.EventProofValidityChecked.reason": + value := x.Reason + return protoreflect.ValueOfString(value) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.proof.EventProofValidityChecked")) + } + panic(fmt.Errorf("message poktroll.proof.EventProofValidityChecked 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_EventProofValidityChecked) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "poktroll.proof.EventProofValidityChecked.proof": + x.Proof = value.Message().Interface().(*Proof) + case "poktroll.proof.EventProofValidityChecked.block_height": + x.BlockHeight = value.Uint() + case "poktroll.proof.EventProofValidityChecked.proof_status": + x.ProofStatus = (ClaimProofStatus)(value.Enum()) + case "poktroll.proof.EventProofValidityChecked.reason": + x.Reason = value.Interface().(string) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.proof.EventProofValidityChecked")) + } + panic(fmt.Errorf("message poktroll.proof.EventProofValidityChecked 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_EventProofValidityChecked) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "poktroll.proof.EventProofValidityChecked.proof": + if x.Proof == nil { + x.Proof = new(Proof) + } + return protoreflect.ValueOfMessage(x.Proof.ProtoReflect()) + case "poktroll.proof.EventProofValidityChecked.block_height": + panic(fmt.Errorf("field block_height of message poktroll.proof.EventProofValidityChecked is not mutable")) + case "poktroll.proof.EventProofValidityChecked.proof_status": + panic(fmt.Errorf("field proof_status of message poktroll.proof.EventProofValidityChecked is not mutable")) + case "poktroll.proof.EventProofValidityChecked.reason": + panic(fmt.Errorf("field reason of message poktroll.proof.EventProofValidityChecked is not mutable")) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.proof.EventProofValidityChecked")) + } + panic(fmt.Errorf("message poktroll.proof.EventProofValidityChecked 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_EventProofValidityChecked) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "poktroll.proof.EventProofValidityChecked.proof": + m := new(Proof) + return protoreflect.ValueOfMessage(m.ProtoReflect()) + case "poktroll.proof.EventProofValidityChecked.block_height": + return protoreflect.ValueOfUint64(uint64(0)) + case "poktroll.proof.EventProofValidityChecked.proof_status": + return protoreflect.ValueOfEnum(0) + case "poktroll.proof.EventProofValidityChecked.reason": + return protoreflect.ValueOfString("") + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.proof.EventProofValidityChecked")) + } + panic(fmt.Errorf("message poktroll.proof.EventProofValidityChecked 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_EventProofValidityChecked) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in poktroll.proof.EventProofValidityChecked", 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_EventProofValidityChecked) 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_EventProofValidityChecked) 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_EventProofValidityChecked) 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_EventProofValidityChecked) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*EventProofValidityChecked) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + if x.Proof != nil { + l = options.Size(x.Proof) + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.BlockHeight != 0 { + n += 1 + runtime.Sov(uint64(x.BlockHeight)) + } + if x.ProofStatus != 0 { + n += 1 + runtime.Sov(uint64(x.ProofStatus)) + } + l = len(x.Reason) + if l > 0 { + 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().(*EventProofValidityChecked) + 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 len(x.Reason) > 0 { + i -= len(x.Reason) + copy(dAtA[i:], x.Reason) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.Reason))) + i-- + dAtA[i] = 0x22 + } + if x.ProofStatus != 0 { + i = runtime.EncodeVarint(dAtA, i, uint64(x.ProofStatus)) + i-- + dAtA[i] = 0x18 + } + if x.BlockHeight != 0 { + i = runtime.EncodeVarint(dAtA, i, uint64(x.BlockHeight)) + i-- + dAtA[i] = 0x10 + } + if x.Proof != nil { + encoded, err := options.Marshal(x.Proof) + 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] = 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().(*EventProofValidityChecked) + 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: EventProofValidityChecked: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: EventProofValidityChecked: 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 Proof", 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.Proof == nil { + x.Proof = &Proof{} + } + if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.Proof); err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field BlockHeight", wireType) + } + x.BlockHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + x.BlockHeight |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field ProofStatus", wireType) + } + x.ProofStatus = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + x.ProofStatus |= ClaimProofStatus(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Reason", 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.Reason = string(dAtA[iNdEx:postIndex]) + 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 @@ -3103,6 +3698,69 @@ func (x *EventProofUpdated) GetClaimedUpokt() *v1beta1.Coin { return nil } +// Event emitted after a proof has been checked for validity in the proof module's +// EndBlocker. +type EventProofValidityChecked struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Proof *Proof `protobuf:"bytes,1,opt,name=proof,proto3" json:"proof,omitempty"` + BlockHeight uint64 `protobuf:"varint,2,opt,name=block_height,json=blockHeight,proto3" json:"block_height,omitempty"` + ProofStatus ClaimProofStatus `protobuf:"varint,3,opt,name=proof_status,json=proofStatus,proto3,enum=poktroll.proof.ClaimProofStatus" json:"proof_status,omitempty"` + // reason is the string representation of the error that led to the proof being + // marked as invalid (e.g. "invalid closest merkle proof", "invalid relay request signature") + Reason string `protobuf:"bytes,4,opt,name=reason,proto3" json:"reason,omitempty"` +} + +func (x *EventProofValidityChecked) Reset() { + *x = EventProofValidityChecked{} + if protoimpl.UnsafeEnabled { + mi := &file_poktroll_proof_event_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EventProofValidityChecked) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EventProofValidityChecked) ProtoMessage() {} + +// Deprecated: Use EventProofValidityChecked.ProtoReflect.Descriptor instead. +func (*EventProofValidityChecked) Descriptor() ([]byte, []int) { + return file_poktroll_proof_event_proto_rawDescGZIP(), []int{4} +} + +func (x *EventProofValidityChecked) GetProof() *Proof { + if x != nil { + return x.Proof + } + return nil +} + +func (x *EventProofValidityChecked) GetBlockHeight() uint64 { + if x != nil { + return x.BlockHeight + } + return 0 +} + +func (x *EventProofValidityChecked) GetProofStatus() ClaimProofStatus { + if x != nil { + return x.ProofStatus + } + return ClaimProofStatus_PENDING_VALIDATION +} + +func (x *EventProofValidityChecked) GetReason() string { + if x != nil { + return x.Reason + } + return "" +} + var File_poktroll_proof_event_proto protoreflect.FileDescriptor var file_poktroll_proof_event_proto_rawDesc = []byte{ @@ -3219,18 +3877,34 @@ var file_poktroll_proof_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, 0x42, 0x9e, 0x01, 0xd8, 0xe2, 0x1e, 0x01, 0x0a, - 0x12, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x70, 0x72, - 0x6f, 0x6f, 0x66, 0x42, 0x0a, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, - 0x01, 0x5a, 0x1f, 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, 0x70, 0x72, 0x6f, - 0x6f, 0x66, 0xa2, 0x02, 0x03, 0x50, 0x50, 0x58, 0xaa, 0x02, 0x0e, 0x50, 0x6f, 0x6b, 0x74, 0x72, - 0x6f, 0x6c, 0x6c, 0x2e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0xca, 0x02, 0x0e, 0x50, 0x6f, 0x6b, 0x74, - 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0xe2, 0x02, 0x1a, 0x50, 0x6f, 0x6b, - 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x5c, 0x47, 0x50, 0x42, 0x4d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0f, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, - 0x6c, 0x6c, 0x3a, 0x3a, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, + 0x6d, 0x65, 0x64, 0x55, 0x70, 0x6f, 0x6b, 0x74, 0x22, 0x83, 0x02, 0x0a, 0x19, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x69, 0x74, 0x79, 0x43, + 0x68, 0x65, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x36, 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, + 0x2e, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x2e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x42, 0x09, 0xea, 0xde, + 0x1f, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x33, + 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x04, 0x42, 0x10, 0xea, 0xde, 0x1f, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, + 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x69, + 0x67, 0x68, 0x74, 0x12, 0x55, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x5f, 0x73, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x70, 0x6f, 0x6b, 0x74, + 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x2e, 0x43, 0x6c, 0x61, 0x69, 0x6d, + 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x42, 0x10, 0xea, 0xde, 0x1f, + 0x0c, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x0b, 0x70, + 0x72, 0x6f, 0x6f, 0x66, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x22, 0x0a, 0x06, 0x72, 0x65, + 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xea, 0xde, 0x1f, 0x06, + 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x42, 0x9e, + 0x01, 0xd8, 0xe2, 0x1e, 0x01, 0x0a, 0x12, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x6f, 0x6b, 0x74, 0x72, + 0x6f, 0x6c, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x42, 0x0a, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x1f, 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, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0xa2, 0x02, 0x03, 0x50, 0x50, 0x58, 0xaa, 0x02, + 0x0e, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0xca, + 0x02, 0x0e, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x50, 0x72, 0x6f, 0x6f, 0x66, + 0xe2, 0x02, 0x1a, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x50, 0x72, 0x6f, 0x6f, + 0x66, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0f, + 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x3a, 0x3a, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -3245,32 +3919,36 @@ func file_poktroll_proof_event_proto_rawDescGZIP() []byte { return file_poktroll_proof_event_proto_rawDescData } -var file_poktroll_proof_event_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_poktroll_proof_event_proto_msgTypes = make([]protoimpl.MessageInfo, 5) var file_poktroll_proof_event_proto_goTypes = []interface{}{ - (*EventClaimCreated)(nil), // 0: poktroll.proof.EventClaimCreated - (*EventClaimUpdated)(nil), // 1: poktroll.proof.EventClaimUpdated - (*EventProofSubmitted)(nil), // 2: poktroll.proof.EventProofSubmitted - (*EventProofUpdated)(nil), // 3: poktroll.proof.EventProofUpdated - (*Claim)(nil), // 4: poktroll.proof.Claim - (*v1beta1.Coin)(nil), // 5: cosmos.base.v1beta1.Coin - (*Proof)(nil), // 6: poktroll.proof.Proof + (*EventClaimCreated)(nil), // 0: poktroll.proof.EventClaimCreated + (*EventClaimUpdated)(nil), // 1: poktroll.proof.EventClaimUpdated + (*EventProofSubmitted)(nil), // 2: poktroll.proof.EventProofSubmitted + (*EventProofUpdated)(nil), // 3: poktroll.proof.EventProofUpdated + (*EventProofValidityChecked)(nil), // 4: poktroll.proof.EventProofValidityChecked + (*Claim)(nil), // 5: poktroll.proof.Claim + (*v1beta1.Coin)(nil), // 6: cosmos.base.v1beta1.Coin + (*Proof)(nil), // 7: poktroll.proof.Proof + (ClaimProofStatus)(0), // 8: poktroll.proof.ClaimProofStatus } var file_poktroll_proof_event_proto_depIdxs = []int32{ - 4, // 0: poktroll.proof.EventClaimCreated.claim:type_name -> poktroll.proof.Claim - 5, // 1: poktroll.proof.EventClaimCreated.claimed_upokt:type_name -> cosmos.base.v1beta1.Coin - 4, // 2: poktroll.proof.EventClaimUpdated.claim:type_name -> poktroll.proof.Claim - 5, // 3: poktroll.proof.EventClaimUpdated.claimed_upokt:type_name -> cosmos.base.v1beta1.Coin - 4, // 4: poktroll.proof.EventProofSubmitted.claim:type_name -> poktroll.proof.Claim - 6, // 5: poktroll.proof.EventProofSubmitted.proof:type_name -> poktroll.proof.Proof - 5, // 6: poktroll.proof.EventProofSubmitted.claimed_upokt:type_name -> cosmos.base.v1beta1.Coin - 4, // 7: poktroll.proof.EventProofUpdated.claim:type_name -> poktroll.proof.Claim - 6, // 8: poktroll.proof.EventProofUpdated.proof:type_name -> poktroll.proof.Proof - 5, // 9: poktroll.proof.EventProofUpdated.claimed_upokt: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 + 5, // 0: poktroll.proof.EventClaimCreated.claim:type_name -> poktroll.proof.Claim + 6, // 1: poktroll.proof.EventClaimCreated.claimed_upokt:type_name -> cosmos.base.v1beta1.Coin + 5, // 2: poktroll.proof.EventClaimUpdated.claim:type_name -> poktroll.proof.Claim + 6, // 3: poktroll.proof.EventClaimUpdated.claimed_upokt:type_name -> cosmos.base.v1beta1.Coin + 5, // 4: poktroll.proof.EventProofSubmitted.claim:type_name -> poktroll.proof.Claim + 7, // 5: poktroll.proof.EventProofSubmitted.proof:type_name -> poktroll.proof.Proof + 6, // 6: poktroll.proof.EventProofSubmitted.claimed_upokt:type_name -> cosmos.base.v1beta1.Coin + 5, // 7: poktroll.proof.EventProofUpdated.claim:type_name -> poktroll.proof.Claim + 7, // 8: poktroll.proof.EventProofUpdated.proof:type_name -> poktroll.proof.Proof + 6, // 9: poktroll.proof.EventProofUpdated.claimed_upokt:type_name -> cosmos.base.v1beta1.Coin + 7, // 10: poktroll.proof.EventProofValidityChecked.proof:type_name -> poktroll.proof.Proof + 8, // 11: poktroll.proof.EventProofValidityChecked.proof_status:type_name -> poktroll.proof.ClaimProofStatus + 12, // [12:12] is the sub-list for method output_type + 12, // [12:12] is the sub-list for method input_type + 12, // [12:12] is the sub-list for extension type_name + 12, // [12:12] is the sub-list for extension extendee + 0, // [0:12] is the sub-list for field type_name } func init() { file_poktroll_proof_event_proto_init() } @@ -3328,6 +4006,18 @@ func file_poktroll_proof_event_proto_init() { return nil } } + file_poktroll_proof_event_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EventProofValidityChecked); 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{ @@ -3335,7 +4025,7 @@ func file_poktroll_proof_event_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_poktroll_proof_event_proto_rawDesc, NumEnums: 0, - NumMessages: 4, + NumMessages: 5, NumExtensions: 0, NumServices: 0, }, diff --git a/api/poktroll/proof/types.pulsar.go b/api/poktroll/proof/types.pulsar.go index ac6d5b248..a49834e88 100644 --- a/api/poktroll/proof/types.pulsar.go +++ b/api/poktroll/proof/types.pulsar.go @@ -585,6 +585,7 @@ var ( fd_Claim_supplier_operator_address protoreflect.FieldDescriptor fd_Claim_session_header protoreflect.FieldDescriptor fd_Claim_root_hash protoreflect.FieldDescriptor + fd_Claim_proof_validation_status protoreflect.FieldDescriptor ) func init() { @@ -593,6 +594,7 @@ func init() { fd_Claim_supplier_operator_address = md_Claim.Fields().ByName("supplier_operator_address") fd_Claim_session_header = md_Claim.Fields().ByName("session_header") fd_Claim_root_hash = md_Claim.Fields().ByName("root_hash") + fd_Claim_proof_validation_status = md_Claim.Fields().ByName("proof_validation_status") } var _ protoreflect.Message = (*fastReflection_Claim)(nil) @@ -678,6 +680,12 @@ func (x *fastReflection_Claim) Range(f func(protoreflect.FieldDescriptor, protor return } } + if x.ProofValidationStatus != 0 { + value := protoreflect.ValueOfEnum((protoreflect.EnumNumber)(x.ProofValidationStatus)) + if !f(fd_Claim_proof_validation_status, value) { + return + } + } } // Has reports whether a field is populated. @@ -699,6 +707,8 @@ func (x *fastReflection_Claim) Has(fd protoreflect.FieldDescriptor) bool { return x.SessionHeader != nil case "poktroll.proof.Claim.root_hash": return len(x.RootHash) != 0 + case "poktroll.proof.Claim.proof_validation_status": + return x.ProofValidationStatus != 0 default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.proof.Claim")) @@ -721,6 +731,8 @@ func (x *fastReflection_Claim) Clear(fd protoreflect.FieldDescriptor) { x.SessionHeader = nil case "poktroll.proof.Claim.root_hash": x.RootHash = nil + case "poktroll.proof.Claim.proof_validation_status": + x.ProofValidationStatus = 0 default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.proof.Claim")) @@ -746,6 +758,9 @@ func (x *fastReflection_Claim) Get(descriptor protoreflect.FieldDescriptor) prot case "poktroll.proof.Claim.root_hash": value := x.RootHash return protoreflect.ValueOfBytes(value) + case "poktroll.proof.Claim.proof_validation_status": + value := x.ProofValidationStatus + return protoreflect.ValueOfEnum((protoreflect.EnumNumber)(value)) default: if descriptor.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.proof.Claim")) @@ -772,6 +787,8 @@ func (x *fastReflection_Claim) Set(fd protoreflect.FieldDescriptor, value protor x.SessionHeader = value.Message().Interface().(*session.SessionHeader) case "poktroll.proof.Claim.root_hash": x.RootHash = value.Bytes() + case "poktroll.proof.Claim.proof_validation_status": + x.ProofValidationStatus = (ClaimProofStatus)(value.Enum()) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.proof.Claim")) @@ -801,6 +818,8 @@ func (x *fastReflection_Claim) Mutable(fd protoreflect.FieldDescriptor) protoref panic(fmt.Errorf("field supplier_operator_address of message poktroll.proof.Claim is not mutable")) case "poktroll.proof.Claim.root_hash": panic(fmt.Errorf("field root_hash of message poktroll.proof.Claim is not mutable")) + case "poktroll.proof.Claim.proof_validation_status": + panic(fmt.Errorf("field proof_validation_status of message poktroll.proof.Claim is not mutable")) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.proof.Claim")) @@ -821,6 +840,8 @@ func (x *fastReflection_Claim) NewField(fd protoreflect.FieldDescriptor) protore return protoreflect.ValueOfMessage(m.ProtoReflect()) case "poktroll.proof.Claim.root_hash": return protoreflect.ValueOfBytes(nil) + case "poktroll.proof.Claim.proof_validation_status": + return protoreflect.ValueOfEnum(0) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.proof.Claim")) @@ -902,6 +923,9 @@ func (x *fastReflection_Claim) ProtoMethods() *protoiface.Methods { if l > 0 { n += 1 + l + runtime.Sov(uint64(l)) } + if x.ProofValidationStatus != 0 { + n += 1 + runtime.Sov(uint64(x.ProofValidationStatus)) + } if x.unknownFields != nil { n += len(x.unknownFields) } @@ -931,6 +955,11 @@ func (x *fastReflection_Claim) ProtoMethods() *protoiface.Methods { i -= len(x.unknownFields) copy(dAtA[i:], x.unknownFields) } + if x.ProofValidationStatus != 0 { + i = runtime.EncodeVarint(dAtA, i, uint64(x.ProofValidationStatus)) + i-- + dAtA[i] = 0x20 + } if len(x.RootHash) > 0 { i -= len(x.RootHash) copy(dAtA[i:], x.RootHash) @@ -1110,6 +1139,25 @@ func (x *fastReflection_Claim) ProtoMethods() *protoiface.Methods { x.RootHash = []byte{} } iNdEx = postIndex + case 4: + if wireType != 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field ProofValidationStatus", wireType) + } + x.ProofValidationStatus = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + x.ProofValidationStatus |= ClaimProofStatus(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := runtime.Skip(dAtA[iNdEx:]) @@ -1263,6 +1311,57 @@ func (ClaimProofStage) EnumDescriptor() ([]byte, []int) { return file_poktroll_proof_types_proto_rawDescGZIP(), []int{1} } +// Status of proof validation for a claim +// Default is PENDING_VALIDATION regardless of proof requirement +type ClaimProofStatus int32 + +const ( + ClaimProofStatus_PENDING_VALIDATION ClaimProofStatus = 0 + ClaimProofStatus_VALIDATED ClaimProofStatus = 1 + ClaimProofStatus_INVALID ClaimProofStatus = 2 +) + +// Enum value maps for ClaimProofStatus. +var ( + ClaimProofStatus_name = map[int32]string{ + 0: "PENDING_VALIDATION", + 1: "VALIDATED", + 2: "INVALID", + } + ClaimProofStatus_value = map[string]int32{ + "PENDING_VALIDATION": 0, + "VALIDATED": 1, + "INVALID": 2, + } +) + +func (x ClaimProofStatus) Enum() *ClaimProofStatus { + p := new(ClaimProofStatus) + *p = x + return p +} + +func (x ClaimProofStatus) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ClaimProofStatus) Descriptor() protoreflect.EnumDescriptor { + return file_poktroll_proof_types_proto_enumTypes[2].Descriptor() +} + +func (ClaimProofStatus) Type() protoreflect.EnumType { + return &file_poktroll_proof_types_proto_enumTypes[2] +} + +func (x ClaimProofStatus) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ClaimProofStatus.Descriptor instead. +func (ClaimProofStatus) EnumDescriptor() ([]byte, []int) { + return file_poktroll_proof_types_proto_rawDescGZIP(), []int{2} +} + type Proof struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1323,11 +1422,14 @@ type Claim struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + // Address of the supplier's operator that submitted this claim. SupplierOperatorAddress string `protobuf:"bytes,1,opt,name=supplier_operator_address,json=supplierOperatorAddress,proto3" json:"supplier_operator_address,omitempty"` // the address of the supplier's operator that submitted this claim - // The session header of the session that this claim is for. + // Session header this claim is for. SessionHeader *session.SessionHeader `protobuf:"bytes,2,opt,name=session_header,json=sessionHeader,proto3" json:"session_header,omitempty"` - // Root hash returned from smt.SMST#Root(). + // Root hash from smt.SMST#Root(). RootHash []byte `protobuf:"bytes,3,opt,name=root_hash,json=rootHash,proto3" json:"root_hash,omitempty"` + // Important: This field MUST only be set by proofKeeper#EnsureValidProofSignaturesAndClosestPath + ProofValidationStatus ClaimProofStatus `protobuf:"varint,4,opt,name=proof_validation_status,json=proofValidationStatus,proto3,enum=poktroll.proof.ClaimProofStatus" json:"proof_validation_status,omitempty"` } func (x *Claim) Reset() { @@ -1371,6 +1473,13 @@ func (x *Claim) GetRootHash() []byte { return nil } +func (x *Claim) GetProofValidationStatus() ClaimProofStatus { + if x != nil { + return x.ProofValidationStatus + } + return ClaimProofStatus_PENDING_VALIDATION +} + var File_poktroll_proof_types_proto protoreflect.FileDescriptor var file_poktroll_proof_types_proto_rawDesc = []byte{ @@ -1395,7 +1504,7 @@ var file_poktroll_proof_types_proto_rawDesc = []byte{ 0x64, 0x65, 0x72, 0x12, 0x30, 0x0a, 0x14, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x73, 0x74, 0x5f, 0x6d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x12, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, - 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x22, 0xc2, 0x01, 0x0a, 0x05, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x12, + 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x22, 0x9c, 0x02, 0x0a, 0x05, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x12, 0x54, 0x0a, 0x19, 0x73, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x5f, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, 0xd2, 0xb4, 0x2d, 0x14, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, @@ -1407,27 +1516,37 @@ var file_poktroll_proof_types_proto_rawDesc = []byte{ 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x0d, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x08, 0x72, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x2a, 0x4c, 0x0a, 0x16, 0x50, 0x72, - 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, - 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x0c, 0x4e, 0x4f, 0x54, 0x5f, 0x52, 0x45, 0x51, 0x55, - 0x49, 0x52, 0x45, 0x44, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x52, 0x4f, 0x42, 0x41, 0x42, - 0x49, 0x4c, 0x49, 0x53, 0x54, 0x49, 0x43, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, 0x54, 0x48, 0x52, - 0x45, 0x53, 0x48, 0x4f, 0x4c, 0x44, 0x10, 0x02, 0x2a, 0x44, 0x0a, 0x0f, 0x43, 0x6c, 0x61, 0x69, - 0x6d, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x53, 0x74, 0x61, 0x67, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x43, - 0x4c, 0x41, 0x49, 0x4d, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x50, 0x52, 0x4f, 0x56, - 0x45, 0x4e, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x45, 0x54, 0x54, 0x4c, 0x45, 0x44, 0x10, - 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x45, 0x58, 0x50, 0x49, 0x52, 0x45, 0x44, 0x10, 0x03, 0x42, 0x9e, - 0x01, 0xd8, 0xe2, 0x1e, 0x01, 0x0a, 0x12, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x6f, 0x6b, 0x74, 0x72, - 0x6f, 0x6c, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x42, 0x0a, 0x54, 0x79, 0x70, 0x65, 0x73, - 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x1f, 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, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0xa2, 0x02, 0x03, 0x50, 0x50, 0x58, 0xaa, 0x02, - 0x0e, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0xca, - 0x02, 0x0e, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x50, 0x72, 0x6f, 0x6f, 0x66, - 0xe2, 0x02, 0x1a, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x50, 0x72, 0x6f, 0x6f, - 0x66, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0f, - 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x3a, 0x3a, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x52, 0x08, 0x72, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x58, 0x0a, 0x17, 0x70, 0x72, + 0x6f, 0x6f, 0x66, 0x5f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x70, 0x6f, + 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x2e, 0x43, 0x6c, 0x61, + 0x69, 0x6d, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x15, 0x70, + 0x72, 0x6f, 0x6f, 0x66, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x2a, 0x4c, 0x0a, 0x16, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x71, + 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x10, + 0x0a, 0x0c, 0x4e, 0x4f, 0x54, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x49, 0x52, 0x45, 0x44, 0x10, 0x00, + 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x52, 0x4f, 0x42, 0x41, 0x42, 0x49, 0x4c, 0x49, 0x53, 0x54, 0x49, + 0x43, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, 0x54, 0x48, 0x52, 0x45, 0x53, 0x48, 0x4f, 0x4c, 0x44, + 0x10, 0x02, 0x2a, 0x44, 0x0a, 0x0f, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x50, 0x72, 0x6f, 0x6f, 0x66, + 0x53, 0x74, 0x61, 0x67, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x4c, 0x41, 0x49, 0x4d, 0x45, 0x44, + 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x50, 0x52, 0x4f, 0x56, 0x45, 0x4e, 0x10, 0x01, 0x12, 0x0b, + 0x0a, 0x07, 0x53, 0x45, 0x54, 0x54, 0x4c, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x45, + 0x58, 0x50, 0x49, 0x52, 0x45, 0x44, 0x10, 0x03, 0x2a, 0x46, 0x0a, 0x10, 0x43, 0x6c, 0x61, 0x69, + 0x6d, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x0a, 0x12, + 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x5f, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x41, 0x54, 0x49, + 0x4f, 0x4e, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x41, 0x54, 0x45, + 0x44, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x02, + 0x42, 0x9e, 0x01, 0xd8, 0xe2, 0x1e, 0x01, 0x0a, 0x12, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x6f, 0x6b, + 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x42, 0x0a, 0x54, 0x79, 0x70, + 0x65, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x1f, 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, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0xa2, 0x02, 0x03, 0x50, 0x50, 0x58, + 0xaa, 0x02, 0x0e, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x50, 0x72, 0x6f, 0x6f, + 0x66, 0xca, 0x02, 0x0e, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x50, 0x72, 0x6f, + 0x6f, 0x66, 0xe2, 0x02, 0x1a, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x50, 0x72, + 0x6f, 0x6f, 0x66, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, + 0x02, 0x0f, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x3a, 0x3a, 0x50, 0x72, 0x6f, 0x6f, + 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1442,23 +1561,25 @@ func file_poktroll_proof_types_proto_rawDescGZIP() []byte { return file_poktroll_proof_types_proto_rawDescData } -var file_poktroll_proof_types_proto_enumTypes = make([]protoimpl.EnumInfo, 2) +var file_poktroll_proof_types_proto_enumTypes = make([]protoimpl.EnumInfo, 3) var file_poktroll_proof_types_proto_msgTypes = make([]protoimpl.MessageInfo, 2) var file_poktroll_proof_types_proto_goTypes = []interface{}{ (ProofRequirementReason)(0), // 0: poktroll.proof.ProofRequirementReason (ClaimProofStage)(0), // 1: poktroll.proof.ClaimProofStage - (*Proof)(nil), // 2: poktroll.proof.Proof - (*Claim)(nil), // 3: poktroll.proof.Claim - (*session.SessionHeader)(nil), // 4: poktroll.session.SessionHeader + (ClaimProofStatus)(0), // 2: poktroll.proof.ClaimProofStatus + (*Proof)(nil), // 3: poktroll.proof.Proof + (*Claim)(nil), // 4: poktroll.proof.Claim + (*session.SessionHeader)(nil), // 5: poktroll.session.SessionHeader } var file_poktroll_proof_types_proto_depIdxs = []int32{ - 4, // 0: poktroll.proof.Proof.session_header:type_name -> poktroll.session.SessionHeader - 4, // 1: poktroll.proof.Claim.session_header:type_name -> poktroll.session.SessionHeader - 2, // [2:2] is the sub-list for method output_type - 2, // [2:2] is the sub-list for method input_type - 2, // [2:2] is the sub-list for extension type_name - 2, // [2:2] is the sub-list for extension extendee - 0, // [0:2] is the sub-list for field type_name + 5, // 0: poktroll.proof.Proof.session_header:type_name -> poktroll.session.SessionHeader + 5, // 1: poktroll.proof.Claim.session_header:type_name -> poktroll.session.SessionHeader + 2, // 2: poktroll.proof.Claim.proof_validation_status:type_name -> poktroll.proof.ClaimProofStatus + 3, // [3:3] is the sub-list for method output_type + 3, // [3:3] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name } func init() { file_poktroll_proof_types_proto_init() } @@ -1497,7 +1618,7 @@ func file_poktroll_proof_types_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_poktroll_proof_types_proto_rawDesc, - NumEnums: 2, + NumEnums: 3, NumMessages: 2, NumExtensions: 0, NumServices: 0, diff --git a/pkg/crypto/protocol/proof_path.go b/pkg/crypto/protocol/proof_path.go index 61f7e23ce..1a48b40ee 100644 --- a/pkg/crypto/protocol/proof_path.go +++ b/pkg/crypto/protocol/proof_path.go @@ -6,20 +6,8 @@ import ( "github.com/pokt-network/smt" ) -// SMT specification used for the proof verification. -var ( - newHasher = sha256.New - SmtSpec smt.TrieSpec -) - -func init() { - // Use a spec that does not prehash values in the smst. This returns a nil value - // hasher for the proof verification in order to avoid hashing the value twice. - SmtSpec = smt.NewTrieSpec( - newHasher(), true, - smt.WithValueHasher(nil), - ) -} +// newHasher is the hash function used by the SMT specification. +var newHasher = sha256.New // GetPathForProof computes the path to be used for proof validation by hashing // the block hash and session id. @@ -31,3 +19,15 @@ func GetPathForProof(blockHash []byte, sessionId string) []byte { return hasher.Sum(nil) } + +// NewSMTSpec returns the SMT specification used for the proof verification. +// It uses a new hasher at every call to avoid concurrency issues that could be +// caused by a shared hasher. +func NewSMTSpec() *smt.TrieSpec { + trieSpec := smt.NewTrieSpec( + newHasher(), true, + smt.WithValueHasher(nil), + ) + + return &trieSpec +} diff --git a/proto/poktroll/proof/event.proto b/proto/poktroll/proof/event.proto index b4e99aad9..271a6c355 100644 --- a/proto/poktroll/proof/event.proto +++ b/proto/poktroll/proof/event.proto @@ -43,3 +43,14 @@ message EventProofUpdated { uint64 num_estimated_compute_units = 5 [(gogoproto.jsontag) = "num_estimated_compute_units"]; cosmos.base.v1beta1.Coin claimed_upokt = 6 [(gogoproto.jsontag) = "claimed_upokt"]; } + +// Event emitted after a proof has been checked for validity in the proof module's +// EndBlocker. +message EventProofValidityChecked { + poktroll.proof.Proof proof = 1 [(gogoproto.jsontag) = "proof"]; + uint64 block_height = 2 [(gogoproto.jsontag) = "block_height"]; + poktroll.proof.ClaimProofStatus proof_status = 3 [(gogoproto.jsontag) = "proof_status"]; + // reason is the string representation of the error that led to the proof being + // marked as invalid (e.g. "invalid closest merkle proof", "invalid relay request signature") + string reason = 4 [(gogoproto.jsontag) = "reason"]; +} diff --git a/proto/poktroll/proof/types.proto b/proto/poktroll/proof/types.proto index d131adf90..c35b08fb8 100644 --- a/proto/poktroll/proof/types.proto +++ b/proto/poktroll/proof/types.proto @@ -24,11 +24,17 @@ message Proof { // Claim is the serialized object stored onchain for claims pending to be proven message Claim { + // Address of the supplier's operator that submitted this claim. string supplier_operator_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; // the address of the supplier's operator that submitted this claim - // The session header of the session that this claim is for. + + // Session header this claim is for. poktroll.session.SessionHeader session_header = 2; - // Root hash returned from smt.SMST#Root(). + + // Root hash from smt.SMST#Root(). bytes root_hash = 3; + + // Important: This field MUST only be set by proofKeeper#EnsureValidProofSignaturesAndClosestPath + ClaimProofStatus proof_validation_status = 4; } enum ProofRequirementReason { @@ -43,3 +49,11 @@ enum ClaimProofStage { SETTLED = 2; EXPIRED = 3; } + +// Status of proof validation for a claim +// Default is PENDING_VALIDATION regardless of proof requirement +enum ClaimProofStatus { + PENDING_VALIDATION = 0; + VALIDATED = 1; + INVALID = 2; +} \ No newline at end of file diff --git a/testutil/testtree/tree.go b/testutil/testtree/tree.go index 737e710d0..6252926e2 100644 --- a/testutil/testtree/tree.go +++ b/testutil/testtree/tree.go @@ -152,5 +152,6 @@ func NewClaim( SupplierOperatorAddress: supplierOperatorAddr, SessionHeader: sessionHeader, RootHash: rootHash, + ProofValidationStatus: prooftypes.ClaimProofStatus_PENDING_VALIDATION, } } diff --git a/x/proof/keeper/msg_server_submit_proof.go b/x/proof/keeper/msg_server_submit_proof.go index 5952eb94b..30030a818 100644 --- a/x/proof/keeper/msg_server_submit_proof.go +++ b/x/proof/keeper/msg_server_submit_proof.go @@ -19,84 +19,87 @@ import ( sharedtypes "github.com/pokt-network/poktroll/x/shared/types" ) -// SubmitProof is the server handler to submit and store a proof onchain. -// A proof that's stored onchain is what leads to rewards (i.e. inflation) -// downstream, making this a critical part of the protocol. +// SubmitProof is the server message handler that stores a valid +// proof onchain, enabling downstream reward distribution. // -// Note that the validation of the proof is done in `EnsureValidProof`. However, -// preliminary checks are done in the handler to prevent sybil or DoS attacks on -// full nodes because storing and validating proofs is expensive. +// IMPORTANT: Full proof validation occurs in EnsureValidProofSignaturesAndClosestPath. +// This handler performs preliminary validation to prevent sybil/DoS attacks. // -// We are playing a balance of security and efficiency here, where enough validation -// is done on proof submission, and exhaustive validation is done during session -// settlement. +// There is a security & performance balance and tradeoff between the handler and end blocker: +// - Basic validation on submission (here) +// - Exhaustive validation in endblocker (EnsureValidProofSignaturesAndClosestPath) // -// The entity sending the SubmitProof messages does not necessarily need -// to correspond to the supplier signing the proof. For example, a single entity -// could (theoretically) batch multiple proofs (signed by the corresponding supplier) -// into one transaction to save on transaction fees. +// Note: Proof submitter may differ from supplier signer, allowing batched submissions +// to optimize transaction fees. func (k msgServer) SubmitProof( ctx context.Context, msg *types.MsgSubmitProof, ) (_ *types.MsgSubmitProofResponse, err error) { + sdkCtx := cosmostypes.UnwrapSDKContext(ctx) + // Declare claim to reference in telemetry. var ( - claim = new(types.Claim) + claim *types.Claim isExistingProof bool numRelays uint64 numClaimComputeUnits uint64 + sessionHeader *sessiontypes.SessionHeader ) logger := k.Logger().With("method", "SubmitProof") - sdkCtx := cosmostypes.UnwrapSDKContext(ctx) logger.Info("About to start submitting proof") // Basic validation of the SubmitProof message. if err = msg.ValidateBasic(); err != nil { + logger.Error("failed to validate the submitProof message") return nil, status.Error(codes.InvalidArgument, err.Error()) } - logger.Info("validated the submitProof message") - // Compare msg session header w/ onchain session header. - session, err := k.queryAndValidateSessionHeader(ctx, msg.GetSessionHeader(), msg.GetSupplierOperatorAddress()) - if err != nil { - return nil, status.Error(codes.InvalidArgument, err.Error()) - } + sessionHeader = msg.GetSessionHeader() + supplierOperatorAddress := msg.GetSupplierOperatorAddress() - // Defer telemetry calls so that they reference the final values the relevant variables. - defer k.finalizeSubmitProofTelemetry(session, msg, isExistingProof, numRelays, numClaimComputeUnits, err) + logger = logger.With( + "session_id", sessionHeader.GetSessionId(), + "application_address", sessionHeader.GetApplicationAddress(), + "service_id", sessionHeader.GetServiceId(), + "session_end_height", sessionHeader.GetSessionEndBlockHeight(), + "supplier_operator_address", supplierOperatorAddress, + ) + logger.Info("validated the submitProof message") - if err = k.deductProofSubmissionFee(ctx, msg.GetSupplierOperatorAddress()); err != nil { - logger.Error(fmt.Sprintf("failed to deduct proof submission fee: %v", err)) + // Defer telemetry calls so that they reference the final values the relevant variables. + defer k.finalizeSubmitProofTelemetry(sessionHeader, msg, isExistingProof, numRelays, numClaimComputeUnits, err) + + // Construct the proof from the message. + proof := newProofFromMsg(msg) + + // EnsureWellFormedProof ensures proper proof formation by verifying: + // - Proof structure + // - Associated claim + // - Relay session headers + // - Submission timing within required window + if err = k.EnsureWellFormedProof(ctx, proof); err != nil { + logger.Error(fmt.Sprintf("failed to ensure well-formed proof: %v", err)) return nil, status.Error(codes.FailedPrecondition, err.Error()) } - - // Construct the proof - proof := types.Proof{ - SupplierOperatorAddress: msg.GetSupplierOperatorAddress(), - SessionHeader: session.GetHeader(), - ClosestMerkleProof: msg.GetProof(), + logger.Info("ensured the proof is well-formed") + + // Retrieve the claim associated with the proof. + // The claim should ALWAYS exist since the proof validation in EnsureWellFormedProof + // retrieves and validates the associated claim. + foundClaim, claimFound := k.GetClaim(ctx, sessionHeader.GetSessionId(), supplierOperatorAddress) + if !claimFound { + logger.Error("failed to find the claim associated with the proof") + return nil, status.Error(codes.FailedPrecondition, types.ErrProofClaimNotFound.Error()) } - // Helpers for logging the same metadata throughout this function calls - logger = logger.With( - "session_id", proof.SessionHeader.SessionId, - "session_end_height", proof.SessionHeader.SessionEndBlockHeight, - "supplier_operator_address", proof.SupplierOperatorAddress) + claim = &foundClaim - // Validate proof message commit height is within the respective session's - // proof submission window using the onchain session header. - if err = k.validateProofWindow(ctx, proof.SessionHeader, proof.SupplierOperatorAddress); err != nil { + if err = k.deductProofSubmissionFee(ctx, supplierOperatorAddress); err != nil { + logger.Error(fmt.Sprintf("failed to deduct proof submission fee: %v", err)) return nil, status.Error(codes.FailedPrecondition, err.Error()) } - // Retrieve the corresponding claim for the proof submitted so it can be - // used in the proof validation below. - claim, err = k.queryAndValidateClaimForProof(ctx, proof.SessionHeader, proof.SupplierOperatorAddress) - if err != nil { - return nil, status.Error(codes.Internal, types.ErrProofClaimNotFound.Wrap(err.Error()).Error()) - } - // Check if a proof is required for the claim. proofRequirement, err := k.ProofRequirementForClaim(ctx, claim) if err != nil { @@ -120,7 +123,7 @@ func (k msgServer) SubmitProof( } // Get the service ID relayMiningDifficulty to calculate the claimed uPOKT. - serviceId := session.GetHeader().GetServiceId() + serviceId := sessionHeader.GetServiceId() sharedParams := k.sharedKeeper.GetParams(ctx) relayMiningDifficulty, _ := k.serviceKeeper.GetRelayMiningDifficulty(ctx, serviceId) @@ -131,7 +134,7 @@ func (k msgServer) SubmitProof( _, isExistingProof = k.GetProof(ctx, proof.SessionHeader.SessionId, proof.SupplierOperatorAddress) // Upsert the proof - k.UpsertProof(ctx, proof) + k.UpsertProof(ctx, *proof) logger.Info("successfully upserted the proof") // Emit the appropriate event based on whether the claim was created or updated. @@ -141,7 +144,7 @@ func (k msgServer) SubmitProof( proofUpsertEvent = proto.Message( &types.EventProofUpdated{ Claim: claim, - Proof: &proof, + Proof: proof, NumRelays: numRelays, NumClaimedComputeUnits: numClaimComputeUnits, NumEstimatedComputeUnits: numEstimatedComputUnits, @@ -152,7 +155,7 @@ func (k msgServer) SubmitProof( proofUpsertEvent = proto.Message( &types.EventProofSubmitted{ Claim: claim, - Proof: &proof, + Proof: proof, NumRelays: numRelays, NumClaimedComputeUnits: numClaimComputeUnits, NumEstimatedComputeUnits: numEstimatedComputUnits, @@ -160,6 +163,7 @@ func (k msgServer) SubmitProof( }, ) } + if err = sdkCtx.EventManager().EmitTypedEvent(proofUpsertEvent); err != nil { return nil, status.Error( codes.Internal, @@ -172,7 +176,7 @@ func (k msgServer) SubmitProof( } return &types.MsgSubmitProofResponse{ - Proof: &proof, + Proof: proof, }, nil } @@ -322,10 +326,17 @@ func (k Keeper) getProofRequirementSeedBlockHash( // finalizeSubmitProofTelemetry finalizes telemetry updates for SubmitProof, incrementing counters as needed. // Meant to run deferred. -func (k msgServer) finalizeSubmitProofTelemetry(session *sessiontypes.Session, msg *types.MsgSubmitProof, isExistingProof bool, numRelays, numClaimComputeUnits uint64, err error) { +func (k msgServer) finalizeSubmitProofTelemetry( + sessionHeader *sessiontypes.SessionHeader, + msg *types.MsgSubmitProof, + isExistingProof bool, + numRelays, + numClaimComputeUnits uint64, + err error, +) { if !isExistingProof { - serviceId := session.Header.ServiceId - applicationAddress := session.Header.ApplicationAddress + serviceId := sessionHeader.ServiceId + applicationAddress := sessionHeader.ApplicationAddress supplierOperatorAddress := msg.GetSupplierOperatorAddress() claimProofStage := types.ClaimProofStage_PROVEN.String() @@ -337,7 +348,11 @@ func (k msgServer) finalizeSubmitProofTelemetry(session *sessiontypes.Session, m // finalizeProofRequirementTelemetry finalizes telemetry updates for proof requirements. // Meant to run deferred. -func (k Keeper) finalizeProofRequirementTelemetry(requirementReason types.ProofRequirementReason, claim *types.Claim, err error) { +func (k Keeper) finalizeProofRequirementTelemetry( + requirementReason types.ProofRequirementReason, + claim *types.Claim, + err error, +) { telemetry.ProofRequirementCounter( requirementReason.String(), claim.SessionHeader.ServiceId, @@ -346,3 +361,12 @@ func (k Keeper) finalizeProofRequirementTelemetry(requirementReason types.ProofR err, ) } + +// newProofFromMsg creates a new proof from a MsgSubmitProof message. +func newProofFromMsg(msg *types.MsgSubmitProof) *types.Proof { + return &types.Proof{ + SupplierOperatorAddress: msg.GetSupplierOperatorAddress(), + SessionHeader: msg.GetSessionHeader(), + ClosestMerkleProof: msg.GetProof(), + } +} diff --git a/x/proof/keeper/msg_server_submit_proof_test.go b/x/proof/keeper/msg_server_submit_proof_test.go index 191fdff5d..dbea95aa7 100644 --- a/x/proof/keeper/msg_server_submit_proof_test.go +++ b/x/proof/keeper/msg_server_submit_proof_test.go @@ -630,7 +630,7 @@ func TestMsgServer_SubmitProof_Error(t *testing.T) { }, msgSubmitProofToExpectedErrorFn: func(msgSubmitProof *prooftypes.MsgSubmitProof) error { return status.Error( - codes.InvalidArgument, + codes.FailedPrecondition, prooftypes.ErrProofInvalidSessionId.Wrapf( "session ID does not match onchain session ID; expected %q, got %q", validSessionHeader.GetSessionId(), @@ -652,7 +652,7 @@ func TestMsgServer_SubmitProof_Error(t *testing.T) { }, msgSubmitProofToExpectedErrorFn: func(msgSubmitProof *prooftypes.MsgSubmitProof) error { return status.Error( - codes.InvalidArgument, + codes.FailedPrecondition, prooftypes.ErrProofNotFound.Wrapf( "supplier operator address %q not found in session ID %q", wrongSupplierOperatorAddr, diff --git a/x/proof/keeper/proof.go b/x/proof/keeper/proof.go index 915803199..9a32ddd83 100644 --- a/x/proof/keeper/proof.go +++ b/x/proof/keeper/proof.go @@ -91,11 +91,16 @@ func (k Keeper) RemoveProof(ctx context.Context, sessionId, supplierOperatorAddr ) } -// GetAllProofs returns all proof -func (k Keeper) GetAllProofs(ctx context.Context) (proofs []types.Proof) { +// GetAllProofsIterator returns an iterator for all proofs in the store +func (k Keeper) GetAllProofsIterator(ctx context.Context) storetypes.Iterator { storeAdapter := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) primaryStore := prefix.NewStore(storeAdapter, types.KeyPrefix(types.ProofPrimaryKeyPrefix)) - iterator := storetypes.KVStorePrefixIterator(primaryStore, []byte{}) + return storetypes.KVStorePrefixIterator(primaryStore, []byte{}) +} + +// GetAllProofs returns all proofs in the store +func (k Keeper) GetAllProofs(ctx context.Context) (proofs []types.Proof) { + iterator := k.GetAllProofsIterator(ctx) defer iterator.Close() diff --git a/x/proof/keeper/proof_validation.go b/x/proof/keeper/proof_validation.go index bb45be1aa..bf55d2e3c 100644 --- a/x/proof/keeper/proof_validation.go +++ b/x/proof/keeper/proof_validation.go @@ -31,6 +31,7 @@ package keeper import ( "bytes" "context" + "fmt" cosmostelemetry "github.com/cosmos/cosmos-sdk/telemetry" "github.com/pokt-network/smt" @@ -42,39 +43,31 @@ import ( sessiontypes "github.com/pokt-network/poktroll/x/session/types" ) -// EnsureValidProof validates the proof submitted by the supplier is correct with -// respect to an onchain claim. +// EnsureWellFormedProof validates a supplier's proof for: +// 1. Valid session header +// 2. Submission height within window +// 3. Matching relay request/response headers +// 4. Relay Mining difficulty above reward threshold // -// This function should be called during session settlement (i.e. EndBlocker) -// rather than during proof submission (i.e. SubmitProof) because: -// 1. RPC requests should be quick, lightweight and only do basic validation -// 2. Validators are the ones responsible for the heavy processing & validation during state transitions -// 3. This creates an opportunity to slash suppliers who submit false proofs, whereas -// they can keep retrying if it takes place in the SubmitProof handler. +// EnsureWellFormedProof does not validate computationally expensive operations like: +// 1. Proof relay signatures +// 2. ClosestMerkleProof // -// Note that some of the validation here is redundant with the validation done in -// SubmitProof (in the handler). The reason for this is because were are trying -// to find a balance between preventing sybil or DoS attacks on full nodes -// during proof submission, but being completely exhaustive in all the checks done here. -func (k Keeper) EnsureValidProof( - ctx context.Context, - proof *types.Proof, -) error { - // Telemetry: measure execution time. - defer cosmostelemetry.MeasureSince(cosmostelemetry.Now(), telemetry.MetricNameKeys("proof", "validation")...) - - logger := k.Logger().With("method", "ValidateProof") +// Additional developer context as of #1031: +// - This function is expected to be called from the SubmitProof messages handler +// - Computationally expensive operations are left to the block's EndBlocker +// +// NOTE: Full validation requires passing both: +// 1. EnsureWellFormedProof (this function) +// 2. EnsureValidProofSignaturesAndClosestPath +func (k Keeper) EnsureWellFormedProof(ctx context.Context, proof *types.Proof) error { + logger := k.Logger().With("method", "EnsureWellFormedProof") - // Retrieve the supplier operator's public key. supplierOperatorAddr := proof.SupplierOperatorAddress - supplierOperatorPubKey, err := k.accountQuerier.GetPubKeyFromAddress(ctx, supplierOperatorAddr) - if err != nil { - return err - } // Validate the session header. var onChainSession *sessiontypes.Session - onChainSession, err = k.queryAndValidateSessionHeader(ctx, proof.SessionHeader, supplierOperatorAddr) + onChainSession, err := k.queryAndValidateSessionHeader(ctx, proof.SessionHeader, supplierOperatorAddr) if err != nil { return err } @@ -85,53 +78,63 @@ func (k Keeper) EnsureValidProof( // header which can be derived from known values (e.g. session end height). sessionHeader := onChainSession.GetHeader() + logger = logger.With( + "session_id", sessionHeader.GetSessionId(), + "application_address", sessionHeader.GetApplicationAddress(), + "service_id", sessionHeader.GetServiceId(), + "session_end_height", sessionHeader.GetSessionEndBlockHeight(), + "supplier_operator_address", supplierOperatorAddr, + ) + // Validate proof message commit height is within the respective session's // proof submission window using the onchain session header. if err = k.validateProofWindow(ctx, sessionHeader, supplierOperatorAddr); err != nil { + logger.Error(fmt.Sprintf("failed to validate proof window due to error: %v", err)) return err } if len(proof.ClosestMerkleProof) == 0 { - return types.ErrProofInvalidProof.Wrap("proof cannot be empty") + logger.Error("closest merkle proof cannot be empty") + return types.ErrProofInvalidProof.Wrap("closest merkle proof cannot be empty") } - // Unmarshal the closest merkle proof from the message. + // Unmarshal the sparse compact closest merkle proof from the message. sparseCompactMerkleClosestProof := &smt.SparseCompactMerkleClosestProof{} if err = sparseCompactMerkleClosestProof.Unmarshal(proof.ClosestMerkleProof); err != nil { - return types.ErrProofInvalidProof.Wrapf( - "failed to unmarshal closest merkle proof: %s", - err, - ) + logger.Error(fmt.Sprintf("failed to unmarshal sparse compact merkle closest proof due to error: %v", err)) + return types.ErrProofInvalidProof.Wrapf("failed to unmarshal sparse compact merkle closest proof: %s", err) } // SparseCompactMerkeClosestProof does not implement GetValueHash, so we need to decompact it. - sparseMerkleClosestProof, err := smt.DecompactClosestProof(sparseCompactMerkleClosestProof, &protocol.SmtSpec) + sparseMerkleClosestProof, err := smt.DecompactClosestProof(sparseCompactMerkleClosestProof, protocol.NewSMTSpec()) if err != nil { - return types.ErrProofInvalidProof.Wrapf( - "failed to decompact closest merkle proof: %s", - err, - ) + logger.Error(fmt.Sprintf("failed to decompact sparse merkle closest proof due to error: %v", err)) + return types.ErrProofInvalidProof.Wrapf("failed to decompact sparse erkle closest proof: %s", err) } // Get the relay request and response from the proof.GetClosestMerkleProof. - relayBz := sparseMerkleClosestProof.GetValueHash(&protocol.SmtSpec) + relayBz := sparseMerkleClosestProof.GetValueHash(protocol.NewSMTSpec()) relay := &servicetypes.Relay{} if err = k.cdc.Unmarshal(relayBz, relay); err != nil { - return types.ErrProofInvalidRelay.Wrapf( - "failed to unmarshal relay: %s", - err, - ) + logger.Error(fmt.Sprintf("failed to unmarshal relay due to error: %v", err)) + return types.ErrProofInvalidRelay.Wrapf("failed to unmarshal relay: %s", err) } // Basic validation of the relay request. relayReq := relay.GetReq() if err = relayReq.ValidateBasic(); err != nil { + logger.Error(fmt.Sprintf("failed to validate relay request due to error: %v", err)) return err } logger.Debug("successfully validated relay request") // Make sure that the supplier operator address in the proof matches the one in the relay request. if supplierOperatorAddr != relayReq.Meta.SupplierOperatorAddress { + logger.Error(fmt.Sprintf( + "supplier operator address mismatch; proof: %s, relay request: %s", + supplierOperatorAddr, + relayReq.Meta.SupplierOperatorAddress, + )) return types.ErrProofSupplierMismatch.Wrapf("supplier type mismatch") } logger.Debug("the proof supplier operator address matches the relay request supplier operator address") @@ -139,34 +142,25 @@ func (k Keeper) EnsureValidProof( // Basic validation of the relay response. relayRes := relay.GetRes() if err = relayRes.ValidateBasic(); err != nil { + logger.Error(fmt.Sprintf("failed to validate relay response due to error: %v", err)) return err } logger.Debug("successfully validated relay response") // Verify that the relay request session header matches the proof session header. if err = compareSessionHeaders(sessionHeader, relayReq.Meta.GetSessionHeader()); err != nil { + logger.Error(fmt.Sprintf("relay request and proof session header mismatch: %v", err)) return err } logger.Debug("successfully compared relay request session header") // Verify that the relay response session header matches the proof session header. if err = compareSessionHeaders(sessionHeader, relayRes.Meta.GetSessionHeader()); err != nil { + logger.Error(fmt.Sprintf("relay response and proof session header mismatch: %v", err)) return err } logger.Debug("successfully compared relay response session header") - // Verify the relay request's signature. - if err = k.ringClient.VerifyRelayRequestSignature(ctx, relayReq); err != nil { - return err - } - logger.Debug("successfully verified relay request signature") - - // Verify the relay response's signature. - if err = relayRes.VerifySupplierOperatorSignature(supplierOperatorPubKey); err != nil { - return err - } - logger.Debug("successfully verified relay response signature") - // Get the service's relay mining difficulty. serviceRelayDifficulty, _ := k.serviceKeeper.GetRelayMiningDifficulty(ctx, sessionHeader.GetServiceId()) @@ -175,10 +169,96 @@ func (k Keeper) EnsureValidProof( relayBz, serviceRelayDifficulty.GetTargetHash(), ); err != nil { + logger.Error(fmt.Sprintf("failed to validate relay difficulty due to error: %v", err)) return types.ErrProofInvalidRelayDifficulty.Wrapf("failed to validate relay difficulty for service %s due to: %v", sessionHeader.ServiceId, err) } logger.Debug("successfully validated relay mining difficulty") + // Retrieve the corresponding claim for the proof submitted + if err := k.validateSessionClaim(ctx, sessionHeader, supplierOperatorAddr); err != nil { + return err + } + logger.Debug("successfully retrieved and validated claim") + + return nil +} + +// EnsureValidProofSignaturesAndClosestPath validates: +// 1. Proof signatures from the supplier +// 2. Valid relay request/response signatures from the application/supplier respectively +// 3. Closest path validation against onchain claim +// +// Execution requirements: +// 1. Must run in the EndBlocker of the proof submission height +// 2. Cannot run during SubmitProof due to computational cost +// +// NOTE: Full validation requires passing both: +// 1. EnsureWellFormedProof +// 2. EnsureValidProofSignaturesAndClosestPath (this function) +func (k Keeper) EnsureValidProofSignaturesAndClosestPath( + ctx context.Context, + claim *types.Claim, + proof *types.Proof, +) error { + // Telemetry: measure execution time. + defer cosmostelemetry.MeasureSince(cosmostelemetry.Now(), telemetry.MetricNameKeys("proof", "validation")...) + + sessionHeader := proof.GetSessionHeader() + supplierOperatorAddr := proof.SupplierOperatorAddress + + logger := k.Logger().With( + "method", "EnsureValidProofSignaturesAndClosestPath", + "session_id", sessionHeader.GetSessionId(), + "application_address", sessionHeader.GetApplicationAddress(), + "service_id", sessionHeader.GetServiceId(), + "session_end_height", sessionHeader.GetSessionEndBlockHeight(), + "supplier_operator_address", supplierOperatorAddr, + ) + + // Retrieve the supplier operator's public key. + supplierOperatorPubKey, err := k.accountQuerier.GetPubKeyFromAddress(ctx, supplierOperatorAddr) + if err != nil { + logger.Error(fmt.Sprintf("failed to retrieve supplier operator public key due to error: %v", err)) + return err + } + + // Unmarshal the sparse compact merkle closest proof from the message. + sparseCompactMerkleClosestProof := &smt.SparseCompactMerkleClosestProof{} + if err = sparseCompactMerkleClosestProof.Unmarshal(proof.ClosestMerkleProof); err != nil { + logger.Error(fmt.Sprintf("failed to unmarshal sparse compact merkle closest proof due to error: %v", err)) + return types.ErrProofInvalidProof.Wrapf("failed to unmarshal sparse compact merkle closest proof: %s", err) + } + + // SparseCompactMerkeClosestProof was intentionally compacted to reduce its onchain state size + // so it must be decompacted rather than just retrieving the value via GetValueHash (not implemented). + sparseMerkleClosestProof, err := smt.DecompactClosestProof(sparseCompactMerkleClosestProof, protocol.NewSMTSpec()) + if err != nil { + logger.Error(fmt.Sprintf("failed to decompact sparse merkle closest proof due to error: %v", err)) + return types.ErrProofInvalidProof.Wrapf("failed to decompact sparse merkle closest proof: %s", err) + } + + // Get the relay request and response from the proof.GetClosestMerkleProof. + relayBz := sparseMerkleClosestProof.GetValueHash(protocol.NewSMTSpec()) + relay := &servicetypes.Relay{} + if err = k.cdc.Unmarshal(relayBz, relay); err != nil { + logger.Error(fmt.Sprintf("failed to unmarshal relay due to error: %v", err)) + return types.ErrProofInvalidRelay.Wrapf("failed to unmarshal relay: %s", err) + } + + // Verify the relay request's signature. + if err = k.ringClient.VerifyRelayRequestSignature(ctx, relay.GetReq()); err != nil { + logger.Error(fmt.Sprintf("failed to verify relay request signature due to error: %v", err)) + return err + } + logger.Debug("successfully verified relay request signature") + + // Verify the relay response's signature. + if err = relay.GetRes().VerifySupplierOperatorSignature(supplierOperatorPubKey); err != nil { + logger.Error(fmt.Sprintf("failed to verify relay response signature due to error: %v", err)) + return err + } + logger.Debug("successfully verified relay response signature") + // Validate that path the proof is submitted for matches the expected one // based on the pseudo-random onchain data associated with the header. if err = k.validateClosestPath( @@ -187,24 +267,17 @@ func (k Keeper) EnsureValidProof( sessionHeader, supplierOperatorAddr, ); err != nil { + logger.Error(fmt.Sprintf("failed to validate closest path due to error: %v", err)) return err } logger.Debug("successfully validated proof path") - // Retrieve the corresponding claim for the proof submitted so it can be - // used in the proof validation below. - claim, err := k.queryAndValidateClaimForProof(ctx, sessionHeader, supplierOperatorAddr) - if err != nil { - return err - } - - logger.Debug("successfully retrieved and validated claim") - - // Verify the proof's closest merkle proof. + // Verify the proof's sparse merkle closest proof. if err = verifyClosestProof(sparseMerkleClosestProof, claim.GetRootHash()); err != nil { + logger.Error(fmt.Sprintf("failed to verify sparse merkle closest proof due to error: %v", err)) return err } - logger.Debug("successfully verified closest merkle proof") + logger.Debug("successfully verified sparse merkle closest proof") return nil } @@ -258,21 +331,19 @@ func (k Keeper) validateClosestPath( return nil } -// queryAndValidateClaimForProof ensures that a claim corresponding to the given -// proof's session exists & has a matching supplier operator address and session header, -// it then returns the corresponding claim if the validation is successful. -func (k Keeper) queryAndValidateClaimForProof( +// validateSessionClaim ensures that the given session header and supplierOperatorAddress +// have a corresponding claim. +func (k Keeper) validateSessionClaim( ctx context.Context, sessionHeader *sessiontypes.SessionHeader, supplierOperatorAddr string, -) (*types.Claim, error) { +) error { sessionId := sessionHeader.SessionId - // NB: no need to assert the testSessionId or supplier operator address as it is retrieved - // by respective values of the given proof. I.e., if the claim exists, then these - // values are guaranteed to match. + + // Retrieve the claim corresponding to the session ID and supplier operator address. foundClaim, found := k.GetClaim(ctx, sessionId, supplierOperatorAddr) if !found { - return nil, types.ErrProofClaimNotFound.Wrapf( + return types.ErrProofClaimNotFound.Wrapf( "no claim found for session ID %q and supplier %q", sessionId, supplierOperatorAddr, @@ -280,45 +351,44 @@ func (k Keeper) queryAndValidateClaimForProof( } claimSessionHeader := foundClaim.GetSessionHeader() - proofSessionHeader := sessionHeader // Ensure session start heights match. - if claimSessionHeader.GetSessionStartBlockHeight() != proofSessionHeader.GetSessionStartBlockHeight() { - return nil, types.ErrProofInvalidSessionStartHeight.Wrapf( + if claimSessionHeader.GetSessionStartBlockHeight() != sessionHeader.GetSessionStartBlockHeight() { + return types.ErrProofInvalidSessionStartHeight.Wrapf( "claim session start height %d does not match proof session start height %d", claimSessionHeader.GetSessionStartBlockHeight(), - proofSessionHeader.GetSessionStartBlockHeight(), + sessionHeader.GetSessionStartBlockHeight(), ) } // Ensure session end heights match. - if claimSessionHeader.GetSessionEndBlockHeight() != proofSessionHeader.GetSessionEndBlockHeight() { - return nil, types.ErrProofInvalidSessionEndHeight.Wrapf( + if claimSessionHeader.GetSessionEndBlockHeight() != sessionHeader.GetSessionEndBlockHeight() { + return types.ErrProofInvalidSessionEndHeight.Wrapf( "claim session end height %d does not match proof session end height %d", claimSessionHeader.GetSessionEndBlockHeight(), - proofSessionHeader.GetSessionEndBlockHeight(), + sessionHeader.GetSessionEndBlockHeight(), ) } // Ensure application addresses match. - if claimSessionHeader.GetApplicationAddress() != proofSessionHeader.GetApplicationAddress() { - return nil, types.ErrProofInvalidAddress.Wrapf( + if claimSessionHeader.GetApplicationAddress() != sessionHeader.GetApplicationAddress() { + return types.ErrProofInvalidAddress.Wrapf( "claim application address %q does not match proof application address %q", claimSessionHeader.GetApplicationAddress(), - proofSessionHeader.GetApplicationAddress(), + sessionHeader.GetApplicationAddress(), ) } // Ensure service IDs match. - if claimSessionHeader.GetServiceId() != proofSessionHeader.GetServiceId() { - return nil, types.ErrProofInvalidService.Wrapf( + if claimSessionHeader.GetServiceId() != sessionHeader.GetServiceId() { + return types.ErrProofInvalidService.Wrapf( "claim service ID %q does not match proof service ID %q", claimSessionHeader.GetServiceId(), - proofSessionHeader.GetServiceId(), + sessionHeader.GetServiceId(), ) } - return &foundClaim, nil + return nil } // compareSessionHeaders compares a session header against an expected session header. @@ -379,7 +449,7 @@ func verifyClosestProof( proof *smt.SparseMerkleClosestProof, claimRootHash []byte, ) error { - valid, err := smt.VerifyClosestProof(proof, claimRootHash, &protocol.SmtSpec) + valid, err := smt.VerifyClosestProof(proof, claimRootHash, protocol.NewSMTSpec()) if err != nil { return err } diff --git a/x/proof/keeper/proof_validation_test.go b/x/proof/keeper/proof_validation_test.go index f6c3fa970..f2701db84 100644 --- a/x/proof/keeper/proof_validation_test.go +++ b/x/proof/keeper/proof_validation_test.go @@ -285,7 +285,7 @@ func TestEnsureValidProof_Error(t *testing.T) { return proof }, expectedErr: prooftypes.ErrProofInvalidProof.Wrapf( - "failed to unmarshal closest merkle proof: %s", + "failed to unmarshal sparse compact merkle closest proof: %s", expectedInvalidProofUnmarshalErr, ), }, @@ -611,10 +611,10 @@ func TestEnsureValidProof_Error(t *testing.T) { err = sparseCompactMerkleClosestProof.Unmarshal(proof.ClosestMerkleProof) require.NoError(t, err) var sparseMerkleClosestProof *smt.SparseMerkleClosestProof - sparseMerkleClosestProof, err = smt.DecompactClosestProof(sparseCompactMerkleClosestProof, &protocol.SmtSpec) + sparseMerkleClosestProof, err = smt.DecompactClosestProof(sparseCompactMerkleClosestProof, protocol.NewSMTSpec()) require.NoError(t, err) - relayBz := sparseMerkleClosestProof.GetValueHash(&protocol.SmtSpec) + relayBz := sparseMerkleClosestProof.GetValueHash(protocol.NewSMTSpec()) relayHashArr := protocol.GetRelayHashFromBytes(relayBz) relayHash := relayHashArr[:] @@ -753,6 +753,9 @@ func TestEnsureValidProof_Error(t *testing.T) { for _, test := range tests { t.Run(test.desc, func(t *testing.T) { proof := test.newProof(t) + sessionId := proof.GetSessionHeader().GetSessionId() + supplierOperatorAddr := proof.GetSupplierOperatorAddress() + foundClaim, _ := keepers.GetClaim(ctx, sessionId, supplierOperatorAddr) // Advance the block height to the proof path seed height. earliestSupplierProofCommitHeight := sharedtypes.GetEarliestSupplierProofCommitHeight( @@ -769,8 +772,23 @@ func TestEnsureValidProof_Error(t *testing.T) { // Advance the block height to the earliest proof commit height. ctx = keepertest.SetBlockHeight(ctx, earliestSupplierProofCommitHeight) - err := keepers.EnsureValidProof(ctx, proof) - require.ErrorContains(t, err, test.expectedErr.Error()) + + // A proof is valid IFF it is: + // 1. Well-formed; session header and other metadata + // 2. Has valid relay signatures + // 3. Satisfies the closest merkle path + + // Ensure the proof is well-formed. + if err := keepers.EnsureWellFormedProof(ctx, proof); err != nil { + require.ErrorContains(t, err, test.expectedErr.Error()) + return + } + + // Ensure the proof satisfies the closest merkle path and has valid relay signatures. + if err := keepers.EnsureValidProofSignaturesAndClosestPath(ctx, &foundClaim, proof); err != nil { + require.ErrorContains(t, err, test.expectedErr.Error()) + return + } }) } } diff --git a/x/proof/keeper/validate_proofs.go b/x/proof/keeper/validate_proofs.go new file mode 100644 index 000000000..0e085aafe --- /dev/null +++ b/x/proof/keeper/validate_proofs.go @@ -0,0 +1,206 @@ +package keeper + +import ( + "context" + "fmt" + "runtime" + "sync" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/pokt-network/poktroll/x/proof/types" +) + +// proofValidationTaskCoordinator is a helper struct to coordinate parallel proof +// validation tasks. +type proofValidationTaskCoordinator struct { + // sem is a semaphore to limit the number of concurrent goroutines. + sem chan struct{} + + // wg is a wait group to wait for all goroutines to finish before returning. + wg *sync.WaitGroup + + // processedProofs is a map of supplier operator addresses to the session IDs + // whose proofs that have been processed. + processedProofs map[string][]string + + // numValidProofs and numInvalidProofs are counters to keep track of proof validation results. + numValidProofs, + numInvalidProofs uint64 + + // coordinatorMu protects the coordinator fields. + coordinatorMu *sync.Mutex +} + +// numCPU caches runtime.NumCPU() to avoid being retrieved on every ValidateSubmittedProofs call. +var numCPU int + +func init() { + // Initialize the number of CPU cores available on the machine. + numCPU = runtime.NumCPU() +} + +// ValidateSubmittedProofs performs concurrent proof validation, updating claims' +// proof validation states and removing processed proofs from storage. +func (k Keeper) ValidateSubmittedProofs(ctx sdk.Context) (numValidProofs, numInvalidProofs uint64, err error) { + logger := k.Logger().With("method", "ValidateSubmittedProofs") + + logger.Info(fmt.Sprintf("Number of CPU cores used for parallel proof validation: %d\n", numCPU)) + + // Iterate over proofs using an iterator to prevent OOM issues caused by bulk fetching. + proofIterator := k.GetAllProofsIterator(ctx) + + proofValidationCoordinator := &proofValidationTaskCoordinator{ + // Parallelize proof validation across CPU cores since they are independent from one another. + // Use semaphores to limit concurrent goroutines and prevent memory issues. + sem: make(chan struct{}, numCPU), + // Use a wait group to wait for all goroutines to finish before returning. + wg: &sync.WaitGroup{}, + + processedProofs: make(map[string][]string), + coordinatorMu: &sync.Mutex{}, + } + + for ; proofIterator.Valid(); proofIterator.Next() { + proofBz := proofIterator.Value() + + // Acquire a semaphore to limit the number of goroutines. + // This will block if the sem channel is full. + proofValidationCoordinator.sem <- struct{}{} + + // Increment the wait group to wait for proof validation to finish. + proofValidationCoordinator.wg.Add(1) + + go k.validateProof(ctx, proofBz, proofValidationCoordinator) + } + + // Wait for all goroutines to finish before returning. + proofValidationCoordinator.wg.Wait() + + // Close the proof iterator before deleting the processed proofs. + proofIterator.Close() + + // Delete all the processed proofs from the store since they are no longer needed. + logger.Info("removing processed proofs from the store") + for supplierOperatorAddr, processedProofs := range proofValidationCoordinator.processedProofs { + for _, sessionId := range processedProofs { + k.RemoveProof(ctx, sessionId, supplierOperatorAddr) + logger.Info(fmt.Sprintf( + "removing proof for supplier %s with session ID %s", + supplierOperatorAddr, + sessionId, + )) + } + } + + return proofValidationCoordinator.numValidProofs, proofValidationCoordinator.numInvalidProofs, nil +} + +// validateProof validates a proof submitted by a supplier. +// It marks the corresponding claim as valid or invalid based on the proof validation. +// It is meant to be called concurrently by multiple goroutines to parallelize +// proof validation. +func (k Keeper) validateProof( + ctx context.Context, + proofBz []byte, + coordinator *proofValidationTaskCoordinator, +) { + sdkCtx := sdk.UnwrapSDKContext(ctx) + + logger := k.Logger().With("method", "validateProof") + + // Decrement the wait group when the goroutine finishes. + defer coordinator.wg.Done() + + // Release the semaphore after the goroutine finishes which unblocks another one. + defer func() { <-coordinator.sem }() + + var proof types.Proof + // proofBz is not expected to fail unmarshalling since it is should have + // passed EnsureWellFormedProof validation in MsgSubmitProof handler. + // Panic if it fails unmarshalling. + // If a failure occurs, it indicates either a bug in the code or data corruption. + // In either case, panicking is an appropriate response since both panics and + // returning an error would halt block production. + k.cdc.MustUnmarshal(proofBz, &proof) + + sessionHeader := proof.GetSessionHeader() + supplierOperatorAddr := proof.GetSupplierOperatorAddress() + + logger = logger.With( + "session_id", sessionHeader.GetSessionId(), + "application_address", sessionHeader.GetApplicationAddress(), + "service_id", sessionHeader.GetServiceId(), + "session_end_height", sessionHeader.GetSessionEndBlockHeight(), + "supplier_operator_address", supplierOperatorAddr, + ) + + // Retrieve the corresponding claim for the proof submitted so it can be + // used in the proof validation below. + // EnsureWellFormedProof which is called in MsgSubmitProof handler has already validated + // that the claim referenced by the proof exists and has a matching session header. + claim, claimFound := k.GetClaim(ctx, sessionHeader.GetSessionId(), supplierOperatorAddr) + if !claimFound { + // DEV_NOTE: This should never happen since EnsureWellFormedProof has already checked + // that the proof has a corresponding claim. + logger.Error("no claim found for the corresponding proof") + return + } + logger.Debug("successfully retrieved claim") + + // Set the proof status to valid by default. + proofStatus := types.ClaimProofStatus_VALIDATED + // Set the invalidity reason to an empty string by default. + invalidProofCause := "" + + if err := k.EnsureValidProofSignaturesAndClosestPath(ctx, &claim, &proof); err != nil { + // Set the proof status to invalid. + proofStatus = types.ClaimProofStatus_INVALID + + // Set the invalidity reason to the error message. + invalidProofCause = err.Error() + + logger.Info(fmt.Sprintf("invalid proof due to error: %v", err)) + } + logger.Info(fmt.Sprintf("proof checked, validation result: %s", proofStatus)) + + // Create and emit an event for the proof validation result. + eventProofValidityChecked := types.EventProofValidityChecked{ + Proof: &proof, + BlockHeight: uint64(sdkCtx.BlockHeight()), + ProofStatus: proofStatus, + Reason: invalidProofCause, + } + + if err := sdkCtx.EventManager().EmitTypedEvent(&eventProofValidityChecked); err != nil { + logger.Error(fmt.Sprintf("failed to emit proof validity check event due to: %v", err)) + return + } + + // Protect the subsequent operations from concurrent access. + coordinator.coordinatorMu.Lock() + defer coordinator.coordinatorMu.Unlock() + + // Update the claim to reflect the validation result of the associated proof. + // + // It will be used later by the SettlePendingClaims routine to determine whether: + // 1. The claim should be settled or not + // 2. The corresponding supplier should be slashed or not + claim.ProofValidationStatus = proofStatus + k.UpsertClaim(ctx, claim) + + // Collect the processed proofs info to delete them after the proofIterator is closed + // to prevent iterator invalidation. + coordinator.processedProofs[supplierOperatorAddr] = append( + coordinator.processedProofs[supplierOperatorAddr], + sessionHeader.GetSessionId(), + ) + + if proofStatus == types.ClaimProofStatus_INVALID { + // Increment the number of invalid proofs. + coordinator.numInvalidProofs++ + } else { + // Increment the number of valid proofs. + coordinator.numValidProofs++ + } +} diff --git a/x/proof/module/abci.go b/x/proof/module/abci.go new file mode 100644 index 000000000..5c4f02d4b --- /dev/null +++ b/x/proof/module/abci.go @@ -0,0 +1,37 @@ +package proof + +import ( + "fmt" + + cosmostelemetry "github.com/cosmos/cosmos-sdk/telemetry" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/pokt-network/poktroll/x/proof/keeper" + "github.com/pokt-network/poktroll/x/proof/types" +) + +// EndBlocker is called at every block and handles proof-related operations. +func EndBlocker(ctx sdk.Context, k keeper.Keeper) (err error) { + // Telemetry: measure the end-block execution time following standard cosmos-sdk practices. + defer cosmostelemetry.ModuleMeasureSince(types.ModuleName, cosmostelemetry.Now(), cosmostelemetry.MetricKeyEndBlocker) + + logger := k.Logger().With("method", "EndBlocker") + + // Iterates through all proofs submitted in this block and: + // 1. Updates the proof validation status in the associated claim + // 2. Removes all processed proofs from onchain state + numValidProofs, numInvalidProofs, err := k.ValidateSubmittedProofs(ctx) + if err != nil { + logger.Error(fmt.Sprintf("could not validate submitted proofs due to error %v", err)) + return err + } + + logger.Info(fmt.Sprintf( + "checked %d proofs: %d valid, %d invalid", + numValidProofs+numInvalidProofs, + numValidProofs, + numInvalidProofs, + )) + + return nil +} diff --git a/x/proof/module/module.go b/x/proof/module/module.go index 2cc495194..82d9b04d0 100644 --- a/x/proof/module/module.go +++ b/x/proof/module/module.go @@ -149,8 +149,9 @@ func (am AppModule) BeginBlock(_ context.Context) error { // EndBlock contains the logic that is automatically triggered at the end of each block. // The end block implementation is optional. -func (am AppModule) EndBlock(_ context.Context) error { - return nil +func (am AppModule) EndBlock(goCtx context.Context) error { + ctx := sdk.UnwrapSDKContext(goCtx) + return EndBlocker(ctx, am.keeper) } // IsOnePerModuleType implements the depinject.OnePerModuleType interface. diff --git a/x/proof/types/event.pb.go b/x/proof/types/event.pb.go index 8e467c0c5..45873d3b6 100644 --- a/x/proof/types/event.pb.go +++ b/x/proof/types/event.pb.go @@ -330,46 +330,121 @@ func (m *EventProofUpdated) GetClaimedUpokt() *types.Coin { return nil } +// Event emitted after a proof has been checked for validity in the proof module's +// EndBlocker. +type EventProofValidityChecked struct { + Proof *Proof `protobuf:"bytes,1,opt,name=proof,proto3" json:"proof"` + BlockHeight uint64 `protobuf:"varint,2,opt,name=block_height,json=blockHeight,proto3" json:"block_height"` + ProofStatus ClaimProofStatus `protobuf:"varint,3,opt,name=proof_status,json=proofStatus,proto3,enum=poktroll.proof.ClaimProofStatus" json:"proof_status"` + // reason is the string representation of the error that led to the proof being + // marked as invalid (e.g. "invalid closest merkle proof", "invalid relay request signature") + Reason string `protobuf:"bytes,4,opt,name=reason,proto3" json:"reason"` +} + +func (m *EventProofValidityChecked) Reset() { *m = EventProofValidityChecked{} } +func (m *EventProofValidityChecked) String() string { return proto.CompactTextString(m) } +func (*EventProofValidityChecked) ProtoMessage() {} +func (*EventProofValidityChecked) Descriptor() ([]byte, []int) { + return fileDescriptor_dd4c19e04487fbec, []int{4} +} +func (m *EventProofValidityChecked) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *EventProofValidityChecked) 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 *EventProofValidityChecked) XXX_Merge(src proto.Message) { + xxx_messageInfo_EventProofValidityChecked.Merge(m, src) +} +func (m *EventProofValidityChecked) XXX_Size() int { + return m.Size() +} +func (m *EventProofValidityChecked) XXX_DiscardUnknown() { + xxx_messageInfo_EventProofValidityChecked.DiscardUnknown(m) +} + +var xxx_messageInfo_EventProofValidityChecked proto.InternalMessageInfo + +func (m *EventProofValidityChecked) GetProof() *Proof { + if m != nil { + return m.Proof + } + return nil +} + +func (m *EventProofValidityChecked) GetBlockHeight() uint64 { + if m != nil { + return m.BlockHeight + } + return 0 +} + +func (m *EventProofValidityChecked) GetProofStatus() ClaimProofStatus { + if m != nil { + return m.ProofStatus + } + return ClaimProofStatus_PENDING_VALIDATION +} + +func (m *EventProofValidityChecked) GetReason() string { + if m != nil { + return m.Reason + } + return "" +} + func init() { proto.RegisterType((*EventClaimCreated)(nil), "poktroll.proof.EventClaimCreated") proto.RegisterType((*EventClaimUpdated)(nil), "poktroll.proof.EventClaimUpdated") proto.RegisterType((*EventProofSubmitted)(nil), "poktroll.proof.EventProofSubmitted") proto.RegisterType((*EventProofUpdated)(nil), "poktroll.proof.EventProofUpdated") + proto.RegisterType((*EventProofValidityChecked)(nil), "poktroll.proof.EventProofValidityChecked") } func init() { proto.RegisterFile("poktroll/proof/event.proto", fileDescriptor_dd4c19e04487fbec) } var fileDescriptor_dd4c19e04487fbec = []byte{ - // 451 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x95, 0x3f, 0x8f, 0xd3, 0x30, - 0x18, 0xc6, 0x1b, 0x7a, 0x3d, 0xe9, 0x0c, 0x9c, 0x74, 0xe1, 0x8f, 0x72, 0x45, 0x38, 0x27, 0xa6, - 0x5b, 0xce, 0x56, 0x41, 0xea, 0x07, 0x48, 0xd4, 0x8d, 0x01, 0x82, 0x2a, 0x21, 0x06, 0xaa, 0x24, - 0x35, 0x25, 0x6a, 0x6c, 0x47, 0x89, 0x5d, 0xe8, 0x27, 0x60, 0xe5, 0x1b, 0x21, 0x36, 0xc6, 0x8e, - 0x9d, 0x22, 0x94, 0x6e, 0xf9, 0x14, 0xc8, 0x76, 0x83, 0xda, 0x08, 0x90, 0x50, 0x25, 0x58, 0x3a, - 0xc5, 0x7e, 0x9f, 0xe7, 0xb1, 0x9d, 0xf7, 0x27, 0xcb, 0xa0, 0x9f, 0xf1, 0xb9, 0xc8, 0x79, 0x9a, - 0xe2, 0x2c, 0xe7, 0xfc, 0x1d, 0x26, 0x0b, 0xc2, 0x04, 0xca, 0x72, 0x2e, 0xb8, 0x7d, 0xde, 0x68, - 0x48, 0x6b, 0x7d, 0x18, 0xf3, 0x82, 0xf2, 0x02, 0x47, 0x61, 0x41, 0xf0, 0x62, 0x10, 0x11, 0x11, - 0x0e, 0x70, 0xcc, 0x13, 0x66, 0xfc, 0xfd, 0xfb, 0x33, 0x3e, 0xe3, 0x7a, 0x88, 0xd5, 0x68, 0x5b, - 0x6d, 0xef, 0x20, 0x96, 0x19, 0x29, 0x8c, 0xf6, 0xe4, 0x53, 0x17, 0x5c, 0x8c, 0xd4, 0x8e, 0x7e, - 0x1a, 0x26, 0xd4, 0xcf, 0x49, 0x28, 0xc8, 0xd4, 0x1e, 0x82, 0x5e, 0xac, 0xe6, 0x8e, 0x75, 0x65, - 0x5d, 0xdf, 0x7e, 0xfa, 0x00, 0xed, 0x9f, 0x03, 0x69, 0xb3, 0x77, 0x56, 0x97, 0xae, 0xf1, 0x05, - 0xe6, 0x63, 0xdf, 0x00, 0xc0, 0x24, 0x9d, 0xe4, 0x24, 0x0d, 0x97, 0x85, 0x73, 0xeb, 0xca, 0xba, - 0x3e, 0xf1, 0xce, 0xeb, 0xd2, 0xdd, 0xa9, 0x06, 0x67, 0x4c, 0xd2, 0x40, 0x0f, 0xed, 0xd7, 0xe0, - 0x52, 0x09, 0x3a, 0x4b, 0xa6, 0x93, 0x98, 0xd3, 0x4c, 0x0a, 0x32, 0x91, 0x2c, 0x11, 0x85, 0x73, - 0xa2, 0xd3, 0x8f, 0xeb, 0xd2, 0xfd, 0xbd, 0x29, 0x78, 0xc8, 0x24, 0xf5, 0x8d, 0xe2, 0x1b, 0x61, - 0xac, 0xea, 0xf6, 0x5b, 0xf0, 0x48, 0x85, 0x48, 0x21, 0x12, 0xaa, 0xfe, 0xa8, 0xb5, 0x76, 0x4f, - 0xaf, 0xed, 0xd6, 0xa5, 0xfb, 0x27, 0x5b, 0xe0, 0x30, 0x49, 0x47, 0x8d, 0xb6, 0xb7, 0xfe, 0x4b, - 0x70, 0xb7, 0x39, 0x90, 0x54, 0xbd, 0x71, 0x4e, 0x75, 0xa3, 0x2e, 0x91, 0x01, 0x84, 0x14, 0x20, - 0xb4, 0x05, 0x84, 0x7c, 0x9e, 0x30, 0xef, 0xa2, 0x2e, 0xdd, 0xfd, 0x4c, 0x70, 0x67, 0x3b, 0x1d, - 0xab, 0x59, 0x8b, 0xc4, 0x38, 0x9b, 0x1e, 0x49, 0xfc, 0x27, 0x12, 0x5f, 0xbb, 0xe0, 0x9e, 0x26, - 0xf1, 0x42, 0xb5, 0xf8, 0x95, 0x8c, 0x68, 0x22, 0x0e, 0x61, 0x31, 0x04, 0x3d, 0x6d, 0xd0, 0x18, - 0x7e, 0x91, 0xd3, 0xdb, 0x98, 0x9c, 0x2e, 0x04, 0xe6, 0xd3, 0x62, 0xd8, 0x3d, 0x32, 0xfc, 0x0b, - 0x86, 0x5f, 0x9a, 0xdb, 0xa4, 0x9b, 0x7b, 0xe8, 0x6d, 0x3a, 0x12, 0xfc, 0xe7, 0x04, 0xbd, 0xe7, - 0xdf, 0x2a, 0x68, 0xad, 0x2a, 0x68, 0xad, 0x2b, 0x68, 0x7d, 0xaf, 0xa0, 0xf5, 0x79, 0x03, 0x3b, - 0xab, 0x0d, 0xec, 0xac, 0x37, 0xb0, 0xf3, 0x06, 0xcd, 0x12, 0xf1, 0x5e, 0x46, 0x28, 0xe6, 0x14, - 0x2b, 0xfb, 0x0d, 0x23, 0xe2, 0x03, 0xcf, 0xe7, 0xf8, 0xe7, 0x5b, 0xf7, 0x71, 0xf7, 0xb5, 0x8b, - 0x4e, 0xf5, 0x73, 0xf7, 0xec, 0x47, 0x00, 0x00, 0x00, 0xff, 0xff, 0xa1, 0x12, 0xa3, 0x30, 0x6e, - 0x07, 0x00, 0x00, + // 551 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x95, 0x4f, 0x6f, 0xda, 0x3e, + 0x18, 0xc7, 0x49, 0x29, 0x48, 0x18, 0x7e, 0xe8, 0xd7, 0xec, 0x8f, 0x80, 0x69, 0x09, 0xea, 0xa9, + 0x97, 0x26, 0x6a, 0x2b, 0xf5, 0x05, 0x10, 0x55, 0xda, 0x61, 0x87, 0x2d, 0x13, 0xd3, 0xb4, 0xc3, + 0x50, 0x12, 0x3c, 0xb0, 0x88, 0xed, 0x28, 0xb1, 0xbb, 0x71, 0xde, 0x61, 0xd7, 0xbd, 0xa3, 0x69, + 0xb7, 0x1d, 0x7b, 0xec, 0x29, 0x9a, 0xe0, 0x96, 0x57, 0x31, 0xf9, 0x71, 0x58, 0x01, 0x75, 0x93, + 0xaa, 0x4a, 0xdb, 0x85, 0x93, 0xfd, 0x3c, 0xdf, 0xe7, 0x6b, 0x9b, 0xe7, 0x43, 0x6c, 0xd4, 0x4b, + 0xf8, 0x4c, 0xa4, 0x3c, 0x8e, 0xdd, 0x24, 0xe5, 0xfc, 0xbd, 0x8b, 0x2f, 0x31, 0x13, 0x4e, 0x92, + 0x72, 0xc1, 0xcd, 0xf6, 0x4a, 0x73, 0x40, 0xeb, 0x59, 0x11, 0xcf, 0x28, 0xcf, 0xdc, 0x30, 0xc8, + 0xb0, 0x7b, 0x79, 0x12, 0x62, 0x11, 0x9c, 0xb8, 0x11, 0x27, 0x4c, 0xd7, 0xf7, 0x1e, 0x4e, 0xf8, + 0x84, 0xc3, 0xd4, 0x55, 0xb3, 0x32, 0xbb, 0xbd, 0x83, 0x98, 0x27, 0x38, 0xd3, 0xda, 0xe1, 0xe7, + 0x2a, 0x3a, 0xb8, 0x50, 0x3b, 0x7a, 0x71, 0x40, 0xa8, 0x97, 0xe2, 0x40, 0xe0, 0xb1, 0x79, 0x8e, + 0x6a, 0x91, 0x8a, 0x3b, 0x46, 0xdf, 0x38, 0x6a, 0x9e, 0x3e, 0x72, 0x36, 0xcf, 0xe1, 0x40, 0xf1, + 0xa0, 0x51, 0xe4, 0xb6, 0xae, 0xf3, 0xf5, 0x60, 0x1e, 0x23, 0xc4, 0x24, 0x1d, 0xa5, 0x38, 0x0e, + 0xe6, 0x59, 0x67, 0xaf, 0x6f, 0x1c, 0xed, 0x0f, 0xda, 0x45, 0x6e, 0xaf, 0x65, 0xfd, 0x06, 0x93, + 0xd4, 0x87, 0xa9, 0xf9, 0x06, 0x75, 0x95, 0x00, 0x5e, 0x3c, 0x1e, 0x45, 0x9c, 0x26, 0x52, 0xe0, + 0x91, 0x64, 0x44, 0x64, 0x9d, 0x7d, 0x70, 0x3f, 0x2d, 0x72, 0xfb, 0xf7, 0x45, 0xfe, 0x63, 0x26, + 0xa9, 0xa7, 0x15, 0x4f, 0x0b, 0x43, 0x95, 0x37, 0xdf, 0xa1, 0x27, 0xca, 0x84, 0x33, 0x41, 0xa8, + 0xfa, 0x45, 0x5b, 0x6b, 0xd7, 0x60, 0x6d, 0xbb, 0xc8, 0xed, 0x3f, 0x95, 0xf9, 0x1d, 0x26, 0xe9, + 0xc5, 0x4a, 0xdb, 0x58, 0xff, 0x25, 0xfa, 0x6f, 0x75, 0x20, 0xa9, 0x7a, 0xd3, 0xa9, 0x43, 0xa3, + 0xba, 0x8e, 0x06, 0xe4, 0x28, 0x40, 0x4e, 0x09, 0xc8, 0xf1, 0x38, 0x61, 0x83, 0x83, 0x22, 0xb7, + 0x37, 0x3d, 0x7e, 0xab, 0x0c, 0x87, 0x2a, 0xda, 0x22, 0x31, 0x4c, 0xc6, 0x3b, 0x12, 0xff, 0x88, + 0xc4, 0xb7, 0x2a, 0x7a, 0x00, 0x24, 0x5e, 0xa8, 0x16, 0xbf, 0x92, 0x21, 0x25, 0xe2, 0x3e, 0x2c, + 0xce, 0x51, 0x0d, 0x0a, 0x00, 0xc3, 0x2d, 0x3e, 0xd8, 0x46, 0xfb, 0x20, 0xe1, 0xeb, 0x61, 0x8b, + 0x61, 0x75, 0xc7, 0xf0, 0x0e, 0x0c, 0xbf, 0xae, 0xbe, 0x26, 0x68, 0xee, 0x7d, 0xbf, 0xa6, 0x1d, + 0xc1, 0xbf, 0x4f, 0xf0, 0xd3, 0x1e, 0xea, 0xde, 0x10, 0x7c, 0x1d, 0xc4, 0x64, 0x4c, 0xc4, 0xdc, + 0x9b, 0xe2, 0x68, 0xa6, 0x49, 0x6a, 0x22, 0xc6, 0xdd, 0x88, 0x9c, 0xa1, 0x56, 0x18, 0xf3, 0x68, + 0x36, 0x9a, 0x62, 0x32, 0x99, 0x8a, 0xf2, 0x66, 0xfc, 0xbf, 0xc8, 0xed, 0x8d, 0xbc, 0xdf, 0x84, + 0xe8, 0x19, 0x04, 0xe6, 0x10, 0xb5, 0xc0, 0x3d, 0xca, 0x44, 0x20, 0xa4, 0x06, 0xd9, 0x3e, 0xed, + 0xdf, 0xfa, 0xef, 0xd1, 0x77, 0x06, 0xd4, 0xe9, 0x65, 0xd7, 0x9d, 0x7e, 0x33, 0xb9, 0x91, 0xcd, + 0x43, 0x54, 0x4f, 0x71, 0x90, 0x71, 0x06, 0x6c, 0x1b, 0x03, 0x54, 0xe4, 0x76, 0x99, 0xf1, 0xcb, + 0x71, 0xf0, 0xfc, 0xfb, 0xc2, 0x32, 0xae, 0x16, 0x96, 0x71, 0xbd, 0xb0, 0x8c, 0x1f, 0x0b, 0xcb, + 0xf8, 0xb2, 0xb4, 0x2a, 0x57, 0x4b, 0xab, 0x72, 0xbd, 0xb4, 0x2a, 0x6f, 0x9d, 0x09, 0x11, 0x53, + 0x19, 0x3a, 0x11, 0xa7, 0xae, 0x3a, 0xcc, 0x31, 0xc3, 0xe2, 0x03, 0x4f, 0x67, 0xee, 0xaf, 0x17, + 0xff, 0xe3, 0xfa, 0x9b, 0x1f, 0xd6, 0xe1, 0xd1, 0x3f, 0xfb, 0x19, 0x00, 0x00, 0xff, 0xff, 0x68, + 0x6f, 0xcf, 0x81, 0x74, 0x08, 0x00, 0x00, } func (m *EventClaimCreated) Marshal() (dAtA []byte, err error) { @@ -644,6 +719,58 @@ func (m *EventProofUpdated) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *EventProofValidityChecked) 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 *EventProofValidityChecked) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *EventProofValidityChecked) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Reason) > 0 { + i -= len(m.Reason) + copy(dAtA[i:], m.Reason) + i = encodeVarintEvent(dAtA, i, uint64(len(m.Reason))) + i-- + dAtA[i] = 0x22 + } + if m.ProofStatus != 0 { + i = encodeVarintEvent(dAtA, i, uint64(m.ProofStatus)) + i-- + dAtA[i] = 0x18 + } + if m.BlockHeight != 0 { + i = encodeVarintEvent(dAtA, i, uint64(m.BlockHeight)) + i-- + dAtA[i] = 0x10 + } + if m.Proof != nil { + { + size, err := m.Proof.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvent(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintEvent(dAtA []byte, offset int, v uint64) int { offset -= sovEvent(v) base := offset @@ -767,6 +894,29 @@ func (m *EventProofUpdated) Size() (n int) { return n } +func (m *EventProofValidityChecked) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Proof != nil { + l = m.Proof.Size() + n += 1 + l + sovEvent(uint64(l)) + } + if m.BlockHeight != 0 { + n += 1 + sovEvent(uint64(m.BlockHeight)) + } + if m.ProofStatus != 0 { + n += 1 + sovEvent(uint64(m.ProofStatus)) + } + l = len(m.Reason) + if l > 0 { + n += 1 + l + sovEvent(uint64(l)) + } + return n +} + func sovEvent(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -1561,6 +1711,162 @@ func (m *EventProofUpdated) Unmarshal(dAtA []byte) error { } return nil } +func (m *EventProofValidityChecked) 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: EventProofValidityChecked: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: EventProofValidityChecked: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Proof", 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.Proof == nil { + m.Proof = &Proof{} + } + if err := m.Proof.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field BlockHeight", wireType) + } + m.BlockHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvent + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.BlockHeight |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ProofStatus", wireType) + } + m.ProofStatus = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvent + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ProofStatus |= ClaimProofStatus(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Reason", 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.Reason = string(dAtA[iNdEx:postIndex]) + 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/proof/types/query.pb.go b/x/proof/types/query.pb.go index ebe21a473..c27b6d9c2 100644 --- a/x/proof/types/query.pb.go +++ b/x/proof/types/query.pb.go @@ -436,7 +436,6 @@ func (m *QueryGetProofResponse) GetProof() Proof { type QueryAllProofsRequest struct { Pagination *query.PageRequest `protobuf:"bytes,1,opt,name=pagination,proto3" json:"pagination,omitempty"` // Types that are valid to be assigned to Filter: - // // *QueryAllProofsRequest_SupplierOperatorAddress // *QueryAllProofsRequest_SessionId // *QueryAllProofsRequest_SessionEndHeight diff --git a/x/proof/types/types.pb.go b/x/proof/types/types.pb.go index 088ac987e..dc594d9e0 100644 --- a/x/proof/types/types.pb.go +++ b/x/proof/types/types.pb.go @@ -84,6 +84,36 @@ func (ClaimProofStage) EnumDescriptor() ([]byte, []int) { return fileDescriptor_b75ef15dfd4d6998, []int{1} } +// Status of proof validation for a claim +// Default is PENDING_VALIDATION regardless of proof requirement +type ClaimProofStatus int32 + +const ( + ClaimProofStatus_PENDING_VALIDATION ClaimProofStatus = 0 + ClaimProofStatus_VALIDATED ClaimProofStatus = 1 + ClaimProofStatus_INVALID ClaimProofStatus = 2 +) + +var ClaimProofStatus_name = map[int32]string{ + 0: "PENDING_VALIDATION", + 1: "VALIDATED", + 2: "INVALID", +} + +var ClaimProofStatus_value = map[string]int32{ + "PENDING_VALIDATION": 0, + "VALIDATED": 1, + "INVALID": 2, +} + +func (x ClaimProofStatus) String() string { + return proto.EnumName(ClaimProofStatus_name, int32(x)) +} + +func (ClaimProofStatus) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_b75ef15dfd4d6998, []int{2} +} + type Proof struct { // Address of the supplier's operator that submitted this proof. SupplierOperatorAddress string `protobuf:"bytes,1,opt,name=supplier_operator_address,json=supplierOperatorAddress,proto3" json:"supplier_operator_address,omitempty"` @@ -145,11 +175,14 @@ func (m *Proof) GetClosestMerkleProof() []byte { // Claim is the serialized object stored onchain for claims pending to be proven type Claim struct { + // Address of the supplier's operator that submitted this claim. SupplierOperatorAddress string `protobuf:"bytes,1,opt,name=supplier_operator_address,json=supplierOperatorAddress,proto3" json:"supplier_operator_address,omitempty"` - // The session header of the session that this claim is for. + // Session header this claim is for. SessionHeader *types.SessionHeader `protobuf:"bytes,2,opt,name=session_header,json=sessionHeader,proto3" json:"session_header,omitempty"` - // Root hash returned from smt.SMST#Root(). + // Root hash from smt.SMST#Root(). RootHash []byte `protobuf:"bytes,3,opt,name=root_hash,json=rootHash,proto3" json:"root_hash,omitempty"` + // Important: This field MUST only be set by proofKeeper#EnsureValidProofSignaturesAndClosestPath + ProofValidationStatus ClaimProofStatus `protobuf:"varint,4,opt,name=proof_validation_status,json=proofValidationStatus,proto3,enum=poktroll.proof.ClaimProofStatus" json:"proof_validation_status,omitempty"` } func (m *Claim) Reset() { *m = Claim{} } @@ -202,9 +235,17 @@ func (m *Claim) GetRootHash() []byte { return nil } +func (m *Claim) GetProofValidationStatus() ClaimProofStatus { + if m != nil { + return m.ProofValidationStatus + } + return ClaimProofStatus_PENDING_VALIDATION +} + func init() { proto.RegisterEnum("poktroll.proof.ProofRequirementReason", ProofRequirementReason_name, ProofRequirementReason_value) proto.RegisterEnum("poktroll.proof.ClaimProofStage", ClaimProofStage_name, ClaimProofStage_value) + proto.RegisterEnum("poktroll.proof.ClaimProofStatus", ClaimProofStatus_name, ClaimProofStatus_value) proto.RegisterType((*Proof)(nil), "poktroll.proof.Proof") proto.RegisterType((*Claim)(nil), "poktroll.proof.Claim") } @@ -212,36 +253,41 @@ func init() { func init() { proto.RegisterFile("poktroll/proof/types.proto", fileDescriptor_b75ef15dfd4d6998) } var fileDescriptor_b75ef15dfd4d6998 = []byte{ - // 452 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x92, 0xcf, 0x6e, 0xd3, 0x40, - 0x10, 0xc6, 0xb3, 0xa9, 0x5a, 0xc8, 0xb6, 0x29, 0x66, 0x15, 0x41, 0x1a, 0x90, 0x89, 0x7a, 0x8a, - 0x2a, 0xd5, 0x46, 0xf0, 0x04, 0xf9, 0x63, 0x14, 0x4b, 0x6e, 0x1d, 0xd6, 0x06, 0x21, 0x2e, 0x96, - 0x9b, 0x2c, 0xb6, 0x15, 0xdb, 0x63, 0x76, 0x37, 0x02, 0xde, 0x82, 0x87, 0xe1, 0x09, 0x38, 0x71, - 0xac, 0xb8, 0xd0, 0x23, 0x72, 0x5e, 0x04, 0x79, 0xed, 0x46, 0x79, 0x04, 0x4e, 0xf6, 0xcc, 0x6f, - 0xe6, 0x9b, 0xfd, 0x46, 0x83, 0x07, 0x05, 0xac, 0x25, 0x87, 0x34, 0x35, 0x0b, 0x0e, 0xf0, 0xc9, - 0x94, 0xdf, 0x0a, 0x26, 0x8c, 0x82, 0x83, 0x04, 0x72, 0x7a, 0xcf, 0x0c, 0xc5, 0x06, 0x67, 0x4b, - 0x10, 0x19, 0x88, 0x40, 0x51, 0xb3, 0x0e, 0xea, 0xd2, 0xc1, 0xf3, 0x9d, 0x8c, 0x60, 0x42, 0x24, - 0x90, 0xef, 0x0b, 0x0d, 0x7a, 0x11, 0x44, 0x50, 0x77, 0x55, 0x7f, 0x75, 0xf6, 0xfc, 0x0f, 0xc2, - 0x87, 0x8b, 0x4a, 0x98, 0xf8, 0xf8, 0x4c, 0x6c, 0x8a, 0x22, 0x4d, 0x18, 0x0f, 0xa0, 0x60, 0x3c, - 0x94, 0xc0, 0x83, 0x70, 0xb5, 0xe2, 0x4c, 0x88, 0x3e, 0x1a, 0xa2, 0x51, 0x67, 0xd2, 0xff, 0xfd, - 0xe3, 0xb2, 0xd7, 0x8c, 0x1c, 0xd7, 0xc4, 0x93, 0x3c, 0xc9, 0x23, 0xfa, 0xf4, 0xbe, 0xd5, 0x6d, - 0x3a, 0x1b, 0x4c, 0xde, 0xe0, 0xd3, 0xe6, 0x31, 0x41, 0xcc, 0xc2, 0x15, 0xe3, 0xfd, 0xf6, 0x10, - 0x8d, 0x8e, 0x5f, 0xbd, 0x30, 0x76, 0xbe, 0x1a, 0x6e, 0x78, 0xf5, 0x77, 0xae, 0xca, 0x68, 0x57, - 0xec, 0x87, 0xe4, 0x25, 0xee, 0x2d, 0x53, 0x10, 0x4c, 0xc8, 0x20, 0x63, 0x7c, 0x9d, 0xb2, 0x40, - 0xad, 0xa3, 0x7f, 0x30, 0x44, 0xa3, 0x13, 0x4a, 0x1a, 0x76, 0xa5, 0x90, 0xf2, 0x73, 0xfe, 0x13, - 0xe1, 0xc3, 0x69, 0x1a, 0x26, 0xd9, 0x7f, 0xee, 0xec, 0x19, 0xee, 0x70, 0x00, 0x19, 0xc4, 0xa1, - 0x88, 0x1b, 0x3b, 0x0f, 0xab, 0xc4, 0x3c, 0x14, 0xf1, 0x85, 0x83, 0x9f, 0x28, 0x37, 0x94, 0x7d, - 0xde, 0x24, 0x9c, 0x65, 0x2c, 0x97, 0x94, 0x85, 0x02, 0x72, 0xa2, 0xe1, 0x93, 0x6b, 0xd7, 0x0f, - 0xa8, 0xf5, 0xf6, 0x9d, 0x4d, 0xad, 0x99, 0xd6, 0x22, 0x8f, 0x71, 0x77, 0x41, 0xdd, 0xc9, 0x78, - 0x62, 0x3b, 0xb6, 0xe7, 0xdb, 0x53, 0x0d, 0x91, 0x2e, 0xee, 0xf8, 0x73, 0x6a, 0x79, 0x73, 0xd7, - 0x99, 0x69, 0xed, 0x8b, 0x19, 0x7e, 0xa4, 0x36, 0xa2, 0x24, 0x3d, 0x19, 0x46, 0x8c, 0x1c, 0xe3, - 0x07, 0x53, 0x67, 0x6c, 0x5f, 0x29, 0x05, 0x8c, 0x8f, 0x16, 0xd4, 0x7d, 0x6f, 0x5d, 0x6b, 0xa8, - 0x02, 0x9e, 0xe5, 0xfb, 0x8e, 0x35, 0xd3, 0xda, 0x55, 0x60, 0x7d, 0x58, 0xa8, 0x39, 0x07, 0x13, - 0xe7, 0x57, 0xa9, 0xa3, 0xdb, 0x52, 0x47, 0x77, 0xa5, 0x8e, 0xfe, 0x96, 0x3a, 0xfa, 0xbe, 0xd5, - 0x5b, 0xb7, 0x5b, 0xbd, 0x75, 0xb7, 0xd5, 0x5b, 0x1f, 0x8d, 0x28, 0x91, 0xf1, 0xe6, 0xc6, 0x58, - 0x42, 0x66, 0x56, 0x8b, 0xb8, 0xcc, 0x99, 0xfc, 0x02, 0x7c, 0x6d, 0xee, 0x8e, 0xf3, 0xeb, 0xfe, - 0x95, 0xdf, 0x1c, 0xa9, 0x3b, 0x7c, 0xfd, 0x2f, 0x00, 0x00, 0xff, 0xff, 0x74, 0x9b, 0x7a, 0x80, - 0x04, 0x03, 0x00, 0x00, + // 533 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x53, 0x5f, 0x6e, 0xda, 0x4e, + 0x10, 0x66, 0xc9, 0x2f, 0xf9, 0x95, 0x4d, 0xa0, 0xee, 0x8a, 0x26, 0x84, 0x56, 0x2e, 0xca, 0x13, + 0x42, 0x8a, 0xa9, 0xd2, 0x13, 0x00, 0x76, 0x8a, 0x25, 0xc7, 0xa6, 0x6b, 0x17, 0x45, 0x7d, 0xb1, + 0x36, 0xb0, 0x05, 0x0b, 0xe3, 0x75, 0x77, 0x97, 0xfe, 0xb9, 0x45, 0x0f, 0xd0, 0x63, 0xf4, 0x10, + 0x7d, 0x8c, 0xfa, 0xd2, 0x3c, 0x56, 0x70, 0x91, 0xca, 0x6b, 0x07, 0x91, 0x9e, 0xa0, 0x4f, 0xf6, + 0x7c, 0xdf, 0xcc, 0x37, 0xf3, 0x8d, 0x76, 0x60, 0x33, 0x65, 0x0b, 0xc9, 0x59, 0x1c, 0x77, 0x53, + 0xce, 0xd8, 0xfb, 0xae, 0xfc, 0x92, 0x52, 0x61, 0xa4, 0x9c, 0x49, 0x86, 0x6a, 0xf7, 0x9c, 0xa1, + 0xb8, 0xe6, 0xe9, 0x84, 0x89, 0x25, 0x13, 0xa1, 0x62, 0xbb, 0x79, 0x90, 0xa7, 0x36, 0x9f, 0x6f, + 0x65, 0x04, 0x15, 0x22, 0x62, 0xc9, 0xae, 0x50, 0xb3, 0x3e, 0x63, 0x33, 0x96, 0x57, 0x65, 0x7f, + 0x39, 0x7a, 0xf6, 0x0b, 0xc0, 0xfd, 0x51, 0x26, 0x8c, 0x02, 0x78, 0x2a, 0x56, 0x69, 0x1a, 0x47, + 0x94, 0x87, 0x2c, 0xa5, 0x9c, 0x48, 0xc6, 0x43, 0x32, 0x9d, 0x72, 0x2a, 0x44, 0x03, 0xb4, 0x40, + 0xbb, 0xd2, 0x6f, 0xfc, 0xfc, 0x7e, 0x5e, 0x2f, 0x5a, 0xf6, 0x72, 0xc6, 0x97, 0x3c, 0x4a, 0x66, + 0xf8, 0xe4, 0xbe, 0xd4, 0x2b, 0x2a, 0x0b, 0x1a, 0x5d, 0xc2, 0x5a, 0x31, 0x4c, 0x38, 0xa7, 0x64, + 0x4a, 0x79, 0xa3, 0xdc, 0x02, 0xed, 0xc3, 0x8b, 0x17, 0xc6, 0xd6, 0x57, 0xc1, 0x1b, 0x7e, 0xfe, + 0x1d, 0xaa, 0x34, 0x5c, 0x15, 0xbb, 0x21, 0x7a, 0x09, 0xeb, 0x93, 0x98, 0x09, 0x2a, 0x64, 0xb8, + 0xa4, 0x7c, 0x11, 0xd3, 0x50, 0xad, 0xa3, 0xb1, 0xd7, 0x02, 0xed, 0x23, 0x8c, 0x0a, 0xee, 0x4a, + 0x51, 0xca, 0xcf, 0xd9, 0xb7, 0x32, 0xdc, 0x1f, 0xc4, 0x24, 0x5a, 0xfe, 0xe3, 0xce, 0x9e, 0xc1, + 0x0a, 0x67, 0x4c, 0x86, 0x73, 0x22, 0xe6, 0x85, 0x9d, 0x47, 0x19, 0x30, 0x24, 0x62, 0x8e, 0xae, + 0xe1, 0x89, 0xf2, 0x19, 0x7e, 0x24, 0x71, 0x34, 0x25, 0x32, 0xeb, 0x26, 0x24, 0x91, 0x2b, 0xd1, + 0xf8, 0xaf, 0x05, 0xda, 0xb5, 0x8b, 0x96, 0xf1, 0xf0, 0x7d, 0x18, 0xca, 0xb2, 0xda, 0x80, 0xaf, + 0xf2, 0xf0, 0x53, 0x85, 0x8f, 0xb7, 0xf5, 0x39, 0xdc, 0x71, 0xe0, 0xb1, 0xca, 0xc2, 0xf4, 0xc3, + 0x2a, 0xe2, 0x74, 0x49, 0x13, 0x89, 0x29, 0x11, 0x2c, 0x41, 0x1a, 0x3c, 0x72, 0xbd, 0x20, 0xc4, + 0xd6, 0x9b, 0xb7, 0x36, 0xb6, 0x4c, 0xad, 0x84, 0x9e, 0xc0, 0xea, 0x08, 0x7b, 0xfd, 0x5e, 0xdf, + 0x76, 0x6c, 0x3f, 0xb0, 0x07, 0x1a, 0x40, 0x55, 0x58, 0x09, 0x86, 0xd8, 0xf2, 0x87, 0x9e, 0x63, + 0x6a, 0xe5, 0x8e, 0x09, 0x1f, 0x3f, 0x68, 0x3c, 0xa3, 0xe8, 0x10, 0xfe, 0x3f, 0x70, 0x7a, 0xf6, + 0x95, 0x52, 0x80, 0xf0, 0x60, 0x84, 0xbd, 0xb1, 0xe5, 0x6a, 0x20, 0x23, 0x7c, 0x2b, 0x08, 0x1c, + 0xcb, 0xd4, 0xca, 0x59, 0x60, 0x5d, 0x8f, 0x54, 0x9f, 0xbd, 0xce, 0x25, 0xd4, 0xfe, 0x1e, 0x1f, + 0x1d, 0x43, 0x34, 0xb2, 0x5c, 0xd3, 0x76, 0x5f, 0x87, 0xe3, 0x9e, 0x63, 0x9b, 0xbd, 0xc0, 0xf6, + 0x5c, 0xad, 0x94, 0x0d, 0x50, 0xc4, 0x96, 0x99, 0x8b, 0xda, 0xae, 0x02, 0xb4, 0x72, 0xdf, 0xf9, + 0xb1, 0xd6, 0xc1, 0xed, 0x5a, 0x07, 0x77, 0x6b, 0x1d, 0xfc, 0x5e, 0xeb, 0xe0, 0xeb, 0x46, 0x2f, + 0xdd, 0x6e, 0xf4, 0xd2, 0xdd, 0x46, 0x2f, 0xbd, 0x33, 0x66, 0x91, 0x9c, 0xaf, 0x6e, 0x8c, 0x09, + 0x5b, 0x76, 0xb3, 0xe5, 0x9d, 0x27, 0x54, 0x7e, 0x62, 0x7c, 0xd1, 0xdd, 0x9e, 0xcf, 0xe7, 0xdd, + 0x3b, 0xbc, 0x39, 0x50, 0x97, 0xf2, 0xea, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0x4b, 0xbc, + 0x6b, 0xa6, 0x03, 0x00, 0x00, } func (m *Proof) Marshal() (dAtA []byte, err error) { @@ -313,6 +359,11 @@ func (m *Claim) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.ProofValidationStatus != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.ProofValidationStatus)) + i-- + dAtA[i] = 0x20 + } if len(m.RootHash) > 0 { i -= len(m.RootHash) copy(dAtA[i:], m.RootHash) @@ -392,6 +443,9 @@ func (m *Claim) Size() (n int) { if l > 0 { n += 1 + l + sovTypes(uint64(l)) } + if m.ProofValidationStatus != 0 { + n += 1 + sovTypes(uint64(m.ProofValidationStatus)) + } return n } @@ -684,6 +738,25 @@ func (m *Claim) Unmarshal(dAtA []byte) error { m.RootHash = []byte{} } iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ProofValidationStatus", wireType) + } + m.ProofValidationStatus = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ProofValidationStatus |= ClaimProofStatus(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipTypes(dAtA[iNdEx:]) diff --git a/x/tokenomics/keeper/keeper_settle_pending_claims_test.go b/x/tokenomics/keeper/keeper_settle_pending_claims_test.go index 076663cce..46daae103 100644 --- a/x/tokenomics/keeper/keeper_settle_pending_claims_test.go +++ b/x/tokenomics/keeper/keeper_settle_pending_claims_test.go @@ -384,12 +384,15 @@ func (s *TestSuite) TestSettlePendingClaims_ClaimSettled_ProofRequiredAndProvide s.keepers.UpsertClaim(ctx, s.claim) s.keepers.UpsertProof(ctx, s.proof) + sdkCtx := cosmostypes.UnwrapSDKContext(ctx) + s.keepers.ValidateSubmittedProofs(sdkCtx) + // Settle pending claims after proof window closes // Expectation: All (1) claims should be claimed. // NB: proofs should be rejected when the current height equals the proof window close height. sessionEndHeight := s.claim.SessionHeader.SessionEndBlockHeight blockHeight := sharedtypes.GetProofWindowCloseHeight(&sharedParams, sessionEndHeight) - sdkCtx := cosmostypes.UnwrapSDKContext(ctx).WithBlockHeight(blockHeight) + sdkCtx = cosmostypes.UnwrapSDKContext(ctx).WithBlockHeight(blockHeight) settledResult, expiredResult, err := s.keepers.SettlePendingClaims(sdkCtx) require.NoError(t, err) @@ -440,12 +443,15 @@ func (s *TestSuite) TestSettlePendingClaims_ClaimExpired_ProofRequired_InvalidOn s.keepers.UpsertClaim(ctx, s.claim) s.keepers.UpsertProof(ctx, proof) + sdkCtx := cosmostypes.UnwrapSDKContext(ctx) + s.keepers.ValidateSubmittedProofs(sdkCtx) + // Settle pending claims after proof window closes // Expectation: All (1) claims should be expired. // NB: proofs should be rejected when the current height equals the proof window close height. sessionEndHeight := s.claim.SessionHeader.SessionEndBlockHeight blockHeight := sharedtypes.GetProofWindowCloseHeight(&sharedParams, sessionEndHeight) - sdkCtx := cosmostypes.UnwrapSDKContext(ctx).WithBlockHeight(blockHeight) + sdkCtx = sdkCtx.WithBlockHeight(blockHeight) settledResults, expiredResults, err := s.keepers.SettlePendingClaims(sdkCtx) require.NoError(t, err) @@ -469,10 +475,15 @@ func (s *TestSuite) TestSettlePendingClaims_ClaimExpired_ProofRequired_InvalidOn // Confirm an expiration event was emitted events := sdkCtx.EventManager().Events() - require.Equal(t, 12, len(events)) // minting, burning, settling, etc.. + require.Equal(t, 13, len(events)) // minting, burning, settling, etc.. + expectedClaimExpiredEvents := testutilevents.FilterEvents[*tokenomicstypes.EventClaimExpired](t, events) require.Equal(t, 1, len(expectedClaimExpiredEvents)) + // Confirm an invalid proof removed event was emitted + expectedProofValidityCheckedEvents := testutilevents.FilterEvents[*prooftypes.EventProofValidityChecked](t, events) + require.Equal(t, 1, len(expectedProofValidityCheckedEvents)) + // Validate the event expectedClaimExpiredEvent := expectedClaimExpiredEvents[0] require.Equal(t, tokenomicstypes.ClaimExpirationReason_PROOF_INVALID, expectedClaimExpiredEvent.GetExpirationReason()) @@ -481,6 +492,9 @@ func (s *TestSuite) TestSettlePendingClaims_ClaimExpired_ProofRequired_InvalidOn require.Equal(t, s.numEstimatedComputeUnits, expectedClaimExpiredEvent.GetNumEstimatedComputeUnits()) require.Equal(t, s.claimedUpokt, *expectedClaimExpiredEvent.GetClaimedUpokt()) + expectedProofValidityCheckedEvent := expectedProofValidityCheckedEvents[0] + require.Equal(t, prooftypes.ClaimProofStatus_INVALID, expectedProofValidityCheckedEvent.GetProofStatus()) + // Confirm that a slashing event was emitted expectedSlashingEvents := testutilevents.FilterEvents[*tokenomicstypes.EventSupplierSlashed](t, events) require.Equal(t, 1, len(expectedSlashingEvents)) @@ -516,12 +530,15 @@ func (s *TestSuite) TestClaimSettlement_ClaimSettled_ProofRequiredAndProvided_Vi s.keepers.UpsertClaim(ctx, s.claim) s.keepers.UpsertProof(ctx, s.proof) + sdkCtx := cosmostypes.UnwrapSDKContext(ctx) + s.keepers.ValidateSubmittedProofs(sdkCtx) + // Settle pending claims after proof window closes // Expectation: All (1) claims should be claimed. // NB: proof window has definitely closed at this point sessionEndHeight := s.claim.SessionHeader.SessionEndBlockHeight blockHeight := sharedtypes.GetProofWindowCloseHeight(&sharedParams, sessionEndHeight) - sdkCtx := cosmostypes.UnwrapSDKContext(ctx).WithBlockHeight(blockHeight) + sdkCtx = cosmostypes.UnwrapSDKContext(ctx).WithBlockHeight(blockHeight) settledResults, expiredResults, err := s.keepers.SettlePendingClaims(sdkCtx) require.NoError(t, err) @@ -571,12 +588,15 @@ func (s *TestSuite) TestSettlePendingClaims_Settles_WhenAProofIsNotRequired() { // Upsert the claim only (not the proof) s.keepers.UpsertClaim(ctx, s.claim) + sdkCtx := cosmostypes.UnwrapSDKContext(ctx) + s.keepers.ValidateSubmittedProofs(sdkCtx) + // Settle pending claims after proof window closes // Expectation: All (1) claims should be claimed. // NB: proofs should be rejected when the current height equals the proof window close height. sessionEndHeight := s.claim.SessionHeader.SessionEndBlockHeight blockHeight := sharedtypes.GetProofWindowCloseHeight(&sharedParams, sessionEndHeight) - sdkCtx := cosmostypes.UnwrapSDKContext(ctx).WithBlockHeight(blockHeight) + sdkCtx = cosmostypes.UnwrapSDKContext(ctx).WithBlockHeight(blockHeight) settledResults, expiredResults, err := s.keepers.SettlePendingClaims(sdkCtx) require.NoError(t, err) @@ -771,7 +791,7 @@ func (s *TestSuite) TestSettlePendingClaims_ClaimExpired_SupplierUnstaked() { // Validate the EventSupplierUnbondingBegin event. unbondingEndHeight := sharedtypes.GetSupplierUnbondingEndHeight(&sharedParams, &slashedSupplier) slashedSupplier.ServicesActivationHeightsMap = make(map[string]uint64) - for i, _ := range slashedSupplier.GetServices() { + for i := range slashedSupplier.GetServices() { slashedSupplier.Services[i].Endpoints = make([]*sharedtypes.SupplierEndpoint, 0) } expectedUnbondingBeginEvent := &suppliertypes.EventSupplierUnbondingBegin{ diff --git a/x/tokenomics/keeper/settle_pending_claims.go b/x/tokenomics/keeper/settle_pending_claims.go index c6ecd397a..722d328d6 100644 --- a/x/tokenomics/keeper/settle_pending_claims.go +++ b/x/tokenomics/keeper/settle_pending_claims.go @@ -112,7 +112,6 @@ func (k Keeper) SettlePendingClaims(ctx cosmostypes.Context) ( return settledResults, expiredResults, err } - proof, isProofFound := k.proofKeeper.GetProof(ctx, sessionId, claim.SupplierOperatorAddress) // Using the probabilistic proofs approach, determine if this expiring // claim required an onchain proof proofRequirement, err = k.proofKeeper.ProofRequirementForClaim(ctx, &claim) @@ -135,19 +134,25 @@ func (k Keeper) SettlePendingClaims(ctx cosmostypes.Context) ( proofIsRequired := proofRequirement != prooftypes.ProofRequirementReason_NOT_REQUIRED if proofIsRequired { - expirationReason := tokenomicstypes.ClaimExpirationReason_EXPIRATION_REASON_UNSPECIFIED // EXPIRATION_REASON_UNSPECIFIED is the default - - if isProofFound { - if err = k.proofKeeper.EnsureValidProof(ctx, &proof); err != nil { - logger.Warn(fmt.Sprintf("Proof was found but is invalid due to %v", err)) - expirationReason = tokenomicstypes.ClaimExpirationReason_PROOF_INVALID - } - } else { + // IMPORTANT: Proof validation and claims settlement timing: + // - Proof validation (proof end blocker): Executes WITHIN proof submission window + // - Claims settlement (tokenomics end blocker): Executes AFTER window closes + // This ensures proofs are validated before claims are settled + + var expirationReason tokenomicstypes.ClaimExpirationReason + switch claim.ProofValidationStatus { + // If the proof is required and not found, the claim is expired. + case prooftypes.ClaimProofStatus_PENDING_VALIDATION: expirationReason = tokenomicstypes.ClaimExpirationReason_PROOF_MISSING + // If the proof is required and invalid, the claim is expired. + case prooftypes.ClaimProofStatus_INVALID: + expirationReason = tokenomicstypes.ClaimExpirationReason_PROOF_INVALID + // If the proof is required and valid, the claim is settled. + case prooftypes.ClaimProofStatus_VALIDATED: + expirationReason = tokenomicstypes.ClaimExpirationReason_EXPIRATION_REASON_UNSPECIFIED } - // If the proof is missing or invalid -> expire it - if expirationReason != tokenomicstypes.ClaimExpirationReason_EXPIRATION_REASON_UNSPECIFIED { + if claim.ProofValidationStatus != prooftypes.ClaimProofStatus_VALIDATED { // TODO_BETA(@red-0ne): Slash the supplier in proportion to their stake. // TODO_POST_MAINNET: Consider allowing suppliers to RemoveClaim via a new // message in case it was sent by accident @@ -177,12 +182,8 @@ func (k Keeper) SettlePendingClaims(ctx cosmostypes.Context) ( // have other valid claims and the protocol might want to touch the supplier // owner or operator balances if the stake is negative. - // The claim & proof are no longer necessary, so there's no need for them - // to take up onchain space. + // The claim is no longer necessary, so there's no need for it to take up onchain space. k.proofKeeper.RemoveClaim(ctx, sessionId, claim.SupplierOperatorAddress) - if isProofFound { - k.proofKeeper.RemoveProof(ctx, sessionId, claim.SupplierOperatorAddress) - } // Append the settlement result to the expired results. expiredResults.Append(ClaimSettlementResult) @@ -245,13 +246,6 @@ func (k Keeper) SettlePendingClaims(ctx cosmostypes.Context) ( // The claim & proof are no longer necessary, so there's no need for them // to take up onchain space. k.proofKeeper.RemoveClaim(ctx, sessionId, claim.SupplierOperatorAddress) - // Whether or not the proof is required, the supplier may have submitted one - // so we need to delete it either way. If we don't have the if structure, - // a safe error will be printed, but it can be confusing to the operator - // or developer. - if isProofFound { - k.proofKeeper.RemoveProof(ctx, sessionId, claim.SupplierOperatorAddress) - } logger.Debug(fmt.Sprintf("Successfully settled claim for session ID %q at block height %d", claim.SessionHeader.SessionId, blockHeight)) diff --git a/x/tokenomics/types/expected_keepers.go b/x/tokenomics/types/expected_keepers.go index 9d555f4e2..dac960fa4 100644 --- a/x/tokenomics/types/expected_keepers.go +++ b/x/tokenomics/types/expected_keepers.go @@ -56,10 +56,10 @@ type ProofKeeper interface { RemoveProof(ctx context.Context, sessionId, supplierOperatorAddr string) AllClaims(ctx context.Context, req *prooftypes.QueryAllClaimsRequest) (*prooftypes.QueryAllClaimsResponse, error) - EnsureValidProof(ctx context.Context, proof *prooftypes.Proof) error ProofRequirementForClaim(ctx context.Context, claim *prooftypes.Claim) (prooftypes.ProofRequirementReason, error) // Only used for testing & simulation + ValidateSubmittedProofs(ctx cosmostypes.Context) (numValidProofs, numInvalidProofs uint64, err error) GetAllProofs(ctx context.Context) []prooftypes.Proof UpsertClaim(ctx context.Context, claim prooftypes.Claim) UpsertProof(ctx context.Context, claim prooftypes.Proof)