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

Amino JSON representation of inner message in Msg{Instantiate,Migrate,Execute}Contract #642

Closed
webmaster128 opened this issue Oct 13, 2021 · 6 comments · Fixed by #658
Closed
Assignees

Comments

@webmaster128
Copy link
Member

With the change in #520 we most likely changed the JSON representation of the msg field in MsgInstantiateContract, MsgMigrateContract and MsgExecuteContract by accident. It is now a base64 encoded string of the JSON. The problem with this is that Ledger users cannot read the content of the smart contract interaction anymore. The same applies for other generic Amino JSON signers that do not have a dedicated UI for those message types.

While most of the #520 makes sense, this diff in the autogenerated x/wasm/types/tx.pb.go is problematic:
Bildschirmfoto 2021-10-13 um 14 40 56

As you can see in https://play.golang.org/p/ois4zkjeRbr, the type defines the JSON serialization.

Seems like we should have a custom seralizer for those types that

  1. Keeps the []byte type for the inner messages because we have no clue what is in there
  2. Converts to JSON (can fail) and then embeds the message as an object as part of the signdoc generation
@webmaster128 webmaster128 added this to the v1.0.0 milestone Oct 13, 2021
@ethanfrey
Copy link
Member

Seems like we should have a custom seralizer for those types that

  1. Keeps the []byte type for the inner messages because we have no clue what is in there
  2. Converts to JSON (can fail) and then embeds the message as an object as part of the signdoc generation

I agree with this. Just a custom JSON encoder, right?

I think allowing non-valid json and encoding as base64 is a nice touch. So if someone did want to use eg. protobuf messages, nothing in wasmd stops them. But we optimize UX when they are JSON

@webmaster128
Copy link
Member Author

Just a custom JSON encoder, right?

Yes, we only need this for signature verification, i.e. protobuf encoding -> Go struct -> JSON -> sign bytes conversion.

I think allowing non-valid json and encoding as base64 is a nice touch. So if someone did want to use eg. protobuf messages, nothing in wasmd stops them. But we optimize UX when they are JSON

I don't think we should allow this without adapting a whole lot of tooling. The readability of the signdoc is an important feature of Cosmos and we'd provide a way around it. It would require us to write extra code (if JSON validation fails fall back to base64). Not much, but still. This brings the risk that someone is tricks Go into considering something invalid JSON just to hide the content from the users.

@ethanfrey
Copy link
Member

Fair enough

@ethanfrey
Copy link
Member

@alpe I think this is the most important/breaking item between 0.20 and 1.0-beta

@alpe
Copy link
Contributor

alpe commented Oct 21, 2021

I have looked into the issue and the changes in #520 were causing the issues. Nice find @webmaster128
Unfortunately I don't remember what was driving the changes in that PR. 🙄

One option is to revert to the json RawMessage type as the validate methods ensure that we only accept valid json in the inner payloads but I assume I had a good reason for the refactoring ;-)
The custom marshaler would either require a custom type that represents the byte array or a lot of work in the UnmarshalJSON function of the message/proposal types to do it at that level.

I also looked a bit deeper at queries and contract responses and we have a mix of raw bytes and json.RawMessage now. A custom type with marshaler seems to be the cleanest and most extendable solution. I have implemented it in #658 to show the changes.

@webmaster128
Copy link
Member Author

Unfortunately I don't remember what was driving the changes in that PR.

The problem is that the type annotations are casts. At the protobuf level no JSON type exists and all bytes are perfectly valid. Now with the casttype annotation in the generated Go struct, unvalidated bytes are casted to json.RawMessage. But the type guarantees to be a raw encoded JSON value. It must never ever hold non-JSON bytes.

If we had a validating bytes -> json.RawMessage converter, this would be fine. But a cast is unsafe.

One option is to revert to the json RawMessage type as the validate methods ensure that we only accept valid json in the inner payloads but I assume I had a good reason for the refactoring ;-)

This still gives you instances of json.RawMessage with invalid data. Even if we validate them at some point, I consider this error prone and unintuitive.

The custom marshaler would either require a custom type that represents the byte array

Right, this is what we need. Raw bytes intended to hold JSON data but not guaranteed to be valid JSON.

@alpe alpe closed this as completed in #658 Oct 25, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants