github.com/cosmos/cosmos-sdk@v0.50.10/codec/proto_codec.go (about)

     1  package codec
     2  
     3  import (
     4  	"encoding/binary"
     5  	"errors"
     6  	"fmt"
     7  	"strings"
     8  
     9  	"github.com/cosmos/cosmos-proto/anyutil"
    10  	"github.com/cosmos/gogoproto/jsonpb"
    11  	gogoproto "github.com/cosmos/gogoproto/proto"
    12  	"google.golang.org/grpc/encoding"
    13  	"google.golang.org/protobuf/proto"
    14  	"google.golang.org/protobuf/reflect/protoreflect"
    15  	"google.golang.org/protobuf/reflect/protoregistry"
    16  	"google.golang.org/protobuf/types/dynamicpb"
    17  	"google.golang.org/protobuf/types/known/anypb"
    18  
    19  	"cosmossdk.io/x/tx/signing/aminojson"
    20  
    21  	"github.com/cosmos/cosmos-sdk/codec/types"
    22  )
    23  
    24  // ProtoCodecMarshaler defines an interface for codecs that utilize Protobuf for both
    25  // binary and JSON encoding.
    26  // Deprecated: Use Codec instead.
    27  type ProtoCodecMarshaler interface {
    28  	Codec
    29  }
    30  
    31  // ProtoCodec defines a codec that utilizes Protobuf for both binary and JSON
    32  // encoding.
    33  type ProtoCodec struct {
    34  	interfaceRegistry types.InterfaceRegistry
    35  }
    36  
    37  var _ Codec = (*ProtoCodec)(nil)
    38  
    39  // NewProtoCodec returns a reference to a new ProtoCodec
    40  func NewProtoCodec(interfaceRegistry types.InterfaceRegistry) *ProtoCodec {
    41  	return &ProtoCodec{
    42  		interfaceRegistry: interfaceRegistry,
    43  	}
    44  }
    45  
    46  // Marshal implements BinaryMarshaler.Marshal method.
    47  // NOTE: this function must be used with a concrete type which
    48  // implements proto.Message. For interface please use the codec.MarshalInterface
    49  func (pc *ProtoCodec) Marshal(o gogoproto.Message) ([]byte, error) {
    50  	// Size() check can catch the typed nil value.
    51  	if o == nil || gogoproto.Size(o) == 0 {
    52  		// return empty bytes instead of nil, because nil has special meaning in places like store.Set
    53  		return []byte{}, nil
    54  	}
    55  
    56  	return gogoproto.Marshal(o)
    57  }
    58  
    59  // MustMarshal implements BinaryMarshaler.MustMarshal method.
    60  // NOTE: this function must be used with a concrete type which
    61  // implements proto.Message. For interface please use the codec.MarshalInterface
    62  func (pc *ProtoCodec) MustMarshal(o gogoproto.Message) []byte {
    63  	bz, err := pc.Marshal(o)
    64  	if err != nil {
    65  		panic(err)
    66  	}
    67  
    68  	return bz
    69  }
    70  
    71  // MarshalLengthPrefixed implements BinaryMarshaler.MarshalLengthPrefixed method.
    72  func (pc *ProtoCodec) MarshalLengthPrefixed(o gogoproto.Message) ([]byte, error) {
    73  	bz, err := pc.Marshal(o)
    74  	if err != nil {
    75  		return nil, err
    76  	}
    77  
    78  	var sizeBuf [binary.MaxVarintLen64]byte
    79  	n := binary.PutUvarint(sizeBuf[:], uint64(len(bz)))
    80  	return append(sizeBuf[:n], bz...), nil
    81  }
    82  
    83  // MustMarshalLengthPrefixed implements BinaryMarshaler.MustMarshalLengthPrefixed method.
    84  func (pc *ProtoCodec) MustMarshalLengthPrefixed(o gogoproto.Message) []byte {
    85  	bz, err := pc.MarshalLengthPrefixed(o)
    86  	if err != nil {
    87  		panic(err)
    88  	}
    89  
    90  	return bz
    91  }
    92  
    93  // Unmarshal implements BinaryMarshaler.Unmarshal method.
    94  // NOTE: this function must be used with a concrete type which
    95  // implements proto.Message. For interface please use the codec.UnmarshalInterface
    96  func (pc *ProtoCodec) Unmarshal(bz []byte, ptr gogoproto.Message) error {
    97  	err := gogoproto.Unmarshal(bz, ptr)
    98  	if err != nil {
    99  		return err
   100  	}
   101  	err = types.UnpackInterfaces(ptr, pc.interfaceRegistry)
   102  	if err != nil {
   103  		return err
   104  	}
   105  	return nil
   106  }
   107  
   108  // MustUnmarshal implements BinaryMarshaler.MustUnmarshal method.
   109  // NOTE: this function must be used with a concrete type which
   110  // implements proto.Message. For interface please use the codec.UnmarshalInterface
   111  func (pc *ProtoCodec) MustUnmarshal(bz []byte, ptr gogoproto.Message) {
   112  	if err := pc.Unmarshal(bz, ptr); err != nil {
   113  		panic(err)
   114  	}
   115  }
   116  
   117  // UnmarshalLengthPrefixed implements BinaryMarshaler.UnmarshalLengthPrefixed method.
   118  func (pc *ProtoCodec) UnmarshalLengthPrefixed(bz []byte, ptr gogoproto.Message) error {
   119  	size, n := binary.Uvarint(bz)
   120  	if n < 0 {
   121  		return fmt.Errorf("invalid number of bytes read from length-prefixed encoding: %d", n)
   122  	}
   123  
   124  	if size > uint64(len(bz)-n) {
   125  		return fmt.Errorf("not enough bytes to read; want: %v, got: %v", size, len(bz)-n)
   126  	} else if size < uint64(len(bz)-n) {
   127  		return fmt.Errorf("too many bytes to read; want: %v, got: %v", size, len(bz)-n)
   128  	}
   129  
   130  	bz = bz[n:]
   131  	return pc.Unmarshal(bz, ptr)
   132  }
   133  
   134  // MustUnmarshalLengthPrefixed implements BinaryMarshaler.MustUnmarshalLengthPrefixed method.
   135  func (pc *ProtoCodec) MustUnmarshalLengthPrefixed(bz []byte, ptr gogoproto.Message) {
   136  	if err := pc.UnmarshalLengthPrefixed(bz, ptr); err != nil {
   137  		panic(err)
   138  	}
   139  }
   140  
   141  // MarshalJSON implements JSONCodec.MarshalJSON method,
   142  // it marshals to JSON using proto codec.
   143  // NOTE: this function must be used with a concrete type which
   144  // implements proto.Message. For interface please use the codec.MarshalInterfaceJSON
   145  func (pc *ProtoCodec) MarshalJSON(o gogoproto.Message) ([]byte, error) { //nolint:stdmethods // we don't want to implement Marshaler interface
   146  	if o == nil {
   147  		return nil, fmt.Errorf("cannot protobuf JSON encode nil")
   148  	}
   149  	return ProtoMarshalJSON(o, pc.interfaceRegistry)
   150  }
   151  
   152  // MustMarshalJSON implements JSONCodec.MustMarshalJSON method,
   153  // it executes MarshalJSON except it panics upon failure.
   154  // NOTE: this function must be used with a concrete type which
   155  // implements proto.Message. For interface please use the codec.MarshalInterfaceJSON
   156  func (pc *ProtoCodec) MustMarshalJSON(o gogoproto.Message) []byte {
   157  	bz, err := pc.MarshalJSON(o)
   158  	if err != nil {
   159  		panic(err)
   160  	}
   161  
   162  	return bz
   163  }
   164  
   165  // MarshalAminoJSON provides aminojson.Encoder compatibility for gogoproto messages.
   166  // x/tx/signing/aminojson cannot marshal gogoproto messages directly since this type does not implement
   167  // the standard library google.golang.org/protobuf/proto.Message.
   168  // We convert gogo types to dynamicpb messages and then marshal that directly to amino JSON.
   169  func (pc *ProtoCodec) MarshalAminoJSON(msg gogoproto.Message) ([]byte, error) {
   170  	encoder := aminojson.NewEncoder(aminojson.EncoderOptions{FileResolver: pc.interfaceRegistry})
   171  	gogoBytes, err := gogoproto.Marshal(msg)
   172  	if err != nil {
   173  		return nil, err
   174  	}
   175  
   176  	var protoMsg protoreflect.ProtoMessage
   177  	typ, err := protoregistry.GlobalTypes.FindMessageByURL(fmt.Sprintf("/%s", gogoproto.MessageName(msg)))
   178  	if typ != nil && err != nil {
   179  		protoMsg = typ.New().Interface()
   180  	} else {
   181  		desc, err := pc.interfaceRegistry.FindDescriptorByName(protoreflect.FullName(gogoproto.MessageName(msg)))
   182  		if err != nil {
   183  			return nil, err
   184  		}
   185  		dynamicMsgType := dynamicpb.NewMessageType(desc.(protoreflect.MessageDescriptor))
   186  		protoMsg = dynamicMsgType.New().Interface()
   187  	}
   188  
   189  	err = proto.Unmarshal(gogoBytes, protoMsg)
   190  	if err != nil {
   191  		return nil, err
   192  	}
   193  	return encoder.Marshal(protoMsg)
   194  }
   195  
   196  // UnmarshalJSON implements JSONCodec.UnmarshalJSON method,
   197  // it unmarshals from JSON using proto codec.
   198  // NOTE: this function must be used with a concrete type which
   199  // implements proto.Message. For interface please use the codec.UnmarshalInterfaceJSON
   200  func (pc *ProtoCodec) UnmarshalJSON(bz []byte, ptr gogoproto.Message) error {
   201  	if ptr == nil {
   202  		return fmt.Errorf("cannot protobuf JSON decode unsupported type: %T", ptr)
   203  	}
   204  	unmarshaler := jsonpb.Unmarshaler{AnyResolver: pc.interfaceRegistry}
   205  	err := unmarshaler.Unmarshal(strings.NewReader(string(bz)), ptr)
   206  	if err != nil {
   207  		return err
   208  	}
   209  
   210  	return types.UnpackInterfaces(ptr, pc.interfaceRegistry)
   211  }
   212  
   213  // MustUnmarshalJSON implements JSONCodec.MustUnmarshalJSON method,
   214  // it executes UnmarshalJSON except it panics upon failure.
   215  // NOTE: this function must be used with a concrete type which
   216  // implements proto.Message. For interface please use the codec.UnmarshalInterfaceJSON
   217  func (pc *ProtoCodec) MustUnmarshalJSON(bz []byte, ptr gogoproto.Message) {
   218  	if err := pc.UnmarshalJSON(bz, ptr); err != nil {
   219  		panic(err)
   220  	}
   221  }
   222  
   223  // MarshalInterface is a convenience function for proto marshaling interfaces. It packs
   224  // the provided value, which must be an interface, in an Any and then marshals it to bytes.
   225  // NOTE: to marshal a concrete type, you should use Marshal instead
   226  func (pc *ProtoCodec) MarshalInterface(i gogoproto.Message) ([]byte, error) {
   227  	if err := assertNotNil(i); err != nil {
   228  		return nil, err
   229  	}
   230  	any, err := types.NewAnyWithValue(i)
   231  	if err != nil {
   232  		return nil, err
   233  	}
   234  	err = pc.interfaceRegistry.EnsureRegistered(i)
   235  	if err != nil {
   236  		return nil, err
   237  	}
   238  
   239  	return pc.Marshal(any)
   240  }
   241  
   242  // UnmarshalInterface is a convenience function for proto unmarshaling interfaces. It
   243  // unmarshals an Any from bz bytes and then unpacks it to the `ptr`, which must
   244  // be a pointer to a non empty interface with registered implementations.
   245  // NOTE: to unmarshal a concrete type, you should use Unmarshal instead
   246  //
   247  // Example:
   248  //
   249  //	var x MyInterface
   250  //	err := cdc.UnmarshalInterface(bz, &x)
   251  func (pc *ProtoCodec) UnmarshalInterface(bz []byte, ptr interface{}) error {
   252  	any := &types.Any{}
   253  	err := pc.Unmarshal(bz, any)
   254  	if err != nil {
   255  		return err
   256  	}
   257  
   258  	return pc.UnpackAny(any, ptr)
   259  }
   260  
   261  // MarshalInterfaceJSON is a convenience function for proto marshaling interfaces. It
   262  // packs the provided value in an Any and then marshals it to bytes.
   263  // NOTE: to marshal a concrete type, you should use MarshalJSON instead
   264  func (pc *ProtoCodec) MarshalInterfaceJSON(x gogoproto.Message) ([]byte, error) {
   265  	any, err := types.NewAnyWithValue(x)
   266  	if err != nil {
   267  		return nil, err
   268  	}
   269  	return pc.MarshalJSON(any)
   270  }
   271  
   272  // UnmarshalInterfaceJSON is a convenience function for proto unmarshaling interfaces.
   273  // It unmarshals an Any from bz bytes and then unpacks it to the `iface`, which must
   274  // be a pointer to a non empty interface, implementing proto.Message with registered implementations.
   275  // NOTE: to unmarshal a concrete type, you should use UnmarshalJSON instead
   276  //
   277  // Example:
   278  //
   279  //	var x MyInterface  // must implement proto.Message
   280  //	err := cdc.UnmarshalInterfaceJSON(&x, bz)
   281  func (pc *ProtoCodec) UnmarshalInterfaceJSON(bz []byte, iface interface{}) error {
   282  	any := &types.Any{}
   283  	err := pc.UnmarshalJSON(bz, any)
   284  	if err != nil {
   285  		return err
   286  	}
   287  	return pc.UnpackAny(any, iface)
   288  }
   289  
   290  // UnpackAny implements AnyUnpacker.UnpackAny method,
   291  // it unpacks the value in any to the interface pointer passed in as
   292  // iface.
   293  func (pc *ProtoCodec) UnpackAny(any *types.Any, iface interface{}) error {
   294  	return pc.interfaceRegistry.UnpackAny(any, iface)
   295  }
   296  
   297  // InterfaceRegistry returns InterfaceRegistry
   298  func (pc *ProtoCodec) InterfaceRegistry() types.InterfaceRegistry {
   299  	return pc.interfaceRegistry
   300  }
   301  
   302  func (pc ProtoCodec) GetMsgAnySigners(msg *types.Any) ([][]byte, proto.Message, error) {
   303  	msgv2, err := anyutil.Unpack(&anypb.Any{
   304  		TypeUrl: msg.TypeUrl,
   305  		Value:   msg.Value,
   306  	}, pc.interfaceRegistry, nil)
   307  	if err != nil {
   308  		return nil, nil, err
   309  	}
   310  
   311  	signers, err := pc.interfaceRegistry.SigningContext().GetSigners(msgv2)
   312  	return signers, msgv2, err
   313  }
   314  
   315  func (pc *ProtoCodec) GetMsgV2Signers(msg proto.Message) ([][]byte, error) {
   316  	return pc.interfaceRegistry.SigningContext().GetSigners(msg)
   317  }
   318  
   319  func (pc *ProtoCodec) GetMsgV1Signers(msg gogoproto.Message) ([][]byte, proto.Message, error) {
   320  	if msgV2, ok := msg.(proto.Message); ok {
   321  		signers, err := pc.interfaceRegistry.SigningContext().GetSigners(msgV2)
   322  		return signers, msgV2, err
   323  	}
   324  	a, err := types.NewAnyWithValue(msg)
   325  	if err != nil {
   326  		return nil, nil, err
   327  	}
   328  	return pc.GetMsgAnySigners(a)
   329  }
   330  
   331  // GRPCCodec returns the gRPC Codec for this specific ProtoCodec
   332  func (pc *ProtoCodec) GRPCCodec() encoding.Codec {
   333  	return &grpcProtoCodec{cdc: pc}
   334  }
   335  
   336  func (pc *ProtoCodec) mustEmbedCodec() {}
   337  
   338  var errUnknownProtoType = errors.New("codec: unknown proto type") // sentinel error
   339  
   340  // grpcProtoCodec is the implementation of the gRPC proto codec.
   341  type grpcProtoCodec struct {
   342  	cdc *ProtoCodec
   343  }
   344  
   345  func (g grpcProtoCodec) Marshal(v interface{}) ([]byte, error) {
   346  	switch m := v.(type) {
   347  	case proto.Message:
   348  		protov2MarshalOpts := proto.MarshalOptions{Deterministic: true}
   349  		return protov2MarshalOpts.Marshal(m)
   350  	case gogoproto.Message:
   351  		return g.cdc.Marshal(m)
   352  	default:
   353  		return nil, fmt.Errorf("%w: cannot marshal type %T", errUnknownProtoType, v)
   354  	}
   355  }
   356  
   357  func (g grpcProtoCodec) Unmarshal(data []byte, v interface{}) error {
   358  	switch m := v.(type) {
   359  	case proto.Message:
   360  		return proto.Unmarshal(data, m)
   361  	case gogoproto.Message:
   362  		return g.cdc.Unmarshal(data, m)
   363  	default:
   364  		return fmt.Errorf("%w: cannot unmarshal type %T", errUnknownProtoType, v)
   365  	}
   366  }
   367  
   368  func (g grpcProtoCodec) Name() string {
   369  	return "cosmos-sdk-grpc-codec"
   370  }
   371  
   372  func assertNotNil(i interface{}) error {
   373  	if i == nil {
   374  		return errors.New("can't marshal <nil> value")
   375  	}
   376  	return nil
   377  }