212 lines
4.5 KiB
Go
212 lines
4.5 KiB
Go
package types
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"runtime/debug"
|
|
|
|
"github.com/gogo/protobuf/jsonpb"
|
|
"github.com/gogo/protobuf/proto"
|
|
|
|
amino "github.com/tendermint/go-amino"
|
|
)
|
|
|
|
type anyCompat struct {
|
|
aminoBz []byte
|
|
jsonBz []byte
|
|
err error
|
|
}
|
|
|
|
var Debug = true
|
|
|
|
func anyCompatError(errType string, x interface{}) error {
|
|
if Debug {
|
|
debug.PrintStack()
|
|
}
|
|
return fmt.Errorf(
|
|
"%s marshaling error for %+v, this is likely because "+
|
|
"amino is being used directly (instead of codec.LegacyAmino which is preferred) "+
|
|
"or UnpackInterfacesMessage is not defined for some type which contains "+
|
|
"a protobuf Any either directly or via one of its members. To see a "+
|
|
"stacktrace of where the error is coming from, set the var Debug = true "+
|
|
"in codec/types/compat.go",
|
|
errType, x,
|
|
)
|
|
}
|
|
|
|
func (any Any) MarshalAmino() ([]byte, error) {
|
|
ac := any.compat
|
|
if ac == nil {
|
|
return nil, anyCompatError("amino binary marshal", any)
|
|
}
|
|
return ac.aminoBz, ac.err
|
|
}
|
|
|
|
func (any *Any) UnmarshalAmino(bz []byte) error {
|
|
any.compat = &anyCompat{
|
|
aminoBz: bz,
|
|
err: nil,
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (any *Any) MarshalJSON() ([]byte, error) {
|
|
ac := any.compat
|
|
if ac == nil {
|
|
return nil, anyCompatError("JSON marshal", any)
|
|
}
|
|
return ac.jsonBz, ac.err
|
|
}
|
|
|
|
func (any *Any) UnmarshalJSON(bz []byte) error {
|
|
any.compat = &anyCompat{
|
|
jsonBz: bz,
|
|
err: nil,
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// AminoUnpacker is an AnyUnpacker provided for backwards compatibility with
|
|
// amino for the binary un-marshaling phase
|
|
type AminoUnpacker struct {
|
|
Cdc *amino.Codec
|
|
}
|
|
|
|
var _ AnyUnpacker = AminoUnpacker{}
|
|
|
|
func (a AminoUnpacker) UnpackAny(any *Any, iface interface{}) error {
|
|
ac := any.compat
|
|
if ac == nil {
|
|
return anyCompatError("amino binary unmarshal", reflect.TypeOf(iface))
|
|
}
|
|
err := a.Cdc.UnmarshalBinaryBare(ac.aminoBz, iface)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
val := reflect.ValueOf(iface).Elem().Interface()
|
|
err = UnpackInterfaces(val, a)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if m, ok := val.(proto.Message); ok {
|
|
if err = any.pack(m); err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
any.cachedValue = val
|
|
}
|
|
|
|
// this is necessary for tests that use reflect.DeepEqual and compare
|
|
// proto vs amino marshaled values
|
|
any.compat = nil
|
|
|
|
return nil
|
|
}
|
|
|
|
// AminoUnpacker is an AnyUnpacker provided for backwards compatibility with
|
|
// amino for the binary marshaling phase
|
|
type AminoPacker struct {
|
|
Cdc *amino.Codec
|
|
}
|
|
|
|
var _ AnyUnpacker = AminoPacker{}
|
|
|
|
func (a AminoPacker) UnpackAny(any *Any, _ interface{}) error {
|
|
err := UnpackInterfaces(any.cachedValue, a)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
bz, err := a.Cdc.MarshalBinaryBare(any.cachedValue)
|
|
any.compat = &anyCompat{
|
|
aminoBz: bz,
|
|
err: err,
|
|
}
|
|
return err
|
|
}
|
|
|
|
// AminoUnpacker is an AnyUnpacker provided for backwards compatibility with
|
|
// amino for the JSON marshaling phase
|
|
type AminoJSONUnpacker struct {
|
|
Cdc *amino.Codec
|
|
}
|
|
|
|
var _ AnyUnpacker = AminoJSONUnpacker{}
|
|
|
|
func (a AminoJSONUnpacker) UnpackAny(any *Any, iface interface{}) error {
|
|
ac := any.compat
|
|
if ac == nil {
|
|
return anyCompatError("JSON unmarshal", reflect.TypeOf(iface))
|
|
}
|
|
err := a.Cdc.UnmarshalJSON(ac.jsonBz, iface)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
val := reflect.ValueOf(iface).Elem().Interface()
|
|
err = UnpackInterfaces(val, a)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if m, ok := val.(proto.Message); ok {
|
|
if err = any.pack(m); err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
any.cachedValue = val
|
|
}
|
|
|
|
// this is necessary for tests that use reflect.DeepEqual and compare
|
|
// proto vs amino marshaled values
|
|
any.compat = nil
|
|
|
|
return nil
|
|
}
|
|
|
|
// AminoUnpacker is an AnyUnpacker provided for backwards compatibility with
|
|
// amino for the JSON un-marshaling phase
|
|
type AminoJSONPacker struct {
|
|
Cdc *amino.Codec
|
|
}
|
|
|
|
var _ AnyUnpacker = AminoJSONPacker{}
|
|
|
|
func (a AminoJSONPacker) UnpackAny(any *Any, _ interface{}) error {
|
|
err := UnpackInterfaces(any.cachedValue, a)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
bz, err := a.Cdc.MarshalJSON(any.cachedValue)
|
|
any.compat = &anyCompat{
|
|
jsonBz: bz,
|
|
err: err,
|
|
}
|
|
return err
|
|
}
|
|
|
|
// ProtoJSONPacker is an AnyUnpacker provided for compatibility with jsonpb
|
|
type ProtoJSONPacker struct {
|
|
JSONPBMarshaler *jsonpb.Marshaler
|
|
}
|
|
|
|
var _ AnyUnpacker = ProtoJSONPacker{}
|
|
|
|
func (a ProtoJSONPacker) UnpackAny(any *Any, _ interface{}) error {
|
|
if any == nil {
|
|
return nil
|
|
}
|
|
|
|
if any.cachedValue != nil {
|
|
err := UnpackInterfaces(any.cachedValue, a)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
bz, err := a.JSONPBMarshaler.MarshalToString(any)
|
|
any.compat = &anyCompat{
|
|
jsonBz: []byte(bz),
|
|
err: err,
|
|
}
|
|
|
|
return err
|
|
}
|