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