Skip to content

Commit c9d7635

Browse files
authored
test(x/auth/tx): cover nil nested ModeInfo in adaptModeInfo
A nil nested ModeInfo must be adapted to an empty ModeInfo rather than left as a nil element: a nil element in a protov2 repeated message field panics in proto.Marshal. Document this on the loop and add a regression test driving adaptModeInfo directly.
1 parent ce7b429 commit c9d7635

2 files changed

Lines changed: 42 additions & 0 deletions

File tree

‎x/auth/tx/adapter.go‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,11 @@ func adaptModeInfo(legacy *tx.ModeInfo, res *txv1beta1.ModeInfo) {
135135
}
136136
multiModeInfos := mi.Multi.ModeInfos
137137
modeInfos := make([]*txv1beta1.ModeInfo, len(multiModeInfos))
138+
// Always allocate the destination entry, even when the legacy entry is
139+
// nil (an omitted sub-signature): a nil element in a protov2 repeated
140+
// message field makes proto.Marshal / proto.Equal panic on the adapted
141+
// AuthInfo, whereas an empty ModeInfo mirrors the top-level handling in
142+
// GetSigningTxData.
138143
for i, modeInfo := range multiModeInfos {
139144
modeInfos[i] = &txv1beta1.ModeInfo{}
140145
adaptModeInfo(modeInfo, modeInfos[i])

‎x/auth/tx/builder_test.go‎

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ import (
55
"time"
66

77
"github.com/stretchr/testify/require"
8+
"google.golang.org/protobuf/proto"
89

910
signingv1beta1 "cosmossdk.io/api/cosmos/tx/signing/v1beta1"
11+
txv1beta1 "cosmossdk.io/api/cosmos/tx/v1beta1"
1012
errorsmod "cosmossdk.io/errors"
1113
sdkmath "cosmossdk.io/math"
1214

@@ -489,3 +491,38 @@ func TestGetSigningTxData_MultisigModeInfos(t *testing.T) {
489491
require.Equal(t, signingv1beta1.SignMode_SIGN_MODE_DIRECT, multiModeInfo.ModeInfos[0].GetSingle().Mode)
490492
require.Equal(t, signingv1beta1.SignMode_SIGN_MODE_LEGACY_AMINO_JSON, multiModeInfo.ModeInfos[1].GetSingle().Mode)
491493
}
494+
495+
func TestAdaptModeInfo_MultisigNilChildModeInfo(t *testing.T) {
496+
// a nil nested ModeInfo is what SignatureDataToModeInfoAndSig yields for a
497+
// nil sub-signature; it cannot be reached through the builder because the
498+
// gogoproto AuthInfo does not marshal with a nil element either, so drive
499+
// adaptModeInfo directly
500+
legacy := &txtypes.ModeInfo{
501+
Sum: &txtypes.ModeInfo_Multi_{
502+
Multi: &txtypes.ModeInfo_Multi{
503+
Bitarray: cryptotypes.NewCompactBitArray(2),
504+
ModeInfos: []*txtypes.ModeInfo{
505+
{Sum: &txtypes.ModeInfo_Single_{Single: &txtypes.ModeInfo_Single{Mode: signing.SignMode_SIGN_MODE_DIRECT}}},
506+
nil,
507+
},
508+
},
509+
},
510+
}
511+
512+
res := &txv1beta1.ModeInfo{}
513+
adaptModeInfo(legacy, res)
514+
515+
multiModeInfo := res.GetMulti()
516+
require.NotNil(t, multiModeInfo)
517+
require.Len(t, multiModeInfo.ModeInfos, 2)
518+
require.Equal(t, signingv1beta1.SignMode_SIGN_MODE_DIRECT, multiModeInfo.ModeInfos[0].GetSingle().Mode)
519+
520+
// the nil child must become an empty ModeInfo, not a nil element: a nil
521+
// element in a protov2 repeated field panics in proto.Marshal
522+
require.NotNil(t, multiModeInfo.ModeInfos[1])
523+
require.Nil(t, multiModeInfo.ModeInfos[1].Sum)
524+
require.NotPanics(t, func() {
525+
_, err := proto.Marshal(res)
526+
require.NoError(t, err)
527+
})
528+
}

0 commit comments

Comments
 (0)