Skip to content

Commit

Permalink
feat(x/tx): add an option to encode maps using amino json (backport #…
Browse files Browse the repository at this point in the history
…23539) (#23540)

Co-authored-by: Julien Robert <[email protected]>
  • Loading branch information
mergify[bot] and julienrbrt authored Jan 28, 2025
1 parent 9d3c384 commit f1b139d
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 5 deletions.
6 changes: 4 additions & 2 deletions x/tx/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,11 @@ Since v0.13.0, x/tx follows Cosmos SDK semver: https://github.com/cosmos/cosmos-

## [Unreleased]

## [v0.13.7](https://github.com/cosmos/cosmos-sdk/releases/tag/x/tx/v0.13.7) - 2024-12-16
## [v0.13.8](https://github.com/cosmos/cosmos-sdk/releases/tag/x/tx/v0.13.8) - 2025-01-28

### Bug Fixes
* [#23513](https://github.com/cosmos/cosmos-sdk/pull/23513), [#23539](https://github.com/cosmos/cosmos-sdk/pull/23539) Add map marshalling support (as option) to Amino JSON encoder.

## [v0.13.7](https://github.com/cosmos/cosmos-sdk/releases/tag/x/tx/v0.13.7) - 2024-12-16

* Fix [ABS-0043](https://github.com/cosmos/cosmos-sdk/security/advisories/GHSA-8wcc-m6j2-qxvm) Limit recursion depth for unknown field detection

Expand Down
18 changes: 18 additions & 0 deletions x/tx/signing/aminojson/json_marshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ type EncoderOptions struct {
// It is useful when using the Amino JSON encoder for non Amino purposes,
// such as JSON RPC.
AminoNameAsTypeURL bool
// MarshalMappings when set will use the Amino JSON encoder to marshal maps.
MarshalMappings bool
// TypeResolver is used to resolve protobuf message types by TypeURL when marshaling any packed messages.
TypeResolver signing.TypeResolver
// FileResolver is used to resolve protobuf file descriptors TypeURL when TypeResolver fails.
Expand All @@ -57,6 +59,7 @@ type Encoder struct {
indent string
enumsAsString bool
aminoNameAsTypeURL bool
marshalMappings bool
}

// NewEncoder returns a new Encoder capable of serializing protobuf messages to JSON using the Amino JSON encoding
Expand Down Expand Up @@ -93,6 +96,7 @@ func NewEncoder(options EncoderOptions) Encoder {
indent: options.Indent,
enumsAsString: options.EnumAsString,
aminoNameAsTypeURL: options.AminoNameAsTypeURL,
marshalMappings: options.MarshalMappings,
}
return enc
}
Expand Down Expand Up @@ -237,6 +241,20 @@ func (enc Encoder) marshal(value protoreflect.Value, fd protoreflect.FieldDescri
return err

case protoreflect.Map:
if enc.marshalMappings {
if !val.IsValid() {
_, err := io.WriteString(writer, "null")
return err
}

mapData := make(map[string]interface{})
val.Range(func(k protoreflect.MapKey, v protoreflect.Value) bool {
mapData[k.String()] = v.Interface()
return true
})

return jsonMarshal(writer, mapData)
}
return errors.New("maps are not supported")

case protoreflect.List:
Expand Down
29 changes: 26 additions & 3 deletions x/tx/signing/aminojson/json_marshal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,6 @@ func TestIndent(t *testing.T) {

bz, err := encoder.Marshal(msg)
require.NoError(t, err)
fmt.Println(string(bz))
require.Equal(t, `{
"type": "ABitOfEverything",
"value": {
Expand Down Expand Up @@ -324,7 +323,6 @@ func TestEnumAsString(t *testing.T) {

bz, err := encoder.Marshal(msg)
require.NoError(t, err)
fmt.Println(string(bz))
require.Equal(t, `{
"type": "ABitOfEverything",
"value": {
Expand Down Expand Up @@ -383,7 +381,6 @@ func TestAminoNameAsTypeURL(t *testing.T) {

bz, err := encoder.Marshal(msg)
require.NoError(t, err)
fmt.Println(string(bz))
require.Equal(t, `{
"type": "/testpb.ABitOfEverything",
"value": {
Expand Down Expand Up @@ -414,3 +411,29 @@ func TestAminoNameAsTypeURL(t *testing.T) {
}
}`, string(bz))
}

func TestMarshalMappings(t *testing.T) {
// valid
encoder := aminojson.NewEncoder(aminojson.EncoderOptions{Indent: " ", MarshalMappings: true})

msg := &testpb.WithAMap{
StrMap: map[string]string{
"foo": "bar",
"baz": "qux",
},
}

bz, err := encoder.Marshal(msg)
require.NoError(t, err)
require.Equal(t, `{
"str_map": {
"baz": "qux",
"foo": "bar"
}
}`, string(bz))

// invalid
encoder = aminojson.NewEncoder(aminojson.EncoderOptions{Indent: " ", MarshalMappings: false})
_, err = encoder.Marshal(msg)
require.Error(t, err)
}

0 comments on commit f1b139d

Please sign in to comment.