Skip to content
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(x/tx): Rename custom Amino JSON encoder to "inline_json" #19919

Merged
merged 6 commits into from
Apr 10, 2024

Conversation

webmaster128
Copy link
Member

@webmaster128 webmaster128 commented Apr 2, 2024

This is a follow-up to #19786 as discussed.

The important clarifications here are:

  • The bytes must contain valid JSON. Otherwise this produces nonsense documents.
  • Rename away from "bytes_as_string" which to me implied a level of escaping and embedding as a string. Feel free to suggest something better than "inline_json" if this is not good though.
  • Increase test coverage for other valid JSON documents that are not objects
  • Improve code-level documentation

Open questions/tasks

  • Should we add a JSON validity check here to make it harder to misuse the annotation by other users?
  • Can we have a test case that shows how an annotated field is embeded?

Summary by CodeRabbit

  • New Features
    • Enhanced JSON encoding capabilities to support inlining bytes as valid JSON, aligning with CosmWasm behavior.
    • Introduced a new field encoder for handling specific data types more efficiently in JSON marshaling.
  • Refactor
    • Renamed and updated a critical function for improved clarity and functionality in JSON handling.
  • Tests
    • Updated and expanded test cases to cover a broader range of JSON types and scenarios.
  • Documentation
    • Added documentation for a new field in a message structure to support advanced encoding attributes.

@webmaster128 webmaster128 requested a review from a team as a code owner April 2, 2024 18:29
Copy link
Contributor

coderabbitai bot commented Apr 2, 2024

Note

Reviews Paused

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Walkthrough

The recent changes revolve around optimizing byte encoding into JSON documents in a specific codebase. A key update is the renaming of cosmosBytesAsString to cosmosInlineJSON, enabling direct embedding of valid JSON bytes into JSON documents akin to CosmWasm. Furthermore, a new field encoder was introduced to enhance JSON marshaling, particularly for "legacy_coins" and "inline_json" fields. Test cases were also expanded to encompass a wider range of JSON data types.

Changes

Files Change Summary
x/tx/signing/aminojson/encoder.go, x/tx/signing/aminojson/encoder_test.go Renamed cosmosBytesAsString to cosmosInlineJSON with updated logic for inlining JSON bytes; test cases revised for various JSON types.
x/tx/signing/aminojson/json_marshal.go Added "inline_json" field encoder and updated "legacy_coins" field encoder for enhanced JSON marshaling.
x/tx/signing/aminojson/internal/testpb/test.proto, x/tx/signing/aminojson/internal/testpb/test.pulsar.go Introduced a new json field of type bytes in ABitOfEverything message and struct with corresponding method updates.
x/tx/signing/aminojson/json_marshal_test.go Modified TestIndent to include additional JSON fields like Json with byte slice value and nested JSON object in the test message map.

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share
Tips

Chat

There are 3 ways to chat with CodeRabbit:

Note: Auto-reply has been disabled for this repository by the repository owner. The CodeRabbit bot will not respond to your replies unless it is explicitly tagged.

  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger a review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions github-actions bot added the C:x/tx label Apr 2, 2024
@webmaster128 webmaster128 changed the title Rename custom Amino JSON encoder to "inline_json" feat(x/tx): Rename custom Amino JSON encoder to "inline_json" Apr 2, 2024
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Review Status

Configuration used: .coderabbit.yml

Commits Files that changed from the base of the PR and between 319e6e4 and 03c27c84d213cabd5716855aa339495878737749.
Files selected for processing (4)
  • docs/build/building-modules/05-protobuf-annotations.md (1 hunks)
  • x/tx/signing/aminojson/encoder.go (1 hunks)
  • x/tx/signing/aminojson/encoder_test.go (2 hunks)
  • x/tx/signing/aminojson/json_marshal.go (1 hunks)
Additional Context Used
Path-based Instructions (4)
x/tx/signing/aminojson/encoder_test.go (2)

Pattern **/*.go: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.


Pattern **/*_test.go: "Assess the unit test code assessing sufficient code coverage for the changes associated in the pull request"

