exchange_api_batch_deposit.c (24561B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2014-2024 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify it under the 6 terms of the GNU General Public License as published by the Free Software 7 Foundation; either version 3, or (at your option) any later version. 8 9 TALER is distributed in the hope that it will be useful, but WITHOUT ANY 10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 11 A PARTICULAR PURPOSE. See the GNU General Public License for more details. 12 13 You should have received a copy of the GNU General Public License along with 14 TALER; see the file COPYING. If not, see 15 <http://www.gnu.org/licenses/> 16 */ 17 /** 18 * @file lib/exchange_api_batch_deposit.c 19 * @brief Implementation of the /batch-deposit request of the exchange's HTTP API 20 * @author Sree Harsha Totakura <sreeharsha@totakura.in> 21 * @author Christian Grothoff 22 */ 23 #include "taler/platform.h" 24 #include <jansson.h> 25 #include <microhttpd.h> /* just for HTTP status codes */ 26 #include <gnunet/gnunet_util_lib.h> 27 #include <gnunet/gnunet_json_lib.h> 28 #include <gnunet/gnunet_curl_lib.h> 29 #include "taler/taler_json_lib.h" 30 #include "taler/taler_auditor_service.h" 31 #include "taler/taler_exchange_service.h" 32 #include "exchange_api_common.h" 33 #include "exchange_api_handle.h" 34 #include "taler/taler_signatures.h" 35 #include "exchange_api_curl_defaults.h" 36 37 38 /** 39 * 1:#AUDITOR_CHANCE is the probability that we report deposits 40 * to the auditor. 41 * 42 * 20==5% of going to auditor. This is possibly still too high, but set 43 * deliberately this high for testing 44 */ 45 #define AUDITOR_CHANCE 20 46 47 48 /** 49 * Entry in list of ongoing interactions with an auditor. 50 */ 51 struct TEAH_AuditorInteractionEntry 52 { 53 /** 54 * DLL entry. 55 */ 56 struct TEAH_AuditorInteractionEntry *next; 57 58 /** 59 * DLL entry. 60 */ 61 struct TEAH_AuditorInteractionEntry *prev; 62 63 /** 64 * URL of our auditor. For logging. 65 */ 66 const char *auditor_url; 67 68 /** 69 * Interaction state. 70 */ 71 struct TALER_AUDITOR_DepositConfirmationHandle *dch; 72 73 /** 74 * Batch deposit this is for. 75 */ 76 struct TALER_EXCHANGE_BatchDepositHandle *dh; 77 }; 78 79 80 /** 81 * @brief A Deposit Handle 82 */ 83 struct TALER_EXCHANGE_BatchDepositHandle 84 { 85 86 /** 87 * The keys of the exchange. 88 */ 89 struct TALER_EXCHANGE_Keys *keys; 90 91 /** 92 * Context for our curl request(s). 93 */ 94 struct GNUNET_CURL_Context *ctx; 95 96 /** 97 * The url for this request. 98 */ 99 char *url; 100 101 /** 102 * Context for #TEH_curl_easy_post(). Keeps the data that must 103 * persist for Curl to make the upload. 104 */ 105 struct TALER_CURL_PostContext post_ctx; 106 107 /** 108 * Handle for the request. 109 */ 110 struct GNUNET_CURL_Job *job; 111 112 /** 113 * Function to call with the result. 114 */ 115 TALER_EXCHANGE_BatchDepositResultCallback cb; 116 117 /** 118 * Closure for @a cb. 119 */ 120 void *cb_cls; 121 122 /** 123 * Details about the contract. 124 */ 125 struct TALER_EXCHANGE_DepositContractDetail dcd; 126 127 /** 128 * Array with details about the coins. 129 */ 130 struct TALER_EXCHANGE_CoinDepositDetail *cdds; 131 132 /** 133 * Hash of the merchant's wire details. 134 */ 135 struct TALER_MerchantWireHashP h_wire; 136 137 /** 138 * Hash over the extensions, or all zero. 139 */ 140 struct TALER_ExtensionPolicyHashP h_policy; 141 142 /** 143 * Time when this confirmation was generated / when the exchange received 144 * the deposit request. 145 */ 146 struct GNUNET_TIME_Timestamp exchange_timestamp; 147 148 /** 149 * Exchange signature, set for #auditor_cb. 150 */ 151 struct TALER_ExchangeSignatureP exchange_sig; 152 153 /** 154 * Head of DLL of interactions with this auditor. 155 */ 156 struct TEAH_AuditorInteractionEntry *ai_head; 157 158 /** 159 * Tail of DLL of interactions with this auditor. 160 */ 161 struct TEAH_AuditorInteractionEntry *ai_tail; 162 163 /** 164 * Result to return to the application once @e ai_head is empty. 165 */ 166 struct TALER_EXCHANGE_BatchDepositResult dr; 167 168 /** 169 * Exchange signing public key, set for #auditor_cb. 170 */ 171 struct TALER_ExchangePublicKeyP exchange_pub; 172 173 /** 174 * Total amount deposited without fees as calculated by us. 175 */ 176 struct TALER_Amount total_without_fee; 177 178 /** 179 * Response object to free at the end. 180 */ 181 json_t *response; 182 183 /** 184 * Chance that we will inform the auditor about the deposit 185 * is 1:n, where the value of this field is "n". 186 */ 187 unsigned int auditor_chance; 188 189 /** 190 * Length of the @e cdds array. 191 */ 192 unsigned int num_cdds; 193 194 }; 195 196 197 /** 198 * Finish batch deposit operation by calling the callback. 199 * 200 * @param[in] dh handle to finished batch deposit operation 201 */ 202 static void 203 finish_dh (struct TALER_EXCHANGE_BatchDepositHandle *dh) 204 { 205 dh->cb (dh->cb_cls, 206 &dh->dr); 207 TALER_EXCHANGE_batch_deposit_cancel (dh); 208 } 209 210 211 /** 212 * Function called with the result from our call to the 213 * auditor's /deposit-confirmation handler. 214 * 215 * @param cls closure of type `struct TEAH_AuditorInteractionEntry *` 216 * @param dcr response 217 */ 218 static void 219 acc_confirmation_cb ( 220 void *cls, 221 const struct TALER_AUDITOR_DepositConfirmationResponse *dcr) 222 { 223 struct TEAH_AuditorInteractionEntry *aie = cls; 224 struct TALER_EXCHANGE_BatchDepositHandle *dh = aie->dh; 225 226 if (MHD_HTTP_OK != dcr->hr.http_status) 227 { 228 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 229 "Failed to submit deposit confirmation to auditor `%s' with HTTP status %d (EC: %d). This is acceptable if it does not happen often.\n", 230 aie->auditor_url, 231 dcr->hr.http_status, 232 dcr->hr.ec); 233 } 234 GNUNET_CONTAINER_DLL_remove (dh->ai_head, 235 dh->ai_tail, 236 aie); 237 GNUNET_free (aie); 238 if (NULL == dh->ai_head) 239 finish_dh (dh); 240 } 241 242 243 /** 244 * Function called for each auditor to give us a chance to possibly 245 * launch a deposit confirmation interaction. 246 * 247 * @param cls closure 248 * @param auditor_url base URL of the auditor 249 * @param auditor_pub public key of the auditor 250 */ 251 static void 252 auditor_cb (void *cls, 253 const char *auditor_url, 254 const struct TALER_AuditorPublicKeyP *auditor_pub) 255 { 256 struct TALER_EXCHANGE_BatchDepositHandle *dh = cls; 257 const struct TALER_EXCHANGE_SigningPublicKey *spk; 258 struct TEAH_AuditorInteractionEntry *aie; 259 const struct TALER_CoinSpendSignatureP *csigs[GNUNET_NZL ( 260 dh->num_cdds)]; 261 const struct TALER_CoinSpendPublicKeyP *cpubs[GNUNET_NZL ( 262 dh->num_cdds)]; 263 264 for (unsigned int i = 0; i<dh->num_cdds; i++) 265 { 266 const struct TALER_EXCHANGE_CoinDepositDetail *cdd = &dh->cdds[i]; 267 268 csigs[i] = &cdd->coin_sig; 269 cpubs[i] = &cdd->coin_pub; 270 } 271 272 if (0 != 273 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 274 dh->auditor_chance)) 275 { 276 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 277 "Not providing deposit confirmation to auditor\n"); 278 return; 279 } 280 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 281 "Will provide deposit confirmation to auditor `%s'\n", 282 TALER_B2S (auditor_pub)); 283 spk = TALER_EXCHANGE_get_signing_key_info (dh->keys, 284 &dh->exchange_pub); 285 if (NULL == spk) 286 { 287 GNUNET_break_op (0); 288 return; 289 } 290 aie = GNUNET_new (struct TEAH_AuditorInteractionEntry); 291 aie->dh = dh; 292 aie->auditor_url = auditor_url; 293 aie->dch = TALER_AUDITOR_deposit_confirmation ( 294 dh->ctx, 295 auditor_url, 296 &dh->h_wire, 297 &dh->h_policy, 298 &dh->dcd.h_contract_terms, 299 dh->exchange_timestamp, 300 dh->dcd.wire_deadline, 301 dh->dcd.refund_deadline, 302 &dh->total_without_fee, 303 dh->num_cdds, 304 cpubs, 305 csigs, 306 &dh->dcd.merchant_pub, 307 &dh->exchange_pub, 308 &dh->exchange_sig, 309 &dh->keys->master_pub, 310 spk->valid_from, 311 spk->valid_until, 312 spk->valid_legal, 313 &spk->master_sig, 314 &acc_confirmation_cb, 315 aie); 316 GNUNET_CONTAINER_DLL_insert (dh->ai_head, 317 dh->ai_tail, 318 aie); 319 } 320 321 322 /** 323 * Function called when we're done processing the 324 * HTTP /deposit request. 325 * 326 * @param cls the `struct TALER_EXCHANGE_BatchDepositHandle` 327 * @param response_code HTTP response code, 0 on error 328 * @param response parsed JSON result, NULL on error 329 */ 330 static void 331 handle_deposit_finished (void *cls, 332 long response_code, 333 const void *response) 334 { 335 struct TALER_EXCHANGE_BatchDepositHandle *dh = cls; 336 const json_t *j = response; 337 struct TALER_EXCHANGE_BatchDepositResult *dr = &dh->dr; 338 339 dh->job = NULL; 340 dh->response = json_incref ((json_t*) j); 341 dr->hr.reply = dh->response; 342 dr->hr.http_status = (unsigned int) response_code; 343 switch (response_code) 344 { 345 case 0: 346 dr->hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 347 break; 348 case MHD_HTTP_OK: 349 { 350 struct GNUNET_JSON_Specification spec[] = { 351 GNUNET_JSON_spec_fixed_auto ("exchange_sig", 352 &dh->exchange_sig), 353 GNUNET_JSON_spec_fixed_auto ("exchange_pub", 354 &dh->exchange_pub), 355 GNUNET_JSON_spec_mark_optional ( 356 TALER_JSON_spec_web_url ("transaction_base_url", 357 &dr->details.ok.transaction_base_url), 358 NULL), 359 GNUNET_JSON_spec_timestamp ("exchange_timestamp", 360 &dh->exchange_timestamp), 361 GNUNET_JSON_spec_end () 362 }; 363 364 if (GNUNET_OK != 365 GNUNET_JSON_parse (j, 366 spec, 367 NULL, NULL)) 368 { 369 GNUNET_break_op (0); 370 dr->hr.http_status = 0; 371 dr->hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; 372 break; 373 } 374 if (GNUNET_OK != 375 TALER_EXCHANGE_test_signing_key (dh->keys, 376 &dh->exchange_pub)) 377 { 378 GNUNET_break_op (0); 379 dr->hr.http_status = 0; 380 dr->hr.ec = TALER_EC_EXCHANGE_DEPOSIT_INVALID_SIGNATURE_BY_EXCHANGE; 381 break; 382 } 383 { 384 const struct TALER_CoinSpendSignatureP *csigs[ 385 GNUNET_NZL (dh->num_cdds)]; 386 387 for (unsigned int i = 0; i<dh->num_cdds; i++) 388 csigs[i] = &dh->cdds[i].coin_sig; 389 if (GNUNET_OK != 390 TALER_exchange_online_deposit_confirmation_verify ( 391 &dh->dcd.h_contract_terms, 392 &dh->h_wire, 393 &dh->h_policy, 394 dh->exchange_timestamp, 395 dh->dcd.wire_deadline, 396 dh->dcd.refund_deadline, 397 &dh->total_without_fee, 398 dh->num_cdds, 399 csigs, 400 &dh->dcd.merchant_pub, 401 &dh->exchange_pub, 402 &dh->exchange_sig)) 403 { 404 GNUNET_break_op (0); 405 dr->hr.http_status = 0; 406 dr->hr.ec = TALER_EC_EXCHANGE_DEPOSIT_INVALID_SIGNATURE_BY_EXCHANGE; 407 break; 408 } 409 } 410 TEAH_get_auditors_for_dc (dh->keys, 411 &auditor_cb, 412 dh); 413 } 414 dr->details.ok.exchange_sig = &dh->exchange_sig; 415 dr->details.ok.exchange_pub = &dh->exchange_pub; 416 dr->details.ok.deposit_timestamp = dh->exchange_timestamp; 417 break; 418 case MHD_HTTP_BAD_REQUEST: 419 /* This should never happen, either us or the exchange is buggy 420 (or API version conflict); just pass JSON reply to the application */ 421 dr->hr.ec = TALER_JSON_get_error_code (j); 422 dr->hr.hint = TALER_JSON_get_error_hint (j); 423 break; 424 case MHD_HTTP_FORBIDDEN: 425 dr->hr.ec = TALER_JSON_get_error_code (j); 426 dr->hr.hint = TALER_JSON_get_error_hint (j); 427 /* Nothing really to verify, exchange says one of the signatures is 428 invalid; as we checked them, this should never happen, we 429 should pass the JSON reply to the application */ 430 break; 431 case MHD_HTTP_NOT_FOUND: 432 dr->hr.ec = TALER_JSON_get_error_code (j); 433 dr->hr.hint = TALER_JSON_get_error_hint (j); 434 /* Nothing really to verify, this should never 435 happen, we should pass the JSON reply to the application */ 436 break; 437 case MHD_HTTP_CONFLICT: 438 { 439 dr->hr.ec = TALER_JSON_get_error_code (j); 440 dr->hr.hint = TALER_JSON_get_error_hint (j); 441 switch (dr->hr.ec) 442 { 443 case TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS: 444 { 445 struct GNUNET_JSON_Specification spec[] = { 446 GNUNET_JSON_spec_fixed_auto ( 447 "coin_pub", 448 &dr->details.conflict.details 449 .insufficient_funds.coin_pub), 450 GNUNET_JSON_spec_end () 451 }; 452 453 if (GNUNET_OK != 454 GNUNET_JSON_parse (j, 455 spec, 456 NULL, NULL)) 457 { 458 GNUNET_break_op (0); 459 dr->hr.http_status = 0; 460 dr->hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; 461 break; 462 } 463 } 464 break; 465 case TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_AGE_HASH: 466 { 467 struct GNUNET_JSON_Specification spec[] = { 468 GNUNET_JSON_spec_fixed_auto ( 469 "coin_pub", 470 &dr->details.conflict.details 471 .coin_conflicting_age_hash.coin_pub), 472 GNUNET_JSON_spec_end () 473 }; 474 475 if (GNUNET_OK != 476 GNUNET_JSON_parse (j, 477 spec, 478 NULL, NULL)) 479 { 480 GNUNET_break_op (0); 481 dr->hr.http_status = 0; 482 dr->hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; 483 break; 484 } 485 } 486 break; 487 case TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY: 488 { 489 struct GNUNET_JSON_Specification spec[] = { 490 GNUNET_JSON_spec_fixed_auto ( 491 "coin_pub", 492 &dr->details.conflict.details 493 .coin_conflicting_denomination_key.coin_pub), 494 GNUNET_JSON_spec_end () 495 }; 496 497 if (GNUNET_OK != 498 GNUNET_JSON_parse (j, 499 spec, 500 NULL, NULL)) 501 { 502 GNUNET_break_op (0); 503 dr->hr.http_status = 0; 504 dr->hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; 505 break; 506 } 507 } 508 break; 509 case TALER_EC_EXCHANGE_DEPOSIT_CONFLICTING_CONTRACT: 510 break; 511 default: 512 GNUNET_break_op (0); 513 break; 514 } 515 } 516 break; 517 case MHD_HTTP_GONE: 518 /* could happen if denomination was revoked */ 519 /* Note: one might want to check /keys for revocation 520 signature here, alas tricky in case our /keys 521 is outdated => left to clients */ 522 dr->hr.ec = TALER_JSON_get_error_code (j); 523 dr->hr.hint = TALER_JSON_get_error_hint (j); 524 break; 525 case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS: 526 { 527 struct GNUNET_JSON_Specification spec[] = { 528 GNUNET_JSON_spec_fixed_auto ( 529 "h_payto", 530 &dr->details.unavailable_for_legal_reasons.h_payto), 531 GNUNET_JSON_spec_uint64 ( 532 "requirement_row", 533 &dr->details.unavailable_for_legal_reasons.requirement_row), 534 GNUNET_JSON_spec_bool ( 535 "bad_kyc_auth", 536 &dr->details.unavailable_for_legal_reasons.bad_kyc_auth), 537 GNUNET_JSON_spec_end () 538 }; 539 540 if (GNUNET_OK != 541 GNUNET_JSON_parse (j, 542 spec, 543 NULL, NULL)) 544 { 545 GNUNET_break_op (0); 546 dr->hr.http_status = 0; 547 dr->hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; 548 break; 549 } 550 } 551 break; 552 case MHD_HTTP_INTERNAL_SERVER_ERROR: 553 dr->hr.ec = TALER_JSON_get_error_code (j); 554 dr->hr.hint = TALER_JSON_get_error_hint (j); 555 /* Server had an internal issue; we should retry, but this API 556 leaves this to the application */ 557 break; 558 default: 559 /* unexpected response code */ 560 dr->hr.ec = TALER_JSON_get_error_code (j); 561 dr->hr.hint = TALER_JSON_get_error_hint (j); 562 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 563 "Unexpected response code %u/%d for exchange deposit\n", 564 (unsigned int) response_code, 565 dr->hr.ec); 566 GNUNET_break_op (0); 567 break; 568 } 569 if (NULL != dh->ai_head) 570 return; 571 finish_dh (dh); 572 } 573 574 575 struct TALER_EXCHANGE_BatchDepositHandle * 576 TALER_EXCHANGE_batch_deposit ( 577 struct GNUNET_CURL_Context *ctx, 578 const char *url, 579 struct TALER_EXCHANGE_Keys *keys, 580 const struct TALER_EXCHANGE_DepositContractDetail *dcd, 581 unsigned int num_cdds, 582 const struct TALER_EXCHANGE_CoinDepositDetail cdds[static num_cdds], 583 TALER_EXCHANGE_BatchDepositResultCallback cb, 584 void *cb_cls, 585 enum TALER_ErrorCode *ec) 586 { 587 struct TALER_EXCHANGE_BatchDepositHandle *dh; 588 json_t *deposit_obj; 589 json_t *deposits; 590 CURL *eh; 591 const struct GNUNET_HashCode *wallet_data_hashp; 592 593 if (0 == num_cdds) 594 { 595 GNUNET_break (0); 596 return NULL; 597 } 598 if (GNUNET_TIME_timestamp_cmp (dcd->refund_deadline, 599 >, 600 dcd->wire_deadline)) 601 { 602 GNUNET_break_op (0); 603 *ec = TALER_EC_EXCHANGE_DEPOSIT_REFUND_DEADLINE_AFTER_WIRE_DEADLINE; 604 return NULL; 605 } 606 dh = GNUNET_new (struct TALER_EXCHANGE_BatchDepositHandle); 607 dh->auditor_chance = AUDITOR_CHANCE; 608 dh->cb = cb; 609 dh->cb_cls = cb_cls; 610 dh->cdds = GNUNET_memdup (cdds, 611 num_cdds * sizeof (*cdds)); 612 dh->num_cdds = num_cdds; 613 dh->dcd = *dcd; 614 if (NULL != dcd->policy_details) 615 TALER_deposit_policy_hash (dcd->policy_details, 616 &dh->h_policy); 617 TALER_merchant_wire_signature_hash (dcd->merchant_payto_uri, 618 &dcd->wire_salt, 619 &dh->h_wire); 620 deposits = json_array (); 621 GNUNET_assert (NULL != deposits); 622 GNUNET_assert (GNUNET_OK == 623 TALER_amount_set_zero (cdds[0].amount.currency, 624 &dh->total_without_fee)); 625 for (unsigned int i = 0; i<num_cdds; i++) 626 { 627 const struct TALER_EXCHANGE_CoinDepositDetail *cdd = &cdds[i]; 628 const struct TALER_EXCHANGE_DenomPublicKey *dki; 629 const struct TALER_AgeCommitmentHashP *h_age_commitmentp; 630 struct TALER_Amount amount_without_fee; 631 632 dki = TALER_EXCHANGE_get_denomination_key_by_hash (keys, 633 &cdd->h_denom_pub); 634 if (NULL == dki) 635 { 636 *ec = TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN; 637 GNUNET_break_op (0); 638 json_decref (deposits); 639 return NULL; 640 } 641 if (0 > 642 TALER_amount_subtract (&amount_without_fee, 643 &cdd->amount, 644 &dki->fees.deposit)) 645 { 646 *ec = TALER_EC_EXCHANGE_DEPOSIT_FEE_ABOVE_AMOUNT; 647 GNUNET_break_op (0); 648 GNUNET_free (dh->cdds); 649 GNUNET_free (dh); 650 json_decref (deposits); 651 return NULL; 652 } 653 GNUNET_assert (0 <= 654 TALER_amount_add (&dh->total_without_fee, 655 &dh->total_without_fee, 656 &amount_without_fee)); 657 if (GNUNET_OK != 658 TALER_EXCHANGE_verify_deposit_signature_ (dcd, 659 &dh->h_policy, 660 &dh->h_wire, 661 cdd, 662 dki)) 663 { 664 *ec = TALER_EC_EXCHANGE_DEPOSIT_COIN_SIGNATURE_INVALID; 665 GNUNET_break_op (0); 666 GNUNET_free (dh->cdds); 667 GNUNET_free (dh); 668 json_decref (deposits); 669 return NULL; 670 } 671 if (! GNUNET_is_zero (&dcd->merchant_sig)) 672 { 673 /* FIXME #9185: check merchant_sig!? */ 674 } 675 if (GNUNET_is_zero (&cdd->h_age_commitment)) 676 h_age_commitmentp = NULL; 677 else 678 h_age_commitmentp = &cdd->h_age_commitment; 679 GNUNET_assert ( 680 0 == 681 json_array_append_new ( 682 deposits, 683 GNUNET_JSON_PACK ( 684 TALER_JSON_pack_amount ("contribution", 685 &cdd->amount), 686 GNUNET_JSON_pack_data_auto ("denom_pub_hash", 687 &cdd->h_denom_pub), 688 TALER_JSON_pack_denom_sig ("ub_sig", 689 &cdd->denom_sig), 690 GNUNET_JSON_pack_data_auto ("coin_pub", 691 &cdd->coin_pub), 692 GNUNET_JSON_pack_allow_null ( 693 GNUNET_JSON_pack_data_auto ("h_age_commitment", 694 h_age_commitmentp)), 695 GNUNET_JSON_pack_data_auto ("coin_sig", 696 &cdd->coin_sig) 697 ))); 698 } 699 dh->url = TALER_url_join (url, 700 "batch-deposit", 701 NULL); 702 if (NULL == dh->url) 703 { 704 GNUNET_break (0); 705 *ec = TALER_EC_GENERIC_ALLOCATION_FAILURE; 706 GNUNET_free (dh->url); 707 GNUNET_free (dh->cdds); 708 GNUNET_free (dh); 709 json_decref (deposits); 710 return NULL; 711 } 712 713 if (GNUNET_is_zero (&dcd->wallet_data_hash)) 714 wallet_data_hashp = NULL; 715 else 716 wallet_data_hashp = &dcd->wallet_data_hash; 717 718 deposit_obj = GNUNET_JSON_PACK ( 719 TALER_JSON_pack_full_payto ("merchant_payto_uri", 720 dcd->merchant_payto_uri), 721 GNUNET_JSON_pack_data_auto ("wire_salt", 722 &dcd->wire_salt), 723 GNUNET_JSON_pack_data_auto ("h_contract_terms", 724 &dcd->h_contract_terms), 725 GNUNET_JSON_pack_array_steal ("coins", 726 deposits), 727 GNUNET_JSON_pack_allow_null ( 728 GNUNET_JSON_pack_data_auto ("wallet_data_hash", 729 wallet_data_hashp)), 730 GNUNET_JSON_pack_allow_null ( 731 GNUNET_JSON_pack_object_steal ("policy_details", 732 (json_t *) dcd->policy_details)), 733 GNUNET_JSON_pack_timestamp ("timestamp", 734 dcd->wallet_timestamp), 735 GNUNET_JSON_pack_data_auto ("merchant_pub", 736 &dcd->merchant_pub), 737 GNUNET_JSON_pack_data_auto ("merchant_sig", 738 &dcd->merchant_sig), 739 GNUNET_JSON_pack_allow_null ( 740 GNUNET_JSON_pack_timestamp ("refund_deadline", 741 dcd->refund_deadline)), 742 GNUNET_JSON_pack_timestamp ("wire_transfer_deadline", 743 dcd->wire_deadline)); 744 GNUNET_assert (NULL != deposit_obj); 745 eh = TALER_EXCHANGE_curl_easy_get_ (dh->url); 746 if ( (NULL == eh) || 747 (GNUNET_OK != 748 TALER_curl_easy_post (&dh->post_ctx, 749 eh, 750 deposit_obj)) ) 751 { 752 *ec = TALER_EC_GENERIC_CURL_ALLOCATION_FAILURE; 753 GNUNET_break (0); 754 if (NULL != eh) 755 curl_easy_cleanup (eh); 756 json_decref (deposit_obj); 757 GNUNET_free (dh->cdds); 758 GNUNET_free (dh->url); 759 GNUNET_free (dh); 760 return NULL; 761 } 762 json_decref (deposit_obj); 763 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 764 "URL for deposit: `%s'\n", 765 dh->url); 766 dh->ctx = ctx; 767 dh->keys = TALER_EXCHANGE_keys_incref (keys); 768 dh->job = GNUNET_CURL_job_add2 (ctx, 769 eh, 770 dh->post_ctx.headers, 771 &handle_deposit_finished, 772 dh); 773 return dh; 774 } 775 776 777 void 778 TALER_EXCHANGE_batch_deposit_force_dc ( 779 struct TALER_EXCHANGE_BatchDepositHandle *deposit) 780 { 781 deposit->auditor_chance = 1; 782 } 783 784 785 void 786 TALER_EXCHANGE_batch_deposit_cancel ( 787 struct TALER_EXCHANGE_BatchDepositHandle *deposit) 788 { 789 struct TEAH_AuditorInteractionEntry *aie; 790 791 while (NULL != (aie = deposit->ai_head)) 792 { 793 GNUNET_assert (aie->dh == deposit); 794 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 795 "Not sending deposit confirmation to auditor `%s' due to cancellation\n", 796 aie->auditor_url); 797 TALER_AUDITOR_deposit_confirmation_cancel (aie->dch); 798 GNUNET_CONTAINER_DLL_remove (deposit->ai_head, 799 deposit->ai_tail, 800 aie); 801 GNUNET_free (aie); 802 } 803 if (NULL != deposit->job) 804 { 805 GNUNET_CURL_job_cancel (deposit->job); 806 deposit->job = NULL; 807 } 808 TALER_EXCHANGE_keys_decref (deposit->keys); 809 GNUNET_free (deposit->url); 810 GNUNET_free (deposit->cdds); 811 TALER_curl_easy_post_finished (&deposit->post_ctx); 812 json_decref (deposit->response); 813 GNUNET_free (deposit); 814 } 815 816 817 /* end of exchange_api_batch_deposit.c */