LCOV - code coverage report
Current view: top level - lib - exchange_api_purse_create_with_deposit.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 108 237 45.6 %
Date: 2025-06-05 21:03:14 Functions: 3 3 100.0 %

          Line data    Source code
       1             : /*
       2             :    This file is part of TALER
       3             :    Copyright (C) 2022-2023 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_purse_create_with_deposit.c
      19             :  * @brief Implementation of the client to create a purse with
      20             :  *        an initial set of deposits (and a contract)
      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_exchange_service.h"
      31             : #include "exchange_api_handle.h"
      32             : #include "exchange_api_common.h"
      33             : #include "taler_signatures.h"
      34             : #include "exchange_api_curl_defaults.h"
      35             : 
      36             : 
      37             : /**
      38             :  * Information we track per deposited coin.
      39             :  */
      40             : struct Deposit
      41             : {
      42             :   /**
      43             :    * Coin's public key.
      44             :    */
      45             :   struct TALER_CoinSpendPublicKeyP coin_pub;
      46             : 
      47             :   /**
      48             :    * Signature made with the coin.
      49             :    */
      50             :   struct TALER_CoinSpendSignatureP coin_sig;
      51             : 
      52             :   /**
      53             :    * Coin's denomination.
      54             :    */
      55             :   struct TALER_DenominationHashP h_denom_pub;
      56             : 
      57             :   /**
      58             :    * Age restriction hash for the coin.
      59             :    */
      60             :   struct TALER_AgeCommitmentHash ahac;
      61             : 
      62             :   /**
      63             :    * How much did we say the coin contributed.
      64             :    */
      65             :   struct TALER_Amount contribution;
      66             : };
      67             : 
      68             : 
      69             : /**
      70             :  * @brief A purse create with deposit handle
      71             :  */
      72             : struct TALER_EXCHANGE_PurseCreateDepositHandle
      73             : {
      74             : 
      75             :   /**
      76             :    * The keys of the exchange this request handle will use
      77             :    */
      78             :   struct TALER_EXCHANGE_Keys *keys;
      79             : 
      80             :   /**
      81             :    * The url for this request.
      82             :    */
      83             :   char *url;
      84             : 
      85             :   /**
      86             :    * The base URL of the exchange.
      87             :    */
      88             :   char *exchange_url;
      89             : 
      90             :   /**
      91             :    * Context for #TEH_curl_easy_post(). Keeps the data that must
      92             :    * persist for Curl to make the upload.
      93             :    */
      94             :   struct TALER_CURL_PostContext ctx;
      95             : 
      96             :   /**
      97             :    * Handle for the request.
      98             :    */
      99             :   struct GNUNET_CURL_Job *job;
     100             : 
     101             :   /**
     102             :    * Function to call with the result.
     103             :    */
     104             :   TALER_EXCHANGE_PurseCreateDepositCallback cb;
     105             : 
     106             :   /**
     107             :    * Closure for @a cb.
     108             :    */
     109             :   void *cb_cls;
     110             : 
     111             :   /**
     112             :    * Expected value in the purse after fees.
     113             :    */
     114             :   struct TALER_Amount purse_value_after_fees;
     115             : 
     116             :   /**
     117             :    * Our encrypted contract (if we had any).
     118             :    */
     119             :   struct TALER_EncryptedContract econtract;
     120             : 
     121             :   /**
     122             :    * Public key of the merge capability.
     123             :    */
     124             :   struct TALER_PurseMergePublicKeyP merge_pub;
     125             : 
     126             :   /**
     127             :    * Public key of the purse.
     128             :    */
     129             :   struct TALER_PurseContractPublicKeyP purse_pub;
     130             : 
     131             :   /**
     132             :    * Signature with the purse key on the request.
     133             :    */
     134             :   struct TALER_PurseContractSignatureP purse_sig;
     135             : 
     136             :   /**
     137             :    * Hash over the purse's contract terms.
     138             :    */
     139             :   struct TALER_PrivateContractHashP h_contract_terms;
     140             : 
     141             :   /**
     142             :    * When does the purse expire.
     143             :    */
     144             :   struct GNUNET_TIME_Timestamp purse_expiration;
     145             : 
     146             :   /**
     147             :    * Array of @e num_deposit deposits.
     148             :    */
     149             :   struct Deposit *deposits;
     150             : 
     151             :   /**
     152             :    * How many deposits did we make?
     153             :    */
     154             :   unsigned int num_deposits;
     155             : 
     156             : };
     157             : 
     158             : 
     159             : /**
     160             :  * Function called when we're done processing the
     161             :  * HTTP /deposit request.
     162             :  *
     163             :  * @param cls the `struct TALER_EXCHANGE_DepositHandle`
     164             :  * @param response_code HTTP response code, 0 on error
     165             :  * @param response parsed JSON result, NULL on error
     166             :  */
     167             : static void
     168          11 : handle_purse_create_deposit_finished (void *cls,
     169             :                                       long response_code,
     170             :                                       const void *response)
     171             : {
     172          11 :   struct TALER_EXCHANGE_PurseCreateDepositHandle *pch = cls;
     173          11 :   const json_t *j = response;
     174          11 :   struct TALER_EXCHANGE_PurseCreateDepositResponse dr = {
     175             :     .hr.reply = j,
     176          11 :     .hr.http_status = (unsigned int) response_code
     177             :   };
     178          11 :   const struct TALER_EXCHANGE_Keys *keys = pch->keys;
     179             : 
     180          11 :   pch->job = NULL;
     181          11 :   switch (response_code)
     182             :   {
     183           0 :   case 0:
     184           0 :     dr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
     185           0 :     break;
     186           9 :   case MHD_HTTP_OK:
     187             :     {
     188             :       struct GNUNET_TIME_Timestamp etime;
     189             :       struct TALER_Amount total_deposited;
     190             :       struct TALER_ExchangeSignatureP exchange_sig;
     191             :       struct TALER_ExchangePublicKeyP exchange_pub;
     192             :       struct GNUNET_JSON_Specification spec[] = {
     193           9 :         GNUNET_JSON_spec_fixed_auto ("exchange_sig",
     194             :                                      &exchange_sig),
     195           9 :         GNUNET_JSON_spec_fixed_auto ("exchange_pub",
     196             :                                      &exchange_pub),
     197           9 :         GNUNET_JSON_spec_timestamp ("exchange_timestamp",
     198             :                                     &etime),
     199           9 :         TALER_JSON_spec_amount ("total_deposited",
     200           9 :                                 pch->purse_value_after_fees.currency,
     201             :                                 &total_deposited),
     202           9 :         GNUNET_JSON_spec_end ()
     203             :       };
     204             : 
     205           9 :       if (GNUNET_OK !=
     206           9 :           GNUNET_JSON_parse (j,
     207             :                              spec,
     208             :                              NULL, NULL))
     209             :       {
     210           0 :         GNUNET_break_op (0);
     211           0 :         dr.hr.http_status = 0;
     212           0 :         dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
     213           0 :         break;
     214             :       }
     215           9 :       if (GNUNET_OK !=
     216           9 :           TALER_EXCHANGE_test_signing_key (keys,
     217             :                                            &exchange_pub))
     218             :       {
     219           0 :         GNUNET_break_op (0);
     220           0 :         dr.hr.http_status = 0;
     221           0 :         dr.hr.ec = TALER_EC_EXCHANGE_PURSE_CREATE_EXCHANGE_SIGNATURE_INVALID;
     222           0 :         break;
     223             :       }
     224           9 :       if (GNUNET_OK !=
     225           9 :           TALER_exchange_online_purse_created_verify (
     226             :             etime,
     227             :             pch->purse_expiration,
     228           9 :             &pch->purse_value_after_fees,
     229             :             &total_deposited,
     230           9 :             &pch->purse_pub,
     231           9 :             &pch->h_contract_terms,
     232             :             &exchange_pub,
     233             :             &exchange_sig))
     234             :       {
     235           0 :         GNUNET_break_op (0);
     236           0 :         dr.hr.http_status = 0;
     237           0 :         dr.hr.ec = TALER_EC_EXCHANGE_PURSE_CREATE_EXCHANGE_SIGNATURE_INVALID;
     238           0 :         break;
     239             :       }
     240             :     }
     241           9 :     break;
     242           0 :   case MHD_HTTP_BAD_REQUEST:
     243             :     /* This should never happen, either us or the exchange is buggy
     244             :        (or API version conflict); just pass JSON reply to the application */
     245           0 :     dr.hr.ec = TALER_JSON_get_error_code (j);
     246           0 :     dr.hr.hint = TALER_JSON_get_error_hint (j);
     247           0 :     break;
     248           0 :   case MHD_HTTP_FORBIDDEN:
     249           0 :     dr.hr.ec = TALER_JSON_get_error_code (j);
     250           0 :     dr.hr.hint = TALER_JSON_get_error_hint (j);
     251             :     /* Nothing really to verify, exchange says one of the signatures is
     252             :        invalid; as we checked them, this should never happen, we
     253             :        should pass the JSON reply to the application */
     254           0 :     break;
     255           0 :   case MHD_HTTP_NOT_FOUND:
     256           0 :     dr.hr.ec = TALER_JSON_get_error_code (j);
     257           0 :     dr.hr.hint = TALER_JSON_get_error_hint (j);
     258             :     /* Nothing really to verify, this should never
     259             :        happen, we should pass the JSON reply to the application */
     260           0 :     break;
     261           2 :   case MHD_HTTP_CONFLICT:
     262             :     {
     263           2 :       dr.hr.ec = TALER_JSON_get_error_code (j);
     264           2 :       switch (dr.hr.ec)
     265             :       {
     266           0 :       case TALER_EC_EXCHANGE_PURSE_CREATE_CONFLICTING_META_DATA:
     267           0 :         if (GNUNET_OK !=
     268           0 :             TALER_EXCHANGE_check_purse_create_conflict_ (
     269           0 :               &pch->purse_sig,
     270           0 :               &pch->purse_pub,
     271             :               j))
     272             :         {
     273           0 :           GNUNET_break_op (0);
     274           0 :           dr.hr.http_status = 0;
     275           0 :           dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
     276           0 :           break;
     277             :         }
     278           0 :         break;
     279           2 :       case TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS:
     280             :         /* Nothing to check anymore here, proof needs to be
     281             :            checked in the GET /coins/$COIN_PUB handler */
     282           2 :         break;
     283           0 :       case TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY:
     284             :         // FIXME #7267: write check (add to exchange_api_common! */
     285           0 :         break;
     286           0 :       case TALER_EC_EXCHANGE_PURSE_DEPOSIT_CONFLICTING_META_DATA:
     287             :         {
     288             :           struct TALER_CoinSpendPublicKeyP coin_pub;
     289             :           struct TALER_CoinSpendSignatureP coin_sig;
     290             :           struct TALER_DenominationHashP h_denom_pub;
     291             :           struct TALER_AgeCommitmentHash phac;
     292           0 :           bool found = false;
     293             : 
     294           0 :           if (GNUNET_OK !=
     295           0 :               TALER_EXCHANGE_check_purse_coin_conflict_ (
     296           0 :                 &pch->purse_pub,
     297           0 :                 pch->exchange_url,
     298             :                 j,
     299             :                 &h_denom_pub,
     300             :                 &phac,
     301             :                 &coin_pub,
     302             :                 &coin_sig))
     303             :           {
     304           0 :             GNUNET_break_op (0);
     305           0 :             dr.hr.http_status = 0;
     306           0 :             dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
     307           0 :             break;
     308             :           }
     309           0 :           for (unsigned int i = 0; i<pch->num_deposits; i++)
     310             :           {
     311           0 :             struct Deposit *deposit = &pch->deposits[i];
     312             : 
     313           0 :             if (0 !=
     314           0 :                 GNUNET_memcmp (&coin_pub,
     315             :                                &deposit->coin_pub))
     316           0 :               continue;
     317           0 :             if (0 !=
     318           0 :                 GNUNET_memcmp (&deposit->h_denom_pub,
     319             :                                &h_denom_pub))
     320             :             {
     321           0 :               found = true;
     322           0 :               break;
     323             :             }
     324           0 :             if (0 !=
     325           0 :                 GNUNET_memcmp (&deposit->ahac,
     326             :                                &phac))
     327             :             {
     328           0 :               found = true;
     329           0 :               break;
     330             :             }
     331           0 :             if (0 ==
     332           0 :                 GNUNET_memcmp (&coin_sig,
     333             :                                &deposit->coin_sig))
     334             :             {
     335           0 :               GNUNET_break_op (0);
     336           0 :               continue;
     337             :             }
     338           0 :             found = true;
     339           0 :             break;
     340             :           }
     341           0 :           if (! found)
     342             :           {
     343             :             /* conflict is for a different coin! */
     344           0 :             GNUNET_break_op (0);
     345           0 :             dr.hr.http_status = 0;
     346           0 :             dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
     347           0 :             break;
     348             :           }
     349             :         }
     350             :       case TALER_EC_EXCHANGE_PURSE_ECONTRACT_CONFLICTING_META_DATA:
     351           0 :         if (GNUNET_OK !=
     352           0 :             TALER_EXCHANGE_check_purse_econtract_conflict_ (
     353           0 :               &pch->econtract.econtract_sig,
     354           0 :               &pch->purse_pub,
     355             :               j))
     356             :         {
     357           0 :           GNUNET_break_op (0);
     358           0 :           dr.hr.http_status = 0;
     359           0 :           dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
     360           0 :           break;
     361             :         }
     362           0 :         break;
     363           0 :       default:
     364           0 :         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     365             :                     "Unexpected error code %d for conflcting deposit\n",
     366             :                     dr.hr.ec);
     367           0 :         GNUNET_break_op (0);
     368           0 :         dr.hr.http_status = 0;
     369           0 :         dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
     370             :       }
     371             :     }
     372           2 :     break;
     373           0 :   case MHD_HTTP_GONE:
     374             :     /* could happen if denomination was revoked */
     375             :     /* Note: one might want to check /keys for revocation
     376             :        signature here, alas tricky in case our /keys
     377             :        is outdated => left to clients */
     378           0 :     dr.hr.ec = TALER_JSON_get_error_code (j);
     379           0 :     dr.hr.hint = TALER_JSON_get_error_hint (j);
     380           0 :     break;
     381           0 :   case MHD_HTTP_INTERNAL_SERVER_ERROR:
     382           0 :     dr.hr.ec = TALER_JSON_get_error_code (j);
     383           0 :     dr.hr.hint = TALER_JSON_get_error_hint (j);
     384             :     /* Server had an internal issue; we should retry, but this API
     385             :        leaves this to the application */
     386           0 :     break;
     387           0 :   default:
     388             :     /* unexpected response code */
     389           0 :     dr.hr.ec = TALER_JSON_get_error_code (j);
     390           0 :     dr.hr.hint = TALER_JSON_get_error_hint (j);
     391           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     392             :                 "Unexpected response code %u/%d for exchange deposit\n",
     393             :                 (unsigned int) response_code,
     394             :                 dr.hr.ec);
     395           0 :     GNUNET_break_op (0);
     396           0 :     break;
     397             :   }
     398          11 :   pch->cb (pch->cb_cls,
     399             :            &dr);
     400          11 :   TALER_EXCHANGE_purse_create_with_deposit_cancel (pch);
     401          11 : }
     402             : 
     403             : 
     404             : struct TALER_EXCHANGE_PurseCreateDepositHandle *
     405          11 : TALER_EXCHANGE_purse_create_with_deposit (
     406             :   struct GNUNET_CURL_Context *ctx,
     407             :   const char *url,
     408             :   struct TALER_EXCHANGE_Keys *keys,
     409             :   const struct TALER_PurseContractPrivateKeyP *purse_priv,
     410             :   const struct TALER_PurseMergePrivateKeyP *merge_priv,
     411             :   const struct TALER_ContractDiffiePrivateP *contract_priv,
     412             :   const json_t *contract_terms,
     413             :   unsigned int num_deposits,
     414             :   const struct TALER_EXCHANGE_PurseDeposit deposits[static num_deposits],
     415             :   bool upload_contract,
     416             :   TALER_EXCHANGE_PurseCreateDepositCallback cb,
     417             :   void *cb_cls)
     418          11 : {
     419             :   struct TALER_EXCHANGE_PurseCreateDepositHandle *pch;
     420             :   json_t *create_obj;
     421             :   json_t *deposit_arr;
     422             :   CURL *eh;
     423             :   char arg_str[sizeof (pch->purse_pub) * 2 + 32];
     424          11 :   uint32_t min_age = 0;
     425             : 
     426          11 :   pch = GNUNET_new (struct TALER_EXCHANGE_PurseCreateDepositHandle);
     427          11 :   pch->cb = cb;
     428          11 :   pch->cb_cls = cb_cls;
     429             :   {
     430             :     struct GNUNET_JSON_Specification spec[] = {
     431          11 :       GNUNET_JSON_spec_timestamp ("pay_deadline",
     432             :                                   &pch->purse_expiration),
     433          11 :       TALER_JSON_spec_amount_any ("amount",
     434             :                                   &pch->purse_value_after_fees),
     435          11 :       GNUNET_JSON_spec_mark_optional (
     436             :         GNUNET_JSON_spec_uint32 ("minimum_age",
     437             :                                  &min_age),
     438             :         NULL),
     439          11 :       GNUNET_JSON_spec_end ()
     440             :     };
     441             : 
     442          11 :     if (GNUNET_OK !=
     443          11 :         GNUNET_JSON_parse (contract_terms,
     444             :                            spec,
     445             :                            NULL, NULL))
     446             :     {
     447           0 :       GNUNET_break (0);
     448           0 :       return NULL;
     449             :     }
     450             :   }
     451          11 :   if (GNUNET_OK !=
     452          11 :       TALER_JSON_contract_hash (contract_terms,
     453             :                                 &pch->h_contract_terms))
     454             :   {
     455           0 :     GNUNET_break (0);
     456           0 :     return NULL;
     457             :   }
     458          11 :   GNUNET_CRYPTO_eddsa_key_get_public (&purse_priv->eddsa_priv,
     459             :                                       &pch->purse_pub.eddsa_pub);
     460             :   {
     461             :     char pub_str[sizeof (pch->purse_pub) * 2];
     462             :     char *end;
     463             : 
     464          11 :     end = GNUNET_STRINGS_data_to_string (
     465          11 :       &pch->purse_pub,
     466             :       sizeof (pch->purse_pub),
     467             :       pub_str,
     468             :       sizeof (pub_str));
     469          11 :     *end = '\0';
     470          11 :     GNUNET_snprintf (arg_str,
     471             :                      sizeof (arg_str),
     472             :                      "purses/%s/create",
     473             :                      pub_str);
     474             :   }
     475          11 :   GNUNET_CRYPTO_eddsa_key_get_public (&merge_priv->eddsa_priv,
     476             :                                       &pch->merge_pub.eddsa_pub);
     477          11 :   pch->url = TALER_url_join (url,
     478             :                              arg_str,
     479             :                              NULL);
     480          11 :   if (NULL == pch->url)
     481             :   {
     482           0 :     GNUNET_break (0);
     483           0 :     GNUNET_free (pch);
     484           0 :     return NULL;
     485             :   }
     486          11 :   pch->num_deposits = num_deposits;
     487          11 :   pch->deposits = GNUNET_new_array (num_deposits,
     488             :                                     struct Deposit);
     489          11 :   deposit_arr = json_array ();
     490          11 :   GNUNET_assert (NULL != deposit_arr);
     491          11 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     492             :               "Signing with URL `%s'\n",
     493             :               url);
     494          22 :   for (unsigned int i = 0; i<num_deposits; i++)
     495             :   {
     496          11 :     const struct TALER_EXCHANGE_PurseDeposit *deposit = &deposits[i];
     497          11 :     const struct TALER_AgeCommitmentProof *acp = deposit->age_commitment_proof;
     498          11 :     struct Deposit *d = &pch->deposits[i];
     499             :     json_t *jdeposit;
     500          11 :     struct TALER_AgeCommitmentHash *aghp = NULL;
     501             :     struct TALER_AgeAttestation attest;
     502          11 :     struct TALER_AgeAttestation *attestp = NULL;
     503             : 
     504          11 :     if (NULL != acp)
     505             :     {
     506           0 :       TALER_age_commitment_hash (&acp->commitment,
     507             :                                  &d->ahac);
     508           0 :       aghp = &d->ahac;
     509           0 :       if (GNUNET_OK !=
     510           0 :           TALER_age_commitment_attest (acp,
     511             :                                        min_age,
     512             :                                        &attest))
     513             :       {
     514           0 :         GNUNET_break (0);
     515           0 :         GNUNET_array_grow (pch->deposits,
     516             :                            pch->num_deposits,
     517             :                            0);
     518           0 :         GNUNET_free (pch->url);
     519           0 :         json_decref (deposit_arr);
     520           0 :         GNUNET_free (pch);
     521           0 :         return NULL;
     522             :       }
     523             :     }
     524          11 :     d->contribution = deposit->amount;
     525          11 :     d->h_denom_pub = deposit->h_denom_pub;
     526          11 :     GNUNET_CRYPTO_eddsa_key_get_public (&deposit->coin_priv.eddsa_priv,
     527             :                                         &d->coin_pub.eddsa_pub);
     528          11 :     TALER_wallet_purse_deposit_sign (
     529             :       url,
     530          11 :       &pch->purse_pub,
     531             :       &deposit->amount,
     532          11 :       &d->h_denom_pub,
     533          11 :       &d->ahac,
     534             :       &deposit->coin_priv,
     535             :       &d->coin_sig);
     536          11 :     jdeposit = GNUNET_JSON_PACK (
     537             :       GNUNET_JSON_pack_allow_null (
     538             :         GNUNET_JSON_pack_data_auto ("h_age_commitment",
     539             :                                     aghp)),
     540             :       GNUNET_JSON_pack_allow_null (
     541             :         GNUNET_JSON_pack_data_auto ("age_attestation",
     542             :                                     attestp)),
     543             :       TALER_JSON_pack_amount ("amount",
     544             :                               &deposit->amount),
     545             :       GNUNET_JSON_pack_data_auto ("denom_pub_hash",
     546             :                                   &deposit->h_denom_pub),
     547             :       TALER_JSON_pack_denom_sig ("ub_sig",
     548             :                                  &deposit->denom_sig),
     549             :       GNUNET_JSON_pack_data_auto ("coin_sig",
     550             :                                   &d->coin_sig),
     551             :       GNUNET_JSON_pack_data_auto ("coin_pub",
     552             :                                   &d->coin_pub));
     553          11 :     GNUNET_assert (0 ==
     554             :                    json_array_append_new (deposit_arr,
     555             :                                           jdeposit));
     556             :   }
     557          11 :   TALER_wallet_purse_create_sign (pch->purse_expiration,
     558          11 :                                   &pch->h_contract_terms,
     559          11 :                                   &pch->merge_pub,
     560             :                                   min_age,
     561          11 :                                   &pch->purse_value_after_fees,
     562             :                                   purse_priv,
     563             :                                   &pch->purse_sig);
     564          11 :   if (upload_contract)
     565             :   {
     566          11 :     TALER_CRYPTO_contract_encrypt_for_merge (&pch->purse_pub,
     567             :                                              contract_priv,
     568             :                                              merge_priv,
     569             :                                              contract_terms,
     570             :                                              &pch->econtract.econtract,
     571             :                                              &pch->econtract.econtract_size);
     572          11 :     GNUNET_CRYPTO_ecdhe_key_get_public (&contract_priv->ecdhe_priv,
     573             :                                         &pch->econtract.contract_pub.ecdhe_pub);
     574          11 :     TALER_wallet_econtract_upload_sign (pch->econtract.econtract,
     575             :                                         pch->econtract.econtract_size,
     576          11 :                                         &pch->econtract.contract_pub,
     577             :                                         purse_priv,
     578             :                                         &pch->econtract.econtract_sig);
     579             :   }
     580          11 :   create_obj = GNUNET_JSON_PACK (
     581             :     TALER_JSON_pack_amount ("amount",
     582             :                             &pch->purse_value_after_fees),
     583             :     GNUNET_JSON_pack_uint64 ("min_age",
     584             :                              min_age),
     585             :     GNUNET_JSON_pack_allow_null (
     586             :       TALER_JSON_pack_econtract ("econtract",
     587             :                                  upload_contract
     588             :                                  ? &pch->econtract
     589             :                                  : NULL)),
     590             :     GNUNET_JSON_pack_data_auto ("purse_sig",
     591             :                                 &pch->purse_sig),
     592             :     GNUNET_JSON_pack_data_auto ("merge_pub",
     593             :                                 &pch->merge_pub),
     594             :     GNUNET_JSON_pack_data_auto ("h_contract_terms",
     595             :                                 &pch->h_contract_terms),
     596             :     GNUNET_JSON_pack_timestamp ("purse_expiration",
     597             :                                 pch->purse_expiration),
     598             :     GNUNET_JSON_pack_array_steal ("deposits",
     599             :                                   deposit_arr));
     600          11 :   GNUNET_assert (NULL != create_obj);
     601          11 :   eh = TALER_EXCHANGE_curl_easy_get_ (pch->url);
     602          22 :   if ( (NULL == eh) ||
     603             :        (GNUNET_OK !=
     604          11 :         TALER_curl_easy_post (&pch->ctx,
     605             :                               eh,
     606             :                               create_obj)) )
     607             :   {
     608           0 :     GNUNET_break (0);
     609           0 :     if (NULL != eh)
     610           0 :       curl_easy_cleanup (eh);
     611           0 :     json_decref (create_obj);
     612           0 :     GNUNET_free (pch->econtract.econtract);
     613           0 :     GNUNET_array_grow (pch->deposits,
     614             :                        pch->num_deposits,
     615             :                        0);
     616           0 :     GNUNET_free (pch->url);
     617           0 :     GNUNET_free (pch);
     618           0 :     return NULL;
     619             :   }
     620          11 :   json_decref (create_obj);
     621          11 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     622             :               "URL for purse create with deposit: `%s'\n",
     623             :               pch->url);
     624          11 :   pch->keys = TALER_EXCHANGE_keys_incref (keys);
     625          11 :   pch->exchange_url = GNUNET_strdup (url);
     626          22 :   pch->job = GNUNET_CURL_job_add2 (ctx,
     627             :                                    eh,
     628          11 :                                    pch->ctx.headers,
     629             :                                    &handle_purse_create_deposit_finished,
     630             :                                    pch);
     631          11 :   return pch;
     632             : }
     633             : 
     634             : 
     635             : void
     636          11 : TALER_EXCHANGE_purse_create_with_deposit_cancel (
     637             :   struct TALER_EXCHANGE_PurseCreateDepositHandle *pch)
     638             : {
     639          11 :   if (NULL != pch->job)
     640             :   {
     641           0 :     GNUNET_CURL_job_cancel (pch->job);
     642           0 :     pch->job = NULL;
     643             :   }
     644          11 :   GNUNET_free (pch->econtract.econtract);
     645          11 :   GNUNET_free (pch->exchange_url);
     646          11 :   GNUNET_free (pch->url);
     647          11 :   GNUNET_array_grow (pch->deposits,
     648             :                      pch->num_deposits,
     649             :                      0);
     650          11 :   TALER_EXCHANGE_keys_decref (pch->keys);
     651          11 :   TALER_curl_easy_post_finished (&pch->ctx);
     652          11 :   GNUNET_free (pch);
     653          11 : }
     654             : 
     655             : 
     656             : /* end of exchange_api_purse_create_with_deposit.c */

Generated by: LCOV version 1.16