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