github.com/cosmos/cosmos-sdk@v0.50.10/x/auth/tx/aux_test.go (about) 1 package tx_test 2 3 import ( 4 "context" 5 "testing" 6 7 "github.com/stretchr/testify/require" 8 9 clienttx "github.com/cosmos/cosmos-sdk/client/tx" 10 codectypes "github.com/cosmos/cosmos-sdk/codec/types" 11 "github.com/cosmos/cosmos-sdk/testutil/testdata" 12 _ "github.com/cosmos/cosmos-sdk/testutil/testdata/testpb" 13 sdk "github.com/cosmos/cosmos-sdk/types" 14 moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" 15 "github.com/cosmos/cosmos-sdk/types/tx/signing" 16 authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" 17 ) 18 19 var ( 20 // The final TX has 3 signers, in this order. 21 tipperPriv, tipperPk, tipperAddr = testdata.KeyTestPubAddr() 22 aux2Priv, aux2Pk, aux2Addr = testdata.KeyTestPubAddr() 23 feepayerPriv, feepayerPk, feepayerAddr = testdata.KeyTestPubAddr() 24 25 msg = testdata.NewTestMsg(tipperAddr, aux2Addr) 26 memo = "test-memo" 27 28 chainID = "test-chain" 29 gas = testdata.NewTestGasLimit() 30 fee = testdata.NewTestFeeAmount() 31 extOpt = &testdata.Cat{} 32 ) 33 34 // TestBuilderWithAux creates a tx with 2 aux signers: 35 // - 1st one is tipper, 36 // - 2nd one is just an aux signer. 37 // Then it tests integrating the 2 AuxSignerData into a 38 // client.TxBuilder created by the fee payer. 39 func TestBuilderWithAux(t *testing.T) { 40 encodingConfig := moduletestutil.MakeTestEncodingConfig() 41 interfaceRegistry := encodingConfig.InterfaceRegistry 42 txConfig := encodingConfig.TxConfig 43 44 testdata.RegisterInterfaces(interfaceRegistry) 45 46 // Create an AuxTxBuilder for tipper (1st signer) 47 txBuilder, txSig := makeTxBuilder(t) 48 txSignerData, err := txBuilder.GetAuxSignerData() 49 require.NoError(t, err) 50 51 // Create an AuxTxBuilder for aux2 (2nd signer) 52 aux2Builder := clienttx.NewAuxTxBuilder() 53 aux2Builder.SetAddress(aux2Addr.String()) 54 aux2Builder.SetAccountNumber(11) 55 aux2Builder.SetSequence(12) 56 aux2Builder.SetTimeoutHeight(3) 57 aux2Builder.SetMemo(memo) 58 aux2Builder.SetChainID(chainID) 59 err = aux2Builder.SetMsgs(msg) 60 require.NoError(t, err) 61 err = aux2Builder.SetPubKey(aux2Pk) 62 require.NoError(t, err) 63 extOptAny, err := codectypes.NewAnyWithValue(extOpt) 64 require.NoError(t, err) 65 aux2Builder.SetExtensionOptions(extOptAny) 66 aux2Builder.SetNonCriticalExtensionOptions(extOptAny) 67 err = aux2Builder.SetSignMode(signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON) 68 require.NoError(t, err) 69 signBz, err := aux2Builder.GetSignBytes() 70 require.NoError(t, err) 71 aux2Sig, err := aux2Priv.Sign(signBz) 72 require.NoError(t, err) 73 aux2Builder.SetSignature(aux2Sig) 74 aux2SignerData, err := aux2Builder.GetAuxSignerData() 75 require.NoError(t, err) 76 77 // Fee payer (3rd and last signer) creates a TxBuilder. 78 w := txConfig.NewTxBuilder() 79 // Note: we're testing calling AddAuxSignerData in the wrong order, i.e. 80 // adding the aux2 signer data first before the tipper. 81 err = w.AddAuxSignerData(aux2SignerData) 82 require.NoError(t, err) 83 84 // Test that when adding another AuxSignerData, the 2nd data should match 85 // the 1st one. 86 testcases := []struct { 87 name string 88 malleate func() 89 expErr bool 90 }{ 91 {"address and msg signer mistacher", func() { txBuilder.SetAddress("foobar") }, true}, 92 {"memo mismatch", func() { txBuilder.SetMemo("mismatch") }, true}, 93 {"timeout height mismatch", func() { txBuilder.SetTimeoutHeight(98) }, true}, 94 {"extension options length mismatch", func() { txBuilder.SetExtensionOptions() }, true}, 95 {"extension options member mismatch", func() { txBuilder.SetExtensionOptions(&codectypes.Any{}) }, true}, 96 {"non-critical extension options length mismatch", func() { txBuilder.SetNonCriticalExtensionOptions() }, true}, 97 {"non-critical extension options member mismatch", func() { txBuilder.SetNonCriticalExtensionOptions(&codectypes.Any{}) }, true}, 98 {"happy case", func() {}, false}, 99 } 100 for _, tc := range testcases { 101 tc := tc 102 t.Run(tc.name, func(t *testing.T) { 103 txBuilder, txSig = makeTxBuilder(t) 104 105 tc.malleate() 106 107 _, err := txBuilder.GetSignBytes() 108 require.NoError(t, err) 109 txSignerData, err = txBuilder.GetAuxSignerData() 110 require.NoError(t, err) 111 112 err = w.AddAuxSignerData(txSignerData) 113 if tc.expErr { 114 require.Error(t, err) 115 } else { 116 require.NoError(t, err) 117 } 118 }) 119 } 120 121 w.SetFeePayer(feepayerAddr) 122 w.SetFeeAmount(fee) 123 w.SetGasLimit(gas) 124 sigs, err := w.(authsigning.SigVerifiableTx).GetSignaturesV2() 125 require.NoError(t, err) 126 txSigV2 := sigs[0] 127 aux2SigV2 := sigs[1] 128 // Set all signer infos. 129 w.SetSignatures(txSigV2, aux2SigV2, signing.SignatureV2{ 130 PubKey: feepayerPk, 131 Sequence: 15, 132 }) 133 signerData := authsigning.SignerData{ 134 Address: feepayerAddr.String(), 135 ChainID: chainID, 136 AccountNumber: 11, 137 Sequence: 15, 138 PubKey: feepayerPk, 139 } 140 141 signBz, err = authsigning.GetSignBytesAdapter( 142 context.Background(), txConfig.SignModeHandler(), signing.SignMode_SIGN_MODE_DIRECT, 143 signerData, w.GetTx()) 144 145 require.NoError(t, err) 146 feepayerSig, err := feepayerPriv.Sign(signBz) 147 require.NoError(t, err) 148 // Set all signatures. 149 w.SetSignatures(txSigV2, aux2SigV2, signing.SignatureV2{ 150 PubKey: feepayerPk, 151 Data: &signing.SingleSignatureData{ 152 SignMode: signing.SignMode_SIGN_MODE_DIRECT, 153 Signature: feepayerSig, 154 }, 155 Sequence: 22, 156 }) 157 158 // Make sure tx is correct. 159 txBz, err := txConfig.TxEncoder()(w.GetTx()) 160 require.NoError(t, err) 161 tx, err := txConfig.TxDecoder()(txBz) 162 require.NoError(t, err) 163 require.Equal(t, tx.(sdk.FeeTx).FeePayer(), []byte(feepayerAddr)) 164 require.Equal(t, tx.(sdk.FeeTx).GetFee(), fee) 165 require.Equal(t, tx.(sdk.FeeTx).GetGas(), gas) 166 require.Equal(t, msg, tx.GetMsgs()[0]) 167 require.Equal(t, memo, tx.(sdk.TxWithMemo).GetMemo()) 168 require.Equal(t, uint64(3), tx.(sdk.TxWithTimeoutHeight).GetTimeoutHeight()) 169 sigs, err = tx.(authsigning.Tx).GetSignaturesV2() 170 require.NoError(t, err) 171 require.Len(t, sigs, 3) 172 require.Equal(t, signing.SignatureV2{ 173 PubKey: tipperPk, 174 Data: &signing.SingleSignatureData{SignMode: signing.SignMode_SIGN_MODE_DIRECT_AUX, Signature: txSig}, 175 Sequence: 2, 176 }, sigs[0]) 177 require.Equal(t, signing.SignatureV2{ 178 PubKey: aux2Pk, 179 Data: &signing.SingleSignatureData{SignMode: signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON, Signature: aux2Sig}, 180 Sequence: 12, 181 }, sigs[1]) 182 require.Equal(t, signing.SignatureV2{ 183 PubKey: feepayerPk, 184 Data: &signing.SingleSignatureData{SignMode: signing.SignMode_SIGN_MODE_DIRECT, Signature: feepayerSig}, 185 Sequence: 22, 186 }, sigs[2]) 187 } 188 189 func makeTxBuilder(t *testing.T) (clienttx.AuxTxBuilder, []byte) { 190 t.Helper() 191 txBuilder := clienttx.NewAuxTxBuilder() 192 txBuilder.SetAddress(tipperAddr.String()) 193 txBuilder.SetAccountNumber(1) 194 txBuilder.SetSequence(2) 195 txBuilder.SetTimeoutHeight(3) 196 txBuilder.SetMemo(memo) 197 txBuilder.SetChainID(chainID) 198 err := txBuilder.SetMsgs(msg) 199 require.NoError(t, err) 200 err = txBuilder.SetPubKey(tipperPk) 201 require.NoError(t, err) 202 extOptAny, err := codectypes.NewAnyWithValue(extOpt) 203 require.NoError(t, err) 204 txBuilder.SetExtensionOptions(extOptAny) 205 txBuilder.SetNonCriticalExtensionOptions(extOptAny) 206 err = txBuilder.SetSignMode(signing.SignMode_SIGN_MODE_DIRECT_AUX) 207 require.NoError(t, err) 208 signBz, err := txBuilder.GetSignBytes() 209 require.NoError(t, err) 210 tipperSig, err := tipperPriv.Sign(signBz) 211 require.NoError(t, err) 212 txBuilder.SetSignature(tipperSig) 213 214 return txBuilder, tipperSig 215 }