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

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

Generated by: LCOV version 1.14