Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2014-2022 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 "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_json_lib.h"
30 : #include "taler_auditor_service.h"
31 : #include "taler_exchange_service.h"
32 : #include "exchange_api_common.h"
33 : #include "exchange_api_handle.h"
34 : #include "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 : * @brief A Deposit Handle
49 : */
50 : struct TALER_EXCHANGE_BatchDepositHandle
51 : {
52 :
53 : /**
54 : * The connection to exchange this request handle will use
55 : */
56 : struct TALER_EXCHANGE_Handle *exchange;
57 :
58 : /**
59 : * The url for this request.
60 : */
61 : char *url;
62 :
63 : /**
64 : * Context for #TEH_curl_easy_post(). Keeps the data that must
65 : * persist for Curl to make the upload.
66 : */
67 : struct TALER_CURL_PostContext ctx;
68 :
69 : /**
70 : * Handle for the request.
71 : */
72 : struct GNUNET_CURL_Job *job;
73 :
74 : /**
75 : * Function to call with the result.
76 : */
77 : TALER_EXCHANGE_BatchDepositResultCallback cb;
78 :
79 : /**
80 : * Closure for @a cb.
81 : */
82 : void *cb_cls;
83 :
84 : /**
85 : * Details about the contract.
86 : */
87 : struct TALER_EXCHANGE_DepositContractDetail dcd;
88 :
89 : /**
90 : * Array with details about the coins.
91 : */
92 : struct TALER_EXCHANGE_CoinDepositDetail *cdds;
93 :
94 : /**
95 : * Hash of the merchant's wire details.
96 : */
97 : struct TALER_MerchantWireHashP h_wire;
98 :
99 : /**
100 : * Hash over the extensions, or all zero.
101 : */
102 : struct TALER_ExtensionContractHashP h_extensions;
103 :
104 : /**
105 : * Time when this confirmation was generated / when the exchange received
106 : * the deposit request.
107 : */
108 : struct GNUNET_TIME_Timestamp exchange_timestamp;
109 :
110 : /**
111 : * Exchange signatures, set for #auditor_cb.
112 : */
113 : struct TALER_ExchangeSignatureP *exchange_sigs;
114 :
115 : /**
116 : * Exchange signing public key, set for #auditor_cb.
117 : */
118 : struct TALER_ExchangePublicKeyP exchange_pub;
119 :
120 : /**
121 : * Chance that we will inform the auditor about the deposit
122 : * is 1:n, where the value of this field is "n".
123 : */
124 : unsigned int auditor_chance;
125 :
126 : /**
127 : * Length of the @e cdds array.
128 : */
129 : unsigned int num_cdds;
130 :
131 : };
132 :
133 :
134 : /**
135 : * Function called for each auditor to give us a chance to possibly
136 : * launch a deposit confirmation interaction.
137 : *
138 : * @param cls closure
139 : * @param ah handle to the auditor
140 : * @param auditor_pub public key of the auditor
141 : * @return NULL if no deposit confirmation interaction was launched
142 : */
143 : static struct TEAH_AuditorInteractionEntry *
144 0 : auditor_cb (void *cls,
145 : struct TALER_AUDITOR_Handle *ah,
146 : const struct TALER_AuditorPublicKeyP *auditor_pub)
147 : {
148 0 : struct TALER_EXCHANGE_BatchDepositHandle *dh = cls;
149 : const struct TALER_EXCHANGE_Keys *key_state;
150 : const struct TALER_EXCHANGE_SigningPublicKey *spk;
151 : struct TEAH_AuditorInteractionEntry *aie;
152 : struct TALER_Amount amount_without_fee;
153 : const struct TALER_EXCHANGE_DenomPublicKey *dki;
154 : unsigned int coin;
155 :
156 0 : if (0 !=
157 0 : GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
158 : dh->auditor_chance))
159 : {
160 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
161 : "Not providing deposit confirmation to auditor\n");
162 0 : return NULL;
163 : }
164 0 : coin = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
165 : dh->num_cdds);
166 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
167 : "Will provide deposit confirmation to auditor `%s'\n",
168 : TALER_B2S (auditor_pub));
169 0 : key_state = TALER_EXCHANGE_get_keys (dh->exchange);
170 0 : dki = TALER_EXCHANGE_get_denomination_key_by_hash (key_state,
171 0 : &dh->cdds[coin].h_denom_pub);
172 0 : GNUNET_assert (NULL != dki);
173 0 : spk = TALER_EXCHANGE_get_signing_key_info (key_state,
174 0 : &dh->exchange_pub);
175 0 : if (NULL == spk)
176 : {
177 0 : GNUNET_break_op (0);
178 0 : return NULL;
179 : }
180 0 : GNUNET_assert (0 <=
181 : TALER_amount_subtract (&amount_without_fee,
182 : &dh->cdds[coin].amount,
183 : &dki->fees.deposit));
184 0 : aie = GNUNET_new (struct TEAH_AuditorInteractionEntry);
185 0 : aie->dch = TALER_AUDITOR_deposit_confirmation (
186 : ah,
187 0 : &dh->h_wire,
188 0 : &dh->h_extensions,
189 0 : &dh->dcd.h_contract_terms,
190 : dh->exchange_timestamp,
191 : dh->dcd.wire_deadline,
192 : dh->dcd.refund_deadline,
193 : &amount_without_fee,
194 0 : &dh->cdds[coin].coin_pub,
195 0 : &dh->dcd.merchant_pub,
196 0 : &dh->exchange_pub,
197 0 : &dh->exchange_sigs[coin],
198 : &key_state->master_pub,
199 : spk->valid_from,
200 : spk->valid_until,
201 : spk->valid_legal,
202 : &spk->master_sig,
203 : &TEAH_acc_confirmation_cb,
204 : aie);
205 0 : return aie;
206 : }
207 :
208 :
209 : /**
210 : * Function called when we're done processing the
211 : * HTTP /deposit request.
212 : *
213 : * @param cls the `struct TALER_EXCHANGE_BatchDepositHandle`
214 : * @param response_code HTTP response code, 0 on error
215 : * @param response parsed JSON result, NULL on error
216 : */
217 : static void
218 0 : handle_deposit_finished (void *cls,
219 : long response_code,
220 : const void *response)
221 : {
222 0 : struct TALER_EXCHANGE_BatchDepositHandle *dh = cls;
223 0 : const json_t *j = response;
224 0 : struct TALER_EXCHANGE_BatchDepositResult dr = {
225 : .hr.reply = j,
226 0 : .hr.http_status = (unsigned int) response_code
227 : };
228 : const struct TALER_EXCHANGE_Keys *keys;
229 :
230 0 : dh->job = NULL;
231 0 : keys = TALER_EXCHANGE_get_keys (dh->exchange);
232 0 : switch (response_code)
233 : {
234 0 : case 0:
235 0 : dr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
236 0 : break;
237 0 : case MHD_HTTP_OK:
238 : {
239 : const struct TALER_EXCHANGE_Keys *key_state;
240 : json_t *sigs;
241 : json_t *sig;
242 : unsigned int idx;
243 : struct GNUNET_JSON_Specification spec[] = {
244 0 : GNUNET_JSON_spec_json ("exchange_sigs",
245 : &sigs),
246 0 : GNUNET_JSON_spec_fixed_auto ("exchange_pub",
247 : &dh->exchange_pub),
248 0 : GNUNET_JSON_spec_mark_optional (
249 : GNUNET_JSON_spec_string ("transaction_base_url",
250 : &dr.details.success.transaction_base_url),
251 : NULL),
252 0 : GNUNET_JSON_spec_timestamp ("exchange_timestamp",
253 : &dh->exchange_timestamp),
254 0 : GNUNET_JSON_spec_end ()
255 : };
256 :
257 0 : if (GNUNET_OK !=
258 0 : GNUNET_JSON_parse (j,
259 : spec,
260 : NULL, NULL))
261 : {
262 0 : GNUNET_break_op (0);
263 0 : dr.hr.http_status = 0;
264 0 : dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
265 0 : break;
266 : }
267 0 : if (json_array_size (sigs) != dh->num_cdds)
268 : {
269 0 : GNUNET_break_op (0);
270 0 : dr.hr.http_status = 0;
271 0 : dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
272 0 : break;
273 : }
274 0 : dh->exchange_sigs = GNUNET_new_array (dh->num_cdds,
275 : struct TALER_ExchangeSignatureP);
276 0 : key_state = TALER_EXCHANGE_get_keys (dh->exchange);
277 0 : if (GNUNET_OK !=
278 0 : TALER_EXCHANGE_test_signing_key (key_state,
279 0 : &dh->exchange_pub))
280 : {
281 0 : GNUNET_break_op (0);
282 0 : dr.hr.http_status = 0;
283 0 : dr.hr.ec = TALER_EC_EXCHANGE_DEPOSIT_INVALID_SIGNATURE_BY_EXCHANGE;
284 0 : break;
285 : }
286 0 : json_array_foreach (sigs, idx, sig)
287 : {
288 : struct GNUNET_JSON_Specification ispec[] = {
289 0 : GNUNET_JSON_spec_fixed_auto ("exchange_sig",
290 : &dh->exchange_sigs[idx]),
291 0 : GNUNET_JSON_spec_end ()
292 : };
293 : struct TALER_Amount amount_without_fee;
294 : const struct TALER_EXCHANGE_DenomPublicKey *dki;
295 :
296 0 : if (GNUNET_OK !=
297 0 : GNUNET_JSON_parse (sig,
298 : ispec,
299 : NULL, NULL))
300 : {
301 0 : GNUNET_break_op (0);
302 0 : dr.hr.http_status = 0;
303 0 : dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
304 0 : GNUNET_JSON_parse_free (spec);
305 0 : break;
306 : }
307 0 : dki = TALER_EXCHANGE_get_denomination_key_by_hash (key_state,
308 0 : &dh->cdds[idx].
309 : h_denom_pub);
310 0 : GNUNET_assert (NULL != dki);
311 0 : GNUNET_assert (0 <=
312 : TALER_amount_subtract (&amount_without_fee,
313 : &dh->cdds[idx].amount,
314 : &dki->fees.deposit));
315 :
316 0 : if (GNUNET_OK !=
317 0 : TALER_exchange_online_deposit_confirmation_verify (
318 0 : &dh->dcd.h_contract_terms,
319 0 : &dh->h_wire,
320 0 : &dh->h_extensions,
321 : dh->exchange_timestamp,
322 : dh->dcd.wire_deadline,
323 : dh->dcd.refund_deadline,
324 : &amount_without_fee,
325 0 : &dh->cdds[idx].coin_pub,
326 0 : &dh->dcd.merchant_pub,
327 0 : &dh->exchange_pub,
328 0 : &dh->exchange_sigs[idx]))
329 : {
330 0 : GNUNET_break_op (0);
331 0 : dr.hr.http_status = 0;
332 0 : dr.hr.ec = TALER_EC_EXCHANGE_DEPOSIT_INVALID_SIGNATURE_BY_EXCHANGE;
333 0 : break;
334 : }
335 : }
336 0 : TEAH_get_auditors_for_dc (dh->exchange,
337 : &auditor_cb,
338 : dh);
339 : }
340 0 : dr.details.success.exchange_sigs = dh->exchange_sigs;
341 0 : dr.details.success.exchange_pub = &dh->exchange_pub;
342 0 : dr.details.success.deposit_timestamp = dh->exchange_timestamp;
343 0 : dr.details.success.num_signatures = dh->num_cdds;
344 0 : break;
345 0 : case MHD_HTTP_BAD_REQUEST:
346 : /* This should never happen, either us or the exchange is buggy
347 : (or API version conflict); just pass JSON reply to the application */
348 0 : dr.hr.ec = TALER_JSON_get_error_code (j);
349 0 : dr.hr.hint = TALER_JSON_get_error_hint (j);
350 0 : break;
351 0 : case MHD_HTTP_FORBIDDEN:
352 0 : dr.hr.ec = TALER_JSON_get_error_code (j);
353 0 : dr.hr.hint = TALER_JSON_get_error_hint (j);
354 : /* Nothing really to verify, exchange says one of the signatures is
355 : invalid; as we checked them, this should never happen, we
356 : should pass the JSON reply to the application */
357 0 : break;
358 0 : case MHD_HTTP_NOT_FOUND:
359 0 : dr.hr.ec = TALER_JSON_get_error_code (j);
360 0 : dr.hr.hint = TALER_JSON_get_error_hint (j);
361 : /* Nothing really to verify, this should never
362 : happen, we should pass the JSON reply to the application */
363 0 : break;
364 0 : case MHD_HTTP_CONFLICT:
365 : {
366 : const struct TALER_EXCHANGE_Keys *key_state;
367 : struct TALER_CoinSpendPublicKeyP coin_pub;
368 : struct GNUNET_JSON_Specification spec[] = {
369 0 : GNUNET_JSON_spec_fixed_auto ("coin_pub",
370 : &coin_pub),
371 0 : GNUNET_JSON_spec_end ()
372 : };
373 : const struct TALER_EXCHANGE_DenomPublicKey *dki;
374 0 : bool found = false;
375 :
376 0 : if (GNUNET_OK !=
377 0 : GNUNET_JSON_parse (j,
378 : spec,
379 : NULL, NULL))
380 : {
381 0 : GNUNET_break_op (0);
382 0 : dr.hr.http_status = 0;
383 0 : dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
384 0 : break;
385 : }
386 0 : for (unsigned int i = 0; i<dh->num_cdds; i++)
387 : {
388 0 : if (0 !=
389 0 : GNUNET_memcmp (&coin_pub,
390 : &dh->cdds[i].coin_pub))
391 0 : continue;
392 0 : key_state = TALER_EXCHANGE_get_keys (dh->exchange);
393 0 : dki = TALER_EXCHANGE_get_denomination_key_by_hash (key_state,
394 0 : &dh->cdds[i].
395 : h_denom_pub);
396 0 : GNUNET_assert (NULL != dki);
397 0 : if (GNUNET_OK !=
398 0 : TALER_EXCHANGE_check_coin_conflict_ (
399 : keys,
400 : j,
401 : dki,
402 0 : &dh->cdds[i].coin_pub,
403 0 : &dh->cdds[i].coin_sig,
404 0 : &dh->cdds[i].amount))
405 : {
406 0 : GNUNET_break_op (0);
407 0 : dr.hr.http_status = 0;
408 0 : dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
409 0 : break;
410 : }
411 0 : found = true;
412 0 : break;
413 : }
414 0 : if (! found)
415 : {
416 0 : GNUNET_break_op (0);
417 0 : dr.hr.http_status = 0;
418 0 : dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
419 0 : break;
420 : }
421 0 : dr.hr.ec = TALER_JSON_get_error_code (j);
422 0 : dr.hr.hint = TALER_JSON_get_error_hint (j);
423 : }
424 0 : break;
425 0 : case MHD_HTTP_GONE:
426 : /* could happen if denomination was revoked */
427 : /* Note: one might want to check /keys for revocation
428 : signature here, alas tricky in case our /keys
429 : is outdated => left to clients */
430 0 : dr.hr.ec = TALER_JSON_get_error_code (j);
431 0 : dr.hr.hint = TALER_JSON_get_error_hint (j);
432 0 : break;
433 0 : case MHD_HTTP_INTERNAL_SERVER_ERROR:
434 0 : dr.hr.ec = TALER_JSON_get_error_code (j);
435 0 : dr.hr.hint = TALER_JSON_get_error_hint (j);
436 : /* Server had an internal issue; we should retry, but this API
437 : leaves this to the application */
438 0 : break;
439 0 : default:
440 : /* unexpected response code */
441 0 : dr.hr.ec = TALER_JSON_get_error_code (j);
442 0 : dr.hr.hint = TALER_JSON_get_error_hint (j);
443 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
444 : "Unexpected response code %u/%d for exchange deposit\n",
445 : (unsigned int) response_code,
446 : dr.hr.ec);
447 0 : GNUNET_break_op (0);
448 0 : break;
449 : }
450 0 : dh->cb (dh->cb_cls,
451 : &dr);
452 0 : TALER_EXCHANGE_batch_deposit_cancel (dh);
453 0 : }
454 :
455 :
456 : struct TALER_EXCHANGE_BatchDepositHandle *
457 0 : TALER_EXCHANGE_batch_deposit (
458 : struct TALER_EXCHANGE_Handle *exchange,
459 : const struct TALER_EXCHANGE_DepositContractDetail *dcd,
460 : unsigned int num_cdds,
461 : const struct TALER_EXCHANGE_CoinDepositDetail *cdds,
462 : TALER_EXCHANGE_BatchDepositResultCallback cb,
463 : void *cb_cls,
464 : enum TALER_ErrorCode *ec)
465 : {
466 : const struct TALER_EXCHANGE_Keys *key_state;
467 : struct TALER_EXCHANGE_BatchDepositHandle *dh;
468 : struct GNUNET_CURL_Context *ctx;
469 : json_t *deposit_obj;
470 : json_t *deposits;
471 : CURL *eh;
472 : struct TALER_Amount amount_without_fee;
473 :
474 0 : GNUNET_assert (GNUNET_YES ==
475 : TEAH_handle_is_ready (exchange));
476 0 : if (GNUNET_TIME_timestamp_cmp (dcd->refund_deadline,
477 : >,
478 : dcd->wire_deadline))
479 : {
480 0 : GNUNET_break_op (0);
481 0 : *ec = TALER_EC_EXCHANGE_DEPOSIT_REFUND_DEADLINE_AFTER_WIRE_DEADLINE;
482 0 : return NULL;
483 : }
484 0 : key_state = TALER_EXCHANGE_get_keys (exchange);
485 0 : dh = GNUNET_new (struct TALER_EXCHANGE_BatchDepositHandle);
486 0 : dh->auditor_chance = AUDITOR_CHANCE;
487 0 : dh->exchange = exchange;
488 0 : dh->cb = cb;
489 0 : dh->cb_cls = cb_cls;
490 0 : dh->cdds = GNUNET_memdup (cdds,
491 : num_cdds
492 : * sizeof (*cdds));
493 0 : dh->num_cdds = num_cdds;
494 0 : dh->dcd = *dcd;
495 0 : if (NULL != dcd->extension_details)
496 0 : TALER_deposit_extension_hash (dcd->extension_details,
497 : &dh->h_extensions);
498 0 : TALER_merchant_wire_signature_hash (dcd->merchant_payto_uri,
499 : &dcd->wire_salt,
500 : &dh->h_wire);
501 0 : deposits = json_array ();
502 0 : GNUNET_assert (NULL != deposits);
503 0 : for (unsigned int i = 0; i<num_cdds; i++)
504 : {
505 0 : const struct TALER_EXCHANGE_CoinDepositDetail *cdd = &cdds[i];
506 : const struct TALER_EXCHANGE_DenomPublicKey *dki;
507 :
508 0 : dki = TALER_EXCHANGE_get_denomination_key_by_hash (key_state,
509 : &cdd->h_denom_pub);
510 0 : if (NULL == dki)
511 : {
512 0 : *ec = TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN;
513 0 : GNUNET_break_op (0);
514 0 : return NULL;
515 : }
516 0 : if (0 >
517 0 : TALER_amount_subtract (&amount_without_fee,
518 : &cdd->amount,
519 : &dki->fees.deposit))
520 : {
521 0 : *ec = TALER_EC_EXCHANGE_DEPOSIT_FEE_ABOVE_AMOUNT;
522 0 : GNUNET_break_op (0);
523 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
524 : "Amount: %s\n",
525 : TALER_amount2s (&cdd->amount));
526 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
527 : "Fee: %s\n",
528 : TALER_amount2s (&dki->fees.deposit));
529 0 : GNUNET_free (dh->cdds);
530 0 : GNUNET_free (dh);
531 0 : return NULL;
532 : }
533 :
534 0 : if (GNUNET_OK !=
535 0 : TALER_EXCHANGE_verify_deposit_signature_ (dcd,
536 0 : &dh->h_extensions,
537 0 : &dh->h_wire,
538 : cdd,
539 : dki))
540 : {
541 0 : *ec = TALER_EC_EXCHANGE_DEPOSIT_COIN_SIGNATURE_INVALID;
542 0 : GNUNET_break_op (0);
543 0 : GNUNET_free (dh->cdds);
544 0 : GNUNET_free (dh);
545 0 : return NULL;
546 : }
547 0 : GNUNET_assert (
548 : 0 ==
549 : json_array_append_new (
550 : deposits,
551 : GNUNET_JSON_PACK (
552 : TALER_JSON_pack_amount ("contribution",
553 : &cdd->amount),
554 : GNUNET_JSON_pack_data_auto ("denom_pub_hash",
555 : &cdd->h_denom_pub),
556 : TALER_JSON_pack_denom_sig ("ub_sig",
557 : &cdd->denom_sig),
558 : GNUNET_JSON_pack_data_auto ("coin_pub",
559 : &cdd->coin_pub),
560 : GNUNET_JSON_pack_allow_null (
561 : GNUNET_JSON_pack_data_auto ("h_age_commitment",
562 : &cdd->h_age_commitment)),
563 : GNUNET_JSON_pack_data_auto ("coin_sig",
564 : &cdd->coin_sig)
565 : )));
566 : }
567 0 : dh->url = TEAH_path_to_url (exchange,
568 : "/batch-deposit");
569 0 : if (NULL == dh->url)
570 : {
571 0 : GNUNET_break (0);
572 0 : *ec = TALER_EC_GENERIC_ALLOCATION_FAILURE;
573 0 : GNUNET_free (dh->url);
574 0 : GNUNET_free (dh->cdds);
575 0 : GNUNET_free (dh);
576 0 : return NULL;
577 : }
578 :
579 0 : deposit_obj = GNUNET_JSON_PACK (
580 : GNUNET_JSON_pack_string ("merchant_payto_uri",
581 : dcd->merchant_payto_uri),
582 : GNUNET_JSON_pack_data_auto ("wire_salt",
583 : &dcd->wire_salt),
584 : GNUNET_JSON_pack_data_auto ("h_contract_terms",
585 : &dcd->h_contract_terms),
586 : GNUNET_JSON_pack_array_steal ("coins",
587 : deposits),
588 : GNUNET_JSON_pack_allow_null (
589 : GNUNET_JSON_pack_object_steal ("extension_details",
590 : NULL)), /* FIXME #7270-Oec */
591 : GNUNET_JSON_pack_timestamp ("timestamp",
592 : dcd->timestamp),
593 : GNUNET_JSON_pack_data_auto ("merchant_pub",
594 : &dcd->merchant_pub),
595 : GNUNET_JSON_pack_allow_null (
596 : GNUNET_JSON_pack_timestamp ("refund_deadline",
597 : dcd->refund_deadline)),
598 : GNUNET_JSON_pack_timestamp ("wire_transfer_deadline",
599 : dcd->wire_deadline));
600 0 : GNUNET_assert (NULL != deposit_obj);
601 0 : eh = TALER_EXCHANGE_curl_easy_get_ (dh->url);
602 0 : if ( (NULL == eh) ||
603 : (GNUNET_OK !=
604 0 : TALER_curl_easy_post (&dh->ctx,
605 : eh,
606 : deposit_obj)) )
607 : {
608 0 : *ec = TALER_EC_GENERIC_CURL_ALLOCATION_FAILURE;
609 0 : GNUNET_break (0);
610 0 : if (NULL != eh)
611 0 : curl_easy_cleanup (eh);
612 0 : json_decref (deposit_obj);
613 0 : GNUNET_free (dh->cdds);
614 0 : GNUNET_free (dh->url);
615 0 : GNUNET_free (dh);
616 0 : return NULL;
617 : }
618 0 : json_decref (deposit_obj);
619 0 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
620 : "URL for deposit: `%s'\n",
621 : dh->url);
622 0 : ctx = TEAH_handle_to_context (exchange);
623 0 : dh->job = GNUNET_CURL_job_add2 (ctx,
624 : eh,
625 0 : dh->ctx.headers,
626 : &handle_deposit_finished,
627 : dh);
628 0 : return dh;
629 : }
630 :
631 :
632 : void
633 0 : TALER_EXCHANGE_batch_deposit_force_dc (
634 : struct TALER_EXCHANGE_BatchDepositHandle *deposit)
635 : {
636 0 : deposit->auditor_chance = 1;
637 0 : }
638 :
639 :
640 : void
641 0 : TALER_EXCHANGE_batch_deposit_cancel (
642 : struct TALER_EXCHANGE_BatchDepositHandle *deposit)
643 : {
644 0 : if (NULL != deposit->job)
645 : {
646 0 : GNUNET_CURL_job_cancel (deposit->job);
647 0 : deposit->job = NULL;
648 : }
649 0 : GNUNET_free (deposit->url);
650 0 : GNUNET_free (deposit->cdds);
651 0 : GNUNET_free (deposit->exchange_sigs);
652 0 : TALER_curl_easy_post_finished (&deposit->ctx);
653 0 : GNUNET_free (deposit);
654 0 : }
655 :
656 :
657 : /* end of exchange_api_batch_deposit.c */
|