-
Notifications
You must be signed in to change notification settings - Fork 3.8k
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
Change how we handle Sorted JSON encoding #2350
Comments
What is the input here? A byte string or an interface? |
The sort JSON method takes a JSON encoded byte string. Amino takes in a concrete struct and returns a JSON encoded byte string. The order currently getting called is effectively:
example: https://github.com/cosmos/cosmos-sdk/blob/develop/x/gov/msgs.go#L132 |
@alexanderbez is this still applicable with the client encoding changes that will be done in the coming weeks |
I imagine this will still be useful for clients that still which to use amino. But we should fix the SDK's |
reopen if still applicable |
This is still relevant. Most messages sign bytes are implemented of the form
The implementation now does
See Lines 29 to 35 in ab24d0e
I propose we add a |
@ValarDragon thanks for filing this issue! So if I follow closely, this issue is asking for go-amino's JSON encoder to be eliminated entirely, correct? If so, that means that we are going to entirely use encoding/json which means, we are going to violate the unsupported types per https://github.com/tendermint/go-amino#unsupported-types that will now be supported:
this can potentially cause security issues given that JSON is not bound to any schema and would be unexpected for Cosmos ecosystem code. Also Amino has an advantage of understanding interfaces. Suggested remedies
CURRENT DIRECTION/EXPERIMENT /cc @elias-orijtech |
Implements a function "AllClear" which checks that an object is amino-json compatible and iff all clear, can permit us to directly: * use encoding/json.Marshal which produces sorted JSON instead of 3 expensive steps to produce sorted JSON: * amino.MarshalJSON * encoding/json.Unmarshal * encoding/json.Marshal and the results are stark ```shell $ benchstat before.txt after.txt name old time/op new time/op delta MsgDeposit-8 10.8µs ± 1% 1.3µs ± 1% -87.55% (p=0.000 n=10+8) name old alloc/op new alloc/op delta MsgDeposit-8 3.75kB ± 0% 0.26kB ± 0% -92.96% (p=0.000 n=10+10) name old allocs/op new allocs/op delta MsgDeposit-8 99.0 ± 0% 13.0 ± 0% -86.87% (p=0.000 n=10+10) ``` Updates #2350
Great results from my 1.5 hour long experiment in which I wrote a package aminocompat with a function $ benchstat before.txt after.txt
name old time/op new time/op delta
MsgDeposit-8 10.8µs ± 1% 1.3µs ± 1% -87.55% (p=0.000 n=10+8)
name old alloc/op new alloc/op delta
MsgDeposit-8 3.75kB ± 0% 0.26kB ± 0% -92.96% (p=0.000 n=10+10)
name old allocs/op new allocs/op delta
MsgDeposit-8 99.0 ± 0% 13.0 ± 0% -86.87% (p=0.000 n=10+10) |
Signing using go-amino and GetSignBytes is deprecated and I believe the code paths calling these have mostly been removed on main. The new implementation is in x/tx and we can optimize sorting there addressing this issue. @kocubinski can you comment. |
Correct, main no longer uses go-amino for amino JSON marshaling in production code paths. The current implementation uses a round trip to sort JSON same as the legacy encoder.
That said we should just render JSON fields in order. The sort should happen after we fetch all field names from the protoreflect.Message, somewhere the vicinity of the line linked below.
|
@odeke-em would you be interested in working on the improvement to |
Gladly @aaronc! I'll jump onto it in the morning as it is almost midnight here. |
This change gives (aminojson.Encoder).Marshal the ability to sort field names before marshalling, mimicking the outward behavior of encoding/json.Marshal and thus eliminating a long prior roundtrip that required sdk.*SortJSON which would take the produced JSON and encoding/json.Unmarshal it to an interface firstly, then encoding/json.Marshal it out to get the field names sorted. While here, this change adds an opt-out field to aminojson.EncoderOptions called "DoNotSortFields", in case one wants to preserve legacy behavior for compatibility checks/reasons. The performance benchmarks from before and after reveal improvements ```shell $ benchstat before.txt after.txt name old time/op new time/op delta AminoJSON-8 76.4µs ± 1% 61.7µs ± 2% -19.28% (p=0.000 n=9+10) name old alloc/op new alloc/op delta AminoJSON-8 15.0kB ± 0% 9.4kB ± 0% -37.28% (p=0.000 n=10+10) name old allocs/op new allocs/op delta AminoJSON-8 332 ± 0% 234 ± 0% -29.52% (p=0.000 n=10+10) ``` Fixes #2350
This change gives (aminojson.Encoder).Marshal the ability to sort field names before marshalling, mimicking the outward behavior of encoding/json.Marshal and thus eliminating a long prior roundtrip that required sdk.*SortJSON which would take the produced JSON and encoding/json.Unmarshal it to an interface firstly, then encoding/json.Marshal it out to get the field names sorted. While here, this change adds an opt-out field to aminojson.EncoderOptions called "DoNotSortFields", in case one wants to preserve legacy behavior for compatibility checks/reasons. The performance benchmarks from before and after reveal improvements ```shell $ benchstat before.txt after.txt name old time/op new time/op delta AminoJSON-8 76.4µs ± 1% 61.7µs ± 2% -19.28% (p=0.000 n=9+10) name old alloc/op new alloc/op delta AminoJSON-8 15.0kB ± 0% 9.4kB ± 0% -37.28% (p=0.000 n=10+10) name old allocs/op new allocs/op delta AminoJSON-8 332 ± 0% 234 ± 0% -29.52% (p=0.000 n=10+10) ``` Fixes #2350
This change gives (aminojson.Encoder).Marshal the ability to sort field names before marshalling, mimicking the outward behavior of encoding/json.Marshal and thus eliminating a long prior roundtrip that required sdk.*SortJSON which would take the produced JSON and encoding/json.Unmarshal it to an interface firstly, then encoding/json.Marshal it out to get the field names sorted. While here, this change adds an opt-out field to aminojson.EncoderOptions called "DoNotSortFields", in case one wants to preserve legacy behavior for compatibility checks/reasons. The performance benchmarks from before and after reveal improvements ```shell $ benchstat before.txt after.txt name old time/op new time/op delta AminoJSON-8 76.4µs ± 1% 61.7µs ± 2% -19.28% (p=0.000 n=9+10) name old alloc/op new alloc/op delta AminoJSON-8 15.0kB ± 0% 9.4kB ± 0% -37.28% (p=0.000 n=10+10) name old allocs/op new allocs/op delta AminoJSON-8 332 ± 0% 234 ± 0% -29.52% (p=0.000 n=10+10) ``` Fixes #2350
This change gives (aminojson.Encoder).Marshal the ability to sort field names before marshalling, mimicking the outward behavior of encoding/json.Marshal and thus eliminating a long prior roundtrip that required sdk.*SortJSON which would take the produced JSON and encoding/json.Unmarshal it to an interface firstly, then encoding/json.Marshal it out to get the field names sorted. While here, this change adds an opt-out field to aminojson.EncoderOptions called "DoNotSortFields", in case one wants to preserve legacy behavior for compatibility checks/reasons. The performance benchmarks from before and after reveal improvements ```shell $ benchstat before.txt after.txt name old time/op new time/op delta AminoJSON-8 76.4µs ± 1% 61.7µs ± 2% -19.28% (p=0.000 n=9+10) name old alloc/op new alloc/op delta AminoJSON-8 15.0kB ± 0% 9.4kB ± 0% -37.28% (p=0.000 n=10+10) name old allocs/op new allocs/op delta AminoJSON-8 332 ± 0% 234 ± 0% -29.52% (p=0.000 n=10+10) ``` Fixes #2350
Currently what we do is inefficient. We marshal a JSON string, and then run
MustSortJSON
on it.MustSortJSON
JSON decodes the input, and then re-JSON encodes, but using the stdlib instead of amino.Either we should make amino provide a method to JSON sort its input, or we should make a method to just sort the lines of a JSON encoded blob. In a 30 block simulation I ran, it was responsible for about 10% of the time. (A little bit skewed though, since the simulation didn't really hit anything that actually makes the chain slow down. This simulation did however have 525 signature verifications)
For Admin Use
The text was updated successfully, but these errors were encountered: