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

Generated by: LCOV version 2.0-1