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: deep-stack/laconic2d#11
Co-authored-by: Prathamesh Musale <prathamesh.musale0@gmail.com>
Co-committed-by: Prathamesh Musale <prathamesh.musale0@gmail.com>
This commit is contained in:
Prathamesh Musale 2024-02-29 11:54:35 +00:00 committed by ashwin
parent d2505367aa
commit 0af44b5f17
26 changed files with 2326 additions and 129 deletions

View File

@ -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

View File

@ -81,3 +81,10 @@ lint-fix:
@$(golangci_lint_cmd) run ./... --fix --timeout 15m @$(golangci_lint_cmd) run ./... --fix --timeout 15m
.PHONY: lint lint-fix .PHONY: lint lint-fix
#################
### Tests ###
#################
test-integration:
$(MAKE) -C tests test-integration

View File

@ -12,3 +12,9 @@ Install and run `laconic2d`:
# start the chain # start the chain
laconic2d start laconic2d start
``` ```
Run tests:
```bash
make test-integration
```

View File

@ -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. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.27.0 // protoc-gen-go v1.27.0
@ -6712,6 +7192,43 @@ func (x *ExpiryQueue) GetValue() []string {
return nil 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 protoreflect.FileDescriptor
var file_cerc_registry_v1_registry_proto_rawDesc = []byte{ 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, 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, 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, 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, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x23,
0x01, 0x0a, 0x14, 0x63, 0x6f, 0x6d, 0x2e, 0x63, 0x65, 0x72, 0x63, 0x2e, 0x72, 0x65, 0x67, 0x69, 0x0a, 0x0b, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x14, 0x0a,
0x73, 0x74, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x42, 0x0d, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61,
0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3c, 0x67, 0x69, 0x74, 0x2e, 0x76, 0x64, 0x6c, 0x75, 0x65, 0x42, 0xc5, 0x01, 0x0a, 0x14, 0x63, 0x6f, 0x6d, 0x2e, 0x63, 0x65, 0x72, 0x63,
0x62, 0x2e, 0x74, 0x6f, 0x2f, 0x63, 0x65, 0x72, 0x63, 0x2d, 0x69, 0x6f, 0x2f, 0x6c, 0x61, 0x63, 0x2e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x42, 0x0d, 0x52, 0x65,
0x6f, 0x6e, 0x69, 0x63, 0x32, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x65, 0x72, 0x63, 0x2f, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3c, 0x67,
0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2f, 0x76, 0x31, 0x3b, 0x72, 0x65, 0x67, 0x69, 0x69, 0x74, 0x2e, 0x76, 0x64, 0x62, 0x2e, 0x74, 0x6f, 0x2f, 0x63, 0x65, 0x72, 0x63, 0x2d, 0x69,
0x73, 0x74, 0x72, 0x79, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x43, 0x52, 0x58, 0xaa, 0x02, 0x10, 0x43, 0x6f, 0x2f, 0x6c, 0x61, 0x63, 0x6f, 0x6e, 0x69, 0x63, 0x32, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f,
0x65, 0x72, 0x63, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x56, 0x31, 0xca, 0x63, 0x65, 0x72, 0x63, 0x2f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2f, 0x76, 0x31,
0x02, 0x10, 0x43, 0x65, 0x72, 0x63, 0x5c, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x5c, 0x3b, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x43, 0x52,
0x56, 0x31, 0xe2, 0x02, 0x1c, 0x43, 0x65, 0x72, 0x63, 0x5c, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x58, 0xaa, 0x02, 0x10, 0x43, 0x65, 0x72, 0x63, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72,
0x72, 0x79, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x79, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x10, 0x43, 0x65, 0x72, 0x63, 0x5c, 0x52, 0x65, 0x67, 0x69,
0x61, 0xea, 0x02, 0x12, 0x43, 0x65, 0x72, 0x63, 0x3a, 0x3a, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x73, 0x74, 0x72, 0x79, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x1c, 0x43, 0x65, 0x72, 0x63, 0x5c, 0x52,
0x72, 0x79, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 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 ( var (
@ -6960,7 +7480,7 @@ func file_cerc_registry_v1_registry_proto_rawDescGZIP() []byte {
return file_cerc_registry_v1_registry_proto_rawDescData 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{}{ var file_cerc_registry_v1_registry_proto_goTypes = []interface{}{
(*Params)(nil), // 0: cerc.registry.v1.Params (*Params)(nil), // 0: cerc.registry.v1.Params
(*Record)(nil), // 1: cerc.registry.v1.Record (*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 (*NameRecordEntry)(nil), // 6: cerc.registry.v1.NameRecordEntry
(*Signature)(nil), // 7: cerc.registry.v1.Signature (*Signature)(nil), // 7: cerc.registry.v1.Signature
(*ExpiryQueue)(nil), // 8: cerc.registry.v1.ExpiryQueue (*ExpiryQueue)(nil), // 8: cerc.registry.v1.ExpiryQueue
(*v1beta1.Coin)(nil), // 9: cosmos.base.v1beta1.Coin (*RecordsList)(nil), // 9: cerc.registry.v1.RecordsList
(*durationpb.Duration)(nil), // 10: google.protobuf.Duration (*v1beta1.Coin)(nil), // 10: cosmos.base.v1beta1.Coin
(*timestamppb.Timestamp)(nil), // 11: google.protobuf.Timestamp (*durationpb.Duration)(nil), // 11: google.protobuf.Duration
(*timestamppb.Timestamp)(nil), // 12: google.protobuf.Timestamp
} }
var file_cerc_registry_v1_registry_proto_depIdxs = []int32{ var file_cerc_registry_v1_registry_proto_depIdxs = []int32{
9, // 0: cerc.registry.v1.Params.record_rent:type_name -> cosmos.base.v1beta1.Coin 10, // 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 11, // 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, // 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 11, // 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 11, // 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 11, // 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 11, // 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 10, // 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 10, // 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, // 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 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 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, // 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 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 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{} type x struct{}
out := protoimpl.TypeBuilder{ out := protoimpl.TypeBuilder{
@ -7119,7 +7652,7 @@ func file_cerc_registry_v1_registry_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_cerc_registry_v1_registry_proto_rawDesc, RawDescriptor: file_cerc_registry_v1_registry_proto_rawDesc,
NumEnums: 0, NumEnums: 0,
NumMessages: 9, NumMessages: 10,
NumExtensions: 0, NumExtensions: 0,
NumServices: 0, NumServices: 0,
}, },

View File

@ -79,7 +79,6 @@ type LaconicApp struct {
AuctionKeeper *auctionkeeper.Keeper // (Use * as per ProvideModule implementation) AuctionKeeper *auctionkeeper.Keeper // (Use * as per ProvideModule implementation)
BondKeeper *bondkeeper.Keeper BondKeeper *bondkeeper.Keeper
RegistryKeeper registrykeeper.Keeper RegistryKeeper registrykeeper.Keeper
// RegistryRecordKeeper registrykeeper.RecordKeeper
// simulation manager // simulation manager
sm *module.SimulationManager sm *module.SimulationManager
@ -141,7 +140,6 @@ func NewLaconicApp(
&app.ConsensusParamsKeeper, &app.ConsensusParamsKeeper,
&app.AuctionKeeper, &app.AuctionKeeper,
&app.BondKeeper, &app.BondKeeper,
// &app.RegistryRecordKeeper,
&app.RegistryKeeper, &app.RegistryKeeper,
); err != nil { ); err != nil {
return nil, err return nil, err

View File

@ -106,7 +106,7 @@ func NewRootCmd() *cobra.Command {
// overwrite the block timeout // overwrite the block timeout
cmtCfg := cmtcfg.DefaultConfig() cmtCfg := cmtcfg.DefaultConfig()
cmtCfg.Consensus.TimeoutCommit = 3 * time.Second 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) return server.InterceptConfigsPreRunHandler(cmd, serverconfig.DefaultConfigTemplate, srvCfg, cmtCfg)
}, },

2
go.mod
View File

@ -37,6 +37,7 @@ require (
github.com/ipld/go-ipld-prime v0.21.0 github.com/ipld/go-ipld-prime v0.21.0
github.com/spf13/cobra v1.8.0 github.com/spf13/cobra v1.8.0
github.com/spf13/viper v1.17.0 github.com/spf13/viper v1.17.0
github.com/stretchr/testify v1.8.4
golang.org/x/exp v0.0.0-20231006140011-7918f672742d golang.org/x/exp v0.0.0-20231006140011-7918f672742d
google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f
google.golang.org/grpc v1.60.1 google.golang.org/grpc v1.60.1
@ -160,7 +161,6 @@ require (
github.com/spf13/afero v1.10.0 // indirect github.com/spf13/afero v1.10.0 // indirect
github.com/spf13/cast v1.5.1 // indirect github.com/spf13/cast v1.5.1 // indirect
github.com/spf13/pflag v1.0.5 // 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/subosito/gotenv v1.6.0 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect
github.com/tendermint/go-amino v0.16.0 // indirect github.com/tendermint/go-amino v0.16.0 // indirect

View File

@ -138,3 +138,9 @@ message ExpiryQueue {
string id = 1; string id = 1;
repeated string value = 2; repeated string value = 2;
} }
// List of record ids
// Value type to be used in AttributesMap
message RecordsList {
repeated string value = 1;
}

View File

@ -3,7 +3,6 @@
rm -r ~/.laconic2d || true rm -r ~/.laconic2d || true
LACONIC2D_BIN=$(which laconic2d) LACONIC2D_BIN=$(which laconic2d)
# configure 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 chain-id demo
$LACONIC2D_BIN config set client keyring-backend test $LACONIC2D_BIN config set client keyring-backend test
$LACONIC2D_BIN keys add alice $LACONIC2D_BIN keys add alice

2
tests/Makefile Normal file
View File

@ -0,0 +1,2 @@
test-integration:
go test -mod=readonly ./integration/... -test.v -timeout 10m

View File

@ -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))
}

View File

@ -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
}

View File

@ -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))
}

View File

@ -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
}

