LCOV - code coverage report
Current view: top level - testing - testing_api_cmd_withdraw.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 136 210 64.8 %
Date: 2025-06-05 21:03:14 Functions: 7 10 70.0 %

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

Generated by: LCOV version 1.16