github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/codec/proto_codec.go (about) 1 package codec 2 3 import ( 4 "encoding/binary" 5 "errors" 6 "fmt" 7 "strings" 8 9 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/codec/types" 10 11 "github.com/gogo/protobuf/jsonpb" 12 "github.com/gogo/protobuf/proto" 13 ) 14 15 // ProtoCodecMarshaler defines an interface for codecs that utilize Protobuf for both 16 // binary and JSON encoding. 17 type ProtoCodecMarshaler interface { 18 Marshaler 19 InterfaceRegistry() types.InterfaceRegistry 20 } 21 22 // ProtoCodec defines a codec that utilizes Protobuf for both binary and JSON 23 // encoding. 24 type ProtoCodec struct { 25 interfaceRegistry types.InterfaceRegistry 26 } 27 28 var _ Marshaler = &ProtoCodec{} 29 var _ ProtoCodecMarshaler = &ProtoCodec{} 30 31 // NewProtoCodec returns a reference to a new ProtoCodec 32 func NewProtoCodec(interfaceRegistry types.InterfaceRegistry) *ProtoCodec { 33 return &ProtoCodec{interfaceRegistry: interfaceRegistry} 34 } 35 36 // Marshal implements BinaryMarshaler.Marshal method. 37 // NOTE: this function must be used with a concrete type which 38 // implements proto.Message. For interface please use the codec.MarshalInterface 39 func (pc *ProtoCodec) Marshal(o ProtoMarshaler) ([]byte, error) { 40 return o.Marshal() 41 } 42 43 // MustMarshal implements BinaryMarshaler.MustMarshal method. 44 // NOTE: this function must be used with a concrete type which 45 // implements proto.Message. For interface please use the codec.MarshalInterface 46 func (pc *ProtoCodec) MustMarshal(o ProtoMarshaler) []byte { 47 bz, err := pc.Marshal(o) 48 if err != nil { 49 panic(err) 50 } 51 52 return bz 53 } 54 55 // Unmarshal implements BinaryMarshaler.Unmarshal method. 56 // NOTE: this function must be used with a concrete type which 57 // implements proto.Message. For interface please use the codec.UnmarshalInterface 58 func (pc *ProtoCodec) Unmarshal(bz []byte, ptr ProtoMarshaler) error { 59 err := ptr.Unmarshal(bz) 60 if err != nil { 61 return err 62 } 63 err = types.UnpackInterfaces(ptr, pc.interfaceRegistry) 64 if err != nil { 65 return err 66 } 67 return nil 68 } 69 70 // MustUnmarshal implements BinaryMarshaler.MustUnmarshal method. 71 // NOTE: this function must be used with a concrete type which 72 // implements proto.Message. For interface please use the codec.UnmarshalInterface 73 func (pc *ProtoCodec) MustUnmarshal(bz []byte, ptr ProtoMarshaler) { 74 if err := pc.Unmarshal(bz, ptr); err != nil { 75 panic(err) 76 } 77 } 78 79 // MarshalBinaryBare implements BinaryMarshaler.MarshalBinaryBare method. 80 func (pc *ProtoCodec) MarshalBinaryBare(o ProtoMarshaler) ([]byte, error) { 81 return o.Marshal() 82 } 83 84 // MustMarshalBinaryBare implements BinaryMarshaler.MustMarshalBinaryBare method. 85 func (pc *ProtoCodec) MustMarshalBinaryBare(o ProtoMarshaler) []byte { 86 bz, err := pc.MarshalBinaryBare(o) 87 if err != nil { 88 panic(err) 89 } 90 91 return bz 92 } 93 94 // MarshalBinaryLengthPrefixed implements BinaryMarshaler.MarshalBinaryLengthPrefixed method. 95 func (pc *ProtoCodec) MarshalBinaryLengthPrefixed(o ProtoMarshaler) ([]byte, error) { 96 bz, err := pc.MarshalBinaryBare(o) 97 if err != nil { 98 return nil, err 99 } 100 101 var sizeBuf [binary.MaxVarintLen64]byte 102 n := binary.PutUvarint(sizeBuf[:], uint64(o.Size())) 103 return append(sizeBuf[:n], bz...), nil 104 } 105 106 // MustMarshalBinaryLengthPrefixed implements BinaryMarshaler.MustMarshalBinaryLengthPrefixed method. 107 func (pc *ProtoCodec) MustMarshalBinaryLengthPrefixed(o ProtoMarshaler) []byte { 108 bz, err := pc.MarshalBinaryLengthPrefixed(o) 109 if err != nil { 110 panic(err) 111 } 112 113 return bz 114 } 115 116 // UnmarshalBinaryBare implements BinaryMarshaler.UnmarshalBinaryBare method. 117 func (pc *ProtoCodec) UnmarshalBinaryBare(bz []byte, ptr ProtoMarshaler) error { 118 err := ptr.Unmarshal(bz) 119 if err != nil { 120 return err 121 } 122 err = types.UnpackInterfaces(ptr, pc.interfaceRegistry) 123 if err != nil { 124 return err 125 } 126 return nil 127 } 128 129 // MustUnmarshalBinaryBare implements BinaryMarshaler.MustUnmarshalBinaryBare method. 130 func (pc *ProtoCodec) MustUnmarshalBinaryBare(bz []byte, ptr ProtoMarshaler) { 131 if err := pc.UnmarshalBinaryBare(bz, ptr); err != nil { 132 panic(err) 133 } 134 } 135 136 // UnmarshalBinaryLengthPrefixed implements BinaryMarshaler.UnmarshalBinaryLengthPrefixed method. 137 func (pc *ProtoCodec) UnmarshalBinaryLengthPrefixed(bz []byte, ptr ProtoMarshaler) error { 138 size, n := binary.Uvarint(bz) 139 if n < 0 { 140 return fmt.Errorf("invalid number of bytes read from length-prefixed encoding: %d", n) 141 } 142 143 if size > uint64(len(bz)-n) { 144 return fmt.Errorf("not enough bytes to read; want: %v, got: %v", size, len(bz)-n) 145 } else if size < uint64(len(bz)-n) { 146 return fmt.Errorf("too many bytes to read; want: %v, got: %v", size, len(bz)-n) 147 } 148 149 bz = bz[n:] 150 return pc.UnmarshalBinaryBare(bz, ptr) 151 } 152 153 // MustUnmarshalBinaryLengthPrefixed implements BinaryMarshaler.MustUnmarshalBinaryLengthPrefixed method. 154 func (pc *ProtoCodec) MustUnmarshalBinaryLengthPrefixed(bz []byte, ptr ProtoMarshaler) { 155 if err := pc.UnmarshalBinaryLengthPrefixed(bz, ptr); err != nil { 156 panic(err) 157 } 158 } 159 160 // MarshalJSON implements JSONMarshaler.MarshalJSON method, 161 // it marshals to JSON using proto codec. 162 func (pc *ProtoCodec) MarshalJSON(o proto.Message) ([]byte, error) { 163 m, ok := o.(ProtoMarshaler) 164 if !ok { 165 return nil, fmt.Errorf("cannot protobuf JSON encode unsupported type: %T", o) 166 } 167 168 return ProtoMarshalJSON(m, pc.interfaceRegistry) 169 } 170 171 // MustMarshalJSON implements JSONMarshaler.MustMarshalJSON method, 172 // it executes MarshalJSON except it panics upon failure. 173 func (pc *ProtoCodec) MustMarshalJSON(o proto.Message) []byte { 174 bz, err := pc.MarshalJSON(o) 175 if err != nil { 176 panic(err) 177 } 178 179 return bz 180 } 181 182 // UnmarshalJSON implements JSONMarshaler.UnmarshalJSON method, 183 // it unmarshals from JSON using proto codec. 184 func (pc *ProtoCodec) UnmarshalJSON(bz []byte, ptr proto.Message) error { 185 m, ok := ptr.(ProtoMarshaler) 186 if !ok { 187 return fmt.Errorf("cannot protobuf JSON decode unsupported type: %T", ptr) 188 } 189 190 unmarshaler := jsonpb.Unmarshaler{AnyResolver: pc.interfaceRegistry} 191 err := unmarshaler.Unmarshal(strings.NewReader(string(bz)), m) 192 if err != nil { 193 return err 194 } 195 196 return types.UnpackInterfaces(ptr, pc.interfaceRegistry) 197 } 198 199 // MustUnmarshalJSON implements JSONMarshaler.MustUnmarshalJSON method, 200 // it executes UnmarshalJSON except it panics upon failure. 201 func (pc *ProtoCodec) MustUnmarshalJSON(bz []byte, ptr proto.Message) { 202 if err := pc.UnmarshalJSON(bz, ptr); err != nil { 203 panic(err) 204 } 205 } 206 207 // MarshalInterface is a convenience function for proto marshalling interfaces. It packs 208 // the provided value, which must be an interface, in an Any and then marshals it to bytes. 209 // NOTE: to marshal a concrete type, you should use MarshalBinaryBare instead 210 func (pc *ProtoCodec) MarshalInterface(i proto.Message) ([]byte, error) { 211 if err := assertNotNil(i); err != nil { 212 return nil, err 213 } 214 any, err := types.NewAnyWithValue(i) 215 if err != nil { 216 return nil, err 217 } 218 219 return pc.MarshalBinaryBare(any) 220 } 221 222 // UnmarshalInterface is a convenience function for proto unmarshaling interfaces. It 223 // unmarshals an Any from bz bytes and then unpacks it to the `ptr`, which must 224 // be a pointer to a non empty interface with registered implementations. 225 // NOTE: to unmarshal a concrete type, you should use UnmarshalBinaryBare instead 226 // 227 // Example: 228 // 229 // var x MyInterface 230 // err := cdc.UnmarshalInterface(bz, &x) 231 func (pc *ProtoCodec) UnmarshalInterface(bz []byte, ptr interface{}) error { 232 any := &types.Any{} 233 err := pc.UnmarshalBinaryBare(bz, any) 234 if err != nil { 235 return err 236 } 237 238 return pc.UnpackAny(any, ptr) 239 } 240 241 // MarshalInterfaceJSON is a convenience function for proto marshalling interfaces. It 242 // packs the provided value in an Any and then marshals it to bytes. 243 // NOTE: to marshal a concrete type, you should use MarshalJSON instead 244 func (pc *ProtoCodec) MarshalInterfaceJSON(x proto.Message) ([]byte, error) { 245 any, err := types.NewAnyWithValue(x) 246 if err != nil { 247 return nil, err 248 } 249 return pc.MarshalJSON(any) 250 } 251 252 // UnmarshalInterfaceJSON is a convenience function for proto unmarshaling interfaces. 253 // It unmarshals an Any from bz bytes and then unpacks it to the `iface`, which must 254 // be a pointer to a non empty interface, implementing proto.Message with registered implementations. 255 // NOTE: to unmarshal a concrete type, you should use UnmarshalJSON instead 256 // 257 // Example: 258 // 259 // var x MyInterface // must implement proto.Message 260 // err := cdc.UnmarshalInterfaceJSON(&x, bz) 261 func (pc *ProtoCodec) UnmarshalInterfaceJSON(bz []byte, iface interface{}) error { 262 any := &types.Any{} 263 err := pc.UnmarshalJSON(bz, any) 264 if err != nil { 265 return err 266 } 267 return pc.UnpackAny(any, iface) 268 } 269 270 // UnpackAny implements AnyUnpacker.UnpackAny method, 271 // it unpacks the value in any to the interface pointer passed in as 272 // iface. 273 func (pc *ProtoCodec) UnpackAny(any *types.Any, iface interface{}) error { 274 return pc.interfaceRegistry.UnpackAny(any, iface) 275 } 276 277 func (pc *ProtoCodec) InterfaceRegistry() types.InterfaceRegistry { 278 return pc.interfaceRegistry 279 } 280 281 func assertNotNil(i interface{}) error { 282 if i == nil { 283 return errors.New("can't marshal <nil> value") 284 } 285 return nil 286 }