Skip to content

Commit

Permalink
refactor: Improve textual's API (cosmos#14595)
Browse files Browse the repository at this point in the history
  • Loading branch information
amaury1093 authored Jan 12, 2023
1 parent 5e7b744 commit 3050531
Show file tree
Hide file tree
Showing 35 changed files with 258 additions and 115 deletions.
117 changes: 117 additions & 0 deletions api/cosmos/msg/textual/v1/textual.pulsar.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 2 additions & 3 deletions docs/architecture/adr-050-sign-mode-textual.md
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,6 @@ message Grant {
message MsgGrant {
option (cosmos.msg.v1.signer) = "granter";
option (cosmos.msg.v1.textual.type_url) = "authz v1beta1 grant";
string granter = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
string grantee = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"];
Expand All @@ -249,13 +248,13 @@ End of transaction messages

Application developers may choose to not follow default renderer value output for their own `Msg`s. In this case, they can implement their own custom `Msg` renderer. This is similar to [EIP4430](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-4430.md), where the smart contract developer chooses the description string to be shown to the end user.

This is done by setting the `cosmos.msg.v1.textual.expert_custom_renderer` Protobuf option to a non-empty string. This option CAN ONLY be set on a Protobuf message representing transaction message object (implementing `sdk.Msg` interface).
This is done by setting the `cosmos.msg.textual.v1.expert_custom_renderer` Protobuf option to a non-empty string. This option CAN ONLY be set on a Protobuf message representing transaction message object (implementing `sdk.Msg` interface).

```protobuf
message MsgFooBar {
// Optional comments to describe in human-readable language the formatting
// rules of the custom renderer.
option (cosmos.msg.v1.textual.expert_custom_renderer) = "<unique algorithm identifier>";
option (cosmos.msg.textual.v1.expert_custom_renderer) = "<unique algorithm identifier>";
// proto fields
}
Expand Down
18 changes: 18 additions & 0 deletions proto/cosmos/msg/textual/v1/textual.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
syntax = "proto3";

package cosmos.msg.textual.v1;

import "google/protobuf/descriptor.proto";

extend google.protobuf.MessageOptions {
// expert_custom_renderer is an informative identifier to reference the
// algorithm used to generate the custom textual representation of the
// protobuf message where this annotation is applied. We recommend to use a
// short, versioned name as this identifier, e.g. "replace_with_username_v1".
// We also recommand providing a human-readable description as protobuf
// comments on this annotation, for example a short specification or a link
// to the relevant documentation.
//
// Also see the section on Custom Message Renderers in ADR-050.
string expert_custom_renderer = 11110009;
}
2 changes: 1 addition & 1 deletion tx/textual/valuerenderer/any.go → tx/textual/any.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package valuerenderer
package textual

import (
"context"
Expand Down
13 changes: 6 additions & 7 deletions tx/textual/valuerenderer/any_test.go → tx/textual/any_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package valuerenderer_test
package textual_test

import (
"context"
Expand All @@ -7,8 +7,7 @@ import (
"os"
"testing"

"cosmossdk.io/tx/textual/valuerenderer"

"cosmossdk.io/tx/textual"
"github.com/google/go-cmp/cmp"
"github.com/stretchr/testify/require"

Expand All @@ -20,26 +19,26 @@ import (

type anyJsonTest struct {
Proto json.RawMessage
Screens []valuerenderer.Screen
Screens []textual.Screen
}

func TestAny(t *testing.T) {
raw, err := os.ReadFile("../internal/testdata/any.json")
raw, err := os.ReadFile("./internal/testdata/any.json")
require.NoError(t, err)

var testcases []anyJsonTest
err = json.Unmarshal(raw, &testcases)
require.NoError(t, err)

tr := valuerenderer.NewTextual(EmptyCoinMetadataQuerier)
tr := textual.NewTextual(EmptyCoinMetadataQuerier)
for i, tc := range testcases {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
anyMsg := anypb.Any{}
err = protojson.Unmarshal(tc.Proto, &anyMsg)
require.NoError(t, err)

// Format into screens and check vs expected
rend := valuerenderer.NewAnyValueRenderer((&tr))
rend := textual.NewAnyValueRenderer((&tr))
screens, err := rend.Format(context.Background(), protoreflect.ValueOfMessage(anyMsg.ProtoReflect()))
require.NoError(t, err)
require.Equal(t, tc.Screens, screens)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package valuerenderer
package textual

import (
"bytes"
Expand Down
2 changes: 1 addition & 1 deletion tx/textual/valuerenderer/bytes.go → tx/textual/bytes.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package valuerenderer
package textual

import (
"bytes"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package valuerenderer_test
package textual_test

import (
"context"
"encoding/json"
"os"
"testing"

"cosmossdk.io/tx/textual/valuerenderer"
"cosmossdk.io/tx/textual"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/reflect/protoreflect"
)
Expand All @@ -15,12 +15,12 @@ func TestBytesJsonTestCases(t *testing.T) {
var testcases []bytesTest
// Bytes.json contains bytes that are represented in base64 format, and
// their expected results in hex.
raw, err := os.ReadFile("../internal/testdata/bytes.json")
raw, err := os.ReadFile("./internal/testdata/bytes.json")
require.NoError(t, err)
err = json.Unmarshal(raw, &testcases)
require.NoError(t, err)

textual := valuerenderer.NewTextual(nil)
textual := textual.NewTextual(nil)

for _, tc := range testcases {
valrend, err := textual.GetFieldValueRenderer(fieldDescriptorFromName("BYTES"))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package valuerenderer_test
package textual_test

import (
"context"
Expand All @@ -12,7 +12,7 @@ import (

bankv1beta1 "cosmossdk.io/api/cosmos/bank/v1beta1"
basev1beta1 "cosmossdk.io/api/cosmos/base/v1beta1"
"cosmossdk.io/tx/textual/valuerenderer"
"cosmossdk.io/tx/textual"
)

// mockCoinMetadataKey is used in the mock coin metadata querier.
Expand Down Expand Up @@ -47,33 +47,33 @@ func addMetadataToContext(ctx context.Context, metadata *bankv1beta1.Metadata) c

func TestMetadataQuerier(t *testing.T) {
// Errors on nil metadata querier
textual := valuerenderer.NewTextual(nil)
vr, err := textual.GetFieldValueRenderer(fieldDescriptorFromName("COIN"))
txt := textual.NewTextual(nil)
vr, err := txt.GetFieldValueRenderer(fieldDescriptorFromName("COIN"))
require.NoError(t, err)
_, err = vr.Format(context.Background(), protoreflect.ValueOf((&basev1beta1.Coin{}).ProtoReflect()))
require.Error(t, err)

// Errors if metadata querier returns an error
expErr := fmt.Errorf("mock error")
textual = valuerenderer.NewTextual(func(_ context.Context, _ string) (*bankv1beta1.Metadata, error) {
txt = textual.NewTextual(func(_ context.Context, _ string) (*bankv1beta1.Metadata, error) {
return nil, expErr
})
vr, err = textual.GetFieldValueRenderer(fieldDescriptorFromName("COIN"))
vr, err = txt.GetFieldValueRenderer(fieldDescriptorFromName("COIN"))
require.NoError(t, err)
_, err = vr.Format(context.Background(), protoreflect.ValueOf((&basev1beta1.Coin{}).ProtoReflect()))
require.ErrorIs(t, err, expErr)
_, err = vr.(valuerenderer.RepeatedValueRenderer).FormatRepeated(context.Background(), protoreflect.ValueOf(NewGenericList([]*basev1beta1.Coin{{}})))
_, err = vr.(textual.RepeatedValueRenderer).FormatRepeated(context.Background(), protoreflect.ValueOf(NewGenericList([]*basev1beta1.Coin{{}})))
require.ErrorIs(t, err, expErr)
}

func TestCoinJsonTestcases(t *testing.T) {
var testcases []coinJsonTest
raw, err := os.ReadFile("../internal/testdata/coin.json")
raw, err := os.ReadFile("./internal/testdata/coin.json")
require.NoError(t, err)
err = json.Unmarshal(raw, &testcases)
require.NoError(t, err)

textual := valuerenderer.NewTextual(mockCoinMetadataQuerier)
textual := textual.NewTextual(mockCoinMetadataQuerier)
vr, err := textual.GetFieldValueRenderer(fieldDescriptorFromName("COIN"))
require.NoError(t, err)

Expand Down
2 changes: 1 addition & 1 deletion tx/textual/valuerenderer/coins.go → tx/textual/coins.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package valuerenderer
package textual

import (
"context"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package valuerenderer_test
package textual_test

import (
"context"
Expand All @@ -9,21 +9,21 @@ import (
bankv1beta1 "cosmossdk.io/api/cosmos/bank/v1beta1"
basev1beta1 "cosmossdk.io/api/cosmos/base/v1beta1"
"cosmossdk.io/math"
"cosmossdk.io/tx/textual/valuerenderer"
"cosmossdk.io/tx/textual"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/reflect/protoreflect"
)

func TestCoinsJsonTestcases(t *testing.T) {
var testcases []coinsJsonTest
raw, err := os.ReadFile("../internal/testdata/coins.json")
raw, err := os.ReadFile("./internal/testdata/coins.json")
require.NoError(t, err)
err = json.Unmarshal(raw, &testcases)
require.NoError(t, err)

textual := valuerenderer.NewTextual(mockCoinMetadataQuerier)
vr, err := textual.GetFieldValueRenderer(fieldDescriptorFromName("COINS"))
vrr := vr.(valuerenderer.RepeatedValueRenderer)
txt := textual.NewTextual(mockCoinMetadataQuerier)
vr, err := txt.GetFieldValueRenderer(fieldDescriptorFromName("COINS"))
vrr := vr.(textual.RepeatedValueRenderer)
require.NoError(t, err)

for _, tc := range testcases {
Expand Down
2 changes: 1 addition & 1 deletion tx/textual/valuerenderer/dec.go → tx/textual/dec.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package valuerenderer
package textual

import (
"context"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
package valuerenderer_test
package textual_test

import (
"encoding/json"
"os"
"testing"

"cosmossdk.io/tx/textual/valuerenderer"
"cosmossdk.io/tx/textual"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/reflect/protoreflect"
)

func TestDecJsonTestcases(t *testing.T) {
type decimalTest []string
var testcases []decimalTest
raw, err := os.ReadFile("../internal/testdata/decimals.json")
raw, err := os.ReadFile("./internal/testdata/decimals.json")
require.NoError(t, err)
err = json.Unmarshal(raw, &testcases)
require.NoError(t, err)

textual := valuerenderer.NewTextual(nil)
textual := textual.NewTextual(nil)

for _, tc := range testcases {
tc := tc
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package valuerenderer
package textual

import (
"context"
Expand Down
Loading

0 comments on commit 3050531

Please sign in to comment.