LCOV - code coverage report
Current view: top level - testing - testing_api_cmd_withdraw.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 65.4 % 214 140
Test Date: 2026-06-14 14:19:22 Functions: 70.0 % 10 7

            Line data    Source code
       1              : /*
       2              :   This file is part of TALER
       3              :   Copyright (C) 2018-2024 Taler Systems SA
       4              : 
       5              :   TALER is free software; you can redistribute it and/or modify it
       6              :   under the terms of the GNU General Public License as published by
       7              :   the Free Software Foundation; either version 3, or (at your
       8              :   option) any later version.
       9              : 
      10              :   TALER is distributed in the hope that it will be useful, but
      11              :   WITHOUT ANY WARRANTY; without even the implied warranty of
      12              :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13              :   General Public License for more details.
      14              : 
      15              :   You should have received a copy of the GNU General Public
      16              :   License along with TALER; see the file COPYING.  If not, see
      17              :   <http://www.gnu.org/licenses/>
      18              : */
      19              : /**
      20              :  * @file testing/testing_api_cmd_withdraw.c
      21              :  * @brief main interpreter loop for testcases
      22              :  * @author Christian Grothoff
      23              :  * @author Marcello Stanisci
      24              :  * @author Özgür Kesim
      25              :  */
      26              : #include "taler/taler_json_lib.h"
      27              : #include <microhttpd.h>
      28              : #include <gnunet/gnunet_curl_lib.h>
      29              : #include "taler/taler_signatures.h"
      30              : #include "taler/taler_testing_lib.h"
      31              : #include "backoff.h"
      32              : 
      33              : 
      34              : /**
      35              :  * How often do we retry before giving up?
      36              :  */
      37              : #define NUM_RETRIES 15
      38              : 
      39              : /**
      40              :  * How long do we wait AT LEAST if the exchange says the reserve is unknown?
      41              :  */
      42              : #define UNKNOWN_MIN_BACKOFF GNUNET_TIME_relative_multiply ( \
      43              :           GNUNET_TIME_UNIT_MILLISECONDS, 10)
      44              : 
      45              : /**
      46              :  * How long do we wait AT MOST if the exchange says the reserve is unknown?
      47              :  */
      48              : #define UNKNOWN_MAX_BACKOFF GNUNET_TIME_relative_multiply ( \
      49              :           GNUNET_TIME_UNIT_MILLISECONDS, 100)
      50              : 
      51              : /**
      52              :  * State for a "withdraw" CMD.
      53              :  */
      54              : struct WithdrawState
      55              : {
      56              : 
      57              :   /**
      58              :    * Which reserve should we withdraw from?
      59              :    */
      60              :   const char *reserve_reference;
      61              : 
      62              :   /**
      63              :    * Reference to a withdraw or reveal operation from which we should
      64              :    * reuse the private coin key, or NULL for regular withdrawal.
      65              :    */
      66              :   const char *reuse_coin_key_ref;
      67              : 
      68              :   /**
      69              :    * If true and @e reuse_coin_key_ref is not NULL, also reuses
      70              :    * the blinding_seed.
      71              :    */
      72              :   bool reuse_blinding_seed;
      73              : 
      74              :   /**
      75              :    * Our command.
      76              :    */
      77              :   const struct TALER_TESTING_Command *cmd;
      78              : 
      79              :   /**
      80              :    * String describing the denomination value we should withdraw.
      81              :    * A corresponding denomination key must exist in the exchange's
      82              :    * offerings.  Can be NULL if @e pk is set instead.
      83              :    */
      84              :   struct TALER_Amount amount;
      85              : 
      86              :   /**
      87              :    * If @e amount is NULL, this specifies the denomination key to
      88              :    * use.  Otherwise, this will be set (by the interpreter) to the
      89              :    * denomination PK matching @e amount.
      90              :    */
      91              :   struct TALER_EXCHANGE_DenomPublicKey *pk;
      92              : 
      93              :   /**
      94              :    * Exchange base URL.  Only used as offered trait.
      95              :    */
      96              :   char *exchange_url;
      97              : 
      98              :   /**
      99              :    * URI if the reserve we are withdrawing from.
     100              :    */
     101              :   struct TALER_NormalizedPayto reserve_payto_uri;
     102              : 
     103              :   /**
     104              :    * Private key of the reserve we are withdrawing from.
     105              :    */
     106              :   struct TALER_ReservePrivateKeyP reserve_priv;
     107              : 
     108              :   /**
     109              :    * Public key of the reserve we are withdrawing from.
     110              :    */
     111              :   struct TALER_ReservePublicKeyP reserve_pub;
     112              : 
     113              :   /**
     114              :    * Private key of the coin.
     115              :    */
     116              :   struct TALER_CoinSpendPrivateKeyP coin_priv;
     117              : 
     118              :   /**
     119              :    * Public key of the coin.
     120              :    */
     121              :   struct TALER_CoinSpendPublicKeyP coin_pub;
     122              : 
     123              :   /**
     124              :    * Blinding key used during the operation.
     125              :    */
     126              :   union GNUNET_CRYPTO_BlindingSecretP bks;
     127              : 
     128              :   /**
     129              :    * Values contributed from the exchange during the
     130              :    * withdraw protocol.
     131              :    */
     132              :   struct TALER_ExchangeBlindingValues exchange_vals;
     133              : 
     134              :   /**
     135              :    * Interpreter state (during command).
     136              :    */
     137              :   struct TALER_TESTING_Interpreter *is;
     138              : 
     139              :   /**
     140              :    * Set (by the interpreter) to the exchange's signature over the
     141              :    * coin's public key.
     142              :    */
     143              :   struct TALER_DenominationSignature sig;
     144              : 
     145              :   /**
     146              :    * Seed for the key material of the coin, set by the interpreter.
     147              :    */
     148              :   struct TALER_WithdrawMasterSeedP seed;
     149              : 
     150              :   /**
     151              :    * Blinding seed for the blinding preparation for CS.
     152              :    */
     153              :   struct TALER_BlindingMasterSeedP blinding_seed;
     154              : 
     155              :   /**
     156              :    * An age > 0 signifies age restriction is required
     157              :    */
     158              :   uint8_t age;
     159              : 
     160              :   /**
     161              :    * If age > 0, put here the corresponding age commitment with its proof and
     162              :    * its hash, respectively.
     163              :    */
     164              :   struct TALER_AgeCommitmentProof age_commitment_proof;
     165              :   struct TALER_AgeCommitmentHashP h_age_commitment;
     166              : 
     167              :   /**
     168              :    * Reserve history entry that corresponds to this operation.
     169              :    * Will be of type #TALER_EXCHANGE_RTT_WITHDRAWAL.
     170              :    */
     171              :   struct TALER_EXCHANGE_ReserveHistoryEntry reserve_history;
     172              : 
     173              :   /**
     174              :    * Withdraw handle (while operation is running).
     175              :    */
     176              :   struct TALER_EXCHANGE_PostWithdrawHandle *wsh;
     177              : 
     178              :   /**
     179              :    * The commitment for the withdraw operation, later needed for /recoup
     180              :    */
     181              :   struct TALER_HashBlindedPlanchetsP planchets_h;
     182              : 
     183              :   /**
     184              :    * Task scheduled to try later.
     185              :    */
     186              :   struct GNUNET_SCHEDULER_Task *retry_task;
     187              : 
     188              :   /**
     189              :    * How long do we wait until we retry?
     190              :    */
     191              :   struct GNUNET_TIME_Relative backoff;
     192              : 
     193              :   /**
     194              :    * Total withdraw backoff applied.
     195              :    */
     196              :   struct GNUNET_TIME_Relative total_backoff;
     197              : 
     198              :   /**
     199              :    * Set to the KYC requirement payto hash *if* the exchange replied with a
     200              :    * request for KYC.
     201              :    */
     202              :   struct TALER_NormalizedPaytoHashP h_payto;
     203              : 
     204              :   /**
     205              :    * Set to the KYC requirement row *if* the exchange replied with
     206              :    * a request for KYC.
     207              :    */
     208              :   uint64_t requirement_row;
     209              : 
     210              :   /**
     211              :    * Expected HTTP response code to the request.
     212              :    */
     213              :   unsigned int expected_response_code;
     214              : 
     215              :   /**
     216              :    * Was this command modified via
     217              :    * #TALER_TESTING_cmd_withdraw_with_retry to
     218              :    * enable retries? How often should we still retry?
     219              :    */
     220              :   unsigned int do_retry;
     221              : };
     222              : 
     223              : 
     224              : /**
     225              :  * Run the command.
     226              :  *
     227              :  * @param cls closure.
     228              :  * @param cmd the commaind being run.
     229              :  * @param is interpreter state.
     230              :  */
     231              : static void
     232              : withdraw_run (void *cls,
     233              :               const struct TALER_TESTING_Command *cmd,
     234              :               struct TALER_TESTING_Interpreter *is);
     235              : 
     236              : 
     237              : /**
     238              :  * Task scheduled to re-try #withdraw_run.
     239              :  *
     240              :  * @param cls a `struct WithdrawState`
     241              :  */
     242              : static void
     243            0 : do_retry (void *cls)
     244              : {
     245            0 :   struct WithdrawState *ws = cls;
     246              : 
     247            0 :   ws->retry_task = NULL;
     248            0 :   TALER_TESTING_touch_cmd (ws->is);
     249            0 :   withdraw_run (ws,
     250              :                 NULL,
     251              :                 ws->is);
     252            0 : }
     253              : 
     254              : 
     255              : /**
     256              :  * "reserve withdraw" operation callback; checks that the
     257              :  * response code is expected and store the exchange signature
     258              :  * in the state.
     259              :  *
     260              :  * @param cls closure.
     261              :  * @param wr withdraw response details
     262              :  */
     263              : static void
     264           68 : withdraw_cb (void *cls,
     265              :              const struct TALER_EXCHANGE_PostWithdrawResponse *wr)
     266              : {
     267           68 :   struct WithdrawState *ws = cls;
     268           68 :   struct TALER_TESTING_Interpreter *is = ws->is;
     269              : 
     270           68 :   ws->wsh = NULL;
     271           68 :   if (ws->expected_response_code != wr->hr.http_status)
     272              :   {
     273            0 :     if (0 != ws->do_retry)
     274              :     {
     275            0 :       if (TALER_EC_EXCHANGE_GENERIC_RESERVE_UNKNOWN != wr->hr.ec)
     276            0 :         ws->do_retry--; /* we don't count reserve unknown as failures here */
     277            0 :       if ( (0 == wr->hr.http_status) ||
     278            0 :            (TALER_EC_GENERIC_DB_SOFT_FAILURE == wr->hr.ec) ||
     279            0 :            (TALER_EC_EXCHANGE_WITHDRAW_INSUFFICIENT_FUNDS == wr->hr.ec) ||
     280            0 :            (TALER_EC_EXCHANGE_GENERIC_RESERVE_UNKNOWN == wr->hr.ec) ||
     281            0 :            (MHD_HTTP_INTERNAL_SERVER_ERROR == wr->hr.http_status) )
     282              :       {
     283            0 :         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     284              :                     "Retrying withdraw failed with %u/%d\n",
     285              :                     wr->hr.http_status,
     286              :                     (int) wr->hr.ec);
     287              :         /* on DB conflicts, do not use backoff */
     288            0 :         if (TALER_EC_GENERIC_DB_SOFT_FAILURE == wr->hr.ec)
     289            0 :           ws->backoff = GNUNET_TIME_UNIT_ZERO;
     290            0 :         else if (TALER_EC_EXCHANGE_GENERIC_RESERVE_UNKNOWN != wr->hr.ec)
     291            0 :           ws->backoff = EXCHANGE_LIB_BACKOFF (ws->backoff);
     292              :         else
     293            0 :           ws->backoff = GNUNET_TIME_relative_max (UNKNOWN_MIN_BACKOFF,
     294              :                                                   ws->backoff);
     295            0 :         ws->backoff = GNUNET_TIME_relative_min (ws->backoff,
     296              :                                                 UNKNOWN_MAX_BACKOFF);
     297            0 :         ws->total_backoff = GNUNET_TIME_relative_add (ws->total_backoff,
     298              :                                                       ws->backoff);
     299            0 :         TALER_TESTING_inc_tries (ws->is);
     300            0 :         ws->retry_task = GNUNET_SCHEDULER_add_delayed (ws->backoff,
     301              :                                                        &do_retry,
     302              :                                                        ws);
     303            0 :         return;
     304              :       }
     305              :     }
     306            0 :     TALER_TESTING_unexpected_status_with_body (is,
     307              :                                                wr->hr.http_status,
     308              :                                                ws->expected_response_code,
     309              :                                                wr->hr.reply);
     310            0 :     return;
     311              :   }
     312           68 :   switch (wr->hr.http_status)
     313              :   {
     314           59 :   case MHD_HTTP_OK:
     315           59 :     GNUNET_assert (1 == wr->details.ok.num_sigs);
     316           59 :     TALER_denom_sig_copy (&ws->sig,
     317           59 :                           &wr->details.ok.coin_details[0].denom_sig);
     318           59 :     ws->coin_priv = wr->details.ok.coin_details[0].coin_priv;
     319           59 :     GNUNET_CRYPTO_eddsa_key_get_public (&ws->coin_priv.eddsa_priv,
     320              :                                         &ws->coin_pub.eddsa_pub);
     321           59 :     ws->bks = wr->details.ok.coin_details[0].blinding_key;
     322           59 :     TALER_denom_ewv_copy (&ws->exchange_vals,
     323           59 :                           &wr->details.ok.coin_details[0].blinding_values);
     324           59 :     ws->planchets_h = wr->details.ok.planchets_h;
     325           59 :     if (0<ws->age)
     326              :     {
     327              :       /* copy the age-commitment data */
     328           10 :       ws->h_age_commitment = wr->details.ok.coin_details[0].h_age_commitment;
     329           10 :       TALER_age_commitment_proof_deep_copy (
     330              :         &ws->age_commitment_proof,
     331           10 :         &wr->details.ok.coin_details[0].age_commitment_proof);
     332              :     }
     333              : 
     334           59 :     if (0 != ws->total_backoff.rel_value_us)
     335              :     {
     336            0 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     337              :                   "Total withdraw backoff for %s was %s\n",
     338              :                   ws->cmd->label,
     339              :                   GNUNET_STRINGS_relative_time_to_string (ws->total_backoff,
     340              :                                                           true));
     341              :     }
     342           59 :     break;
     343            0 :   case MHD_HTTP_FORBIDDEN:
     344              :     /* nothing to check */
     345            0 :     break;
     346            0 :   case MHD_HTTP_NOT_FOUND:
     347              :     /* nothing to check */
     348            0 :     break;
     349            5 :   case MHD_HTTP_CONFLICT:
     350              :     /* nothing to check */
     351            5 :     break;
     352            0 :   case MHD_HTTP_GONE:
     353              :     /* theoretically could check that the key was actually */
     354            0 :     break;
     355            4 :   case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
     356              :     /* KYC required */
     357            4 :     ws->requirement_row =
     358            4 :       wr->details.unavailable_for_legal_reasons.requirement_row;
     359              :     ws->h_payto
     360            4 :       = wr->details.unavailable_for_legal_reasons.h_payto;
     361            4 :     break;
     362            0 :   default:
     363              :     /* Unsupported status code (by test harness) */
     364            0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     365              :                 "Withdraw test command does not support status code %u\n",
     366              :                 wr->hr.http_status);
     367            0 :     GNUNET_break (0);
     368            0 :     break;
     369              :   }
     370           68 :   TALER_TESTING_interpreter_next (is);
     371              : }
     372              : 
     373              : 
     374              : /**
     375              :  * Run the command.
     376              :  */
     377              : static void
     378           68 : withdraw_run (void *cls,
     379              :               const struct TALER_TESTING_Command *cmd,
     380              :               struct TALER_TESTING_Interpreter *is)
     381              : {
     382           68 :   struct WithdrawState *ws = cls;
     383              :   const struct TALER_ReservePrivateKeyP *rp;
     384              :   const struct TALER_TESTING_Command *create_reserve;
     385              :   const struct TALER_EXCHANGE_DenomPublicKey *dpk;
     386              : 
     387           68 :   if (NULL != cmd)
     388           68 :     ws->cmd = cmd;
     389           68 :   ws->is = is;
     390              :   create_reserve
     391           68 :     = TALER_TESTING_interpreter_lookup_command (
     392              :         is,
     393              :         ws->reserve_reference);
     394           68 :   if (NULL == create_reserve)
     395              :   {
     396            0 :     GNUNET_break (0);
     397            0 :     TALER_TESTING_interpreter_fail (is);
     398            0 :     return;
     399              :   }
     400           68 :   if (GNUNET_OK !=
     401           68 :       TALER_TESTING_get_trait_reserve_priv (create_reserve,
     402              :                                             &rp))
     403              :   {
     404            0 :     GNUNET_break (0);
     405            0 :     TALER_TESTING_interpreter_fail (is);
     406            0 :     return;
     407              :   }
     408           68 :   if (NULL == ws->exchange_url)
     409              :     ws->exchange_url
     410           68 :       = GNUNET_strdup (TALER_TESTING_get_exchange_url (is));
     411           68 :   ws->reserve_priv = *rp;
     412           68 :   GNUNET_CRYPTO_eddsa_key_get_public (&ws->reserve_priv.eddsa_priv,
     413              :                                       &ws->reserve_pub.eddsa_pub);
     414              :   ws->reserve_payto_uri
     415           68 :     = TALER_reserve_make_payto (ws->exchange_url,
     416           68 :                                 &ws->reserve_pub);
     417              : 
     418           68 :   TALER_withdraw_master_seed_setup_random (&ws->seed);
     419           68 :   TALER_cs_withdraw_seed_to_blinding_seed (&ws->seed,
     420              :                                            &ws->blinding_seed);
     421              : 
     422              :   /**
     423              :    * In case of coin key material reuse, we _only_ reuse the
     424              :    * master seed, but the blinding seed is still randomly chosen,
     425              :    * see the lines prior to this.
     426              :    */
     427           68 :   if (NULL != ws->reuse_coin_key_ref)
     428              :   {
     429              :     const struct TALER_WithdrawMasterSeedP *seed;
     430              :     const struct TALER_TESTING_Command *cref;
     431              :     char *cstr;
     432              :     unsigned int index;
     433              : 
     434            6 :     GNUNET_assert (GNUNET_OK ==
     435              :                    TALER_TESTING_parse_coin_reference (
     436              :                      ws->reuse_coin_key_ref,
     437              :                      &cstr,
     438              :                      &index));
     439            6 :     cref = TALER_TESTING_interpreter_lookup_command (is,
     440              :                                                      cstr);
     441            6 :     GNUNET_assert (NULL != cref);
     442            6 :     GNUNET_free (cstr);
     443            6 :     GNUNET_assert (GNUNET_OK ==
     444              :                    TALER_TESTING_get_trait_withdraw_seed (cref,
     445              :                                                           &seed));
     446            6 :     ws->seed = *seed;
     447              : 
     448            6 :     if (ws->reuse_blinding_seed)
     449            2 :       TALER_cs_withdraw_seed_to_blinding_seed (&ws->seed,
     450              :                                                &ws->blinding_seed);
     451              :   }
     452              : 
     453           68 :   if (NULL == ws->pk)
     454              :   {
     455           68 :     dpk = TALER_TESTING_find_pk (TALER_TESTING_get_keys (is),
     456           68 :                                  &ws->amount,
     457           68 :                                  ws->age > 0);
     458           68 :     if (NULL == dpk)
     459              :     {
     460            0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     461              :                   "Failed to determine denomination key at %s\n",
     462              :                   (NULL != cmd) ? cmd->label : "<retried command>");
     463            0 :       GNUNET_break (0);
     464            0 :       TALER_TESTING_interpreter_fail (is);
     465            0 :       return;
     466              :     }
     467              :     /* We copy the denomination key, as re-querying /keys
     468              :      * would free the old one. */
     469           68 :     ws->pk = TALER_EXCHANGE_copy_denomination_key (dpk);
     470              :   }
     471              :   else
     472              :   {
     473            0 :     ws->amount = ws->pk->value;
     474              :   }
     475              : 
     476           68 :   ws->reserve_history.type = TALER_EXCHANGE_RTT_WITHDRAWAL;
     477           68 :   GNUNET_assert (0 <=
     478              :                  TALER_amount_add (&ws->reserve_history.amount,
     479              :                                    &ws->amount,
     480              :                                    &ws->pk->fees.withdraw));
     481           68 :   ws->reserve_history.details.withdraw.fee =
     482           68 :     ws->pk->fees.withdraw;
     483              : 
     484           68 :   ws->wsh = TALER_EXCHANGE_post_withdraw_create (
     485              :     TALER_TESTING_interpreter_get_context (is),
     486              :     TALER_TESTING_get_exchange_url (is),
     487              :     TALER_TESTING_get_keys (is),
     488              :     rp,
     489              :     1,
     490           68 :     ws->pk,
     491           68 :     &ws->seed,
     492           68 :     ws->age);
     493           68 :   if (NULL == ws->wsh)
     494              :   {
     495            0 :     GNUNET_break (0);
     496            0 :     TALER_TESTING_interpreter_fail (is);
     497            0 :     return;
     498              :   }
     499           68 :   GNUNET_assert (GNUNET_OK ==
     500              :                  TALER_EXCHANGE_post_withdraw_set_options (
     501              :                    ws->wsh,
     502              :                    TALER_EXCHANGE_post_withdraw_option_blinding_seed (
     503              :                      &ws->blinding_seed)));
     504           68 :   GNUNET_assert (TALER_EC_NONE ==
     505              :                  TALER_EXCHANGE_post_withdraw_start (ws->wsh,
     506              :                                                      &withdraw_cb,
     507              :                                                      ws));
     508              : }
     509              : 
     510              : 
     511              : /**
     512              :  * Free the state of a "withdraw" CMD, and possibly cancel
     513              :  * a pending operation thereof.
     514              :  *
     515              :  * @param cls closure.
     516              :  * @param cmd the command being freed.
     517              :  */
     518              : static void
     519           68 : withdraw_cleanup (void *cls,
     520              :                   const struct TALER_TESTING_Command *cmd)
     521              : {
     522           68 :   struct WithdrawState *ws = cls;
     523              : 
     524           68 :   if (NULL != ws->wsh)
     525              :   {
     526            0 :     TALER_TESTING_command_incomplete (ws->is,
     527              :                                       cmd->label);
     528            0 :     TALER_EXCHANGE_post_withdraw_cancel (ws->wsh);
     529            0 :     ws->wsh = NULL;
     530              :   }
     531           68 :   if (NULL != ws->retry_task)
     532              :   {
     533            0 :     GNUNET_SCHEDULER_cancel (ws->retry_task);
     534            0 :     ws->retry_task = NULL;
     535              :   }
     536           68 :   TALER_denom_sig_free (&ws->sig);
     537           68 :   TALER_denom_ewv_free (&ws->exchange_vals);
     538           68 :   if (NULL != ws->pk)
     539              :   {
     540           68 :     TALER_EXCHANGE_destroy_denomination_key (ws->pk);
     541           68 :     ws->pk = NULL;
     542              :   }
     543           68 :   if (ws->age > 0)
     544           10 :     TALER_age_commitment_proof_free (&ws->age_commitment_proof);
     545           68 :   GNUNET_free (ws->exchange_url);
     546           68 :   GNUNET_free (ws->reserve_payto_uri.normalized_payto);
     547           68 :   GNUNET_free (ws);
     548           68 : }
     549              : 
     550              : 
     551              : /**
     552              :  * Offer internal data to a "withdraw" CMD state to other
     553              :  * commands.
     554              :  *
     555              :  * @param cls closure
     556              :  * @param[out] ret result (could be anything)
     557              :  * @param trait name of the trait
     558              :  * @param index index number of the object to offer.
     559              :  * @return #GNUNET_OK on success
     560              :  */
     561              : static enum GNUNET_GenericReturnValue
     562         1833 : withdraw_traits (void *cls,
     563              :                  const void **ret,
     564              :                  const char *trait,
     565              :                  unsigned int index)
     566              : {
     567         1833 :   struct WithdrawState *ws = cls;
     568              :   struct TALER_TESTING_Trait traits[] = {
     569              :     /* history entry MUST be first due to response code logic below! */
     570         1833 :     TALER_TESTING_make_trait_reserve_history (0 /* only one coin */,
     571         1833 :                                               &ws->reserve_history),
     572         1833 :     TALER_TESTING_make_trait_coin_priv (0 /* only one coin */,
     573         1833 :                                         &ws->coin_priv),
     574         1833 :     TALER_TESTING_make_trait_coin_pub (0 /* only one coin */,
     575         1833 :                                        &ws->coin_pub),
     576         1833 :     TALER_TESTING_make_trait_withdraw_seed (&ws->seed),
     577         1833 :     TALER_TESTING_make_trait_blinding_seed (&ws->blinding_seed),
     578         1833 :     TALER_TESTING_make_trait_withdraw_commitment (&ws->planchets_h),
     579         1833 :     TALER_TESTING_make_trait_blinding_key (0 /* only one coin */,
     580         1833 :                                            &ws->bks),
     581         1833 :     TALER_TESTING_make_trait_exchange_blinding_values (0 /* only one coin */,
     582         1833 :                                                        &ws->exchange_vals),
     583         1833 :     TALER_TESTING_make_trait_denom_pub (0 /* only one coin */,
     584         1833 :                                         ws->pk),
     585         1833 :     TALER_TESTING_make_trait_denom_sig (0 /* only one coin */,
     586         1833 :                                         &ws->sig),
     587         1833 :     TALER_TESTING_make_trait_reserve_priv (&ws->reserve_priv),
     588         1833 :     TALER_TESTING_make_trait_reserve_pub (&ws->reserve_pub),
     589         1833 :     TALER_TESTING_make_trait_amount (&ws->amount),
     590         1833 :     TALER_TESTING_make_trait_legi_requirement_row (&ws->requirement_row),
     591         1833 :     TALER_TESTING_make_trait_h_normalized_payto (&ws->h_payto),
     592         1833 :     TALER_TESTING_make_trait_normalized_payto_uri (&ws->reserve_payto_uri),
     593         1833 :     TALER_TESTING_make_trait_exchange_url (ws->exchange_url),
     594         1833 :     TALER_TESTING_make_trait_age_commitment_proof (0,
     595         1833 :                                                    0 < ws->age
     596              :                                                    ? &ws->age_commitment_proof
     597              :                                                    : NULL),
     598         1833 :     TALER_TESTING_make_trait_h_age_commitment (0,
     599         1833 :                                                0 < ws->age
     600              :                                                ? &ws->h_age_commitment
     601              :                                                : NULL),
     602         1833 :     TALER_TESTING_trait_end ()
     603              :   };
     604              : 
     605         1833 :   return TALER_TESTING_get_trait ((ws->expected_response_code == MHD_HTTP_OK)
     606              :                                   ? &traits[0]   /* we have reserve history */
     607              :                                   : &traits[1],  /* skip reserve history */
     608              :                                   ret,
     609              :                                   trait,
     610              :                                   index);
     611              : }
     612              : 
     613              : 
     614              : struct TALER_TESTING_Command
     615           68 : TALER_TESTING_cmd_withdraw_amount (const char *label,
     616              :                                    const char *reserve_reference,
     617              :                                    const char *amount,
     618              :                                    uint8_t age,
     619              :                                    unsigned int expected_response_code)
     620              : {
     621              :   struct WithdrawState *ws;
     622              : 
     623           68 :   ws = GNUNET_new (struct WithdrawState);
     624           68 :   ws->age = age;
     625           68 :   ws->reserve_reference = reserve_reference;
     626           68 :   if (GNUNET_OK !=
     627           68 :       TALER_string_to_amount (amount,
     628              :                               &ws->amount))
     629              :   {
     630            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     631              :                 "Failed to parse amount `%s' at %s\n",
     632              :                 amount,
     633              :                 label);
     634            0 :     GNUNET_assert (0);
     635              :   }
     636           68 :   ws->expected_response_code = expected_response_code;
     637              :   {
     638           68 :     struct TALER_TESTING_Command cmd = {
     639              :       .cls = ws,
     640              :       .label = label,
     641              :       .run = &withdraw_run,
     642              :       .cleanup = &withdraw_cleanup,
     643              :       .traits = &withdraw_traits
     644              :     };
     645              : 
     646           68 :     return cmd;
     647              :   }
     648              : }
     649              : 
     650              : 
     651              : struct TALER_TESTING_Command
     652            4 : TALER_TESTING_cmd_withdraw_amount_reuse_key (
     653              :   const char *label,
     654              :   const char *reserve_reference,
     655              :   const char *amount,
     656              :   uint8_t age,
     657              :   const char *coin_ref,
     658              :   unsigned int expected_response_code)
     659              : {
     660              :   struct TALER_TESTING_Command cmd;
     661              : 
     662            4 :   cmd = TALER_TESTING_cmd_withdraw_amount (label,
     663              :                                            reserve_reference,
     664              :                                            amount,
     665              :                                            age,
     666              :                                            expected_response_code);
     667              :   {
     668            4 :     struct WithdrawState *ws = cmd.cls;
     669              : 
     670            4 :     ws->reuse_coin_key_ref = coin_ref;
     671              :   }
     672            4 :   return cmd;
     673              : }
     674              : 
     675              : 
     676              : struct TALER_TESTING_Command
     677            2 : TALER_TESTING_cmd_withdraw_amount_reuse_all_secrets (
     678              :   const char *label,
     679              :   const char *reserve_reference,
     680              :   const char *amount,
     681              :   uint8_t age,
     682              :   const char *coin_ref,
     683              :   unsigned int expected_response_code)
     684              : {
     685              :   struct TALER_TESTING_Command cmd;
     686              : 
     687            2 :   cmd = TALER_TESTING_cmd_withdraw_amount (label,
     688              :                                            reserve_reference,
     689              :                                            amount,
     690              :                                            age,
     691              :                                            expected_response_code);
     692              :   {
     693            2 :     struct WithdrawState *ws = cmd.cls;
     694              : 
     695            2 :     ws->reuse_coin_key_ref = coin_ref;
     696            2 :     ws->reuse_blinding_seed = true;
     697              :   }
     698            2 :   return cmd;
     699              : }
     700              : 
     701              : 
     702              : struct TALER_TESTING_Command
     703            0 : TALER_TESTING_cmd_withdraw_denomination (
     704              :   const char *label,
     705              :   const char *reserve_reference,
     706              :   const struct TALER_EXCHANGE_DenomPublicKey *dk,
     707              :   unsigned int expected_response_code)
     708              : {
     709              :   struct WithdrawState *ws;
     710              : 
     711            0 :   if (NULL == dk)
     712              :   {
     713            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     714              :                 "Denomination key not specified at %s\n",
     715              :                 label);
     716            0 :     GNUNET_assert (0);
     717              :   }
     718            0 :   ws = GNUNET_new (struct WithdrawState);
     719            0 :   ws->reserve_reference = reserve_reference;
     720            0 :   ws->pk = TALER_EXCHANGE_copy_denomination_key (dk);
     721            0 :   ws->expected_response_code = expected_response_code;
     722              :   {
     723            0 :     struct TALER_TESTING_Command cmd = {
     724              :       .cls = ws,
     725              :       .label = label,
     726              :       .run = &withdraw_run,
     727              :       .cleanup = &withdraw_cleanup,
     728              :       .traits = &withdraw_traits
     729              :     };
     730              : 
     731            0 :     return cmd;
     732              :   }
     733              : }
     734              : 
     735              : 
     736              : struct TALER_TESTING_Command
     737            0 : TALER_TESTING_cmd_withdraw_with_retry (struct TALER_TESTING_Command cmd)
     738              : {
     739              :   struct WithdrawState *ws;
     740              : 
     741            0 :   GNUNET_assert (&withdraw_run == cmd.run);
     742            0 :   ws = cmd.cls;
     743            0 :   ws->do_retry = NUM_RETRIES;
     744            0 :   return cmd;
     745              : }
     746              : 
     747              : 
     748              : /* end of testing_api_cmd_withdraw.c */
        

Generated by: LCOV version 2.0-1