LCOV - code coverage report
Current view: top level - lib - exchange_api_purse_deposit.c (source / functions) Hit Total Coverage
Test: GNU Taler exchange coverage report Lines: 0 244 0.0 %
Date: 2022-08-25 06:15:09 Functions: 0 3 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    This file is part of TALER
       3             :    Copyright (C) 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_purse_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_common.h"
      32             : #include "exchange_api_handle.h"
      33             : #include "taler_signatures.h"
      34             : #include "exchange_api_curl_defaults.h"
      35             : 
      36             : 
      37             : /**
      38             :  * Information we track per coin.
      39             :  */
      40             : struct Coin
      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_PurseDepositHandle
      73             : {
      74             : 
      75             :   /**
      76             :    * The connection to exchange this request handle will use
      77             :    */
      78             :   struct TALER_EXCHANGE_Handle *exchange;
      79             : 
      80             :   /**
      81             :    * The url for this request.
      82             :    */
      83             :   char *url;
      84             : 
      85             :   /**
      86             :    * The base url of the exchange we are talking to.
      87             :    */
      88             :   char *base_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_PurseDepositCallback cb;
     105             : 
     106             :   /**
     107             :    * Closure for @a cb.
     108             :    */
     109             :   void *cb_cls;
     110             : 
     111             :   /**
     112             :    * Public key of the purse.
     113             :    */
     114             :   struct TALER_PurseContractPublicKeyP purse_pub;
     115             : 
     116             :   /**
     117             :    * Array of @e num_deposits coins we are depositing.
     118             :    */
     119             :   struct Coin *coins;
     120             : 
     121             :   /**
     122             :    * Number of coins we are depositing.
     123             :    */
     124             :   unsigned int num_deposits;
     125             : };
     126             : 
     127             : 
     128             : /**
     129             :  * Function called when we're done processing the
     130             :  * HTTP /purses/$PID/deposit request.
     131             :  *
     132             :  * @param cls the `struct TALER_EXCHANGE_PurseDepositHandle`
     133             :  * @param response_code HTTP response code, 0 on error
     134             :  * @param response parsed JSON result, NULL on error
     135             :  */
     136             : static void
     137           0 : handle_purse_deposit_finished (void *cls,
     138             :                                long response_code,
     139             :                                const void *response)
     140             : {
     141           0 :   struct TALER_EXCHANGE_PurseDepositHandle *pch = cls;
     142           0 :   const json_t *j = response;
     143           0 :   struct TALER_EXCHANGE_PurseDepositResponse dr = {
     144             :     .hr.reply = j,
     145           0 :     .hr.http_status = (unsigned int) response_code
     146             :   };
     147             :   const struct TALER_EXCHANGE_Keys *keys;
     148             : 
     149           0 :   pch->job = NULL;
     150           0 :   keys = TALER_EXCHANGE_get_keys (pch->exchange);
     151           0 :   switch (response_code)
     152             :   {
     153           0 :   case 0:
     154           0 :     dr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
     155           0 :     break;
     156           0 :   case MHD_HTTP_OK:
     157             :     {
     158             :       struct GNUNET_TIME_Timestamp etime;
     159             :       struct TALER_ExchangeSignatureP exchange_sig;
     160             :       struct TALER_ExchangePublicKeyP exchange_pub;
     161             :       struct GNUNET_JSON_Specification spec[] = {
     162           0 :         GNUNET_JSON_spec_fixed_auto ("exchange_sig",
     163             :                                      &exchange_sig),
     164           0 :         GNUNET_JSON_spec_fixed_auto ("exchange_pub",
     165             :                                      &exchange_pub),
     166           0 :         GNUNET_JSON_spec_fixed_auto ("h_contract_terms",
     167             :                                      &dr.details.success.h_contract_terms),
     168           0 :         GNUNET_JSON_spec_timestamp ("exchange_timestamp",
     169             :                                     &etime),
     170           0 :         GNUNET_JSON_spec_timestamp ("purse_expiration",
     171             :                                     &dr.details.success.purse_expiration),
     172           0 :         TALER_JSON_spec_amount ("total_deposited",
     173           0 :                                 keys->currency,
     174             :                                 &dr.details.success.total_deposited),
     175           0 :         TALER_JSON_spec_amount ("purse_value_after_fees",
     176           0 :                                 keys->currency,
     177             :                                 &dr.details.success.purse_value_after_fees),
     178           0 :         GNUNET_JSON_spec_end ()
     179             :       };
     180             : 
     181           0 :       if (GNUNET_OK !=
     182           0 :           GNUNET_JSON_parse (j,
     183             :                              spec,
     184             :                              NULL, NULL))
     185             :       {
     186           0 :         GNUNET_break_op (0);
     187           0 :         dr.hr.http_status = 0;
     188           0 :         dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
     189           0 :         break;
     190             :       }
     191           0 :       if (GNUNET_OK !=
     192           0 :           TALER_EXCHANGE_test_signing_key (keys,
     193             :                                            &exchange_pub))
     194             :       {
     195           0 :         GNUNET_break_op (0);
     196           0 :         dr.hr.http_status = 0;
     197           0 :         dr.hr.ec = TALER_EC_EXCHANGE_PURSE_DEPOSIT_EXCHANGE_SIGNATURE_INVALID;
     198           0 :         break;
     199             :       }
     200           0 :       if (GNUNET_OK !=
     201           0 :           TALER_exchange_online_purse_created_verify (
     202             :             etime,
     203             :             dr.details.success.purse_expiration,
     204             :             &dr.details.success.purse_value_after_fees,
     205             :             &dr.details.success.total_deposited,
     206           0 :             &pch->purse_pub,
     207             :             &dr.details.success.h_contract_terms,
     208             :             &exchange_pub,
     209             :             &exchange_sig))
     210             :       {
     211           0 :         GNUNET_break_op (0);
     212           0 :         dr.hr.http_status = 0;
     213           0 :         dr.hr.ec = TALER_EC_EXCHANGE_PURSE_DEPOSIT_EXCHANGE_SIGNATURE_INVALID;
     214           0 :         break;
     215             :       }
     216             :     }
     217           0 :     break;
     218           0 :   case MHD_HTTP_BAD_REQUEST:
     219             :     /* This should never happen, either us or the exchange is buggy
     220             :        (or API version conflict); just pass JSON reply to the application */
     221           0 :     dr.hr.ec = TALER_JSON_get_error_code (j);
     222           0 :     break;
     223           0 :   case MHD_HTTP_FORBIDDEN:
     224           0 :     dr.hr.ec = TALER_JSON_get_error_code (j);
     225             :     /* Nothing really to verify, exchange says one of the signatures is
     226             :        invalid; as we checked them, this should never happen, we
     227             :        should pass the JSON reply to the application */
     228           0 :     break;
     229           0 :   case MHD_HTTP_NOT_FOUND:
     230           0 :     dr.hr.ec = TALER_JSON_get_error_code (j);
     231             :     /* Nothing really to verify, this should never
     232             :        happen, we should pass the JSON reply to the application */
     233           0 :     break;
     234           0 :   case MHD_HTTP_CONFLICT:
     235           0 :     dr.hr.ec = TALER_JSON_get_error_code (j);
     236           0 :     switch (dr.hr.ec)
     237             :     {
     238           0 :     case TALER_EC_EXCHANGE_PURSE_DEPOSIT_CONFLICTING_META_DATA:
     239             :       {
     240             :         struct TALER_CoinSpendPublicKeyP coin_pub;
     241             :         struct TALER_CoinSpendSignatureP coin_sig;
     242             :         struct TALER_DenominationHashP h_denom_pub;
     243             :         struct TALER_AgeCommitmentHash phac;
     244           0 :         bool found = false;
     245             : 
     246           0 :         if (GNUNET_OK !=
     247           0 :             TALER_EXCHANGE_check_purse_coin_conflict_ (
     248           0 :               &pch->purse_pub,
     249           0 :               pch->base_url,
     250             :               j,
     251             :               &h_denom_pub,
     252             :               &phac,
     253             :               &coin_pub,
     254             :               &coin_sig))
     255             :         {
     256           0 :           GNUNET_break_op (0);
     257           0 :           dr.hr.http_status = 0;
     258           0 :           dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
     259           0 :           break;
     260             :         }
     261           0 :         for (unsigned int i = 0; i<pch->num_deposits; i++)
     262             :         {
     263           0 :           struct Coin *coin = &pch->coins[i];
     264           0 :           if (0 != GNUNET_memcmp (&coin_pub,
     265             :                                   &coin->coin_pub))
     266           0 :             continue;
     267           0 :           if (0 !=
     268           0 :               GNUNET_memcmp (&coin->h_denom_pub,
     269             :                              &h_denom_pub))
     270             :           {
     271           0 :             found = true;
     272           0 :             break;
     273             :           }
     274           0 :           if (0 !=
     275           0 :               GNUNET_memcmp (&coin->ahac,
     276             :                              &phac))
     277             :           {
     278           0 :             found = true;
     279           0 :             break;
     280             :           }
     281           0 :           if (0 == GNUNET_memcmp (&coin_sig,
     282             :                                   &coin->coin_sig))
     283             :           {
     284             :             /* identical signature => not a conflict */
     285           0 :             continue;
     286             :           }
     287           0 :           found = true;
     288           0 :           break;
     289             :         }
     290           0 :         if (! found)
     291             :         {
     292           0 :           GNUNET_break_op (0);
     293           0 :           dr.hr.http_status = 0;
     294           0 :           dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
     295           0 :           break;
     296             :         }
     297             :         /* meta data conflict is real! */
     298           0 :         break;
     299             :       }
     300           0 :     case TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS:
     301             :       {
     302             :         struct TALER_CoinSpendPublicKeyP coin_pub;
     303             :         struct TALER_Amount remaining;
     304           0 :         bool found = false;
     305             :         const struct Coin *my_coin;
     306             : 
     307           0 :         if (GNUNET_OK !=
     308           0 :             TALER_EXCHANGE_check_coin_amount_conflict_ (
     309             :               keys,
     310             :               j,
     311             :               &coin_pub,
     312             :               &remaining))
     313             :         {
     314           0 :           dr.hr.http_status = 0;
     315           0 :           dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
     316           0 :           break;
     317             :         }
     318           0 :         for (unsigned int i = 0; i<pch->num_deposits; i++)
     319             :         {
     320           0 :           if (0 == GNUNET_memcmp (&coin_pub,
     321             :                                   &pch->coins[i].coin_pub))
     322             :           {
     323           0 :             found = true;
     324           0 :             my_coin = &pch->coins[i];
     325           0 :             break;
     326             :           }
     327             :         }
     328           0 :         if (! found)
     329             :         {
     330             :           /* proof is about a coin we did not even deposit */
     331           0 :           GNUNET_break_op (0);
     332           0 :           dr.hr.http_status = 0;
     333           0 :           dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
     334           0 :           break;
     335             :         }
     336           0 :         if (1 == TALER_amount_cmp (&remaining,
     337             :                                    &my_coin->contribution))
     338             :         {
     339             :           /* transaction should have still fit */
     340           0 :           GNUNET_break_op (0);
     341           0 :           dr.hr.http_status = 0;
     342           0 :           dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
     343           0 :           break;
     344             :         }
     345           0 :         if (GNUNET_OK !=
     346           0 :             TALER_EXCHANGE_check_coin_signature_conflict_ (
     347             :               j,
     348             :               &my_coin->coin_sig))
     349             :         {
     350             :           /* THIS transaction must not be in the conflicting history */
     351           0 :           GNUNET_break_op (0);
     352           0 :           dr.hr.http_status = 0;
     353           0 :           dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
     354           0 :           break;
     355             :         }
     356             :         /* everything OK, proof of double-spending was provided */
     357           0 :         break;
     358             :       }
     359           0 :     case TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY:
     360             :       {
     361             :         struct TALER_CoinSpendPublicKeyP coin_pub;
     362             :         struct TALER_Amount remaining;
     363           0 :         bool found = false;
     364             :         const struct Coin *my_coin;
     365             : 
     366           0 :         if (GNUNET_OK !=
     367           0 :             TALER_EXCHANGE_check_coin_amount_conflict_ (
     368             :               keys,
     369             :               j,
     370             :               &coin_pub,
     371             :               &remaining))
     372             :         {
     373           0 :           dr.hr.http_status = 0;
     374           0 :           dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
     375           0 :           break;
     376             :         }
     377           0 :         for (unsigned int i = 0; i<pch->num_deposits; i++)
     378             :         {
     379           0 :           if (0 == GNUNET_memcmp (&coin_pub,
     380             :                                   &pch->coins[i].coin_pub))
     381             :           {
     382           0 :             found = true;
     383           0 :             my_coin = &pch->coins[i];
     384           0 :             break;
     385             :           }
     386             :         }
     387           0 :         if (! found)
     388             :         {
     389             :           /* proof is about a coin we did not even deposit */
     390           0 :           GNUNET_break_op (0);
     391           0 :           dr.hr.http_status = 0;
     392           0 :           dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
     393           0 :           break;
     394             :         }
     395           0 :         if (GNUNET_OK !=
     396           0 :             TALER_EXCHANGE_check_coin_denomination_conflict_ (
     397             :               j,
     398             :               &my_coin->h_denom_pub))
     399             :         {
     400             :           /* no conflicting denomination detected */
     401           0 :           GNUNET_break_op (0);
     402           0 :           dr.hr.http_status = 0;
     403           0 :           dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
     404           0 :           break;
     405             :         }
     406             :         /* everything OK, proof of conflicting denomination was provided */
     407           0 :         break;
     408             :       }
     409           0 :     default:
     410           0 :       GNUNET_break_op (0);
     411           0 :       dr.hr.http_status = 0;
     412           0 :       dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
     413           0 :       break;
     414             :     } /* ec switch */
     415           0 :     break;
     416           0 :   case MHD_HTTP_GONE:
     417             :     /* could happen if denomination was revoked */
     418             :     /* Note: one might want to check /keys for revocation
     419             :        signature here, alas tricky in case our /keys
     420             :        is outdated => left to clients */
     421           0 :     dr.hr.ec = TALER_JSON_get_error_code (j);
     422           0 :     break;
     423           0 :   case MHD_HTTP_INTERNAL_SERVER_ERROR:
     424           0 :     dr.hr.ec = TALER_JSON_get_error_code (j);
     425             :     /* Server had an internal issue; we should retry, but this API
     426             :        leaves this to the application */
     427           0 :     break;
     428           0 :   default:
     429             :     /* unexpected response code */
     430           0 :     dr.hr.ec = TALER_JSON_get_error_code (j);
     431           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     432             :                 "Unexpected response code %u/%d for exchange deposit\n",
     433             :                 (unsigned int) response_code,
     434             :                 dr.hr.ec);
     435           0 :     GNUNET_break_op (0);
     436           0 :     break;
     437             :   }
     438           0 :   if (TALER_EC_NONE == dr.hr.ec)
     439           0 :     dr.hr.hint = NULL;
     440             :   else
     441           0 :     dr.hr.hint = TALER_ErrorCode_get_hint (dr.hr.ec);
     442           0 :   pch->cb (pch->cb_cls,
     443             :            &dr);
     444           0 :   TALER_EXCHANGE_purse_deposit_cancel (pch);
     445           0 : }
     446             : 
     447             : 
     448             : struct TALER_EXCHANGE_PurseDepositHandle *
     449           0 : TALER_EXCHANGE_purse_deposit (
     450             :   struct TALER_EXCHANGE_Handle *exchange,
     451             :   const char *purse_exchange_url,
     452             :   const struct TALER_PurseContractPublicKeyP *purse_pub,
     453             :   uint8_t min_age,
     454             :   unsigned int num_deposits,
     455             :   const struct TALER_EXCHANGE_PurseDeposit *deposits,
     456             :   TALER_EXCHANGE_PurseDepositCallback cb,
     457             :   void *cb_cls)
     458             : {
     459             :   struct TALER_EXCHANGE_PurseDepositHandle *pch;
     460             :   struct GNUNET_CURL_Context *ctx;
     461             :   json_t *create_obj;
     462             :   json_t *deposit_arr;
     463             :   CURL *eh;
     464             :   char arg_str[sizeof (pch->purse_pub) * 2 + 32];
     465             : 
     466             :   // FIXME: use purse_exchange_url for wad transfers (#7271)
     467             :   (void) purse_exchange_url;
     468           0 :   if (0 == num_deposits)
     469             :   {
     470           0 :     GNUNET_break (0);
     471           0 :     return NULL;
     472             :   }
     473           0 :   GNUNET_assert (GNUNET_YES ==
     474             :                  TEAH_handle_is_ready (exchange));
     475           0 :   pch = GNUNET_new (struct TALER_EXCHANGE_PurseDepositHandle);
     476           0 :   pch->purse_pub = *purse_pub;
     477           0 :   pch->exchange = exchange;
     478           0 :   pch->cb = cb;
     479           0 :   pch->cb_cls = cb_cls;
     480             :   {
     481             :     char pub_str[sizeof (pch->purse_pub) * 2];
     482             :     char *end;
     483             : 
     484           0 :     end = GNUNET_STRINGS_data_to_string (
     485           0 :       &pch->purse_pub,
     486             :       sizeof (pch->purse_pub),
     487             :       pub_str,
     488             :       sizeof (pub_str));
     489           0 :     *end = '\0';
     490           0 :     GNUNET_snprintf (arg_str,
     491             :                      sizeof (arg_str),
     492             :                      "/purses/%s/deposit",
     493             :                      pub_str);
     494             :   }
     495           0 :   pch->url = TEAH_path_to_url (exchange,
     496             :                                arg_str);
     497           0 :   if (NULL == pch->url)
     498             :   {
     499           0 :     GNUNET_break (0);
     500           0 :     GNUNET_free (pch);
     501           0 :     return NULL;
     502             :   }
     503           0 :   deposit_arr = json_array ();
     504           0 :   GNUNET_assert (NULL != deposit_arr);
     505           0 :   pch->base_url = TEAH_path_to_url (exchange,
     506             :                                     "/");
     507           0 :   pch->num_deposits = num_deposits;
     508           0 :   pch->coins = GNUNET_new_array (num_deposits,
     509             :                                  struct Coin);
     510           0 :   for (unsigned int i = 0; i<num_deposits; i++)
     511             :   {
     512           0 :     const struct TALER_EXCHANGE_PurseDeposit *deposit = &deposits[i];
     513           0 :     const struct TALER_AgeCommitmentProof *acp = deposit->age_commitment_proof;
     514           0 :     struct Coin *coin = &pch->coins[i];
     515             :     json_t *jdeposit;
     516           0 :     struct TALER_AgeCommitmentHash *achp = NULL;
     517             :     struct TALER_AgeAttestation attest;
     518           0 :     struct TALER_AgeAttestation *attestp = NULL;
     519             : 
     520           0 :     if (NULL != acp)
     521             :     {
     522           0 :       TALER_age_commitment_hash (&acp->commitment,
     523             :                                  &coin->ahac);
     524           0 :       achp = &coin->ahac;
     525           0 :       if (GNUNET_OK !=
     526           0 :           TALER_age_commitment_attest (acp,
     527             :                                        min_age,
     528             :                                        &attest))
     529             :       {
     530           0 :         GNUNET_break (0);
     531           0 :         json_decref (deposit_arr);
     532           0 :         GNUNET_free (pch->base_url);
     533           0 :         GNUNET_free (pch->coins);
     534           0 :         GNUNET_free (pch);
     535           0 :         return NULL;
     536             :       }
     537           0 :       attestp = &attest;
     538             :     }
     539           0 :     GNUNET_CRYPTO_eddsa_key_get_public (&deposit->coin_priv.eddsa_priv,
     540             :                                         &coin->coin_pub.eddsa_pub);
     541           0 :     coin->h_denom_pub = deposit->h_denom_pub;
     542           0 :     coin->contribution = deposit->amount;
     543           0 :     TALER_wallet_purse_deposit_sign (
     544           0 :       pch->base_url,
     545           0 :       &pch->purse_pub,
     546             :       &deposit->amount,
     547           0 :       &coin->h_denom_pub,
     548           0 :       &coin->ahac,
     549             :       &deposit->coin_priv,
     550             :       &coin->coin_sig);
     551           0 :     jdeposit = GNUNET_JSON_PACK (
     552             :       GNUNET_JSON_pack_allow_null (
     553             :         GNUNET_JSON_pack_data_auto ("h_age_commitment",
     554             :                                     achp)),
     555             :       GNUNET_JSON_pack_allow_null (
     556             :         GNUNET_JSON_pack_data_auto ("age_attestation",
     557             :                                     attestp)),
     558             :       TALER_JSON_pack_amount ("amount",
     559             :                               &deposit->amount),
     560             :       GNUNET_JSON_pack_data_auto ("denom_pub_hash",
     561             :                                   &deposit->h_denom_pub),
     562             :       TALER_JSON_pack_denom_sig ("ub_sig",
     563             :                                  &deposit->denom_sig),
     564             :       GNUNET_JSON_pack_data_auto ("coin_pub",
     565             :                                   &coin->coin_pub),
     566             :       GNUNET_JSON_pack_data_auto ("coin_sig",
     567             :                                   &coin->coin_sig));
     568           0 :     GNUNET_assert (0 ==
     569             :                    json_array_append_new (deposit_arr,
     570             :                                           jdeposit));
     571             :   }
     572           0 :   create_obj = GNUNET_JSON_PACK (
     573             :     GNUNET_JSON_pack_array_steal ("deposits",
     574             :                                   deposit_arr));
     575           0 :   GNUNET_assert (NULL != create_obj);
     576           0 :   eh = TALER_EXCHANGE_curl_easy_get_ (pch->url);
     577           0 :   if ( (NULL == eh) ||
     578             :        (GNUNET_OK !=
     579           0 :         TALER_curl_easy_post (&pch->ctx,
     580             :                               eh,
     581             :                               create_obj)) )
     582             :   {
     583           0 :     GNUNET_break (0);
     584           0 :     if (NULL != eh)
     585           0 :       curl_easy_cleanup (eh);
     586           0 :     json_decref (create_obj);
     587           0 :     GNUNET_free (pch->base_url);
     588           0 :     GNUNET_free (pch->url);
     589           0 :     GNUNET_free (pch->coins);
     590           0 :     GNUNET_free (pch);
     591           0 :     return NULL;
     592             :   }
     593           0 :   json_decref (create_obj);
     594           0 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     595             :               "URL for purse deposit: `%s'\n",
     596             :               pch->url);
     597           0 :   ctx = TEAH_handle_to_context (exchange);
     598           0 :   pch->job = GNUNET_CURL_job_add2 (ctx,
     599             :                                    eh,
     600           0 :                                    pch->ctx.headers,
     601             :                                    &handle_purse_deposit_finished,
     602             :                                    pch);
     603           0 :   return pch;
     604             : }
     605             : 
     606             : 
     607             : void
     608           0 : TALER_EXCHANGE_purse_deposit_cancel (
     609             :   struct TALER_EXCHANGE_PurseDepositHandle *pch)
     610             : {
     611           0 :   if (NULL != pch->job)
     612             :   {
     613           0 :     GNUNET_CURL_job_cancel (pch->job);
     614           0 :     pch->job = NULL;
     615             :   }
     616           0 :   GNUNET_free (pch->base_url);
     617           0 :   GNUNET_free (pch->url);
     618           0 :   GNUNET_free (pch->coins);
     619           0 :   TALER_curl_easy_post_finished (&pch->ctx);
     620           0 :   GNUNET_free (pch);
     621           0 : }
     622             : 
     623             : 
     624             : /* end of exchange_api_purse_deposit.c */

Generated by: LCOV version 1.14