github.com/cosmos/cosmos-sdk@v0.50.10/x/auth/tx/builder_test.go (about) 1 package tx 2 3 import ( 4 "testing" 5 6 "github.com/stretchr/testify/require" 7 8 errorsmod "cosmossdk.io/errors" 9 sdkmath "cosmossdk.io/math" 10 11 "github.com/cosmos/cosmos-sdk/codec" 12 "github.com/cosmos/cosmos-sdk/codec/legacy" 13 "github.com/cosmos/cosmos-sdk/codec/testutil" 14 codectypes "github.com/cosmos/cosmos-sdk/codec/types" 15 "github.com/cosmos/cosmos-sdk/testutil/testdata" 16 sdk "github.com/cosmos/cosmos-sdk/types" 17 sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" 18 txtypes "github.com/cosmos/cosmos-sdk/types/tx" 19 "github.com/cosmos/cosmos-sdk/types/tx/signing" 20 ) 21 22 func TestTxBuilder(t *testing.T) { 23 _, pubkey, addr := testdata.KeyTestPubAddr() 24 25 marshaler := codec.NewProtoCodec(codectypes.NewInterfaceRegistry()) 26 txBuilder := newBuilder(marshaler) 27 28 memo := "testmemo" 29 msgs := []sdk.Msg{testdata.NewTestMsg(addr)} 30 accSeq := uint64(2) // Arbitrary account sequence 31 any, err := codectypes.NewAnyWithValue(pubkey) 32 require.NoError(t, err) 33 34 var signerInfo []*txtypes.SignerInfo 35 signerInfo = append(signerInfo, &txtypes.SignerInfo{ 36 PublicKey: any, 37 ModeInfo: &txtypes.ModeInfo{ 38 Sum: &txtypes.ModeInfo_Single_{ 39 Single: &txtypes.ModeInfo_Single{ 40 Mode: signing.SignMode_SIGN_MODE_DIRECT, 41 }, 42 }, 43 }, 44 Sequence: accSeq, 45 }) 46 47 sig := signing.SignatureV2{ 48 PubKey: pubkey, 49 Data: &signing.SingleSignatureData{ 50 SignMode: signing.SignMode_SIGN_MODE_DIRECT, 51 Signature: legacy.Cdc.MustMarshal(pubkey), 52 }, 53 Sequence: accSeq, 54 } 55 56 fee := txtypes.Fee{Amount: sdk.NewCoins(sdk.NewInt64Coin("atom", 150)), GasLimit: 20000} 57 58 t.Log("verify that authInfo bytes encoded with DefaultTxEncoder and decoded with DefaultTxDecoder can be retrieved from getAuthInfoBytes") 59 authInfo := &txtypes.AuthInfo{ 60 Fee: &fee, 61 SignerInfos: signerInfo, 62 } 63 64 authInfoBytes := marshaler.MustMarshal(authInfo) 65 66 require.NotEmpty(t, authInfoBytes) 67 68 t.Log("verify that body bytes encoded with DefaultTxEncoder and decoded with DefaultTxDecoder can be retrieved from getBodyBytes") 69 anys := make([]*codectypes.Any, len(msgs)) 70 71 for i, msg := range msgs { 72 var err error 73 anys[i], err = codectypes.NewAnyWithValue(msg) 74 if err != nil { 75 panic(err) 76 } 77 } 78 79 txBody := &txtypes.TxBody{ 80 Memo: memo, 81 Messages: anys, 82 } 83 bodyBytes := marshaler.MustMarshal(txBody) 84 require.NotEmpty(t, bodyBytes) 85 require.Empty(t, txBuilder.getBodyBytes()) 86 87 t.Log("verify that calling the SetMsgs, SetMemo results in the correct getBodyBytes") 88 require.NotEqual(t, bodyBytes, txBuilder.getBodyBytes()) 89 err = txBuilder.SetMsgs(msgs...) 90 require.NoError(t, err) 91 require.NotEqual(t, bodyBytes, txBuilder.getBodyBytes()) 92 txBuilder.SetMemo(memo) 93 require.Equal(t, bodyBytes, txBuilder.getBodyBytes()) 94 require.Equal(t, len(msgs), len(txBuilder.GetMsgs())) 95 pks, err := txBuilder.GetPubKeys() 96 require.NoError(t, err) 97 require.Empty(t, pks) 98 99 t.Log("verify that updated AuthInfo results in the correct getAuthInfoBytes and GetPubKeys") 100 require.NotEqual(t, authInfoBytes, txBuilder.getAuthInfoBytes()) 101 txBuilder.SetFeeAmount(fee.Amount) 102 require.NotEqual(t, authInfoBytes, txBuilder.getAuthInfoBytes()) 103 txBuilder.SetGasLimit(fee.GasLimit) 104 require.NotEqual(t, authInfoBytes, txBuilder.getAuthInfoBytes()) 105 err = txBuilder.SetSignatures(sig) 106 require.NoError(t, err) 107 108 // once fee, gas and signerInfos are all set, AuthInfo bytes should match 109 require.Equal(t, authInfoBytes, txBuilder.getAuthInfoBytes()) 110 111 require.Equal(t, len(msgs), len(txBuilder.GetMsgs())) 112 pks, err = txBuilder.GetPubKeys() 113 require.NoError(t, err) 114 require.Equal(t, 1, len(pks)) 115 require.True(t, pubkey.Equals(pks[0])) 116 117 any, err = codectypes.NewAnyWithValue(testdata.NewTestMsg()) 118 require.NoError(t, err) 119 txBuilder.SetExtensionOptions(any) 120 require.Equal(t, []*codectypes.Any{any}, txBuilder.GetExtensionOptions()) 121 txBuilder.SetNonCriticalExtensionOptions(any) 122 require.Equal(t, []*codectypes.Any{any}, txBuilder.GetNonCriticalExtensionOptions()) 123 124 txBuilder = &wrapper{} 125 require.NotPanics(t, func() { 126 _ = txBuilder.GetMsgs() 127 }) 128 } 129 130 func TestSetSignaturesNoPublicKey(t *testing.T) { 131 _, pubkey, _ := testdata.KeyTestPubAddr() 132 txBuilder := newBuilder(nil) 133 sig2 := signing.SignatureV2{ 134 Data: &signing.SingleSignatureData{ 135 SignMode: signing.SignMode_SIGN_MODE_DIRECT, 136 Signature: legacy.Cdc.MustMarshal(pubkey), 137 }, 138 Sequence: 1, 139 } 140 err := txBuilder.SetSignatures(sig2) 141 require.NoError(t, err) 142 } 143 144 func TestBuilderValidateBasic(t *testing.T) { 145 // keys and addresses 146 _, pubKey1, addr1 := testdata.KeyTestPubAddr() 147 _, pubKey2, addr2 := testdata.KeyTestPubAddr() 148 149 // msg and signatures 150 msg1 := testdata.NewTestMsg(addr1, addr2) 151 feeAmount := testdata.NewTestFeeAmount() 152 msgs := []sdk.Msg{msg1} 153 154 // require to fail validation upon invalid fee 155 badFeeAmount := testdata.NewTestFeeAmount() 156 badFeeAmount[0].Amount = sdkmath.NewInt(-5) 157 txBuilder := newBuilder(testutil.CodecOptions{}.NewCodec()) 158 159 var sig1, sig2 signing.SignatureV2 160 sig1 = signing.SignatureV2{ 161 PubKey: pubKey1, 162 Data: &signing.SingleSignatureData{ 163 SignMode: signing.SignMode_SIGN_MODE_DIRECT, 164 Signature: legacy.Cdc.MustMarshal(pubKey1), 165 }, 166 Sequence: 0, // Arbitrary account sequence 167 } 168 169 sig2 = signing.SignatureV2{ 170 PubKey: pubKey2, 171 Data: &signing.SingleSignatureData{ 172 SignMode: signing.SignMode_SIGN_MODE_DIRECT, 173 Signature: legacy.Cdc.MustMarshal(pubKey2), 174 }, 175 Sequence: 0, // Arbitrary account sequence 176 } 177 178 err := txBuilder.SetMsgs(msgs...) 179 require.NoError(t, err) 180 txBuilder.SetGasLimit(200000) 181 err = txBuilder.SetSignatures(sig1, sig2) 182 require.NoError(t, err) 183 txBuilder.SetFeeAmount(badFeeAmount) 184 err = txBuilder.ValidateBasic() 185 require.Error(t, err) 186 _, code, _ := errorsmod.ABCIInfo(err, false) 187 require.Equal(t, sdkerrors.ErrInsufficientFee.ABCICode(), code) 188 189 // require to fail validation when no signatures exist 190 err = txBuilder.SetSignatures() 191 require.NoError(t, err) 192 txBuilder.SetFeeAmount(feeAmount) 193 err = txBuilder.ValidateBasic() 194 require.Error(t, err) 195 _, code, _ = errorsmod.ABCIInfo(err, false) 196 require.Equal(t, sdkerrors.ErrNoSignatures.ABCICode(), code) 197 198 // require to fail with nil values for tx, authinfo 199 err = txBuilder.SetMsgs(msgs...) 200 require.NoError(t, err) 201 err = txBuilder.ValidateBasic() 202 require.Error(t, err) 203 204 // require to fail validation when signatures do not match expected signers 205 err = txBuilder.SetSignatures(sig1) 206 require.NoError(t, err) 207 208 err = txBuilder.ValidateBasic() 209 require.Error(t, err) 210 _, code, _ = errorsmod.ABCIInfo(err, false) 211 require.Equal(t, sdkerrors.ErrUnauthorized.ABCICode(), code) 212 213 require.Error(t, err) 214 txBuilder.SetFeeAmount(feeAmount) 215 err = txBuilder.SetSignatures(sig1, sig2) 216 require.NoError(t, err) 217 err = txBuilder.ValidateBasic() 218 require.NoError(t, err) 219 220 // gas limit too high 221 txBuilder.SetGasLimit(txtypes.MaxGasWanted + 1) 222 err = txBuilder.ValidateBasic() 223 require.Error(t, err) 224 txBuilder.SetGasLimit(txtypes.MaxGasWanted - 1) 225 err = txBuilder.ValidateBasic() 226 require.NoError(t, err) 227 228 // bad builder structs 229 230 // missing body 231 body := txBuilder.tx.Body 232 txBuilder.tx.Body = nil 233 err = txBuilder.ValidateBasic() 234 require.Error(t, err) 235 txBuilder.tx.Body = body 236 err = txBuilder.ValidateBasic() 237 require.NoError(t, err) 238 239 // missing fee 240 f := txBuilder.tx.AuthInfo.Fee 241 txBuilder.tx.AuthInfo.Fee = nil 242 err = txBuilder.ValidateBasic() 243 require.Error(t, err) 244 txBuilder.tx.AuthInfo.Fee = f 245 err = txBuilder.ValidateBasic() 246 require.NoError(t, err) 247 248 // missing AuthInfo 249 authInfo := txBuilder.tx.AuthInfo 250 txBuilder.tx.AuthInfo = nil 251 err = txBuilder.ValidateBasic() 252 require.Error(t, err) 253 txBuilder.tx.AuthInfo = authInfo 254 err = txBuilder.ValidateBasic() 255 require.NoError(t, err) 256 257 // missing tx 258 txBuilder.tx = nil 259 err = txBuilder.ValidateBasic() 260 require.Error(t, err) 261 } 262 263 func TestBuilderFeePayer(t *testing.T) { 264 // keys and addresses 265 _, _, addr1 := testdata.KeyTestPubAddr() 266 _, _, addr2 := testdata.KeyTestPubAddr() 267 _, _, addr3 := testdata.KeyTestPubAddr() 268 269 // msg and signatures 270 msg1 := testdata.NewTestMsg(addr1, addr2) 271 feeAmount := testdata.NewTestFeeAmount() 272 msgs := []sdk.Msg{msg1} 273 274 cases := map[string]struct { 275 txFeePayer sdk.AccAddress 276 expectedSigners [][]byte 277 expectedPayer []byte 278 }{ 279 "no fee payer specified": { 280 expectedSigners: [][]byte{addr1, addr2}, 281 expectedPayer: addr1, 282 }, 283 "secondary signer set as fee payer": { 284 txFeePayer: addr2, 285 expectedSigners: [][]byte{addr1, addr2}, 286 expectedPayer: addr2, 287 }, 288 "outside signer set as fee payer": { 289 txFeePayer: addr3, 290 expectedSigners: [][]byte{addr1, addr2, addr3}, 291 expectedPayer: addr3, 292 }, 293 } 294 295 for name, tc := range cases { 296 t.Run(name, func(t *testing.T) { 297 // setup basic tx 298 txBuilder := newBuilder(testutil.CodecOptions{}.NewCodec()) 299 err := txBuilder.SetMsgs(msgs...) 300 require.NoError(t, err) 301 txBuilder.SetGasLimit(200000) 302 txBuilder.SetFeeAmount(feeAmount) 303 304 // set fee payer 305 txBuilder.SetFeePayer(tc.txFeePayer) 306 // and check it updates fields properly 307 signers, err := txBuilder.GetSigners() 308 require.NoError(t, err) 309 require.Equal(t, tc.expectedSigners, signers) 310 require.Equal(t, tc.expectedPayer, txBuilder.FeePayer()) 311 }) 312 } 313 } 314 315 func TestBuilderFeeGranter(t *testing.T) { 316 // keys and addresses 317 _, _, addr1 := testdata.KeyTestPubAddr() 318 319 // msg and signatures 320 msg1 := testdata.NewTestMsg(addr1, addr2) 321 feeAmount := testdata.NewTestFeeAmount() 322 msgs := []sdk.Msg{msg1} 323 324 txBuilder := newBuilder(testutil.CodecOptions{}.NewCodec()) 325 err := txBuilder.SetMsgs(msgs...) 326 require.NoError(t, err) 327 txBuilder.SetGasLimit(200000) 328 txBuilder.SetFeeAmount(feeAmount) 329 330 require.Empty(t, txBuilder.GetTx().FeeGranter()) 331 332 // set fee granter 333 txBuilder.SetFeeGranter(addr1) 334 require.Equal(t, addr1.String(), sdk.AccAddress(txBuilder.GetTx().FeeGranter()).String()) 335 }