Skip to content

Commit

Permalink
Update Encoding Doc for 0.40 (#7430)
Browse files Browse the repository at this point in the history
* Remove deprecated docs and add first guidelines to protobuf migration

* Add conventions

* Reorder and add more FAQ doc

* Update guidelines for pb msg definitions

* Use commit hash in github links

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
  • Loading branch information
blushi and mergify[bot] committed Oct 7, 2020
1 parent bb6b0cf commit eff82d0
Showing 1 changed file with 76 additions and 23 deletions.
99 changes: 76 additions & 23 deletions docs/core/encoding.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,15 @@ order: 6

# Encoding

The `codec` is used everywhere in the Cosmos SDK to encode and decode structs and interfaces. The specific codec used in the Cosmos SDK is called `go-amino`. {synopsis}
While encoding in the SDK used to be mainly handled by `go-amino` codec, the SDK is moving towards using `gogoprotobuf` for both state and client-side encoding. {synopsis}

## Pre-requisite Readings

- [Anatomy of an SDK application](../basics/app-anatomy.md) {prereq}

## Encoding

The Cosmos SDK utilizes two binary wire encoding protocols, [Amino](https://github.com/tendermint/go-amino/)
and [Protocol Buffers](https://developers.google.com/protocol-buffers), where Amino
is an object encoding specification. It is a subset of Proto3 with an extension for
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
interface support. See the [Proto3 spec](https://developers.google.com/protocol-buffers/docs/proto3)
for more information on Proto3, which Amino is largely compatible with (but not with Proto2).

Expand All @@ -40,13 +38,10 @@ In the `codec` package, there exists two core interfaces, `Marshaler` and `Proto
where the former encapsulates the current Amino interface except it operates on
types implementing the latter instead of generic `interface{}` types.

In addition, there exists three implementations of `Marshaler`. The first being
In addition, there exists two implementations of `Marshaler`. The first being
`AminoCodec`, where both binary and JSON serialization is handled via Amino. The
second being `ProtoCodec`, where both binary and JSON serialization is handled
via Protobuf. Finally, `HybridCodec`, a codec that utilizes Protobuf for binary
serialization and Amino for JSON serialization. The `HybridCodec` is typically
the codec that used in majority in situations as it's easier to use for client
and state serialization.
via Protobuf.

This means that modules may use Amino or Protobuf encoding but the types must
implement `ProtoMarshaler`. If modules wish to avoid implementing this interface
Expand All @@ -72,30 +67,88 @@ Note, there are length-prefixed variants of the above functionality and this is
typically used for when the data needs to be streamed or grouped together
(e.g. `ResponseDeliverTx.Data`)

Another important use of the Amino is the encoding and decoding of
### Gogoproto

Modules are encouraged to utilize Protobuf encoding for their respective types.

#### FAQ

1. How to create modules using protobuf encoding?

**Defining module types**

Protobuf types can be defined to encode:
- state
- [`Msg`s](../building-modules/messages-and-queries.md#messages)
- [queries](../building-modules/querier.md)
- [genesis](../building-modules/genesis.md)

**Naming and conventions**

We encourage developers to follow industry guidelines: [Protocol Buffers style guide](https://developers.google.com/protocol-buffers/docs/style)
and [Buf](https://buf.build/docs/style-guide), see more details in [ADR 023](../architecture/adr-023-protobuf-naming.md)

2. How to update modules to protobuf encoding?

If modules do not contain any interfaces (e.g. `Account` or `Content`), then they
may simply migrate any existing types that
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`
without any further customization.

However, if modules are to handle type interfaces, module-level .proto files should define messages which encode interfaces
using [`google.protobuf.Any`](https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto).

For example, we can define `MsgSubmitEvidence` as follows where `Evidence` is
an interface:

```protobuf
// proto/cosmos/evidence/v1beta1/tx.proto
message MsgSubmitEvidence {
string submitter = 1;
google.protobuf.Any evidence = 2 [(cosmos_proto.accepts_interface) = "Evidence"];
}
```

The SDK provides support methods `MarshalAny` and `UnmarshalAny` to allow
easy encoding of state to `Any`.

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:

+++ https://github.com/cosmos/cosmos-sdk/blob/3d969a1ffdf9a80f9ee16db9c16b8a8aa1004af6/codec/types/interface_registry.go#L23-L52

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:

```go
type UnpackInterfacesMessage interface {
UnpackInterfaces(InterfaceUnpacker) error
}
```

#### Guidelines for protobuf message definitions

In addition to [following official guidelines](https://developers.google.com/protocol-buffers/docs/proto3#simple), we recommend to use these annotations in .proto files when dealing with interfaces:
* fields which accept interfaces should be annotated with `cosmos_proto.accepts_interface`
using the same full-qualified name passed as `protoName` to `InterfaceRegistry.RegisterInterface`
* interface implementations should be annotated with `cosmos_proto.implements_interface`
using the same full-qualified name passed as `protoName` to `InterfaceRegistry.RegisterInterface`

#### Transaction Encoding

Another important use of Protobuf is the encoding and decoding of
[transactions](./transactions.md). Transactions are defined by the application or
the SDK, but passed to the underlying consensus engine in order to be relayed to
other peers. Since the underlying consensus engine is agnostic to the application,
it only accepts transactions in the form of raw bytes. The encoding is done by an
object called `TxEncoder` and the decoding by an object called `TxDecoder`.

+++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/tx_msg.go#L45-L49
+++ https://github.com/cosmos/cosmos-sdk/blob/9ae17669d6715a84c20d52e10e2232be9f467360/types/tx_msg.go#L82-L86

A standard implementation of both these objects can be found in the [`auth` module](https://github.com/cosmos/cosmos-sdk/blob/master/x/auth):

+++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/x/auth/types/stdtx.go#L241-L266

### Gogoproto

Modules are encouraged to utilize Protobuf encoding for their respective types.
If modules do not contain any interfaces (e.g. `Account` or `Content`), then they
may simply accept a `Marshaler` as the codec which is implemented via the `HybridCodec`
without any further customization.
+++ https://github.com/cosmos/cosmos-sdk/blob/9ae17669d6715a84c20d52e10e2232be9f467360/x/auth/tx/decoder.go

However, if modules are to handle type interfaces, they should seek to extend the
`Marshaler` interface contract for these types (e.g. `MarshalAccount`). Note, they
should still use a `HybridCodec` internally. These extended contracts will typically
use concrete types with unique `oneof` messages.
+++ https://github.com/cosmos/cosmos-sdk/blob/9ae17669d6715a84c20d52e10e2232be9f467360/x/auth/tx/encoder.go

## Next {hide}

Expand Down

0 comments on commit eff82d0

Please sign in to comment.