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

Generated by: LCOV version 2.0-1