testing_api_cmd_deposit.c (27091B)
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_BatchDepositHandle *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 * Reference to previous deposit operation. 180 * Only present if we're supposed to replay the previous deposit. 181 */ 182 const char *deposit_reference; 183 184 /** 185 * Did we set the parameters for this deposit command? 186 * 187 * When we're referencing another deposit operation, 188 * this will only be set after the command has been started. 189 */ 190 bool command_initialized; 191 192 /** 193 * Reference to fetch the merchant private key from. 194 * If NULL, we generate our own, fresh merchant key. 195 */ 196 const char *merchant_priv_reference; 197 }; 198 199 200 /** 201 * Run the command. 202 * 203 * @param cls closure. 204 * @param cmd the command to execute. 205 * @param is the interpreter state. 206 */ 207 static void 208 deposit_run (void *cls, 209 const struct TALER_TESTING_Command *cmd, 210 struct TALER_TESTING_Interpreter *is); 211 212 213 /** 214 * Task scheduled to re-try #deposit_run. 215 * 216 * @param cls a `struct DepositState` 217 */ 218 static void 219 do_retry (void *cls) 220 { 221 struct DepositState *ds = cls; 222 223 ds->retry_task = NULL; 224 TALER_TESTING_touch_cmd (ds->is); 225 deposit_run (ds, 226 NULL, 227 ds->is); 228 } 229 230 231 /** 232 * Callback to analyze the /deposit response, just used to 233 * check if the response code is acceptable. 234 * 235 * @param cls closure. 236 * @param dr deposit response details 237 */ 238 static void 239 deposit_cb (void *cls, 240 const struct TALER_EXCHANGE_BatchDepositResult *dr) 241 { 242 struct DepositState *ds = cls; 243 244 ds->dh = NULL; 245 if (ds->expected_response_code != dr->hr.http_status) 246 { 247 if (0 != ds->do_retry) 248 { 249 ds->do_retry--; 250 if ( (0 == dr->hr.http_status) || 251 (TALER_EC_GENERIC_DB_SOFT_FAILURE == dr->hr.ec) || 252 (MHD_HTTP_INTERNAL_SERVER_ERROR == dr->hr.http_status) ) 253 { 254 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 255 "Retrying deposit failed with %u/%d\n", 256 dr->hr.http_status, 257 (int) dr->hr.ec); 258 /* on DB conflicts, do not use backoff */ 259 if (TALER_EC_GENERIC_DB_SOFT_FAILURE == dr->hr.ec) 260 ds->backoff = GNUNET_TIME_UNIT_ZERO; 261 else 262 ds->backoff = GNUNET_TIME_randomized_backoff (ds->backoff, 263 MAX_BACKOFF); 264 TALER_TESTING_inc_tries (ds->is); 265 GNUNET_assert (NULL == ds->retry_task); 266 ds->retry_task 267 = GNUNET_SCHEDULER_add_delayed (ds->backoff, 268 &do_retry, 269 ds); 270 return; 271 } 272 } 273 TALER_TESTING_unexpected_status_with_body ( 274 ds->is, 275 dr->hr.http_status, 276 ds->expected_response_code, 277 dr->hr.reply); 278 279 return; 280 } 281 if (MHD_HTTP_OK == dr->hr.http_status) 282 { 283 ds->deposit_succeeded = true; 284 ds->exchange_timestamp = dr->details.ok.deposit_timestamp; 285 ds->exchange_pub = *dr->details.ok.exchange_pub; 286 ds->exchange_sig = *dr->details.ok.exchange_sig; 287 } 288 TALER_TESTING_interpreter_next (ds->is); 289 } 290 291 292 /** 293 * Run the command. 294 * 295 * @param cls closure. 296 * @param cmd the command to execute. 297 * @param is the interpreter state. 298 */ 299 static void 300 deposit_run (void *cls, 301 const struct TALER_TESTING_Command *cmd, 302 struct TALER_TESTING_Interpreter *is) 303 { 304 struct DepositState *ds = cls; 305 const struct TALER_TESTING_Command *coin_cmd; 306 const struct TALER_TESTING_Command *acc_var; 307 const struct TALER_CoinSpendPrivateKeyP *coin_priv; 308 struct TALER_CoinSpendPublicKeyP coin_pub; 309 const struct TALER_AgeCommitmentHashP *phac; 310 const struct TALER_DenominationSignature *denom_pub_sig; 311 struct TALER_PrivateContractHashP h_contract_terms; 312 enum TALER_ErrorCode ec; 313 struct TALER_WireSaltP wire_salt; 314 struct TALER_FullPayto payto_uri; 315 struct GNUNET_JSON_Specification spec[] = { 316 TALER_JSON_spec_full_payto_uri ("payto_uri", 317 &payto_uri), 318 GNUNET_JSON_spec_fixed_auto ("salt", 319 &wire_salt), 320 GNUNET_JSON_spec_end () 321 }; 322 const char *exchange_url 323 = TALER_TESTING_get_exchange_url (is); 324 325 (void) cmd; 326 if (NULL == exchange_url) 327 { 328 GNUNET_break (0); 329 return; 330 } 331 ds->is = is; 332 if (! GNUNET_TIME_absolute_is_zero (ds->refund_deadline.abs_time)) 333 { 334 struct GNUNET_TIME_Relative refund_deadline; 335 336 refund_deadline 337 = GNUNET_TIME_absolute_get_remaining (ds->refund_deadline.abs_time); 338 ds->wire_deadline 339 = GNUNET_TIME_relative_to_timestamp ( 340 GNUNET_TIME_relative_multiply (refund_deadline, 341 2)); 342 } 343 else 344 { 345 ds->refund_deadline = ds->wallet_timestamp; 346 ds->wire_deadline = GNUNET_TIME_timestamp_get (); 347 } 348 if (NULL != ds->deposit_reference) 349 { 350 /* We're copying another deposit operation, initialize here. */ 351 const struct TALER_TESTING_Command *drcmd; 352 struct DepositState *ods; 353 354 drcmd = TALER_TESTING_interpreter_lookup_command (is, 355 ds->deposit_reference); 356 if (NULL == drcmd) 357 { 358 GNUNET_break (0); 359 TALER_TESTING_interpreter_fail (is); 360 return; 361 } 362 ods = drcmd->cls; 363 ds->coin_reference = ods->coin_reference; 364 ds->coin_index = ods->coin_index; 365 ds->wire_details = json_incref (ods->wire_details); 366 GNUNET_assert (NULL != ds->wire_details); 367 ds->contract_terms = json_incref (ods->contract_terms); 368 ds->wallet_timestamp = ods->wallet_timestamp; 369 ds->refund_deadline = ods->refund_deadline; 370 ds->wire_deadline = ods->wire_deadline; 371 ds->amount = ods->amount; 372 ds->account_priv = ods->account_priv; 373 ds->account_pub = ods->account_pub; 374 ds->command_initialized = true; 375 } 376 else if (NULL != ds->merchant_priv_reference) 377 { 378 /* We're copying the merchant key from another deposit operation */ 379 const struct TALER_MerchantPrivateKeyP *merchant_priv; 380 const struct TALER_TESTING_Command *mpcmd; 381 382 mpcmd = TALER_TESTING_interpreter_lookup_command ( 383 is, 384 ds->merchant_priv_reference); 385 if (NULL == mpcmd) 386 { 387 GNUNET_break (0); 388 TALER_TESTING_interpreter_fail (is); 389 return; 390 } 391 if ( (GNUNET_OK != 392 TALER_TESTING_get_trait_merchant_priv (mpcmd, 393 &merchant_priv)) ) 394 { 395 GNUNET_break (0); 396 TALER_TESTING_interpreter_fail (is); 397 return; 398 } 399 ds->account_priv.merchant_priv = *merchant_priv; 400 GNUNET_CRYPTO_eddsa_key_get_public ( 401 &ds->account_priv.merchant_priv.eddsa_priv, 402 &ds->account_pub.merchant_pub.eddsa_pub); 403 } 404 else if (NULL != (acc_var 405 = TALER_TESTING_interpreter_get_command ( 406 is, 407 "account-priv"))) 408 { 409 const union TALER_AccountPrivateKeyP *account_priv; 410 411 if ( (GNUNET_OK != 412 TALER_TESTING_get_trait_account_priv (acc_var, 413 &account_priv)) ) 414 { 415 GNUNET_break (0); 416 TALER_TESTING_interpreter_fail (is); 417 return; 418 } 419 ds->account_priv = *account_priv; 420 GNUNET_CRYPTO_eddsa_key_get_public ( 421 &ds->account_priv.merchant_priv.eddsa_priv, 422 &ds->account_pub.merchant_pub.eddsa_pub); 423 } 424 else 425 { 426 GNUNET_CRYPTO_eddsa_key_create ( 427 &ds->account_priv.merchant_priv.eddsa_priv); 428 GNUNET_CRYPTO_eddsa_key_get_public ( 429 &ds->account_priv.merchant_priv.eddsa_priv, 430 &ds->account_pub.merchant_pub.eddsa_pub); 431 } 432 GNUNET_assert (NULL != ds->wire_details); 433 if (GNUNET_OK != 434 GNUNET_JSON_parse (ds->wire_details, 435 spec, 436 NULL, NULL)) 437 { 438 json_dumpf (ds->wire_details, 439 stderr, 440 JSON_INDENT (2)); 441 GNUNET_break (0); 442 TALER_TESTING_interpreter_fail (is); 443 return; 444 } 445 GNUNET_assert (ds->coin_reference); 446 coin_cmd = TALER_TESTING_interpreter_lookup_command (is, 447 ds->coin_reference); 448 if (NULL == coin_cmd) 449 { 450 GNUNET_break (0); 451 TALER_TESTING_interpreter_fail (is); 452 return; 453 } 454 #if DUMP_CONTRACT 455 fprintf (stderr, 456 "Using contract:\n"); 457 json_dumpf (ds->contract_terms, 458 stderr, 459 JSON_INDENT (2)); 460 #endif 461 if (GNUNET_OK != 462 TALER_TESTING_get_trait_coin_priv (coin_cmd, 463 ds->coin_index, 464 &coin_priv)) 465 { 466 GNUNET_break (0); 467 TALER_TESTING_interpreter_fail (is); 468 return; 469 } 470 if (GNUNET_OK != 471 TALER_TESTING_get_trait_h_age_commitment (coin_cmd, 472 ds->coin_index, 473 &phac)) 474 { 475 GNUNET_break (0); 476 TALER_TESTING_interpreter_fail (is); 477 return; 478 } 479 if (GNUNET_OK != 480 TALER_TESTING_get_trait_denom_pub (coin_cmd, 481 ds->coin_index, 482 &ds->denom_pub)) 483 { 484 GNUNET_break (0); 485 TALER_TESTING_interpreter_fail (is); 486 return; 487 } 488 if (GNUNET_OK != 489 TALER_TESTING_get_trait_denom_sig (coin_cmd, 490 ds->coin_index, 491 &denom_pub_sig)) 492 { 493 GNUNET_break (0); 494 TALER_TESTING_interpreter_fail (is); 495 return; 496 } 497 if (GNUNET_OK != 498 TALER_JSON_contract_hash (ds->contract_terms, 499 &h_contract_terms)) 500 { 501 GNUNET_break (0); 502 TALER_TESTING_interpreter_fail (is); 503 return; 504 } 505 506 ds->deposit_fee = ds->denom_pub->fees.deposit; 507 GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv, 508 &coin_pub.eddsa_pub); 509 510 { 511 struct TALER_MerchantWireHashP h_wire; 512 513 GNUNET_assert (GNUNET_OK == 514 TALER_JSON_merchant_wire_signature_hash (ds->wire_details, 515 &h_wire)); 516 TALER_wallet_deposit_sign (&ds->amount, 517 &ds->denom_pub->fees.deposit, 518 &h_wire, 519 &h_contract_terms, 520 NULL, /* wallet data hash */ 521 phac, 522 NULL, /* hash of extensions */ 523 &ds->denom_pub->h_key, 524 ds->wallet_timestamp, 525 &ds->account_pub.merchant_pub, 526 ds->refund_deadline, 527 coin_priv, 528 &ds->coin_sig); 529 ds->che.type = TALER_EXCHANGE_CTT_DEPOSIT; 530 ds->che.amount = ds->amount; 531 ds->che.details.deposit.h_wire = h_wire; 532 ds->che.details.deposit.h_contract_terms = h_contract_terms; 533 ds->che.details.deposit.no_h_policy = true; 534 ds->che.details.deposit.no_wallet_data_hash = true; 535 ds->che.details.deposit.wallet_timestamp = ds->wallet_timestamp; 536 ds->che.details.deposit.merchant_pub = ds->account_pub.merchant_pub; 537 ds->che.details.deposit.refund_deadline = ds->refund_deadline; 538 ds->che.details.deposit.sig = ds->coin_sig; 539 ds->che.details.deposit.no_hac = true; 540 ds->che.details.deposit.deposit_fee = ds->denom_pub->fees.deposit; 541 } 542 GNUNET_assert (NULL == ds->dh); 543 { 544 struct TALER_EXCHANGE_CoinDepositDetail cdd = { 545 .amount = ds->amount, 546 .coin_pub = coin_pub, 547 .coin_sig = ds->coin_sig, 548 .denom_sig = *denom_pub_sig, 549 .h_denom_pub = ds->denom_pub->h_key, 550 .h_age_commitment = {{{0}}}, 551 }; 552 struct TALER_EXCHANGE_DepositContractDetail dcd = { 553 .wire_deadline = ds->wire_deadline, 554 .merchant_payto_uri = payto_uri, 555 .wire_salt = wire_salt, 556 .h_contract_terms = h_contract_terms, 557 .wallet_timestamp = ds->wallet_timestamp, 558 .merchant_pub = ds->account_pub.merchant_pub, 559 .refund_deadline = ds->refund_deadline 560 }; 561 562 TALER_merchant_contract_sign (&h_contract_terms, 563 &ds->account_priv.merchant_priv, 564 &dcd.merchant_sig); 565 if (NULL != phac) 566 cdd.h_age_commitment = *phac; 567 568 ds->dh = TALER_EXCHANGE_batch_deposit ( 569 TALER_TESTING_interpreter_get_context (is), 570 exchange_url, 571 TALER_TESTING_get_keys (is), 572 &dcd, 573 1, 574 &cdd, 575 &deposit_cb, 576 ds, 577 &ec); 578 } 579 if (NULL == ds->dh) 580 { 581 GNUNET_break (0); 582 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 583 "Could not create deposit with EC %d\n", 584 (int) ec); 585 TALER_TESTING_interpreter_fail (is); 586 return; 587 } 588 } 589 590 591 /** 592 * Free the state of a "deposit" CMD, and possibly cancel a 593 * pending operation thereof. 594 * 595 * @param cls closure, must be a `struct DepositState`. 596 * @param cmd the command which is being cleaned up. 597 */ 598 static void 599 deposit_cleanup (void *cls, 600 const struct TALER_TESTING_Command *cmd) 601 { 602 struct DepositState *ds = cls; 603 604 if (NULL != ds->dh) 605 { 606 TALER_TESTING_command_incomplete (ds->is, 607 cmd->label); 608 TALER_EXCHANGE_batch_deposit_cancel (ds->dh); 609 ds->dh = NULL; 610 } 611 if (NULL != ds->retry_task) 612 { 613 GNUNET_SCHEDULER_cancel (ds->retry_task); 614 ds->retry_task = NULL; 615 } 616 json_decref (ds->wire_details); 617 json_decref (ds->contract_terms); 618 GNUNET_free (ds); 619 } 620 621 622 /** 623 * Offer internal data from a "deposit" CMD, to other commands. 624 * 625 * @param cls closure. 626 * @param[out] ret result. 627 * @param trait name of the trait. 628 * @param index index number of the object to offer. 629 * @return #GNUNET_OK on success. 630 */ 631 static enum GNUNET_GenericReturnValue 632 deposit_traits (void *cls, 633 const void **ret, 634 const char *trait, 635 unsigned int index) 636 { 637 struct DepositState *ds = cls; 638 const struct TALER_TESTING_Command *coin_cmd; 639 /* Will point to coin cmd internals. */ 640 const struct TALER_CoinSpendPrivateKeyP *coin_spent_priv; 641 struct TALER_CoinSpendPublicKeyP coin_spent_pub; 642 const struct TALER_AgeCommitmentProof *age_commitment_proof=NULL; 643 const struct TALER_AgeCommitmentHashP *h_age_commitment=NULL; 644 645 if (! ds->command_initialized) 646 { 647 /* No access to traits yet. */ 648 GNUNET_break (0); 649 return GNUNET_NO; 650 } 651 652 coin_cmd 653 = TALER_TESTING_interpreter_lookup_command (ds->is, 654 ds->coin_reference); 655 if (NULL == coin_cmd) 656 { 657 GNUNET_break (0); 658 TALER_TESTING_interpreter_fail (ds->is); 659 return GNUNET_NO; 660 } 661 if ( (GNUNET_OK != 662 TALER_TESTING_get_trait_coin_priv (coin_cmd, 663 ds->coin_index, 664 &coin_spent_priv)) || 665 (GNUNET_OK != 666 TALER_TESTING_get_trait_age_commitment_proof (coin_cmd, 667 ds->coin_index, 668 &age_commitment_proof)) || 669 (GNUNET_OK != 670 TALER_TESTING_get_trait_h_age_commitment (coin_cmd, 671 ds->coin_index, 672 &h_age_commitment)) ) 673 { 674 GNUNET_break (0); 675 TALER_TESTING_interpreter_fail (ds->is); 676 return GNUNET_NO; 677 } 678 679 GNUNET_CRYPTO_eddsa_key_get_public (&coin_spent_priv->eddsa_priv, 680 &coin_spent_pub.eddsa_pub); 681 682 { 683 struct TALER_TESTING_Trait traits[] = { 684 /* First two traits are only available if 685 ds->traits is true */ 686 TALER_TESTING_make_trait_exchange_pub (0, 687 &ds->exchange_pub), 688 TALER_TESTING_make_trait_exchange_sig (0, 689 &ds->exchange_sig), 690 /* These traits are always available */ 691 TALER_TESTING_make_trait_coin_history (0, 692 &ds->che), 693 TALER_TESTING_make_trait_coin_priv (0, 694 coin_spent_priv), 695 TALER_TESTING_make_trait_coin_pub (0, 696 &coin_spent_pub), 697 TALER_TESTING_make_trait_denom_pub (0, 698 ds->denom_pub), 699 TALER_TESTING_make_trait_coin_sig (0, 700 &ds->coin_sig), 701 TALER_TESTING_make_trait_age_commitment_proof (0, 702 age_commitment_proof), 703 TALER_TESTING_make_trait_h_age_commitment (0, 704 h_age_commitment), 705 TALER_TESTING_make_trait_wire_details (ds->wire_details), 706 TALER_TESTING_make_trait_contract_terms (ds->contract_terms), 707 TALER_TESTING_make_trait_merchant_priv (&ds->account_priv.merchant_priv), 708 TALER_TESTING_make_trait_merchant_pub (&ds->account_pub.merchant_pub), 709 TALER_TESTING_make_trait_account_priv (&ds->account_priv), 710 TALER_TESTING_make_trait_account_pub (&ds->account_pub), 711 TALER_TESTING_make_trait_deposit_amount (0, 712 &ds->amount), 713 TALER_TESTING_make_trait_deposit_fee_amount (0, 714 &ds->deposit_fee), 715 TALER_TESTING_make_trait_timestamp (0, 716 &ds->exchange_timestamp), 717 TALER_TESTING_make_trait_wire_deadline (0, 718 &ds->wire_deadline), 719 TALER_TESTING_make_trait_refund_deadline (0, 720 &ds->refund_deadline), 721 TALER_TESTING_trait_end () 722 }; 723 724 return TALER_TESTING_get_trait ((ds->deposit_succeeded) 725 ? traits 726 : &traits[2], 727 ret, 728 trait, 729 index); 730 } 731 } 732 733 734 struct TALER_TESTING_Command 735 TALER_TESTING_cmd_deposit ( 736 const char *label, 737 const char *coin_reference, 738 unsigned int coin_index, 739 struct TALER_FullPayto target_account_payto, 740 const char *contract_terms, 741 struct GNUNET_TIME_Relative refund_deadline, 742 const char *amount, 743 unsigned int expected_response_code) 744 { 745 struct DepositState *ds; 746 747 ds = GNUNET_new (struct DepositState); 748 ds->coin_reference = coin_reference; 749 ds->coin_index = coin_index; 750 ds->wire_details = TALER_TESTING_make_wire_details (target_account_payto); 751 GNUNET_assert (NULL != ds->wire_details); 752 ds->contract_terms = json_loads (contract_terms, 753 JSON_REJECT_DUPLICATES, 754 NULL); 755 if (NULL == ds->contract_terms) 756 { 757 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 758 "Failed to parse contract terms `%s' for CMD `%s'\n", 759 contract_terms, 760 label); 761 GNUNET_assert (0); 762 } 763 ds->wallet_timestamp = GNUNET_TIME_timestamp_get (); 764 GNUNET_assert (0 == 765 json_object_set_new (ds->contract_terms, 766 "timestamp", 767 GNUNET_JSON_from_timestamp ( 768 ds->wallet_timestamp))); 769 if (! GNUNET_TIME_relative_is_zero (refund_deadline)) 770 { 771 ds->refund_deadline = GNUNET_TIME_relative_to_timestamp (refund_deadline); 772 GNUNET_assert (0 == 773 json_object_set_new (ds->contract_terms, 774 "refund_deadline", 775 GNUNET_JSON_from_timestamp ( 776 ds->refund_deadline))); 777 } 778 GNUNET_assert (GNUNET_OK == 779 TALER_string_to_amount (amount, 780 &ds->amount)); 781 ds->expected_response_code = expected_response_code; 782 ds->command_initialized = true; 783 { 784 struct TALER_TESTING_Command cmd = { 785 .cls = ds, 786 .label = label, 787 .run = &deposit_run, 788 .cleanup = &deposit_cleanup, 789 .traits = &deposit_traits 790 }; 791 792 return cmd; 793 } 794 } 795 796 797 struct TALER_TESTING_Command 798 TALER_TESTING_cmd_deposit_with_ref ( 799 const char *label, 800 const char *coin_reference, 801 unsigned int coin_index, 802 struct TALER_FullPayto target_account_payto, 803 const char *contract_terms, 804 struct GNUNET_TIME_Relative refund_deadline, 805 const char *amount, 806 unsigned int expected_response_code, 807 const char *merchant_priv_reference) 808 { 809 struct DepositState *ds; 810 811 ds = GNUNET_new (struct DepositState); 812 ds->merchant_priv_reference = merchant_priv_reference; 813 ds->coin_reference = coin_reference; 814 ds->coin_index = coin_index; 815 ds->wire_details = TALER_TESTING_make_wire_details (target_account_payto); 816 GNUNET_assert (NULL != ds->wire_details); 817 ds->contract_terms = json_loads (contract_terms, 818 JSON_REJECT_DUPLICATES, 819 NULL); 820 if (NULL == ds->contract_terms) 821 { 822 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 823 "Failed to parse contract terms `%s' for CMD `%s'\n", 824 contract_terms, 825 label); 826 GNUNET_assert (0); 827 } 828 ds->wallet_timestamp = GNUNET_TIME_timestamp_get (); 829 GNUNET_assert (0 == 830 json_object_set_new (ds->contract_terms, 831 "timestamp", 832 GNUNET_JSON_from_timestamp ( 833 ds->wallet_timestamp))); 834 if (0 != refund_deadline.rel_value_us) 835 { 836 ds->refund_deadline = GNUNET_TIME_relative_to_timestamp (refund_deadline); 837 GNUNET_assert (0 == 838 json_object_set_new (ds->contract_terms, 839 "refund_deadline", 840 GNUNET_JSON_from_timestamp ( 841 ds->refund_deadline))); 842 } 843 GNUNET_assert (GNUNET_OK == 844 TALER_string_to_amount (amount, 845 &ds->amount)); 846 ds->expected_response_code = expected_response_code; 847 ds->command_initialized = true; 848 { 849 struct TALER_TESTING_Command cmd = { 850 .cls = ds, 851 .label = label, 852 .run = &deposit_run, 853 .cleanup = &deposit_cleanup, 854 .traits = &deposit_traits 855 }; 856 857 return cmd; 858 } 859 } 860 861 862 struct TALER_TESTING_Command 863 TALER_TESTING_cmd_deposit_replay ( 864 const char *label, 865 const char *deposit_reference, 866 unsigned int expected_response_code) 867 { 868 struct DepositState *ds; 869 870 ds = GNUNET_new (struct DepositState); 871 ds->deposit_reference = deposit_reference; 872 ds->expected_response_code = expected_response_code; 873 { 874 struct TALER_TESTING_Command cmd = { 875 .cls = ds, 876 .label = label, 877 .run = &deposit_run, 878 .cleanup = &deposit_cleanup, 879 .traits = &deposit_traits 880 }; 881 882 return cmd; 883 } 884 } 885 886 887 struct TALER_TESTING_Command 888 TALER_TESTING_cmd_deposit_with_retry (struct TALER_TESTING_Command cmd) 889 { 890 struct DepositState *ds; 891 892 GNUNET_assert (&deposit_run == cmd.run); 893 ds = cmd.cls; 894 ds->do_retry = NUM_RETRIES; 895 return cmd; 896 } 897 898 899 /* end of testing_api_cmd_deposit.c */