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