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

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 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_purse_deposit.c
      21             :  * @brief command for testing /purses/$PID/create
      22             :  * @author Christian Grothoff
      23             :  */
      24             : #include "platform.h"
      25             : #include "taler_json_lib.h"
      26             : #include <gnunet/gnunet_curl_lib.h>
      27             : #include "taler_testing_lib.h"
      28             : #include "taler_signatures.h"
      29             : #include "backoff.h"
      30             : 
      31             : /**
      32             :  * Information we keep per deposited coin.
      33             :  */
      34             : struct Coin
      35             : {
      36             :   /**
      37             :    * Reference to the respective command.
      38             :    */
      39             :   char *command_ref;
      40             : 
      41             :   /**
      42             :    * index of the specific coin in the traits of @e command_ref.
      43             :    */
      44             :   unsigned int coin_index;
      45             : 
      46             :   /**
      47             :    * Amount to deposit (with fee).
      48             :    */
      49             :   struct TALER_Amount deposit_with_fee;
      50             : 
      51             : };
      52             : 
      53             : 
      54             : /**
      55             :  * State for a "purse deposit" CMD.
      56             :  */
      57             : struct PurseDepositState
      58             : {
      59             : 
      60             :   /**
      61             :    * Total purse target amount without fees.
      62             :    */
      63             :   struct TALER_Amount target_amount;
      64             : 
      65             :   /**
      66             :    * Reference to any command that is able to provide a coin.
      67             :    */
      68             :   struct Coin *coin_references;
      69             : 
      70             :   /**
      71             :    * The purse's public key.
      72             :    */
      73             :   struct TALER_PurseContractPublicKeyP purse_pub;
      74             : 
      75             :   /**
      76             :    * The reserve we are being deposited into.
      77             :    * Set as a trait once we know the reserve.
      78             :    */
      79             :   struct TALER_ReservePublicKeyP reserve_pub;
      80             : 
      81             :   /**
      82             :    * PurseDeposit handle while operation is running.
      83             :    */
      84             :   struct TALER_EXCHANGE_PurseDepositHandle *dh;
      85             : 
      86             :   /**
      87             :    * Interpreter state.
      88             :    */
      89             :   struct TALER_TESTING_Interpreter *is;
      90             : 
      91             :   /**
      92             :    * Reference to the command that established the purse.
      93             :    */
      94             :   const char *purse_ref;
      95             : 
      96             :   /**
      97             :    * Reserve history entry that corresponds to this operation.
      98             :    * Will be of type #TALER_EXCHANGE_RTT_MERGE.
      99             :    * Only valid if @e purse_complete is true.
     100             :    */
     101             :   struct TALER_EXCHANGE_ReserveHistoryEntry reserve_history;
     102             :   /**
     103             :    * Expected HTTP response code.
     104             :    */
     105             :   unsigned int expected_response_code;
     106             : 
     107             :   /**
     108             :    * Length of the @e coin_references array.
     109             :    */
     110             :   unsigned int num_coin_references;
     111             : 
     112             :   /**
     113             :    * Minimum age to apply to all deposits.
     114             :    */
     115             :   uint8_t min_age;
     116             : 
     117             :   /**
     118             :    * Set to true if this deposit filled the purse.
     119             :    */
     120             :   bool purse_complete;
     121             : };
     122             : 
     123             : 
     124             : /**
     125             :  * Callback to analyze the /purses/$PID/deposit response, just used to check if
     126             :  * the response code is acceptable.
     127             :  *
     128             :  * @param cls closure.
     129             :  * @param dr deposit response details
     130             :  */
     131             : static void
     132           0 : deposit_cb (void *cls,
     133             :             const struct TALER_EXCHANGE_PurseDepositResponse *dr)
     134             : {
     135           0 :   struct PurseDepositState *ds = cls;
     136             : 
     137           0 :   ds->dh = NULL;
     138           0 :   if (ds->expected_response_code != dr->hr.http_status)
     139             :   {
     140           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     141             :                 "Unexpected response code %u to command %s in %s:%u\n",
     142             :                 dr->hr.http_status,
     143             :                 ds->is->commands[ds->is->ip].label,
     144             :                 __FILE__,
     145             :                 __LINE__);
     146           0 :     json_dumpf (dr->hr.reply,
     147             :                 stderr,
     148             :                 JSON_INDENT (2));
     149           0 :     TALER_TESTING_interpreter_fail (ds->is);
     150           0 :     return;
     151             :   }
     152           0 :   if (MHD_HTTP_OK == dr->hr.http_status)
     153             :   {
     154           0 :     if (-1 !=
     155           0 :         TALER_amount_cmp (&dr->details.success.total_deposited,
     156             :                           &dr->details.success.purse_value_after_fees))
     157             :     {
     158             :       const struct TALER_TESTING_Command *purse_cmd;
     159             :       const struct TALER_ReserveSignatureP *reserve_sig;
     160             :       const struct TALER_ReservePublicKeyP *reserve_pub;
     161             :       const struct GNUNET_TIME_Timestamp *merge_timestamp;
     162             :       const struct TALER_PurseMergePublicKeyP *merge_pub;
     163             : 
     164           0 :       purse_cmd = TALER_TESTING_interpreter_lookup_command (ds->is,
     165             :                                                             ds->purse_ref);
     166             : 
     167           0 :       if (GNUNET_OK !=
     168           0 :           TALER_TESTING_get_trait_reserve_sig (purse_cmd,
     169             :                                                &reserve_sig))
     170             :       {
     171           0 :         GNUNET_break (0);
     172           0 :         TALER_TESTING_interpreter_fail (ds->is);
     173           0 :         return;
     174             :       }
     175           0 :       if (GNUNET_OK !=
     176           0 :           TALER_TESTING_get_trait_reserve_pub (purse_cmd,
     177             :                                                &reserve_pub))
     178             :       {
     179           0 :         GNUNET_break (0);
     180           0 :         TALER_TESTING_interpreter_fail (ds->is);
     181           0 :         return;
     182             :       }
     183           0 :       if (GNUNET_OK !=
     184           0 :           TALER_TESTING_get_trait_merge_pub (purse_cmd,
     185             :                                              &merge_pub))
     186             :       {
     187           0 :         GNUNET_break (0);
     188           0 :         TALER_TESTING_interpreter_fail (ds->is);
     189           0 :         return;
     190             :       }
     191           0 :       ds->reserve_pub = *reserve_pub;
     192           0 :       if (GNUNET_OK !=
     193           0 :           TALER_TESTING_get_trait_timestamp (purse_cmd,
     194             :                                              0,
     195             :                                              &merge_timestamp))
     196             :       {
     197           0 :         GNUNET_break (0);
     198           0 :         TALER_TESTING_interpreter_fail (ds->is);
     199           0 :         return;
     200             :       }
     201             : 
     202             :       /* Deposits complete, create trait! */
     203           0 :       ds->reserve_history.type = TALER_EXCHANGE_RTT_MERGE;
     204             :       {
     205             :         const struct TALER_EXCHANGE_Keys *keys;
     206             :         const struct TALER_EXCHANGE_GlobalFee *gf;
     207             : 
     208           0 :         keys = TALER_EXCHANGE_get_keys (ds->is->exchange);
     209           0 :         GNUNET_assert (NULL != keys);
     210           0 :         gf = TALER_EXCHANGE_get_global_fee (keys,
     211             :                                             *merge_timestamp);
     212           0 :         GNUNET_assert (NULL != gf);
     213             : 
     214             :         /* Note: change when flags below changes! */
     215             :         ds->reserve_history.amount
     216           0 :           = dr->details.success.purse_value_after_fees;
     217             :         if (true)
     218             :         {
     219           0 :           ds->reserve_history.details.merge_details.purse_fee = gf->fees.purse;
     220             :         }
     221             :         else
     222             :         {
     223             :           TALER_amount_set_zero (
     224             :             ds->reserve_history.amount.currency,
     225             :             &ds->reserve_history.details.merge_details.purse_fee);
     226             :         }
     227             :       }
     228             :       ds->reserve_history.details.merge_details.h_contract_terms
     229           0 :         = dr->details.success.h_contract_terms;
     230             :       ds->reserve_history.details.merge_details.merge_pub
     231           0 :         = *merge_pub;
     232             :       ds->reserve_history.details.merge_details.purse_pub
     233           0 :         = ds->purse_pub;
     234             :       ds->reserve_history.details.merge_details.reserve_sig
     235           0 :         = *reserve_sig;
     236             :       ds->reserve_history.details.merge_details.merge_timestamp
     237           0 :         = *merge_timestamp;
     238             :       ds->reserve_history.details.merge_details.purse_expiration
     239           0 :         = dr->details.success.purse_expiration;
     240             :       ds->reserve_history.details.merge_details.min_age
     241           0 :         = ds->min_age;
     242             :       ds->reserve_history.details.merge_details.flags
     243           0 :         = TALER_WAMF_MODE_CREATE_WITH_PURSE_FEE;
     244           0 :       ds->purse_complete = true;
     245             :     }
     246             :   }
     247           0 :   TALER_TESTING_interpreter_next (ds->is);
     248             : }
     249             : 
     250             : 
     251             : /**
     252             :  * Run the command.
     253             :  *
     254             :  * @param cls closure.
     255             :  * @param cmd the command to execute.
     256             :  * @param is the interpreter state.
     257             :  */
     258             : static void
     259           0 : deposit_run (void *cls,
     260             :              const struct TALER_TESTING_Command *cmd,
     261             :              struct TALER_TESTING_Interpreter *is)
     262           0 : {
     263           0 :   struct PurseDepositState *ds = cls;
     264           0 :   struct TALER_EXCHANGE_PurseDeposit deposits[ds->num_coin_references];
     265             :   const struct TALER_PurseContractPublicKeyP *purse_pub;
     266             :   const struct TALER_TESTING_Command *purse_cmd;
     267             : 
     268             :   (void) cmd;
     269           0 :   ds->is = is;
     270             : 
     271           0 :   purse_cmd = TALER_TESTING_interpreter_lookup_command (is,
     272             :                                                         ds->purse_ref);
     273           0 :   if (GNUNET_OK !=
     274           0 :       TALER_TESTING_get_trait_purse_pub (purse_cmd,
     275             :                                          &purse_pub))
     276             :   {
     277           0 :     GNUNET_break (0);
     278           0 :     TALER_TESTING_interpreter_fail (is);
     279           0 :     return;
     280             :   }
     281           0 :   ds->purse_pub = *purse_pub;
     282           0 :   for (unsigned int i = 0; i<ds->num_coin_references; i++)
     283             :   {
     284           0 :     const struct Coin *cr = &ds->coin_references[i];
     285           0 :     struct TALER_EXCHANGE_PurseDeposit *pd = &deposits[i];
     286             :     const struct TALER_TESTING_Command *coin_cmd;
     287             :     const struct TALER_CoinSpendPrivateKeyP *coin_priv;
     288           0 :     const struct TALER_AgeCommitmentProof *age_commitment_proof = NULL;
     289             :     const struct TALER_EXCHANGE_DenomPublicKey *denom_pub;
     290             :     const struct TALER_DenominationSignature *denom_pub_sig;
     291             : 
     292           0 :     coin_cmd = TALER_TESTING_interpreter_lookup_command (is,
     293           0 :                                                          cr->command_ref);
     294           0 :     if (NULL == coin_cmd)
     295             :     {
     296           0 :       GNUNET_break (0);
     297           0 :       TALER_TESTING_interpreter_fail (is);
     298           0 :       return;
     299             :     }
     300             : 
     301           0 :     if ( (GNUNET_OK !=
     302           0 :           TALER_TESTING_get_trait_coin_priv (coin_cmd,
     303             :                                              cr->coin_index,
     304           0 :                                              &coin_priv)) ||
     305             :          (GNUNET_OK !=
     306           0 :           TALER_TESTING_get_trait_age_commitment_proof (coin_cmd,
     307             :                                                         cr->coin_index,
     308             :                                                         &age_commitment_proof))
     309           0 :          ||
     310             :          (GNUNET_OK !=
     311           0 :           TALER_TESTING_get_trait_denom_pub (coin_cmd,
     312             :                                              cr->coin_index,
     313           0 :                                              &denom_pub)) ||
     314             :          (GNUNET_OK !=
     315           0 :           TALER_TESTING_get_trait_denom_sig (coin_cmd,
     316             :                                              cr->coin_index,
     317             :                                              &denom_pub_sig)) )
     318             :     {
     319           0 :       GNUNET_break (0);
     320           0 :       TALER_TESTING_interpreter_fail (is);
     321           0 :       return;
     322             :     }
     323           0 :     pd->age_commitment_proof = age_commitment_proof;
     324           0 :     pd->denom_sig = *denom_pub_sig;
     325           0 :     pd->coin_priv = *coin_priv;
     326           0 :     pd->amount = cr->deposit_with_fee;
     327           0 :     pd->h_denom_pub = denom_pub->h_key;
     328             :   }
     329             : 
     330           0 :   ds->dh = TALER_EXCHANGE_purse_deposit (
     331             :     is->exchange,
     332             :     NULL, /* FIXME #7271: WADs support: purse exchange URL */
     333           0 :     &ds->purse_pub,
     334           0 :     ds->min_age,
     335             :     ds->num_coin_references,
     336             :     deposits,
     337             :     &deposit_cb,
     338             :     ds);
     339           0 :   if (NULL == ds->dh)
     340             :   {
     341           0 :     GNUNET_break (0);
     342           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     343             :                 "Could not deposit into purse\n");
     344           0 :     TALER_TESTING_interpreter_fail (is);
     345           0 :     return;
     346             :   }
     347             : }
     348             : 
     349             : 
     350             : /**
     351             :  * Free the state of a "deposit" CMD, and possibly cancel a
     352             :  * pending operation thereof.
     353             :  *
     354             :  * @param cls closure, must be a `struct PurseDepositState`.
     355             :  * @param cmd the command which is being cleaned up.
     356             :  */
     357             : static void
     358           0 : deposit_cleanup (void *cls,
     359             :                  const struct TALER_TESTING_Command *cmd)
     360             : {
     361           0 :   struct PurseDepositState *ds = cls;
     362             : 
     363           0 :   if (NULL != ds->dh)
     364             :   {
     365           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     366             :                 "Command %u (%s) did not complete\n",
     367             :                 ds->is->ip,
     368             :                 cmd->label);
     369           0 :     TALER_EXCHANGE_purse_deposit_cancel (ds->dh);
     370           0 :     ds->dh = NULL;
     371             :   }
     372           0 :   for (unsigned int i = 0; i<ds->num_coin_references; i++)
     373           0 :     GNUNET_free (ds->coin_references[i].command_ref);
     374           0 :   GNUNET_free (ds->coin_references);
     375           0 :   GNUNET_free (ds);
     376           0 : }
     377             : 
     378             : 
     379             : /**
     380             :  * Offer internal data from a "deposit" CMD, to other commands.
     381             :  *
     382             :  * @param cls closure.
     383             :  * @param[out] ret result.
     384             :  * @param trait name of the trait.
     385             :  * @param index index number of the object to offer.
     386             :  * @return #GNUNET_OK on success.
     387             :  */
     388             : static enum GNUNET_GenericReturnValue
     389           0 : deposit_traits (void *cls,
     390             :                 const void **ret,
     391             :                 const char *trait,
     392             :                 unsigned int index)
     393             : {
     394           0 :   struct PurseDepositState *ds = cls;
     395             :   struct TALER_TESTING_Trait traits[] = {
     396             :     /* history entry MUST be first due to response code logic below! */
     397           0 :     TALER_TESTING_make_trait_reserve_history (0,
     398           0 :                                               &ds->reserve_history),
     399           0 :     TALER_TESTING_make_trait_reserve_pub (&ds->reserve_pub),
     400           0 :     TALER_TESTING_make_trait_purse_pub (&ds->purse_pub),
     401           0 :     TALER_TESTING_trait_end ()
     402             :   };
     403             : 
     404           0 :   return TALER_TESTING_get_trait (ds->purse_complete
     405             :                                   ? &traits[0]   /* we have reserve history */
     406             :                                   : &traits[1],  /* skip reserve history */
     407             :                                   ret,
     408             :                                   trait,
     409             :                                   index);
     410             : }
     411             : 
     412             : 
     413             : struct TALER_TESTING_Command
     414           0 : TALER_TESTING_cmd_purse_deposit_coins (
     415             :   const char *label,
     416             :   unsigned int expected_http_status,
     417             :   uint8_t min_age,
     418             :   const char *purse_ref,
     419             :   ...)
     420             : {
     421             :   struct PurseDepositState *ds;
     422             : 
     423           0 :   ds = GNUNET_new (struct PurseDepositState);
     424           0 :   ds->expected_response_code = expected_http_status;
     425           0 :   ds->min_age = min_age;
     426           0 :   ds->purse_ref = purse_ref;
     427             :   {
     428             :     va_list ap;
     429             :     unsigned int i;
     430             :     const char *ref;
     431             :     const char *val;
     432             : 
     433           0 :     va_start (ap, purse_ref);
     434           0 :     while (NULL != (va_arg (ap, const char *)))
     435           0 :       ds->num_coin_references++;
     436           0 :     va_end (ap);
     437           0 :     GNUNET_assert (0 == (ds->num_coin_references % 2));
     438           0 :     ds->num_coin_references /= 2;
     439           0 :     ds->coin_references = GNUNET_new_array (ds->num_coin_references,
     440             :                                             struct Coin);
     441           0 :     i = 0;
     442           0 :     va_start (ap, purse_ref);
     443           0 :     while (NULL != (ref = va_arg (ap, const char *)))
     444             :     {
     445           0 :       struct Coin *c = &ds->coin_references[i++];
     446             : 
     447           0 :       GNUNET_assert (NULL != (val = va_arg (ap, const char *)));
     448           0 :       GNUNET_assert (GNUNET_OK ==
     449             :                      TALER_TESTING_parse_coin_reference (
     450             :                        ref,
     451             :                        &c->command_ref,
     452             :                        &c->coin_index));
     453           0 :       GNUNET_assert (GNUNET_OK ==
     454             :                      TALER_string_to_amount (val,
     455             :                                              &c->deposit_with_fee));
     456             :     }
     457           0 :     va_end (ap);
     458             :   }
     459             :   {
     460           0 :     struct TALER_TESTING_Command cmd = {
     461             :       .cls = ds,
     462             :       .label = label,
     463             :       .run = &deposit_run,
     464             :       .cleanup = &deposit_cleanup,
     465             :       .traits = &deposit_traits
     466             :     };
     467             : 
     468           0 :     return cmd;
     469             :   }
     470             : }
     471             : 
     472             : 
     473             : /* end of testing_api_cmd_purse_deposit.c */

Generated by: LCOV version 1.14