github.com/Finschia/finschia-sdk@v0.48.1/docs/core/encoding.md (about)

     1  <!--
     2  order: 6
     3  -->
     4  
     5  # Encoding
     6  
     7  While encoding in the Cosmos SDK used to be mainly handled by `go-amino` codec, the Cosmos SDK is moving towards using `gogoprotobuf` for both state and client-side encoding. {synopsis}
     8  
     9  ## Pre-requisite Readings
    10  
    11  * [Anatomy of a Cosmos SDK application](../basics/app-anatomy.md) {prereq}
    12  
    13  ## Encoding
    14  
    15  The Cosmos SDK utilizes two binary wire encoding protocols, [Amino](https://github.com/tendermint/go-amino/) which is an object encoding specification and [Protocol Buffers](https://developers.google.com/protocol-buffers), a subset of Proto3 with an extension for
    16  interface support. See the [Proto3 spec](https://developers.google.com/protocol-buffers/docs/proto3)
    17  for more information on Proto3, which Amino is largely compatible with (but not with Proto2).
    18  
    19  Due to Amino having significant performance drawbacks, being reflection-based, and
    20  not having any meaningful cross-language/client support, Protocol Buffers, specifically
    21  [gogoprotobuf](https://github.com/gogo/protobuf/), is being used in place of Amino.
    22  Note, this process of using Protocol Buffers over Amino is still an ongoing process.
    23  
    24  Binary wire encoding of types in the Cosmos SDK can be broken down into two main
    25  categories, client encoding and store encoding. Client encoding mainly revolves
    26  around transaction processing and signing, whereas store encoding revolves around
    27  types used in state-machine transitions and what is ultimately stored in the Merkle
    28  tree.
    29  
    30  For store encoding, protobuf definitions can exist for any type and will typically
    31  have an Amino-based "intermediary" type. Specifically, the protobuf-based type
    32  definition is used for serialization and persistence, whereas the Amino-based type
    33  is used for business logic in the state-machine where they may converted back-n-forth.
    34  Note, the Amino-based types may slowly be phased-out in the future so developers
    35  should take note to use the protobuf message definitions where possible.
    36  
    37  In the `codec` package, there exists two core interfaces, `Marshaler` and `ProtoMarshaler`,
    38  where the former encapsulates the current Amino interface except it operates on
    39  types implementing the latter instead of generic `interface{}` types.
    40  
    41  In addition, there exists two implementations of `Marshaler`. The first being
    42  `AminoCodec`, where both binary and JSON serialization is handled via Amino. The
    43  second being `ProtoCodec`, where both binary and JSON serialization is handled
    44  via Protobuf.
    45  
    46  This means that modules may use Amino or Protobuf encoding but the types must
    47  implement `ProtoMarshaler`. If modules wish to avoid implementing this interface
    48  for their types, they may use an Amino codec directly.
    49  
    50  ### Amino
    51  
    52  Every module uses an Amino codec to serialize types and interfaces. This codec typically
    53  has types and interfaces registered in that module's domain only (e.g. messages),
    54  but there are exceptions like `x/gov`. Each module exposes a `RegisterLegacyAminoCodec` function
    55  that allows a user to provide a codec and have all the types registered. An application
    56  will call this method for each necessary module.
    57  
    58  Where there is no protobuf-based type definition for a module (see below), Amino
    59  is used to encode and decode raw wire bytes to the concrete type or interface:
    60  
    61  ```go
    62  bz := keeper.cdc.MustMarshal(typeOrInterface)
    63  keeper.cdc.MustUnmarshal(bz, &typeOrInterface)
    64  ```
    65  
    66  Note, there are length-prefixed variants of the above functionality and this is
    67  typically used for when the data needs to be streamed or grouped together
    68  (e.g. `ResponseDeliverTx.Data`)
    69  
    70  #### Authz authorizations and Gov proposals
    71  
    72  Since authz's `MsgExec` and `MsgGrant` message types, as well as gov's `MsgSubmitProposal`, can contain different messages instances, it is important that developers
    73  add the following code inside the `init` method of their module's `codec.go` file:
    74  
    75  ```go
    76  import (
    77    authzcodec "github.com/Finschia/finschia-sdk/x/authz/codec"
    78    govcodec "github.com/Finschia/finschia-sdk/x/gov/codec"
    79  )
    80  
    81  init() {
    82      // Register all Amino interfaces and concrete types on the authz and gov Amino codec so that this can later be
    83      // used to properly serialize MsgGrant, MsgExec and MsgSubmitProposal instances
    84      RegisterLegacyAminoCodec(authzcodec.Amino)
    85      RegisterLegacyAminoCodec(govcodec.Amino)
    86  }
    87  ```
    88  
    89  This will allow the `x/authz` module to properly serialize and de-serializes `MsgExec` instances using Amino, 
    90  which is required when signing this kind of messages using a Ledger. 
    91  
    92  ### Gogoproto
    93  
    94  Modules are encouraged to utilize Protobuf encoding for their respective types. In the Cosmos SDK, we use the [Gogoproto](https://github.com/gogo/protobuf) specific implementation of the Protobuf spec that offers speed and DX improvements compared to the official [Google protobuf implementation](https://github.com/protocolbuffers/protobuf).
    95  
    96  ### Guidelines for protobuf message definitions
    97  
    98  In addition to [following official Protocol Buffer guidelines](https://developers.google.com/protocol-buffers/docs/proto3#simple), we recommend using these annotations in .proto files when dealing with interfaces:
    99  
   100  * use `cosmos_proto.accepts_interface` to annote fields that accept interfaces
   101  * pass the same fully qualified name as `protoName` to `InterfaceRegistry.RegisterInterface`
   102  * annotate interface implementations with `cosmos_proto.implements_interface`
   103  * pass the same fully qualified name as `protoName` to `InterfaceRegistry.RegisterInterface`
   104  
   105  ### Transaction Encoding
   106  
   107  Another important use of Protobuf is the encoding and decoding of
   108  [transactions](./transactions.md). Transactions are defined by the application or
   109  the Cosmos SDK but are then passed to the underlying consensus engine to be relayed to
   110  other peers. Since the underlying consensus engine is agnostic to the application,
   111  the consensus engine accepts only transactions in the form of raw bytes.
   112  
   113  * The `TxEncoder` object performs the encoding.
   114  * The `TxDecoder` object performs the decoding.
   115  
   116  +++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc4/types/tx_msg.go#L83-L87
   117  
   118  A standard implementation of both these objects can be found in the [`auth` module](../../x/auth/spec/README.md):
   119  
   120  +++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc4/x/auth/tx/decoder.go
   121  
   122  +++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc4/x/auth/tx/encoder.go
   123  
   124  See [ADR-020](../architecture/adr-020-protobuf-transaction-encoding.md) for details of how a transaction is encoded.
   125  
   126  ### Interface Encoding and Usage of `Any`
   127  
   128  The Protobuf DSL is strongly typed, which can make inserting variable-typed fields difficult. Imagine we want to create a `Profile` protobuf message that serves as a wrapper over [an account](../basics/accounts.md):
   129  
   130  ```proto
   131  message Profile {
   132    // account is the account associated to a profile.
   133    cosmos.auth.v1beta1.BaseAccount account = 1;
   134    // bio is a short description of the account.
   135    string bio = 4;
   136  }
   137  ```
   138  
   139  In this `Profile` example, we hardcoded `account` as a `BaseAccount`. However, there are several other types of [user accounts related to vesting](../../x/auth/spec/05_vesting.md), such as `BaseVestingAccount` or `ContinuousVestingAccount`. All of these accounts are different, but they all implement the `AccountI` interface. How would you create a `Profile` that allows all these types of accounts with an `account` field that accepts an `AccountI` interface?
   140  
   141  +++ https://github.com/cosmos/cosmos-sdk/blob/v0.42.1/x/auth/types/account.go#L307-L330
   142  
   143  In [ADR-019](../architecture/adr-019-protobuf-state-encoding.md), it has been decided to use [`Any`](https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto)s to encode interfaces in protobuf. An `Any` contains an arbitrary serialized message as bytes, along with a URL that acts as a globally unique identifier for and resolves to that message's type. This strategy allows us to pack arbitrary Go types inside protobuf messages. Our new `Profile` then looks like:
   144  
   145  ```protobuf
   146  message Profile {
   147    // account is the account associated to a profile.
   148    google.protobuf.Any account = 1 [
   149      (cosmos_proto.accepts_interface) = "AccountI"; // Asserts that this field only accepts Go types implementing `AccountI`. It is purely informational for now.
   150    ];
   151    // bio is a short description of the account.
   152    string bio = 4;
   153  }
   154  ```
   155  
   156  To add an account inside a profile, we need to "pack" it inside an `Any` first, using `codectypes.NewAnyWithValue`:
   157  
   158  ```go
   159  var myAccount AccountI
   160  myAccount = ... // Can be a BaseAccount, a ContinuousVestingAccount or any struct implementing `AccountI`
   161  
   162  // Pack the account into an Any
   163  accAny, err := codectypes.NewAnyWithValue(myAccount)
   164  if err != nil {
   165    return nil, err
   166  }
   167  
   168  // Create a new Profile with the any.
   169  profile := Profile {
   170    Account: accAny,
   171    Bio: "some bio",
   172  }
   173  
   174  // We can then marshal the profile as usual.
   175  bz, err := cdc.Marshal(profile)
   176  jsonBz, err := cdc.MarshalJSON(profile)
   177  ```
   178  
   179  To summarize, to encode an interface, you must 1/ pack the interface into an `Any` and 2/ marshal the `Any`. For convenience, the Cosmos SDK provides a `MarshalInterface` method to bundle these two steps. Have a look at [a real-life example in the x/auth module](https://github.com/cosmos/cosmos-sdk/blob/v0.42.1/x/auth/keeper/keeper.go#L218-L221).
   180  
   181  The reverse operation of retrieving the concrete Go type from inside an `Any`, called "unpacking", is done with the `GetCachedValue()` on `Any`.
   182  
   183  ```go
   184  profileBz := ... // The proto-encoded bytes of a Profile, e.g. retrieved through gRPC.
   185  var myProfile Profile
   186  // Unmarshal the bytes into the myProfile struct.
   187  err := cdc.Unmarshal(profilebz, &myProfile)
   188  
   189  // Let's see the types of the Account field.
   190  fmt.Printf("%T\n", myProfile.Account)                  // Prints "Any"
   191  fmt.Printf("%T\n", myProfile.Account.GetCachedValue()) // Prints "BaseAccount", "ContinuousVestingAccount" or whatever was initially packed in the Any.
   192  
   193  // Get the address of the accountt.
   194  accAddr := myProfile.Account.GetCachedValue().(AccountI).GetAddress()
   195  ```
   196  
   197  It is important to note that for `GetCachedValue()` to work, `Profile` (and any other structs embedding `Profile`) must implement the `UnpackInterfaces` method:
   198  
   199  ```go
   200  func (p *Profile) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error {
   201    if p.Account != nil {
   202      var account AccountI
   203      return unpacker.UnpackAny(p.Account, &account)
   204    }
   205  
   206    return nil
   207  }
   208  ```
   209  
   210  The `UnpackInterfaces` gets called recursively on all structs implementing this method, to allow all `Any`s to have their `GetCachedValue()` correctly populated.
   211  
   212  For more information about interface encoding, and especially on `UnpackInterfaces` and how the `Any`'s `type_url` gets resolved using the `InterfaceRegistry`, please refer to [ADR-019](../architecture/adr-019-protobuf-state-encoding.md).
   213  
   214  #### `Any` Encoding in the Cosmos SDK
   215  
   216  The above `Profile` example is a fictive example used for educational purposes. In the Cosmos SDK, we use `Any` encoding in several places (non-exhaustive list):
   217  
   218  * the `cryptotypes.PubKey` interface for encoding different types of public keys,
   219  * the `sdk.Msg` interface for encoding different `Msg`s in a transaction,
   220  * the `AccountI` interface for encodinig different types of accounts (similar to the above example) in the x/auth query responses,
   221  * the `Evidencei` interface for encoding different types of evidences in the x/evidence module,
   222  * the `AuthorizationI` interface for encoding different types of x/authz authorizations,
   223  * the [`Validator`](https://github.com/cosmos/cosmos-sdk/blob/v0.42.5/x/staking/types/staking.pb.go#L306-L337) struct that contains information about a validator.
   224  
   225  A real-life example of encoding the pubkey as `Any` inside the Validator struct in x/staking is shown in the following example:
   226  
   227  +++ https://github.com/cosmos/cosmos-sdk/blob/v0.42.1/x/staking/types/validator.go#L40-L61
   228  
   229  ## FAQ
   230  
   231  ### How to create modules using protobuf encoding
   232  
   233  #### Defining module types
   234  
   235  Protobuf types can be defined to encode:
   236  
   237  * state
   238  * [`Msg`s](../building-modules/messages-and-queries.md#messages)
   239  * [Query services](../building-modules/query-services.md)
   240  * [genesis](../building-modules/genesis.md)
   241  
   242  #### Naming and conventions
   243  
   244  We encourage developers to follow industry guidelines: [Protocol Buffers style guide](https://developers.google.com/protocol-buffers/docs/style)
   245  and [Buf](https://buf.build/docs/style-guide), see more details in [ADR 023](../architecture/adr-023-protobuf-naming.md)
   246  
   247  ### How to update modules to protobuf encoding
   248  
   249  If modules do not contain any interfaces (e.g. `Account` or `Content`), then they
   250  may simply migrate any existing types that
   251  are encoded and persisted via their concrete Amino codec to Protobuf (see 1. for further guidelines) and accept a `Marshaler` as the codec which is implemented via the `ProtoCodec`
   252  without any further customization.
   253  
   254  However, if a module type composes an interface, it must wrap it in the `skd.Any` (from `/types` package) type. To do that, a module-level .proto file must use [`google.protobuf.Any`](https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto) for respective message type interface types.
   255  
   256  For example, in the `x/evidence` module defines an `Evidence` interface, which is used by the `MsgSubmitEvidence`. The structure definition must use `sdk.Any` to wrap the evidence file. In the proto file we define it as follows:
   257  
   258  ```protobuf
   259  // proto/cosmos/evidence/v1beta1/tx.proto
   260  
   261  message MsgSubmitEvidence {
   262    string              submitter = 1;
   263    google.protobuf.Any evidence  = 2 [(cosmos_proto.accepts_interface) = "Evidence"];
   264  }
   265  ```
   266  
   267  The Cosmos SDK `codec.Codec` interface provides support methods `MarshalInterface` and `UnmarshalInterface` to easy encoding of state to `Any`.
   268  
   269  Module should register interfaces using `InterfaceRegistry` which provides a mechanism for registering interfaces: `RegisterInterface(protoName string, iface interface{})` and implementations: `RegisterImplementations(iface interface{}, impls ...proto.Message)` that can be safely unpacked from Any, similarly to type registration with Amino:
   270  
   271  +++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc4/codec/types/interface_registry.go#L25-L66
   272  
   273  In addition, an `UnpackInterfaces` phase should be introduced to deserialization to unpack interfaces before they're needed. Protobuf types that contain a protobuf `Any` either directly or via one of their members should implement the `UnpackInterfacesMessage` interface:
   274  
   275  ```go
   276  type UnpackInterfacesMessage interface {
   277    UnpackInterfaces(InterfaceUnpacker) error
   278  }
   279  ```
   280  
   281  ## Next {hide}
   282  
   283  Learn about [gRPC, REST and other endpoints](./grpc_rest.md) {hide}