From 0af44b5f17441703e101659411bb44279f9f4393 Mon Sep 17 00:00:00 2001 From: Prathamesh Musale Date: Thu, 29 Feb 2024 11:54:35 +0000 Subject: [PATCH] Setup integration tests and CI (#11) - Setup integration tests following pattern suggested in cosmos-sdk docs: https://docs.cosmos.network/v0.50/build/building-modules/testing#integration-tests - Add tests for laconic modules query services - Setup a CI workflow to run the integration tests Reviewed-on: https://git.vdb.to/deep-stack/laconic2d/pulls/11 Co-authored-by: Prathamesh Musale Co-committed-by: Prathamesh Musale --- .gitea/workflows/test-integration.yml | 19 + Makefile | 7 + README.md | 6 + api/cerc/registry/v1/registry.pulsar.go | 593 +++++++++++++++++- app/app.go | 2 - cmd/laconic2d/cmd/root.go | 2 +- go.mod | 2 +- proto/cerc/registry/v1/registry.proto | 6 + scripts/init.sh | 1 - tests/Makefile | 2 + .../integration/auction/keeper/common_test.go | 30 + .../auction/keeper/query_server_test.go | 349 +++++++++++ tests/integration/bond/keeper/common_test.go | 30 + .../bond/keeper/query_server_test.go | 210 +++++++ tests/integration/common.go | 157 +++++ tests/integration/data/examples/example1.yml | 7 + .../data/examples/general_record_example.yml | 7 + .../examples/service_provider_example.yml | 13 + .../examples/website_registration_example.yml | 7 + .../registry/keeper/common_test.go | 59 ++ .../registry/keeper/query_server_test.go | 421 +++++++++++++ x/auction/keys.go | 3 + x/bond/keys.go | 3 + x/registry/keeper/keeper.go | 181 +++++- x/registry/keys.go | 5 + x/registry/registry.pb.go | 333 +++++++--- 26 files changed, 2326 insertions(+), 129 deletions(-) create mode 100644 .gitea/workflows/test-integration.yml create mode 100644 tests/Makefile create mode 100644 tests/integration/auction/keeper/common_test.go create mode 100644 tests/integration/auction/keeper/query_server_test.go create mode 100644 tests/integration/bond/keeper/common_test.go create mode 100644 tests/integration/bond/keeper/query_server_test.go create mode 100644 tests/integration/common.go create mode 100644 tests/integration/data/examples/example1.yml create mode 100644 tests/integration/data/examples/general_record_example.yml create mode 100644 tests/integration/data/examples/service_provider_example.yml create mode 100644 tests/integration/data/examples/website_registration_example.yml create mode 100644 tests/integration/registry/keeper/common_test.go create mode 100644 tests/integration/registry/keeper/query_server_test.go diff --git a/.gitea/workflows/test-integration.yml b/.gitea/workflows/test-integration.yml new file mode 100644 index 00000000..99fe58e4 --- /dev/null +++ b/.gitea/workflows/test-integration.yml @@ -0,0 +1,19 @@ +name: Integration Tests +on: + pull_request: + push: + branches: + - main + +jobs: + test-integration: + runs-on: ubuntu-latest + steps: + - uses: actions/setup-go@v3 + with: + go-version: 1.21 + check-latest: true + - uses: actions/checkout@v3 + - name: Test + run: | + make test-integration diff --git a/Makefile b/Makefile index 34a7d9ca..6ce6a9da 100644 --- a/Makefile +++ b/Makefile @@ -81,3 +81,10 @@ lint-fix: @$(golangci_lint_cmd) run ./... --fix --timeout 15m .PHONY: lint lint-fix + +################# +### Tests ### +################# + +test-integration: + $(MAKE) -C tests test-integration diff --git a/README.md b/README.md index 976c019c..ab165b07 100644 --- a/README.md +++ b/README.md @@ -12,3 +12,9 @@ Install and run `laconic2d`: # start the chain laconic2d start ``` + +Run tests: + + ```bash + make test-integration + ``` diff --git a/api/cerc/registry/v1/registry.pulsar.go b/api/cerc/registry/v1/registry.pulsar.go index 497fb74f..f45b1d6c 100644 --- a/api/cerc/registry/v1/registry.pulsar.go +++ b/api/cerc/registry/v1/registry.pulsar.go @@ -6130,6 +6130,486 @@ func (x *fastReflection_ExpiryQueue) ProtoMethods() *protoiface.Methods { } } +var _ protoreflect.List = (*_RecordsList_1_list)(nil) + +type _RecordsList_1_list struct { + list *[]string +} + +func (x *_RecordsList_1_list) Len() int { + if x.list == nil { + return 0 + } + return len(*x.list) +} + +func (x *_RecordsList_1_list) Get(i int) protoreflect.Value { + return protoreflect.ValueOfString((*x.list)[i]) +} + +func (x *_RecordsList_1_list) Set(i int, value protoreflect.Value) { + valueUnwrapped := value.String() + concreteValue := valueUnwrapped + (*x.list)[i] = concreteValue +} + +func (x *_RecordsList_1_list) Append(value protoreflect.Value) { + valueUnwrapped := value.String() + concreteValue := valueUnwrapped + *x.list = append(*x.list, concreteValue) +} + +func (x *_RecordsList_1_list) AppendMutable() protoreflect.Value { + panic(fmt.Errorf("AppendMutable can not be called on message RecordsList at list field Value as it is not of Message kind")) +} + +func (x *_RecordsList_1_list) Truncate(n int) { + *x.list = (*x.list)[:n] +} + +func (x *_RecordsList_1_list) NewElement() protoreflect.Value { + v := "" + return protoreflect.ValueOfString(v) +} + +func (x *_RecordsList_1_list) IsValid() bool { + return x.list != nil +} + +var ( + md_RecordsList protoreflect.MessageDescriptor + fd_RecordsList_value protoreflect.FieldDescriptor +) + +func init() { + file_cerc_registry_v1_registry_proto_init() + md_RecordsList = File_cerc_registry_v1_registry_proto.Messages().ByName("RecordsList") + fd_RecordsList_value = md_RecordsList.Fields().ByName("value") +} + +var _ protoreflect.Message = (*fastReflection_RecordsList)(nil) + +type fastReflection_RecordsList RecordsList + +func (x *RecordsList) ProtoReflect() protoreflect.Message { + return (*fastReflection_RecordsList)(x) +} + +func (x *RecordsList) slowProtoReflect() protoreflect.Message { + mi := &file_cerc_registry_v1_registry_proto_msgTypes[9] + 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_RecordsList_messageType fastReflection_RecordsList_messageType +var _ protoreflect.MessageType = fastReflection_RecordsList_messageType{} + +type fastReflection_RecordsList_messageType struct{} + +func (x fastReflection_RecordsList_messageType) Zero() protoreflect.Message { + return (*fastReflection_RecordsList)(nil) +} +func (x fastReflection_RecordsList_messageType) New() protoreflect.Message { + return new(fastReflection_RecordsList) +} +func (x fastReflection_RecordsList_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_RecordsList +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_RecordsList) Descriptor() protoreflect.MessageDescriptor { + return md_RecordsList +} + +// 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_RecordsList) Type() protoreflect.MessageType { + return _fastReflection_RecordsList_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_RecordsList) New() protoreflect.Message { + return new(fastReflection_RecordsList) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_RecordsList) Interface() protoreflect.ProtoMessage { + return (*RecordsList)(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_RecordsList) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if len(x.Value) != 0 { + value := protoreflect.ValueOfList(&_RecordsList_1_list{list: &x.Value}) + if !f(fd_RecordsList_value, 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_RecordsList) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "cerc.registry.v1.RecordsList.value": + return len(x.Value) != 0 + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cerc.registry.v1.RecordsList")) + } + panic(fmt.Errorf("message cerc.registry.v1.RecordsList 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_RecordsList) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "cerc.registry.v1.RecordsList.value": + x.Value = nil + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cerc.registry.v1.RecordsList")) + } + panic(fmt.Errorf("message cerc.registry.v1.RecordsList 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_RecordsList) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "cerc.registry.v1.RecordsList.value": + if len(x.Value) == 0 { + return protoreflect.ValueOfList(&_RecordsList_1_list{}) + } + listValue := &_RecordsList_1_list{list: &x.Value} + return protoreflect.ValueOfList(listValue) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cerc.registry.v1.RecordsList")) + } + panic(fmt.Errorf("message cerc.registry.v1.RecordsList 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_RecordsList) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "cerc.registry.v1.RecordsList.value": + lv := value.List() + clv := lv.(*_RecordsList_1_list) + x.Value = *clv.list + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cerc.registry.v1.RecordsList")) + } + panic(fmt.Errorf("message cerc.registry.v1.RecordsList 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_RecordsList) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "cerc.registry.v1.RecordsList.value": + if x.Value == nil { + x.Value = []string{} + } + value := &_RecordsList_1_list{list: &x.Value} + return protoreflect.ValueOfList(value) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cerc.registry.v1.RecordsList")) + } + panic(fmt.Errorf("message cerc.registry.v1.RecordsList 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_RecordsList) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "cerc.registry.v1.RecordsList.value": + list := []string{} + return protoreflect.ValueOfList(&_RecordsList_1_list{list: &list}) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cerc.registry.v1.RecordsList")) + } + panic(fmt.Errorf("message cerc.registry.v1.RecordsList 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_RecordsList) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in cerc.registry.v1.RecordsList", 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_RecordsList) 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_RecordsList) 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_RecordsList) 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_RecordsList) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*RecordsList) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + if len(x.Value) > 0 { + for _, s := range x.Value { + l = len(s) + 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().(*RecordsList) + 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.Value) > 0 { + for iNdEx := len(x.Value) - 1; iNdEx >= 0; iNdEx-- { + i -= len(x.Value[iNdEx]) + copy(dAtA[i:], x.Value[iNdEx]) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.Value[iNdEx]))) + 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().(*RecordsList) + 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: RecordsList: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: RecordsList: 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 Value", 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.Value = append(x.Value, 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 @@ -6712,6 +7192,43 @@ func (x *ExpiryQueue) GetValue() []string { return nil } +// List of record ids +// Value type to be used in AttributesMap +type RecordsList struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Value []string `protobuf:"bytes,1,rep,name=value,proto3" json:"value,omitempty"` +} + +func (x *RecordsList) Reset() { + *x = RecordsList{} + if protoimpl.UnsafeEnabled { + mi := &file_cerc_registry_v1_registry_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RecordsList) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RecordsList) ProtoMessage() {} + +// Deprecated: Use RecordsList.ProtoReflect.Descriptor instead. +func (*RecordsList) Descriptor() ([]byte, []int) { + return file_cerc_registry_v1_registry_proto_rawDescGZIP(), []int{9} +} + +func (x *RecordsList) GetValue() []string { + if x != nil { + return x.Value + } + return nil +} + var File_cerc_registry_v1_registry_proto protoreflect.FileDescriptor var file_cerc_registry_v1_registry_proto_rawDesc = []byte{ @@ -6932,20 +7449,23 @@ var file_cerc_registry_v1_registry_proto_rawDesc = []byte{ 0x22, 0x52, 0x06, 0x70, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x22, 0x33, 0x0a, 0x0b, 0x45, 0x78, 0x70, 0x69, 0x72, 0x79, 0x51, 0x75, 0x65, 0x75, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x42, 0xc5, - 0x01, 0x0a, 0x14, 0x63, 0x6f, 0x6d, 0x2e, 0x63, 0x65, 0x72, 0x63, 0x2e, 0x72, 0x65, 0x67, 0x69, - 0x73, 0x74, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x42, 0x0d, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, - 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3c, 0x67, 0x69, 0x74, 0x2e, 0x76, 0x64, - 0x62, 0x2e, 0x74, 0x6f, 0x2f, 0x63, 0x65, 0x72, 0x63, 0x2d, 0x69, 0x6f, 0x2f, 0x6c, 0x61, 0x63, - 0x6f, 0x6e, 0x69, 0x63, 0x32, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x65, 0x72, 0x63, 0x2f, - 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2f, 0x76, 0x31, 0x3b, 0x72, 0x65, 0x67, 0x69, - 0x73, 0x74, 0x72, 0x79, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x43, 0x52, 0x58, 0xaa, 0x02, 0x10, 0x43, - 0x65, 0x72, 0x63, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x56, 0x31, 0xca, - 0x02, 0x10, 0x43, 0x65, 0x72, 0x63, 0x5c, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x5c, - 0x56, 0x31, 0xe2, 0x02, 0x1c, 0x43, 0x65, 0x72, 0x63, 0x5c, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, - 0x72, 0x79, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0xea, 0x02, 0x12, 0x43, 0x65, 0x72, 0x63, 0x3a, 0x3a, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, - 0x72, 0x79, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x23, + 0x0a, 0x0b, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x14, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x42, 0xc5, 0x01, 0x0a, 0x14, 0x63, 0x6f, 0x6d, 0x2e, 0x63, 0x65, 0x72, 0x63, + 0x2e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x42, 0x0d, 0x52, 0x65, + 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3c, 0x67, + 0x69, 0x74, 0x2e, 0x76, 0x64, 0x62, 0x2e, 0x74, 0x6f, 0x2f, 0x63, 0x65, 0x72, 0x63, 0x2d, 0x69, + 0x6f, 0x2f, 0x6c, 0x61, 0x63, 0x6f, 0x6e, 0x69, 0x63, 0x32, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, + 0x63, 0x65, 0x72, 0x63, 0x2f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2f, 0x76, 0x31, + 0x3b, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x43, 0x52, + 0x58, 0xaa, 0x02, 0x10, 0x43, 0x65, 0x72, 0x63, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, + 0x79, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x10, 0x43, 0x65, 0x72, 0x63, 0x5c, 0x52, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x72, 0x79, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x1c, 0x43, 0x65, 0x72, 0x63, 0x5c, 0x52, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x12, 0x43, 0x65, 0x72, 0x63, 0x3a, 0x3a, 0x52, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, } var ( @@ -6960,7 +7480,7 @@ func file_cerc_registry_v1_registry_proto_rawDescGZIP() []byte { return file_cerc_registry_v1_registry_proto_rawDescData } -var file_cerc_registry_v1_registry_proto_msgTypes = make([]protoimpl.MessageInfo, 9) +var file_cerc_registry_v1_registry_proto_msgTypes = make([]protoimpl.MessageInfo, 10) var file_cerc_registry_v1_registry_proto_goTypes = []interface{}{ (*Params)(nil), // 0: cerc.registry.v1.Params (*Record)(nil), // 1: cerc.registry.v1.Record @@ -6971,23 +7491,24 @@ var file_cerc_registry_v1_registry_proto_goTypes = []interface{}{ (*NameRecordEntry)(nil), // 6: cerc.registry.v1.NameRecordEntry (*Signature)(nil), // 7: cerc.registry.v1.Signature (*ExpiryQueue)(nil), // 8: cerc.registry.v1.ExpiryQueue - (*v1beta1.Coin)(nil), // 9: cosmos.base.v1beta1.Coin - (*durationpb.Duration)(nil), // 10: google.protobuf.Duration - (*timestamppb.Timestamp)(nil), // 11: google.protobuf.Timestamp + (*RecordsList)(nil), // 9: cerc.registry.v1.RecordsList + (*v1beta1.Coin)(nil), // 10: cosmos.base.v1beta1.Coin + (*durationpb.Duration)(nil), // 11: google.protobuf.Duration + (*timestamppb.Timestamp)(nil), // 12: google.protobuf.Timestamp } var file_cerc_registry_v1_registry_proto_depIdxs = []int32{ - 9, // 0: cerc.registry.v1.Params.record_rent:type_name -> cosmos.base.v1beta1.Coin - 10, // 1: cerc.registry.v1.Params.record_rent_duration:type_name -> google.protobuf.Duration - 9, // 2: cerc.registry.v1.Params.authority_rent:type_name -> cosmos.base.v1beta1.Coin - 10, // 3: cerc.registry.v1.Params.authority_rent_duration:type_name -> google.protobuf.Duration - 10, // 4: cerc.registry.v1.Params.authority_grace_period:type_name -> google.protobuf.Duration - 10, // 5: cerc.registry.v1.Params.authority_auction_commits_duration:type_name -> google.protobuf.Duration - 10, // 6: cerc.registry.v1.Params.authority_auction_reveals_duration:type_name -> google.protobuf.Duration - 9, // 7: cerc.registry.v1.Params.authority_auction_commit_fee:type_name -> cosmos.base.v1beta1.Coin - 9, // 8: cerc.registry.v1.Params.authority_auction_reveal_fee:type_name -> cosmos.base.v1beta1.Coin - 9, // 9: cerc.registry.v1.Params.authority_auction_minimum_bid:type_name -> cosmos.base.v1beta1.Coin + 10, // 0: cerc.registry.v1.Params.record_rent:type_name -> cosmos.base.v1beta1.Coin + 11, // 1: cerc.registry.v1.Params.record_rent_duration:type_name -> google.protobuf.Duration + 10, // 2: cerc.registry.v1.Params.authority_rent:type_name -> cosmos.base.v1beta1.Coin + 11, // 3: cerc.registry.v1.Params.authority_rent_duration:type_name -> google.protobuf.Duration + 11, // 4: cerc.registry.v1.Params.authority_grace_period:type_name -> google.protobuf.Duration + 11, // 5: cerc.registry.v1.Params.authority_auction_commits_duration:type_name -> google.protobuf.Duration + 11, // 6: cerc.registry.v1.Params.authority_auction_reveals_duration:type_name -> google.protobuf.Duration + 10, // 7: cerc.registry.v1.Params.authority_auction_commit_fee:type_name -> cosmos.base.v1beta1.Coin + 10, // 8: cerc.registry.v1.Params.authority_auction_reveal_fee:type_name -> cosmos.base.v1beta1.Coin + 10, // 9: cerc.registry.v1.Params.authority_auction_minimum_bid:type_name -> cosmos.base.v1beta1.Coin 3, // 10: cerc.registry.v1.AuthorityEntry.entry:type_name -> cerc.registry.v1.NameAuthority - 11, // 11: cerc.registry.v1.NameAuthority.expiry_time:type_name -> google.protobuf.Timestamp + 12, // 11: cerc.registry.v1.NameAuthority.expiry_time:type_name -> google.protobuf.Timestamp 5, // 12: cerc.registry.v1.NameEntry.entry:type_name -> cerc.registry.v1.NameRecord 6, // 13: cerc.registry.v1.NameRecord.latest:type_name -> cerc.registry.v1.NameRecordEntry 6, // 14: cerc.registry.v1.NameRecord.history:type_name -> cerc.registry.v1.NameRecordEntry @@ -7112,6 +7633,18 @@ func file_cerc_registry_v1_registry_proto_init() { return nil } } + file_cerc_registry_v1_registry_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RecordsList); 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{ @@ -7119,7 +7652,7 @@ func file_cerc_registry_v1_registry_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_cerc_registry_v1_registry_proto_rawDesc, NumEnums: 0, - NumMessages: 9, + NumMessages: 10, NumExtensions: 0, NumServices: 0, }, diff --git a/app/app.go b/app/app.go index 13bcb96b..aea38d1a 100644 --- a/app/app.go +++ b/app/app.go @@ -79,7 +79,6 @@ type LaconicApp struct { AuctionKeeper *auctionkeeper.Keeper // (Use * as per ProvideModule implementation) BondKeeper *bondkeeper.Keeper RegistryKeeper registrykeeper.Keeper - // RegistryRecordKeeper registrykeeper.RecordKeeper // simulation manager sm *module.SimulationManager @@ -141,7 +140,6 @@ func NewLaconicApp( &app.ConsensusParamsKeeper, &app.AuctionKeeper, &app.BondKeeper, - // &app.RegistryRecordKeeper, &app.RegistryKeeper, ); err != nil { return nil, err diff --git a/cmd/laconic2d/cmd/root.go b/cmd/laconic2d/cmd/root.go index 1f3a5bd3..f578999d 100644 --- a/cmd/laconic2d/cmd/root.go +++ b/cmd/laconic2d/cmd/root.go @@ -106,7 +106,7 @@ func NewRootCmd() *cobra.Command { // overwrite the block timeout cmtCfg := cmtcfg.DefaultConfig() cmtCfg.Consensus.TimeoutCommit = 3 * time.Second - cmtCfg.LogLevel = "*:error,p2p:info,state:info" // better default logging + cmtCfg.LogLevel = "*:error,p2p:info,state:info,auction:info,bond:info,registry:info" // better default logging return server.InterceptConfigsPreRunHandler(cmd, serverconfig.DefaultConfigTemplate, srvCfg, cmtCfg) }, diff --git a/go.mod b/go.mod index e4386920..c3677768 100644 --- a/go.mod +++ b/go.mod @@ -37,6 +37,7 @@ require ( github.com/ipld/go-ipld-prime v0.21.0 github.com/spf13/cobra v1.8.0 github.com/spf13/viper v1.17.0 + github.com/stretchr/testify v1.8.4 golang.org/x/exp v0.0.0-20231006140011-7918f672742d google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f google.golang.org/grpc v1.60.1 @@ -160,7 +161,6 @@ require ( github.com/spf13/afero v1.10.0 // indirect github.com/spf13/cast v1.5.1 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/stretchr/testify v1.8.4 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect github.com/tendermint/go-amino v0.16.0 // indirect diff --git a/proto/cerc/registry/v1/registry.proto b/proto/cerc/registry/v1/registry.proto index 001a6ea5..a97bbeb1 100644 --- a/proto/cerc/registry/v1/registry.proto +++ b/proto/cerc/registry/v1/registry.proto @@ -138,3 +138,9 @@ message ExpiryQueue { string id = 1; repeated string value = 2; } + +// List of record ids +// Value type to be used in AttributesMap +message RecordsList { + repeated string value = 1; +} diff --git a/scripts/init.sh b/scripts/init.sh index abde54cd..0f9a788a 100755 --- a/scripts/init.sh +++ b/scripts/init.sh @@ -3,7 +3,6 @@ rm -r ~/.laconic2d || true LACONIC2D_BIN=$(which laconic2d) # configure laconic2d -$LACONIC2D_BIN config set config log_level "*:error,p2p:info,state:info,auction:info,bond:info,registry:info" --skip-validate $LACONIC2D_BIN config set client chain-id demo $LACONIC2D_BIN config set client keyring-backend test $LACONIC2D_BIN keys add alice diff --git a/tests/Makefile b/tests/Makefile new file mode 100644 index 00000000..3ed7cfec --- /dev/null +++ b/tests/Makefile @@ -0,0 +1,2 @@ +test-integration: + go test -mod=readonly ./integration/... -test.v -timeout 10m diff --git a/tests/integration/auction/keeper/common_test.go b/tests/integration/auction/keeper/common_test.go new file mode 100644 index 00000000..509c8297 --- /dev/null +++ b/tests/integration/auction/keeper/common_test.go @@ -0,0 +1,30 @@ +package keeper_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + + integrationTest "git.vdb.to/cerc-io/laconic2d/tests/integration" + types "git.vdb.to/cerc-io/laconic2d/x/auction" +) + +type KeeperTestSuite struct { + suite.Suite + integrationTest.TestFixture + + queryClient types.QueryClient +} + +func (kts *KeeperTestSuite) SetupTest() { + err := kts.TestFixture.Setup() + assert.Nil(kts.T(), err) + + qr := kts.App.QueryHelper() + kts.queryClient = types.NewQueryClient(qr) +} + +func TestAuctionKeeperTestSuite(t *testing.T) { + suite.Run(t, new(KeeperTestSuite)) +} diff --git a/tests/integration/auction/keeper/query_server_test.go b/tests/integration/auction/keeper/query_server_test.go new file mode 100644 index 00000000..698b377f --- /dev/null +++ b/tests/integration/auction/keeper/query_server_test.go @@ -0,0 +1,349 @@ +package keeper_test + +import ( + "context" + "fmt" + + "cosmossdk.io/math" + simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" + + integrationTest "git.vdb.to/cerc-io/laconic2d/tests/integration" + types "git.vdb.to/cerc-io/laconic2d/x/auction" +) + +const testCommitHash = "71D8CF34026E32A3A34C2C2D4ADF25ABC8D7943A4619761BE27F196603D91B9D" + +func (kts *KeeperTestSuite) TestGrpcQueryParams() { + testCases := []struct { + msg string + req *types.QueryParamsRequest + }{ + { + "fetch params", + &types.QueryParamsRequest{}, + }, + } + for _, test := range testCases { + kts.Run(fmt.Sprintf("Case %s", test.msg), func() { + resp, err := kts.queryClient.Params(context.Background(), test.req) + kts.Require().Nil(err) + kts.Require().Equal(*(resp.Params), types.DefaultParams()) + }) + } +} + +func (kts *KeeperTestSuite) TestGrpcGetAuction() { + testCases := []struct { + msg string + req *types.QueryAuctionRequest + createAuction bool + }{ + { + "fetch auction with empty auction ID", + &types.QueryAuctionRequest{}, + false, + }, + { + "fetch auction with valid auction ID", + &types.QueryAuctionRequest{}, + true, + }, + } + + for _, test := range testCases { + kts.Run(fmt.Sprintf("Case %s", test.msg), func() { + var expectedAuction types.Auction + if test.createAuction { + auction, _, err := kts.createAuctionAndCommitBid(false) + kts.Require().Nil(err) + test.req.Id = auction.Id + expectedAuction = *auction + } + + resp, err := kts.queryClient.GetAuction(context.Background(), test.req) + if test.createAuction { + kts.Require().Nil(err) + kts.Require().NotNil(resp.GetAuction()) + kts.Require().EqualExportedValues(expectedAuction, *(resp.GetAuction())) + } else { + kts.Require().NotNil(err) + kts.Require().Error(err) + } + }) + } +} + +func (kts *KeeperTestSuite) TestGrpcGetAllAuctions() { + testCases := []struct { + msg string + req *types.QueryAuctionsRequest + createAuctions bool + auctionCount int + }{ + { + "fetch auctions when no auctions exist", + &types.QueryAuctionsRequest{}, + false, + 0, + }, + + { + "fetch auctions with one auction created", + &types.QueryAuctionsRequest{}, + true, + 1, + }, + } + + for _, test := range testCases { + kts.Run(fmt.Sprintf("Case %s", test.msg), func() { + if test.createAuctions { + _, _, err := kts.createAuctionAndCommitBid(false) + kts.Require().Nil(err) + } + + resp, _ := kts.queryClient.Auctions(context.Background(), test.req) + kts.Require().Equal(test.auctionCount, len(resp.GetAuctions().Auctions)) + }) + } +} + +func (kts *KeeperTestSuite) TestGrpcGetBids() { + testCases := []struct { + msg string + req *types.QueryBidsRequest + createAuction bool + commitBid bool + bidCount int + }{ + { + "fetch all bids when no auction exists", + &types.QueryBidsRequest{}, + false, + false, + 0, + }, + { + "fetch all bids for valid auction but no added bids", + &types.QueryBidsRequest{}, + true, + false, + 0, + }, + { + "fetch all bids for valid auction and valid bid", + &types.QueryBidsRequest{}, + true, + true, + 1, + }, + } + + for _, test := range testCases { + kts.Run(fmt.Sprintf("Case %s", test.msg), func() { + if test.createAuction { + auction, _, err := kts.createAuctionAndCommitBid(test.commitBid) + kts.Require().NoError(err) + test.req.AuctionId = auction.Id + } + + resp, err := kts.queryClient.GetBids(context.Background(), test.req) + if test.createAuction { + kts.Require().Nil(err) + kts.Require().Equal(test.bidCount, len(resp.GetBids())) + } else { + kts.Require().NotNil(err) + kts.Require().Error(err) + } + }) + } +} + +func (kts *KeeperTestSuite) TestGrpcGetBid() { + testCases := []struct { + msg string + req *types.QueryBidRequest + createAuctionAndBid bool + }{ + { + "fetch bid when bid does not exist", + &types.QueryBidRequest{}, + false, + }, + { + "fetch bid when valid bid exists", + &types.QueryBidRequest{}, + true, + }, + } + + for _, test := range testCases { + kts.Run(fmt.Sprintf("Case %s", test.msg), func() { + if test.createAuctionAndBid { + auction, bid, err := kts.createAuctionAndCommitBid(test.createAuctionAndBid) + kts.Require().NoError(err) + test.req.AuctionId = auction.Id + test.req.Bidder = bid.BidderAddress + } + + resp, err := kts.queryClient.GetBid(context.Background(), test.req) + if test.createAuctionAndBid { + kts.Require().NoError(err) + kts.Require().NotNil(resp.Bid) + kts.Require().Equal(test.req.Bidder, resp.Bid.BidderAddress) + } else { + kts.Require().NotNil(err) + kts.Require().Error(err) + } + }) + } +} + +func (kts *KeeperTestSuite) TestGrpcGetAuctionsByBidder() { + testCases := []struct { + msg string + req *types.QueryAuctionsByBidderRequest + createAuctionAndCommitBid bool + auctionCount int + }{ + { + "get auctions by bidder with invalid bidder address", + &types.QueryAuctionsByBidderRequest{}, + false, + 0, + }, + { + "get auctions by bidder with valid auction and bid", + &types.QueryAuctionsByBidderRequest{}, + true, + 1, + }, + } + + for _, test := range testCases { + kts.Run(fmt.Sprintf("Case %s", test.msg), func() { + if test.createAuctionAndCommitBid { + _, bid, err := kts.createAuctionAndCommitBid(test.createAuctionAndCommitBid) + kts.Require().NoError(err) + test.req.BidderAddress = bid.BidderAddress + } + + resp, err := kts.queryClient.AuctionsByBidder(context.Background(), test.req) + if test.createAuctionAndCommitBid { + kts.Require().NoError(err) + kts.Require().NotNil(resp.Auctions) + kts.Require().Equal(test.auctionCount, len(resp.Auctions.Auctions)) + } else { + kts.Require().NotNil(err) + kts.Require().Error(err) + } + }) + } +} + +func (kts *KeeperTestSuite) TestGrpcGetAuctionsByOwner() { + testCases := []struct { + msg string + req *types.QueryAuctionsByOwnerRequest + createAuction bool + auctionCount int + }{ + { + "get auctions by owner with invalid owner address", + &types.QueryAuctionsByOwnerRequest{}, + false, + 0, + }, + { + "get auctions by owner with valid auction", + &types.QueryAuctionsByOwnerRequest{}, + true, + 1, + }, + } + + for _, test := range testCases { + kts.Run(fmt.Sprintf("Case %s", test.msg), func() { + if test.createAuction { + auction, _, err := kts.createAuctionAndCommitBid(false) + kts.Require().NoError(err) + test.req.OwnerAddress = auction.OwnerAddress + } + + resp, err := kts.queryClient.AuctionsByOwner(context.Background(), test.req) + if test.createAuction { + kts.Require().NoError(err) + kts.Require().NotNil(resp.Auctions) + kts.Require().Equal(test.auctionCount, len(resp.Auctions.Auctions)) + } else { + kts.Require().NotNil(err) + kts.Require().Error(err) + } + }) + } +} + +func (kts *KeeperTestSuite) TestGrpcQueryBalance() { + testCases := []struct { + msg string + req *types.QueryGetAuctionModuleBalanceRequest + createAuction bool + auctionCount int + }{ + { + "get balance with no auctions created", + &types.QueryGetAuctionModuleBalanceRequest{}, + false, + 0, + }, + { + "get balance with single auction created", + &types.QueryGetAuctionModuleBalanceRequest{}, + true, + 1, + }, + } + + for _, test := range testCases { + if test.createAuction { + _, _, err := kts.createAuctionAndCommitBid(true) + kts.Require().NoError(err) + } + + resp, err := kts.queryClient.GetAuctionModuleBalance(context.Background(), test.req) + kts.Require().NoError(err) + kts.Require().Equal(test.auctionCount, len(resp.GetBalance())) + } +} + +func (kts *KeeperTestSuite) createAuctionAndCommitBid(commitBid bool) (*types.Auction, *types.Bid, error) { + ctx, k := kts.SdkCtx, kts.AuctionKeeper + accCount := 1 + if commitBid { + accCount++ + } + + // Create funded account(s) + accounts := simtestutil.AddTestAddrs(kts.BankKeeper, integrationTest.BondDenomProvider{}, ctx, accCount, math.NewInt(100)) + + params, err := k.GetParams(ctx) + if err != nil { + return nil, nil, err + } + + auction, err := k.CreateAuction(ctx, types.NewMsgCreateAuction(*params, accounts[0])) + if err != nil { + return nil, nil, err + } + + if commitBid { + bid, err := k.CommitBid(ctx, types.NewMsgCommitBid(auction.Id, testCommitHash, accounts[1])) + if err != nil { + return nil, nil, err + } + + return auction, bid, nil + } + + return auction, nil, nil +} diff --git a/tests/integration/bond/keeper/common_test.go b/tests/integration/bond/keeper/common_test.go new file mode 100644 index 00000000..45155c02 --- /dev/null +++ b/tests/integration/bond/keeper/common_test.go @@ -0,0 +1,30 @@ +package keeper_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + + integrationTest "git.vdb.to/cerc-io/laconic2d/tests/integration" + types "git.vdb.to/cerc-io/laconic2d/x/bond" +) + +type KeeperTestSuite struct { + suite.Suite + integrationTest.TestFixture + + queryClient types.QueryClient +} + +func (kts *KeeperTestSuite) SetupTest() { + err := kts.TestFixture.Setup() + assert.Nil(kts.T(), err) + + qr := kts.App.QueryHelper() + kts.queryClient = types.NewQueryClient(qr) +} + +func TestBondKeeperTestSuite(t *testing.T) { + suite.Run(t, new(KeeperTestSuite)) +} diff --git a/tests/integration/bond/keeper/query_server_test.go b/tests/integration/bond/keeper/query_server_test.go new file mode 100644 index 00000000..e652326e --- /dev/null +++ b/tests/integration/bond/keeper/query_server_test.go @@ -0,0 +1,210 @@ +package keeper_test + +import ( + "context" + "fmt" + + "cosmossdk.io/math" + simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" + sdk "github.com/cosmos/cosmos-sdk/types" + + integrationTest "git.vdb.to/cerc-io/laconic2d/tests/integration" + types "git.vdb.to/cerc-io/laconic2d/x/bond" +) + +func (kts *KeeperTestSuite) TestGrpcQueryParams() { + testCases := []struct { + msg string + req *types.QueryParamsRequest + }{ + { + "fetch params", + &types.QueryParamsRequest{}, + }, + } + for _, test := range testCases { + kts.Run(fmt.Sprintf("Case %s", test.msg), func() { + resp, err := kts.queryClient.Params(context.Background(), test.req) + kts.Require().Nil(err) + kts.Require().Equal(*(resp.Params), types.DefaultParams()) + }) + } +} + +func (kts *KeeperTestSuite) TestGrpcQueryBondsList() { + testCases := []struct { + msg string + req *types.QueryGetBondsRequest + resp *types.QueryGetBondsResponse + noOfBonds int + createBonds bool + }{ + { + "empty request", + &types.QueryGetBondsRequest{}, + &types.QueryGetBondsResponse{}, + 0, + false, + }, + { + "Get Bonds", + &types.QueryGetBondsRequest{}, + &types.QueryGetBondsResponse{}, + 1, + true, + }, + } + + for _, test := range testCases { + kts.Run(fmt.Sprintf("Case %s ", test.msg), func() { + if test.createBonds { + _, err := kts.createBond() + kts.Require().NoError(err) + } + resp, _ := kts.queryClient.Bonds(context.Background(), test.req) + kts.Require().Equal(test.noOfBonds, len(resp.GetBonds())) + }) + } +} + +func (kts *KeeperTestSuite) TestGrpcQueryBondByBondId() { + testCases := []struct { + msg string + req *types.QueryGetBondByIdRequest + createBonds bool + errResponse bool + bondId string + }{ + { + "empty request", + &types.QueryGetBondByIdRequest{}, + false, + true, + "", + }, + { + "Get Bond By ID", + &types.QueryGetBondByIdRequest{}, + true, + false, + "", + }, + } + + for _, test := range testCases { + kts.Run(fmt.Sprintf("Case %s ", test.msg), func() { + if test.createBonds { + bond, err := kts.createBond() + kts.Require().NoError(err) + test.req.Id = bond.Id + } + resp, err := kts.queryClient.GetBondById(context.Background(), test.req) + if !test.errResponse { + kts.Require().Nil(err) + kts.Require().NotNil(resp.GetBond()) + kts.Require().Equal(test.req.Id, resp.GetBond().GetId()) + } else { + kts.Require().NotNil(err) + kts.Require().Error(err) + } + }) + } +} + +func (kts *KeeperTestSuite) TestGrpcGetBondsByOwner() { + testCases := []struct { + msg string + req *types.QueryGetBondsByOwnerRequest + noOfBonds int + createBonds bool + errResponse bool + bondId string + }{ + { + "empty request", + &types.QueryGetBondsByOwnerRequest{}, + 0, + false, + true, + "", + }, + { + "Get Bond By Owner", + &types.QueryGetBondsByOwnerRequest{}, + 1, + true, + false, + "", + }, + } + + for _, test := range testCases { + kts.Run(fmt.Sprintf("Case %s ", test.msg), func() { + if test.createBonds { + bond, err := kts.createBond() + kts.Require().NoError(err) + test.req.Owner = bond.Owner + } + resp, err := kts.queryClient.GetBondsByOwner(context.Background(), test.req) + if !test.errResponse { + kts.Require().Nil(err) + kts.Require().NotNil(resp.GetBonds()) + kts.Require().Equal(test.noOfBonds, len(resp.GetBonds())) + } else { + kts.Require().NotNil(err) + kts.Require().Error(err) + } + }) + } +} + +func (kts *KeeperTestSuite) TestGrpcGetModuleBalance() { + testCases := []struct { + msg string + req *types.QueryGetBondModuleBalanceRequest + noOfBonds int + createBonds bool + errResponse bool + }{ + { + "empty request", + &types.QueryGetBondModuleBalanceRequest{}, + 0, + true, + false, + }, + } + + for _, test := range testCases { + kts.Run(fmt.Sprintf("Case %s ", test.msg), func() { + if test.createBonds { + _, err := kts.createBond() + kts.Require().NoError(err) + } + resp, err := kts.queryClient.GetBondsModuleBalance(context.Background(), test.req) + if !test.errResponse { + kts.Require().Nil(err) + kts.Require().NotNil(resp.GetBalance()) + kts.Require().Equal(resp.GetBalance(), sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(10)))) + } else { + kts.Require().NotNil(err) + kts.Require().Error(err) + } + }) + } +} + +func (kts *KeeperTestSuite) createBond() (*types.Bond, error) { + ctx, k := kts.SdkCtx, kts.BondKeeper + accCount := 1 + + // Create funded account(s) + accounts := simtestutil.AddTestAddrs(kts.BankKeeper, integrationTest.BondDenomProvider{}, ctx, accCount, math.NewInt(1000)) + + bond, err := k.CreateBond(ctx, accounts[0], sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(10)))) + if err != nil { + return nil, err + } + + return bond, nil +} diff --git a/tests/integration/common.go b/tests/integration/common.go new file mode 100644 index 00000000..4e605a3d --- /dev/null +++ b/tests/integration/common.go @@ -0,0 +1,157 @@ +package integration_test + +import ( + "context" + + "cosmossdk.io/core/appmodule" + "cosmossdk.io/log" + storetypes "cosmossdk.io/store/types" + cmtprototypes "github.com/cometbft/cometbft/proto/tendermint/types" + + "github.com/cosmos/cosmos-sdk/codec" + addresscodec "github.com/cosmos/cosmos-sdk/codec/address" + "github.com/cosmos/cosmos-sdk/runtime" + "github.com/cosmos/cosmos-sdk/testutil/integration" + sdk "github.com/cosmos/cosmos-sdk/types" + moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" + "github.com/cosmos/cosmos-sdk/x/auth" + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + authsims "github.com/cosmos/cosmos-sdk/x/auth/simulation" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/cosmos/cosmos-sdk/x/bank" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" + + auctionTypes "git.vdb.to/cerc-io/laconic2d/x/auction" + auctionkeeper "git.vdb.to/cerc-io/laconic2d/x/auction/keeper" + auctionmodule "git.vdb.to/cerc-io/laconic2d/x/auction/module" + bondTypes "git.vdb.to/cerc-io/laconic2d/x/bond" + bondkeeper "git.vdb.to/cerc-io/laconic2d/x/bond/keeper" + bondmodule "git.vdb.to/cerc-io/laconic2d/x/bond/module" + registryTypes "git.vdb.to/cerc-io/laconic2d/x/registry" + registrykeeper "git.vdb.to/cerc-io/laconic2d/x/registry/keeper" + registrymodule "git.vdb.to/cerc-io/laconic2d/x/registry/module" +) + +type TestFixture struct { + App *integration.App + + SdkCtx sdk.Context + cdc codec.Codec + keys map[string]*storetypes.KVStoreKey + + AccountKeeper authkeeper.AccountKeeper + BankKeeper bankkeeper.Keeper + + AuctionKeeper *auctionkeeper.Keeper + BondKeeper *bondkeeper.Keeper + RegistryKeeper registrykeeper.Keeper +} + +func (tf *TestFixture) Setup() error { + keys := storetypes.NewKVStoreKeys( + authtypes.StoreKey, banktypes.StoreKey, auctionTypes.StoreKey, bondTypes.StoreKey, registryTypes.StoreKey, + ) + cdc := moduletestutil.MakeTestEncodingConfig( + auth.AppModuleBasic{}, + auctionmodule.AppModule{}, + bondmodule.AppModule{}, + registrymodule.AppModule{}, + ).Codec + + logger := log.NewNopLogger() // Use log.NewTestLogger(kts.T()) for help with debugging + cms := integration.CreateMultiStore(keys, logger) + + newCtx := sdk.NewContext(cms, cmtprototypes.Header{}, true, logger) + + authority := authtypes.NewModuleAddress("gov") + + maccPerms := map[string][]string{ + minttypes.ModuleName: {authtypes.Minter}, + auctionTypes.ModuleName: {}, + auctionTypes.AuctionBurnModuleAccountName: {}, + bondTypes.ModuleName: {}, + registryTypes.ModuleName: {}, + registryTypes.RecordRentModuleAccountName: {}, + registryTypes.AuthorityRentModuleAccountName: {}, + } + + accountKeeper := authkeeper.NewAccountKeeper( + cdc, + runtime.NewKVStoreService(keys[authtypes.StoreKey]), + authtypes.ProtoBaseAccount, + maccPerms, + addresscodec.NewBech32Codec(sdk.Bech32MainPrefix), + sdk.Bech32MainPrefix, + authority.String(), + ) + + blockedAddresses := map[string]bool{ + accountKeeper.GetAuthority(): false, + } + bankKeeper := bankkeeper.NewBaseKeeper( + cdc, + runtime.NewKVStoreService(keys[banktypes.StoreKey]), + accountKeeper, + blockedAddresses, + authority.String(), + log.NewNopLogger(), + ) + + auctionKeeper := auctionkeeper.NewKeeper(cdc, runtime.NewKVStoreService(keys[auctionTypes.StoreKey]), accountKeeper, bankKeeper) + + bondKeeper := bondkeeper.NewKeeper(cdc, runtime.NewKVStoreService(keys[bondTypes.StoreKey]), accountKeeper, bankKeeper) + + registryKeeper := registrykeeper.NewKeeper(cdc, runtime.NewKVStoreService(keys[registryTypes.StoreKey]), accountKeeper, bankKeeper, bondKeeper, auctionKeeper) + + authModule := auth.NewAppModule(cdc, accountKeeper, authsims.RandomGenesisAccounts, nil) + bankModule := bank.NewAppModule(cdc, bankKeeper, accountKeeper, nil) + auctionModule := auctionmodule.NewAppModule(cdc, auctionKeeper) + bondModule := bondmodule.NewAppModule(cdc, bondKeeper) + registryModule := registrymodule.NewAppModule(cdc, registryKeeper) + + integrationApp := integration.NewIntegrationApp(newCtx, logger, keys, cdc, map[string]appmodule.AppModule{ + authtypes.ModuleName: authModule, + banktypes.ModuleName: bankModule, + auctionTypes.ModuleName: auctionModule, + bondTypes.ModuleName: bondModule, + registryTypes.ModuleName: registryModule, + }) + + sdkCtx := sdk.UnwrapSDKContext(integrationApp.Context()) + + // Register MsgServer and QueryServer + auctionTypes.RegisterMsgServer(integrationApp.MsgServiceRouter(), auctionkeeper.NewMsgServerImpl(auctionKeeper)) + auctionTypes.RegisterQueryServer(integrationApp.QueryHelper(), auctionkeeper.NewQueryServerImpl(auctionKeeper)) + + bondTypes.RegisterMsgServer(integrationApp.MsgServiceRouter(), bondkeeper.NewMsgServerImpl(bondKeeper)) + bondTypes.RegisterQueryServer(integrationApp.QueryHelper(), bondkeeper.NewQueryServerImpl(bondKeeper)) + + registryTypes.RegisterMsgServer(integrationApp.MsgServiceRouter(), registrykeeper.NewMsgServerImpl(registryKeeper)) + registryTypes.RegisterQueryServer(integrationApp.QueryHelper(), registrykeeper.NewQueryServerImpl(registryKeeper)) + + // set default params + if err := auctionKeeper.Params.Set(sdkCtx, auctionTypes.DefaultParams()); err != nil { + return err + } + if err := bondKeeper.Params.Set(sdkCtx, bondTypes.DefaultParams()); err != nil { + return err + } + if err := registryKeeper.Params.Set(sdkCtx, registryTypes.DefaultParams()); err != nil { + return err + } + + tf.App = integrationApp + tf.SdkCtx, tf.cdc, tf.keys = sdkCtx, cdc, keys + tf.AccountKeeper, tf.BankKeeper = accountKeeper, bankKeeper + tf.AuctionKeeper, tf.BondKeeper, tf.RegistryKeeper = auctionKeeper, bondKeeper, registryKeeper + + return nil +} + +type BondDenomProvider struct{} + +func (bdp BondDenomProvider) BondDenom(ctx context.Context) (string, error) { + return sdk.DefaultBondDenom, nil +} diff --git a/tests/integration/data/examples/example1.yml b/tests/integration/data/examples/example1.yml new file mode 100644 index 00000000..3f7b4863 --- /dev/null +++ b/tests/integration/data/examples/example1.yml @@ -0,0 +1,7 @@ +record: + attr1: value1 + attr2: value2 + link1: + /: QmSnuWmxptJZdLJpKRarxBMS2Ju2oANVrgbr2xWbie9b2D + link2: + /: QmP8jTG1m9GSDJLCbeWhVSVgEzCPPwXRdCRuJtQ5Tz9Kc9 diff --git a/tests/integration/data/examples/general_record_example.yml b/tests/integration/data/examples/general_record_example.yml new file mode 100644 index 00000000..5b3ef3b5 --- /dev/null +++ b/tests/integration/data/examples/general_record_example.yml @@ -0,0 +1,7 @@ +record: + type: GeneralRecord + name: foo + version: 1.0.0 + tags: + - tagA + - tagB diff --git a/tests/integration/data/examples/service_provider_example.yml b/tests/integration/data/examples/service_provider_example.yml new file mode 100644 index 00000000..87ea35ca --- /dev/null +++ b/tests/integration/data/examples/service_provider_example.yml @@ -0,0 +1,13 @@ + +record: + type: ServiceProviderRegistration + bond_id: madeUpBondID + laconic_id: madeUpLaconicID + version: 1.0.0 + x500: + common_name: cerc-io + organization_unit: xyz + organization_name: abc + state_name: california + country: US + locality_name: local \ No newline at end of file diff --git a/tests/integration/data/examples/website_registration_example.yml b/tests/integration/data/examples/website_registration_example.yml new file mode 100644 index 00000000..419f62fd --- /dev/null +++ b/tests/integration/data/examples/website_registration_example.yml @@ -0,0 +1,7 @@ +record: + type: WebsiteRegistrationRecord + url: https://cerc.io + repo_registration_record_cid: QmSnuWmxptJZdLJpKRarxBMS2Ju2oANVrgbr2xWbie9b2D + build_artifact_cid: QmP8jTG1m9GSDJLCbeWhVSVgEzCPPwXRdCRuJtQ5Tz9Kc9 + tls_cerc_cid: QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR + version: 1.0.0 \ No newline at end of file diff --git a/tests/integration/registry/keeper/common_test.go b/tests/integration/registry/keeper/common_test.go new file mode 100644 index 00000000..05712894 --- /dev/null +++ b/tests/integration/registry/keeper/common_test.go @@ -0,0 +1,59 @@ +package keeper_test + +import ( + "testing" + + "cosmossdk.io/math" + simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + + integrationTest "git.vdb.to/cerc-io/laconic2d/tests/integration" + bondTypes "git.vdb.to/cerc-io/laconic2d/x/bond" + types "git.vdb.to/cerc-io/laconic2d/x/registry" +) + +type KeeperTestSuite struct { + suite.Suite + integrationTest.TestFixture + + queryClient types.QueryClient + + accounts []sdk.AccAddress + bond bondTypes.Bond +} + +func (kts *KeeperTestSuite) SetupTest() { + kts.TestFixture.Setup() + + // set default params + err := kts.RegistryKeeper.Params.Set(kts.SdkCtx, types.DefaultParams()) + assert.Nil(kts.T(), err) + + qr := kts.App.QueryHelper() + kts.queryClient = types.NewQueryClient(qr) + + // Create a bond + bond, err := kts.createBond() + assert.Nil(kts.T(), err) + kts.bond = *bond +} + +func TestRegistryKeeperTestSuite(t *testing.T) { + suite.Run(t, new(KeeperTestSuite)) +} + +func (kts *KeeperTestSuite) createBond() (*bondTypes.Bond, error) { + ctx := kts.SdkCtx + + // Create a funded account + kts.accounts = simtestutil.AddTestAddrs(kts.BankKeeper, integrationTest.BondDenomProvider{}, ctx, 1, math.NewInt(100000000000)) + + bond, err := kts.BondKeeper.CreateBond(ctx, kts.accounts[0], sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(1000000000)))) + if err != nil { + return nil, err + } + + return bond, nil +} diff --git a/tests/integration/registry/keeper/query_server_test.go b/tests/integration/registry/keeper/query_server_test.go new file mode 100644 index 00000000..0c527dd8 --- /dev/null +++ b/tests/integration/registry/keeper/query_server_test.go @@ -0,0 +1,421 @@ +package keeper_test + +import ( + "context" + "fmt" + "path/filepath" + "reflect" + + types "git.vdb.to/cerc-io/laconic2d/x/registry" + "git.vdb.to/cerc-io/laconic2d/x/registry/client/cli" + "git.vdb.to/cerc-io/laconic2d/x/registry/helpers" + registryKeeper "git.vdb.to/cerc-io/laconic2d/x/registry/keeper" +) + +func (kts *KeeperTestSuite) TestGrpcQueryParams() { + testCases := []struct { + msg string + req *types.QueryParamsRequest + }{ + { + "Get Params", + &types.QueryParamsRequest{}, + }, + } + for _, test := range testCases { + kts.Run(fmt.Sprintf("Case %s ", test.msg), func() { + resp, _ := kts.queryClient.Params(context.Background(), test.req) + defaultParams := types.DefaultParams() + kts.Require().Equal(defaultParams.String(), resp.GetParams().String()) + }) + } +} + +func (kts *KeeperTestSuite) TestGrpcGetRecordLists() { + ctx, queryClient := kts.SdkCtx, kts.queryClient + sr := kts.Require() + + var recordId string + examples := []string{ + "../../data/examples/service_provider_example.yml", + "../../data/examples/website_registration_example.yml", + "../../data/examples/general_record_example.yml", + } + testCases := []struct { + msg string + req *types.QueryRecordsRequest + createRecords bool + expErr bool + noOfRecords int + }{ + { + "Empty Records", + &types.QueryRecordsRequest{}, + false, + false, + 0, + }, + { + "List Records", + &types.QueryRecordsRequest{}, + true, + false, + 3, + }, + { + "Filter with type", + &types.QueryRecordsRequest{ + Attributes: []*types.QueryRecordsRequest_KeyValueInput{ + { + Key: "type", + Value: &types.QueryRecordsRequest_ValueInput{ + Value: &types.QueryRecordsRequest_ValueInput_String_{String_: "WebsiteRegistrationRecord"}, + }, + }, + }, + All: true, + }, + true, + false, + 1, + }, + // Skip the following test as querying with recursive values not supported (PR https://git.vdb.to/cerc-io/laconicd/pulls/112) + // See function RecordsFromAttributes (QueryValueToJSON call) in the registry keeper implementation (x/registry/keeper/keeper.go) + // { + // "Filter with tag (extant) (https://git.vdb.to/cerc-io/laconicd/issues/129)", + // &types.QueryRecordsRequest{ + // Attributes: []*types.QueryRecordsRequest_KeyValueInput{ + // { + // Key: "tags", + // // Value: &types.QueryRecordsRequest_ValueInput{ + // // Value: &types.QueryRecordsRequest_ValueInput_String_{"tagA"}, + // // }, + // Value: &types.QueryRecordsRequest_ValueInput{ + // Value: &types.QueryRecordsRequest_ValueInput_Array{Array: &types.QueryRecordsRequest_ArrayInput{ + // Values: []*types.QueryRecordsRequest_ValueInput{ + // { + // Value: &types.QueryRecordsRequest_ValueInput_String_{"tagA"}, + // }, + // }, + // }}, + // }, + // // Throws: "Recursive query values are not supported" + // }, + // }, + // All: true, + // }, + // true, + // false, + // 1, + // }, + { + "Filter with tag (non-existent) (https://git.vdb.to/cerc-io/laconicd/issues/129)", + &types.QueryRecordsRequest{ + Attributes: []*types.QueryRecordsRequest_KeyValueInput{ + { + Key: "tags", + Value: &types.QueryRecordsRequest_ValueInput{ + Value: &types.QueryRecordsRequest_ValueInput_String_{String_: "NOEXIST"}, + }, + }, + }, + All: true, + }, + true, + false, + 0, + }, + { + "Filter test for key collision (https://git.vdb.to/cerc-io/laconicd/issues/122)", + &types.QueryRecordsRequest{ + Attributes: []*types.QueryRecordsRequest_KeyValueInput{ + { + Key: "typ", + Value: &types.QueryRecordsRequest_ValueInput{ + Value: &types.QueryRecordsRequest_ValueInput_String_{String_: "eWebsiteRegistrationRecord"}, + }, + }, + }, + All: true, + }, + true, + false, + 0, + }, + { + "Filter with attributes ServiceProviderRegistration", + &types.QueryRecordsRequest{ + Attributes: []*types.QueryRecordsRequest_KeyValueInput{ + { + Key: "x500state_name", + Value: &types.QueryRecordsRequest_ValueInput{ + Value: &types.QueryRecordsRequest_ValueInput_String_{String_: "california"}, + }, + }, + }, + All: true, + }, + true, + false, + 1, + }, + } + for _, test := range testCases { + kts.Run(fmt.Sprintf("Case %s ", test.msg), func() { + if test.createRecords { + for _, example := range examples { + filePath, err := filepath.Abs(example) + sr.NoError(err) + payloadType, err := cli.GetPayloadFromFile(filePath) + sr.NoError(err) + payload := payloadType.ToPayload() + record, err := kts.RegistryKeeper.SetRecord(ctx, types.MsgSetRecord{ + BondId: kts.bond.GetId(), + Signer: kts.accounts[0].String(), + Payload: payload, + }) + sr.NoError(err) + sr.NotNil(record.Id) + } + } + + resp, err := queryClient.Records(context.Background(), test.req) + + if test.expErr { + kts.Error(err) + } else { + sr.NoError(err) + sr.Equal(test.noOfRecords, len(resp.GetRecords())) + if test.createRecords && test.noOfRecords > 0 { + recordId = resp.GetRecords()[0].GetId() + sr.NotZero(resp.GetRecords()) + sr.Equal(resp.GetRecords()[0].GetBondId(), kts.bond.GetId()) + + for _, record := range resp.GetRecords() { + recAttr := helpers.MustUnmarshalJSON[types.AttributeMap](record.Attributes) + + for _, attr := range test.req.GetAttributes() { + enc, err := registryKeeper.QueryValueToJSON(attr.Value) + sr.NoError(err) + av := helpers.MustUnmarshalJSON[any](enc) + + if nil != av && nil != recAttr[attr.Key] && + reflect.Slice == reflect.TypeOf(recAttr[attr.Key]).Kind() && + reflect.Slice != reflect.TypeOf(av).Kind() { + found := false + allValues := recAttr[attr.Key].([]interface{}) + for i := range allValues { + if av == allValues[i] { + fmt.Printf("Found %s in %s", allValues[i], recAttr[attr.Key]) + found = true + } + } + sr.Equal(true, found, fmt.Sprintf("Unable to find %s in %s", av, recAttr[attr.Key])) + } else { + if attr.Key[:4] == "x500" { + sr.Equal(av, recAttr["x500"].(map[string]interface{})[attr.Key[4:]]) + } else { + sr.Equal(av, recAttr[attr.Key]) + } + } + } + } + } + } + }) + } + + // Get the records by record id + testCases1 := []struct { + msg string + req *types.QueryRecordByIdRequest + createRecord bool + expErr bool + noOfRecords int + }{ + { + "Invalid Request without record id", + &types.QueryRecordByIdRequest{}, + false, + true, + 0, + }, + { + "With Record ID", + &types.QueryRecordByIdRequest{ + Id: recordId, + }, + true, + false, + 1, + }, + } + for _, test := range testCases1 { + kts.Run(fmt.Sprintf("Case %s ", test.msg), func() { + resp, err := queryClient.GetRecord(context.Background(), test.req) + + if test.expErr { + kts.Error(err) + } else { + sr.NoError(err) + sr.NotNil(resp.GetRecord()) + if test.createRecord { + sr.Equal(resp.GetRecord().BondId, kts.bond.GetId()) + sr.Equal(resp.GetRecord().Id, recordId) + } + } + }) + } + + // Get the records by record id + testCasesByBondID := []struct { + msg string + req *types.QueryRecordsByBondIdRequest + createRecord bool + expErr bool + noOfRecords int + }{ + { + "Invalid Request without bond id", + &types.QueryRecordsByBondIdRequest{}, + false, + true, + 0, + }, + { + "With Bond ID", + &types.QueryRecordsByBondIdRequest{ + Id: kts.bond.GetId(), + }, + true, + false, + 1, + }, + } + for _, test := range testCasesByBondID { + kts.Run(fmt.Sprintf("Case %s ", test.msg), func() { + resp, err := queryClient.GetRecordsByBondId(context.Background(), test.req) + + if test.expErr { + sr.Zero(resp.GetRecords()) + } else { + sr.NoError(err) + sr.NotNil(resp.GetRecords()) + if test.createRecord { + sr.NotZero(resp.GetRecords()) + sr.Equal(resp.GetRecords()[0].GetBondId(), kts.bond.GetId()) + } + } + }) + } +} + +func (kts *KeeperTestSuite) TestGrpcQueryRegistryModuleBalance() { + queryClient, ctx := kts.queryClient, kts.SdkCtx + sr := kts.Require() + examples := []string{ + "../../data/examples/service_provider_example.yml", + "../../data/examples/website_registration_example.yml", + } + testCases := []struct { + msg string + req *types.QueryGetRegistryModuleBalanceRequest + createRecords bool + expErr bool + noOfRecords int + }{ + { + "Get Module Balance", + &types.QueryGetRegistryModuleBalanceRequest{}, + true, + false, + 1, + }, + } + for _, test := range testCases { + kts.Run(fmt.Sprintf("Case %s ", test.msg), func() { + if test.createRecords { + for _, example := range examples { + filePath, err := filepath.Abs(example) + sr.NoError(err) + payloadType, err := cli.GetPayloadFromFile(filePath) + sr.NoError(err) + payload := payloadType.ToPayload() + record, err := kts.RegistryKeeper.SetRecord(ctx, types.MsgSetRecord{ + BondId: kts.bond.GetId(), + Signer: kts.accounts[0].String(), + Payload: payload, + }) + sr.NoError(err) + sr.NotNil(record.Id) + } + } + resp, err := queryClient.GetRegistryModuleBalance(context.Background(), test.req) + if test.expErr { + kts.Error(err) + } else { + sr.NoError(err) + sr.Equal(test.noOfRecords, len(resp.GetBalances())) + if test.createRecords { + balance := resp.GetBalances()[0] + sr.Equal(balance.AccountName, types.RecordRentModuleAccountName) + } + } + }) + } +} + +func (kts *KeeperTestSuite) TestGrpcQueryWhoIs() { + queryClient, ctx := kts.queryClient, kts.SdkCtx + sr := kts.Require() + authorityName := "TestGrpcQueryWhoIs" + + testCases := []struct { + msg string + req *types.QueryWhoisRequest + createName bool + expErr bool + noOfRecords int + }{ + { + "Invalid Request without name", + &types.QueryWhoisRequest{}, + false, + true, + 1, + }, + { + "Success", + &types.QueryWhoisRequest{}, + true, + false, + 1, + }, + } + for _, test := range testCases { + kts.Run(fmt.Sprintf("Case %s ", test.msg), func() { + if test.createName { + err := kts.RegistryKeeper.ReserveAuthority(ctx, types.MsgReserveAuthority{ + Name: authorityName, + Signer: kts.accounts[0].String(), + Owner: kts.accounts[0].String(), + }) + sr.NoError(err) + test.req = &types.QueryWhoisRequest{Name: authorityName} + } + resp, err := queryClient.Whois(context.Background(), test.req) + if test.expErr { + kts.Error(err) + sr.Nil(resp) + } else { + sr.NoError(err) + if test.createName { + nameAuth := resp.NameAuthority + sr.NotNil(nameAuth) + sr.Equal(nameAuth.OwnerAddress, kts.accounts[0].String()) + sr.Equal(types.AuthorityActive, nameAuth.Status) + } + } + }) + } +} diff --git a/x/auction/keys.go b/x/auction/keys.go index fe626433..81c24cf3 100644 --- a/x/auction/keys.go +++ b/x/auction/keys.go @@ -5,6 +5,9 @@ import "cosmossdk.io/collections" const ( ModuleName = "auction" + // StoreKey defines the primary module store key + StoreKey = ModuleName + // AuctionBurnModuleAccountName is the name of the auction burn module account. AuctionBurnModuleAccountName = "auction_burn" ) diff --git a/x/bond/keys.go b/x/bond/keys.go index ddb5e32e..60c178a3 100644 --- a/x/bond/keys.go +++ b/x/bond/keys.go @@ -4,6 +4,9 @@ import "cosmossdk.io/collections" const ( ModuleName = "bond" + + // StoreKey defines the primary module store key + StoreKey = ModuleName ) // Store prefixes diff --git a/x/registry/keeper/keeper.go b/x/registry/keeper/keeper.go index 2d9c2c32..fbc854cc 100644 --- a/x/registry/keeper/keeper.go +++ b/x/registry/keeper/keeper.go @@ -19,8 +19,10 @@ import ( auth "github.com/cosmos/cosmos-sdk/x/auth/keeper" bank "github.com/cosmos/cosmos-sdk/x/bank/keeper" "github.com/gibson042/canonicaljson-go" + cid "github.com/ipfs/go-cid" "github.com/ipld/go-ipld-prime" "github.com/ipld/go-ipld-prime/codec/dagjson" + cidlink "github.com/ipld/go-ipld-prime/linking/cid" "github.com/ipld/go-ipld-prime/node/basicnode" auctionkeeper "git.vdb.to/cerc-io/laconic2d/x/auction/keeper" @@ -105,6 +107,7 @@ type Keeper struct { NameRecords *collections.IndexedMap[string, registrytypes.NameRecord, NameRecordsIndexes] RecordExpiryQueue collections.Map[time.Time, registrytypes.ExpiryQueue] AuthorityExpiryQueue collections.Map[time.Time, registrytypes.ExpiryQueue] + AttributesMap collections.Map[collections.Pair[string, string], registrytypes.RecordsList] } // NewKeeper creates a new Keeper instance @@ -147,6 +150,10 @@ func NewKeeper( sb, registrytypes.AuthorityExpiryQueuePrefix, "authority_expiry_queue", sdk.TimeKey, codec.CollValue[registrytypes.ExpiryQueue](cdc), ), + AttributesMap: collections.NewMap( + sb, registrytypes.AttributesMapPrefix, "attributes_map", + collections.PairKeyCodec(collections.StringKey, collections.StringKey), codec.CollValue[registrytypes.RecordsList](cdc), + ), } schema, err := sb.Build() @@ -237,7 +244,90 @@ func (k Keeper) GetRecordsByBondId(ctx sdk.Context, bondId string) ([]registryty // RecordsFromAttributes gets a list of records whose attributes match all provided values func (k Keeper) RecordsFromAttributes(ctx sdk.Context, attributes []*registrytypes.QueryRecordsRequest_KeyValueInput, all bool) ([]registrytypes.Record, error) { - panic("unimplemented") + resultRecordIds := []string{} + for i, attr := range attributes { + suffix, err := QueryValueToJSON(attr.Value) + if err != nil { + return nil, err + } + mapKey := collections.Join(attr.Key, string(suffix)) + recordIds, err := k.getAttributeMapping(ctx, mapKey) + if err != nil { + return nil, err + } + + if i == 0 { + resultRecordIds = recordIds + } else { + resultRecordIds = getIntersection(recordIds, resultRecordIds) + } + } + + records := []registrytypes.Record{} + for _, id := range resultRecordIds { + record, err := k.GetRecordById(ctx, id) + if err != nil { + return nil, err + } + if record.Deleted { + continue + } + if !all && len(record.Names) == 0 { + continue + } + records = append(records, record) + } + + return records, nil +} + +// TODO not recursive, and only should be if we want to support querying with whole sub-objects, +// which seems unnecessary. +func QueryValueToJSON(input *registrytypes.QueryRecordsRequest_ValueInput) ([]byte, error) { + np := basicnode.Prototype.Any + nb := np.NewBuilder() + + switch value := input.GetValue().(type) { + case *registrytypes.QueryRecordsRequest_ValueInput_String_: + err := nb.AssignString(value.String_) + if err != nil { + return nil, err + } + case *registrytypes.QueryRecordsRequest_ValueInput_Int: + err := nb.AssignInt(value.Int) + if err != nil { + return nil, err + } + case *registrytypes.QueryRecordsRequest_ValueInput_Float: + err := nb.AssignFloat(value.Float) + if err != nil { + return nil, err + } + case *registrytypes.QueryRecordsRequest_ValueInput_Boolean: + err := nb.AssignBool(value.Boolean) + if err != nil { + return nil, err + } + case *registrytypes.QueryRecordsRequest_ValueInput_Link: + link := cidlink.Link{Cid: cid.MustParse(value.Link)} + err := nb.AssignLink(link) + if err != nil { + return nil, err + } + case *registrytypes.QueryRecordsRequest_ValueInput_Array: + return nil, fmt.Errorf("recursive query values are not supported") + case *registrytypes.QueryRecordsRequest_ValueInput_Map: + return nil, fmt.Errorf("recursive query values are not supported") + default: + return nil, fmt.Errorf("value has unexpected type %T", value) + } + + n := nb.Build() + var buf bytes.Buffer + if err := dagjson.Encode(n, &buf); err != nil { + return nil, fmt.Errorf("encoding value to JSON failed: %w", err) + } + return buf.Bytes(), nil } // PutRecord - saves a record to the store. @@ -321,20 +411,14 @@ func (k Keeper) processRecord(ctx sdk.Context, record *registrytypes.ReadableRec // TODO look up/validate record type here - if err := k.processAttributes(ctx, record.Attributes, record.Id, ""); err != nil { + if err := k.processAttributes(ctx, record.Attributes, record.Id); err != nil { return err } - // TODO - // expiryTimeKey := GetAttributesIndexKey(ExpiryTimeAttributeName, []byte(record.ExpiryTime)) - // if err := k.SetAttributeMapping(ctx, expiryTimeKey, record.ID); err != nil { - // return err - // } - return k.insertRecordExpiryQueue(ctx, recordObj) } -func (k Keeper) processAttributes(ctx sdk.Context, attrs registrytypes.AttributeMap, id string, prefix string) error { +func (k Keeper) processAttributes(ctx sdk.Context, attrs registrytypes.AttributeMap, id string) error { np := basicnode.Prototype.Map nb := np.NewBuilder() encAttrs, err := canonicaljson.Marshal(attrs) @@ -353,7 +437,7 @@ func (k Keeper) processAttributes(ctx sdk.Context, attrs registrytypes.Attribute return fmt.Errorf("record attributes must be a map, not %T", n.Kind()) } - return k.processAttributeMap(ctx, n, id, prefix) + return k.processAttributeMap(ctx, n, id, "") } func (k Keeper) processAttributeMap(ctx sdk.Context, n ipld.Node, id string, prefix string) error { @@ -378,17 +462,55 @@ func (k Keeper) processAttributeMap(ctx sdk.Context, n ipld.Node, id string, pre if err := dagjson.Encode(valuenode, &buf); err != nil { return err } - // TODO - // value := buf.Bytes() - // indexKey := GetAttributesIndexKey(prefix+key, value) - // if err := k.SetAttributeMapping(ctx, indexKey, id); err != nil { - // return err - // } + + value := buf.Bytes() + mapKey := collections.Join(prefix+key, string(value)) + if err := k.setAttributeMapping(ctx, mapKey, id); err != nil { + return err + } } } return nil } +func (k Keeper) setAttributeMapping(ctx sdk.Context, key collections.Pair[string, string], recordId string) error { + var recordIds []string + + has, err := k.AttributesMap.Has(ctx, key) + if err != nil { + return err + } + if has { + value, err := k.AttributesMap.Get(ctx, key) + if err != nil { + return err + } + recordIds = value.Value + } + + recordIds = append(recordIds, recordId) + + return k.AttributesMap.Set(ctx, key, registrytypes.RecordsList{Value: recordIds}) +} + +func (k Keeper) getAttributeMapping(ctx sdk.Context, key collections.Pair[string, string]) ([]string, error) { + if has, err := k.AttributesMap.Has(ctx, key); !has { + if err != nil { + return []string{}, err + } + + k.Logger(ctx).Debug(fmt.Sprintf("store doesn't have key: %v", key)) + return []string{}, nil + } + + value, err := k.AttributesMap.Get(ctx, key) + if err != nil { + return []string{}, err + } + + return value.Value, nil +} + func (k Keeper) populateRecordNames(ctx sdk.Context, record *registrytypes.Record) error { iter, err := k.NameRecords.Indexes.Cid.MatchExact(ctx, record.Id) if err != nil { @@ -571,3 +693,30 @@ func (k Keeper) tryTakeRecordRent(ctx sdk.Context, record registrytypes.Record) record.Deleted = false return k.SaveRecord(ctx, record) } + +func getIntersection(a []string, b []string) []string { + result := []string{} + if len(a) < len(b) { + for _, str := range a { + if contains(b, str) { + result = append(result, str) + } + } + } else { + for _, str := range b { + if contains(a, str) { + result = append(result, str) + } + } + } + return result +} + +func contains(arr []string, str string) bool { + for _, s := range arr { + if s == str { + return true + } + } + return false +} diff --git a/x/registry/keys.go b/x/registry/keys.go index 58e68269..6f03eb73 100644 --- a/x/registry/keys.go +++ b/x/registry/keys.go @@ -6,6 +6,9 @@ const ( // ModuleName is the name of the registry module ModuleName = "registry" + // StoreKey defines the primary module store key + StoreKey = ModuleName + // RecordRentModuleAccountName is the name of the module account that keeps track of record rents paid. RecordRentModuleAccountName = "record_rent" @@ -30,4 +33,6 @@ var ( RecordExpiryQueuePrefix = collections.NewPrefix(8) AuthorityExpiryQueuePrefix = collections.NewPrefix(9) + + AttributesMapPrefix = collections.NewPrefix(10) ) diff --git a/x/registry/registry.pb.go b/x/registry/registry.pb.go index 3fff0fa0..b104b413 100644 --- a/x/registry/registry.pb.go +++ b/x/registry/registry.pb.go @@ -679,6 +679,52 @@ func (m *ExpiryQueue) GetValue() []string { return nil } +// List of record ids +// Value type to be used in AttributesMap +type RecordsList struct { + Value []string `protobuf:"bytes,1,rep,name=value,proto3" json:"value,omitempty"` +} + +func (m *RecordsList) Reset() { *m = RecordsList{} } +func (m *RecordsList) String() string { return proto.CompactTextString(m) } +func (*RecordsList) ProtoMessage() {} +func (*RecordsList) Descriptor() ([]byte, []int) { + return fileDescriptor_d792f2373089b5b9, []int{9} +} +func (m *RecordsList) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RecordsList) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RecordsList.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RecordsList) XXX_Merge(src proto.Message) { + xxx_messageInfo_RecordsList.Merge(m, src) +} +func (m *RecordsList) XXX_Size() int { + return m.Size() +} +func (m *RecordsList) XXX_DiscardUnknown() { + xxx_messageInfo_RecordsList.DiscardUnknown(m) +} + +var xxx_messageInfo_RecordsList proto.InternalMessageInfo + +func (m *RecordsList) GetValue() []string { + if m != nil { + return m.Value + } + return nil +} + func init() { proto.RegisterType((*Params)(nil), "cerc.registry.v1.Params") proto.RegisterType((*Record)(nil), "cerc.registry.v1.Record") @@ -689,89 +735,91 @@ func init() { proto.RegisterType((*NameRecordEntry)(nil), "cerc.registry.v1.NameRecordEntry") proto.RegisterType((*Signature)(nil), "cerc.registry.v1.Signature") proto.RegisterType((*ExpiryQueue)(nil), "cerc.registry.v1.ExpiryQueue") + proto.RegisterType((*RecordsList)(nil), "cerc.registry.v1.RecordsList") } func init() { proto.RegisterFile("cerc/registry/v1/registry.proto", fileDescriptor_d792f2373089b5b9) } var fileDescriptor_d792f2373089b5b9 = []byte{ - // 1221 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x57, 0xcb, 0x6e, 0xdb, 0x46, - 0x17, 0x36, 0x6d, 0x59, 0xb6, 0x8e, 0x63, 0xff, 0xc1, 0xfc, 0x4e, 0x22, 0xbb, 0xb1, 0xe8, 0xa8, - 0x28, 0xec, 0x20, 0x30, 0x09, 0xd9, 0x28, 0x82, 0x24, 0xe8, 0xc2, 0x72, 0x1d, 0xc3, 0x0d, 0xda, - 0x3a, 0xe3, 0xac, 0x5a, 0x14, 0x02, 0x2f, 0x13, 0x79, 0x5a, 0x91, 0x14, 0xc8, 0xa1, 0x1a, 0x2d, - 0x0b, 0x74, 0xd3, 0x9d, 0x97, 0x59, 0xf4, 0x0d, 0xba, 0xe8, 0x63, 0x34, 0xcb, 0x2c, 0xbb, 0x29, - 0x5b, 0xd8, 0x40, 0x1f, 0x40, 0x4f, 0x50, 0x70, 0x66, 0x78, 0x95, 0x14, 0xb5, 0xc8, 0x8e, 0xe7, - 0xf6, 0xcd, 0x37, 0xdf, 0x9c, 0xb9, 0x10, 0x54, 0x8b, 0xf8, 0x96, 0xee, 0x93, 0x2e, 0x0d, 0x98, - 0x3f, 0xd4, 0x07, 0xad, 0xf4, 0x5b, 0xeb, 0xfb, 0x1e, 0xf3, 0xd0, 0xcd, 0x38, 0x41, 0x4b, 0x9d, - 0x83, 0xd6, 0x66, 0xa3, 0xeb, 0x79, 0xdd, 0x1e, 0xd1, 0x79, 0xdc, 0x0c, 0x5f, 0xea, 0x76, 0xe8, - 0x1b, 0x8c, 0x7a, 0xae, 0xa8, 0xd8, 0x54, 0xcb, 0x71, 0x46, 0x1d, 0x12, 0x30, 0xc3, 0xe9, 0xcb, - 0x84, 0xf5, 0xae, 0xd7, 0xf5, 0xf8, 0xa7, 0x1e, 0x7f, 0x49, 0x6f, 0xc3, 0xf2, 0x02, 0xc7, 0x0b, - 0x74, 0xd3, 0x08, 0x88, 0x3e, 0x68, 0x99, 0x84, 0x19, 0x2d, 0xdd, 0xf2, 0xa8, 0x84, 0x6d, 0xfe, - 0xb1, 0x0a, 0xd5, 0x33, 0xc3, 0x37, 0x9c, 0x00, 0x51, 0x58, 0xf1, 0x89, 0xe5, 0xf9, 0x76, 0xc7, - 0x27, 0x2e, 0xab, 0x2b, 0xdb, 0xca, 0xee, 0xca, 0xfe, 0x86, 0x26, 0x00, 0xb4, 0x18, 0x40, 0x93, - 0x00, 0xda, 0x91, 0x47, 0xdd, 0xf6, 0xde, 0x9b, 0x48, 0x9d, 0x1b, 0x45, 0xea, 0x47, 0xdf, 0x06, - 0x9e, 0xfb, 0xb8, 0x99, 0xab, 0x6d, 0x6e, 0x0f, 0x0d, 0xa7, 0x57, 0x74, 0x61, 0x10, 0x16, 0x26, - 0x2e, 0x43, 0x97, 0x0a, 0xac, 0xe7, 0x82, 0x9d, 0x64, 0xae, 0xf5, 0x79, 0x39, 0xa8, 0x98, 0xac, - 0x96, 0x4c, 0x56, 0xfb, 0x54, 0x26, 0xb4, 0x8f, 0xe4, 0xa0, 0x0f, 0xc7, 0x06, 0x4d, 0x41, 0x26, - 0x8c, 0x9e, 0xc5, 0x5e, 0xff, 0xa9, 0x2a, 0x18, 0x65, 0x54, 0x12, 0x60, 0x14, 0xc2, 0x9a, 0x11, - 0xb2, 0x0b, 0xcf, 0xa7, 0x6c, 0x28, 0x04, 0x58, 0x98, 0x25, 0xc0, 0x81, 0xe4, 0xf2, 0x40, 0x70, - 0x29, 0x96, 0x27, 0x2c, 0x4a, 0x5e, 0xbc, 0x9a, 0x3a, 0xb8, 0x12, 0x3f, 0x2b, 0x70, 0xa7, 0x98, - 0x92, 0x89, 0x51, 0x99, 0x25, 0xc6, 0xa9, 0x24, 0xf0, 0xc9, 0x24, 0x02, 0x63, 0x7a, 0x4c, 0x0b, - 0x73, 0x49, 0x6e, 0x15, 0x68, 0xa5, 0xaa, 0xbc, 0x56, 0xe0, 0x76, 0x56, 0xd7, 0xf5, 0x0d, 0x8b, - 0x74, 0xfa, 0xc4, 0xa7, 0x9e, 0x5d, 0x5f, 0x9c, 0xc5, 0xee, 0x44, 0xb2, 0x7b, 0x52, 0x66, 0x97, - 0x87, 0x19, 0x27, 0x57, 0x88, 0x72, 0x6e, 0xeb, 0x69, 0xf0, 0x24, 0x8e, 0x9d, 0xf1, 0x10, 0xfa, - 0x41, 0x81, 0x8d, 0xac, 0xca, 0x08, 0xad, 0x78, 0xd0, 0x0e, 0x71, 0x0d, 0xb3, 0x47, 0xec, 0x7a, - 0x75, 0x5b, 0xd9, 0x5d, 0x6e, 0x1f, 0x8f, 0x22, 0xf5, 0xb0, 0x3c, 0x7c, 0x29, 0x75, 0x9c, 0x41, - 0x39, 0x01, 0x67, 0x2b, 0x74, 0x28, 0x42, 0xc7, 0x22, 0x82, 0x7e, 0x53, 0x60, 0x42, 0x9d, 0xe5, - 0x39, 0x0e, 0x65, 0x41, 0xb6, 0x90, 0x4b, 0xb3, 0xa4, 0xea, 0x48, 0xa9, 0xce, 0xa7, 0x71, 0x2d, - 0x43, 0x4e, 0x27, 0x3d, 0x96, 0xc9, 0x25, 0x54, 0xcb, 0x33, 0x38, 0x12, 0x69, 0xe9, 0x42, 0x4f, - 0x9e, 0x89, 0x4f, 0x06, 0xc4, 0xe8, 0xe5, 0x66, 0xb2, 0xfc, 0xde, 0x33, 0x29, 0x43, 0x4e, 0x9f, - 0xc9, 0x58, 0xe6, 0xe4, 0x99, 0x60, 0x91, 0x96, 0xce, 0xe4, 0x17, 0x05, 0xee, 0x4e, 0x93, 0xa5, - 0xf3, 0x92, 0x90, 0x7a, 0x6d, 0xd6, 0xbe, 0xfe, 0x52, 0xce, 0xe1, 0xe4, 0xdd, 0xab, 0x11, 0x83, - 0xcd, 0x5a, 0x07, 0x9e, 0x83, 0x37, 0x26, 0xab, 0xff, 0x94, 0x90, 0x29, 0x6c, 0xc5, 0xd4, 0x39, - 0x5b, 0x78, 0x6f, 0xb6, 0x19, 0xd8, 0x2c, 0xad, 0xa7, 0xb0, 0x15, 0x0a, 0xc7, 0x6c, 0x7f, 0x55, - 0x60, 0x6b, 0xbc, 0xd8, 0xa1, 0x2e, 0x75, 0x42, 0xa7, 0x63, 0x52, 0xbb, 0xbe, 0x32, 0x8b, 0xee, - 0x73, 0x49, 0xf7, 0x74, 0x1a, 0xdd, 0x1c, 0xda, 0x74, 0xbe, 0xf9, 0x24, 0xbc, 0x59, 0x26, 0xfc, - 0xb9, 0x88, 0xb6, 0xa9, 0xdd, 0xfc, 0xa9, 0x02, 0x55, 0xcc, 0x4f, 0x7b, 0xb4, 0x03, 0xf3, 0xd4, - 0xe6, 0xd7, 0x5a, 0xad, 0x7d, 0x67, 0x14, 0xa9, 0xff, 0x17, 0x0c, 0xb2, 0x61, 0x62, 0xac, 0x79, - 0x6a, 0xa3, 0xc7, 0xb0, 0x64, 0x7a, 0xae, 0xdd, 0xa1, 0x36, 0xbf, 0x8f, 0x6a, 0xed, 0x7b, 0xa3, - 0x48, 0xdd, 0x12, 0xd9, 0x32, 0x90, 0x94, 0x24, 0x26, 0xae, 0xc6, 0x5f, 0xa7, 0x36, 0xfa, 0x0c, - 0x56, 0x2c, 0x9f, 0x18, 0x8c, 0x74, 0xe2, 0xfb, 0x99, 0xdf, 0x21, 0xb5, 0xf6, 0xfd, 0xec, 0x96, - 0xcc, 0x05, 0x13, 0x8c, 0xbc, 0x0b, 0x83, 0xb0, 0x5e, 0x50, 0x87, 0xc4, 0x58, 0xe4, 0x55, 0x9f, - 0xfa, 0x43, 0x81, 0x55, 0x29, 0x63, 0xe5, 0x82, 0x09, 0x56, 0xde, 0x85, 0x41, 0x58, 0x1c, 0xab, - 0x0e, 0x4b, 0x36, 0xe9, 0x11, 0x46, 0xc4, 0xc1, 0xbd, 0x8c, 0x13, 0x13, 0x3d, 0x84, 0xaa, 0xf7, - 0xbd, 0x4b, 0xfc, 0xa0, 0x5e, 0xdd, 0x5e, 0xd8, 0xad, 0xb5, 0xd5, 0x51, 0xa4, 0x7e, 0x20, 0x06, - 0x10, 0xfe, 0x04, 0x5b, 0x5a, 0x58, 0xa6, 0xa3, 0x13, 0x00, 0x83, 0x31, 0x9f, 0x9a, 0x21, 0x23, - 0x01, 0x3f, 0xe3, 0x6e, 0xb4, 0x77, 0x46, 0x91, 0xfa, 0xa1, 0x5c, 0xd9, 0x34, 0x96, 0x2e, 0x63, - 0xe6, 0xc1, 0xb9, 0x52, 0x74, 0x00, 0x8b, 0xae, 0xe1, 0x90, 0xa0, 0xbe, 0xcc, 0x09, 0x6c, 0x8d, - 0x22, 0x75, 0x43, 0x60, 0x70, 0x77, 0x52, 0x2e, 0x0c, 0x2c, 0x72, 0x51, 0x0b, 0x2a, 0x6c, 0xd8, - 0x17, 0xbb, 0xb9, 0x50, 0x13, 0x7b, 0xd3, 0x1a, 0x61, 0x60, 0x9e, 0xda, 0xfc, 0x1a, 0xd6, 0x0e, - 0x93, 0x4e, 0x39, 0x76, 0x99, 0x3f, 0x44, 0x08, 0x2a, 0x31, 0x9a, 0x68, 0x0a, 0xcc, 0xbf, 0xd1, - 0xc7, 0xb0, 0x48, 0xe2, 0xa0, 0x7c, 0x8b, 0xa8, 0x5a, 0xf9, 0xa9, 0xa6, 0x7d, 0x61, 0x38, 0x24, - 0x05, 0xc2, 0x22, 0xbb, 0xf9, 0xf7, 0x02, 0xac, 0x16, 0x02, 0xe8, 0x1b, 0xb8, 0xc9, 0x95, 0xea, - 0xf4, 0x43, 0xb3, 0x47, 0xad, 0xce, 0x77, 0x64, 0x28, 0xbb, 0xef, 0x60, 0x14, 0xa9, 0x7a, 0x4e, - 0xe2, 0x5c, 0x46, 0x41, 0xec, 0xbc, 0x1f, 0xaf, 0x71, 0xd7, 0x19, 0xf7, 0x3c, 0x23, 0x43, 0x84, - 0x61, 0x55, 0x24, 0x19, 0xb6, 0xed, 0x93, 0x20, 0x90, 0xbd, 0xba, 0x37, 0x8a, 0xd4, 0xfb, 0x79, - 0x6c, 0x19, 0x2e, 0x02, 0x27, 0x4e, 0x7c, 0x83, 0xdb, 0x87, 0xc2, 0x44, 0xb7, 0xa1, 0x7a, 0x41, - 0x68, 0xf7, 0x42, 0x3c, 0x7e, 0x2a, 0x58, 0x5a, 0xb1, 0x3f, 0x60, 0x06, 0x0b, 0x03, 0xd1, 0x84, - 0x58, 0x5a, 0xe8, 0x29, 0x40, 0xb2, 0x23, 0xa9, 0x68, 0xac, 0x5a, 0xa1, 0x05, 0xd2, 0x58, 0xb6, - 0x93, 0x53, 0x0f, 0xae, 0x49, 0xe3, 0xb4, 0xb0, 0xe3, 0xaa, 0xff, 0x75, 0xc7, 0xb9, 0xc5, 0x5d, - 0x22, 0xee, 0xda, 0xcd, 0xb1, 0x1b, 0xea, 0x45, 0xf2, 0x5c, 0x6e, 0xb7, 0x8a, 0xef, 0xd6, 0x19, - 0xbb, 0xe8, 0x32, 0xbe, 0x74, 0x72, 0x3b, 0xa9, 0x79, 0x0e, 0xb5, 0x78, 0x9d, 0xa7, 0x37, 0xd0, - 0x7e, 0xb1, 0x81, 0xee, 0x4e, 0x6e, 0x20, 0x71, 0x28, 0x25, 0xdd, 0xf3, 0xa3, 0x02, 0x90, 0x79, - 0xd1, 0x23, 0xa8, 0xf6, 0x0c, 0x46, 0x82, 0xe4, 0x15, 0x7e, 0xef, 0x5d, 0x18, 0x9c, 0x09, 0x96, - 0x05, 0xe8, 0x09, 0x2c, 0x5d, 0xd0, 0x80, 0x79, 0x7c, 0xfc, 0x85, 0x7f, 0x57, 0x9b, 0x54, 0x34, - 0x1f, 0xc1, 0xff, 0x4a, 0x31, 0xb4, 0x96, 0x9d, 0x9a, 0xfc, 0x70, 0xcc, 0x5a, 0x64, 0x3e, 0xdf, - 0x22, 0x4d, 0x06, 0xb5, 0x73, 0xda, 0x75, 0x0d, 0x16, 0xfa, 0x04, 0x3d, 0x80, 0x85, 0x80, 0x76, - 0x65, 0xb7, 0x6f, 0x8c, 0x22, 0xf5, 0x96, 0xd0, 0x3a, 0xa0, 0xdd, 0x44, 0xe3, 0xf8, 0x13, 0xc7, - 0x59, 0xf1, 0xe2, 0xf7, 0x43, 0x93, 0x6f, 0x8f, 0xb1, 0xe3, 0x56, 0x06, 0x92, 0xa2, 0xc4, 0xc4, - 0xd5, 0x7e, 0x68, 0x3e, 0x23, 0xc3, 0xe6, 0x01, 0xac, 0x1c, 0xf3, 0xa5, 0x79, 0x1e, 0x92, 0x90, - 0x8c, 0x91, 0x5d, 0x87, 0xc5, 0x81, 0xd1, 0x0b, 0x09, 0x97, 0xa2, 0x86, 0x85, 0xd1, 0x3e, 0x7c, - 0x73, 0xd5, 0x50, 0xde, 0x5e, 0x35, 0x94, 0xbf, 0xae, 0x1a, 0xca, 0xe5, 0x75, 0x63, 0xee, 0xed, - 0x75, 0x63, 0xee, 0xf7, 0xeb, 0xc6, 0xdc, 0x57, 0x3b, 0x5d, 0xca, 0xb4, 0x81, 0x6d, 0x6a, 0xcc, - 0xd3, 0x63, 0xd5, 0xf6, 0xa8, 0xa7, 0xf7, 0x0c, 0xcb, 0x73, 0xa9, 0xb5, 0x6f, 0xeb, 0xaf, 0xd2, - 0xbf, 0x38, 0xb3, 0xca, 0xfb, 0xea, 0xe0, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xd2, 0xef, 0x57, - 0x0f, 0xe9, 0x0d, 0x00, 0x00, + // 1234 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x57, 0xcd, 0x6e, 0xdb, 0x46, + 0x10, 0x36, 0x6d, 0x59, 0xb6, 0x46, 0xb1, 0x1b, 0x6c, 0x9d, 0x44, 0x76, 0x63, 0xd1, 0x51, 0x50, + 0xd8, 0x41, 0x60, 0x12, 0xb2, 0x51, 0x04, 0x49, 0xd0, 0x83, 0xe5, 0x3a, 0x86, 0x9b, 0xfe, 0x38, + 0xeb, 0x9c, 0x5a, 0x14, 0x02, 0x7f, 0x36, 0xf2, 0xb6, 0x22, 0x29, 0x90, 0x4b, 0x35, 0x3a, 0x16, + 0xe8, 0xa5, 0x37, 0x1f, 0x73, 0xe8, 0x1b, 0xf4, 0xd0, 0xc7, 0x68, 0x8e, 0x39, 0xf6, 0x52, 0xb5, + 0xb0, 0x81, 0x3e, 0x80, 0x9e, 0xa0, 0xe0, 0xee, 0xf2, 0x57, 0x52, 0xd4, 0x20, 0x37, 0xce, 0xdf, + 0xb7, 0xdf, 0xcc, 0xce, 0xec, 0x2e, 0x41, 0xb5, 0x88, 0x6f, 0xe9, 0x3e, 0xe9, 0xd0, 0x80, 0xf9, + 0x03, 0xbd, 0xdf, 0x4c, 0xbe, 0xb5, 0x9e, 0xef, 0x31, 0x0f, 0x5d, 0x8f, 0x1c, 0xb4, 0x44, 0xd9, + 0x6f, 0x6e, 0xd4, 0x3b, 0x9e, 0xd7, 0xe9, 0x12, 0x9d, 0xdb, 0xcd, 0xf0, 0x85, 0x6e, 0x87, 0xbe, + 0xc1, 0xa8, 0xe7, 0x8a, 0x88, 0x0d, 0xb5, 0x68, 0x67, 0xd4, 0x21, 0x01, 0x33, 0x9c, 0x9e, 0x74, + 0x58, 0xeb, 0x78, 0x1d, 0x8f, 0x7f, 0xea, 0xd1, 0x97, 0xd4, 0xd6, 0x2d, 0x2f, 0x70, 0xbc, 0x40, + 0x37, 0x8d, 0x80, 0xe8, 0xfd, 0xa6, 0x49, 0x98, 0xd1, 0xd4, 0x2d, 0x8f, 0x4a, 0xd8, 0xc6, 0x5f, + 0x2b, 0x50, 0x3e, 0x35, 0x7c, 0xc3, 0x09, 0x10, 0x85, 0xaa, 0x4f, 0x2c, 0xcf, 0xb7, 0xdb, 0x3e, + 0x71, 0x59, 0x4d, 0xd9, 0x52, 0x76, 0xaa, 0x7b, 0xeb, 0x9a, 0x00, 0xd0, 0x22, 0x00, 0x4d, 0x02, + 0x68, 0x87, 0x1e, 0x75, 0x5b, 0xbb, 0xaf, 0x87, 0xea, 0xdc, 0x68, 0xa8, 0x7e, 0xfc, 0x7d, 0xe0, + 0xb9, 0x8f, 0x1a, 0x99, 0xd8, 0xc6, 0xd6, 0xc0, 0x70, 0xba, 0x79, 0x15, 0x06, 0x21, 0x61, 0xe2, + 0x32, 0x74, 0xa1, 0xc0, 0x5a, 0xc6, 0xd8, 0x8e, 0x73, 0xad, 0xcd, 0xcb, 0x45, 0x45, 0xb2, 0x5a, + 0x9c, 0xac, 0xf6, 0x99, 0x74, 0x68, 0x1d, 0xca, 0x45, 0x1f, 0x8c, 0x2d, 0x9a, 0x80, 0x4c, 0x58, + 0x3d, 0xb5, 0xbd, 0xfa, 0x5b, 0x55, 0x30, 0x4a, 0xa9, 0xc4, 0xc0, 0x28, 0x84, 0x55, 0x23, 0x64, + 0xe7, 0x9e, 0x4f, 0xd9, 0x40, 0x14, 0x60, 0x61, 0x56, 0x01, 0xf6, 0x25, 0x97, 0xfb, 0x82, 0x4b, + 0x3e, 0x3c, 0x66, 0x51, 0xd0, 0xe2, 0x95, 0x44, 0xc1, 0x2b, 0xf1, 0xab, 0x02, 0xb7, 0xf2, 0x2e, + 0x69, 0x31, 0x4a, 0xb3, 0x8a, 0x71, 0x22, 0x09, 0x7c, 0x3a, 0x89, 0xc0, 0x58, 0x3d, 0xa6, 0x99, + 0x79, 0x49, 0x6e, 0xe4, 0x68, 0x25, 0x55, 0x79, 0xa5, 0xc0, 0xcd, 0x34, 0xae, 0xe3, 0x1b, 0x16, + 0x69, 0xf7, 0x88, 0x4f, 0x3d, 0xbb, 0xb6, 0x38, 0x8b, 0xdd, 0xb1, 0x64, 0xf7, 0xb8, 0xc8, 0x2e, + 0x0b, 0x33, 0x4e, 0x2e, 0x67, 0xe5, 0xdc, 0xd6, 0x12, 0xe3, 0x71, 0x64, 0x3b, 0xe5, 0x26, 0xf4, + 0x93, 0x02, 0xeb, 0x69, 0x94, 0x11, 0x5a, 0xd1, 0xa2, 0x6d, 0xe2, 0x1a, 0x66, 0x97, 0xd8, 0xb5, + 0xf2, 0x96, 0xb2, 0xb3, 0xdc, 0x3a, 0x1a, 0x0d, 0xd5, 0x83, 0xe2, 0xf2, 0x05, 0xd7, 0x71, 0x06, + 0x45, 0x07, 0x9c, 0xee, 0xd0, 0x81, 0x30, 0x1d, 0x09, 0x0b, 0xfa, 0x43, 0x81, 0x09, 0x71, 0x96, + 0xe7, 0x38, 0x94, 0x05, 0xe9, 0x46, 0x2e, 0xcd, 0x2a, 0x55, 0x5b, 0x96, 0xea, 0x6c, 0x1a, 0xd7, + 0x22, 0xe4, 0x74, 0xd2, 0x63, 0x9e, 0xbc, 0x84, 0x6a, 0x31, 0x83, 0x43, 0xe1, 0x96, 0x6c, 0xf4, + 0xe4, 0x4c, 0x7c, 0xd2, 0x27, 0x46, 0x37, 0x93, 0xc9, 0xf2, 0x7b, 0x67, 0x52, 0x84, 0x9c, 0x9e, + 0xc9, 0x98, 0xe7, 0xe4, 0x4c, 0xb0, 0x70, 0x4b, 0x32, 0xf9, 0x4d, 0x81, 0xdb, 0xd3, 0xca, 0xd2, + 0x7e, 0x41, 0x48, 0xad, 0x32, 0x6b, 0xae, 0xbf, 0x96, 0x39, 0x1c, 0xbf, 0x7d, 0x37, 0x22, 0xb0, + 0x59, 0xfb, 0xc0, 0x7d, 0xf0, 0xfa, 0xe4, 0xea, 0x3f, 0x21, 0x64, 0x0a, 0x5b, 0x91, 0x3a, 0x67, + 0x0b, 0xef, 0xcd, 0x36, 0x05, 0x9b, 0x55, 0xeb, 0x29, 0x6c, 0x45, 0x85, 0x23, 0xb6, 0xbf, 0x2b, + 0xb0, 0x39, 0x1e, 0xec, 0x50, 0x97, 0x3a, 0xa1, 0xd3, 0x36, 0xa9, 0x5d, 0xab, 0xce, 0xa2, 0xfb, + 0x4c, 0xd2, 0x3d, 0x99, 0x46, 0x37, 0x83, 0x36, 0x9d, 0x6f, 0xd6, 0x09, 0x6f, 0x14, 0x09, 0x7f, + 0x29, 0xac, 0x2d, 0x6a, 0x37, 0x7e, 0x29, 0x41, 0x19, 0xf3, 0xd3, 0x1e, 0x6d, 0xc3, 0x3c, 0xb5, + 0xf9, 0xb5, 0x56, 0x69, 0xdd, 0x1a, 0x0d, 0xd5, 0x0f, 0x05, 0x83, 0x74, 0x99, 0x08, 0x6b, 0x9e, + 0xda, 0xe8, 0x11, 0x2c, 0x99, 0x9e, 0x6b, 0xb7, 0xa9, 0xcd, 0xef, 0xa3, 0x4a, 0xeb, 0xce, 0x68, + 0xa8, 0x6e, 0x0a, 0x6f, 0x69, 0x88, 0x43, 0x62, 0x11, 0x97, 0xa3, 0xaf, 0x13, 0x1b, 0x7d, 0x0e, + 0x55, 0xcb, 0x27, 0x06, 0x23, 0xed, 0xe8, 0x7e, 0xe6, 0x77, 0x48, 0xa5, 0x75, 0x2f, 0xbd, 0x25, + 0x33, 0xc6, 0x18, 0x23, 0xab, 0xc2, 0x20, 0xa4, 0xe7, 0xd4, 0x21, 0x11, 0x16, 0x79, 0xd9, 0xa3, + 0xfe, 0x40, 0x60, 0x95, 0x8a, 0x58, 0x19, 0x63, 0x8c, 0x95, 0x55, 0x61, 0x10, 0x12, 0xc7, 0xaa, + 0xc1, 0x92, 0x4d, 0xba, 0x84, 0x11, 0x71, 0x70, 0x2f, 0xe3, 0x58, 0x44, 0x0f, 0xa0, 0xec, 0xfd, + 0xe8, 0x12, 0x3f, 0xa8, 0x95, 0xb7, 0x16, 0x76, 0x2a, 0x2d, 0x75, 0x34, 0x54, 0x3f, 0x12, 0x0b, + 0x08, 0x7d, 0x8c, 0x2d, 0x25, 0x2c, 0xdd, 0xd1, 0x31, 0x80, 0xc1, 0x98, 0x4f, 0xcd, 0x90, 0x91, + 0x80, 0x9f, 0x71, 0xd7, 0x5a, 0xdb, 0xa3, 0xa1, 0x7a, 0x57, 0xee, 0x6c, 0x62, 0x4b, 0xb6, 0x31, + 0xd5, 0xe0, 0x4c, 0x28, 0xda, 0x87, 0x45, 0xd7, 0x70, 0x48, 0x50, 0x5b, 0xe6, 0x04, 0x36, 0x47, + 0x43, 0x75, 0x5d, 0x60, 0x70, 0x75, 0x1c, 0x2e, 0x04, 0x2c, 0x7c, 0x51, 0x13, 0x4a, 0x6c, 0xd0, + 0x13, 0xd3, 0x9c, 0x8b, 0x89, 0xb4, 0x49, 0x8c, 0x10, 0x30, 0x77, 0x6d, 0x7c, 0x0b, 0xab, 0x07, + 0x71, 0xa7, 0x1c, 0xb9, 0xcc, 0x1f, 0x20, 0x04, 0xa5, 0x08, 0x4d, 0x34, 0x05, 0xe6, 0xdf, 0xe8, + 0x13, 0x58, 0x24, 0x91, 0x51, 0xbe, 0x45, 0x54, 0xad, 0xf8, 0x54, 0xd3, 0xbe, 0x32, 0x1c, 0x92, + 0x00, 0x61, 0xe1, 0xdd, 0xf8, 0x77, 0x01, 0x56, 0x72, 0x06, 0xf4, 0x1d, 0x5c, 0xe7, 0x95, 0x6a, + 0xf7, 0x42, 0xb3, 0x4b, 0xad, 0xf6, 0x0f, 0x64, 0x20, 0xbb, 0x6f, 0x7f, 0x34, 0x54, 0xf5, 0x4c, + 0x89, 0x33, 0x1e, 0xb9, 0x62, 0x67, 0xf5, 0x78, 0x95, 0xab, 0x4e, 0xb9, 0xe6, 0x29, 0x19, 0x20, + 0x0c, 0x2b, 0xc2, 0xc9, 0xb0, 0x6d, 0x9f, 0x04, 0x81, 0xec, 0xd5, 0xdd, 0xd1, 0x50, 0xbd, 0x97, + 0xc5, 0x96, 0xe6, 0x3c, 0x70, 0xac, 0xc4, 0xd7, 0xb8, 0x7c, 0x20, 0x44, 0x74, 0x13, 0xca, 0xe7, + 0x84, 0x76, 0xce, 0xc5, 0xe3, 0xa7, 0x84, 0xa5, 0x14, 0xe9, 0x03, 0x66, 0xb0, 0x30, 0x10, 0x4d, + 0x88, 0xa5, 0x84, 0x9e, 0x00, 0xc4, 0x13, 0x49, 0x45, 0x63, 0x55, 0x72, 0x2d, 0x90, 0xd8, 0xd2, + 0x49, 0x4e, 0x34, 0xb8, 0x22, 0x85, 0x93, 0xdc, 0xc4, 0x95, 0xdf, 0x75, 0xe2, 0xdc, 0xfc, 0x94, + 0x88, 0xbb, 0x76, 0x63, 0xec, 0x86, 0x7a, 0x1e, 0x3f, 0x97, 0x5b, 0xcd, 0xfc, 0xbb, 0x75, 0xc6, + 0x14, 0x5d, 0x44, 0x97, 0x4e, 0x66, 0x92, 0x1a, 0x67, 0x50, 0x89, 0xf6, 0x79, 0x7a, 0x03, 0xed, + 0xe5, 0x1b, 0xe8, 0xf6, 0xe4, 0x06, 0x12, 0x87, 0x52, 0xdc, 0x3d, 0x3f, 0x2b, 0x00, 0xa9, 0x16, + 0x3d, 0x84, 0x72, 0xd7, 0x60, 0x24, 0x88, 0x5f, 0xe1, 0x77, 0xde, 0x86, 0xc1, 0x99, 0x60, 0x19, + 0x80, 0x1e, 0xc3, 0xd2, 0x39, 0x0d, 0x98, 0xc7, 0xd7, 0x5f, 0xf8, 0x7f, 0xb1, 0x71, 0x44, 0xe3, + 0x21, 0x7c, 0x50, 0xb0, 0xa1, 0xd5, 0xf4, 0xd4, 0xe4, 0x87, 0x63, 0xda, 0x22, 0xf3, 0xd9, 0x16, + 0x69, 0x30, 0xa8, 0x9c, 0xd1, 0x8e, 0x6b, 0xb0, 0xd0, 0x27, 0xe8, 0x3e, 0x2c, 0x04, 0xb4, 0x23, + 0xbb, 0x7d, 0x7d, 0x34, 0x54, 0x6f, 0x88, 0x5a, 0x07, 0xb4, 0x13, 0xd7, 0x38, 0xfa, 0xc4, 0x91, + 0x57, 0xb4, 0xf9, 0xbd, 0xd0, 0xe4, 0xe3, 0x31, 0x76, 0xdc, 0x4a, 0x43, 0x1c, 0x14, 0x8b, 0xb8, + 0xdc, 0x0b, 0xcd, 0xa7, 0x64, 0xd0, 0xd8, 0x87, 0xea, 0x11, 0xdf, 0x9a, 0x67, 0x21, 0x09, 0xc9, + 0x18, 0xd9, 0x35, 0x58, 0xec, 0x1b, 0xdd, 0x90, 0xf0, 0x52, 0x54, 0xb0, 0x10, 0x1a, 0x77, 0xa1, + 0x2a, 0x32, 0x0c, 0xbe, 0xa0, 0x01, 0x4b, 0x9d, 0x94, 0x8c, 0x53, 0xeb, 0xe0, 0xf5, 0x65, 0x5d, + 0x79, 0x73, 0x59, 0x57, 0xfe, 0xb9, 0xac, 0x2b, 0x17, 0x57, 0xf5, 0xb9, 0x37, 0x57, 0xf5, 0xb9, + 0x3f, 0xaf, 0xea, 0x73, 0xdf, 0x6c, 0x77, 0x28, 0xd3, 0xfa, 0xb6, 0xa9, 0x31, 0x4f, 0x8f, 0x4a, + 0xbb, 0x4b, 0x3d, 0xbd, 0x6b, 0x58, 0x9e, 0x4b, 0xad, 0x3d, 0x5b, 0x7f, 0x99, 0xfc, 0xea, 0x99, + 0x65, 0xde, 0x7c, 0xfb, 0xff, 0x05, 0x00, 0x00, 0xff, 0xff, 0xfb, 0x80, 0xc8, 0x98, 0x0e, 0x0e, + 0x00, 0x00, } func (m *Params) Marshal() (dAtA []byte, err error) { @@ -1305,6 +1353,38 @@ func (m *ExpiryQueue) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *RecordsList) 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 *RecordsList) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RecordsList) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Value) > 0 { + for iNdEx := len(m.Value) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Value[iNdEx]) + copy(dAtA[i:], m.Value[iNdEx]) + i = encodeVarintRegistry(dAtA, i, uint64(len(m.Value[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + func encodeVarintRegistry(dAtA []byte, offset int, v uint64) int { offset -= sovRegistry(v) base := offset @@ -1535,6 +1615,21 @@ func (m *ExpiryQueue) Size() (n int) { return n } +func (m *RecordsList) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Value) > 0 { + for _, s := range m.Value { + l = len(s) + n += 1 + l + sovRegistry(uint64(l)) + } + } + return n +} + func sovRegistry(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -3216,6 +3311,88 @@ func (m *ExpiryQueue) Unmarshal(dAtA []byte) error { } return nil } +func (m *RecordsList) 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 ErrIntOverflowRegistry + } + 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: RecordsList: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RecordsList: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRegistry + } + 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 ErrInvalidLengthRegistry + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRegistry + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Value = append(m.Value, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipRegistry(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthRegistry + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipRegistry(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0