Skip to content

Commit

Permalink
Merge PR cosmos#5634: Protobuf - Migrate x/evidence
Browse files Browse the repository at this point in the history
  • Loading branch information
tac0turtle authored Feb 24, 2020
1 parent e3dc0fd commit f7486b9
Show file tree
Hide file tree
Showing 71 changed files with 3,143 additions and 756 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,17 @@ serialization instead of Amino.
requiring a concrete codec to know how to serialize `SupplyI` types.
* The `SupplyI` interface has been modified to no longer return `SupplyI` on methods. Instead the
concrete type's receiver should modify the type.
* (x/mint) [\#5634](https://github.com/cosmos/cosmos-sdk/pull/5634) Migrate the `x/mint` module to use Protocol Buffers for state
serialization instead of Amino.
* The `internal` sub-package has been removed in order to expose the types proto file.
* (x/evidence) [\#5634](https://github.com/cosmos/cosmos-sdk/pull/5634) Migrate the `x/evidence` module to use Protocol Buffers for state
serialization instead of Amino.
* The `internal` sub-package has been removed in order to expose the types proto file.
* The module now accepts a `Codec` interface which extends the `codec.Marshaler` interface by
requiring a concrete codec to know how to serialize `Evidence` types.
* The `MsgSubmitEvidence` message has been removed in favor of `MsgSubmitEvidenceBase`. The application-level
codec must now define the concrete `MsgSubmitEvidence` type which must implement the module's `MsgSubmitEvidence`
interface.

### Improvements

Expand Down
103 changes: 86 additions & 17 deletions docs/architecture/adr-019-protobuf-state-encoding.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## Changelog

- 2020 Feb 15: Initial Draft
- 2020 Feb 24: Updates to handle messages with interface fields

## Status

Expand Down Expand Up @@ -143,19 +144,6 @@ message Account {
```go
// app/codec/codec.go

import (
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/supply"
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
// ...
)

var (
_ auth.Codec = (*Codec)(nil)
// ...
)

type Codec struct {
codec.Marshaler

Expand Down Expand Up @@ -192,10 +180,91 @@ about all the required types. Note, the use of `interface_type` allows us to avo
amount of code boilerplate when implementing the `Codec`.

A similar concept is to be applied for messages that contain interfaces fields. The module will
define a "base" concrete message type (e.g. `MsgSubmitProposalBase`) that the application-level codec
will extend via `oneof` (e.g. `MsgSubmitProposal`) that fulfills the required interface
(e.g. `MsgSubmitProposalI`). Note, however, the module's message handler must now switch on the
interface rather than the concrete type for this particular message.
define a "base" concrete message type that the application-level codec will extend via `oneof` that
fulfills the required message interface.

Example:

The `MsgSubmitEvidence` defined by the `x/evidence` module contains a field `Evidence` which is an
interface.

```go
type MsgSubmitEvidence struct {
Evidence exported.Evidence
Submitter sdk.AccAddress
}
```

Instead, we will implement a "base" message type and an interface which the concrete message type
must implement.

```protobuf
// x/evidence/types/types.proto
message MsgSubmitEvidenceBase {
bytes submitter = 1
[
(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"
];
}
```

```go
// x/evidence/exported/evidence.go

type MsgSubmitEvidence interface {
sdk.Msg

GetEvidence() Evidence
GetSubmitter() sdk.AccAddress
}
```

Notice the `MsgSubmitEvidence` interface extends `sdk.Msg` and allows for the `Evidence` interface
to be retrieved from the concrete message type.

Now, the application-level codec will define the concrete `MsgSubmitEvidence` type and will have it
fulfill the `MsgSubmitEvidence` interface defined by `x/evidence`.

```protobuf
// app/codec/codec.proto
message Evidence {
option (gogoproto.equal) = true;
option (cosmos_proto.interface_type) = "github.com/cosmos/cosmos-sdk/x/evidence/exported.Evidence";
oneof sum {
cosmos_sdk.x.evidence.v1.Equivocation equivocation = 1;
}
}
message MsgSubmitEvidence {
option (gogoproto.equal) = true;
option (gogoproto.goproto_getters) = false;
Evidence evidence = 1;
cosmos_sdk.x.evidence.v1.MsgSubmitEvidenceBase base = 2
[
(gogoproto.nullable) = false,
(gogoproto.embed) = true
];
}
```

```go
// app/codec/msgs.go

func (msg MsgSubmitEvidence) GetEvidence() eviexported.Evidence {
return msg.Evidence.GetEvidence()
}

func (msg MsgSubmitEvidence) GetSubmitter() sdk.AccAddress {
return msg.Submitter
}
```

Note, however, the module's message handler must now handle the interface `MsgSubmitEvidence` in
addition to any concrete types.

### Why Wasn't X Chosen Instead

Expand Down
4 changes: 2 additions & 2 deletions simapp/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ func NewSimApp(
appCodec, keys[staking.StoreKey], app.BankKeeper, app.SupplyKeeper, app.subspaces[staking.ModuleName],
)
app.MintKeeper = mint.NewKeeper(
app.cdc, keys[mint.StoreKey], app.subspaces[mint.ModuleName], &stakingKeeper,
appCodec, keys[mint.StoreKey], app.subspaces[mint.ModuleName], &stakingKeeper,
app.SupplyKeeper, auth.FeeCollectorName,
)
app.DistrKeeper = distr.NewKeeper(
Expand All @@ -193,7 +193,7 @@ func NewSimApp(

// create evidence keeper with router
evidenceKeeper := evidence.NewKeeper(
app.cdc, keys[evidence.StoreKey], app.subspaces[evidence.ModuleName], &app.StakingKeeper, app.SlashingKeeper,
appCodec, keys[evidence.StoreKey], app.subspaces[evidence.ModuleName], &app.StakingKeeper, app.SlashingKeeper,
)
evidenceRouter := evidence.NewRouter()
// TODO: Register evidence routes.
Expand Down
59 changes: 50 additions & 9 deletions simapp/codec/codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,16 @@ import (
"github.com/cosmos/cosmos-sdk/x/auth"
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
"github.com/cosmos/cosmos-sdk/x/auth/vesting"
"github.com/cosmos/cosmos-sdk/x/evidence"
eviexported "github.com/cosmos/cosmos-sdk/x/evidence/exported"
"github.com/cosmos/cosmos-sdk/x/supply"
"github.com/cosmos/cosmos-sdk/x/supply/exported"
supplyexported "github.com/cosmos/cosmos-sdk/x/supply/exported"
)

var (
_ auth.Codec = (*Codec)(nil)
_ supply.Codec = (*Codec)(nil)
_ auth.Codec = (*Codec)(nil)
_ supply.Codec = (*Codec)(nil)
_ evidence.Codec = (*Codec)(nil)
)

// Codec defines the application-level codec. This codec contains all the
Expand Down Expand Up @@ -72,7 +75,7 @@ func (c *Codec) UnmarshalAccountJSON(bz []byte) (authexported.Account, error) {
// MarshalSupply marshals a SupplyI interface. If the given type implements
// the Marshaler interface, it is treated as a Proto-defined message and
// serialized that way. Otherwise, it falls back on the internal Amino codec.
func (c *Codec) MarshalSupply(supplyI exported.SupplyI) ([]byte, error) {
func (c *Codec) MarshalSupply(supplyI supplyexported.SupplyI) ([]byte, error) {
supply := &Supply{}
if err := supply.SetSupplyI(supplyI); err != nil {
return nil, err
Expand All @@ -83,7 +86,7 @@ func (c *Codec) MarshalSupply(supplyI exported.SupplyI) ([]byte, error) {

// UnmarshalSupply returns a SupplyI interface from raw encoded account bytes
// of a Proto-based SupplyI type. An error is returned upon decoding failure.
func (c *Codec) UnmarshalSupply(bz []byte) (exported.SupplyI, error) {
func (c *Codec) UnmarshalSupply(bz []byte) (supplyexported.SupplyI, error) {
supply := &Supply{}
if err := c.Marshaler.UnmarshalBinaryLengthPrefixed(bz, supply); err != nil {
return nil, err
Expand All @@ -94,12 +97,12 @@ func (c *Codec) UnmarshalSupply(bz []byte) (exported.SupplyI, error) {

// MarshalSupplyJSON JSON encodes a supply object implementing the SupplyI
// interface.
func (c *Codec) MarshalSupplyJSON(supply exported.SupplyI) ([]byte, error) {
func (c *Codec) MarshalSupplyJSON(supply supplyexported.SupplyI) ([]byte, error) {
return c.Marshaler.MarshalJSON(supply)
}

// UnmarshalSupplyJSON returns a SupplyI from JSON encoded bytes.
func (c *Codec) UnmarshalSupplyJSON(bz []byte) (exported.SupplyI, error) {
func (c *Codec) UnmarshalSupplyJSON(bz []byte) (supplyexported.SupplyI, error) {
supply := &Supply{}
if err := c.Marshaler.UnmarshalJSON(bz, supply); err != nil {
return nil, err
Expand All @@ -108,9 +111,47 @@ func (c *Codec) UnmarshalSupplyJSON(bz []byte) (exported.SupplyI, error) {
return supply.GetSupplyI(), nil
}

// ----------------------------------------------------------------------------
// MarshalEvidence marshals an Evidence interface. If the given type implements
// the Marshaler interface, it is treated as a Proto-defined message and
// serialized that way. Otherwise, it falls back on the internal Amino codec.
func (c *Codec) MarshalEvidence(evidenceI eviexported.Evidence) ([]byte, error) {
evidence := &Evidence{}
if err := evidence.SetEvidence(evidenceI); err != nil {
return nil, err
}

// MakeCodec creates and returns a reference to an Amino codec that has all the
return c.Marshaler.MarshalBinaryLengthPrefixed(evidence)
}

// UnmarshalEvidence returns an Evidence interface from raw encoded evidence
// bytes of a Proto-based Evidence type. An error is returned upon decoding
// failure.
func (c *Codec) UnmarshalEvidence(bz []byte) (eviexported.Evidence, error) {
evidence := &Evidence{}
if err := c.Marshaler.UnmarshalBinaryLengthPrefixed(bz, evidence); err != nil {
return nil, err
}

return evidence.GetEvidence(), nil
}

// MarshalEvidenceJSON JSON encodes an evidence object implementing the Evidence
// interface.
func (c *Codec) MarshalEvidenceJSON(evidence eviexported.Evidence) ([]byte, error) {
return c.Marshaler.MarshalJSON(evidence)
}

// UnmarshalEvidenceJSON returns an Evidence from JSON encoded bytes
func (c *Codec) UnmarshalEvidenceJSON(bz []byte) (eviexported.Evidence, error) {
evidence := &Evidence{}
if err := c.Marshaler.UnmarshalJSON(bz, evidence); err != nil {
return nil, err
}

return evidence.GetEvidence(), nil
}

// ----------------------------------------------------------------------------
// necessary types and interfaces registered. This codec is provided to all the
// modules the application depends on.
//
Expand Down
Loading

0 comments on commit f7486b9

Please sign in to comment.