diff --git a/tests/go.mod b/tests/go.mod index 57fb698ddd..935c9bde0c 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -13,7 +13,7 @@ require ( cosmossdk.io/x/evidence v0.1.0 cosmossdk.io/x/feegrant v0.0.0-20230117113717-50e7c4a4ceff cosmossdk.io/x/nft v0.0.0-20230113085233-fae3332d62fc - cosmossdk.io/x/tx v0.5.1-0.20230407182919-057d2e09bd63 + cosmossdk.io/x/tx v0.5.1 cosmossdk.io/x/upgrade v0.0.0-20230127052425-54c8e1568335 github.com/cometbft/cometbft v0.37.1-0.20230411132551-3a91d155e664 github.com/cosmos/cosmos-db v1.0.0-rc.1 @@ -197,7 +197,6 @@ replace ( cosmossdk.io/x/evidence => ../x/evidence cosmossdk.io/x/feegrant => ../x/feegrant cosmossdk.io/x/nft => ../x/nft - cosmossdk.io/x/tx => ../x/tx cosmossdk.io/x/upgrade => ../x/upgrade ) diff --git a/tests/go.sum b/tests/go.sum index 8c9abd0583..a6ed45a16c 100644 --- a/tests/go.sum +++ b/tests/go.sum @@ -202,6 +202,8 @@ cosmossdk.io/log v1.0.0 h1:NGKZ/A5rd4PduDfoscgABklX557PWjQINbosZy/m3Jk= cosmossdk.io/log v1.0.0/go.mod h1:CwX9BLiBruZb7lzLlRr3R231d/fVPUXk8gAdV4LQap0= cosmossdk.io/math v1.0.0 h1:ro9w7eKx23om2tZz/VM2Pf+z2WAbGX1yDQQOJ6iGeJw= cosmossdk.io/math v1.0.0/go.mod h1:Ygz4wBHrgc7g0N+8+MrnTfS9LLn9aaTGa9hKopuym5k= +cosmossdk.io/x/tx v0.5.1 h1:OcHU8ex3JzxDjexSkMovBx8EnJXcqhrRt7msBq/3vqs= +cosmossdk.io/x/tx v0.5.1/go.mod h1:Oh3Kh+IPOfMEILNxVd2e8SLqRrIjYHpdGBfDg4ghU/k= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek= filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= diff --git a/x/tx/CHANGELOG.md b/x/tx/CHANGELOG.md index dd956831e6..2b5921d986 100644 --- a/x/tx/CHANGELOG.md +++ b/x/tx/CHANGELOG.md @@ -31,10 +31,22 @@ Ref: https://keepachangelog.com/en/1.0.0/ ## Unreleased +### API Breaking + +* [#15709](https://github.com/cosmos/cosmos-sdk/pull/15709): + * `GetSignersContext` has been renamed to `signing.Context` + * `GetSigners` now returns `[][]byte` instead of `[]string` + * `GetSignersOptions` has been renamed to `signing.Options` and requires `address.Codec`s for account and validator addresses + * `GetSignersOptions.ProtoFiles` has been renamed to `signing.Options.FileResolver` + +## v0.5.1 + ### Features * [#15414](https://github.com/cosmos/cosmos-sdk/pull/15414) Add basic transaction decoding support. +## v0.5.0 + ### API Breaking * [#15581](https://github.com/cosmos/cosmos-sdk/pull/15581) `GetSignersOptions` and `directaux.SignModeHandlerOptions` now diff --git a/x/tx/decode/decode.go b/x/tx/decode/decode.go index 4ee0843770..d046a396d0 100644 --- a/x/tx/decode/decode.go +++ b/x/tx/decode/decode.go @@ -1,12 +1,13 @@ package decode import ( - "github.com/cosmos/cosmos-proto/anyutil" - "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/reflect/protoregistry" + "fmt" v1beta1 "cosmossdk.io/api/cosmos/tx/v1beta1" "cosmossdk.io/errors" + "github.com/cosmos/cosmos-proto/anyutil" + "google.golang.org/protobuf/proto" + "cosmossdk.io/x/tx/signing" ) @@ -15,51 +16,28 @@ type DecodedTx struct { Messages []proto.Message Tx *v1beta1.Tx TxRaw *v1beta1.TxRaw - Signers []string + Signers [][]byte TxBodyHasUnknownNonCriticals bool } // Decoder contains the dependencies required for decoding transactions. type Decoder struct { - getSignersCtx *signing.GetSignersContext - typeResolver protoregistry.MessageTypeResolver - protoFiles *protoregistry.Files + signingCtx *signing.Context } // Options are options for creating a Decoder. type Options struct { - // ProtoFiles are the protobuf files to use for resolving message descriptors. - // If it is nil, the global protobuf registry will be used. - ProtoFiles *protoregistry.Files - TypeResolver protoregistry.MessageTypeResolver - SigningContext *signing.GetSignersContext + SigningContext *signing.Context } // NewDecoder creates a new Decoder for decoding transactions. func NewDecoder(options Options) (*Decoder, error) { - if options.ProtoFiles == nil { - options.ProtoFiles = protoregistry.GlobalFiles - } - - if options.TypeResolver == nil { - options.TypeResolver = protoregistry.GlobalTypes - } - - getSignersCtx := options.SigningContext - if getSignersCtx == nil { - var err error - getSignersCtx, err = signing.NewGetSignersContext(signing.GetSignersOptions{ - ProtoFiles: options.ProtoFiles, - }) - if err != nil { - return nil, err - } + if options.SigningContext == nil { + return nil, fmt.Errorf("signing context is required") } return &Decoder{ - getSignersCtx: getSignersCtx, - protoFiles: options.ProtoFiles, - typeResolver: options.TypeResolver, + signingCtx: options.SigningContext, }, nil } @@ -74,7 +52,8 @@ func (d *Decoder) Decode(txBytes []byte) (*DecodedTx, error) { var raw v1beta1.TxRaw // reject all unknown proto fields in the root TxRaw - err = RejectUnknownFieldsStrict(txBytes, raw.ProtoReflect().Descriptor(), d.protoFiles) + fileResolver := d.signingCtx.FileResolver() + err = RejectUnknownFieldsStrict(txBytes, raw.ProtoReflect().Descriptor(), fileResolver) if err != nil { return nil, errors.Wrap(ErrTxDecode, err.Error()) } @@ -87,7 +66,7 @@ func (d *Decoder) Decode(txBytes []byte) (*DecodedTx, error) { var body v1beta1.TxBody // allow non-critical unknown fields in TxBody - txBodyHasUnknownNonCriticals, err := RejectUnknownFields(raw.BodyBytes, body.ProtoReflect().Descriptor(), true, d.protoFiles) + txBodyHasUnknownNonCriticals, err := RejectUnknownFields(raw.BodyBytes, body.ProtoReflect().Descriptor(), true, fileResolver) if err != nil { return nil, errors.Wrap(ErrTxDecode, err.Error()) } @@ -100,7 +79,7 @@ func (d *Decoder) Decode(txBytes []byte) (*DecodedTx, error) { var authInfo v1beta1.AuthInfo // reject all unknown proto fields in AuthInfo - err = RejectUnknownFieldsStrict(raw.AuthInfoBytes, authInfo.ProtoReflect().Descriptor(), d.protoFiles) + err = RejectUnknownFieldsStrict(raw.AuthInfoBytes, authInfo.ProtoReflect().Descriptor(), fileResolver) if err != nil { return nil, errors.Wrap(ErrTxDecode, err.Error()) } @@ -116,15 +95,15 @@ func (d *Decoder) Decode(txBytes []byte) (*DecodedTx, error) { Signatures: raw.Signatures, } - var signers []string + var signers [][]byte var msgs []proto.Message for _, anyMsg := range body.Messages { - msg, signerErr := anyutil.Unpack(anyMsg, d.protoFiles, d.typeResolver) + msg, signerErr := anyutil.Unpack(anyMsg, fileResolver, d.signingCtx.TypeResolver()) if signerErr != nil { return nil, errors.Wrap(ErrTxDecode, signerErr.Error()) } msgs = append(msgs, msg) - ss, signerErr := d.getSignersCtx.GetSigners(msg) + ss, signerErr := d.signingCtx.GetSigners(msg) if signerErr != nil { return nil, errors.Wrap(ErrTxDecode, signerErr.Error()) } diff --git a/x/tx/decode/decode_test.go b/x/tx/decode/decode_test.go index a7169a9989..1c095030e6 100644 --- a/x/tx/decode/decode_test.go +++ b/x/tx/decode/decode_test.go @@ -1,6 +1,7 @@ package decode_test import ( + "encoding/hex" "fmt" "testing" @@ -9,8 +10,10 @@ import ( "cosmossdk.io/api/cosmos/crypto/secp256k1" signingv1beta1 "cosmossdk.io/api/cosmos/tx/signing/v1beta1" txv1beta1 "cosmossdk.io/api/cosmos/tx/v1beta1" + "cosmossdk.io/x/tx/decode" "cosmossdk.io/x/tx/internal/testpb" + "cosmossdk.io/x/tx/signing" "github.com/cosmos/cosmos-proto/anyutil" "github.com/stretchr/testify/require" @@ -36,6 +39,16 @@ func TestDecode(t *testing.T) { Sequence: accSeq, }) + signingCtx, err := signing.NewContext(signing.Options{ + AddressCodec: dummyAddressCodec{}, + ValidatorAddressCodec: dummyAddressCodec{}, + }) + require.NoError(t, err) + decoder, err := decode.NewDecoder(decode.Options{ + SigningContext: signingCtx, + }) + require.NoError(t, err) + testCases := []struct { name string msg proto.Message @@ -83,9 +96,6 @@ func TestDecode(t *testing.T) { txBytes, err := proto.Marshal(tx) require.NoError(t, err) - decoder, err := decode.NewDecoder(decode.Options{}) - require.NoError(t, err) - decodeTx, err := decoder.Decode(txBytes) if tc.error != "" { require.EqualError(t, err, tc.error) @@ -99,3 +109,13 @@ func TestDecode(t *testing.T) { }) } } + +type dummyAddressCodec struct{} + +func (d dummyAddressCodec) StringToBytes(text string) ([]byte, error) { + return hex.DecodeString(text) +} + +func (d dummyAddressCodec) BytesToString(bz []byte) (string, error) { + return hex.EncodeToString(bz), nil +} diff --git a/x/tx/internal/testpb/signers.proto b/x/tx/internal/testpb/signers.proto index 26b9867b2a..dfd6db0786 100644 --- a/x/tx/internal/testpb/signers.proto +++ b/x/tx/internal/testpb/signers.proto @@ -1,6 +1,7 @@ syntax = "proto3"; import "cosmos/msg/v1/msg.proto"; +import "cosmos_proto/cosmos.proto"; option go_package = "cosmossdk.io/x/tx/internal/testpb"; @@ -58,6 +59,12 @@ message BadSigner { option (cosmos.msg.v1.signer) = "signer"; bytes signer = 1; } + message NoSignerOption { bytes signer = 1; } + +message ValidatorSigner { + option (cosmos.msg.v1.signer) = "signer"; + string signer = 1 [(cosmos_proto.scalar) = "cosmos.ValidatorAddressString"]; +} \ No newline at end of file diff --git a/x/tx/internal/testpb/signers.pulsar.go b/x/tx/internal/testpb/signers.pulsar.go index b554e807f0..f7ce5db88e 100644 --- a/x/tx/internal/testpb/signers.pulsar.go +++ b/x/tx/internal/testpb/signers.pulsar.go @@ -4,6 +4,7 @@ package testpb import ( _ "cosmossdk.io/api/cosmos/msg/v1" fmt "fmt" + _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" @@ -1368,7 +1369,7 @@ func (x *NestedSigner_Inner) ProtoReflect() protoreflect.Message { } func (x *NestedSigner_Inner) slowProtoReflect() protoreflect.Message { - mi := &file_signers_proto_msgTypes[8] + mi := &file_signers_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2282,7 +2283,7 @@ func (x *RepeatedNestedSigner_Inner) ProtoReflect() protoreflect.Message { } func (x *RepeatedNestedSigner_Inner) slowProtoReflect() protoreflect.Message { - mi := &file_signers_proto_msgTypes[9] + mi := &file_signers_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3183,7 +3184,7 @@ func (x *NestedRepeatedSigner_Inner) ProtoReflect() protoreflect.Message { } func (x *NestedRepeatedSigner_Inner) slowProtoReflect() protoreflect.Message { - mi := &file_signers_proto_msgTypes[10] + mi := &file_signers_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4157,7 +4158,7 @@ func (x *RepeatedNestedRepeatedSigner_Inner) ProtoReflect() protoreflect.Message } func (x *RepeatedNestedRepeatedSigner_Inner) slowProtoReflect() protoreflect.Message { - mi := &file_signers_proto_msgTypes[11] + mi := &file_signers_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5415,6 +5416,426 @@ func (x *fastReflection_NoSignerOption) ProtoMethods() *protoiface.Methods { } } +var ( + md_ValidatorSigner protoreflect.MessageDescriptor + fd_ValidatorSigner_signer protoreflect.FieldDescriptor +) + +func init() { + file_signers_proto_init() + md_ValidatorSigner = File_signers_proto.Messages().ByName("ValidatorSigner") + fd_ValidatorSigner_signer = md_ValidatorSigner.Fields().ByName("signer") +} + +var _ protoreflect.Message = (*fastReflection_ValidatorSigner)(nil) + +type fastReflection_ValidatorSigner ValidatorSigner + +func (x *ValidatorSigner) ProtoReflect() protoreflect.Message { + return (*fastReflection_ValidatorSigner)(x) +} + +func (x *ValidatorSigner) slowProtoReflect() protoreflect.Message { + mi := &file_signers_proto_msgTypes[8] + 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_ValidatorSigner_messageType fastReflection_ValidatorSigner_messageType +var _ protoreflect.MessageType = fastReflection_ValidatorSigner_messageType{} + +type fastReflection_ValidatorSigner_messageType struct{} + +func (x fastReflection_ValidatorSigner_messageType) Zero() protoreflect.Message { + return (*fastReflection_ValidatorSigner)(nil) +} +func (x fastReflection_ValidatorSigner_messageType) New() protoreflect.Message { + return new(fastReflection_ValidatorSigner) +} +func (x fastReflection_ValidatorSigner_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_ValidatorSigner +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_ValidatorSigner) Descriptor() protoreflect.MessageDescriptor { + return md_ValidatorSigner +} + +// 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_ValidatorSigner) Type() protoreflect.MessageType { + return _fastReflection_ValidatorSigner_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_ValidatorSigner) New() protoreflect.Message { + return new(fastReflection_ValidatorSigner) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_ValidatorSigner) Interface() protoreflect.ProtoMessage { + return (*ValidatorSigner)(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_ValidatorSigner) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.Signer != "" { + value := protoreflect.ValueOfString(x.Signer) + if !f(fd_ValidatorSigner_signer, 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_ValidatorSigner) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "ValidatorSigner.signer": + return x.Signer != "" + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ValidatorSigner")) + } + panic(fmt.Errorf("message ValidatorSigner 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_ValidatorSigner) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "ValidatorSigner.signer": + x.Signer = "" + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ValidatorSigner")) + } + panic(fmt.Errorf("message ValidatorSigner 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_ValidatorSigner) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "ValidatorSigner.signer": + value := x.Signer + return protoreflect.ValueOfString(value) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ValidatorSigner")) + } + panic(fmt.Errorf("message ValidatorSigner 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_ValidatorSigner) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "ValidatorSigner.signer": + x.Signer = value.Interface().(string) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ValidatorSigner")) + } + panic(fmt.Errorf("message ValidatorSigner 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_ValidatorSigner) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ValidatorSigner.signer": + panic(fmt.Errorf("field signer of message ValidatorSigner is not mutable")) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ValidatorSigner")) + } + panic(fmt.Errorf("message ValidatorSigner 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_ValidatorSigner) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "ValidatorSigner.signer": + return protoreflect.ValueOfString("") + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: ValidatorSigner")) + } + panic(fmt.Errorf("message ValidatorSigner 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_ValidatorSigner) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in ValidatorSigner", 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_ValidatorSigner) 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_ValidatorSigner) 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_ValidatorSigner) 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_ValidatorSigner) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*ValidatorSigner) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + l = len(x.Signer) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*ValidatorSigner) + 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.Signer) > 0 { + i -= len(x.Signer) + copy(dAtA[i:], x.Signer) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.Signer))) + 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().(*ValidatorSigner) + 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: ValidatorSigner: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: ValidatorSigner: 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 Signer", 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.Signer = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.27.0 @@ -5708,6 +6129,41 @@ func (x *NoSignerOption) GetSigner() []byte { return nil } +type ValidatorSigner struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Signer string `protobuf:"bytes,1,opt,name=signer,proto3" json:"signer,omitempty"` +} + +func (x *ValidatorSigner) Reset() { + *x = ValidatorSigner{} + if protoimpl.UnsafeEnabled { + mi := &file_signers_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ValidatorSigner) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ValidatorSigner) ProtoMessage() {} + +// Deprecated: Use ValidatorSigner.ProtoReflect.Descriptor instead. +func (*ValidatorSigner) Descriptor() ([]byte, []int) { + return file_signers_proto_rawDescGZIP(), []int{8} +} + +func (x *ValidatorSigner) GetSigner() string { + if x != nil { + return x.Signer + } + return "" +} + type NestedSigner_Inner struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -5719,7 +6175,7 @@ type NestedSigner_Inner struct { func (x *NestedSigner_Inner) Reset() { *x = NestedSigner_Inner{} if protoimpl.UnsafeEnabled { - mi := &file_signers_proto_msgTypes[8] + mi := &file_signers_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5754,7 +6210,7 @@ type RepeatedNestedSigner_Inner struct { func (x *RepeatedNestedSigner_Inner) Reset() { *x = RepeatedNestedSigner_Inner{} if protoimpl.UnsafeEnabled { - mi := &file_signers_proto_msgTypes[9] + mi := &file_signers_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5789,7 +6245,7 @@ type NestedRepeatedSigner_Inner struct { func (x *NestedRepeatedSigner_Inner) Reset() { *x = NestedRepeatedSigner_Inner{} if protoimpl.UnsafeEnabled { - mi := &file_signers_proto_msgTypes[10] + mi := &file_signers_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5824,7 +6280,7 @@ type RepeatedNestedRepeatedSigner_Inner struct { func (x *RepeatedNestedRepeatedSigner_Inner) Reset() { *x = RepeatedNestedRepeatedSigner_Inner{} if protoimpl.UnsafeEnabled { - mi := &file_signers_proto_msgTypes[11] + mi := &file_signers_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5853,57 +6309,65 @@ var File_signers_proto protoreflect.FileDescriptor var file_signers_proto_rawDesc = []byte{ 0x0a, 0x0d, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x6d, 0x73, 0x67, 0x2f, 0x76, 0x31, 0x2f, 0x6d, - 0x73, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x33, 0x0a, 0x0c, 0x53, 0x69, 0x6d, 0x70, - 0x6c, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x69, 0x67, 0x6e, - 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, - 0x3a, 0x0b, 0x82, 0xe7, 0xb0, 0x2a, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x22, 0x35, 0x0a, - 0x0e, 0x52, 0x65, 0x70, 0x65, 0x61, 0x74, 0x65, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x12, + 0x73, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, + 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x22, 0x33, 0x0a, 0x0c, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x53, 0x69, 0x67, + 0x6e, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x3a, 0x0b, 0x82, 0xe7, 0xb0, + 0x2a, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x22, 0x35, 0x0a, 0x0e, 0x52, 0x65, 0x70, 0x65, + 0x61, 0x74, 0x65, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x69, + 0x67, 0x6e, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x73, 0x69, 0x67, 0x6e, + 0x65, 0x72, 0x3a, 0x0b, 0x82, 0xe7, 0xb0, 0x2a, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x22, + 0x73, 0x0a, 0x0c, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x12, + 0x29, 0x0a, 0x05, 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, + 0x2e, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x2e, 0x49, 0x6e, + 0x6e, 0x65, 0x72, 0x52, 0x05, 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x1a, 0x2c, 0x0a, 0x05, 0x49, 0x6e, + 0x6e, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x3a, 0x0b, 0x82, 0xe7, 0xb0, + 0x2a, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x3a, 0x0a, 0x82, 0xe7, 0xb0, 0x2a, 0x05, 0x69, + 0x6e, 0x6e, 0x65, 0x72, 0x22, 0x83, 0x01, 0x0a, 0x14, 0x52, 0x65, 0x70, 0x65, 0x61, 0x74, 0x65, + 0x64, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x12, 0x31, 0x0a, + 0x05, 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x52, + 0x65, 0x70, 0x65, 0x61, 0x74, 0x65, 0x64, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x53, 0x69, 0x67, + 0x6e, 0x65, 0x72, 0x2e, 0x49, 0x6e, 0x6e, 0x65, 0x72, 0x52, 0x05, 0x69, 0x6e, 0x6e, 0x65, 0x72, + 0x1a, 0x2c, 0x0a, 0x05, 0x49, 0x6e, 0x6e, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x69, 0x67, + 0x6e, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, + 0x72, 0x3a, 0x0b, 0x82, 0xe7, 0xb0, 0x2a, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x3a, 0x0a, + 0x82, 0xe7, 0xb0, 0x2a, 0x05, 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x22, 0x83, 0x01, 0x0a, 0x14, 0x4e, + 0x65, 0x73, 0x74, 0x65, 0x64, 0x52, 0x65, 0x70, 0x65, 0x61, 0x74, 0x65, 0x64, 0x53, 0x69, 0x67, + 0x6e, 0x65, 0x72, 0x12, 0x31, 0x0a, 0x05, 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x52, 0x65, 0x70, 0x65, 0x61, + 0x74, 0x65, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x2e, 0x49, 0x6e, 0x6e, 0x65, 0x72, 0x52, + 0x05, 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x1a, 0x2c, 0x0a, 0x05, 0x49, 0x6e, 0x6e, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x3a, 0x0b, 0x82, 0xe7, 0xb0, 0x2a, 0x06, 0x73, 0x69, - 0x67, 0x6e, 0x65, 0x72, 0x22, 0x73, 0x0a, 0x0c, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x53, 0x69, - 0x67, 0x6e, 0x65, 0x72, 0x12, 0x29, 0x0a, 0x05, 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x53, 0x69, 0x67, 0x6e, - 0x65, 0x72, 0x2e, 0x49, 0x6e, 0x6e, 0x65, 0x72, 0x52, 0x05, 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x1a, - 0x2c, 0x0a, 0x05, 0x49, 0x6e, 0x6e, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x69, 0x67, 0x6e, - 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, - 0x3a, 0x0b, 0x82, 0xe7, 0xb0, 0x2a, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x3a, 0x0a, 0x82, - 0xe7, 0xb0, 0x2a, 0x05, 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x22, 0x83, 0x01, 0x0a, 0x14, 0x52, 0x65, - 0x70, 0x65, 0x61, 0x74, 0x65, 0x64, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x53, 0x69, 0x67, 0x6e, - 0x65, 0x72, 0x12, 0x31, 0x0a, 0x05, 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x1b, 0x2e, 0x52, 0x65, 0x70, 0x65, 0x61, 0x74, 0x65, 0x64, 0x4e, 0x65, 0x73, 0x74, - 0x65, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x2e, 0x49, 0x6e, 0x6e, 0x65, 0x72, 0x52, 0x05, - 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x1a, 0x2c, 0x0a, 0x05, 0x49, 0x6e, 0x6e, 0x65, 0x72, 0x12, 0x16, - 0x0a, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x3a, 0x0b, 0x82, 0xe7, 0xb0, 0x2a, 0x06, 0x73, 0x69, 0x67, - 0x6e, 0x65, 0x72, 0x3a, 0x0a, 0x82, 0xe7, 0xb0, 0x2a, 0x05, 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x22, - 0x83, 0x01, 0x0a, 0x14, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x52, 0x65, 0x70, 0x65, 0x61, 0x74, - 0x65, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x12, 0x31, 0x0a, 0x05, 0x69, 0x6e, 0x6e, 0x65, - 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, - 0x52, 0x65, 0x70, 0x65, 0x61, 0x74, 0x65, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x2e, 0x49, - 0x6e, 0x6e, 0x65, 0x72, 0x52, 0x05, 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x1a, 0x2c, 0x0a, 0x05, 0x49, - 0x6e, 0x6e, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x3a, 0x0b, 0x82, 0xe7, - 0xb0, 0x2a, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x3a, 0x0a, 0x82, 0xe7, 0xb0, 0x2a, 0x05, - 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x22, 0x93, 0x01, 0x0a, 0x1c, 0x52, 0x65, 0x70, 0x65, 0x61, 0x74, - 0x65, 0x64, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x52, 0x65, 0x70, 0x65, 0x61, 0x74, 0x65, 0x64, - 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x12, 0x39, 0x0a, 0x05, 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x52, 0x65, 0x70, 0x65, 0x61, 0x74, 0x65, 0x64, - 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x52, 0x65, 0x70, 0x65, 0x61, 0x74, 0x65, 0x64, 0x53, 0x69, - 0x67, 0x6e, 0x65, 0x72, 0x2e, 0x49, 0x6e, 0x6e, 0x65, 0x72, 0x52, 0x05, 0x69, 0x6e, 0x6e, 0x65, - 0x72, 0x1a, 0x2c, 0x0a, 0x05, 0x49, 0x6e, 0x6e, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x69, - 0x67, 0x6e, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x73, 0x69, 0x67, 0x6e, - 0x65, 0x72, 0x3a, 0x0b, 0x82, 0xe7, 0xb0, 0x2a, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x3a, - 0x0a, 0x82, 0xe7, 0xb0, 0x2a, 0x05, 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x22, 0x30, 0x0a, 0x09, 0x42, - 0x61, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x69, 0x67, 0x6e, - 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, - 0x3a, 0x0b, 0x82, 0xe7, 0xb0, 0x2a, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x22, 0x28, 0x0a, - 0x0e, 0x4e, 0x6f, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x16, 0x0a, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x42, 0x3b, 0x42, 0x0c, 0x53, 0x69, 0x67, 0x6e, 0x65, - 0x72, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x29, 0x63, 0x6f, 0x73, 0x6d, 0x6f, - 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x78, 0x2f, 0x74, 0x78, 0x2f, 0x74, 0x65, 0x78, - 0x74, 0x75, 0x61, 0x6c, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, - 0x73, 0x74, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x67, 0x6e, 0x65, 0x72, 0x3a, 0x0a, 0x82, 0xe7, 0xb0, 0x2a, 0x05, 0x69, 0x6e, 0x6e, 0x65, 0x72, + 0x22, 0x93, 0x01, 0x0a, 0x1c, 0x52, 0x65, 0x70, 0x65, 0x61, 0x74, 0x65, 0x64, 0x4e, 0x65, 0x73, + 0x74, 0x65, 0x64, 0x52, 0x65, 0x70, 0x65, 0x61, 0x74, 0x65, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x65, + 0x72, 0x12, 0x39, 0x0a, 0x05, 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x23, 0x2e, 0x52, 0x65, 0x70, 0x65, 0x61, 0x74, 0x65, 0x64, 0x4e, 0x65, 0x73, 0x74, 0x65, + 0x64, 0x52, 0x65, 0x70, 0x65, 0x61, 0x74, 0x65, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x2e, + 0x49, 0x6e, 0x6e, 0x65, 0x72, 0x52, 0x05, 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x1a, 0x2c, 0x0a, 0x05, + 0x49, 0x6e, 0x6e, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x3a, 0x0b, 0x82, + 0xe7, 0xb0, 0x2a, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x3a, 0x0a, 0x82, 0xe7, 0xb0, 0x2a, + 0x05, 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x22, 0x30, 0x0a, 0x09, 0x42, 0x61, 0x64, 0x53, 0x69, 0x67, + 0x6e, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x3a, 0x0b, 0x82, 0xe7, 0xb0, + 0x2a, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x22, 0x28, 0x0a, 0x0e, 0x4e, 0x6f, 0x53, 0x69, + 0x67, 0x6e, 0x65, 0x72, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x69, + 0x67, 0x6e, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x73, 0x69, 0x67, 0x6e, + 0x65, 0x72, 0x22, 0x59, 0x0a, 0x0f, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x53, + 0x69, 0x67, 0x6e, 0x65, 0x72, 0x12, 0x39, 0x0a, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x21, 0xd2, 0xb4, 0x2d, 0x1d, 0x63, 0x6f, 0x73, 0x6d, 0x6f, + 0x73, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, + 0x3a, 0x0b, 0x82, 0xe7, 0xb0, 0x2a, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x42, 0x3b, 0x42, + 0x0c, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, + 0x29, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x78, 0x2f, + 0x74, 0x78, 0x2f, 0x74, 0x65, 0x78, 0x74, 0x75, 0x61, 0x6c, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, } var ( @@ -5918,7 +6382,7 @@ func file_signers_proto_rawDescGZIP() []byte { return file_signers_proto_rawDescData } -var file_signers_proto_msgTypes = make([]protoimpl.MessageInfo, 12) +var file_signers_proto_msgTypes = make([]protoimpl.MessageInfo, 13) var file_signers_proto_goTypes = []interface{}{ (*SimpleSigner)(nil), // 0: SimpleSigner (*RepeatedSigner)(nil), // 1: RepeatedSigner @@ -5928,16 +6392,17 @@ var file_signers_proto_goTypes = []interface{}{ (*RepeatedNestedRepeatedSigner)(nil), // 5: RepeatedNestedRepeatedSigner (*BadSigner)(nil), // 6: BadSigner (*NoSignerOption)(nil), // 7: NoSignerOption - (*NestedSigner_Inner)(nil), // 8: NestedSigner.Inner - (*RepeatedNestedSigner_Inner)(nil), // 9: RepeatedNestedSigner.Inner - (*NestedRepeatedSigner_Inner)(nil), // 10: NestedRepeatedSigner.Inner - (*RepeatedNestedRepeatedSigner_Inner)(nil), // 11: RepeatedNestedRepeatedSigner.Inner + (*ValidatorSigner)(nil), // 8: ValidatorSigner + (*NestedSigner_Inner)(nil), // 9: NestedSigner.Inner + (*RepeatedNestedSigner_Inner)(nil), // 10: RepeatedNestedSigner.Inner + (*NestedRepeatedSigner_Inner)(nil), // 11: NestedRepeatedSigner.Inner + (*RepeatedNestedRepeatedSigner_Inner)(nil), // 12: RepeatedNestedRepeatedSigner.Inner } var file_signers_proto_depIdxs = []int32{ - 8, // 0: NestedSigner.inner:type_name -> NestedSigner.Inner - 9, // 1: RepeatedNestedSigner.inner:type_name -> RepeatedNestedSigner.Inner - 10, // 2: NestedRepeatedSigner.inner:type_name -> NestedRepeatedSigner.Inner - 11, // 3: RepeatedNestedRepeatedSigner.inner:type_name -> RepeatedNestedRepeatedSigner.Inner + 9, // 0: NestedSigner.inner:type_name -> NestedSigner.Inner + 10, // 1: RepeatedNestedSigner.inner:type_name -> RepeatedNestedSigner.Inner + 11, // 2: NestedRepeatedSigner.inner:type_name -> NestedRepeatedSigner.Inner + 12, // 3: RepeatedNestedRepeatedSigner.inner:type_name -> RepeatedNestedRepeatedSigner.Inner 4, // [4:4] is the sub-list for method output_type 4, // [4:4] is the sub-list for method input_type 4, // [4:4] is the sub-list for extension type_name @@ -6048,7 +6513,7 @@ func file_signers_proto_init() { } } file_signers_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NestedSigner_Inner); i { + switch v := v.(*ValidatorSigner); i { case 0: return &v.state case 1: @@ -6060,7 +6525,7 @@ func file_signers_proto_init() { } } file_signers_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RepeatedNestedSigner_Inner); i { + switch v := v.(*NestedSigner_Inner); i { case 0: return &v.state case 1: @@ -6072,7 +6537,7 @@ func file_signers_proto_init() { } } file_signers_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NestedRepeatedSigner_Inner); i { + switch v := v.(*RepeatedNestedSigner_Inner); i { case 0: return &v.state case 1: @@ -6084,6 +6549,18 @@ func file_signers_proto_init() { } } file_signers_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NestedRepeatedSigner_Inner); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_signers_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*RepeatedNestedRepeatedSigner_Inner); i { case 0: return &v.state @@ -6102,7 +6579,7 @@ func file_signers_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_signers_proto_rawDesc, NumEnums: 0, - NumMessages: 12, + NumMessages: 13, NumExtensions: 0, NumServices: 0, }, diff --git a/x/tx/signing/context.go b/x/tx/signing/context.go new file mode 100644 index 0000000000..c8afe2e838 --- /dev/null +++ b/x/tx/signing/context.go @@ -0,0 +1,320 @@ +package signing + +import ( + "errors" + "fmt" + + "cosmossdk.io/core/address" + cosmos_proto "github.com/cosmos/cosmos-proto" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/reflect/protodesc" + "google.golang.org/protobuf/reflect/protoreflect" + "google.golang.org/protobuf/reflect/protoregistry" + "google.golang.org/protobuf/types/dynamicpb" + + msgv1 "cosmossdk.io/api/cosmos/msg/v1" +) + +// Context is a context for retrieving the list of signers from a +// message where signers are specified by the cosmos.msg.v1.signer protobuf +// option. It also contains the ProtoFileResolver and address.Codec's used +// for resolving message descriptors and converting addresses. +type Context struct { + fileResolver ProtoFileResolver + typeResolver protoregistry.MessageTypeResolver + addressCodec address.Codec + validatorAddressCodec address.Codec + getSignersFuncs map[protoreflect.FullName]getSignersFunc +} + +// Options are options for creating Context which will be used for signing operations. +type Options struct { + // FileResolver is the protobuf file resolver to use for resolving message descriptors. + // If it is nil, the global protobuf registry will be used. + FileResolver ProtoFileResolver + + // TypeResolver is the protobuf type resolver to use for resolving message types. + TypeResolver protoregistry.MessageTypeResolver + + // AddressCodec is the codec for converting addresses between strings and bytes. + AddressCodec address.Codec + + // ValidatorAddressCodec is the codec for converting validator addresses between strings and bytes. + ValidatorAddressCodec address.Codec +} + +// ProtoFileResolver is a protodesc.Resolver that also allows iterating over all +// files descriptors. It is a subset of the methods supported by protoregistry.Files. +type ProtoFileResolver interface { + protodesc.Resolver + RangeFiles(func(protoreflect.FileDescriptor) bool) +} + +// NewContext creates a new Context using the provided options. +func NewContext(options Options) (*Context, error) { + protoFiles := options.FileResolver + if protoFiles == nil { + protoFiles = protoregistry.GlobalFiles + } + + protoTypes := options.TypeResolver + if protoTypes == nil { + protoTypes = protoregistry.GlobalTypes + } + + if options.AddressCodec == nil { + return nil, errors.New("address codec is required") + } + + if options.ValidatorAddressCodec == nil { + return nil, errors.New("validator address codec is required") + } + + c := &Context{ + fileResolver: protoFiles, + typeResolver: protoTypes, + addressCodec: options.AddressCodec, + validatorAddressCodec: options.ValidatorAddressCodec, + getSignersFuncs: map[protoreflect.FullName]getSignersFunc{}, + } + + return c, c.init() +} + +type getSignersFunc func(proto.Message) ([][]byte, error) + +func getSignersFieldNames(descriptor protoreflect.MessageDescriptor) ([]string, error) { + signersFields := proto.GetExtension(descriptor.Options(), msgv1.E_Signer).([]string) + if len(signersFields) == 0 { + return nil, fmt.Errorf("no cosmos.msg.v1.signer option found for message %s", descriptor.FullName()) + } + + return signersFields, nil +} + +// init performs a dry run of getting all msg's signers. This has 2 benefits: +// - it will error if any Msg has forgotten the "cosmos.msg.v1.signer" +// annotation +// - it will pre-populate the context's internal cache for getSignersFuncs +// so that calling it in antehandlers will be faster. +func (c *Context) init() error { + var errs []error + c.fileResolver.RangeFiles(func(fd protoreflect.FileDescriptor) bool { + for i := 0; i < fd.Services().Len(); i++ { + sd := fd.Services().Get(i) + // We use the heuristic that services named "Msg" are exactly the + // ones that need the proto annotation check. + if sd.Name() != "Msg" { + continue + } + + for j := 0; j < sd.Methods().Len(); j++ { + md := sd.Methods().Get(j).Input() + msg := dynamicpb.NewMessage(md) + _, err := c.GetSigners(msg) + if err != nil { + errs = append(errs, err) + } + } + } + + return true + }) + + return errors.Join(errs...) +} + +func (c *Context) makeGetSignersFunc(descriptor protoreflect.MessageDescriptor) (getSignersFunc, error) { + signersFields, err := getSignersFieldNames(descriptor) + if err != nil { + return nil, err + } + + fieldGetters := make([]func(proto.Message, [][]byte) ([][]byte, error), len(signersFields)) + for i, fieldName := range signersFields { + field := descriptor.Fields().ByName(protoreflect.Name(fieldName)) + if field == nil { + return nil, fmt.Errorf("field %s not found in message %s", fieldName, descriptor.FullName()) + } + + if field.IsMap() || field.HasOptionalKeyword() { + return nil, fmt.Errorf("cosmos.msg.v1.signer field %s in message %s must not be a map or optional", fieldName, descriptor.FullName()) + } + + switch field.Kind() { + case protoreflect.StringKind: + addrCdc := c.getAddressCodec(field) + if field.IsList() { + fieldGetters[i] = func(msg proto.Message, arr [][]byte) ([][]byte, error) { + signers := msg.ProtoReflect().Get(field).List() + n := signers.Len() + for i := 0; i < n; i++ { + addrStr := signers.Get(i).String() + addrBz, err := addrCdc.StringToBytes(addrStr) + if err != nil { + return nil, err + } + arr = append(arr, addrBz) + } + return arr, nil + } + } else { + fieldGetters[i] = func(msg proto.Message, arr [][]byte) ([][]byte, error) { + addrStr := msg.ProtoReflect().Get(field).String() + addrBz, err := addrCdc.StringToBytes(addrStr) + if err != nil { + return nil, err + } + return append(arr, addrBz), nil + } + } + case protoreflect.MessageKind: + isList := field.IsList() + nestedMessage := field.Message() + nestedSignersFields, err := getSignersFieldNames(nestedMessage) + if err != nil { + return nil, err + } + + if len(nestedSignersFields) != 1 { + return nil, fmt.Errorf("nested cosmos.msg.v1.signer option in message %s must contain only one value", nestedMessage.FullName()) + } + + nestedFieldName := nestedSignersFields[0] + nestedField := nestedMessage.Fields().ByName(protoreflect.Name(nestedFieldName)) + nestedIsList := nestedField.IsList() + if nestedField == nil { + return nil, fmt.Errorf("field %s not found in message %s", nestedFieldName, nestedMessage.FullName()) + } + + if nestedField.Kind() != protoreflect.StringKind || nestedField.IsMap() || nestedField.HasOptionalKeyword() { + return nil, fmt.Errorf("nested signer field %s in message %s must be a simple string", nestedFieldName, nestedMessage.FullName()) + } + + addrCdc := c.getAddressCodec(nestedField) + + if isList { + if nestedIsList { + fieldGetters[i] = func(msg proto.Message, arr [][]byte) ([][]byte, error) { + msgs := msg.ProtoReflect().Get(field).List() + m := msgs.Len() + for i := 0; i < m; i++ { + signers := msgs.Get(i).Message().Get(nestedField).List() + n := signers.Len() + for j := 0; j < n; j++ { + addrStr := signers.Get(j).String() + addrBz, err := addrCdc.StringToBytes(addrStr) + if err != nil { + return nil, err + } + arr = append(arr, addrBz) + } + } + return arr, nil + } + } else { + fieldGetters[i] = func(msg proto.Message, arr [][]byte) ([][]byte, error) { + msgs := msg.ProtoReflect().Get(field).List() + m := msgs.Len() + for i := 0; i < m; i++ { + addrStr := msgs.Get(i).Message().Get(nestedField).String() + addrBz, err := addrCdc.StringToBytes(addrStr) + if err != nil { + return nil, err + } + arr = append(arr, addrBz) + } + return arr, nil + } + } + } else { + if nestedIsList { + fieldGetters[i] = func(msg proto.Message, arr [][]byte) ([][]byte, error) { + nestedMsg := msg.ProtoReflect().Get(field).Message() + signers := nestedMsg.Get(nestedField).List() + n := signers.Len() + for j := 0; j < n; j++ { + addrStr := signers.Get(j).String() + addrBz, err := addrCdc.StringToBytes(addrStr) + if err != nil { + return nil, err + } + arr = append(arr, addrBz) + } + return arr, nil + } + } else { + fieldGetters[i] = func(msg proto.Message, arr [][]byte) ([][]byte, error) { + addrStr := msg.ProtoReflect().Get(field).Message().Get(nestedField).String() + addrBz, err := addrCdc.StringToBytes(addrStr) + if err != nil { + return nil, err + } + return append(arr, addrBz), nil + } + } + } + + default: + return nil, fmt.Errorf("unexpected field type %s for field %s in message %s", field.Kind(), fieldName, descriptor.FullName()) + } + } + + return func(message proto.Message) ([][]byte, error) { + var signers [][]byte + for _, getter := range fieldGetters { + signers, err = getter(message, signers) + if err != nil { + return nil, err + } + } + return signers, nil + }, nil +} + +func (c *Context) getAddressCodec(field protoreflect.FieldDescriptor) address.Codec { + scalarOpt := proto.GetExtension(field.Options(), cosmos_proto.E_Scalar) + addrCdc := c.addressCodec + if scalarOpt != nil { + if scalarOpt.(string) == "cosmos.ValidatorAddressString" { + addrCdc = c.validatorAddressCodec + } + } + + return addrCdc +} + +// GetSigners returns the signers for a given message. +func (c *Context) GetSigners(msg proto.Message) ([][]byte, error) { + messageDescriptor := msg.ProtoReflect().Descriptor() + f, ok := c.getSignersFuncs[messageDescriptor.FullName()] + if !ok { + var err error + f, err = c.makeGetSignersFunc(messageDescriptor) + if err != nil { + return nil, err + } + c.getSignersFuncs[messageDescriptor.FullName()] = f + } + + return f(msg) +} + +// AddressCodec returns the address codec used by the context. +func (c *Context) AddressCodec() address.Codec { + return c.addressCodec +} + +// ValidatorAddressCodec returns the validator address codec used by the context. +func (c *Context) ValidatorAddressCodec() address.Codec { + return c.validatorAddressCodec +} + +// FileResolver returns the proto file resolver used by the context. +func (c *Context) FileResolver() ProtoFileResolver { + return c.fileResolver +} + +func (c *Context) TypeResolver() protoregistry.MessageTypeResolver { + return c.typeResolver +} diff --git a/x/tx/signing/context_test.go b/x/tx/signing/context_test.go new file mode 100644 index 0000000000..a5979e300d --- /dev/null +++ b/x/tx/signing/context_test.go @@ -0,0 +1,170 @@ +package signing + +import ( + "encoding/hex" + "strings" + "testing" + + bankv1beta1 "cosmossdk.io/api/cosmos/bank/v1beta1" + groupv1 "cosmossdk.io/api/cosmos/group/v1" + "cosmossdk.io/core/address" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/proto" + + "cosmossdk.io/x/tx/internal/testpb" +) + +func TestGetSigners(t *testing.T) { + ctx, err := NewContext(Options{ + AddressCodec: dummyAddressCodec{}, + ValidatorAddressCodec: dummyValidatorAddressCodec{}, + }) + require.NoError(t, err) + tests := []struct { + name string + msg proto.Message + want [][]byte + wantErr bool + }{ + { + name: "MsgSend", + msg: &bankv1beta1.MsgSend{ + FromAddress: hex.EncodeToString([]byte("foo")), + }, + want: [][]byte{[]byte("foo")}, + }, + { + name: "MsgMultiSend", + msg: &bankv1beta1.MsgMultiSend{ + Inputs: []*bankv1beta1.Input{ + {Address: hex.EncodeToString([]byte("foo"))}, + {Address: hex.EncodeToString([]byte("bar"))}, + }, + }, + want: [][]byte{[]byte("foo"), []byte("bar")}, + }, + { + name: "MsgSubmitProposal", + msg: &groupv1.MsgSubmitProposal{ + Proposers: []string{ + hex.EncodeToString([]byte("foo")), + hex.EncodeToString([]byte("bar")), + }, + }, + want: [][]byte{[]byte("foo"), []byte("bar")}, + }, + { + name: "simple", + msg: &testpb.SimpleSigner{Signer: hex.EncodeToString([]byte("foo"))}, + want: [][]byte{[]byte("foo")}, + }, + { + name: "repeated", + msg: &testpb.RepeatedSigner{Signer: []string{ + hex.EncodeToString([]byte("foo")), + hex.EncodeToString([]byte("bar")), + }}, + want: [][]byte{[]byte("foo"), []byte("bar")}, + }, + { + name: "nested", + msg: &testpb.NestedSigner{Inner: &testpb.NestedSigner_Inner{Signer: hex.EncodeToString([]byte("foo"))}}, + want: [][]byte{[]byte("foo")}, + }, + { + name: "nested repeated", + msg: &testpb.NestedRepeatedSigner{Inner: &testpb.NestedRepeatedSigner_Inner{Signer: []string{ + hex.EncodeToString([]byte("foo")), + hex.EncodeToString([]byte("bar")), + }}}, + want: [][]byte{[]byte("foo"), []byte("bar")}, + }, + { + name: "repeated nested", + msg: &testpb.RepeatedNestedSigner{Inner: []*testpb.RepeatedNestedSigner_Inner{ + {Signer: hex.EncodeToString([]byte("foo"))}, + {Signer: hex.EncodeToString([]byte("bar"))}, + }}, + want: [][]byte{[]byte("foo"), []byte("bar")}, + }, + { + name: "nested repeated", + msg: &testpb.NestedRepeatedSigner{Inner: &testpb.NestedRepeatedSigner_Inner{ + Signer: []string{ + hex.EncodeToString([]byte("foo")), + hex.EncodeToString([]byte("bar")), + }, + }}, + want: [][]byte{[]byte("foo"), []byte("bar")}, + }, + { + name: "repeated nested repeated", + msg: &testpb.RepeatedNestedRepeatedSigner{Inner: []*testpb.RepeatedNestedRepeatedSigner_Inner{ + {Signer: []string{ + hex.EncodeToString([]byte("foo")), + hex.EncodeToString([]byte("bar")), + }}, + {Signer: []string{ + hex.EncodeToString([]byte("baz")), + hex.EncodeToString([]byte("bam")), + }}, + {Signer: []string{ + hex.EncodeToString([]byte("blah")), + }}, + }}, + want: [][]byte{[]byte("foo"), []byte("bar"), []byte("baz"), []byte("bam"), []byte("blah")}, + }, + { + name: "bad", + msg: &testpb.BadSigner{}, + wantErr: true, + }, + { + name: "no signer", + msg: &testpb.NoSignerOption{}, + wantErr: true, + }, + { + name: "validator signer", + msg: &testpb.ValidatorSigner{ + Signer: "val" + hex.EncodeToString([]byte("foo")), + }, + want: [][]byte{[]byte("foo")}, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + signers, err := ctx.GetSigners(test.msg) + if test.wantErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + require.Equal(t, test.want, signers) + }) + } +} + +type dummyAddressCodec struct{} + +func (d dummyAddressCodec) StringToBytes(text string) ([]byte, error) { + return hex.DecodeString(text) +} + +func (d dummyAddressCodec) BytesToString(bz []byte) (string, error) { + return hex.EncodeToString(bz), nil +} + +var _ address.Codec = dummyAddressCodec{} + +type dummyValidatorAddressCodec struct{} + +func (d dummyValidatorAddressCodec) StringToBytes(text string) ([]byte, error) { + return hex.DecodeString(strings.TrimPrefix(text, "val")) +} + +func (d dummyValidatorAddressCodec) BytesToString(bz []byte) (string, error) { + return "val" + hex.EncodeToString(bz), nil +} + +var _ address.Codec = dummyValidatorAddressCodec{} diff --git a/x/tx/signing/directaux/direct_aux.go b/x/tx/signing/directaux/direct_aux.go index 8738834906..f20b56f513 100644 --- a/x/tx/signing/directaux/direct_aux.go +++ b/x/tx/signing/directaux/direct_aux.go @@ -16,32 +16,30 @@ import ( // SignModeHandler is the SIGN_MODE_DIRECT_AUX implementation of signing.SignModeHandler. type SignModeHandler struct { - signersContext *signing.GetSignersContext + signersContext *signing.Context fileResolver signing.ProtoFileResolver typeResolver protoregistry.MessageTypeResolver } // SignModeHandlerOptions are the options for the SignModeHandler. type SignModeHandlerOptions struct { - // FileResolver is the protodesc.Resolver to use for resolving proto files when unpacking any messages. - FileResolver signing.ProtoFileResolver - - // TypeResolver is the protoregistry.MessageTypeResolver to use for resolving proto types when unpacking any messages. + // TypeResolver is the protoregistry.MessageTypeResolver to use for resolving protobuf types when unpacking any messages. TypeResolver protoregistry.MessageTypeResolver - // SignersContext is the signing.GetSignersContext to use for getting signers. - SignersContext *signing.GetSignersContext + // SignersContext is the signing.Context to use for getting signers. + SignersContext *signing.Context } // NewSignModeHandler returns a new SignModeHandler. func NewSignModeHandler(options SignModeHandlerOptions) (SignModeHandler, error) { h := SignModeHandler{} - if options.FileResolver == nil { - h.fileResolver = protoregistry.GlobalFiles - } else { - h.fileResolver = options.FileResolver + if options.SignersContext == nil { + return h, fmt.Errorf("signers context is required") } + h.signersContext = options.SignersContext + + h.fileResolver = h.signersContext.FileResolver() if options.TypeResolver == nil { h.typeResolver = protoregistry.GlobalTypes @@ -49,16 +47,6 @@ func NewSignModeHandler(options SignModeHandlerOptions) (SignModeHandler, error) h.typeResolver = options.TypeResolver } - if options.SignersContext == nil { - var err error - h.signersContext, err = signing.NewGetSignersContext(signing.GetSignersOptions{ProtoFiles: h.fileResolver}) - if err != nil { - return h, err - } - } else { - h.signersContext = options.SignersContext - } - return h, nil } @@ -71,18 +59,18 @@ func (h SignModeHandler) Mode() signingv1beta1.SignMode { // getFirstSigner returns the first signer from the first message in the tx. It replicates behavior in // https://github.com/cosmos/cosmos-sdk/blob/4a6a1e3cb8de459891cb0495052589673d14ef51/x/auth/tx/builder.go#L142 -func (h SignModeHandler) getFirstSigner(txData signing.TxData) (string, error) { +func (h SignModeHandler) getFirstSigner(txData signing.TxData) ([]byte, error) { if len(txData.Body.Messages) == 0 { - return "", fmt.Errorf("no signer found") + return nil, fmt.Errorf("no signer found") } msg, err := anyutil.Unpack(txData.Body.Messages[0], h.fileResolver, h.typeResolver) if err != nil { - return "", err + return nil, err } signer, err := h.signersContext.GetSigners(msg) if err != nil { - return "", err + return nil, err } return signer[0], nil } @@ -97,7 +85,10 @@ func (h SignModeHandler) GetSignBytes( if err != nil { return nil, err } - feePayer = fp + feePayer, err = h.signersContext.AddressCodec().BytesToString(fp) + if err != nil { + return nil, err + } } if feePayer == signerData.Address { return nil, fmt.Errorf("fee payer %s cannot sign with %s: unauthorized", diff --git a/x/tx/signing/directaux/direct_aux_test.go b/x/tx/signing/directaux/direct_aux_test.go index 2f7ca5440b..4fba90b7e1 100644 --- a/x/tx/signing/directaux/direct_aux_test.go +++ b/x/tx/signing/directaux/direct_aux_test.go @@ -2,9 +2,11 @@ package directaux_test import ( "context" + "encoding/hex" "fmt" "testing" + "cosmossdk.io/core/address" "github.com/cosmos/cosmos-proto/anyutil" "github.com/stretchr/testify/require" "google.golang.org/protobuf/proto" @@ -15,6 +17,7 @@ import ( "cosmossdk.io/api/cosmos/crypto/secp256k1" signingv1beta1 "cosmossdk.io/api/cosmos/tx/signing/v1beta1" txv1beta1 "cosmossdk.io/api/cosmos/tx/v1beta1" + "cosmossdk.io/x/tx/signing" "cosmossdk.io/x/tx/signing/directaux" ) @@ -83,7 +86,14 @@ func TestDirectAuxHandler(t *testing.T) { AuthInfoBytes: authInfoBz, BodyBytes: bodyBz, } - modeHandler, err := directaux.NewSignModeHandler(directaux.SignModeHandlerOptions{}) + signersCtx, err := signing.NewContext(signing.Options{ + AddressCodec: dummyAddressCodec{}, + ValidatorAddressCodec: dummyAddressCodec{}, + }) + require.NoError(t, err) + modeHandler, err := directaux.NewSignModeHandler(directaux.SignModeHandlerOptions{ + SignersContext: signersCtx, + }) require.NoError(t, err) t.Log("verify fee payer cannot use SIGN_MODE_DIRECT_AUX") @@ -143,3 +153,15 @@ func TestDirectAuxHandler(t *testing.T) { require.NoError(t, err) require.NotEqual(t, expectedSignBytes, signBytes) } + +type dummyAddressCodec struct{} + +func (d dummyAddressCodec) StringToBytes(text string) ([]byte, error) { + return hex.DecodeString(text) +} + +func (d dummyAddressCodec) BytesToString(bz []byte) (string, error) { + return hex.EncodeToString(bz), nil +} + +var _ address.Codec = dummyAddressCodec{} diff --git a/x/tx/signing/get_signers.go b/x/tx/signing/get_signers.go deleted file mode 100644 index eabd70ed03..0000000000 --- a/x/tx/signing/get_signers.go +++ /dev/null @@ -1,222 +0,0 @@ -package signing - -import ( - "errors" - "fmt" - - "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/reflect/protodesc" - "google.golang.org/protobuf/reflect/protoreflect" - "google.golang.org/protobuf/reflect/protoregistry" - "google.golang.org/protobuf/types/dynamicpb" - - msgv1 "cosmossdk.io/api/cosmos/msg/v1" -) - -// GetSignersContext is a context for retrieving the list of signers from a -// message where signers are specified by the cosmos.msg.v1.signer protobuf -// option. -type GetSignersContext struct { - protoFiles ProtoFileResolver - getSignersFuncs map[protoreflect.FullName]getSignersFunc -} - -// GetSignersOptions are options for creating GetSignersContext. -type GetSignersOptions struct { - // ProtoFiles are the protobuf files to use for resolving message descriptors. - // If it is nil, the global protobuf registry will be used. - ProtoFiles ProtoFileResolver -} - -// ProtoFileResolver is a protodesc.Resolver that also allows iterating over all -// files descriptors. It is a subset of the methods supported by protoregistry.Files. -type ProtoFileResolver interface { - protodesc.Resolver - RangeFiles(func(protoreflect.FileDescriptor) bool) -} - -// NewGetSignersContext creates a new GetSignersContext using the provided options. -func NewGetSignersContext(options GetSignersOptions) (*GetSignersContext, error) { - protoFiles := options.ProtoFiles - if protoFiles == nil { - protoFiles = protoregistry.GlobalFiles - } - - c := &GetSignersContext{ - protoFiles: protoFiles, - getSignersFuncs: map[protoreflect.FullName]getSignersFunc{}, - } - - return c, c.init() -} - -type getSignersFunc func(proto.Message) []string - -func getSignersFieldNames(descriptor protoreflect.MessageDescriptor) ([]string, error) { - signersFields := proto.GetExtension(descriptor.Options(), msgv1.E_Signer).([]string) - if len(signersFields) == 0 { - return nil, fmt.Errorf("no cosmos.msg.v1.signer option found for message %s", descriptor.FullName()) - } - - return signersFields, nil -} - -// init performs a dry run of getting all msg's signers. This has 2 benefits: -// - it will error if any Msg has forgotten the "cosmos.msg.v1.signer" -// annotation -// - it will pre-populate the context's internal cache for getSignersFuncs -// so that calling it in antehandlers will be faster. -func (c *GetSignersContext) init() error { - var errs []error - c.protoFiles.RangeFiles(func(fd protoreflect.FileDescriptor) bool { - for i := 0; i < fd.Services().Len(); i++ { - sd := fd.Services().Get(i) - // We use the heuristic that services named "Msg" are exactly the - // ones that need the proto annotation check. - if sd.Name() != "Msg" { - continue - } - - for j := 0; j < sd.Methods().Len(); j++ { - md := sd.Methods().Get(j).Input() - msg := dynamicpb.NewMessage(md) - _, err := c.GetSigners(msg) - if err != nil { - errs = append(errs, err) - } - } - } - - return true - }) - - return errors.Join(errs...) -} - -func (*GetSignersContext) makeGetSignersFunc(descriptor protoreflect.MessageDescriptor) (getSignersFunc, error) { - signersFields, err := getSignersFieldNames(descriptor) - if err != nil { - return nil, err - } - - fieldGetters := make([]func(proto.Message, []string) []string, len(signersFields)) - for i, fieldName := range signersFields { - field := descriptor.Fields().ByName(protoreflect.Name(fieldName)) - if field == nil { - return nil, fmt.Errorf("field %s not found in message %s", fieldName, descriptor.FullName()) - } - - if field.IsMap() || field.HasOptionalKeyword() { - return nil, fmt.Errorf("cosmos.msg.v1.signer field %s in message %s must not be a map or optional", fieldName, descriptor.FullName()) - } - - switch field.Kind() { - case protoreflect.StringKind: - if field.IsList() { - fieldGetters[i] = func(msg proto.Message, arr []string) []string { - signers := msg.ProtoReflect().Get(field).List() - n := signers.Len() - for i := 0; i < n; i++ { - arr = append(arr, signers.Get(i).String()) - } - return arr - } - } else { - fieldGetters[i] = func(msg proto.Message, arr []string) []string { - return append(arr, msg.ProtoReflect().Get(field).String()) - } - } - case protoreflect.MessageKind: - isList := field.IsList() - nestedMessage := field.Message() - nestedSignersFields, err := getSignersFieldNames(nestedMessage) - if err != nil { - return nil, err - } - - if len(nestedSignersFields) != 1 { - return nil, fmt.Errorf("nested cosmos.msg.v1.signer option in message %s must contain only one value", nestedMessage.FullName()) - } - - nestedFieldName := nestedSignersFields[0] - nestedField := nestedMessage.Fields().ByName(protoreflect.Name(nestedFieldName)) - nestedIsList := nestedField.IsList() - if nestedField == nil { - return nil, fmt.Errorf("field %s not found in message %s", nestedFieldName, nestedMessage.FullName()) - } - - if nestedField.Kind() != protoreflect.StringKind || nestedField.IsMap() || nestedField.HasOptionalKeyword() { - return nil, fmt.Errorf("nested signer field %s in message %s must be a simple string", nestedFieldName, nestedMessage.FullName()) - } - - if isList { - if nestedIsList { - fieldGetters[i] = func(msg proto.Message, arr []string) []string { - msgs := msg.ProtoReflect().Get(field).List() - m := msgs.Len() - for i := 0; i < m; i++ { - signers := msgs.Get(i).Message().Get(nestedField).List() - n := signers.Len() - for j := 0; j < n; j++ { - arr = append(arr, signers.Get(j).String()) - } - } - return arr - } - } else { - fieldGetters[i] = func(msg proto.Message, arr []string) []string { - msgs := msg.ProtoReflect().Get(field).List() - m := msgs.Len() - for i := 0; i < m; i++ { - arr = append(arr, msgs.Get(i).Message().Get(nestedField).String()) - } - return arr - } - } - } else { - if nestedIsList { - fieldGetters[i] = func(msg proto.Message, arr []string) []string { - nestedMsg := msg.ProtoReflect().Get(field).Message() - signers := nestedMsg.Get(nestedField).List() - n := signers.Len() - for j := 0; j < n; j++ { - arr = append(arr, signers.Get(j).String()) - } - return arr - } - } else { - fieldGetters[i] = func(msg proto.Message, arr []string) []string { - return append(arr, msg.ProtoReflect().Get(field).Message().Get(nestedField).String()) - } - } - } - - default: - return nil, fmt.Errorf("unexpected field type %s for field %s in message %s", field.Kind(), fieldName, descriptor.FullName()) - } - } - - return func(message proto.Message) []string { - var signers []string - for _, getter := range fieldGetters { - signers = getter(message, signers) - } - return signers - }, nil -} - -// GetSigners returns the signers for a given message. -func (c *GetSignersContext) GetSigners(msg proto.Message) ([]string, error) { - messageDescriptor := msg.ProtoReflect().Descriptor() - f, ok := c.getSignersFuncs[messageDescriptor.FullName()] - if !ok { - var err error - f, err = c.makeGetSignersFunc(messageDescriptor) - if err != nil { - return nil, err - } - c.getSignersFuncs[messageDescriptor.FullName()] = f - } - - return f(msg), nil -} diff --git a/x/tx/signing/get_signers_test.go b/x/tx/signing/get_signers_test.go deleted file mode 100644 index f52fe54542..0000000000 --- a/x/tx/signing/get_signers_test.go +++ /dev/null @@ -1,113 +0,0 @@ -package signing - -import ( - "testing" - - bankv1beta1 "cosmossdk.io/api/cosmos/bank/v1beta1" - groupv1 "cosmossdk.io/api/cosmos/group/v1" - "github.com/stretchr/testify/require" - "google.golang.org/protobuf/proto" - - "cosmossdk.io/x/tx/internal/testpb" -) - -func TestGetSigners(t *testing.T) { - ctx, err := NewGetSignersContext(GetSignersOptions{}) - require.NoError(t, err) - tests := []struct { - name string - msg proto.Message - want []string - wantErr bool - }{ - { - name: "MsgSend", - msg: &bankv1beta1.MsgSend{ - FromAddress: "foo", - }, - want: []string{"foo"}, - }, - { - name: "MsgMultiSend", - msg: &bankv1beta1.MsgMultiSend{ - Inputs: []*bankv1beta1.Input{ - {Address: "foo"}, - {Address: "bar"}, - }, - }, - want: []string{"foo", "bar"}, - }, - { - name: "MsgSubmitProposal", - msg: &groupv1.MsgSubmitProposal{ - Proposers: []string{"foo", "bar"}, - }, - want: []string{"foo", "bar"}, - }, - { - name: "simple", - msg: &testpb.SimpleSigner{Signer: "foo"}, - want: []string{"foo"}, - }, - { - name: "repeated", - msg: &testpb.RepeatedSigner{Signer: []string{"foo", "bar"}}, - want: []string{"foo", "bar"}, - }, - { - name: "nested", - msg: &testpb.NestedSigner{Inner: &testpb.NestedSigner_Inner{Signer: "foo"}}, - want: []string{"foo"}, - }, - { - name: "nested repeated", - msg: &testpb.NestedRepeatedSigner{Inner: &testpb.NestedRepeatedSigner_Inner{Signer: []string{"foo", "bar"}}}, - want: []string{"foo", "bar"}, - }, - { - name: "repeated nested", - msg: &testpb.RepeatedNestedSigner{Inner: []*testpb.RepeatedNestedSigner_Inner{ - {Signer: "foo"}, - {Signer: "bar"}, - }}, - want: []string{"foo", "bar"}, - }, - { - name: "nested repeated", - msg: &testpb.NestedRepeatedSigner{Inner: &testpb.NestedRepeatedSigner_Inner{ - Signer: []string{"foo", "bar"}, - }}, - want: []string{"foo", "bar"}, - }, - { - name: "repeated nested repeated", - msg: &testpb.RepeatedNestedRepeatedSigner{Inner: []*testpb.RepeatedNestedRepeatedSigner_Inner{ - {Signer: []string{"foo", "bar"}}, - {Signer: []string{"baz", "bam"}}, - {Signer: []string{"blah"}}, - }}, - want: []string{"foo", "bar", "baz", "bam", "blah"}, - }, - { - name: "bad", - msg: &testpb.BadSigner{}, - wantErr: true, - }, - { - name: "no signer", - msg: &testpb.NoSignerOption{}, - wantErr: true, - }, - } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - signers, err := ctx.GetSigners(test.msg) - if test.wantErr { - require.Error(t, err) - } else { - require.NoError(t, err) - } - require.Equal(t, test.want, signers) - }) - } -}