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

     1  package types
     2  
     3  import (
     4  	fmt "fmt"
     5  
     6  	"github.com/cosmos/gogoproto/proto"
     7  	protov2 "google.golang.org/protobuf/proto"
     8  
     9  	errorsmod "cosmossdk.io/errors"
    10  
    11  	sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
    12  )
    13  
    14  // nolint:revive // XXX is reqired for proto compatibility
    15  type Any struct {
    16  	// A URL/resource name that uniquely identifies the type of the serialized
    17  	// protocol buffer message. This string must contain at least
    18  	// one "/" character. The last segment of the URL's path must represent
    19  	// the fully qualified name of the type (as in
    20  	// `path/google.protobuf.Duration`). The name should be in a canonical form
    21  	// (e.g., leading "." is not accepted).
    22  	//
    23  	// In practice, teams usually precompile into the binary all types that they
    24  	// expect it to use in the context of Any. However, for URLs which use the
    25  	// scheme `http`, `https`, or no scheme, one can optionally set up a type
    26  	// server that maps type URLs to message definitions as follows:
    27  	//
    28  	// * If no scheme is provided, `https` is assumed.
    29  	// * An HTTP GET on the URL must yield a [google.protobuf.Type][]
    30  	//   value in binary format, or produce an error.
    31  	// * Applications are allowed to cache lookup results based on the
    32  	//   URL, or have them precompiled into a binary to avoid any
    33  	//   lookup. Therefore, binary compatibility needs to be preserved
    34  	//   on changes to types. (Use versioned type names to manage
    35  	//   breaking changes.)
    36  	//
    37  	// Note: this functionality is not currently available in the official
    38  	// protobuf release, and it is not used for type URLs beginning with
    39  	// type.googleapis.com.
    40  	//
    41  	// Schemes other than `http`, `https` (or the empty scheme) might be
    42  	// used with implementation specific semantics.
    43  
    44  	TypeUrl string `protobuf:"bytes,1,opt,name=type_url,json=typeUrl,proto3" json:"type_url,omitempty"`
    45  
    46  	// Must be a valid serialized protocol buffer of the above specified type.
    47  	Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
    48  
    49  	XXX_NoUnkeyedLiteral struct{} `json:"-"`
    50  	XXX_unrecognized     []byte   `json:"-"`
    51  	XXX_sizecache        int32    `json:"-"`
    52  
    53  	cachedValue interface{}
    54  
    55  	compat *anyCompat
    56  }
    57  
    58  // NewAnyWithValue constructs a new Any packed with the value provided or
    59  // returns an error if that value couldn't be packed. This also caches
    60  // the packed value so that it can be retrieved from GetCachedValue without
    61  // unmarshaling
    62  func NewAnyWithValue(v proto.Message) (*Any, error) {
    63  	if v == nil {
    64  		return nil, errorsmod.Wrap(sdkerrors.ErrPackAny, "Expecting non nil value to create a new Any")
    65  	}
    66  
    67  	var (
    68  		bz  []byte
    69  		err error
    70  	)
    71  	if msg, ok := v.(protov2.Message); ok {
    72  		protov2MarshalOpts := protov2.MarshalOptions{Deterministic: true}
    73  		bz, err = protov2MarshalOpts.Marshal(msg)
    74  	} else {
    75  		bz, err = proto.Marshal(v)
    76  	}
    77  	if err != nil {
    78  		return nil, err
    79  	}
    80  
    81  	return &Any{
    82  		TypeUrl:     MsgTypeURL(v),
    83  		Value:       bz,
    84  		cachedValue: v,
    85  	}, nil
    86  }
    87  
    88  // UnsafePackAny packs the value x in the Any and instead of returning the error
    89  // in the case of a packing failure, keeps the cached value. This should only
    90  // be used in situations where compatibility is needed with amino. Amino-only
    91  // values can safely be packed using this method when they will only be
    92  // marshaled with amino and not protobuf.
    93  func UnsafePackAny(x interface{}) *Any {
    94  	if msg, ok := x.(proto.Message); ok {
    95  		any, err := NewAnyWithValue(msg)
    96  		if err == nil {
    97  			return any
    98  		}
    99  	}
   100  	return &Any{cachedValue: x}
   101  }
   102  
   103  // pack packs the value x in the Any or returns an error. This also caches
   104  // the packed value so that it can be retrieved from GetCachedValue without
   105  // unmarshaling
   106  func (any *Any) pack(x proto.Message) error {
   107  	any.TypeUrl = MsgTypeURL(x)
   108  
   109  	var (
   110  		bz  []byte
   111  		err error
   112  	)
   113  	if msg, ok := x.(protov2.Message); ok {
   114  		protov2MarshalOpts := protov2.MarshalOptions{Deterministic: true}
   115  		bz, err = protov2MarshalOpts.Marshal(msg)
   116  	} else {
   117  		bz, err = proto.Marshal(x)
   118  	}
   119  	if err != nil {
   120  		return err
   121  	}
   122  
   123  	any.Value = bz
   124  	any.cachedValue = x
   125  
   126  	return nil
   127  }
   128  
   129  // GetCachedValue returns the cached value from the Any if present
   130  func (any *Any) GetCachedValue() interface{} {
   131  	return any.cachedValue
   132  }
   133  
   134  // GoString returns a string representing valid go code to reproduce the current state of
   135  // the struct.
   136  func (any *Any) GoString() string {
   137  	if any == nil {
   138  		return "nil"
   139  	}
   140  	extra := ""
   141  	if any.XXX_unrecognized != nil {
   142  		extra = fmt.Sprintf(",\n  XXX_unrecognized: %#v,\n", any.XXX_unrecognized)
   143  	}
   144  	return fmt.Sprintf("&Any{TypeUrl: %#v,\n  Value: %#v%s\n}",
   145  		any.TypeUrl, any.Value, extra)
   146  }
   147  
   148  // String implements the stringer interface
   149  func (any *Any) String() string {
   150  	if any == nil {
   151  		return "nil"
   152  	}
   153  	return fmt.Sprintf("&Any{TypeUrl:%v,Value:%v,XXX_unrecognized:%v}",
   154  		any.TypeUrl, any.Value, any.XXX_unrecognized)
   155  }