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

     1  package types
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"runtime/debug"
     7  
     8  	"github.com/cosmos/gogoproto/jsonpb"
     9  	"github.com/cosmos/gogoproto/proto"
    10  	amino "github.com/tendermint/go-amino"
    11  )
    12  
    13  type anyCompat struct {
    14  	aminoBz []byte
    15  	jsonBz  []byte
    16  	err     error
    17  }
    18  
    19  var Debug = true
    20  
    21  func anyCompatError(errType string, x interface{}) error {
    22  	if Debug {
    23  		debug.PrintStack()
    24  	}
    25  	return fmt.Errorf(
    26  		"%s marshaling error for %+v, this is likely because "+
    27  			"amino is being used directly (instead of codec.LegacyAmino which is preferred) "+
    28  			"or UnpackInterfacesMessage is not defined for some type which contains "+
    29  			"a protobuf Any either directly or via one of its members. To see a "+
    30  			"stacktrace of where the error is coming from, set the var Debug = true "+
    31  			"in codec/types/compat.go",
    32  		errType, x,
    33  	)
    34  }
    35  
    36  func (any Any) MarshalAmino() ([]byte, error) {
    37  	ac := any.compat
    38  	if ac == nil {
    39  		return nil, anyCompatError("amino binary marshal", any)
    40  	}
    41  	return ac.aminoBz, ac.err
    42  }
    43  
    44  func (any *Any) UnmarshalAmino(bz []byte) error {
    45  	any.compat = &anyCompat{
    46  		aminoBz: bz,
    47  		err:     nil,
    48  	}
    49  	return nil
    50  }
    51  
    52  func (any *Any) MarshalJSON() ([]byte, error) {
    53  	ac := any.compat
    54  	if ac == nil {
    55  		return nil, anyCompatError("JSON marshal", any)
    56  	}
    57  	return ac.jsonBz, ac.err
    58  }
    59  
    60  func (any *Any) UnmarshalJSON(bz []byte) error {
    61  	any.compat = &anyCompat{
    62  		jsonBz: bz,
    63  		err:    nil,
    64  	}
    65  	return nil
    66  }
    67  
    68  // AminoUnpacker is an AnyUnpacker provided for backwards compatibility with
    69  // amino for the binary un-marshaling phase
    70  type AminoUnpacker struct {
    71  	Cdc *amino.Codec
    72  }
    73  
    74  var _ AnyUnpacker = AminoUnpacker{}
    75  
    76  func (a AminoUnpacker) UnpackAny(any *Any, iface interface{}) error {
    77  	ac := any.compat
    78  	if ac == nil {
    79  		return anyCompatError("amino binary unmarshal", reflect.TypeOf(iface))
    80  	}
    81  	err := a.Cdc.UnmarshalBinaryBare(ac.aminoBz, iface)
    82  	if err != nil {
    83  		return err
    84  	}
    85  	val := reflect.ValueOf(iface).Elem().Interface()
    86  	err = UnpackInterfaces(val, a)
    87  	if err != nil {
    88  		return err
    89  	}
    90  	if m, ok := val.(proto.Message); ok {
    91  		if err = any.pack(m); err != nil {
    92  			return err
    93  		}
    94  	} else {
    95  		any.cachedValue = val
    96  	}
    97  
    98  	// this is necessary for tests that use reflect.DeepEqual and compare
    99  	// proto vs amino marshaled values
   100  	any.compat = nil
   101  
   102  	return nil
   103  }
   104  
   105  // AminoUnpacker is an AnyUnpacker provided for backwards compatibility with
   106  // amino for the binary marshaling phase
   107  type AminoPacker struct {
   108  	Cdc *amino.Codec
   109  }
   110  
   111  var _ AnyUnpacker = AminoPacker{}
   112  
   113  func (a AminoPacker) UnpackAny(any *Any, _ interface{}) error {
   114  	err := UnpackInterfaces(any.cachedValue, a)
   115  	if err != nil {
   116  		return err
   117  	}
   118  	bz, err := a.Cdc.MarshalBinaryBare(any.cachedValue)
   119  	any.compat = &anyCompat{
   120  		aminoBz: bz,
   121  		err:     err,
   122  	}
   123  	return err
   124  }
   125  
   126  // AminoUnpacker is an AnyUnpacker provided for backwards compatibility with
   127  // amino for the JSON marshaling phase
   128  type AminoJSONUnpacker struct {
   129  	Cdc *amino.Codec
   130  }
   131  
   132  var _ AnyUnpacker = AminoJSONUnpacker{}
   133  
   134  func (a AminoJSONUnpacker) UnpackAny(any *Any, iface interface{}) error {
   135  	ac := any.compat
   136  	if ac == nil {
   137  		return anyCompatError("JSON unmarshal", reflect.TypeOf(iface))
   138  	}
   139  	err := a.Cdc.UnmarshalJSON(ac.jsonBz, iface)
   140  	if err != nil {
   141  		return err
   142  	}
   143  	val := reflect.ValueOf(iface).Elem().Interface()
   144  	err = UnpackInterfaces(val, a)
   145  	if err != nil {
   146  		return err
   147  	}
   148  	if m, ok := val.(proto.Message); ok {
   149  		if err = any.pack(m); err != nil {
   150  			return err
   151  		}
   152  	} else {
   153  		any.cachedValue = val
   154  	}
   155  
   156  	// this is necessary for tests that use reflect.DeepEqual and compare
   157  	// proto vs amino marshaled values
   158  	any.compat = nil
   159  
   160  	return nil
   161  }
   162  
   163  // AminoUnpacker is an AnyUnpacker provided for backwards compatibility with
   164  // amino for the JSON un-marshaling phase
   165  type AminoJSONPacker struct {
   166  	Cdc *amino.Codec
   167  }
   168  
   169  var _ AnyUnpacker = AminoJSONPacker{}
   170  
   171  func (a AminoJSONPacker) UnpackAny(any *Any, _ interface{}) error {
   172  	err := UnpackInterfaces(any.cachedValue, a)
   173  	if err != nil {
   174  		return err
   175  	}
   176  	bz, err := a.Cdc.MarshalJSON(any.cachedValue)
   177  	any.compat = &anyCompat{
   178  		jsonBz: bz,
   179  		err:    err,
   180  	}
   181  	return err
   182  }
   183  
   184  // ProtoJSONPacker is an AnyUnpacker provided for compatibility with jsonpb
   185  type ProtoJSONPacker struct {
   186  	JSONPBMarshaler *jsonpb.Marshaler
   187  }
   188  
   189  var _ AnyUnpacker = ProtoJSONPacker{}
   190  
   191  func (a ProtoJSONPacker) UnpackAny(any *Any, _ interface{}) error {
   192  	if any == nil {
   193  		return nil
   194  	}
   195  
   196  	if any.cachedValue != nil {
   197  		err := UnpackInterfaces(any.cachedValue, a)
   198  		if err != nil {
   199  			return err
   200  		}
   201  	}
   202  
   203  	bz, err := a.JSONPBMarshaler.MarshalToString(any)
   204  	any.compat = &anyCompat{
   205  		jsonBz: []byte(bz),
   206  		err:    err,
   207  	}
   208  
   209  	return err
   210  }