docs/build/building-modules/05-protobuf-annotations.md (1)

Pattern **/*.md: "Assess the documentation for misspellings, grammatical errors, missing documentation and correctness"

x/tx/signing/aminojson/encoder.go (1)

Pattern **/*.go: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.

x/tx/signing/aminojson/json_marshal.go (1)

Pattern **/*.go: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.

Additional comments not posted (3)
x/tx/signing/aminojson/encoder_test.go (1)

64-64: The comment regarding undefined behavior for invalid JSON inputs suggests a potential improvement area. Consider implementing JSON validity checks within cosmosInlineJSON to ensure only valid JSON is processed.

Implementing a JSON validity check could prevent the generation of nonsensical documents and improve the robustness of the encoder.

docs/build/building-modules/05-protobuf-annotations.md (1)

129-146: Ensure the documentation clearly states that the inline_json option should only be used when the bytes are guaranteed to contain valid JSON, to prevent the creation of malformed JSON documents.

Clarifying this requirement can help developers understand the importance of validating JSON before using the inline_json option.

x/tx/signing/aminojson/json_marshal.go (1)

75-76: The introduction of the "inline_json" field encoder aligns with the PR's objectives to handle JSON bytes more accurately. Ensure that all uses of this encoder are accompanied by appropriate JSON validity checks upstream.

Consider verifying through the codebase that JSON validity checks are in place wherever the "inline_json" encoder is used to prevent the creation of malformed JSON documents.

x/tx/signing/aminojson/encoder_test.go Outdated Show resolved Hide resolved
x/tx/signing/aminojson/encoder.go Outdated Show resolved Hide resolved
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Review Status

Configuration used: .coderabbit.yml

Commits Files that changed from the base of the PR and between 03c27c84d213cabd5716855aa339495878737749 and ad2f12298e86657a153609e411d9405c324b499d.
Files selected for processing (1)
  • x/tx/CHANGELOG.md (1 hunks)
Additional Context Used
Path-based Instructions (1)
x/tx/CHANGELOG.md (1)

Pattern **/*.md: "Assess the documentation for misspellings, grammatical errors, missing documentation and correctness"

Additional comments not posted (1)
x/tx/CHANGELOG.md (1)

36-36: Consider adding a brief explanation of the "inline_json" option.

While the entry for the "inline_json" option in the Amino JSON encoder is clear, it could benefit from a brief explanation or context. This would help users understand the significance of the change and how it might affect their use of the SDK.

@webmaster128
Copy link
Member Author

webmaster128 commented Apr 2, 2024

Unfortunately this test is now failing:

func TestRapid(t *testing.T) {
	gen := rapidproto.MessageGenerator(&testpb.ABitOfEverything{}, rapidproto.GeneratorOptions{})
	rapid.Check(t, func(t *rapid.T) {
		msg := gen.Draw(t, "msg")
		bz, err := aminojson.NewEncoder(aminojson.EncoderOptions{DoNotSortFields: true}).Marshal(msg)
		assert.NilError(t, err)
		checkInvariants(t, msg, bz)
	})
}

It seems like at some point a []bytes{0} (byte array of length 1) is used as test data. Since this is not valid JSON, the encoder here can't produce reasonable results. Any idea how to best fix this test? Is TestRapid expected to support such types is fields?

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Review Status

Configuration used: .coderabbit.yml

Commits Files that changed from the base of the PR and between ad2f12298e86657a153609e411d9405c324b499d and 05882a97bb3987321ea4476a05b97b387b01c6fe.
Files selected for processing (3)
  • x/tx/signing/aminojson/internal/testpb/test.proto (1 hunks)
  • x/tx/signing/aminojson/internal/testpb/test.pulsar.go (16 hunks)
  • x/tx/signing/aminojson/json_marshal_test.go (2 hunks)
Additional Context Used
Path-based Instructions (2)
x/tx/signing/aminojson/json_marshal_test.go (2)

