From e394604f8382c922e25006af705947c323e08efa Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Wed, 13 Sep 2023 13:19:58 +0200 Subject: [PATCH] feat(x/tx): add custom type encoder (#17681) --- x/tx/CHANGELOG.md | 1 + x/tx/signing/aminojson/any.go | 6 +- .../aminojson/internal/testpb/test.proto | 5 + .../aminojson/internal/testpb/test.pulsar.go | 656 +++++++++++++++++- x/tx/signing/aminojson/json_marshal.go | 78 ++- x/tx/signing/aminojson/json_marshal_test.go | 32 + x/tx/signing/aminojson/options.go | 6 +- x/tx/signing/aminojson/time.go | 5 +- 8 files changed, 711 insertions(+), 78 deletions(-) diff --git a/x/tx/CHANGELOG.md b/x/tx/CHANGELOG.md index ec4885e5ba40..0a6c6c6cc66c 100644 --- a/x/tx/CHANGELOG.md +++ b/x/tx/CHANGELOG.md @@ -35,6 +35,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Features +* [#17681](https://github.com/cosmos/cosmos-sdk/pull/17681) Add encoder `DefineTypeEncoding` method for defining custom type encodings. * [#17600](https://github.com/cosmos/cosmos-sdk/pull/17600) Add encoder `DefineScalarEncoding` method for defining custom scalar encodings. * [#17600](https://github.com/cosmos/cosmos-sdk/pull/17600) Add indent option to encoder. diff --git a/x/tx/signing/aminojson/any.go b/x/tx/signing/aminojson/any.go index 6898f50ce15f..4e0e46954bcb 100644 --- a/x/tx/signing/aminojson/any.go +++ b/x/tx/signing/aminojson/any.go @@ -11,12 +11,12 @@ import ( "google.golang.org/protobuf/types/known/anypb" ) -func (enc Encoder) marshalAny(message protoreflect.Message, writer io.Writer) error { +func marshalAny(enc *Encoder, message protoreflect.Message, writer io.Writer) error { // when a message contains a nested any field, and the top-level message has been unmarshalled into a dyanmicpb, // the nested any field will also be a dynamicpb. In this case, we must use the dynamicpb API. _, ok := message.Interface().(*dynamicpb.Message) if ok { - return enc.marshalDynamic(message, writer) + return marshalDynamic(enc, message, writer) } anyMsg, ok := message.Interface().(*anypb.Any) @@ -64,7 +64,7 @@ const ( anyValueFieldName = "value" ) -func (enc Encoder) marshalDynamic(message protoreflect.Message, writer io.Writer) error { +func marshalDynamic(enc *Encoder, message protoreflect.Message, writer io.Writer) error { msgName := message.Get(message.Descriptor().Fields().ByName(anyTypeURLFieldName)).String()[1:] msgBytes := message.Get(message.Descriptor().Fields().ByName(anyValueFieldName)).Bytes() diff --git a/x/tx/signing/aminojson/internal/testpb/test.proto b/x/tx/signing/aminojson/internal/testpb/test.proto index 0b1b3644c843..de2f25e76c25 100644 --- a/x/tx/signing/aminojson/internal/testpb/test.proto +++ b/x/tx/signing/aminojson/internal/testpb/test.proto @@ -62,6 +62,11 @@ message ABitOfEverything { // google.protobuf.Duration duration = 24; } +message Duration { + google.protobuf.Duration duration = 1; + google.protobuf.Timestamp timestamp = 2; +} + message NestedMessage { option (amino.name) = "NestedMessage"; diff --git a/x/tx/signing/aminojson/internal/testpb/test.pulsar.go b/x/tx/signing/aminojson/internal/testpb/test.pulsar.go index ae8a54ee2571..7cc06a47766e 100644 --- a/x/tx/signing/aminojson/internal/testpb/test.pulsar.go +++ b/x/tx/signing/aminojson/internal/testpb/test.pulsar.go @@ -10,11 +10,11 @@ import ( protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" _ "google.golang.org/protobuf/types/known/anypb" - _ "google.golang.org/protobuf/types/known/durationpb" + durationpb "google.golang.org/protobuf/types/known/durationpb" _ "google.golang.org/protobuf/types/known/emptypb" _ "google.golang.org/protobuf/types/known/fieldmaskpb" _ "google.golang.org/protobuf/types/known/structpb" - _ "google.golang.org/protobuf/types/known/timestamppb" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" _ "google.golang.org/protobuf/types/known/wrapperspb" io "io" reflect "reflect" @@ -2594,6 +2594,520 @@ func (x *fastReflection_ABitOfEverything) ProtoMethods() *protoiface.Methods { } } +var ( + md_Duration protoreflect.MessageDescriptor + fd_Duration_duration protoreflect.FieldDescriptor + fd_Duration_timestamp protoreflect.FieldDescriptor +) + +func init() { + file_testpb_test_proto_init() + md_Duration = File_testpb_test_proto.Messages().ByName("Duration") + fd_Duration_duration = md_Duration.Fields().ByName("duration") + fd_Duration_timestamp = md_Duration.Fields().ByName("timestamp") +} + +var _ protoreflect.Message = (*fastReflection_Duration)(nil) + +type fastReflection_Duration Duration + +func (x *Duration) ProtoReflect() protoreflect.Message { + return (*fastReflection_Duration)(x) +} + +func (x *Duration) slowProtoReflect() protoreflect.Message { + mi := &file_testpb_test_proto_msgTypes[3] + 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_Duration_messageType fastReflection_Duration_messageType +var _ protoreflect.MessageType = fastReflection_Duration_messageType{} + +type fastReflection_Duration_messageType struct{} + +func (x fastReflection_Duration_messageType) Zero() protoreflect.Message { + return (*fastReflection_Duration)(nil) +} +func (x fastReflection_Duration_messageType) New() protoreflect.Message { + return new(fastReflection_Duration) +} +func (x fastReflection_Duration_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_Duration +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_Duration) Descriptor() protoreflect.MessageDescriptor { + return md_Duration +} + +// 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_Duration) Type() protoreflect.MessageType { + return _fastReflection_Duration_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_Duration) New() protoreflect.Message { + return new(fastReflection_Duration) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_Duration) Interface() protoreflect.ProtoMessage { + return (*Duration)(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_Duration) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.Duration != nil { + value := protoreflect.ValueOfMessage(x.Duration.ProtoReflect()) + if !f(fd_Duration_duration, value) { + return + } + } + if x.Timestamp != nil { + value := protoreflect.ValueOfMessage(x.Timestamp.ProtoReflect()) + if !f(fd_Duration_timestamp, 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_Duration) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "testpb.Duration.duration": + return x.Duration != nil + case "testpb.Duration.timestamp": + return x.Timestamp != nil + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: testpb.Duration")) + } + panic(fmt.Errorf("message testpb.Duration 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_Duration) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "testpb.Duration.duration": + x.Duration = nil + case "testpb.Duration.timestamp": + x.Timestamp = nil + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: testpb.Duration")) + } + panic(fmt.Errorf("message testpb.Duration 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_Duration) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "testpb.Duration.duration": + value := x.Duration + return protoreflect.ValueOfMessage(value.ProtoReflect()) + case "testpb.Duration.timestamp": + value := x.Timestamp + return protoreflect.ValueOfMessage(value.ProtoReflect()) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: testpb.Duration")) + } + panic(fmt.Errorf("message testpb.Duration 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_Duration) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "testpb.Duration.duration": + x.Duration = value.Message().Interface().(*durationpb.Duration) + case "testpb.Duration.timestamp": + x.Timestamp = value.Message().Interface().(*timestamppb.Timestamp) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: testpb.Duration")) + } + panic(fmt.Errorf("message testpb.Duration 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_Duration) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "testpb.Duration.duration": + if x.Duration == nil { + x.Duration = new(durationpb.Duration) + } + return protoreflect.ValueOfMessage(x.Duration.ProtoReflect()) + case "testpb.Duration.timestamp": + if x.Timestamp == nil { + x.Timestamp = new(timestamppb.Timestamp) + } + return protoreflect.ValueOfMessage(x.Timestamp.ProtoReflect()) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: testpb.Duration")) + } + panic(fmt.Errorf("message testpb.Duration 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_Duration) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "testpb.Duration.duration": + m := new(durationpb.Duration) + return protoreflect.ValueOfMessage(m.ProtoReflect()) + case "testpb.Duration.timestamp": + m := new(timestamppb.Timestamp) + return protoreflect.ValueOfMessage(m.ProtoReflect()) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: testpb.Duration")) + } + panic(fmt.Errorf("message testpb.Duration 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_Duration) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in testpb.Duration", 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_Duration) 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_Duration) 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_Duration) 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_Duration) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*Duration) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + if x.Duration != nil { + l = options.Size(x.Duration) + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.Timestamp != nil { + l = options.Size(x.Timestamp) + 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().(*Duration) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if x.Timestamp != nil { + encoded, err := options.Marshal(x.Timestamp) + if err != nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) + i-- + dAtA[i] = 0x12 + } + if x.Duration != nil { + encoded, err := options.Marshal(x.Duration) + if err != nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) + i-- + dAtA[i] = 0xa + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*Duration) + 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: Duration: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: Duration: 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 Duration", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if x.Duration == nil { + x.Duration = &durationpb.Duration{} + } + if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.Duration); err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Timestamp", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if x.Timestamp == nil { + x.Timestamp = ×tamppb.Timestamp{} + } + if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.Timestamp); err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + var ( md_NestedMessage protoreflect.MessageDescriptor fd_NestedMessage_foo protoreflect.FieldDescriptor @@ -2616,7 +3130,7 @@ func (x *NestedMessage) ProtoReflect() protoreflect.Message { } func (x *NestedMessage) slowProtoReflect() protoreflect.Message { - mi := &file_testpb_test_proto_msgTypes[3] + mi := &file_testpb_test_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3357,6 +3871,49 @@ func (x *ABitOfEverything) GetSf64() int64 { return 0 } +type Duration struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Duration *durationpb.Duration `protobuf:"bytes,1,opt,name=duration,proto3" json:"duration,omitempty"` + Timestamp *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"` +} + +func (x *Duration) Reset() { + *x = Duration{} + if protoimpl.UnsafeEnabled { + mi := &file_testpb_test_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Duration) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Duration) ProtoMessage() {} + +// Deprecated: Use Duration.ProtoReflect.Descriptor instead. +func (*Duration) Descriptor() ([]byte, []int) { + return file_testpb_test_proto_rawDescGZIP(), []int{3} +} + +func (x *Duration) GetDuration() *durationpb.Duration { + if x != nil { + return x.Duration + } + return nil +} + +func (x *Duration) GetTimestamp() *timestamppb.Timestamp { + if x != nil { + return x.Timestamp + } + return nil +} + type NestedMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -3369,7 +3926,7 @@ type NestedMessage struct { func (x *NestedMessage) Reset() { *x = NestedMessage{} if protoimpl.UnsafeEnabled { - mi := &file_testpb_test_proto_msgTypes[3] + mi := &file_testpb_test_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3383,7 +3940,7 @@ func (*NestedMessage) ProtoMessage() {} // Deprecated: Use NestedMessage.ProtoReflect.Descriptor instead. func (*NestedMessage) Descriptor() ([]byte, []int) { - return file_testpb_test_proto_rawDescGZIP(), []int{3} + return file_testpb_test_proto_rawDescGZIP(), []int{4} } func (x *NestedMessage) GetFoo() string { @@ -3458,23 +4015,31 @@ var file_testpb_test_proto_rawDesc = []byte{ 0x12, 0x52, 0x04, 0x73, 0x69, 0x36, 0x34, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x66, 0x36, 0x34, 0x18, 0x13, 0x20, 0x01, 0x28, 0x10, 0x52, 0x04, 0x73, 0x66, 0x36, 0x34, 0x3a, 0x15, 0x8a, 0xe7, 0xb0, 0x2a, 0x10, 0x41, 0x42, 0x69, 0x74, 0x4f, 0x66, 0x45, 0x76, 0x65, 0x72, 0x79, 0x74, 0x68, 0x69, - 0x6e, 0x67, 0x22, 0x47, 0x0a, 0x0d, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x66, 0x6f, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x03, 0x66, 0x6f, 0x6f, 0x12, 0x10, 0x0a, 0x03, 0x62, 0x61, 0x72, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x05, 0x52, 0x03, 0x62, 0x61, 0x72, 0x3a, 0x12, 0x8a, 0xe7, 0xb0, 0x2a, 0x0d, 0x4e, 0x65, - 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2a, 0x29, 0x0a, 0x06, 0x41, - 0x6e, 0x45, 0x6e, 0x75, 0x6d, 0x12, 0x0d, 0x0a, 0x09, 0x55, 0x4e, 0x44, 0x45, 0x46, 0x49, 0x4e, - 0x45, 0x44, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x4f, 0x4e, 0x45, 0x10, 0x01, 0x12, 0x07, 0x0a, - 0x03, 0x54, 0x57, 0x4f, 0x10, 0x02, 0x42, 0x83, 0x01, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x2e, 0x74, - 0x65, 0x73, 0x74, 0x70, 0x62, 0x42, 0x09, 0x54, 0x65, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, - 0x50, 0x01, 0x5a, 0x32, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, - 0x2f, 0x78, 0x2f, 0x74, 0x78, 0x2f, 0x61, 0x6d, 0x69, 0x6e, 0x6f, 0x6a, 0x73, 0x6f, 0x6e, 0x2f, - 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x70, 0x62, 0x2f, - 0x74, 0x65, 0x73, 0x74, 0x70, 0x62, 0xa2, 0x02, 0x03, 0x54, 0x58, 0x58, 0xaa, 0x02, 0x06, 0x54, - 0x65, 0x73, 0x74, 0x70, 0x62, 0xca, 0x02, 0x06, 0x54, 0x65, 0x73, 0x74, 0x70, 0x62, 0xe2, 0x02, - 0x12, 0x54, 0x65, 0x73, 0x74, 0x70, 0x62, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, - 0x61, 0x74, 0x61, 0xea, 0x02, 0x06, 0x54, 0x65, 0x73, 0x74, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x6e, 0x67, 0x22, 0x7b, 0x0a, 0x08, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x35, + 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x64, 0x75, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, + 0x47, 0x0a, 0x0d, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x12, 0x10, 0x0a, 0x03, 0x66, 0x6f, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x66, + 0x6f, 0x6f, 0x12, 0x10, 0x0a, 0x03, 0x62, 0x61, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x03, 0x62, 0x61, 0x72, 0x3a, 0x12, 0x8a, 0xe7, 0xb0, 0x2a, 0x0d, 0x4e, 0x65, 0x73, 0x74, 0x65, + 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2a, 0x29, 0x0a, 0x06, 0x41, 0x6e, 0x45, 0x6e, + 0x75, 0x6d, 0x12, 0x0d, 0x0a, 0x09, 0x55, 0x4e, 0x44, 0x45, 0x46, 0x49, 0x4e, 0x45, 0x44, 0x10, + 0x00, 0x12, 0x07, 0x0a, 0x03, 0x4f, 0x4e, 0x45, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x54, 0x57, + 0x4f, 0x10, 0x02, 0x42, 0x83, 0x01, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x2e, 0x74, 0x65, 0x73, 0x74, + 0x70, 0x62, 0x42, 0x09, 0x54, 0x65, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, + 0x32, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x78, 0x2f, + 0x74, 0x78, 0x2f, 0x61, 0x6d, 0x69, 0x6e, 0x6f, 0x6a, 0x73, 0x6f, 0x6e, 0x2f, 0x69, 0x6e, 0x74, + 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x70, 0x62, 0x2f, 0x74, 0x65, 0x73, + 0x74, 0x70, 0x62, 0xa2, 0x02, 0x03, 0x54, 0x58, 0x58, 0xaa, 0x02, 0x06, 0x54, 0x65, 0x73, 0x74, + 0x70, 0x62, 0xca, 0x02, 0x06, 0x54, 0x65, 0x73, 0x74, 0x70, 0x62, 0xe2, 0x02, 0x12, 0x54, 0x65, + 0x73, 0x74, 0x70, 0x62, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0xea, 0x02, 0x06, 0x54, 0x65, 0x73, 0x74, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( @@ -3490,24 +4055,29 @@ func file_testpb_test_proto_rawDescGZIP() []byte { } var file_testpb_test_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_testpb_test_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_testpb_test_proto_msgTypes = make([]protoimpl.MessageInfo, 6) var file_testpb_test_proto_goTypes = []interface{}{ - (AnEnum)(0), // 0: testpb.AnEnum - (*WithAMap)(nil), // 1: testpb.WithAMap - (*WithAList)(nil), // 2: testpb.WithAList - (*ABitOfEverything)(nil), // 3: testpb.ABitOfEverything - (*NestedMessage)(nil), // 4: testpb.NestedMessage - nil, // 5: testpb.WithAMap.StrMapEntry + (AnEnum)(0), // 0: testpb.AnEnum + (*WithAMap)(nil), // 1: testpb.WithAMap + (*WithAList)(nil), // 2: testpb.WithAList + (*ABitOfEverything)(nil), // 3: testpb.ABitOfEverything + (*Duration)(nil), // 4: testpb.Duration + (*NestedMessage)(nil), // 5: testpb.NestedMessage + nil, // 6: testpb.WithAMap.StrMapEntry + (*durationpb.Duration)(nil), // 7: google.protobuf.Duration + (*timestamppb.Timestamp)(nil), // 8: google.protobuf.Timestamp } var file_testpb_test_proto_depIdxs = []int32{ - 5, // 0: testpb.WithAMap.str_map:type_name -> testpb.WithAMap.StrMapEntry - 4, // 1: testpb.ABitOfEverything.message:type_name -> testpb.NestedMessage + 6, // 0: testpb.WithAMap.str_map:type_name -> testpb.WithAMap.StrMapEntry + 5, // 1: testpb.ABitOfEverything.message:type_name -> testpb.NestedMessage 0, // 2: testpb.ABitOfEverything.enum:type_name -> testpb.AnEnum - 3, // [3:3] is the sub-list for method output_type - 3, // [3:3] is the sub-list for method input_type - 3, // [3:3] is the sub-list for extension type_name - 3, // [3:3] is the sub-list for extension extendee - 0, // [0:3] is the sub-list for field type_name + 7, // 3: testpb.Duration.duration:type_name -> google.protobuf.Duration + 8, // 4: testpb.Duration.timestamp:type_name -> google.protobuf.Timestamp + 5, // [5:5] is the sub-list for method output_type + 5, // [5:5] is the sub-list for method input_type + 5, // [5:5] is the sub-list for extension type_name + 5, // [5:5] is the sub-list for extension extendee + 0, // [0:5] is the sub-list for field type_name } func init() { file_testpb_test_proto_init() } @@ -3553,6 +4123,18 @@ func file_testpb_test_proto_init() { } } file_testpb_test_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Duration); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_testpb_test_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*NestedMessage); i { case 0: return &v.state @@ -3571,7 +4153,7 @@ func file_testpb_test_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_testpb_test_proto_rawDesc, NumEnums: 1, - NumMessages: 5, + NumMessages: 6, NumExtensions: 0, NumServices: 0, }, diff --git a/x/tx/signing/aminojson/json_marshal.go b/x/tx/signing/aminojson/json_marshal.go index f6698c47578d..d3ca5822b54d 100644 --- a/x/tx/signing/aminojson/json_marshal.go +++ b/x/tx/signing/aminojson/json_marshal.go @@ -37,13 +37,14 @@ type EncoderOptions struct { // Encoder is a JSON encoder that uses the Amino JSON encoding rules for protobuf messages. type Encoder struct { // maps cosmos_proto.scalar -> field encoder - scalarEncoders map[string]FieldEncoder - messageEncoders map[string]MessageEncoder - fieldEncoders map[string]FieldEncoder - fileResolver signing.ProtoFileResolver - typeResolver protoregistry.MessageTypeResolver - doNotSortFields bool - indent string + cosmosProtoScalarEncoders map[string]FieldEncoder + aminoMessageEncoders map[string]MessageEncoder + aminoFieldEncoders map[string]FieldEncoder + protoTypeEncoders map[string]MessageEncoder + fileResolver signing.ProtoFileResolver + typeResolver protoregistry.MessageTypeResolver + doNotSortFields bool + indent string } // NewEncoder returns a new Encoder capable of serializing protobuf messages to JSON using the Amino JSON encoding @@ -56,18 +57,23 @@ func NewEncoder(options EncoderOptions) Encoder { options.TypeResolver = protoregistry.GlobalTypes } enc := Encoder{ - scalarEncoders: map[string]FieldEncoder{ + cosmosProtoScalarEncoders: map[string]FieldEncoder{ "cosmos.Dec": cosmosDecEncoder, "cosmos.Int": cosmosIntEncoder, }, - messageEncoders: map[string]MessageEncoder{ + aminoMessageEncoders: map[string]MessageEncoder{ "key_field": keyFieldEncoder, "module_account": moduleAccountEncoder, "threshold_string": thresholdStringEncoder, }, - fieldEncoders: map[string]FieldEncoder{ + aminoFieldEncoders: map[string]FieldEncoder{ "legacy_coins": nullSliceAsEmptyEncoder, }, + protoTypeEncoders: map[string]MessageEncoder{ + "google.protobuf.Timestamp": marshalTimestamp, + "google.protobuf.Duration": marshalDuration, + "google.protobuf.Any": marshalAny, + }, fileResolver: options.FileResolver, typeResolver: options.TypeResolver, doNotSortFields: options.DoNotSortFields, @@ -86,10 +92,10 @@ func NewEncoder(options EncoderOptions) Encoder { // ... // } func (enc Encoder) DefineMessageEncoding(name string, encoder MessageEncoder) Encoder { - if enc.messageEncoders == nil { - enc.messageEncoders = map[string]MessageEncoder{} + if enc.aminoMessageEncoders == nil { + enc.aminoMessageEncoders = map[string]MessageEncoder{} } - enc.messageEncoders[name] = encoder + enc.aminoMessageEncoders[name] = encoder return enc } @@ -107,10 +113,10 @@ func (enc Encoder) DefineMessageEncoding(name string, encoder MessageEncoder) En // ... // } func (enc Encoder) DefineFieldEncoding(name string, encoder FieldEncoder) Encoder { - if enc.fieldEncoders == nil { - enc.fieldEncoders = map[string]FieldEncoder{} + if enc.aminoFieldEncoders == nil { + enc.aminoFieldEncoders = map[string]FieldEncoder{} } - enc.fieldEncoders[name] = encoder + enc.aminoFieldEncoders[name] = encoder return enc } @@ -123,10 +129,27 @@ func (enc Encoder) DefineFieldEncoding(name string, encoder FieldEncoder) Encode // ... // } func (enc Encoder) DefineScalarEncoding(name string, encoder FieldEncoder) Encoder { - if enc.scalarEncoders == nil { - enc.scalarEncoders = map[string]FieldEncoder{} + if enc.cosmosProtoScalarEncoders == nil { + enc.cosmosProtoScalarEncoders = map[string]FieldEncoder{} } - enc.scalarEncoders[name] = encoder + enc.cosmosProtoScalarEncoders[name] = encoder + return enc +} + +// DefineTypeEncoding defines a custom encoding for a protobuf message type. The `typeURL` field must match the +// type of the protobuf message as in the following example. This encoding will be used instead of the default +// encoding for all usages of the tagged message. +// +// message Foo { +// google.protobuf.Duration type_url = 1; +// ... +// } + +func (enc Encoder) DefineTypeEncoding(typeURL string, encoder MessageEncoder) Encoder { + if enc.protoTypeEncoders == nil { + enc.protoTypeEncoders = map[string]MessageEncoder{} + } + enc.protoTypeEncoders[typeURL] = encoder return enc } @@ -209,14 +232,9 @@ func (enc Encoder) marshalMessage(msg protoreflect.Message, writer io.Writer) er return errors.New("nil message") } - switch msg.Descriptor().FullName() { - case timestampFullName: - // replicate https://github.com/tendermint/go-amino/blob/8e779b71f40d175cd1302d3cd41a75b005225a7a/json-encode.go#L45-L51 - return marshalTimestamp(msg, writer) - case durationFullName: - return marshalDuration(msg, writer) - case anyFullName: - return enc.marshalAny(msg, writer) + // check if we have a custom type encoder for this type + if typeEnc, ok := enc.protoTypeEncoders[string(msg.Descriptor().FullName())]; ok { + return typeEnc(&enc, msg, writer) } if encoder := enc.getMessageEncoder(msg); encoder != nil { @@ -370,9 +388,3 @@ func (enc Encoder) marshalList(list protoreflect.List, writer io.Writer) error { _, err = io.WriteString(writer, "]") return err } - -const ( - timestampFullName protoreflect.FullName = "google.protobuf.Timestamp" - durationFullName protoreflect.FullName = "google.protobuf.Duration" - anyFullName protoreflect.FullName = "google.protobuf.Any" -) diff --git a/x/tx/signing/aminojson/json_marshal_test.go b/x/tx/signing/aminojson/json_marshal_test.go index 8937f8a9da71..d1d00893c30c 100644 --- a/x/tx/signing/aminojson/json_marshal_test.go +++ b/x/tx/signing/aminojson/json_marshal_test.go @@ -3,8 +3,10 @@ package aminojson_test import ( "encoding/json" "fmt" + "io" "reflect" "testing" + "time" "github.com/cosmos/cosmos-proto/rapidproto" "github.com/stretchr/testify/require" @@ -14,6 +16,7 @@ import ( "google.golang.org/protobuf/reflect/protoreflect" "google.golang.org/protobuf/reflect/protoregistry" "google.golang.org/protobuf/types/dynamicpb" + "google.golang.org/protobuf/types/known/durationpb" "gotest.tools/v3/assert" "pgregory.net/rapid" @@ -177,6 +180,35 @@ func TestDynamicPb(t *testing.T) { require.Equal(t, string(bz), string(dynamicBz)) } +func TestMarshalDuration(t *testing.T) { + msg := &testpb.Duration{ + Duration: &durationpb.Duration{Seconds: 1}, + } + encoder := aminojson.NewEncoder(aminojson.EncoderOptions{}) + + bz, err := encoder.Marshal(msg) + require.NoError(t, err) + require.Equal(t, `{"duration":"1000000000"}`, string(bz)) + + // define a custom marshaler for duration + encoder.DefineTypeEncoding("google.protobuf.Duration", func(_ *aminojson.Encoder, msg protoreflect.Message, w io.Writer) error { + var secondsName protoreflect.Name = "seconds" + + fields := msg.Descriptor().Fields() + secondsField := fields.ByName(secondsName) + if secondsField == nil { + return fmt.Errorf("expected seconds field") + } + seconds := msg.Get(secondsField).Int() + + _, err = fmt.Fprint(w, "\"", (time.Duration(seconds) * time.Second).String(), "\"") + return err + }) + bz, err = encoder.Marshal(msg) + require.NoError(t, err) + require.Equal(t, `{"duration":"1s"}`, string(bz)) +} + func TestIndent(t *testing.T) { encoder := aminojson.NewEncoder(aminojson.EncoderOptions{Indent: " "}) diff --git a/x/tx/signing/aminojson/options.go b/x/tx/signing/aminojson/options.go index f8b8991d04db..4e17060c78f3 100644 --- a/x/tx/signing/aminojson/options.go +++ b/x/tx/signing/aminojson/options.go @@ -64,7 +64,7 @@ func (enc Encoder) getMessageEncoder(message protoreflect.Message) MessageEncode opts := message.Descriptor().Options() if proto.HasExtension(opts, amino.E_MessageEncoding) { encoding := proto.GetExtension(opts, amino.E_MessageEncoding).(string) - if fn, ok := enc.messageEncoders[encoding]; ok { + if fn, ok := enc.aminoMessageEncoders[encoding]; ok { return fn } } @@ -75,13 +75,13 @@ func (enc Encoder) getFieldEncoding(field protoreflect.FieldDescriptor) FieldEnc opts := field.Options() if proto.HasExtension(opts, amino.E_Encoding) { encoding := proto.GetExtension(opts, amino.E_Encoding).(string) - if fn, ok := enc.fieldEncoders[encoding]; ok { + if fn, ok := enc.aminoFieldEncoders[encoding]; ok { return fn } } if proto.HasExtension(opts, cosmos_proto.E_Scalar) { scalar := proto.GetExtension(opts, cosmos_proto.E_Scalar).(string) - if fn, ok := enc.scalarEncoders[scalar]; ok { + if fn, ok := enc.cosmosProtoScalarEncoders[scalar]; ok { return fn } } diff --git a/x/tx/signing/aminojson/time.go b/x/tx/signing/aminojson/time.go index c5da99f01849..89577ac49e06 100644 --- a/x/tx/signing/aminojson/time.go +++ b/x/tx/signing/aminojson/time.go @@ -14,7 +14,8 @@ const ( nanosName protoreflect.Name = "nanos" ) -func marshalTimestamp(message protoreflect.Message, writer io.Writer) error { +// marshalTimestamp replicate https://github.com/tendermint/go-amino/blob/8e779b71f40d175cd1302d3cd41a75b005225a7a/json-encode.go#L45-L51 +func marshalTimestamp(_ *Encoder, message protoreflect.Message, writer io.Writer) error { fields := message.Descriptor().Fields() secondsField := fields.ByName(secondsName) if secondsField == nil { @@ -48,7 +49,7 @@ func marshalTimestamp(message protoreflect.Message, writer io.Writer) error { // gogoproto encodes google.protobuf.Duration as a time.Duration, which is 64-bit signed integer. const MaxDurationSeconds = int64(math.MaxInt64)/1e9 - 1 -func marshalDuration(message protoreflect.Message, writer io.Writer) error { +func marshalDuration(_ *Encoder, message protoreflect.Message, writer io.Writer) error { fields := message.Descriptor().Fields() secondsField := fields.ByName(secondsName) if secondsField == nil {