LCOV - code coverage report
Current view: top level - testing - testing_api_cmd_purse_create_deposit.c (source / functions) Hit Total Coverage
Test: GNU Taler exchange coverage report Lines: 0 111 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_create_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 create deposit" CMD.
      56             :  */
      57             : struct PurseCreateDepositState
      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             :    * JSON string describing what a proposal is about.
      72             :    */
      73             :   json_t *contract_terms;
      74             : 
      75             :   /**
      76             :    * Purse expiration time.
      77             :    */
      78             :   struct GNUNET_TIME_Timestamp purse_expiration;
      79             : 
      80             :   /**
      81             :    * Relative purse expiration time.
      82             :    */
      83             :   struct GNUNET_TIME_Relative rel_expiration;
      84             : 
      85             :   /**
      86             :    * Set (by the interpreter) to a fresh private key.  This
      87             :    * key will be used to create the purse.
      88             :    */
      89             :   struct TALER_PurseContractPrivateKeyP purse_priv;
      90             : 
      91             :   /**
      92             :    * Set (by the interpreter) to a fresh private key.  This
      93             :    * key will be used to merge the purse.
      94             :    */
      95             :   struct TALER_PurseMergePrivateKeyP merge_priv;
      96             : 
      97             :   /**
      98             :    * Set (by the interpreter) to a fresh private key.  This
      99             :    * key will be used to decrypt the contract.
     100             :    */
     101             :   struct TALER_ContractDiffiePrivateP contract_priv;
     102             : 
     103             :   /**
     104             :    * Signing key used by the exchange to sign the
     105             :    * deposit confirmation.
     106             :    */
     107             :   struct TALER_ExchangePublicKeyP exchange_pub;
     108             : 
     109             :   /**
     110             :    * Signature from the exchange on the
     111             :    * deposit confirmation.
     112             :    */
     113             :   struct TALER_ExchangeSignatureP exchange_sig;
     114             : 
     115             :   /**
     116             :    * Set (by the interpreter) to a public key corresponding
     117             :    * to @e purse_priv.
     118             :    */
     119             :   struct TALER_PurseContractPublicKeyP purse_pub;
     120             : 
     121             :   /**
     122             :    * PurseCreateDeposit handle while operation is running.
     123             :    */
     124             :   struct TALER_EXCHANGE_PurseCreateDepositHandle *dh;
     125             : 
     126             :   /**
     127             :    * Interpreter state.
     128             :    */
     129             :   struct TALER_TESTING_Interpreter *is;
     130             : 
     131             :   /**
     132             :    * Expected HTTP response code.
     133             :    */
     134             :   unsigned int expected_response_code;
     135             : 
     136             :   /**
     137             :    * Length of the @e coin_references array.
     138             :    */
     139             :   unsigned int num_coin_references;
     140             : 
     141             :   /**
     142             :    * Should we upload the contract?
     143             :    */
     144             :   bool upload_contract;
     145             : 
     146             : };
     147             : 
     148             : 
     149             : /**
     150             :  * Callback to analyze the /purses/$PID/create response, just used to check if
     151             :  * the response code is acceptable.
     152             :  *
     153             :  * @param cls closure.
     154             :  * @param dr deposit response details
     155             :  */
     156             : static void
     157           0 : deposit_cb (void *cls,
     158             :             const struct TALER_EXCHANGE_PurseCreateDepositResponse *dr)
     159             : {
     160           0 :   struct PurseCreateDepositState *ds = cls;
     161             : 
     162           0 :   ds->dh = NULL;
     163           0 :   if (ds->expected_response_code != dr->hr.http_status)
     164             :   {
     165           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     166             :                 "Unexpected response code %u to command %s in %s:%u\n",
     167             :                 dr->hr.http_status,
     168             :                 ds->is->commands[ds->is->ip].label,
     169             :                 __FILE__,
     170             :                 __LINE__);
     171           0 :     json_dumpf (dr->hr.reply,
     172             :                 stderr,
     173             :                 0);
     174           0 :     TALER_TESTING_interpreter_fail (ds->is);
     175           0 :     return;
     176             :   }
     177           0 :   if (MHD_HTTP_OK == dr->hr.http_status)
     178             :   {
     179           0 :     ds->exchange_pub = dr->details.success.exchange_pub;
     180           0 :     ds->exchange_sig = dr->details.success.exchange_sig;
     181             :   }
     182           0 :   TALER_TESTING_interpreter_next (ds->is);
     183             : }
     184             : 
     185             : 
     186             : /**
     187             :  * Run the command.
     188             :  *
     189             :  * @param cls closure.
     190             :  * @param cmd the command to execute.
     191             :  * @param is the interpreter state.
     192             :  */
     193             : static void
     194           0 : deposit_run (void *cls,
     195             :              const struct TALER_TESTING_Command *cmd,
     196             :              struct TALER_TESTING_Interpreter *is)
     197           0 : {
     198           0 :   struct PurseCreateDepositState *ds = cls;
     199           0 :   struct TALER_EXCHANGE_PurseDeposit deposits[ds->num_coin_references];
     200             : 
     201             :   (void) cmd;
     202           0 :   ds->is = is;
     203           0 :   for (unsigned int i = 0; i<ds->num_coin_references; i++)
     204             :   {
     205           0 :     const struct Coin *cr = &ds->coin_references[i];
     206           0 :     struct TALER_EXCHANGE_PurseDeposit *pd = &deposits[i];
     207             :     const struct TALER_TESTING_Command *coin_cmd;
     208             :     const struct TALER_CoinSpendPrivateKeyP *coin_priv;
     209           0 :     const struct TALER_AgeCommitmentProof *age_commitment_proof = NULL;
     210             :     const struct TALER_EXCHANGE_DenomPublicKey *denom_pub;
     211             :     const struct TALER_DenominationSignature *denom_pub_sig;
     212             : 
     213           0 :     coin_cmd = TALER_TESTING_interpreter_lookup_command (is,
     214           0 :                                                          cr->command_ref);
     215           0 :     if (NULL == coin_cmd)
     216             :     {
     217           0 :       GNUNET_break (0);
     218           0 :       TALER_TESTING_interpreter_fail (is);
     219           0 :       return;
     220             :     }
     221             : 
     222           0 :     if ( (GNUNET_OK !=
     223           0 :           TALER_TESTING_get_trait_coin_priv (coin_cmd,
     224             :                                              cr->coin_index,
     225           0 :                                              &coin_priv)) ||
     226             :          (GNUNET_OK !=
     227           0 :           TALER_TESTING_get_trait_age_commitment_proof (coin_cmd,
     228             :                                                         cr->coin_index,
     229             :                                                         &age_commitment_proof))
     230           0 :          ||
     231             :          (GNUNET_OK !=
     232           0 :           TALER_TESTING_get_trait_denom_pub (coin_cmd,
     233             :                                              cr->coin_index,
     234           0 :                                              &denom_pub)) ||
     235             :          (GNUNET_OK !=
     236           0 :           TALER_TESTING_get_trait_denom_sig (coin_cmd,
     237             :                                              cr->coin_index,
     238             :                                              &denom_pub_sig)) )
     239             :     {
     240           0 :       GNUNET_break (0);
     241           0 :       TALER_TESTING_interpreter_fail (is);
     242           0 :       return;
     243             :     }
     244           0 :     pd->age_commitment_proof = age_commitment_proof;
     245           0 :     pd->denom_sig = *denom_pub_sig;
     246           0 :     pd->coin_priv = *coin_priv;
     247           0 :     pd->amount = cr->deposit_with_fee;
     248           0 :     pd->h_denom_pub = denom_pub->h_key;
     249             :   }
     250             : 
     251           0 :   GNUNET_CRYPTO_eddsa_key_create (&ds->purse_priv.eddsa_priv);
     252           0 :   GNUNET_CRYPTO_eddsa_key_create (&ds->merge_priv.eddsa_priv);
     253           0 :   GNUNET_CRYPTO_ecdhe_key_create (&ds->contract_priv.ecdhe_priv);
     254           0 :   GNUNET_CRYPTO_eddsa_key_get_public (&ds->purse_priv.eddsa_priv,
     255             :                                       &ds->purse_pub.eddsa_pub);
     256             : 
     257             :   ds->purse_expiration =
     258           0 :     GNUNET_TIME_absolute_to_timestamp (
     259             :       GNUNET_TIME_relative_to_absolute (ds->rel_expiration));
     260           0 :   GNUNET_assert (0 ==
     261             :                  json_object_set_new (
     262             :                    ds->contract_terms,
     263             :                    "pay_deadline",
     264             :                    GNUNET_JSON_from_timestamp (ds->purse_expiration)));
     265           0 :   ds->dh = TALER_EXCHANGE_purse_create_with_deposit (
     266             :     is->exchange,
     267           0 :     &ds->purse_priv,
     268           0 :     &ds->merge_priv,
     269           0 :     &ds->contract_priv,
     270           0 :     ds->contract_terms,
     271             :     ds->num_coin_references,
     272             :     deposits,
     273           0 :     ds->upload_contract,
     274             :     &deposit_cb,
     275             :     ds);
     276           0 :   if (NULL == ds->dh)
     277             :   {
     278           0 :     GNUNET_break (0);
     279           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     280             :                 "Could not create purse with deposit\n");
     281           0 :     TALER_TESTING_interpreter_fail (is);
     282           0 :     return;
     283             :   }
     284             : }
     285             : 
     286             : 
     287             : /**
     288             :  * Free the state of a "deposit" CMD, and possibly cancel a
     289             :  * pending operation thereof.
     290             :  *
     291             :  * @param cls closure, must be a `struct PurseCreateDepositState`.
     292             :  * @param cmd the command which is being cleaned up.
     293             :  */
     294             : static void
     295           0 : deposit_cleanup (void *cls,
     296             :                  const struct TALER_TESTING_Command *cmd)
     297             : {
     298           0 :   struct PurseCreateDepositState *ds = cls;
     299             : 
     300           0 :   if (NULL != ds->dh)
     301             :   {
     302           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     303             :                 "Command %u (%s) did not complete\n",
     304             :                 ds->is->ip,
     305             :                 cmd->label);
     306           0 :     TALER_EXCHANGE_purse_create_with_deposit_cancel (ds->dh);
     307           0 :     ds->dh = NULL;
     308             :   }
     309           0 :   for (unsigned int i = 0; i<ds->num_coin_references; i++)
     310           0 :     GNUNET_free (ds->coin_references[i].command_ref);
     311           0 :   json_decref (ds->contract_terms);
     312           0 :   GNUNET_free (ds->coin_references);
     313           0 :   GNUNET_free (ds);
     314           0 : }
     315             : 
     316             : 
     317             : /**
     318             :  * Offer internal data from a "deposit" CMD, to other commands.
     319             :  *
     320             :  * @param cls closure.
     321             :  * @param[out] ret result.
     322             :  * @param trait name of the trait.
     323             :  * @param index index number of the object to offer.
     324             :  * @return #GNUNET_OK on success.
     325             :  */
     326             : static enum GNUNET_GenericReturnValue
     327           0 : deposit_traits (void *cls,
     328             :                 const void **ret,
     329             :                 const char *trait,
     330             :                 unsigned int index)
     331             : {
     332           0 :   struct PurseCreateDepositState *ds = cls;
     333             :   struct TALER_TESTING_Trait traits[] = {
     334           0 :     TALER_TESTING_make_trait_merge_priv (&ds->merge_priv),
     335           0 :     TALER_TESTING_make_trait_contract_priv (&ds->contract_priv),
     336           0 :     TALER_TESTING_make_trait_purse_priv (&ds->purse_priv),
     337           0 :     TALER_TESTING_make_trait_purse_pub (&ds->purse_pub),
     338           0 :     TALER_TESTING_make_trait_contract_terms (ds->contract_terms),
     339           0 :     TALER_TESTING_make_trait_deposit_amount (0,
     340           0 :                                              &ds->target_amount),
     341           0 :     TALER_TESTING_make_trait_timestamp (index,
     342           0 :                                         &ds->purse_expiration),
     343           0 :     TALER_TESTING_trait_end ()
     344             :   };
     345             : 
     346           0 :   return TALER_TESTING_get_trait (traits,
     347             :                                   ret,
     348             :                                   trait,
     349             :                                   index);
     350             : }
     351             : 
     352             : 
     353             : struct TALER_TESTING_Command
     354           0 : TALER_TESTING_cmd_purse_create_with_deposit (
     355             :   const char *label,
     356             :   unsigned int expected_http_status,
     357             :   const char *contract_terms,
     358             :   bool upload_contract,
     359             :   struct GNUNET_TIME_Relative purse_expiration,
     360             :   ...)
     361             : {
     362             :   struct PurseCreateDepositState *ds;
     363             : 
     364           0 :   ds = GNUNET_new (struct PurseCreateDepositState);
     365           0 :   ds->rel_expiration = purse_expiration;
     366           0 :   ds->upload_contract = upload_contract;
     367           0 :   ds->expected_response_code = expected_http_status;
     368           0 :   ds->contract_terms = json_loads (contract_terms,
     369             :                                    JSON_REJECT_DUPLICATES,
     370             :                                    NULL);
     371           0 :   if (NULL == ds->contract_terms)
     372             :   {
     373           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     374             :                 "Failed to parse contract terms `%s' for CMD `%s'\n",
     375             :                 contract_terms,
     376             :                 label);
     377           0 :     GNUNET_assert (0);
     378             :   }
     379             :   {
     380             :     va_list ap;
     381             :     unsigned int i;
     382             :     const char *ref;
     383             :     const char *val;
     384             : 
     385           0 :     va_start (ap, purse_expiration);
     386           0 :     while (NULL != (va_arg (ap, const char *)))
     387           0 :       ds->num_coin_references++;
     388           0 :     va_end (ap);
     389           0 :     GNUNET_assert (0 == (ds->num_coin_references % 2));
     390           0 :     ds->num_coin_references /= 2;
     391           0 :     ds->coin_references = GNUNET_new_array (ds->num_coin_references,
     392             :                                             struct Coin);
     393           0 :     i = 0;
     394           0 :     va_start (ap, purse_expiration);
     395           0 :     while (NULL != (ref = va_arg (ap, const char *)))
     396             :     {
     397           0 :       struct Coin *c = &ds->coin_references[i++];
     398             : 
     399           0 :       GNUNET_assert (NULL != (val = va_arg (ap, const char *)));
     400           0 :       GNUNET_assert (GNUNET_OK ==
     401             :                      TALER_TESTING_parse_coin_reference (
     402             :                        ref,
     403             :                        &c->command_ref,
     404             :                        &c->coin_index));
     405           0 :       GNUNET_assert (GNUNET_OK ==
     406             :                      TALER_string_to_amount (val,
     407             :                                              &c->deposit_with_fee));
     408             :     }
     409           0 :     va_end (ap);
     410             :   }
     411             :   {
     412           0 :     struct TALER_TESTING_Command cmd = {
     413             :       .cls = ds,
     414             :       .label = label,
     415             :       .run = &deposit_run,
     416             :       .cleanup = &deposit_cleanup,
     417             :       .traits = &deposit_traits
     418             :     };
     419             : 
     420           0 :     return cmd;
     421             :   }
     422             : }
     423             : 
     424             : 
     425             : /* end of testing_api_cmd_purse_create_deposit.c */

Generated by: LCOV version 1.14