testing_api_cmd_deposit.c (27654B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2018-2024 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify it 6 under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 3, or (at your 8 option) any later version. 9 10 TALER is distributed in the hope that it will be useful, but 11 WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 General Public License for more details. 14 15 You should have received a copy of the GNU General Public 16 License along with TALER; see the file COPYING. If not, see 17 <http://www.gnu.org/licenses/> 18 */ 19 /** 20 * @file testing/testing_api_cmd_deposit.c 21 * @brief command for testing /deposit. 22 * @author Marcello Stanisci 23 */ 24 #include "taler/taler_json_lib.h" 25 #include <gnunet/gnunet_curl_lib.h> 26 struct DepositState; 27 #define TALER_EXCHANGE_POST_BATCH_DEPOSIT_RESULT_CLOSURE \ 28 struct DepositState 29 #include "taler/exchange/post-batch-deposit.h" 30 #include "taler/taler_testing_lib.h" 31 #include "taler/taler_signatures.h" 32 #include "backoff.h" 33 34 35 /** 36 * How often do we retry before giving up? 37 */ 38 #define NUM_RETRIES 5 39 40 /** 41 * How long do we wait AT MOST when retrying? 42 */ 43 #define MAX_BACKOFF GNUNET_TIME_relative_multiply ( \ 44 GNUNET_TIME_UNIT_MILLISECONDS, 100) 45 46 47 /** 48 * State for a "deposit" CMD. 49 */ 50 struct DepositState 51 { 52 53 /** 54 * Amount to deposit. 55 */ 56 struct TALER_Amount amount; 57 58 /** 59 * Deposit fee. 60 */ 61 struct TALER_Amount deposit_fee; 62 63 /** 64 * Reference to any command that is able to provide a coin. 65 */ 66 const char *coin_reference; 67 68 /** 69 * If @e coin_reference refers to an operation that generated 70 * an array of coins, this value determines which coin to pick. 71 */ 72 unsigned int coin_index; 73 74 /** 75 * Our coin signature. 76 */ 77 struct TALER_CoinSpendSignatureP coin_sig; 78 79 /** 80 * Wire details of who is depositing -- this would be merchant 81 * wire details in a normal scenario. 82 */ 83 json_t *wire_details; 84 85 /** 86 * JSON string describing what a proposal is about. 87 */ 88 json_t *contract_terms; 89 90 /** 91 * Refund deadline. Zero for no refunds. 92 */ 93 struct GNUNET_TIME_Timestamp refund_deadline; 94 95 /** 96 * Wire deadline. 97 */ 98 struct GNUNET_TIME_Timestamp wire_deadline; 99 100 /** 101 * Set (by the interpreter) to a fresh private key. This 102 * key will be used to sign the deposit request. 103 */ 104 union TALER_AccountPrivateKeyP account_priv; 105 106 /** 107 * Set (by the interpreter) to the public key 108 * corresponding to @e account_priv. 109 */ 110 union TALER_AccountPublicKeyP account_pub; 111 112 /** 113 * Deposit handle while operation is running. 114 */ 115 struct TALER_EXCHANGE_PostBatchDepositHandle *dh; 116 117 /** 118 * Denomination public key of the deposited coin. 119 */ 120 const struct TALER_EXCHANGE_DenomPublicKey *denom_pub; 121 122 /** 123 * Timestamp of the /deposit operation in the wallet (contract signing time). 124 */ 125 struct GNUNET_TIME_Timestamp wallet_timestamp; 126 127 /** 128 * Interpreter state. 129 */ 130 struct TALER_TESTING_Interpreter *is; 131 132 /** 133 * Task scheduled to try later. 134 */ 135 struct GNUNET_SCHEDULER_Task *retry_task; 136 137 /** 138 * How long do we wait until we retry? 139 */ 140 struct GNUNET_TIME_Relative backoff; 141 142 /** 143 * Expected HTTP response code. 144 */ 145 unsigned int expected_response_code; 146 147 /** 148 * How often should we retry on (transient) failures? 149 */ 150 unsigned int do_retry; 151 152 /** 153 * Set to true if the /deposit succeeded 154 * and we now can provide the resulting traits. 155 */ 156 bool deposit_succeeded; 157 158 /** 159 * Expected entry in the coin history created by this 160 * operation. 161 */ 162 struct TALER_EXCHANGE_CoinHistoryEntry che; 163 164 /** 165 * When did the exchange receive the deposit? 166 */ 167 struct GNUNET_TIME_Timestamp exchange_timestamp; 168 169 /** 170 * Signing key used by the exchange to sign the 171 * deposit confirmation. 172 */ 173 struct TALER_ExchangePublicKeyP exchange_pub; 174 175 /** 176 * Signature from the exchange on the 177 * deposit confirmation. 178 */ 179 struct TALER_ExchangeSignatureP exchange_sig; 180 181 /** 182 * Cumulative total the @e exchange_sig signed over. 183 */ 184 struct TALER_Amount cumulative_total; 185 186 /** 187 * Reference to previous deposit operation. 188 * Only present if we're supposed to replay the previous deposit. 189 */ 190 const char *deposit_reference; 191 192 /** 193 * Did we set the parameters for this deposit command? 194 * 195 * When we're referencing another deposit operation, 196 * this will only be set after the command has been started. 197 */ 198 bool command_initialized; 199 200 /** 201 * Reference to fetch the merchant private key from. 202 * If NULL, we generate our own, fresh merchant key. 203 */ 204 const char *merchant_priv_reference; 205 }; 206 207 208 /** 209 * Run the command. 210 * 211 * @param cls closure. 212 * @param cmd the command to execute. 213 * @param is the interpreter state. 214 */ 215 static void 216 deposit_run (void *cls, 217 const struct TALER_TESTING_Command *cmd, 218 struct TALER_TESTING_Interpreter *is); 219 220 221 /** 222 * Task scheduled to re-try #deposit_run. 223 * 224 * @param cls a `struct DepositState` 225 */ 226 static void 227 do_retry (void *cls) 228 { 229 struct DepositState *ds = cls; 230 231 ds->retry_task = NULL; 232 TALER_TESTING_touch_cmd (ds->is); 233 deposit_run (ds, 234 NULL, 235 ds->is); 236 } 237 238 239 /** 240 * Callback to analyze the /deposit response, just used to 241 * check if the response code is acceptable. 242 * 243 * @param ds closure. 244 * @param dr deposit response details 245 */ 246 static void 247 deposit_cb (struct DepositState *ds, 248 const struct TALER_EXCHANGE_PostBatchDepositResponse *dr) 249 { 250 ds->dh = NULL; 251 if (ds->expected_response_code != dr->hr.http_status) 252 { 253 if (0 != ds->do_retry) 254 { 255 ds->do_retry--; 256 if ( (0 == dr->hr.http_status) || 257 (TALER_EC_GENERIC_DB_SOFT_FAILURE == dr->hr.ec) || 258 (MHD_HTTP_INTERNAL_SERVER_ERROR == dr->hr.http_status) ) 259 { 260 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 261 "Retrying deposit failed with %u/%d\n", 262 dr->hr.http_status, 263 (int) dr->hr.ec); 264 /* on DB conflicts, do not use backoff */ 265 if (TALER_EC_GENERIC_DB_SOFT_FAILURE == dr->hr.ec) 266 ds->backoff = GNUNET_TIME_UNIT_ZERO; 267 else 268 ds->backoff = GNUNET_TIME_randomized_backoff (ds->backoff, 269 MAX_BACKOFF); 270 TALER_TESTING_inc_tries (ds->is); 271 GNUNET_assert (NULL == ds->retry_task); 272 ds->retry_task 273 = GNUNET_SCHEDULER_add_delayed (ds->backoff, 274 &do_retry, 275 ds); 276 return; 277 } 278 } 279 TALER_TESTING_unexpected_status_with_body ( 280 ds->is, 281 dr->hr.http_status, 282 ds->expected_response_code, 283 dr->hr.reply); 284 285 return; 286 } 287 if (MHD_HTTP_OK == dr->hr.http_status) 288 { 289 ds->deposit_succeeded = true; 290 ds->exchange_timestamp = dr->details.ok.deposit_timestamp; 291 ds->exchange_pub = *dr->details.ok.exchange_pub; 292 ds->exchange_sig = *dr->details.ok.exchange_sig; 293 ds->cumulative_total = dr->details.ok.accumulated_total_without_fee; 294 } 295 TALER_TESTING_interpreter_next (ds->is); 296 } 297 298 299 /** 300 * Run the command. 301 * 302 * @param cls closure. 303 * @param cmd the command to execute. 304 * @param is the interpreter state. 305 */ 306 static void 307 deposit_run (void *cls, 308 const struct TALER_TESTING_Command *cmd, 309 struct TALER_TESTING_Interpreter *is) 310 { 311 struct DepositState *ds = cls; 312 const struct TALER_TESTING_Command *coin_cmd; 313 const struct TALER_TESTING_Command *acc_var; 314 const struct TALER_CoinSpendPrivateKeyP *coin_priv; 315 struct TALER_CoinSpendPublicKeyP coin_pub; 316 const struct TALER_AgeCommitmentHashP *phac; 317 const struct TALER_DenominationSignature *denom_pub_sig; 318 struct TALER_PrivateContractHashP h_contract_terms; 319 enum TALER_ErrorCode ec; 320 struct TALER_WireSaltP wire_salt; 321 struct TALER_FullPayto payto_uri; 322 struct GNUNET_JSON_Specification spec[] = { 323 TALER_JSON_spec_full_payto_uri ("payto_uri", 324 &payto_uri), 325 GNUNET_JSON_spec_fixed_auto ("salt", 326 &wire_salt), 327 GNUNET_JSON_spec_end () 328 }; 329 const char *exchange_url 330 = TALER_TESTING_get_exchange_url (is); 331 332 (void) cmd; 333 if (NULL == exchange_url) 334 { 335 GNUNET_break (0); 336 return; 337 } 338 ds->is = is; 339 if (! GNUNET_TIME_absolute_is_zero (ds->refund_deadline.abs_time)) 340 { 341 struct GNUNET_TIME_Relative refund_deadline; 342 343 refund_deadline 344 = GNUNET_TIME_absolute_get_remaining (ds->refund_deadline.abs_time); 345 ds->wire_deadline 346 = GNUNET_TIME_relative_to_timestamp ( 347 GNUNET_TIME_relative_multiply (refund_deadline, 348 2)); 349 } 350 else 351 { 352 ds->refund_deadline = ds->wallet_timestamp; 353 ds->wire_deadline = GNUNET_TIME_timestamp_get (); 354 } 355 if (NULL != ds->deposit_reference) 356 { 357 /* We're copying another deposit operation, initialize here. */ 358 const struct TALER_TESTING_Command *drcmd; 359 struct DepositState *ods; 360 361 drcmd = TALER_TESTING_interpreter_lookup_command (is, 362 ds->deposit_reference); 363 if (NULL == drcmd) 364 { 365 GNUNET_break (0); 366 TALER_TESTING_interpreter_fail (is); 367 return; 368 } 369 ods = drcmd->cls; 370 ds->coin_reference = ods->coin_reference; 371 ds->coin_index = ods->coin_index; 372 ds->wire_details = json_incref (ods->wire_details); 373 GNUNET_assert (NULL != ds->wire_details); 374 ds->contract_terms = json_incref (ods->contract_terms); 375 ds->wallet_timestamp = ods->wallet_timestamp; 376 ds->refund_deadline = ods->refund_deadline; 377 ds->wire_deadline = ods->wire_deadline; 378 ds->amount = ods->amount; 379 ds->account_priv = ods->account_priv; 380 ds->account_pub = ods->account_pub; 381 ds->command_initialized = true; 382 } 383 else if (NULL != ds->merchant_priv_reference) 384 { 385 /* We're copying the merchant key from another deposit operation */ 386 const struct TALER_MerchantPrivateKeyP *merchant_priv; 387 const struct TALER_TESTING_Command *mpcmd; 388 389 mpcmd = TALER_TESTING_interpreter_lookup_command ( 390 is, 391 ds->merchant_priv_reference); 392 if (NULL == mpcmd) 393 { 394 GNUNET_break (0); 395 TALER_TESTING_interpreter_fail (is); 396 return; 397 } 398 if ( (GNUNET_OK != 399 TALER_TESTING_get_trait_merchant_priv (mpcmd, 400 &merchant_priv)) ) 401 { 402 GNUNET_break (0); 403 TALER_TESTING_interpreter_fail (is); 404 return; 405 } 406 ds->account_priv.merchant_priv = *merchant_priv; 407 GNUNET_CRYPTO_eddsa_key_get_public ( 408 &ds->account_priv.merchant_priv.eddsa_priv, 409 &ds->account_pub.merchant_pub.eddsa_pub); 410 } 411 else if (NULL != (acc_var 412 = TALER_TESTING_interpreter_get_command ( 413 is, 414 "account-priv"))) 415 { 416 const union TALER_AccountPrivateKeyP *account_priv; 417 418 if ( (GNUNET_OK != 419 TALER_TESTING_get_trait_account_priv (acc_var, 420 &account_priv)) ) 421 { 422 GNUNET_break (0); 423 TALER_TESTING_interpreter_fail (is); 424 return; 425 } 426 ds->account_priv = *account_priv; 427 GNUNET_CRYPTO_eddsa_key_get_public ( 428 &ds->account_priv.merchant_priv.eddsa_priv, 429 &ds->account_pub.merchant_pub.eddsa_pub); 430 } 431 else 432 { 433 GNUNET_CRYPTO_eddsa_key_create ( 434 &ds->account_priv.merchant_priv.eddsa_priv); 435 GNUNET_CRYPTO_eddsa_key_get_public ( 436 &ds->account_priv.merchant_priv.eddsa_priv, 437 &ds->account_pub.merchant_pub.eddsa_pub); 438 } 439 GNUNET_assert (NULL != ds->wire_details); 440 if (GNUNET_OK != 441 GNUNET_JSON_parse (ds->wire_details, 442 spec, 443 NULL, NULL)) 444 { 445 json_dumpf (ds->wire_details, 446 stderr, 447 JSON_INDENT (2)); 448 GNUNET_break (0); 449 TALER_TESTING_interpreter_fail (is); 450 return; 451 } 452 GNUNET_assert (ds->coin_reference); 453 coin_cmd = TALER_TESTING_interpreter_lookup_command (is, 454 ds->coin_reference); 455 if (NULL == coin_cmd) 456 { 457 GNUNET_break (0); 458 TALER_TESTING_interpreter_fail (is); 459 return; 460 } 461 #if DUMP_CONTRACT 462 fprintf (stderr, 463 "Using contract:\n"); 464 json_dumpf (ds->contract_terms, 465 stderr, 466 JSON_INDENT (2)); 467 #endif 468 if (GNUNET_OK != 469 TALER_TESTING_get_trait_coin_priv (coin_cmd, 470 ds->coin_index, 471 &coin_priv)) 472 { 473 GNUNET_break (0); 474 TALER_TESTING_interpreter_fail (is); 475 return; 476 } 477 if (GNUNET_OK != 478 TALER_TESTING_get_trait_h_age_commitment (coin_cmd, 479 ds->coin_index, 480 &phac)) 481 { 482 GNUNET_break (0); 483 TALER_TESTING_interpreter_fail (is); 484 return; 485 } 486 if (GNUNET_OK != 487 TALER_TESTING_get_trait_denom_pub (coin_cmd, 488 ds->coin_index, 489 &ds->denom_pub)) 490 { 491 GNUNET_break (0); 492 TALER_TESTING_interpreter_fail (is); 493 return; 494 } 495 if (GNUNET_OK != 496 TALER_TESTING_get_trait_denom_sig (coin_cmd, 497 ds->coin_index, 498 &denom_pub_sig)) 499 { 500 GNUNET_break (0); 501 TALER_TESTING_interpreter_fail (is); 502 return; 503 } 504 if (GNUNET_OK != 505 TALER_JSON_contract_hash (ds->contract_terms, 506 &h_contract_terms)) 507 { 508 GNUNET_break (0); 509 TALER_TESTING_interpreter_fail (is); 510 return; 511 } 512 513 ds->deposit_fee = ds->denom_pub->fees.deposit; 514 GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv, 515 &coin_pub.eddsa_pub); 516 517 { 518 struct TALER_MerchantWireHashP h_wire; 519 520 GNUNET_assert (GNUNET_OK == 521 TALER_JSON_merchant_wire_signature_hash (ds->wire_details, 522 &h_wire)); 523 TALER_wallet_deposit_sign (&ds->amount, 524 &ds->denom_pub->fees.deposit, 525 &h_wire, 526 &h_contract_terms, 527 NULL, /* wallet data hash */ 528 phac, 529 NULL, /* hash of extensions */ 530 &ds->denom_pub->h_key, 531 ds->wallet_timestamp, 532 &ds->account_pub.merchant_pub, 533 ds->refund_deadline, 534 coin_priv, 535 &ds->coin_sig); 536 ds->che.type = TALER_EXCHANGE_CTT_DEPOSIT; 537 ds->che.amount = ds->amount; 538 ds->che.details.deposit.h_wire = h_wire; 539 ds->che.details.deposit.h_contract_terms = h_contract_terms; 540 ds->che.details.deposit.no_h_policy = true; 541 ds->che.details.deposit.no_wallet_data_hash = true; 542 ds->che.details.deposit.wallet_timestamp = ds->wallet_timestamp; 543 ds->che.details.deposit.merchant_pub = ds->account_pub.merchant_pub; 544 ds->che.details.deposit.refund_deadline = ds->refund_deadline; 545 ds->che.details.deposit.sig = ds->coin_sig; 546 ds->che.details.deposit.no_hac = true; 547 ds->che.details.deposit.deposit_fee = ds->denom_pub->fees.deposit; 548 } 549 GNUNET_assert (NULL == ds->dh); 550 { 551 struct TALER_EXCHANGE_CoinDepositDetail cdd = { 552 .amount = ds->amount, 553 .coin_pub = coin_pub, 554 .coin_sig = ds->coin_sig, 555 .denom_sig = *denom_pub_sig, 556 .h_denom_pub = ds->denom_pub->h_key, 557 .h_age_commitment = {{{0}}}, 558 }; 559 struct TALER_EXCHANGE_DepositContractDetail dcd = { 560 .wire_deadline = ds->wire_deadline, 561 .merchant_payto_uri = payto_uri, 562 .wire_salt = wire_salt, 563 .h_contract_terms = h_contract_terms, 564 .wallet_timestamp = ds->wallet_timestamp, 565 .merchant_pub = ds->account_pub.merchant_pub, 566 .refund_deadline = ds->refund_deadline 567 }; 568 569 TALER_merchant_contract_sign (&h_contract_terms, 570 &ds->account_priv.merchant_priv, 571 &dcd.merchant_sig); 572 if (NULL != phac) 573 cdd.h_age_commitment = *phac; 574 575 ds->dh = TALER_EXCHANGE_post_batch_deposit_create ( 576 TALER_TESTING_interpreter_get_context (is), 577 exchange_url, 578 TALER_TESTING_get_keys (is), 579 &dcd, 580 1, 581 &cdd, 582 &ec); 583 } 584 if (NULL == ds->dh) 585 { 586 GNUNET_break (0); 587 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 588 "Could not create deposit with EC %d\n", 589 (int) ec); 590 TALER_TESTING_interpreter_fail (is); 591 return; 592 } 593 TALER_EXCHANGE_post_batch_deposit_start (ds->dh, 594 &deposit_cb, 595 ds); 596 } 597 598 599 /** 600 * Free the state of a "deposit" CMD, and possibly cancel a 601 * pending operation thereof. 602 * 603 * @param cls closure, must be a `struct DepositState`. 604 * @param cmd the command which is being cleaned up. 605 */ 606 static void 607 deposit_cleanup (void *cls, 608 const struct TALER_TESTING_Command *cmd) 609 { 610 struct DepositState *ds = cls; 611 612 if (NULL != ds->dh) 613 { 614 TALER_TESTING_command_incomplete (ds->is, 615 cmd->label); 616 TALER_EXCHANGE_post_batch_deposit_cancel (ds->dh); 617 ds->dh = NULL; 618 } 619 if (NULL != ds->retry_task) 620 { 621 GNUNET_SCHEDULER_cancel (ds->retry_task); 622 ds->retry_task = NULL; 623 } 624 json_decref (ds->wire_details); 625 json_decref (ds->contract_terms); 626 GNUNET_free (ds); 627 } 628 629 630 /** 631 * Offer internal data from a "deposit" CMD, to other commands. 632 * 633 * @param cls closure. 634 * @param[out] ret result. 635 * @param trait name of the trait. 636 * @param index index number of the object to offer. 637 * @return #GNUNET_OK on success. 638 */ 639 static enum GNUNET_GenericReturnValue 640 deposit_traits (void *cls, 641 const void **ret, 642 const char *trait, 643 unsigned int index) 644 { 645 struct DepositState *ds = cls; 646 const struct TALER_TESTING_Command *coin_cmd; 647 /* Will point to coin cmd internals. */ 648 const struct TALER_CoinSpendPrivateKeyP *coin_spent_priv; 649 const struct TALER_CoinSpendPublicKeyP *coin_spent_pub; 650 const struct TALER_AgeCommitmentProof *age_commitment_proof=NULL; 651 const struct TALER_AgeCommitmentHashP *h_age_commitment=NULL; 652 653 if (! ds->command_initialized) 654 { 655 /* No access to traits yet. */ 656 GNUNET_break (0); 657 return GNUNET_NO; 658 } 659 660 coin_cmd 661 = TALER_TESTING_interpreter_lookup_command (ds->is, 662 ds->coin_reference); 663 if (NULL == coin_cmd) 664 { 665 GNUNET_break (0); 666 TALER_TESTING_interpreter_fail (ds->is); 667 return GNUNET_NO; 668 } 669 if ( (GNUNET_OK != 670 TALER_TESTING_get_trait_coin_priv (coin_cmd, 671 ds->coin_index, 672 &coin_spent_priv)) || 673 (GNUNET_OK != 674 TALER_TESTING_get_trait_coin_pub (coin_cmd, 675 ds->coin_index, 676 &coin_spent_pub)) || 677 (GNUNET_OK != 678 TALER_TESTING_get_trait_age_commitment_proof (coin_cmd, 679 ds->coin_index, 680 &age_commitment_proof)) || 681 (GNUNET_OK != 682 TALER_TESTING_get_trait_h_age_commitment (coin_cmd, 683 ds->coin_index, 684 &h_age_commitment)) ) 685 { 686 GNUNET_break (0); 687 TALER_TESTING_interpreter_fail (ds->is); 688 return GNUNET_NO; 689 } 690 691 { 692 struct TALER_TESTING_Trait traits[] = { 693 /* First four traits are only available if 694 ds->traits is true */ 695 TALER_TESTING_make_trait_exchange_pub (0, 696 &ds->exchange_pub), 697 TALER_TESTING_make_trait_exchange_sig (0, 698 &ds->exchange_sig), 699 TALER_TESTING_make_trait_amount (&ds->cumulative_total), 700 TALER_TESTING_make_trait_timestamp (0, 701 &ds->exchange_timestamp), 702 /* These traits are always available */ 703 TALER_TESTING_make_trait_coin_history (0, 704 &ds->che), 705 TALER_TESTING_make_trait_coin_priv (0, 706 coin_spent_priv), 707 TALER_TESTING_make_trait_coin_pub (0, 708 coin_spent_pub), 709 TALER_TESTING_make_trait_denom_pub (0, 710 ds->denom_pub), 711 TALER_TESTING_make_trait_coin_sig (0, 712 &ds->coin_sig), 713 TALER_TESTING_make_trait_age_commitment_proof (0, 714 age_commitment_proof), 715 TALER_TESTING_make_trait_h_age_commitment (0, 716 h_age_commitment), 717 TALER_TESTING_make_trait_wire_details (ds->wire_details), 718 TALER_TESTING_make_trait_contract_terms (ds->contract_terms), 719 TALER_TESTING_make_trait_merchant_priv (&ds->account_priv.merchant_priv), 720 TALER_TESTING_make_trait_merchant_pub (&ds->account_pub.merchant_pub), 721 TALER_TESTING_make_trait_account_priv (&ds->account_priv), 722 TALER_TESTING_make_trait_account_pub (&ds->account_pub), 723 TALER_TESTING_make_trait_deposit_amount (0, 724 &ds->amount), 725 TALER_TESTING_make_trait_deposit_fee_amount (0, 726 &ds->deposit_fee), 727 TALER_TESTING_make_trait_wire_deadline (0, 728 &ds->wire_deadline), 729 TALER_TESTING_make_trait_refund_deadline (0, 730 &ds->refund_deadline), 731 TALER_TESTING_trait_end () 732 }; 733 734 return TALER_TESTING_get_trait ((ds->deposit_succeeded) 735 ? traits 736 : &traits[4], 737 ret, 738 trait, 739 index); 740 } 741 } 742 743 744 struct TALER_TESTING_Command 745 TALER_TESTING_cmd_deposit ( 746 const char *label, 747 const char *coin_reference, 748 unsigned int coin_index, 749 struct TALER_FullPayto target_account_payto, 750 const char *contract_terms, 751 struct GNUNET_TIME_Relative refund_deadline, 752 const char *amount, 753 unsigned int expected_response_code) 754 { 755 struct DepositState *ds; 756 757 ds = GNUNET_new (struct DepositState); 758 ds->coin_reference = coin_reference; 759 ds->coin_index = coin_index; 760 ds->wire_details = TALER_TESTING_make_wire_details (target_account_payto); 761 GNUNET_assert (NULL != ds->wire_details); 762 ds->contract_terms = json_loads (contract_terms, 763 JSON_REJECT_DUPLICATES, 764 NULL); 765 if (NULL == ds->contract_terms) 766 { 767 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 768 "Failed to parse contract terms `%s' for CMD `%s'\n", 769 contract_terms, 770 label); 771 GNUNET_assert (0); 772 } 773 ds->wallet_timestamp = GNUNET_TIME_timestamp_get (); 774 GNUNET_assert (0 == 775 json_object_set_new (ds->contract_terms, 776 "timestamp", 777 GNUNET_JSON_from_timestamp ( 778 ds->wallet_timestamp))); 779 if (! GNUNET_TIME_relative_is_zero (refund_deadline)) 780 { 781 ds->refund_deadline = GNUNET_TIME_relative_to_timestamp (refund_deadline); 782 GNUNET_assert (0 == 783 json_object_set_new (ds->contract_terms, 784 "refund_deadline", 785 GNUNET_JSON_from_timestamp ( 786 ds->refund_deadline))); 787 } 788 GNUNET_assert (GNUNET_OK == 789 TALER_string_to_amount (amount, 790 &ds->amount)); 791 ds->expected_response_code = expected_response_code; 792 ds->command_initialized = true; 793 { 794 struct TALER_TESTING_Command cmd = { 795 .cls = ds, 796 .label = label, 797 .run = &deposit_run, 798 .cleanup = &deposit_cleanup, 799 .traits = &deposit_traits 800 }; 801 802 return cmd; 803 } 804 } 805 806 807 struct TALER_TESTING_Command 808 TALER_TESTING_cmd_deposit_with_ref ( 809 const char *label, 810 const char *coin_reference, 811 unsigned int coin_index, 812 struct TALER_FullPayto target_account_payto, 813 const char *contract_terms, 814 struct GNUNET_TIME_Relative refund_deadline, 815 const char *amount, 816 unsigned int expected_response_code, 817 const char *merchant_priv_reference) 818 { 819 struct DepositState *ds; 820 821 ds = GNUNET_new (struct DepositState); 822 ds->merchant_priv_reference = merchant_priv_reference; 823 ds->coin_reference = coin_reference; 824 ds->coin_index = coin_index; 825 ds->wire_details = TALER_TESTING_make_wire_details (target_account_payto); 826 GNUNET_assert (NULL != ds->wire_details); 827 ds->contract_terms = json_loads (contract_terms, 828 JSON_REJECT_DUPLICATES, 829 NULL); 830 if (NULL == ds->contract_terms) 831 { 832 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 833 "Failed to parse contract terms `%s' for CMD `%s'\n", 834 contract_terms, 835 label); 836 GNUNET_assert (0); 837 } 838 ds->wallet_timestamp = GNUNET_TIME_timestamp_get (); 839 GNUNET_assert (0 == 840 json_object_set_new (ds->contract_terms, 841 "timestamp", 842 GNUNET_JSON_from_timestamp ( 843 ds->wallet_timestamp))); 844 if (0 != refund_deadline.rel_value_us) 845 { 846 ds->refund_deadline = GNUNET_TIME_relative_to_timestamp (refund_deadline); 847 GNUNET_assert (0 == 848 json_object_set_new (ds->contract_terms, 849 "refund_deadline", 850 GNUNET_JSON_from_timestamp ( 851 ds->refund_deadline))); 852 } 853 GNUNET_assert (GNUNET_OK == 854 TALER_string_to_amount (amount, 855 &ds->amount)); 856 ds->expected_response_code = expected_response_code; 857 ds->command_initialized = true; 858 { 859 struct TALER_TESTING_Command cmd = { 860 .cls = ds, 861 .label = label, 862 .run = &deposit_run, 863 .cleanup = &deposit_cleanup, 864 .traits = &deposit_traits 865 }; 866 867 return cmd; 868 } 869 } 870 871 872 struct TALER_TESTING_Command 873 TALER_TESTING_cmd_deposit_replay ( 874 const char *label, 875 const char *deposit_reference, 876 unsigned int expected_response_code) 877 { 878 struct DepositState *ds; 879 880 ds = GNUNET_new (struct DepositState); 881 ds->deposit_reference = deposit_reference; 882 ds->expected_response_code = expected_response_code; 883 { 884 struct TALER_TESTING_Command cmd = { 885 .cls = ds, 886 .label = label, 887 .run = &deposit_run, 888 .cleanup = &deposit_cleanup, 889 .traits = &deposit_traits 890 }; 891 892 return cmd; 893 } 894 } 895 896 897 struct TALER_TESTING_Command 898 TALER_TESTING_cmd_deposit_with_retry (struct TALER_TESTING_Command cmd) 899 { 900 struct DepositState *ds; 901 902 GNUNET_assert (&deposit_run == cmd.run); 903 ds = cmd.cls; 904 ds->do_retry = NUM_RETRIES; 905 return cmd; 906 } 907 908 909 /* end of testing_api_cmd_deposit.c */