157
tests/integration/common.go Normal file
View File

@ -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
}

View File

@ -0,0 +1,7 @@
record:
attr1: value1
attr2: value2
link1:
/: QmSnuWmxptJZdLJpKRarxBMS2Ju2oANVrgbr2xWbie9b2D
link2:
/: QmP8jTG1m9GSDJLCbeWhVSVgEzCPPwXRdCRuJtQ5Tz9Kc9

View File

@ -0,0 +1,7 @@
record:
type: GeneralRecord
name: foo
version: 1.0.0
tags:
- tagA
- tagB

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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)
}
}
})
}
}

View File

@ -5,6 +5,9 @@ import "cosmossdk.io/collections"
const ( const (
ModuleName = "auction" ModuleName = "auction"
// StoreKey defines the primary module store key
StoreKey = ModuleName
// AuctionBurnModuleAccountName is the name of the auction burn module account. // AuctionBurnModuleAccountName is the name of the auction burn module account.
AuctionBurnModuleAccountName = "auction_burn" AuctionBurnModuleAccountName = "auction_burn"
) )

View File

@ -4,6 +4,9 @@ import "cosmossdk.io/collections"
const ( const (
ModuleName = "bond" ModuleName = "bond"
// StoreKey defines the primary module store key
StoreKey = ModuleName
) )
// Store prefixes // Store prefixes

View File