Pattern **/*.go: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.


Pattern **/*_test.go: "Assess the unit test code assessing sufficient code coverage for the changes associated in the pull request"

x/tx/signing/aminojson/internal/testpb/test.pulsar.go (1)

Pattern **/*.go: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.

Additional comments not posted (2)
x/tx/signing/aminojson/internal/testpb/test.proto (1)

44-44: The addition of the json field with custom encoding attribute (amino.encoding) = "inline_json" is well-aligned with the PR's objectives and follows protobuf conventions.

x/tx/signing/aminojson/json_marshal_test.go (1)

249-259: > 📝 NOTE

This review was outside the diff hunks and was mapped to the diff hunk with the greatest overlap. Original lines [236-256]

The addition of the Json field in the TestIndent function, along with the corresponding test assertion, is correctly implemented and effectively tests the inline_json encoder's functionality.

x/tx/signing/aminojson/internal/testpb/test.pulsar.go Outdated Show resolved Hide resolved
@webmaster128
Copy link
Member Author

Is there an AI tool to mute the rabbit?

@julienrbrt
Copy link
Member

@coderabbitai pause

@kocubinski
Copy link
Member

Confused, the PR description states:

The bytes must contain valid JSON. Otherwise this produces nonsense documents.

However the encoding function includes this comment:

		// Caution, this does not include a validity check as json.RawMessage can be anything 🤷‍♂️

It is clear to me that bytes need not be valid JSON blob, err := json.RawMessage(bz).MarshalJSON() does no validation.

@webmaster128
Copy link
Member Author

Semantically inline_json is only well defined for valid JSON. Everything else is garbage and not a use case this encoder should support. The reason is that any non-valid JSON in the field leads to invalid JSON in the resulting sign doc.

The question is just at which point the JSON validation is happening. In wasmd, this is done in ValidateBasic() of the relevant messages. But I am also happy to add a JSON validity check here to make it harder to misuse this encoder.

@kocubinski
Copy link
Member

Unfortunately this test is now failing:

func TestRapid(t *testing.T) {
	gen := rapidproto.MessageGenerator(&testpb.ABitOfEverything{}, rapidproto.GeneratorOptions{})
	rapid.Check(t, func(t *rapid.T) {
		msg := gen.Draw(t, "msg")
		bz, err := aminojson.NewEncoder(aminojson.EncoderOptions{DoNotSortFields: true}).Marshal(msg)
		assert.NilError(t, err)
		checkInvariants(t, msg, bz)
	})
}

It seems like at some point a []bytes{0} (byte array of length 1) is used as test data. Since this is not valid JSON, the encoder here can't produce reasonable results. Any idea how to best fix this test? Is TestRapid expected to support such types is fields?

This test failure doesn't seem to be due to invalid JSON, rather this code block asserts legacy amino json bytes from the codec in "github.com/tendermint/go-amino" are equivalent to this implementation in x/tx. Since the annotation you're introducing in this PR is not supported in the legacy encoder the test is failing.

I would adjust the tests to keep it out of that code path.

@kocubinski
Copy link
Member

Semantically inline_json is only well defined for valid JSON. Everything else is garbage and not a use case this encoder should support. The reason is that any non-valid JSON in the field leads to invalid JSON in the resulting sign doc.

The question is just at which point the JSON validation is happening. In wasmd, this is done in ValidateBasic() of the relevant messages. But I am also happy to add a JSON validity check here to make it harder to misuse this encoder.

If that annotation is named inline_json it seems reasonable to me to check JSON validity in the encoder. If you don't want to do this for performance reasons, I might suggest raw_bytes and printing them verbatim. This is exactly what's happening now anyway, see below for the entirety of "raw json marshaling" from the go std lib (barely marshaling at all!)

// RawMessage is a raw encoded JSON value.
// It implements [Marshaler] and [Unmarshaler] and can
// be used to delay JSON decoding or precompute a JSON encoding.
type RawMessage []byte

// MarshalJSON returns m as the JSON encoding of m.
func (m RawMessage) MarshalJSON() ([]byte, error) {
	if m == nil {
		return []byte("null"), nil
	}
	return m, nil
}

@webmaster128
Copy link
Member Author

The latest commit adds a JSON validity check. I agree, it's good to have it here. Opening up the encoder for arbitrary bytes would just lead to invalid signdocs and issues further down the road.

I would adjust the tests to keep it out of that code path.

Could you elaborate what you mean here? Should I avoid the bytes json = 20 [(amino.encoding) = "inline_json"]; from the ABitOfEverything structure?

I think it would be nice to have a test that shows the encoder in action. But yeah, comparing it with the old encoder is not needed.

@webmaster128 webmaster128 force-pushed the rename-to-inline_json branch from 2119604 to 00bf1f0 Compare April 8, 2024 07:37
@webmaster128
Copy link
Member Author

webmaster128 commented Apr 8, 2024

Good morning!

I re-write to embedding test to use a separate proto message for it. The x/tx tests are now all passing. Unfortunately there seem to be a bunch of unrelated CI fails.

From my point of view, this is ready for review.

x/tx/signing/aminojson/internal/testpb/test.pulsar.go Dismissed Show dismissed Hide dismissed
x/tx/signing/aminojson/internal/testpb/test.pulsar.go Dismissed Show dismissed Hide dismissed
wantErr: false,
wantOutput: `"hey yo"`,
},
"supported type - invalid JSON": {
Copy link
Member

@kocubinski kocubinski Apr 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since you're expected an error here, should the case include the name "supported type"?
suggest renaming to just "invalid JSON" (ditto for the negative err tests below also).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding is this: The term "type" here refers to the data type. "ValueOfBytes" is a supported type, but bool and int64 are not. This highlights two levels of errors: one is a wrong type and the other one is wrong contents of the right type.

However, we can also rephrase those to failure reasons only. No strong opinion what is better.

Copy link
Contributor

@testinginprod testinginprod left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@julienrbrt julienrbrt added this pull request to the merge queue Apr 10, 2024
Merged via the queue into cosmos:main with commit 4be248e Apr 10, 2024
57 of 59 checks passed
@webmaster128 webmaster128 deleted the rename-to-inline_json branch April 10, 2024 21:17
@julienrbrt julienrbrt mentioned this pull request Apr 10, 2024
2 tasks
alpe added a commit to alpe/cosmos-sdk that referenced this pull request Apr 15, 2024
* main: (25 commits)
  fix: Implement gogoproto customtype to secp256r1 keys (cosmos#20027)
  fix(x/epochs): avoid invalid epoch duration in simulation (cosmos#20030)
  fix(x/bank): align query with multi denoms for send-enabled (cosmos#20028)
  refactor(x/slashing)!: remove Accounts String (cosmos#20026)
  refactor(x/evidence)!: remove Address.String() (cosmos#20016)
  chore: make telemetry consistent (cosmos#20025)
  chore: prepare x/tx changelog (cosmos#20015)
  build(deps): Bump actions/add-to-project from 1.0.0 to 1.0.1 (cosmos#20018)
  feat(x/bank): support depinject for send restrictions (cosmos#20014)
  feat: Conditionally emit metrics based on enablement (cosmos#19903)
  fix(store): fix the typo (cosmos#20011)
  docs(x/feegrant): fix allowance typo (cosmos#20000)
  chore(confix): update latest config value (cosmos#20012)
  refactor(x/auth): auth module can recognize x/accounts account (cosmos#20002)
  fix(mempool): use no-op mempool as default (cosmos#19970)
  fix(simapp): add epoch store to upgrade (cosmos#20007)
  test(kv): add unit tests for the helpers functions kv.AssertKeyAtLeas… (cosmos#19965)
  feat(x/tx): Rename custom Amino JSON encoder to "inline_json" (cosmos#19919)
  refactor(x/auth): use transaction service (cosmos#19967)
  fix(client/v2): add encoder for `cosmos.base.v1beta1.DecCoin` (cosmos#19976)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants