-
Notifications
You must be signed in to change notification settings - Fork 3.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: api updates required for aminojson encoder #15019
Conversation
@@ -76,4 +76,10 @@ extend google.protobuf.FieldOptions { | |||
// out := AminoJSONEncoder(&f); | |||
// out == {"baz":""} | |||
bool dont_omitempty = 11110005; | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These options were added to achieve marshal parity for messages with a oneof
field, e.g. StakeAuthorization:
cosmos-sdk/proto/cosmos/staking/v1beta1/authz.proto
Lines 22 to 29 in 5946320
oneof validators { | |
option (amino.oneof_field_name) = "Validators"; | |
// allow_list specifies list of validator addresses to whom grantee can delegate tokens on behalf of granter's | |
// account. | |
Validators allow_list = 2 [(amino.oneof_type_name) = "cosmos-sdk/StakeAuthorization/AllowList"]; | |
// deny_list specifies list of validator addresses to whom grantee can not delegate tokens. | |
Validators deny_list = 3 [(amino.oneof_type_name) = "cosmos-sdk/StakeAuthorization/DenyList"]; | |
} |
Since the legacy encoder uses golang reflection it produces JSON shaped like below.
{"type":"cosmos-sdk/StakeAuthorization","value":{"Validators":{"type":"cosmos-sdk/StakeAuthorization/AllowList","value":{"allow_list":{"address":["foo"]}}}}}
The protoreflect default field traversal differs:
{"type":"cosmos-sdk/StakeAuthorization","value":{"allow_list":{"address":["foo"]}}}
The options are introspected and used in the encoder to bring the JSON output into equivalence.
cosmos-sdk/x/tx/aminojson/json_marshal.go
Lines 160 to 162 in 732bcaf
oneof := f.ContainingOneof() | |
isOneOf := oneof != nil | |
oneofFieldName, oneofTypeName, err := getOneOfNames(f) |
uint64 account_number = 3; | ||
uint64 sequence = 4; | ||
} | ||
|
||
// ModuleAccount defines an account for modules that holds coins on a pool. | ||
message ModuleAccount { | ||
option (amino.name) = "cosmos-sdk/ModuleAccount"; | ||
option (amino.message_encoding) = "module_account"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The legacy encoder features a custom encoding for ModuleAccount
cosmos-sdk/x/auth/types/account.go
Lines 240 to 254 in 41a3dfe
func (ma ModuleAccount) MarshalJSON() ([]byte, error) { | |
accAddr, err := sdk.AccAddressFromBech32(ma.Address) | |
if err != nil { | |
return nil, err | |
} | |
return json.Marshal(moduleAccountPretty{ | |
Address: accAddr, | |
PubKey: "", | |
AccountNumber: ma.AccountNumber, | |
Sequence: ma.Sequence, | |
Name: ma.Name, | |
Permissions: ma.Permissions, | |
}) | |
} |
The protoreflect encoder provides this by registering message encoding overrides by key. This encoding corresponds to this registration:
cosmos-sdk/x/tx/aminojson/json_marshal.go
Line 41 in 732bcaf
"module_account": moduleAccountEncoder, |
and this implementation:
cosmos-sdk/x/tx/aminojson/encoder.go
Lines 101 to 124 in 583181c
func moduleAccountEncoder(msg protoreflect.Message, w io.Writer) error { | |
ma := msg.Interface().(*authapi.ModuleAccount) | |
pretty := moduleAccountPretty{ | |
PubKey: "", | |
Name: ma.Name, | |
Permissions: ma.Permissions, | |
} | |
if ma.BaseAccount != nil { | |
pretty.Address = ma.BaseAccount.Address | |
pretty.AccountNumber = ma.BaseAccount.AccountNumber | |
pretty.Sequence = ma.BaseAccount.Sequence | |
} else { | |
pretty.Address = "" | |
pretty.AccountNumber = 0 | |
pretty.Sequence = 0 | |
} | |
bz, err := json.Marshal(pretty) | |
if err != nil { | |
return err | |
} | |
_, err = w.Write(bz) | |
return err | |
} |
@@ -41,18 +41,21 @@ message Params { | |||
bytes min_signed_per_window = 2 [ | |||
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", | |||
(gogoproto.nullable) = false, | |||
(amino.encoding) = "cosmos_dec_bytes", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
encoder implementation:
cosmos-sdk/x/tx/aminojson/encoder.go
Lines 14 to 29 in 583181c
func cosmosDecBytesEncoder(_ AminoJSON, v protoreflect.Value, w io.Writer) error { | |
switch bz := v.Interface().(type) { | |
case []byte: | |
if len(bz) == 0 { | |
return jsonMarshal(w, "0") | |
} | |
var dec math.LegacyDec | |
err := dec.Unmarshal(bz) | |
if err != nil { | |
return err | |
} | |
return jsonMarshal(w, dec.String()) | |
default: | |
return fmt.Errorf("unsupported type %T", bz) | |
} | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally looks good. Worried about the null_as_empty stuff. This looks really easy to forget.
It's a fair point, we could also special case on all usages of |
Lets keep it as is. Sorry it wasn't a suggestion to change anything. Don't want to over engineer it since hopefully amino will die soon. |
If this will make upgrading easier I'm not sure its over engineering. Otherwise developers will need to remember to tag any usage of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since coins do have a special encoding, I prefer to add an annotation to all coins (instead of hard coding a convention). However, I see there's already a amino.dont_omit_empty, so I'm wondering if we need null_slice_as_empty.
note 3 broken tests. could revert. ref: #15019 (comment)
…osmos-sdk into kocubinski/aminojson/just-proto
…minojson/just-proto
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Description
These are all the protobuf changes required to ship #10993. This patch is a subset of the feature complete PR #14877, and an attempt to make it more reviewable.
Changes
oneof
types.amino.message_encoding
for whole messages andamino.encoding
for fields.amino.dont_omityempty
usages where needed.amino.name
usages to correlate with legacy amino type registration.More nuanced descriptions are provided as comments closer to the source location in this PR.
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...
!
to the type prefix if API or client breaking changeCHANGELOG.md
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...
!
in the type prefix if API or client breaking change