Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2025 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_post-melt.c
19 : * @brief Implementation of the /melt request
20 : * @author Özgür Kesim
21 : */
22 : #include <jansson.h>
23 : #include <microhttpd.h> /* just for HTTP status codes */
24 : #include <gnunet/gnunet_util_lib.h>
25 : #include <gnunet/gnunet_json_lib.h>
26 : #include <gnunet/gnunet_curl_lib.h>
27 : #include "taler/taler_json_lib.h"
28 : #include "exchange_api_common.h"
29 : #include "exchange_api_handle.h"
30 : #include "taler/taler_signatures.h"
31 : #include "exchange_api_curl_defaults.h"
32 : #include "exchange_api_refresh_common.h"
33 :
34 :
35 : /**
36 : * @brief A /melt Handle
37 : */
38 : struct TALER_EXCHANGE_PostMeltHandle
39 : {
40 :
41 : /**
42 : * The keys of the this request handle will use
43 : */
44 : struct TALER_EXCHANGE_Keys *keys;
45 :
46 : /**
47 : * The url for this request.
48 : */
49 : char *url;
50 :
51 : /**
52 : * The exchange base url.
53 : */
54 : char *exchange_url;
55 :
56 : /**
57 : * Curl context.
58 : */
59 : struct GNUNET_CURL_Context *cctx;
60 :
61 : /**
62 : * Context for #TEH_curl_easy_post(). Keeps the data that must
63 : * persist for Curl to make the upload.
64 : */
65 : struct TALER_CURL_PostContext ctx;
66 :
67 : /**
68 : * Handle for the request.
69 : */
70 : struct GNUNET_CURL_Job *job;
71 :
72 : /**
73 : * Function to call with refresh melt failure results.
74 : */
75 : TALER_EXCHANGE_PostMeltCallback melt_cb;
76 :
77 : /**
78 : * Closure for @e result_cb and @e melt_failure_cb.
79 : */
80 : void *melt_cb_cls;
81 :
82 : /**
83 : * Actual information about the melt operation.
84 : */
85 : struct MeltData md;
86 :
87 : /**
88 : * The seed for the melt operation.
89 : */
90 : struct TALER_PublicRefreshMasterSeedP rms;
91 :
92 : /**
93 : * Details about the characteristics of the requested melt operation.
94 : */
95 : const struct TALER_EXCHANGE_MeltInput *rd;
96 :
97 : /**
98 : * True, if no blinding_seed is needed (no CS denominations involved)
99 : */
100 : bool no_blinding_seed;
101 :
102 : /**
103 : * If @e no_blinding_seed is false, the blinding seed for the intermediate
104 : * call to /blinding-prepare, in order to retrieve the R-values from the
105 : * exchange for the blind Clause-Schnorr signature.
106 : */
107 : struct TALER_BlindingMasterSeedP blinding_seed;
108 :
109 : /**
110 : * Array of `num_fresh_denom_pubs` per-coin values
111 : * returned from melt operation.
112 : */
113 : struct TALER_ExchangeBlindingValues *melt_blinding_values;
114 :
115 : /**
116 : * Handle for the preflight request, or NULL.
117 : */
118 : struct TALER_EXCHANGE_PostBlindingPrepareHandle *bpr;
119 :
120 : /**
121 : * Public key of the coin being melted.
122 : */
123 : struct TALER_CoinSpendPublicKeyP coin_pub;
124 :
125 : /**
126 : * Signature affirming the melt.
127 : */
128 : struct TALER_CoinSpendSignatureP coin_sig;
129 :
130 : /**
131 : * @brief Public information about the coin's denomination key
132 : */
133 : const struct TALER_EXCHANGE_DenomPublicKey *dki;
134 :
135 : /**
136 : * Gamma value chosen by the exchange during melt.
137 : */
138 : uint32_t noreveal_index;
139 :
140 : };
141 :
142 :
143 : /**
144 : * Verify that the signature on the "200 OK" response
145 : * from the exchange is valid.
146 : *
147 : * @param[in,out] mh melt handle
148 : * @param json json reply with the signature
149 : * @param[out] exchange_pub public key of the exchange used for the signature
150 : * @return #GNUNET_OK if the signature is valid, #GNUNET_SYSERR if not
151 : */
152 : static enum GNUNET_GenericReturnValue
153 16 : verify_melt_signature_ok (struct TALER_EXCHANGE_PostMeltHandle *mh,
154 : const json_t *json,
155 : struct TALER_ExchangePublicKeyP *exchange_pub)
156 : {
157 : struct TALER_ExchangeSignatureP exchange_sig;
158 : struct GNUNET_JSON_Specification spec[] = {
159 16 : GNUNET_JSON_spec_fixed_auto ("exchange_sig",
160 : &exchange_sig),
161 16 : GNUNET_JSON_spec_fixed_auto ("exchange_pub",
162 : exchange_pub),
163 16 : GNUNET_JSON_spec_uint32 ("noreveal_index",
164 : &mh->noreveal_index),
165 16 : GNUNET_JSON_spec_end ()
166 : };
167 :
168 16 : if (GNUNET_OK !=
169 16 : GNUNET_JSON_parse (json,
170 : spec,
171 : NULL, NULL))
172 : {
173 0 : GNUNET_break_op (0);
174 0 : return GNUNET_SYSERR;
175 : }
176 : /* check that exchange signing key is permitted */
177 16 : if (GNUNET_OK !=
178 16 : TALER_EXCHANGE_test_signing_key (mh->keys,
179 : exchange_pub))
180 : {
181 0 : GNUNET_break_op (0);
182 0 : return GNUNET_SYSERR;
183 : }
184 :
185 : /* check that noreveal index is in permitted range */
186 16 : if (TALER_CNC_KAPPA <= mh->noreveal_index)
187 : {
188 0 : GNUNET_break_op (0);
189 0 : return GNUNET_SYSERR;
190 : }
191 :
192 16 : if (GNUNET_OK !=
193 16 : TALER_exchange_online_melt_confirmation_verify (
194 16 : &mh->md.rc,
195 : mh->noreveal_index,
196 : exchange_pub,
197 : &exchange_sig))
198 : {
199 0 : GNUNET_break_op (0);
200 0 : return GNUNET_SYSERR;
201 : }
202 16 : return GNUNET_OK;
203 : }
204 :
205 :
206 : /**
207 : * Function called when we're done processing the
208 : * HTTP /melt request.
209 : *
210 : * @param cls the `struct TALER_EXCHANGE_MeltHandle`
211 : * @param response_code HTTP response code, 0 on error
212 : * @param response parsed JSON result, NULL on error
213 : */
214 : static void
215 30 : handle_melt_finished (void *cls,
216 : long response_code,
217 : const void *response)
218 : {
219 30 : struct TALER_EXCHANGE_PostMeltHandle *mh = cls;
220 30 : const json_t *j = response;
221 30 : struct TALER_EXCHANGE_PostMeltResponse mr = {
222 : .hr.reply = j,
223 30 : .hr.http_status = (unsigned int) response_code
224 : };
225 :
226 30 : mh->job = NULL;
227 30 : switch (response_code)
228 : {
229 0 : case 0:
230 0 : mr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
231 0 : break;
232 16 : case MHD_HTTP_OK:
233 16 : if (GNUNET_OK !=
234 16 : verify_melt_signature_ok (mh,
235 : j,
236 : &mr.details.ok.sign_key))
237 : {
238 0 : GNUNET_break_op (0);
239 0 : mr.hr.http_status = 0;
240 0 : mr.hr.ec = TALER_EC_EXCHANGE_MELT_INVALID_SIGNATURE_BY_EXCHANGE;
241 0 : break;
242 : }
243 16 : mr.details.ok.noreveal_index = mh->noreveal_index;
244 16 : mr.details.ok.num_melt_blinding_values = mh->rd->num_fresh_denom_pubs;
245 16 : mr.details.ok.melt_blinding_values = mh->melt_blinding_values;
246 32 : mr.details.ok.blinding_seed = mh->no_blinding_seed
247 : ? NULL
248 16 : : &mh->blinding_seed;
249 16 : mh->melt_cb (mh->melt_cb_cls,
250 : &mr);
251 16 : mh->melt_cb = NULL;
252 16 : break;
253 0 : case MHD_HTTP_BAD_REQUEST:
254 : /* This should never happen, either us or the exchange is buggy
255 : (or API version conflict); just pass JSON reply to the application */
256 0 : mr.hr.ec = TALER_JSON_get_error_code (j);
257 0 : mr.hr.hint = TALER_JSON_get_error_hint (j);
258 0 : break;
259 14 : case MHD_HTTP_CONFLICT:
260 14 : mr.hr.ec = TALER_JSON_get_error_code (j);
261 14 : mr.hr.hint = TALER_JSON_get_error_hint (j);
262 14 : break;
263 0 : case MHD_HTTP_FORBIDDEN:
264 : /* Nothing really to verify, exchange says one of the signatures is
265 : invalid; assuming we checked them, this should never happen, we
266 : should pass the JSON reply to the application */
267 0 : mr.hr.ec = TALER_JSON_get_error_code (j);
268 0 : mr.hr.hint = TALER_JSON_get_error_hint (j);
269 0 : break;
270 0 : case MHD_HTTP_NOT_FOUND:
271 : /* Nothing really to verify, this should never
272 : happen, we should pass the JSON reply to the application */
273 0 : mr.hr.ec = TALER_JSON_get_error_code (j);
274 0 : mr.hr.hint = TALER_JSON_get_error_hint (j);
275 0 : break;
276 0 : case MHD_HTTP_INTERNAL_SERVER_ERROR:
277 : /* Server had an internal issue; we should retry, but this API
278 : leaves this to the application */
279 0 : mr.hr.ec = TALER_JSON_get_error_code (j);
280 0 : mr.hr.hint = TALER_JSON_get_error_hint (j);
281 0 : break;
282 0 : default:
283 : /* unexpected response code */
284 0 : mr.hr.ec = TALER_JSON_get_error_code (j);
285 0 : mr.hr.hint = TALER_JSON_get_error_hint (j);
286 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
287 : "Unexpected response code %u/%d for exchange melt\n",
288 : (unsigned int) response_code,
289 : mr.hr.ec);
290 0 : GNUNET_break_op (0);
291 0 : break;
292 : }
293 30 : if (NULL != mh->melt_cb)
294 14 : mh->melt_cb (mh->melt_cb_cls,
295 : &mr);
296 30 : TALER_EXCHANGE_post_melt_cancel (mh);
297 30 : }
298 :
299 :
300 : /**
301 : * Start the actual melt operation, now that we have
302 : * the exchange's input values.
303 : *
304 : * @param[in,out] mh melt operation to run
305 : * @return #GNUNET_OK if we could start the operation
306 : */
307 : static enum GNUNET_GenericReturnValue
308 30 : start_melt (struct TALER_EXCHANGE_PostMeltHandle *mh)
309 : {
310 : json_t *j_request_body;
311 : json_t *j_transfer_pubs;
312 : json_t *j_coin_evs;
313 : CURL *eh;
314 : struct TALER_DenominationHashP h_denom_pub;
315 :
316 30 : if (GNUNET_OK !=
317 30 : TALER_EXCHANGE_get_melt_data (&mh->rms,
318 : mh->rd,
319 30 : mh->no_blinding_seed
320 : ? NULL
321 : : &mh->blinding_seed,
322 30 : mh->melt_blinding_values,
323 : &mh->md))
324 : {
325 0 : GNUNET_break (0);
326 0 : return GNUNET_SYSERR;
327 : }
328 30 : TALER_denom_pub_hash (
329 30 : &mh->md.melted_coin.pub_key,
330 : &h_denom_pub);
331 30 : TALER_wallet_melt_sign (
332 30 : &mh->md.melted_coin.melt_amount_with_fee,
333 30 : &mh->md.melted_coin.fee_melt,
334 30 : &mh->md.rc,
335 : &h_denom_pub,
336 : mh->md.melted_coin.h_age_commitment,
337 30 : &mh->md.melted_coin.coin_priv,
338 : &mh->coin_sig);
339 30 : GNUNET_CRYPTO_eddsa_key_get_public (
340 30 : &mh->md.melted_coin.coin_priv.eddsa_priv,
341 : &mh->coin_pub.eddsa_pub);
342 60 : mh->dki = TALER_EXCHANGE_get_denomination_key (
343 30 : mh->keys,
344 30 : &mh->md.melted_coin.pub_key);
345 30 : j_request_body = GNUNET_JSON_PACK (
346 : GNUNET_JSON_pack_data_auto ("old_coin_pub",
347 : &mh->coin_pub),
348 : GNUNET_JSON_pack_data_auto ("old_denom_pub_h",
349 : &h_denom_pub),
350 : TALER_JSON_pack_denom_sig ("old_denom_sig",
351 : &mh->md.melted_coin.sig),
352 : GNUNET_JSON_pack_data_auto ("confirm_sig",
353 : &mh->coin_sig),
354 : TALER_JSON_pack_amount ("value_with_fee",
355 : &mh->md.melted_coin.melt_amount_with_fee),
356 : GNUNET_JSON_pack_allow_null (
357 : (NULL != mh->md.melted_coin.h_age_commitment)
358 : ? GNUNET_JSON_pack_data_auto ("old_age_commitment_h",
359 : mh->md.melted_coin.h_age_commitment)
360 : : GNUNET_JSON_pack_string ("old_age_commitment_h",
361 : NULL)),
362 : GNUNET_JSON_pack_data_auto ("refresh_seed",
363 : &mh->md.refresh_seed),
364 : GNUNET_JSON_pack_allow_null (
365 : (mh->md.no_blinding_seed)
366 : ? GNUNET_JSON_pack_string ("blinding_seed",
367 : NULL)
368 : : GNUNET_JSON_pack_data_auto ("blinding_seed",
369 : &mh->md.blinding_seed)),
370 : TALER_JSON_pack_array_of_data_auto ("denoms_h",
371 : mh->md.num_fresh_coins,
372 : mh->md.denoms_h)
373 : );
374 30 : GNUNET_assert (NULL != j_request_body);
375 30 : GNUNET_assert (NULL !=
376 : (j_transfer_pubs = json_array ()));
377 30 : GNUNET_assert (NULL !=
378 : (j_coin_evs = json_array ()));
379 : /**
380 : * Fill the kappa array of coin envelopes and
381 : * the array of transfer pubs.
382 : */
383 120 : for (uint8_t k=0; k<TALER_CNC_KAPPA; k++)
384 : {
385 : json_t *j_envs;
386 90 : json_t *j_tbs = GNUNET_JSON_PACK (
387 : TALER_JSON_pack_array_of_data_auto ("_",
388 : mh->md.num_fresh_coins,
389 : mh->md.kappa_transfer_pubs[k])
390 : );
391 :
392 90 : GNUNET_assert (NULL != (j_envs = json_array ()));
393 90 : GNUNET_assert (NULL != j_tbs);
394 :
395 450 : for (size_t i = 0; i < mh->md.num_fresh_coins; i++)
396 : {
397 360 : json_t *j_coin = GNUNET_JSON_PACK (
398 : TALER_JSON_pack_blinded_planchet (NULL,
399 : &mh->md.kappa_blinded_planchets[k][i])
400 : );
401 360 : GNUNET_assert (NULL != j_coin);
402 360 : GNUNET_assert (0 ==
403 : json_array_append_new (j_envs,
404 : j_coin));
405 : }
406 90 : GNUNET_assert (0 ==
407 : json_array_append_new (j_coin_evs,
408 : j_envs));
409 90 : GNUNET_assert (0 ==
410 : json_array_append (j_transfer_pubs,
411 : json_object_get (j_tbs,
412 : "_")));
413 90 : json_decref (j_tbs);
414 : }
415 30 : GNUNET_assert (0 ==
416 : json_object_set_new (j_request_body,
417 : "coin_evs",
418 : j_coin_evs));
419 30 : GNUNET_assert (0 ==
420 : json_object_set_new (j_request_body,
421 : "transfer_pubs",
422 : j_transfer_pubs));
423 : /* and now we can at last begin the actual request handling */
424 30 : mh->url = TALER_url_join (mh->exchange_url,
425 : "melt",
426 : NULL);
427 30 : if (NULL == mh->url)
428 : {
429 0 : json_decref (j_request_body);
430 0 : return GNUNET_SYSERR;
431 : }
432 30 : eh = TALER_EXCHANGE_curl_easy_get_ (mh->url);
433 60 : if ( (NULL == eh) ||
434 : (GNUNET_OK !=
435 30 : TALER_curl_easy_post (&mh->ctx,
436 : eh,
437 : j_request_body)) )
438 : {
439 0 : GNUNET_break (0);
440 0 : if (NULL != eh)
441 0 : curl_easy_cleanup (eh);
442 0 : json_decref (j_request_body);
443 0 : return GNUNET_SYSERR;
444 : }
445 30 : json_decref (j_request_body);
446 60 : mh->job = GNUNET_CURL_job_add2 (mh->cctx,
447 : eh,
448 30 : mh->ctx.headers,
449 : &handle_melt_finished,
450 : mh);
451 30 : return GNUNET_OK;
452 : }
453 :
454 :
455 : /**
456 : * The melt request @a mh failed, return an error to
457 : * the application and cancel the operation.
458 : *
459 : * @param[in] mh melt request that failed
460 : * @param ec error code to fail with
461 : */
462 : static void
463 0 : fail_mh (struct TALER_EXCHANGE_PostMeltHandle *mh,
464 : enum TALER_ErrorCode ec)
465 : {
466 0 : struct TALER_EXCHANGE_PostMeltResponse mr = {
467 : .hr.ec = ec
468 : };
469 :
470 0 : mh->melt_cb (mh->melt_cb_cls,
471 : &mr);
472 0 : TALER_EXCHANGE_post_melt_cancel (mh);
473 0 : }
474 :
475 :
476 : /**
477 : * Callbacks of this type are used to serve the result of submitting a
478 : * /blinding-prepare request to a exchange.
479 : *
480 : * @param cls closure with our `struct TALER_EXCHANGE_MeltHandle *`
481 : * @param bpr response details
482 : */
483 : static void
484 15 : blinding_prepare_cb (void *cls,
485 : const struct TALER_EXCHANGE_PostBlindingPrepareResponse *
486 : bpr)
487 : {
488 15 : struct TALER_EXCHANGE_PostMeltHandle *mh = cls;
489 15 : unsigned int nks_off = 0;
490 :
491 15 : mh->bpr = NULL;
492 15 : if (MHD_HTTP_OK != bpr->hr.http_status)
493 : {
494 0 : struct TALER_EXCHANGE_PostMeltResponse mr = {
495 : .hr = bpr->hr
496 : };
497 :
498 0 : mr.hr.hint = "/blinding-prepare failed";
499 0 : mh->melt_cb (mh->melt_cb_cls,
500 : &mr);
501 0 : TALER_EXCHANGE_post_melt_cancel (mh);
502 0 : return;
503 : }
504 75 : for (unsigned int i = 0; i<mh->rd->num_fresh_denom_pubs; i++)
505 : {
506 60 : const struct TALER_EXCHANGE_DenomPublicKey *fresh_pk =
507 60 : &mh->rd->fresh_denom_pubs[i];
508 60 : struct TALER_ExchangeBlindingValues *wv = &mh->melt_blinding_values[i];
509 :
510 60 : switch (fresh_pk->key.bsign_pub_key->cipher)
511 : {
512 0 : case GNUNET_CRYPTO_BSA_INVALID:
513 0 : GNUNET_break (0);
514 0 : fail_mh (mh,
515 : TALER_EC_GENERIC_CLIENT_INTERNAL_ERROR);
516 0 : return;
517 0 : case GNUNET_CRYPTO_BSA_RSA:
518 0 : break;
519 60 : case GNUNET_CRYPTO_BSA_CS:
520 60 : TALER_denom_ewv_copy (wv,
521 60 : &bpr->details.ok.blinding_values[nks_off]);
522 60 : nks_off++;
523 60 : break;
524 : }
525 : }
526 15 : if (GNUNET_OK !=
527 15 : start_melt (mh))
528 : {
529 0 : GNUNET_break (0);
530 0 : fail_mh (mh,
531 : TALER_EC_GENERIC_CLIENT_INTERNAL_ERROR);
532 0 : return;
533 : }
534 : }
535 :
536 :
537 : struct TALER_EXCHANGE_PostMeltHandle *
538 30 : TALER_EXCHANGE_post_melt_create (
539 : struct GNUNET_CURL_Context *ctx,
540 : const char *url,
541 : struct TALER_EXCHANGE_Keys *keys,
542 : const struct TALER_PublicRefreshMasterSeedP *rms,
543 : const struct TALER_EXCHANGE_MeltInput *rd)
544 : {
545 : struct TALER_EXCHANGE_PostMeltHandle *mh;
546 :
547 30 : if (0 == rd->num_fresh_denom_pubs)
548 : {
549 0 : GNUNET_break (0);
550 0 : return NULL;
551 : }
552 30 : mh = GNUNET_new (struct TALER_EXCHANGE_PostMeltHandle);
553 30 : mh->noreveal_index = TALER_CNC_KAPPA; /* invalid value */
554 30 : mh->cctx = ctx;
555 30 : mh->exchange_url = GNUNET_strdup (url);
556 30 : mh->rd = rd;
557 30 : mh->rms = *rms;
558 30 : mh->no_blinding_seed = true;
559 30 : mh->melt_blinding_values =
560 30 : GNUNET_new_array (rd->num_fresh_denom_pubs,
561 : struct TALER_ExchangeBlindingValues);
562 150 : for (unsigned int i = 0; i < rd->num_fresh_denom_pubs; i++)
563 : {
564 120 : const struct TALER_EXCHANGE_DenomPublicKey *fresh_pk =
565 120 : &rd->fresh_denom_pubs[i];
566 :
567 120 : switch (fresh_pk->key.bsign_pub_key->cipher)
568 : {
569 0 : case GNUNET_CRYPTO_BSA_INVALID:
570 0 : GNUNET_break (0);
571 0 : GNUNET_free (mh->melt_blinding_values);
572 0 : GNUNET_free (mh->exchange_url);
573 0 : GNUNET_free (mh);
574 0 : return NULL;
575 60 : case GNUNET_CRYPTO_BSA_RSA:
576 60 : TALER_denom_ewv_copy (&mh->melt_blinding_values[i],
577 : TALER_denom_ewv_rsa_singleton ());
578 60 : break;
579 60 : case GNUNET_CRYPTO_BSA_CS:
580 60 : mh->no_blinding_seed = false;
581 60 : break;
582 : }
583 : }
584 30 : mh->keys = TALER_EXCHANGE_keys_incref (keys);
585 30 : return mh;
586 : }
587 :
588 :
589 : enum TALER_ErrorCode
590 30 : TALER_EXCHANGE_post_melt_start (
591 : struct TALER_EXCHANGE_PostMeltHandle *mh,
592 : TALER_EXCHANGE_PostMeltCallback melt_cb,
593 : TALER_EXCHANGE_POST_MELT_RESULT_CLOSURE *melt_cb_cls)
594 : {
595 30 : mh->melt_cb = melt_cb;
596 30 : mh->melt_cb_cls = melt_cb_cls;
597 :
598 30 : if (! mh->no_blinding_seed)
599 15 : {
600 0 : struct TALER_EXCHANGE_NonceKey nks[
601 15 : GNUNET_NZL (mh->rd->num_fresh_denom_pubs)];
602 15 : unsigned int nks_off = 0;
603 :
604 75 : for (unsigned int i = 0; i < mh->rd->num_fresh_denom_pubs; i++)
605 : {
606 60 : const struct TALER_EXCHANGE_DenomPublicKey *fresh_pk =
607 60 : &mh->rd->fresh_denom_pubs[i];
608 :
609 60 : if (GNUNET_CRYPTO_BSA_CS ==
610 60 : fresh_pk->key.bsign_pub_key->cipher)
611 : {
612 60 : nks[nks_off].pk = fresh_pk;
613 60 : nks[nks_off].cnc_num = i;
614 60 : nks_off++;
615 : }
616 : }
617 15 : TALER_cs_refresh_seed_to_blinding_seed (
618 15 : &mh->rms,
619 15 : &mh->md.melted_coin.coin_priv,
620 : &mh->blinding_seed);
621 15 : mh->bpr = TALER_EXCHANGE_post_blinding_prepare_for_melt_create (
622 : mh->cctx,
623 : mh->exchange_url,
624 : &mh->blinding_seed,
625 : nks_off,
626 : nks);
627 15 : if (NULL == mh->bpr)
628 : {
629 0 : GNUNET_break (0);
630 0 : return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
631 : }
632 : {
633 : enum TALER_ErrorCode ec;
634 :
635 15 : ec = TALER_EXCHANGE_post_blinding_prepare_start (mh->bpr,
636 : &blinding_prepare_cb,
637 : mh);
638 15 : if (TALER_EC_NONE != ec)
639 : {
640 0 : GNUNET_break (0);
641 0 : TALER_EXCHANGE_post_blinding_prepare_cancel (mh->bpr);
642 0 : mh->bpr = NULL;
643 0 : return ec;
644 : }
645 : }
646 15 : return TALER_EC_NONE;
647 : }
648 15 : if (GNUNET_OK !=
649 15 : start_melt (mh))
650 : {
651 0 : GNUNET_break (0);
652 0 : return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
653 : }
654 15 : return TALER_EC_NONE;
655 : }
656 :
657 :
658 : void
659 30 : TALER_EXCHANGE_post_melt_cancel (struct TALER_EXCHANGE_PostMeltHandle *mh)
660 : {
661 150 : for (unsigned int i = 0; i < mh->rd->num_fresh_denom_pubs; i++)
662 120 : TALER_denom_ewv_free (&mh->melt_blinding_values[i]);
663 30 : if (NULL != mh->job)
664 : {
665 0 : GNUNET_CURL_job_cancel (mh->job);
666 0 : mh->job = NULL;
667 : }
668 30 : if (NULL != mh->bpr)
669 : {
670 0 : TALER_EXCHANGE_post_blinding_prepare_cancel (mh->bpr);
671 0 : mh->bpr = NULL;
672 : }
673 30 : TALER_EXCHANGE_free_melt_data (&mh->md); /* does not free 'md' itself */
674 30 : GNUNET_free (mh->melt_blinding_values);
675 30 : GNUNET_free (mh->url);
676 30 : GNUNET_free (mh->exchange_url);
677 30 : TALER_curl_easy_post_finished (&mh->ctx);
678 30 : TALER_EXCHANGE_keys_decref (mh->keys);
679 30 : GNUNET_free (mh);
680 30 : }
681 :
682 :
683 : /* end of exchange_api_melt.c */
|