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