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 }