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