@ -19,8 +19,10 @@ import (
auth "github.com/cosmos/cosmos-sdk/x/auth/keeper" auth "github.com/cosmos/cosmos-sdk/x/auth/keeper"
bank "github.com/cosmos/cosmos-sdk/x/bank/keeper" bank "github.com/cosmos/cosmos-sdk/x/bank/keeper"
"github.com/gibson042/canonicaljson-go" "github.com/gibson042/canonicaljson-go"
cid "github.com/ipfs/go-cid"
"github.com/ipld/go-ipld-prime" "github.com/ipld/go-ipld-prime"
"github.com/ipld/go-ipld-prime/codec/dagjson" "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" "github.com/ipld/go-ipld-prime/node/basicnode"
auctionkeeper "git.vdb.to/cerc-io/laconic2d/x/auction/keeper" auctionkeeper "git.vdb.to/cerc-io/laconic2d/x/auction/keeper"
@ -105,6 +107,7 @@ type Keeper struct {
NameRecords *collections.IndexedMap[string, registrytypes.NameRecord, NameRecordsIndexes] NameRecords *collections.IndexedMap[string, registrytypes.NameRecord, NameRecordsIndexes]
RecordExpiryQueue collections.Map[time.Time, registrytypes.ExpiryQueue] RecordExpiryQueue collections.Map[time.Time, registrytypes.ExpiryQueue]
AuthorityExpiryQueue 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 // NewKeeper creates a new Keeper instance
@ -147,6 +150,10 @@ func NewKeeper(
sb, registrytypes.AuthorityExpiryQueuePrefix, "authority_expiry_queue", sb, registrytypes.AuthorityExpiryQueuePrefix, "authority_expiry_queue",
sdk.TimeKey, codec.CollValue[registrytypes.ExpiryQueue](cdc), 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() 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 // 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) { 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. // 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 // 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 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) 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 np := basicnode.Prototype.Map
nb := np.NewBuilder() nb := np.NewBuilder()
encAttrs, err := canonicaljson.Marshal(attrs) 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 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 { 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 { if err := dagjson.Encode(valuenode, &buf); err != nil {
return err return err
} }
// TODO
// value := buf.Bytes() value := buf.Bytes()
// indexKey := GetAttributesIndexKey(prefix+key, value) mapKey := collections.Join(prefix+key, string(value))
// if err := k.SetAttributeMapping(ctx, indexKey, id); err != nil { if err := k.setAttributeMapping(ctx, mapKey, id); err != nil {
// return err return err
// } }
} }
} }
return nil 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 { func (k Keeper) populateRecordNames(ctx sdk.Context, record *registrytypes.Record) error {
iter, err := k.NameRecords.Indexes.Cid.MatchExact(ctx, record.Id) iter, err := k.NameRecords.Indexes.Cid.MatchExact(ctx, record.Id)
if err != nil { if err != nil {
@ -571,3 +693,30 @@ func (k Keeper) tryTakeRecordRent(ctx sdk.Context, record registrytypes.Record)
record.Deleted = false record.Deleted = false
return k.SaveRecord(ctx, record) 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
}

View File

@ -6,6 +6,9 @@ const (
// ModuleName is the name of the registry module // ModuleName is the name of the registry module
ModuleName = "registry" 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 is the name of the module account that keeps track of record rents paid.
RecordRentModuleAccountName = "record_rent" RecordRentModuleAccountName = "record_rent"
@ -30,4 +33,6 @@ var (
RecordExpiryQueuePrefix = collections.NewPrefix(8) RecordExpiryQueuePrefix = collections.NewPrefix(8)
AuthorityExpiryQueuePrefix = collections.NewPrefix(9) AuthorityExpiryQueuePrefix = collections.NewPrefix(9)
AttributesMapPrefix = collections.NewPrefix(10)
) )

View File

@ -679,6 +679,52 @@ func (m *ExpiryQueue) GetValue() []string {
return nil 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() { func init() {
proto.RegisterType((*Params)(nil), "cerc.registry.v1.Params") proto.RegisterType((*Params)(nil), "cerc.registry.v1.Params")
proto.RegisterType((*Record)(nil), "cerc.registry.v1.Record") proto.RegisterType((*Record)(nil), "cerc.registry.v1.Record")
@ -689,89 +735,91 @@ func init() {
proto.RegisterType((*NameRecordEntry)(nil), "cerc.registry.v1.NameRecordEntry") proto.RegisterType((*NameRecordEntry)(nil), "cerc.registry.v1.NameRecordEntry")
proto.RegisterType((*Signature)(nil), "cerc.registry.v1.Signature") proto.RegisterType((*Signature)(nil), "cerc.registry.v1.Signature")
proto.RegisterType((*ExpiryQueue)(nil), "cerc.registry.v1.ExpiryQueue") 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) } func init() { proto.RegisterFile("cerc/registry/v1/registry.proto", fileDescriptor_d792f2373089b5b9) }
var fileDescriptor_d792f2373089b5b9 = []byte{ var fileDescriptor_d792f2373089b5b9 = []byte{
// 1221 bytes of a gzipped FileDescriptorProto // 1234 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x57, 0xcb, 0x6e, 0xdb, 0x46, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x57, 0xcd, 0x6e, 0xdb, 0x46,
0x17, 0x36, 0x6d, 0x59, 0xb6, 0x8e, 0x63, 0xff, 0xc1, 0xfc, 0x4e, 0x22, 0xbb, 0xb1, 0xe8, 0xa8, 0x10, 0x36, 0x6d, 0x59, 0xb6, 0x46, 0xb1, 0x1b, 0x6c, 0x9d, 0x44, 0x76, 0x63, 0xd1, 0x51, 0x50,
0x28, 0xec, 0x20, 0x30, 0x09, 0xd9, 0x28, 0x82, 0x24, 0xe8, 0xc2, 0x72, 0x1d, 0xc3, 0x0d, 0xda, 0xd8, 0x41, 0x60, 0x12, 0xb2, 0x51, 0x04, 0x49, 0xd0, 0x83, 0xe5, 0x3a, 0x86, 0x9b, 0xfe, 0x38,
0x3a, 0xe3, 0xac, 0x5a, 0x14, 0x02, 0x2f, 0x13, 0x79, 0x5a, 0x91, 0x14, 0xc8, 0xa1, 0x1a, 0x2d, 0xeb, 0x9c, 0x5a, 0x14, 0x02, 0x7f, 0x36, 0xf2, 0xb6, 0x22, 0x29, 0x90, 0x4b, 0x35, 0x3a, 0x16,
0x0b, 0x74, 0xd3, 0x9d, 0x97, 0x59, 0xf4, 0x0d, 0xba, 0xe8, 0x63, 0x34, 0xcb, 0x2c, 0xbb, 0x29, 0xe8, 0xa5, 0x37, 0x1f, 0x73, 0xe8, 0x1b, 0xf4, 0xd0, 0xc7, 0x68, 0x8e, 0x39, 0xf6, 0x52, 0xb5,
0x5b, 0xd8, 0x40, 0x1f, 0x40, 0x4f, 0x50, 0x70, 0x66, 0x78, 0x95, 0x14, 0xb5, 0xc8, 0x8e, 0xe7, 0xb0, 0x81, 0x3e, 0x80, 0x9e, 0xa0, 0xe0, 0xee, 0xf2, 0x57, 0x52, 0xd4, 0x20, 0x37, 0xce, 0xdf,
0xf6, 0xcd, 0x37, 0xdf, 0x9c, 0xb9, 0x10, 0x54, 0x8b, 0xf8, 0x96, 0xee, 0x93, 0x2e, 0x0d, 0x98, 0xb7, 0xdf, 0xcc, 0xce, 0xec, 0x2e, 0x41, 0xb5, 0x88, 0x6f, 0xe9, 0x3e, 0xe9, 0xd0, 0x80, 0xf9,
0x3f, 0xd4, 0x07, 0xad, 0xf4, 0x5b, 0xeb, 0xfb, 0x1e, 0xf3, 0xd0, 0xcd, 0x38, 0x41, 0x4b, 0x9d, 0x03, 0xbd, 0xdf, 0x4c, 0xbe, 0xb5, 0x9e, 0xef, 0x31, 0x0f, 0x5d, 0x8f, 0x1c, 0xb4, 0x44, 0xd9,
0x83, 0xd6, 0x66, 0xa3, 0xeb, 0x79, 0xdd, 0x1e, 0xd1, 0x79, 0xdc, 0x0c, 0x5f, 0xea, 0x76, 0xe8, 0x6f, 0x6e, 0xd4, 0x3b, 0x9e, 0xd7, 0xe9, 0x12, 0x9d, 0xdb, 0xcd, 0xf0, 0x85, 0x6e, 0x87, 0xbe,
0x1b, 0x8c, 0x7a, 0xae, 0xa8, 0xd8, 0x54, 0xcb, 0x71, 0x46, 0x1d, 0x12, 0x30, 0xc3, 0xe9, 0xcb, 0xc1, 0xa8, 0xe7, 0x8a, 0x88, 0x0d, 0xb5, 0x68, 0x67, 0xd4, 0x21, 0x01, 0x33, 0x9c, 0x9e, 0x74,
0x84, 0xf5, 0xae, 0xd7, 0xf5, 0xf8, 0xa7, 0x1e, 0x7f, 0x49, 0x6f, 0xc3, 0xf2, 0x02, 0xc7, 0x0b, 0x58, 0xeb, 0x78, 0x1d, 0x8f, 0x7f, 0xea, 0xd1, 0x97, 0xd4, 0xd6, 0x2d, 0x2f, 0x70, 0xbc, 0x40,
0x74, 0xd3, 0x08, 0x88, 0x3e, 0x68, 0x99, 0x84, 0x19, 0x2d, 0xdd, 0xf2, 0xa8, 0x84, 0x6d, 0xfe, 0x37, 0x8d, 0x80, 0xe8, 0xfd, 0xa6, 0x49, 0x98, 0xd1, 0xd4, 0x2d, 0x8f, 0x4a, 0xd8, 0xc6, 0x5f,
0xb1, 0x0a, 0xd5, 0x33, 0xc3, 0x37, 0x9c, 0x00, 0x51, 0x58, 0xf1, 0x89, 0xe5, 0xf9, 0x76, 0xc7, 0x2b, 0x50, 0x3e, 0x35, 0x7c, 0xc3, 0x09, 0x10, 0x85, 0xaa, 0x4f, 0x2c, 0xcf, 0xb7, 0xdb, 0x3e,
0x27, 0x2e, 0xab, 0x2b, 0xdb, 0xca, 0xee, 0xca, 0xfe, 0x86, 0x26, 0x00, 0xb4, 0x18, 0x40, 0x93, 0x71, 0x59, 0x4d, 0xd9, 0x52, 0x76, 0xaa, 0x7b, 0xeb, 0x9a, 0x00, 0xd0, 0x22, 0x00, 0x4d, 0x02,
0x00, 0xda, 0x91, 0x47, 0xdd, 0xf6, 0xde, 0x9b, 0x48, 0x9d, 0x1b, 0x45, 0xea, 0x47, 0xdf, 0x06, 0x68, 0x87, 0x1e, 0x75, 0x5b, 0xbb, 0xaf, 0x87, 0xea, 0xdc, 0x68, 0xa8, 0x7e, 0xfc, 0x7d, 0xe0,
0x9e, 0xfb, 0xb8, 0x99, 0xab, 0x6d, 0x6e, 0x0f, 0x0d, 0xa7, 0x57, 0x74, 0x61, 0x10, 0x16, 0x26, 0xb9, 0x8f, 0x1a, 0x99, 0xd8, 0xc6, 0xd6, 0xc0, 0x70, 0xba, 0x79, 0x15, 0x06, 0x21, 0x61, 0xe2,
0x2e, 0x43, 0x97, 0x0a, 0xac, 0xe7, 0x82, 0x9d, 0x64, 0xae, 0xf5, 0x79, 0x39, 0xa8, 0x98, 0xac, 0x32, 0x74, 0xa1, 0xc0, 0x5a, 0xc6, 0xd8, 0x8e, 0x73, 0xad, 0xcd, 0xcb, 0x45, 0x45, 0xb2, 0x5a,
0x96, 0x4c, 0x56, 0xfb, 0x54, 0x26, 0xb4, 0x8f, 0xe4, 0xa0, 0x0f, 0xc7, 0x06, 0x4d, 0x41, 0x26, 0x9c, 0xac, 0xf6, 0x99, 0x74, 0x68, 0x1d, 0xca, 0x45, 0x1f, 0x8c, 0x2d, 0x9a, 0x80, 0x4c, 0x58,
0x8c, 0x9e, 0xc5, 0x5e, 0xff, 0xa9, 0x2a, 0x18, 0x65, 0x54, 0x12, 0x60, 0x14, 0xc2, 0x9a, 0x11, 0x3d, 0xb5, 0xbd, 0xfa, 0x5b, 0x55, 0x30, 0x4a, 0xa9, 0xc4, 0xc0, 0x28, 0x84, 0x55, 0x23, 0x64,
0xb2, 0x0b, 0xcf, 0xa7, 0x6c, 0x28, 0x04, 0x58, 0x98, 0x25, 0xc0, 0x81, 0xe4, 0xf2, 0x40, 0x70, 0xe7, 0x9e, 0x4f, 0xd9, 0x40, 0x14, 0x60, 0x61, 0x56, 0x01, 0xf6, 0x25, 0x97, 0xfb, 0x82, 0x4b,
0x29, 0x96, 0x27, 0x2c, 0x4a, 0x5e, 0xbc, 0x9a, 0x3a, 0xb8, 0x12, 0x3f, 0x2b, 0x70, 0xa7, 0x98, 0x3e, 0x3c, 0x66, 0x51, 0xd0, 0xe2, 0x95, 0x44, 0xc1, 0x2b, 0xf1, 0xab, 0x02, 0xb7, 0xf2, 0x2e,
0x92, 0x89, 0x51, 0x99, 0x25, 0xc6, 0xa9, 0x24, 0xf0, 0xc9, 0x24, 0x02, 0x63, 0x7a, 0x4c, 0x0b, 0x69, 0x31, 0x4a, 0xb3, 0x8a, 0x71, 0x22, 0x09, 0x7c, 0x3a, 0x89, 0xc0, 0x58, 0x3d, 0xa6, 0x99,
0x73, 0x49, 0x6e, 0x15, 0x68, 0xa5, 0xaa, 0xbc, 0x56, 0xe0, 0x76, 0x56, 0xd7, 0xf5, 0x0d, 0x8b, 0x79, 0x49, 0x6e, 0xe4, 0x68, 0x25, 0x55, 0x79, 0xa5, 0xc0, 0xcd, 0x34, 0xae, 0xe3, 0x1b, 0x16,
0x74, 0xfa, 0xc4, 0xa7, 0x9e, 0x5d, 0x5f, 0x9c, 0xc5, 0xee, 0x44, 0xb2, 0x7b, 0x52, 0x66, 0x97, 0x69, 0xf7, 0x88, 0x4f, 0x3d, 0xbb, 0xb6, 0x38, 0x8b, 0xdd, 0xb1, 0x64, 0xf7, 0xb8, 0xc8, 0x2e,
0x87, 0x19, 0x27, 0x57, 0x88, 0x72, 0x6e, 0xeb, 0x69, 0xf0, 0x24, 0x8e, 0x9d, 0xf1, 0x10, 0xfa, 0x0b, 0x33, 0x4e, 0x2e, 0x67, 0xe5, 0xdc, 0xd6, 0x12, 0xe3, 0x71, 0x64, 0x3b, 0xe5, 0x26, 0xf4,
0x41, 0x81, 0x8d, 0xac, 0xca, 0x08, 0xad, 0x78, 0xd0, 0x0e, 0x71, 0x0d, 0xb3, 0x47, 0xec, 0x7a, 0x93, 0x02, 0xeb, 0x69, 0x94, 0x11, 0x5a, 0xd1, 0xa2, 0x6d, 0xe2, 0x1a, 0x66, 0x97, 0xd8, 0xb5,
0x75, 0x5b, 0xd9, 0x5d, 0x6e, 0x1f, 0x8f, 0x22, 0xf5, 0xb0, 0x3c, 0x7c, 0x29, 0x75, 0x9c, 0x41, 0xf2, 0x96, 0xb2, 0xb3, 0xdc, 0x3a, 0x1a, 0x0d, 0xd5, 0x83, 0xe2, 0xf2, 0x05, 0xd7, 0x71, 0x06,
0x39, 0x01, 0x67, 0x2b, 0x74, 0x28, 0x42, 0xc7, 0x22, 0x82, 0x7e, 0x53, 0x60, 0x42, 0x9d, 0xe5, 0x45, 0x07, 0x9c, 0xee, 0xd0, 0x81, 0x30, 0x1d, 0x09, 0x0b, 0xfa, 0x43, 0x81, 0x09, 0x71, 0x96,
0x39, 0x0e, 0x65, 0x41, 0xb6, 0x90, 0x4b, 0xb3, 0xa4, 0xea, 0x48, 0xa9, 0xce, 0xa7, 0x71, 0x2d, 0xe7, 0x38, 0x94, 0x05, 0xe9, 0x46, 0x2e, 0xcd, 0x2a, 0x55, 0x5b, 0x96, 0xea, 0x6c, 0x1a, 0xd7,
0x43, 0x4e, 0x27, 0x3d, 0x96, 0xc9, 0x25, 0x54, 0xcb, 0x33, 0x38, 0x12, 0x69, 0xe9, 0x42, 0x4f, 0x22, 0xe4, 0x74, 0xd2, 0x63, 0x9e, 0xbc, 0x84, 0x6a, 0x31, 0x83, 0x43, 0xe1, 0x96, 0x6c, 0xf4,
0x9e, 0x89, 0x4f, 0x06, 0xc4, 0xe8, 0xe5, 0x66, 0xb2, 0xfc, 0xde, 0x33, 0x29, 0x43, 0x4e, 0x9f, 0xe4, 0x4c, 0x7c, 0xd2, 0x27, 0x46, 0x37, 0x93, 0xc9, 0xf2, 0x7b, 0x67, 0x52, 0x84, 0x9c, 0x9e,
0xc9, 0x58, 0xe6, 0xe4, 0x99, 0x60, 0x91, 0x96, 0xce, 0xe4, 0x17, 0x05, 0xee, 0x4e, 0x93, 0xa5, 0xc9, 0x98, 0xe7, 0xe4, 0x4c, 0xb0, 0x70, 0x4b, 0x32, 0xf9, 0x4d, 0x81, 0xdb, 0xd3, 0xca, 0xd2,
0xf3, 0x92, 0x90, 0x7a, 0x6d, 0xd6, 0xbe, 0xfe, 0x52, 0xce, 0xe1, 0xe4, 0xdd, 0xab, 0x11, 0x83, 0x7e, 0x41, 0x48, 0xad, 0x32, 0x6b, 0xae, 0xbf, 0x96, 0x39, 0x1c, 0xbf, 0x7d, 0x37, 0x22, 0xb0,
0xcd, 0x5a, 0x07, 0x9e, 0x83, 0x37, 0x26, 0xab, 0xff, 0x94, 0x90, 0x29, 0x6c, 0xc5, 0xd4, 0x39, 0x59, 0xfb, 0xc0, 0x7d, 0xf0, 0xfa, 0xe4, 0xea, 0x3f, 0x21, 0x64, 0x0a, 0x5b, 0x91, 0x3a, 0x67,
0x5b, 0x78, 0x6f, 0xb6, 0x19, 0xd8, 0x2c, 0xad, 0xa7, 0xb0, 0x15, 0x0a, 0xc7, 0x6c, 0x7f, 0x55, 0x0b, 0xef, 0xcd, 0x36, 0x05, 0x9b, 0x55, 0xeb, 0x29, 0x6c, 0x45, 0x85, 0x23, 0xb6, 0xbf, 0x2b,
0x60, 0x6b, 0xbc, 0xd8, 0xa1, 0x2e, 0x75, 0x42, 0xa7, 0x63, 0x52, 0xbb, 0xbe, 0x32, 0x8b, 0xee, 0xb0, 0x39, 0x1e, 0xec, 0x50, 0x97, 0x3a, 0xa1, 0xd3, 0x36, 0xa9, 0x5d, 0xab, 0xce, 0xa2, 0xfb,
0x73, 0x49, 0xf7, 0x74, 0x1a, 0xdd, 0x1c, 0xda, 0x74, 0xbe, 0xf9, 0x24, 0xbc, 0x59, 0x26, 0xfc, 0x4c, 0xd2, 0x3d, 0x99, 0x46, 0x37, 0x83, 0x36, 0x9d, 0x6f, 0xd6, 0x09, 0x6f, 0x14, 0x09, 0x7f,
0xb9, 0x88, 0xb6, 0xa9, 0xdd, 0xfc, 0xa9, 0x02, 0x55, 0xcc, 0x4f, 0x7b, 0xb4, 0x03, 0xf3, 0xd4, 0x29, 0xac, 0x2d, 0x6a, 0x37, 0x7e, 0x29, 0x41, 0x19, 0xf3, 0xd3, 0x1e, 0x6d, 0xc3, 0x3c, 0xb5,
0xe6, 0xd7, 0x5a, 0xad, 0x7d, 0x67, 0x14, 0xa9, 0xff, 0x17, 0x0c, 0xb2, 0x61, 0x62, 0xac, 0x79, 0xf9, 0xb5, 0x56, 0x69, 0xdd, 0x1a, 0x0d, 0xd5, 0x0f, 0x05, 0x83, 0x74, 0x99, 0x08, 0x6b, 0x9e,
0x6a, 0xa3, 0xc7, 0xb0, 0x64, 0x7a, 0xae, 0xdd, 0xa1, 0x36, 0xbf, 0x8f, 0x6a, 0xed, 0x7b, 0xa3, 0xda, 0xe8, 0x11, 0x2c, 0x99, 0x9e, 0x6b, 0xb7, 0xa9, 0xcd, 0xef, 0xa3, 0x4a, 0xeb, 0xce, 0x68,
0x48, 0xdd, 0x12, 0xd9, 0x32, 0x90, 0x94, 0x24, 0x26, 0xae, 0xc6, 0x5f, 0xa7, 0x36, 0xfa, 0x0c, 0xa8, 0x6e, 0x0a, 0x6f, 0x69, 0x88, 0x43, 0x62, 0x11, 0x97, 0xa3, 0xaf, 0x13, 0x1b, 0x7d, 0x0e,
0x56, 0x2c, 0x9f, 0x18, 0x8c, 0x74, 0xe2, 0xfb, 0x99, 0xdf, 0x21, 0xb5, 0xf6, 0xfd, 0xec, 0x96, 0x55, 0xcb, 0x27, 0x06, 0x23, 0xed, 0xe8, 0x7e, 0xe6, 0x77, 0x48, 0xa5, 0x75, 0x2f, 0xbd, 0x25,
0xcc, 0x05, 0x13, 0x8c, 0xbc, 0x0b, 0x83, 0xb0, 0x5e, 0x50, 0x87, 0xc4, 0x58, 0xe4, 0x55, 0x9f, 0x33, 0xc6, 0x18, 0x23, 0xab, 0xc2, 0x20, 0xa4, 0xe7, 0xd4, 0x21, 0x11, 0x16, 0x79, 0xd9, 0xa3,
0xfa, 0x43, 0x81, 0x55, 0x29, 0x63, 0xe5, 0x82, 0x09, 0x56, 0xde, 0x85, 0x41, 0x58, 0x1c, 0xab, 0xfe, 0x40, 0x60, 0x95, 0x8a, 0x58, 0x19, 0x63, 0x8c, 0x95, 0x55, 0x61, 0x10, 0x12, 0xc7, 0xaa,
0x0e, 0x4b, 0x36, 0xe9, 0x11, 0x46, 0xc4, 0xc1, 0xbd, 0x8c, 0x13, 0x13, 0x3d, 0x84, 0xaa, 0xf7, 0xc1, 0x92, 0x4d, 0xba, 0x84, 0x11, 0x71, 0x70, 0x2f, 0xe3, 0x58, 0x44, 0x0f, 0xa0, 0xec, 0xfd,
0xbd, 0x4b, 0xfc, 0xa0, 0x5e, 0xdd, 0x5e, 0xd8, 0xad, 0xb5, 0xd5, 0x51, 0xa4, 0x7e, 0x20, 0x06, 0xe8, 0x12, 0x3f, 0xa8, 0x95, 0xb7, 0x16, 0x76, 0x2a, 0x2d, 0x75, 0x34, 0x54, 0x3f, 0x12, 0x0b,
0x10, 0xfe, 0x04, 0x5b, 0x5a, 0x58, 0xa6, 0xa3, 0x13, 0x00, 0x83, 0x31, 0x9f, 0x9a, 0x21, 0x23, 0x08, 0x7d, 0x8c, 0x2d, 0x25, 0x2c, 0xdd, 0xd1, 0x31, 0x80, 0xc1, 0x98, 0x4f, 0xcd, 0x90, 0x91,
0x01, 0x3f, 0xe3, 0x6e, 0xb4, 0x77, 0x46, 0x91, 0xfa, 0xa1, 0x5c, 0xd9, 0x34, 0x96, 0x2e, 0x63, 0x80, 0x9f, 0x71, 0xd7, 0x5a, 0xdb, 0xa3, 0xa1, 0x7a, 0x57, 0xee, 0x6c, 0x62, 0x4b, 0xb6, 0x31,
0xe6, 0xc1, 0xb9, 0x52, 0x74, 0x00, 0x8b, 0xae, 0xe1, 0x90, 0xa0, 0xbe, 0xcc, 0x09, 0x6c, 0x8d, 0xd5, 0xe0, 0x4c, 0x28, 0xda, 0x87, 0x45, 0xd7, 0x70, 0x48, 0x50, 0x5b, 0xe6, 0x04, 0x36, 0x47,
0x22, 0x75, 0x43, 0x60, 0x70, 0x77, 0x52, 0x2e, 0x0c, 0x2c, 0x72, 0x51, 0x0b, 0x2a, 0x6c, 0xd8, 0x43, 0x75, 0x5d, 0x60, 0x70, 0x75, 0x1c, 0x2e, 0x04, 0x2c, 0x7c, 0x51, 0x13, 0x4a, 0x6c, 0xd0,
0x17, 0xbb, 0xb9, 0x50, 0x13, 0x7b, 0xd3, 0x1a, 0x61, 0x60, 0x9e, 0xda, 0xfc, 0x1a, 0xd6, 0x0e, 0x13, 0xd3, 0x9c, 0x8b, 0x89, 0xb4, 0x49, 0x8c, 0x10, 0x30, 0x77, 0x6d, 0x7c, 0x0b, 0xab, 0x07,
0x93, 0x4e, 0x39, 0x76, 0x99, 0x3f, 0x44, 0x08, 0x2a, 0x31, 0x9a, 0x68, 0x0a, 0xcc, 0xbf, 0xd1, 0x71, 0xa7, 0x1c, 0xb9, 0xcc, 0x1f, 0x20, 0x04, 0xa5, 0x08, 0x4d, 0x34, 0x05, 0xe6, 0xdf, 0xe8,
0xc7, 0xb0, 0x48, 0xe2, 0xa0, 0x7c, 0x8b, 0xa8, 0x5a, 0xf9, 0xa9, 0xa6, 0x7d, 0x61, 0x38, 0x24, 0x13, 0x58, 0x24, 0x91, 0x51, 0xbe, 0x45, 0x54, 0xad, 0xf8, 0x54, 0xd3, 0xbe, 0x32, 0x1c, 0x92,
0x05, 0xc2, 0x22, 0xbb, 0xf9, 0xf7, 0x02, 0xac, 0x16, 0x02, 0xe8, 0x1b, 0xb8, 0xc9, 0x95, 0xea, 0x00, 0x61, 0xe1, 0xdd, 0xf8, 0x77, 0x01, 0x56, 0x72, 0x06, 0xf4, 0x1d, 0x5c, 0xe7, 0x95, 0x6a,
0xf4, 0x43, 0xb3, 0x47, 0xad, 0xce, 0x77, 0x64, 0x28, 0xbb, 0xef, 0x60, 0x14, 0xa9, 0x7a, 0x4e, 0xf7, 0x42, 0xb3, 0x4b, 0xad, 0xf6, 0x0f, 0x64, 0x20, 0xbb, 0x6f, 0x7f, 0x34, 0x54, 0xf5, 0x4c,
0xe2, 0x5c, 0x46, 0x41, 0xec, 0xbc, 0x1f, 0xaf, 0x71, 0xd7, 0x19, 0xf7, 0x3c, 0x23, 0x43, 0x84, 0x89, 0x33, 0x1e, 0xb9, 0x62, 0x67, 0xf5, 0x78, 0x95, 0xab, 0x4e, 0xb9, 0xe6, 0x29, 0x19, 0x20,
0x61, 0x55, 0x24, 0x19, 0xb6, 0xed, 0x93, 0x20, 0x90, 0xbd, 0xba, 0x37, 0x8a, 0xd4, 0xfb, 0x79, 0x0c, 0x2b, 0xc2, 0xc9, 0xb0, 0x6d, 0x9f, 0x04, 0x81, 0xec, 0xd5, 0xdd, 0xd1, 0x50, 0xbd, 0x97,
0x6c, 0x19, 0x2e, 0x02, 0x27, 0x4e, 0x7c, 0x83, 0xdb, 0x87, 0xc2, 0x44, 0xb7, 0xa1, 0x7a, 0x41, 0xc5, 0x96, 0xe6, 0x3c, 0x70, 0xac, 0xc4, 0xd7, 0xb8, 0x7c, 0x20, 0x44, 0x74, 0x13, 0xca, 0xe7,
0x68, 0xf7, 0x42, 0x3c, 0x7e, 0x2a, 0x58, 0x5a, 0xb1, 0x3f, 0x60, 0x06, 0x0b, 0x03, 0xd1, 0x84, 0x84, 0x76, 0xce, 0xc5, 0xe3, 0xa7, 0x84, 0xa5, 0x14, 0xe9, 0x03, 0x66, 0xb0, 0x30, 0x10, 0x4d,
0x58, 0x5a, 0xe8, 0x29, 0x40, 0xb2, 0x23, 0xa9, 0x68, 0xac, 0x5a, 0xa1, 0x05, 0xd2, 0x58, 0xb6, 0x88, 0xa5, 0x84, 0x9e, 0x00, 0xc4, 0x13, 0x49, 0x45, 0x63, 0x55, 0x72, 0x2d, 0x90, 0xd8, 0xd2,
0x93, 0x53, 0x0f, 0xae, 0x49, 0xe3, 0xb4, 0xb0, 0xe3, 0xaa, 0xff, 0x75, 0xc7, 0xb9, 0xc5, 0x5d, 0x49, 0x4e, 0x34, 0xb8, 0x22, 0x85, 0x93, 0xdc, 0xc4, 0x95, 0xdf, 0x75, 0xe2, 0xdc, 0xfc, 0x94,
0x22, 0xee, 0xda, 0xcd, 0xb1, 0x1b, 0xea, 0x45, 0xf2, 0x5c, 0x6e, 0xb7, 0x8a, 0xef, 0xd6, 0x19, 0x88, 0xbb, 0x76, 0x63, 0xec, 0x86, 0x7a, 0x1e, 0x3f, 0x97, 0x5b, 0xcd, 0xfc, 0xbb, 0x75, 0xc6,
0xbb, 0xe8, 0x32, 0xbe, 0x74, 0x72, 0x3b, 0xa9, 0x79, 0x0e, 0xb5, 0x78, 0x9d, 0xa7, 0x37, 0xd0, 0x14, 0x5d, 0x44, 0x97, 0x4e, 0x66, 0x92, 0x1a, 0x67, 0x50, 0x89, 0xf6, 0x79, 0x7a, 0x03, 0xed,
0x7e, 0xb1, 0x81, 0xee, 0x4e, 0x6e, 0x20, 0x71, 0x28, 0x25, 0xdd, 0xf3, 0xa3, 0x02, 0x90, 0x79, 0xe5, 0x1b, 0xe8, 0xf6, 0xe4, 0x06, 0x12, 0x87, 0x52, 0xdc, 0x3d, 0x3f, 0x2b, 0x00, 0xa9, 0x16,
0xd1, 0x23, 0xa8, 0xf6, 0x0c, 0x46, 0x82, 0xe4, 0x15, 0x7e, 0xef, 0x5d, 0x18, 0x9c, 0x09, 0x96, 0x3d, 0x84, 0x72, 0xd7, 0x60, 0x24, 0x88, 0x5f, 0xe1, 0x77, 0xde, 0x86, 0xc1, 0x99, 0x60, 0x19,
0x05, 0xe8, 0x09, 0x2c, 0x5d, 0xd0, 0x80, 0x79, 0x7c, 0xfc, 0x85, 0x7f, 0x57, 0x9b, 0x54, 0x34, 0x80, 0x1e, 0xc3, 0xd2, 0x39, 0x0d, 0x98, 0xc7, 0xd7, 0x5f, 0xf8, 0x7f, 0xb1, 0x71, 0x44, 0xe3,
0x1f, 0xc1, 0xff, 0x4a, 0x31, 0xb4, 0x96, 0x9d, 0x9a, 0xfc, 0x70, 0xcc, 0x5a, 0x64, 0x3e, 0xdf, 0x21, 0x7c, 0x50, 0xb0, 0xa1, 0xd5, 0xf4, 0xd4, 0xe4, 0x87, 0x63, 0xda, 0x22, 0xf3, 0xd9, 0x16,
0x22, 0x4d, 0x06, 0xb5, 0x73, 0xda, 0x75, 0x0d, 0x16, 0xfa, 0x04, 0x3d, 0x80, 0x85, 0x80, 0x76, 0x69, 0x30, 0xa8, 0x9c, 0xd1, 0x8e, 0x6b, 0xb0, 0xd0, 0x27, 0xe8, 0x3e, 0x2c, 0x04, 0xb4, 0x23,
0x65, 0xb7, 0x6f, 0x8c, 0x22, 0xf5, 0x96, 0xd0, 0x3a, 0xa0, 0xdd, 0x44, 0xe3, 0xf8, 0x13, 0xc7, 0xbb, 0x7d, 0x7d, 0x34, 0x54, 0x6f, 0x88, 0x5a, 0x07, 0xb4, 0x13, 0xd7, 0x38, 0xfa, 0xc4, 0x91,
0x59, 0xf1, 0xe2, 0xf7, 0x43, 0x93, 0x6f, 0x8f, 0xb1, 0xe3, 0x56, 0x06, 0x92, 0xa2, 0xc4, 0xc4, 0x57, 0xb4, 0xf9, 0xbd, 0xd0, 0xe4, 0xe3, 0x31, 0x76, 0xdc, 0x4a, 0x43, 0x1c, 0x14, 0x8b, 0xb8,
0xd5, 0x7e, 0x68, 0x3e, 0x23, 0xc3, 0xe6, 0x01, 0xac, 0x1c, 0xf3, 0xa5, 0x79, 0x1e, 0x92, 0x90, 0xdc, 0x0b, 0xcd, 0xa7, 0x64, 0xd0, 0xd8, 0x87, 0xea, 0x11, 0xdf, 0x9a, 0x67, 0x21, 0x09, 0xc9,
0x8c, 0x91, 0x5d, 0x87, 0xc5, 0x81, 0xd1, 0x0b, 0x09, 0x97, 0xa2, 0x86, 0x85, 0xd1, 0x3e, 0x7c, 0x18, 0xd9, 0x35, 0x58, 0xec, 0x1b, 0xdd, 0x90, 0xf0, 0x52, 0x54, 0xb0, 0x10, 0x1a, 0x77, 0xa1,
0x73, 0xd5, 0x50, 0xde, 0x5e, 0x35, 0x94, 0xbf, 0xae, 0x1a, 0xca, 0xe5, 0x75, 0x63, 0xee, 0xed, 0x2a, 0x32, 0x0c, 0xbe, 0xa0, 0x01, 0x4b, 0x9d, 0x94, 0x8c, 0x53, 0xeb, 0xe0, 0xf5, 0x65, 0x5d,
0x75, 0x63, 0xee, 0xf7, 0xeb, 0xc6, 0xdc, 0x57, 0x3b, 0x5d, 0xca, 0xb4, 0x81, 0x6d, 0x6a, 0xcc, 0x79, 0x73, 0x59, 0x57, 0xfe, 0xb9, 0xac, 0x2b, 0x17, 0x57, 0xf5, 0xb9, 0x37, 0x57, 0xf5, 0xb9,
0xd3, 0x63, 0xd5, 0xf6, 0xa8, 0xa7, 0xf7, 0x0c, 0xcb, 0x73, 0xa9, 0xb5, 0x6f, 0xeb, 0xaf, 0xd2, 0x3f, 0xaf, 0xea, 0x73, 0xdf, 0x6c, 0x77, 0x28, 0xd3, 0xfa, 0xb6, 0xa9, 0x31, 0x4f, 0x8f, 0x4a,
0xbf, 0x38, 0xb3, 0xca, 0xfb, 0xea, 0xe0, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xd2, 0xef, 0x57, 0xbb, 0x4b, 0x3d, 0xbd, 0x6b, 0x58, 0x9e, 0x4b, 0xad, 0x3d, 0x5b, 0x7f, 0x99, 0xfc, 0xea, 0x99,
0x0f, 0xe9, 0x0d, 0x00, 0x00, 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) { 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 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 { func encodeVarintRegistry(dAtA []byte, offset int, v uint64) int {
offset -= sovRegistry(v) offset -= sovRegistry(v)
base := offset base := offset
@ -1535,6 +1615,21 @@ func (m *ExpiryQueue) Size() (n int) {
return n 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) { func sovRegistry(x uint64) (n int) {
return (math_bits.Len64(x|1) + 6) / 7 return (math_bits.Len64(x|1) + 6) / 7
} }
@ -3216,6 +3311,88 @@ func (m *ExpiryQueue) Unmarshal(dAtA []byte) error {
} }
return nil 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) { func skipRegistry(dAtA []byte) (n int, err error) {
l := len(dAtA) l := len(dAtA)
iNdEx := 0 iNdEx := 0