diff --git a/core/appconfig/config.go b/core/appconfig/config.go index 75c9c2e905..1131561d25 100644 --- a/core/appconfig/config.go +++ b/core/appconfig/config.go @@ -4,6 +4,7 @@ import ( "fmt" "strings" + "github.com/cosmos/cosmos-proto/any" "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" @@ -41,7 +42,7 @@ func LoadYAML(bz []byte) depinject.Config { // WrapAny marshals a proto message into a proto Any instance func WrapAny(config protoreflect.ProtoMessage) *anypb.Any { - cfg, err := anypb.New(config) + cfg, err := any.New(config) if err != nil { panic(err) } diff --git a/docs/docs/core/05-encoding.md b/docs/docs/core/05-encoding.md index 744f5debb6..f1728fdd7d 100644 --- a/docs/docs/core/05-encoding.md +++ b/docs/docs/core/05-encoding.md @@ -244,6 +244,34 @@ A real-life example of encoding the pubkey as `Any` inside the Validator struct https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/staking/types/validator.go#L40-L61 ``` +#### `Any`'s TypeURL + +When packing a protobuf message inside an `Any`, the message's type is uniquely defined by its type URL, which is the message's fully qualified name prefixed by a `/` (slash) character. In some implementations of `Any`, like the gogoproto one, there's generally [a resolvable prefix, e.g. `type.googleapis.com`](https://github.com/gogo/protobuf/blob/b03c65ea87cdc3521ede29f62fe3ce239267c1bc/protobuf/google/protobuf/any.proto#L87-L91). However, in the Cosmos SDK, we made the decision to not include such prefix, to have shorter type URLs. The Cosmos SDK's own `Any` implementation can be found in `github.com/cosmos/cosmos-sdk/codec/types`. + +The Cosmos SDK is also switching away from gogoproto to the official `google.golang.org/protobuf` (known as the Protobuf API v2). Its default `Any` implementation also contains the [`type.googleapis.com`](https://github.com/protocolbuffers/protobuf-go/blob/v1.28.1/types/known/anypb/any.pb.go#L266) prefix. To maintain compatibility with the SDK, the following methods from `"google.golang.org/protobuf/types/known/anypb"` should not be used: +- `anypb.New` +- `anypb.MarshalFrom` +- `anypb.Any#MarshalFrom` + +Instead, the Cosmos SDK provides helper functions in `"github.com/cosmos/cosmos-proto/any"`, which create an official `anypb.Any` without inserting the prefixes: +- `any.New` +- `any.MarshalFrom` + +For example, to pack a `sdk.Msg` called `internalMsg`, use: + +```diff +import ( +- "google.golang.org/protobuf/types/known/anypb" ++ "github.com/cosmos/cosmos-proto/any" +) + +- anyMsg, err := anypb.New(internalMsg.Message().Interface()) ++ anyMsg, err := any.New(internalMsg.Message().Interface()) + +- fmt.Println(anyMsg.TypeURL) // type.googleapis.com/cosmos.bank.v1beta1.MsgSend ++ fmt.Println(anyMsg.TypeURL) // /cosmos.bank.v1beta1.MsgSend +``` + ## FAQ ### How to create modules using protobuf encoding diff --git a/orm/internal/stablejson/encode_test.go b/orm/internal/stablejson/encode_test.go index 790045c5d5..b47af60554 100644 --- a/orm/internal/stablejson/encode_test.go +++ b/orm/internal/stablejson/encode_test.go @@ -10,11 +10,12 @@ import ( bankv1beta1 "cosmossdk.io/api/cosmos/bank/v1beta1" basev1beta1 "cosmossdk.io/api/cosmos/base/v1beta1" txv1beta1 "cosmossdk.io/api/cosmos/tx/v1beta1" + "github.com/cosmos/cosmos-proto/any" "github.com/cosmos/cosmos-sdk/orm/internal/stablejson" ) func TestStableJSON(t *testing.T) { - msg, err := anypb.New(&bankv1beta1.MsgSend{ + msg, err := any.New(&bankv1beta1.MsgSend{ FromAddress: "foo213325", ToAddress: "foo32t5sdfh", Amount: []*basev1beta1.Coin{ diff --git a/tx/textual/internal/testdata/any.json b/tx/textual/internal/testdata/any.json index a32415ff39..5e1ad03289 100644 --- a/tx/textual/internal/testdata/any.json +++ b/tx/textual/internal/testdata/any.json @@ -1,74 +1,74 @@ [ { "proto": { - "@type": "type.googleapis.com/Foo" + "@type": "/Foo" }, "screens": [ - {"text": "Object: type.googleapis.com/Foo"}, + {"text": "Object: /Foo"}, {"text": "Foo object", "indent": 1} ] }, { "proto": { - "@type": "type.googleapis.com/Foo", + "@type": "/Foo", "full_name": "testing" }, "screens": [ - {"text": "Object: type.googleapis.com/Foo"}, + {"text": "Object: /Foo"}, {"text": "Foo object", "indent": 1}, {"text": "Full name: testing", "indent": 2} ] }, { "proto": { - "@type": "type.googleapis.com/google.protobuf.Timestamp", + "@type": "/google.protobuf.Timestamp", "value": "2006-01-02T15:04:05Z" }, "screens": [ - {"text": "Object: type.googleapis.com/google.protobuf.Timestamp"}, + {"text": "Object: /google.protobuf.Timestamp"}, {"text": "2006-01-02T15:04:05Z", "indent": 1} ] }, { "proto": { - "@type": "type.googleapis.com/google.protobuf.Any", + "@type": "/google.protobuf.Any", "value": { - "@type": "type.googleapis.com/Foo" + "@type": "/Foo" } }, "screens": [ - {"text": "Object: type.googleapis.com/google.protobuf.Any"}, - {"text": "Object: type.googleapis.com/Foo", "indent": 1}, + {"text": "Object: /google.protobuf.Any"}, + {"text": "Object: /Foo", "indent": 1}, {"text": "Foo object", "indent": 2} ] }, { "proto": { - "@type": "type.googleapis.com/google.protobuf.Any", + "@type": "/google.protobuf.Any", "value": { - "@type": "type.googleapis.com/Foo", + "@type": "/Foo", "full_name": "testing" } }, "screens": [ - {"text": "Object: type.googleapis.com/google.protobuf.Any"}, - {"text": "Object: type.googleapis.com/Foo", "indent": 1}, + {"text": "Object: /google.protobuf.Any"}, + {"text": "Object: /Foo", "indent": 1}, {"text": "Foo object", "indent": 2}, {"text": "Full name: testing", "indent": 3} ] }, { "proto": { - "@type": "type.googleapis.com/A", + "@type": "/A", "ANY": { - "@type": "type.googleapis.com/Foo", + "@type": "/Foo", "full_name": "testing" } }, "screens": [ - {"text": "Object: type.googleapis.com/A"}, + {"text": "Object: /A"}, {"text": "A object", "indent": 1}, - {"text": "ANY: Object: type.googleapis.com/Foo", "indent": 2}, + {"text": "ANY: Object: /Foo", "indent": 2}, {"text": "Foo object", "indent": 3}, {"text": "Full name: testing", "indent": 4} ] diff --git a/tx/textual/valuerenderer/any.go b/tx/textual/valuerenderer/any.go index decb7e86c1..69cd9f0ba7 100644 --- a/tx/textual/valuerenderer/any.go +++ b/tx/textual/valuerenderer/any.go @@ -5,6 +5,7 @@ import ( "fmt" "strings" + "github.com/cosmos/cosmos-proto/any" "google.golang.org/protobuf/reflect/protoreflect" "google.golang.org/protobuf/reflect/protoregistry" "google.golang.org/protobuf/types/known/anypb" @@ -93,7 +94,7 @@ func (ar anyValueRenderer) Parse(ctx context.Context, screens []Screen) (protore return nilValue, err } - anyMsg, err := anypb.New(internalMsg.Message().Interface()) + anyMsg, err := any.New(internalMsg.Message().Interface()) if err != nil { return nilValue, err }