Skip to content

Commit

Permalink
docs(adr): ADR-050 SIGN_MODE_TEXTUAL (#10701)
Browse files Browse the repository at this point in the history
## [Rendered ADR](https://github.com/cosmos/cosmos-sdk/blob/am/adr-textual/docs/architecture/adr-050-sign-mode-textual.md)

## Description



Closes: #6513

Support documents:
- context: #6513
- specification living doc HackmD: https://hackmd.io/7RkGfv_rQAaZzEigUYhcXw



---

### Author Checklist

*All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues.*

I have...

- [ ] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [ ] added `!` to the type prefix if API or client breaking change
- [ ] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#pr-targeting))
- [ ] provided a link to the relevant issue or specification
- [ ] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules)
- [ ] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#testing)
- [ ] added a changelog entry to `CHANGELOG.md`
- [ ] included comments for [documenting Go code](https://blog.golang.org/godoc)
- [ ] updated the relevant documentation or specification
- [ ] reviewed "Files changed" and left comments if necessary
- [ ] confirmed all CI checks have passed

### Reviewers Checklist

*All items are required. Please add a note if the item is not applicable and please add
your handle next to the items reviewed if you only reviewed selected items.*

I have...

- [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [ ] confirmed `!` in the type prefix if API or client breaking change
- [ ] confirmed all author checklist items have been addressed 
- [ ] reviewed state machine logic
- [ ] reviewed API design and naming
- [ ] reviewed documentation is accurate
- [ ] reviewed tests and test coverage
- [ ] manually tested (if applicable)
  • Loading branch information
amaury1093 authored May 27, 2022
1 parent e2ec380 commit 0cee47d
Show file tree
Hide file tree
Showing 2 changed files with 789 additions and 0 deletions.
284 changes: 284 additions & 0 deletions docs/architecture/adr-050-sign-mode-textual-annex1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,284 @@
# ADR 050: SIGN_MODE_TEXTUAL: Annex 1 Value Renderers

## Changelog

- Dec 06, 2021: Initial Draft
- Feb 07, 2022: Draft read and concept-ACKed by the Ledger team.

## Status

Accepted. Implementation started. Small value renderers details still need to be polished.

## Abstract

This Annex describes value renderers, which are used for displaying Protobuf values in a human-friendly way using a string array.

## Value Renderers

Value Renderers describe how values of different Protobuf types should be encoded as a string array. Value renderers can be formalized as a set of bijective functions `func renderT(value T) []string`, where `T` is one of the below Protobuf types for which this spec is defined.

### Protobuf `number`

- Applies to:
- protobuf numeric integer types (`int{32,64}`, `uint{32,64}`, `sint{32,64}`, `fixed{32,64}`, `sfixed{32,64}`)
- strings whose `customtype` is `github.com/cosmos/cosmos-sdk/types.Int` or `github.com/cosmos/cosmos-sdk/types.Dec`
- bytes whose `customtype` is `github.com/cosmos/cosmos-sdk/types.Int` or `github.com/cosmos/cosmos-sdk/types.Dec`
- Trailing decimal zeroes are always removed
- Formatting with `'`s for every three integral digits.
- Usage of `.` to denote the decimal delimiter.

#### Examples

- `1000` (uint64) -> `1'000`
- `"1000000.00"` (string representing a Dec) -> `1'000'000`
- `"1000000.10"` (string representing a Dec) -> `1'000'000.1`

### `coin`

- Applies to `cosmos.base.v1beta1.Coin`.
- Denoms are converted to `display` denoms using `Metadata` (if available). **This requires a state query**. The definition of `Metadata` can be found in the [bank Protobuf definition](https://github.com/cosmos/cosmos-sdk/blob/v0.46.0-rc1/proto/cosmos/bank/v1beta1/bank.proto#L79-L108). If the `display` field is empty or nil, then we do not perform any denom conversion.
- Amounts are converted to `display` denom amounts and rendered as `number`s above
- We do not change the capitalization of the denom. In practice, `display` denoms are stored in lowercase in state (e.g. `10 atom`), however they are often showed in UPPERCASE in everyday life (e.g. `10 ATOM`). Value renderers keep the case used in state, but we may recommend chains changing the denom metadata to be uppercase for better user display.
- One space between the denom and amount (e.g. `10 atom`).
- In the future, IBC denoms could maybe be converted to DID/IIDs, if we can find a robust way for doing this (ex. `cosmos:cosmos:hub:bank:denom:atom`)

#### Examples

- `1000000000uatom` -> `["1'000 atom"]`, because atom is the metadata's display denom.

### `coins`

- an array of `coin` is display as the concatenation of each `coin` encoded as the specification above, the joined together with the delimiter `", "` (a comma and a space, no quotes around).
- the list of coins is ordered by unicode code point of the display denom: `A-Z` < `a-z`. For example, the string `aAbBcC` would be sorted `ABCabc`.

### Example

- `["3cosm", "2000000uatom"]` -> `2 atom, 3 COSM` (assuming the display denoms are `atom` and `COSM`)
- `["10atom", "20Acoin"]` -> `20 Acoin, 10 atom` (assuming the display denoms are `atom` and `Acoin`)

### `repeated`

- Applies to all `repeated` fields, except `cosmos.tx.v1beta1.TxBody#Messages`, which has a particular encoding (see [ADR-050](./adr-050-sign-mode-textual.md)).
- A repeated type has the following template:

```
<message_name> has <int> <field_name>
<field_name> (<int>/<int>): <value rendered 1st line>
<optional value rendered in the next lines>
<field_name> (<int>/<int>): <value rendered 1st line>
<optional value rendered in the next lines>
End of <field_name>.
```

where:

- `message_name` is the name of the Protobuf message which holds the `repeated` field,
- `int` is the length of the array,
- `field_name` is the Protobuf field name of the repeated field,
- add an optional `s` at the end if `<int> > 1` and the `field_name` doesn't already end with `s`.

#### Examples

Given the proto definition:

```proto
message AllowedMsgAllowance {
repeated string allowed_messages = 1;
}
```

and initializing with:

```go
x := []AllowedMsgAllowance{"cosmos.bank.v1beta1.MsgSend", "cosmos.gov.v1.MsgVote"}
```

we have the following value-rendered encoding:

```
Allowed messages: 2 strings
Allowed messages (1/2): cosmos.bank.v1beta1.MsgSend
Allowed messages (2/2): cosmos.gov.v1.MsgVote
End of Allowed messages
```

### `message`

- Applies to Protobuf messages whose name does not start with `Msg`
- For `sdk.Msg`s, please see [ADR-050](./adr-050-sign-mode-textual.md)
- alternatively, we can decide to add a protobuf option to denote messages that are `sdk.Msg`s.
- Field names follow [sentence case](https://en.wiktionary.org/wiki/sentence_case)
- replace `_` with a spaces
- capitalize first letter of the setence
- Field names are ordered by their Protobuf field number
- Nesting:
- if a field contains a nested message, we value-render the underlying message using the template:
```
<field_name>: <1st line of value-rendered message>
> <lines 2-n of value-rendered message> // Notice the `>` prefix.
```
- `>` character is used to denote nesting. For each additional level of nesting, add `>`.

#### Examples

Given the following Protobuf messages:

```proto
enum VoteOption {
VOTE_OPTION_UNSPECIFIED = 0;
VOTE_OPTION_YES = 1;
VOTE_OPTION_ABSTAIN = 2;
VOTE_OPTION_NO = 3;
VOTE_OPTION_NO_WITH_VETO = 4;
}
message WeightedVoteOption {
VoteOption option = 1;
string weight = 2 [(cosmos_proto.scalar) = "cosmos.Dec"];
}
message Vote {
uint64 proposal_id = 1;
string voter = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"];
reserved 3;
repeated WeightedVoteOption options = 4;
}
```

we get the following encoding for the `Vote` message:

```
Vote object
> Proposal id: 4
> Vote: cosmos1abc...def
> Options: 2 WeightedVoteOptions
> Options (1/2): WeightedVoteOption object
>> Option: Yes
>> Weight: 0.7
> Options (2/2): WeightedVoteOption object
>> Option: No
>> Weight: 0.3
> End of Options
```

### Enums

- String case convention: snake case to sentence case
- Allow optional annotation for textual name (TBD)
- Algorithm:
- convert enum name (`VoteOption`) to snake_case (`VOTE_OPTION`)
- truncate that prefix + `_` from the enum name if it exists (`VOTE_OPTION_` gets stripped from `VOTE_OPTION_YES` -> `YES`)
- convert rest to sentence case: `YES` -> `Yes`
- in summary: `VOTE_OPTION_YES` -> `Yes`

#### Examples

See example above with `message Vote{}`.

### `google.protobuf.Any`

- Applies to `google.protobuf.Any`
- Rendered as:

```
Object: <type_url>
> <value rendered underlying message>
```

#### Examples

```
Object: /cosmos.gov.v1.Vote
> Proposal id: 4
> Vote: cosmos1abc...def
> Options: 2 WeightedVoteOptions
> Options (1/2): WeightedVoteOption object
>> Option: Yes
>> Weight: 0.7
> Options (2/2): WeightedVoteOption object
>> Option: No
>> Weight: 0.3
> End of Options
```

### `google.protobuf.Timestamp`

Rendered as either ISO8601 (`2021-01-01T12:00:00Z`).

### `google.protobuf.Duration` (TODO)

- rendered in terms of weeks, days, hours, minutes and seconds as these time units can be measured independently of any calendar and duration values are in seconds (so months and years can't be used precisely)
- total seconds values included at the end so users have both pieces of information
- Ex:
- `1483530 seconds` -> `2 weeks, 3 days, 4 hours, 5 minutes, 30 seconds (1483530 seconds total)`

### bytes

- Bytes are rendered in base64.

### address bytes

We currently use `string` types in protobuf for addresses so this may not be needed, but if any address bytes are used in sign mode textual they should be rendered with bech32 formatting

### strings

Strings are rendered as-is.

### Default Values

- Default Protobuf values for each field are skipped.

#### Example

```proto
message TestData {
string signer = 1;
string metadata = 2;
}
```

```go
myTestData := TestData{
Signer: "cosmos1abc"
}
```

We get the following encoding for the `TestData` message:

```
TestData object
> Signer: cosmos1abc
```

### [ABANDONED] Custom `msg_title` instead of Msg `type_url`

_This paragraph is in the Annex for informational purposes only, and will be removed in a next update of the ADR._

<details>
<summary>Click to see abandoned idea.</summary>

- all protobuf messages to be used with `SIGN_MODE_TEXTUAL` CAN have a short title associated with them that can be used in format strings whenever the type URL is explicitly referenced via the `cosmos.msg.v1.textual.msg_title` Protobuf message option.
- if this option is not specified for a Msg, then the Protobuf fully qualified name will be used.

```proto
message MsgSend {
option (cosmos.msg.v1.textual.msg_title) = "bank send coins";
}
```

- they MUST be unique per message, per chain

#### Examples

- `cosmos.gov.v1.MsgVote` -> `governance v1 vote`

#### Best Pratices

We recommend to use this option only for `Msg`s whose Protobuf fully qualified name can be hard to understand. As such, the two examples above (`MsgSend` and `MsgVote`) are not good examples to be used with `msg_title`. We still allow `msg_title` for chains who might have `Msg`s with complex or non-obvious names.

In those cases, we recommend to drop the version (e.g. `v1`) in the string if there's only one version of the module on chain. This way, the bijective mapping can figure out which message each string corresponds to. If multiple Protobuf versions of the same module exist on the same chain, we recommend keeping the first `msg_title` with version, and the second `msg_title` with version (e.g. `v2`):

- `mychain.mymodule.v1.MsgDo` -> `mymodule do something`
- `mychain.mymodule.v2.MsgDo` -> `mymodule v2 do something`

</details>
Loading

0 comments on commit 0cee47d

Please sign in to comment.