Skip to content

Commit 4917211

Browse files
rootulpclaude
andcommitted
test: reproduce Amino JSON signing bug for MsgSetRoutingIsmDomain
Add a unit test that reproduces the bug where Amino JSON signing fails for MsgSetRoutingIsmDomain with "unknown protobuf field" because the nested Route message's field descriptors are not resolvable via gogoproto.HybridResolver. Also add a TxConfig() accessor to simapp.App for future integration-level amino signing tests. Closes #156 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent f17cb96 commit 4917211

2 files changed

Lines changed: 95 additions & 0 deletions

File tree

tests/simapp/app.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,3 +251,7 @@ func (app *App) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APIConfig
251251
func (app *App) AppCodec() codec.Codec {
252252
return app.appCodec
253253
}
254+
255+
func (app *App) TxConfig() client.TxConfig {
256+
return app.txConfig
257+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package types_test
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
"github.com/stretchr/testify/require"
8+
9+
txv1beta1 "cosmossdk.io/api/cosmos/tx/v1beta1"
10+
"cosmossdk.io/x/tx/signing"
11+
"cosmossdk.io/x/tx/signing/aminojson"
12+
13+
"github.com/bcp-innovations/hyperlane-cosmos/util"
14+
"github.com/bcp-innovations/hyperlane-cosmos/x/core/01_interchain_security/types"
15+
16+
gogoproto "github.com/cosmos/gogoproto/proto"
17+
"google.golang.org/protobuf/proto"
18+
"google.golang.org/protobuf/types/known/anypb"
19+
)
20+
21+
// TestAminoJSONSigningMsgSetRoutingIsmDomain reproduces the bug where Amino
22+
// JSON signing fails for MsgSetRoutingIsmDomain because the nested Route
23+
// message's field descriptors are not resolvable via gogoproto.HybridResolver.
24+
//
25+
// See: https://github.com/celestiaorg/celestia-app/issues/6541
26+
func TestAminoJSONSigningMsgSetRoutingIsmDomain(t *testing.T) {
27+
// 1. Construct a MsgSetRoutingIsmDomain with a populated Route
28+
ismAddr := util.CreateMockHexAddress("routing-ism", 1)
29+
routeIsm := util.CreateMockHexAddress("route-ism", 1)
30+
31+
msg := &types.MsgSetRoutingIsmDomain{
32+
IsmId: ismAddr,
33+
Route: types.Route{
34+
Ism: routeIsm,
35+
Domain: 42,
36+
},
37+
Owner: "cosmos1testowner",
38+
}
39+
40+
// 2. Marshal with gogo proto
41+
msgBytes, err := gogoproto.Marshal(msg)
42+
require.NoError(t, err)
43+
44+
// 3. Wrap as an anypb.Any
45+
anyMsg := &anypb.Any{
46+
TypeUrl: "/" + gogoproto.MessageName(msg),
47+
Value: msgBytes,
48+
}
49+
50+
// 4. Build a TxBody and marshal to bodyBytes
51+
body := &txv1beta1.TxBody{
52+
Messages: []*anypb.Any{anyMsg},
53+
}
54+
bodyBytes, err := proto.Marshal(body)
55+
require.NoError(t, err)
56+
57+
// 5. Build a minimal AuthInfo with a Fee and marshal to authInfoBytes
58+
authInfo := &txv1beta1.AuthInfo{
59+
Fee: &txv1beta1.Fee{
60+
GasLimit: 200000,
61+
},
62+
}
63+
authInfoBytes, err := proto.Marshal(authInfo)
64+
require.NoError(t, err)
65+
66+
// 6. Create an amino JSON sign mode handler with default options
67+
// (uses gogoproto.HybridResolver, same as the real app)
68+
handler := aminojson.NewSignModeHandler(aminojson.SignModeHandlerOptions{})
69+
70+
signerData := signing.SignerData{
71+
Address: "cosmos1testowner",
72+
ChainID: "test-chain",
73+
AccountNumber: 1,
74+
Sequence: 0,
75+
}
76+
77+
txData := signing.TxData{
78+
Body: body,
79+
AuthInfo: authInfo,
80+
BodyBytes: bodyBytes,
81+
AuthInfoBytes: authInfoBytes,
82+
}
83+
84+
// 7. Call GetSignBytes — this is where the bug manifests.
85+
// The handler internally calls RejectUnknownFields which descends into the
86+
// nested Route message and fails because its field descriptors are not
87+
// properly registered in the google.golang.org/protobuf registry.
88+
signBytes, err := handler.GetSignBytes(context.Background(), signerData, txData)
89+
require.NoError(t, err, "GetSignBytes should succeed for MsgSetRoutingIsmDomain")
90+
require.NotEmpty(t, signBytes)
91+
}

0 commit comments

Comments
 (0)