LCOV - code coverage report
Current view: top level - testing - testing_api_cmd_deposit.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 70.0 % 283 198
Test Date: 2025-12-26 23:00:34 Functions: 77.8 % 9 7

            Line data    Source code
       1              : /*
       2              :   This file is part of TALER
       3              :   Copyright (C) 2018-2024 Taler Systems SA
       4              : 
       5              :   TALER is free software; you can redistribute it and/or modify it
       6              :   under the terms of the GNU General Public License as published by
       7              :   the Free Software Foundation; either version 3, or (at your
       8              :   option) any later version.
       9              : 
      10              :   TALER is distributed in the hope that it will be useful, but
      11              :   WITHOUT ANY WARRANTY; without even the implied warranty of
      12              :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13              :   General Public License for more details.
      14              : 
      15              :   You should have received a copy of the GNU General Public
      16              :   License along with TALER; see the file COPYING.  If not, see
      17              :   <http://www.gnu.org/licenses/>
      18              : */
      19              : /**
      20              :  * @file testing/testing_api_cmd_deposit.c
      21              :  * @brief command for testing /deposit.
      22              :  * @author Marcello Stanisci
      23              :  */
      24              : #include "taler/platform.h"
      25              : #include "taler/taler_json_lib.h"
      26              : #include <gnunet/gnunet_curl_lib.h>
      27              : #include "taler/taler_testing_lib.h"
      28              : #include "taler/taler_signatures.h"
      29              : #include "taler/backoff.h"
      30              : 
      31              : 
      32              : /**
      33              :  * How often do we retry before giving up?
      34              :  */
      35              : #define NUM_RETRIES 5
      36              : 
      37              : /**
      38              :  * How long do we wait AT MOST when retrying?
      39              :  */
      40              : #define MAX_BACKOFF GNUNET_TIME_relative_multiply ( \
      41              :           GNUNET_TIME_UNIT_MILLISECONDS, 100)
      42              : 
      43              : 
      44              : /**
      45              :  * State for a "deposit" CMD.
      46              :  */
      47              : struct DepositState
      48              : {
      49              : 
      50              :   /**
      51              :    * Amount to deposit.
      52              :    */
      53              :   struct TALER_Amount amount;
      54              : 
      55              :   /**
      56              :    * Deposit fee.
      57              :    */
      58              :   struct TALER_Amount deposit_fee;
      59              : 
      60              :   /**
      61              :    * Reference to any command that is able to provide a coin.
      62              :    */
      63              :   const char *coin_reference;
      64              : 
      65              :   /**
      66              :    * If @e coin_reference refers to an operation that generated
      67              :    * an array of coins, this value determines which coin to pick.
      68              :    */
      69              :   unsigned int coin_index;
      70              : 
      71              :   /**
      72              :    * Our coin signature.
      73              :    */
      74              :   struct TALER_CoinSpendSignatureP coin_sig;
      75              : 
      76              :   /**
      77              :    * Wire details of who is depositing -- this would be merchant
      78              :    * wire details in a normal scenario.
      79              :    */
      80              :   json_t *wire_details;
      81              : 
      82              :   /**
      83              :    * JSON string describing what a proposal is about.
      84              :    */
      85              :   json_t *contract_terms;
      86              : 
      87              :   /**
      88              :    * Refund deadline. Zero for no refunds.
      89              :    */
      90              :   struct GNUNET_TIME_Timestamp refund_deadline;
      91              : 
      92              :   /**
      93              :    * Wire deadline.
      94              :    */
      95              :   struct GNUNET_TIME_Timestamp wire_deadline;
      96              : 
      97              :   /**
      98              :    * Set (by the interpreter) to a fresh private key.  This
      99              :    * key will be used to sign the deposit request.
     100              :    */
     101              :   union TALER_AccountPrivateKeyP account_priv;
     102              : 
     103              :   /**
     104              :    * Set (by the interpreter) to the public key
     105              :    * corresponding to @e account_priv.
     106              :    */
     107              :   union TALER_AccountPublicKeyP account_pub;
     108              : 
     109              :   /**
     110              :    * Deposit handle while operation is running.
     111              :    */
     112              :   struct TALER_EXCHANGE_BatchDepositHandle *dh;
     113              : 
     114              :   /**
     115              :    * Denomination public key of the deposited coin.
     116              :    */
     117              :   const struct TALER_EXCHANGE_DenomPublicKey *denom_pub;
     118              : 
     119              :   /**
     120              :    * Timestamp of the /deposit operation in the wallet (contract signing time).
     121              :    */
     122              :   struct GNUNET_TIME_Timestamp wallet_timestamp;
     123              : 
     124              :   /**
     125              :    * Interpreter state.
     126              :    */
     127              :   struct TALER_TESTING_Interpreter *is;
     128              : 
     129              :   /**
     130              :    * Task scheduled to try later.
     131              :    */
     132              :   struct GNUNET_SCHEDULER_Task *retry_task;
     133              : 
     134              :   /**
     135              :    * How long do we wait until we retry?
     136              :    */
     137              :   struct GNUNET_TIME_Relative backoff;
     138              : 
     139              :   /**
     140              :    * Expected HTTP response code.
     141              :    */
     142              :   unsigned int expected_response_code;
     143              : 
     144              :   /**
     145              :    * How often should we retry on (transient) failures?
     146              :    */
     147              :   unsigned int do_retry;
     148              : 
     149              :   /**
     150              :    * Set to true if the /deposit succeeded
     151              :    * and we now can provide the resulting traits.
     152              :    */
     153              :   bool deposit_succeeded;
     154              : 
     155              :   /**
     156              :    * Expected entry in the coin history created by this
     157              :    * operation.
     158              :    */
     159              :   struct TALER_EXCHANGE_CoinHistoryEntry che;
     160              : 
     161              :   /**
     162              :    * When did the exchange receive the deposit?
     163              :    */
     164              :   struct GNUNET_TIME_Timestamp exchange_timestamp;
     165              : 
     166              :   /**
     167              :    * Signing key used by the exchange to sign the
     168              :    * deposit confirmation.
     169              :    */
     170              :   struct TALER_ExchangePublicKeyP exchange_pub;
     171              : 
     172              :   /**
     173              :    * Signature from the exchange on the
     174              :    * deposit confirmation.
     175              :    */
     176              :   struct TALER_ExchangeSignatureP exchange_sig;
     177              : 
     178              :   /**
     179              :    * Reference to previous deposit operation.
     180              :    * Only present if we're supposed to replay the previous deposit.
     181              :    */
     182              :   const char *deposit_reference;
     183              : 
     184              :   /**
     185              :    * Did we set the parameters for this deposit command?
     186              :    *
     187              :    * When we're referencing another deposit operation,
     188              :    * this will only be set after the command has been started.
     189              :    */
     190              :   bool command_initialized;
     191              : 
     192              :   /**
     193              :    * Reference to fetch the merchant private key from.
     194              :    * If NULL, we generate our own, fresh merchant key.
     195              :    */
     196              :   const char *merchant_priv_reference;
     197              : };
     198              : 
     199              : 
     200              : /**
     201              :  * Run the command.
     202              :  *
     203              :  * @param cls closure.
     204              :  * @param cmd the command to execute.
     205              :  * @param is the interpreter state.
     206              :  */
     207              : static void
     208              : deposit_run (void *cls,
     209              :              const struct TALER_TESTING_Command *cmd,
     210              :              struct TALER_TESTING_Interpreter *is);
     211              : 
     212              : 
     213              : /**
     214              :  * Task scheduled to re-try #deposit_run.
     215              :  *
     216              :  * @param cls a `struct DepositState`
     217              :  */
     218              : static void
     219            0 : do_retry (void *cls)
     220              : {
     221            0 :   struct DepositState *ds = cls;
     222              : 
     223            0 :   ds->retry_task = NULL;
     224            0 :   TALER_TESTING_touch_cmd (ds->is);
     225            0 :   deposit_run (ds,
     226              :                NULL,
     227              :                ds->is);
     228            0 : }
     229              : 
     230              : 
     231              : /**
     232              :  * Callback to analyze the /deposit response, just used to
     233              :  * check if the response code is acceptable.
     234              :  *
     235              :  * @param cls closure.
     236              :  * @param dr deposit response details
     237              :  */
     238              : static void
     239           96 : deposit_cb (void *cls,
     240              :             const struct TALER_EXCHANGE_BatchDepositResult *dr)
     241              : {
     242           96 :   struct DepositState *ds = cls;
     243              : 
     244           96 :   ds->dh = NULL;
     245           96 :   if (ds->expected_response_code != dr->hr.http_status)
     246              :   {
     247            0 :     if (0 != ds->do_retry)
     248              :     {
     249            0 :       ds->do_retry--;
     250            0 :       if ( (0 == dr->hr.http_status) ||
     251            0 :            (TALER_EC_GENERIC_DB_SOFT_FAILURE == dr->hr.ec) ||
     252            0 :            (MHD_HTTP_INTERNAL_SERVER_ERROR == dr->hr.http_status) )
     253              :       {
     254            0 :         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     255              :                     "Retrying deposit failed with %u/%d\n",
     256              :                     dr->hr.http_status,
     257              :                     (int) dr->hr.ec);
     258              :         /* on DB conflicts, do not use backoff */
     259            0 :         if (TALER_EC_GENERIC_DB_SOFT_FAILURE == dr->hr.ec)
     260            0 :           ds->backoff = GNUNET_TIME_UNIT_ZERO;
     261              :         else
     262            0 :           ds->backoff = GNUNET_TIME_randomized_backoff (ds->backoff,
     263              :                                                         MAX_BACKOFF);
     264            0 :         TALER_TESTING_inc_tries (ds->is);
     265            0 :         GNUNET_assert (NULL == ds->retry_task);
     266              :         ds->retry_task
     267            0 :           = GNUNET_SCHEDULER_add_delayed (ds->backoff,
     268              :                                           &do_retry,
     269              :                                           ds);
     270            0 :         return;
     271              :       }
     272              :     }
     273            0 :     TALER_TESTING_unexpected_status_with_body (
     274              :       ds->is,
     275              :       dr->hr.http_status,
     276              :       ds->expected_response_code,
     277              :       dr->hr.reply);
     278              : 
     279            0 :     return;
     280              :   }
     281           96 :   if (MHD_HTTP_OK == dr->hr.http_status)
     282              :   {
     283           82 :     ds->deposit_succeeded = true;
     284           82 :     ds->exchange_timestamp = dr->details.ok.deposit_timestamp;
     285           82 :     ds->exchange_pub = *dr->details.ok.exchange_pub;
     286           82 :     ds->exchange_sig = *dr->details.ok.exchange_sig;
     287              :   }
     288           96 :   TALER_TESTING_interpreter_next (ds->is);
     289              : }
     290              : 
     291              : 
     292              : /**
     293              :  * Run the command.
     294              :  *
     295              :  * @param cls closure.
     296              :  * @param cmd the command to execute.
     297              :  * @param is the interpreter state.
     298              :  */
     299              : static void
     300           96 : deposit_run (void *cls,
     301              :              const struct TALER_TESTING_Command *cmd,
     302              :              struct TALER_TESTING_Interpreter *is)
     303              : {
     304           96 :   struct DepositState *ds = cls;
     305              :   const struct TALER_TESTING_Command *coin_cmd;
     306              :   const struct TALER_TESTING_Command *acc_var;
     307              :   const struct TALER_CoinSpendPrivateKeyP *coin_priv;
     308              :   struct TALER_CoinSpendPublicKeyP coin_pub;
     309              :   const struct TALER_AgeCommitmentHashP *phac;
     310              :   const struct TALER_DenominationSignature *denom_pub_sig;
     311              :   struct TALER_PrivateContractHashP h_contract_terms;
     312              :   enum TALER_ErrorCode ec;
     313              :   struct TALER_WireSaltP wire_salt;
     314              :   struct TALER_FullPayto payto_uri;
     315              :   struct GNUNET_JSON_Specification spec[] = {
     316           96 :     TALER_JSON_spec_full_payto_uri ("payto_uri",
     317              :                                     &payto_uri),
     318           96 :     GNUNET_JSON_spec_fixed_auto ("salt",
     319              :                                  &wire_salt),
     320           96 :     GNUNET_JSON_spec_end ()
     321              :   };
     322              :   const char *exchange_url
     323           96 :     = TALER_TESTING_get_exchange_url (is);
     324              : 
     325              :   (void) cmd;
     326           96 :   if (NULL == exchange_url)
     327              :   {
     328            0 :     GNUNET_break (0);
     329            0 :     return;
     330              :   }
     331           96 :   ds->is = is;
     332           96 :   if (! GNUNET_TIME_absolute_is_zero (ds->refund_deadline.abs_time))
     333              :   {
     334              :     struct GNUNET_TIME_Relative refund_deadline;
     335              : 
     336              :     refund_deadline
     337           10 :       = GNUNET_TIME_absolute_get_remaining (ds->refund_deadline.abs_time);
     338              :     ds->wire_deadline
     339           10 :       = GNUNET_TIME_relative_to_timestamp (
     340              :           GNUNET_TIME_relative_multiply (refund_deadline,
     341              :                                          2));
     342              :   }
     343              :   else
     344              :   {
     345           86 :     ds->refund_deadline = ds->wallet_timestamp;
     346           86 :     ds->wire_deadline = GNUNET_TIME_timestamp_get ();
     347              :   }
     348           96 :   if (NULL != ds->deposit_reference)
     349              :   {
     350              :     /* We're copying another deposit operation, initialize here. */
     351              :     const struct TALER_TESTING_Command *drcmd;
     352              :     struct DepositState *ods;
     353              : 
     354           14 :     drcmd = TALER_TESTING_interpreter_lookup_command (is,
     355              :                                                       ds->deposit_reference);
     356           14 :     if (NULL == drcmd)
     357              :     {
     358            0 :       GNUNET_break (0);
     359            0 :       TALER_TESTING_interpreter_fail (is);
     360            0 :       return;
     361              :     }
     362           14 :     ods = drcmd->cls;
     363           14 :     ds->coin_reference = ods->coin_reference;
     364           14 :     ds->coin_index = ods->coin_index;
     365           14 :     ds->wire_details = json_incref (ods->wire_details);
     366           14 :     GNUNET_assert (NULL != ds->wire_details);
     367           14 :     ds->contract_terms = json_incref (ods->contract_terms);
     368           14 :     ds->wallet_timestamp = ods->wallet_timestamp;
     369           14 :     ds->refund_deadline = ods->refund_deadline;
     370           14 :     ds->wire_deadline = ods->wire_deadline;
     371           14 :     ds->amount = ods->amount;
     372           14 :     ds->account_priv = ods->account_priv;
     373           14 :     ds->account_pub = ods->account_pub;
     374           14 :     ds->command_initialized = true;
     375              :   }
     376           82 :   else if (NULL != ds->merchant_priv_reference)
     377              :   {
     378              :     /* We're copying the merchant key from another deposit operation */
     379              :     const struct TALER_MerchantPrivateKeyP *merchant_priv;
     380              :     const struct TALER_TESTING_Command *mpcmd;
     381              : 
     382            2 :     mpcmd = TALER_TESTING_interpreter_lookup_command (
     383              :       is,
     384              :       ds->merchant_priv_reference);
     385            2 :     if (NULL == mpcmd)
     386              :     {
     387            0 :       GNUNET_break (0);
     388            0 :       TALER_TESTING_interpreter_fail (is);
     389            0 :       return;
     390              :     }
     391            2 :     if ( (GNUNET_OK !=
     392            2 :           TALER_TESTING_get_trait_merchant_priv (mpcmd,
     393              :                                                  &merchant_priv)) )
     394              :     {
     395            0 :       GNUNET_break (0);
     396            0 :       TALER_TESTING_interpreter_fail (is);
     397            0 :       return;
     398              :     }
     399            2 :     ds->account_priv.merchant_priv = *merchant_priv;
     400            2 :     GNUNET_CRYPTO_eddsa_key_get_public (
     401            2 :       &ds->account_priv.merchant_priv.eddsa_priv,
     402              :       &ds->account_pub.merchant_pub.eddsa_pub);
     403              :   }
     404           80 :   else if (NULL != (acc_var
     405           80 :                       = TALER_TESTING_interpreter_get_command (
     406              :                           is,
     407              :                           "account-priv")))
     408              :   {
     409              :     const union TALER_AccountPrivateKeyP *account_priv;
     410              : 
     411           48 :     if ( (GNUNET_OK !=
     412           48 :           TALER_TESTING_get_trait_account_priv (acc_var,
     413              :                                                 &account_priv)) )
     414              :     {
     415            0 :       GNUNET_break (0);
     416            0 :       TALER_TESTING_interpreter_fail (is);
     417            0 :       return;
     418              :     }
     419           48 :     ds->account_priv = *account_priv;
     420           48 :     GNUNET_CRYPTO_eddsa_key_get_public (
     421           48 :       &ds->account_priv.merchant_priv.eddsa_priv,
     422              :       &ds->account_pub.merchant_pub.eddsa_pub);
     423              :   }
     424              :   else
     425              :   {
     426           32 :     GNUNET_CRYPTO_eddsa_key_create (
     427              :       &ds->account_priv.merchant_priv.eddsa_priv);
     428           32 :     GNUNET_CRYPTO_eddsa_key_get_public (
     429           32 :       &ds->account_priv.merchant_priv.eddsa_priv,
     430              :       &ds->account_pub.merchant_pub.eddsa_pub);
     431              :   }
     432           96 :   GNUNET_assert (NULL != ds->wire_details);
     433           96 :   if (GNUNET_OK !=
     434           96 :       GNUNET_JSON_parse (ds->wire_details,
     435              :                          spec,
     436              :                          NULL, NULL))
     437              :   {
     438            0 :     json_dumpf (ds->wire_details,
     439              :                 stderr,
     440              :                 JSON_INDENT (2));
     441            0 :     GNUNET_break (0);
     442            0 :     TALER_TESTING_interpreter_fail (is);
     443            0 :     return;
     444              :   }
     445           96 :   GNUNET_assert (ds->coin_reference);
     446           96 :   coin_cmd = TALER_TESTING_interpreter_lookup_command (is,
     447              :                                                        ds->coin_reference);
     448           96 :   if (NULL == coin_cmd)
     449              :   {
     450            0 :     GNUNET_break (0);
     451            0 :     TALER_TESTING_interpreter_fail (is);
     452            0 :     return;
     453              :   }
     454              : #if DUMP_CONTRACT
     455              :   fprintf (stderr,
     456              :            "Using contract:\n");
     457              :   json_dumpf (ds->contract_terms,
     458              :               stderr,
     459              :               JSON_INDENT (2));
     460              : #endif
     461           96 :   if (GNUNET_OK !=
     462           96 :       TALER_TESTING_get_trait_coin_priv (coin_cmd,
     463              :                                          ds->coin_index,
     464              :                                          &coin_priv))
     465              :   {
     466            0 :     GNUNET_break (0);
     467            0 :     TALER_TESTING_interpreter_fail (is);
     468            0 :     return;
     469              :   }
     470           96 :   if (GNUNET_OK !=
     471           96 :       TALER_TESTING_get_trait_h_age_commitment (coin_cmd,
     472              :                                                 ds->coin_index,
     473              :                                                 &phac))
     474              :   {
     475            0 :     GNUNET_break (0);
     476            0 :     TALER_TESTING_interpreter_fail (is);
     477            0 :     return;
     478              :   }
     479           96 :   if (GNUNET_OK !=
     480           96 :       TALER_TESTING_get_trait_denom_pub (coin_cmd,
     481              :                                          ds->coin_index,
     482              :                                          &ds->denom_pub))
     483              :   {
     484            0 :     GNUNET_break (0);
     485            0 :     TALER_TESTING_interpreter_fail (is);
     486            0 :     return;
     487              :   }
     488           96 :   if (GNUNET_OK !=
     489           96 :       TALER_TESTING_get_trait_denom_sig (coin_cmd,
     490              :                                          ds->coin_index,
     491              :                                          &denom_pub_sig))
     492              :   {
     493            0 :     GNUNET_break (0);
     494            0 :     TALER_TESTING_interpreter_fail (is);
     495            0 :     return;
     496              :   }
     497           96 :   if (GNUNET_OK !=
     498           96 :       TALER_JSON_contract_hash (ds->contract_terms,
     499              :                                 &h_contract_terms))
     500              :   {
     501            0 :     GNUNET_break (0);
     502            0 :     TALER_TESTING_interpreter_fail (is);
     503            0 :     return;
     504              :   }
     505              : 
     506           96 :   ds->deposit_fee = ds->denom_pub->fees.deposit;
     507           96 :   GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
     508              :                                       &coin_pub.eddsa_pub);
     509              : 
     510              :   {
     511              :     struct TALER_MerchantWireHashP h_wire;
     512              : 
     513           96 :     GNUNET_assert (GNUNET_OK ==
     514              :                    TALER_JSON_merchant_wire_signature_hash (ds->wire_details,
     515              :                                                             &h_wire));
     516           96 :     TALER_wallet_deposit_sign (&ds->amount,
     517           96 :                                &ds->denom_pub->fees.deposit,
     518              :                                &h_wire,
     519              :                                &h_contract_terms,
     520              :                                NULL, /* wallet data hash */
     521              :                                phac,
     522              :                                NULL, /* hash of extensions */
     523           96 :                                &ds->denom_pub->h_key,
     524              :                                ds->wallet_timestamp,
     525           96 :                                &ds->account_pub.merchant_pub,
     526              :                                ds->refund_deadline,
     527              :                                coin_priv,
     528              :                                &ds->coin_sig);
     529           96 :     ds->che.type = TALER_EXCHANGE_CTT_DEPOSIT;
     530           96 :     ds->che.amount = ds->amount;
     531           96 :     ds->che.details.deposit.h_wire = h_wire;
     532           96 :     ds->che.details.deposit.h_contract_terms = h_contract_terms;
     533           96 :     ds->che.details.deposit.no_h_policy = true;
     534           96 :     ds->che.details.deposit.no_wallet_data_hash = true;
     535           96 :     ds->che.details.deposit.wallet_timestamp = ds->wallet_timestamp;
     536           96 :     ds->che.details.deposit.merchant_pub = ds->account_pub.merchant_pub;
     537           96 :     ds->che.details.deposit.refund_deadline = ds->refund_deadline;
     538           96 :     ds->che.details.deposit.sig = ds->coin_sig;
     539           96 :     ds->che.details.deposit.no_hac = true;
     540           96 :     ds->che.details.deposit.deposit_fee = ds->denom_pub->fees.deposit;
     541              :   }
     542           96 :   GNUNET_assert (NULL == ds->dh);
     543              :   {
     544           96 :     struct TALER_EXCHANGE_CoinDepositDetail cdd = {
     545              :       .amount = ds->amount,
     546              :       .coin_pub = coin_pub,
     547              :       .coin_sig = ds->coin_sig,
     548           96 :       .denom_sig = *denom_pub_sig,
     549           96 :       .h_denom_pub = ds->denom_pub->h_key,
     550              :       .h_age_commitment = {{{0}}},
     551              :     };
     552           96 :     struct TALER_EXCHANGE_DepositContractDetail dcd = {
     553              :       .wire_deadline = ds->wire_deadline,
     554              :       .merchant_payto_uri = payto_uri,
     555              :       .wire_salt = wire_salt,
     556              :       .h_contract_terms = h_contract_terms,
     557              :       .wallet_timestamp = ds->wallet_timestamp,
     558              :       .merchant_pub = ds->account_pub.merchant_pub,
     559              :       .refund_deadline = ds->refund_deadline
     560              :     };
     561              : 
     562           96 :     TALER_merchant_contract_sign (&h_contract_terms,
     563           96 :                                   &ds->account_priv.merchant_priv,
     564              :                                   &dcd.merchant_sig);
     565           96 :     if (NULL != phac)
     566           32 :       cdd.h_age_commitment = *phac;
     567              : 
     568           96 :     ds->dh = TALER_EXCHANGE_batch_deposit (
     569              :       TALER_TESTING_interpreter_get_context (is),
     570              :       exchange_url,
     571              :       TALER_TESTING_get_keys (is),
     572              :       &dcd,
     573              :       1,
     574              :       &cdd,
     575              :       &deposit_cb,
     576              :       ds,
     577              :       &ec);
     578              :   }
     579           96 :   if (NULL == ds->dh)
     580              :   {
     581            0 :     GNUNET_break (0);
     582            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     583              :                 "Could not create deposit with EC %d\n",
     584              :                 (int) ec);
     585            0 :     TALER_TESTING_interpreter_fail (is);
     586            0 :     return;
     587              :   }
     588              : }
     589              : 
     590              : 
     591              : /**
     592              :  * Free the state of a "deposit" CMD, and possibly cancel a
     593              :  * pending operation thereof.
     594              :  *
     595              :  * @param cls closure, must be a `struct DepositState`.
     596              :  * @param cmd the command which is being cleaned up.
     597              :  */
     598              : static void
     599           96 : deposit_cleanup (void *cls,
     600              :                  const struct TALER_TESTING_Command *cmd)
     601              : {
     602           96 :   struct DepositState *ds = cls;
     603              : 
     604           96 :   if (NULL != ds->dh)
     605              :   {
     606            0 :     TALER_TESTING_command_incomplete (ds->is,
     607              :                                       cmd->label);
     608            0 :     TALER_EXCHANGE_batch_deposit_cancel (ds->dh);
     609            0 :     ds->dh = NULL;
     610              :   }
     611           96 :   if (NULL != ds->retry_task)
     612              :   {
     613            0 :     GNUNET_SCHEDULER_cancel (ds->retry_task);
     614            0 :     ds->retry_task = NULL;
     615              :   }
     616           96 :   json_decref (ds->wire_details);
     617           96 :   json_decref (ds->contract_terms);
     618           96 :   GNUNET_free (ds);
     619           96 : }
     620              : 
     621              : 
     622              : /**
     623              :  * Offer internal data from a "deposit" CMD, to other commands.
     624              :  *
     625              :  * @param cls closure.
     626              :  * @param[out] ret result.
     627              :  * @param trait name of the trait.
     628              :  * @param index index number of the object to offer.
     629              :  * @return #GNUNET_OK on success.
     630              :  */
     631              : static enum GNUNET_GenericReturnValue
     632          330 : deposit_traits (void *cls,
     633              :                 const void **ret,
     634              :                 const char *trait,
     635              :                 unsigned int index)
     636              : {
     637          330 :   struct DepositState *ds = cls;
     638              :   const struct TALER_TESTING_Command *coin_cmd;
     639              :   /* Will point to coin cmd internals. */
     640              :   const struct TALER_CoinSpendPrivateKeyP *coin_spent_priv;
     641              :   const struct TALER_CoinSpendPublicKeyP *coin_spent_pub;
     642          330 :   const struct TALER_AgeCommitmentProof *age_commitment_proof=NULL;
     643          330 :   const struct TALER_AgeCommitmentHashP *h_age_commitment=NULL;
     644              : 
     645          330 :   if (! ds->command_initialized)
     646              :   {
     647              :     /* No access to traits yet. */
     648            0 :     GNUNET_break (0);
     649            0 :     return GNUNET_NO;
     650              :   }
     651              : 
     652              :   coin_cmd
     653          330 :     = TALER_TESTING_interpreter_lookup_command (ds->is,
     654              :                                                 ds->coin_reference);
     655          330 :   if (NULL == coin_cmd)
     656              :   {
     657            0 :     GNUNET_break (0);
     658            0 :     TALER_TESTING_interpreter_fail (ds->is);
     659            0 :     return GNUNET_NO;
     660              :   }
     661          330 :   if ( (GNUNET_OK !=
     662          330 :         TALER_TESTING_get_trait_coin_priv (coin_cmd,
     663              :                                            ds->coin_index,
     664          330 :                                            &coin_spent_priv)) ||
     665              :        (GNUNET_OK !=
     666          330 :         TALER_TESTING_get_trait_coin_pub (coin_cmd,
     667              :                                           ds->coin_index,
     668          330 :                                           &coin_spent_pub)) ||
     669              :        (GNUNET_OK !=
     670          330 :         TALER_TESTING_get_trait_age_commitment_proof (coin_cmd,
     671              :                                                       ds->coin_index,
     672          330 :                                                       &age_commitment_proof)) ||
     673              :        (GNUNET_OK !=
     674          330 :         TALER_TESTING_get_trait_h_age_commitment (coin_cmd,
     675              :                                                   ds->coin_index,
     676              :                                                   &h_age_commitment)) )
     677              :   {
     678            0 :     GNUNET_break (0);
     679            0 :     TALER_TESTING_interpreter_fail (ds->is);
     680            0 :     return GNUNET_NO;
     681              :   }
     682              : 
     683              :   {
     684              :     struct TALER_TESTING_Trait traits[] = {
     685              :       /* First two traits are only available if
     686              :          ds->traits is true */
     687          330 :       TALER_TESTING_make_trait_exchange_pub (0,
     688          330 :                                              &ds->exchange_pub),
     689          330 :       TALER_TESTING_make_trait_exchange_sig (0,
     690          330 :                                              &ds->exchange_sig),
     691              :       /* These traits are always available */
     692          330 :       TALER_TESTING_make_trait_coin_history (0,
     693          330 :                                              &ds->che),
     694          330 :       TALER_TESTING_make_trait_coin_priv (0,
     695              :                                           coin_spent_priv),
     696          330 :       TALER_TESTING_make_trait_coin_pub (0,
     697              :                                          coin_spent_pub),
     698          330 :       TALER_TESTING_make_trait_denom_pub (0,
     699              :                                           ds->denom_pub),
     700          330 :       TALER_TESTING_make_trait_coin_sig (0,
     701          330 :                                          &ds->coin_sig),
     702          330 :       TALER_TESTING_make_trait_age_commitment_proof (0,
     703              :                                                      age_commitment_proof),
     704          330 :       TALER_TESTING_make_trait_h_age_commitment (0,
     705              :                                                  h_age_commitment),
     706          330 :       TALER_TESTING_make_trait_wire_details (ds->wire_details),
     707          330 :       TALER_TESTING_make_trait_contract_terms (ds->contract_terms),
     708          330 :       TALER_TESTING_make_trait_merchant_priv (&ds->account_priv.merchant_priv),
     709          330 :       TALER_TESTING_make_trait_merchant_pub (&ds->account_pub.merchant_pub),
     710          330 :       TALER_TESTING_make_trait_account_priv (&ds->account_priv),
     711          330 :       TALER_TESTING_make_trait_account_pub (&ds->account_pub),
     712          330 :       TALER_TESTING_make_trait_deposit_amount (0,
     713          330 :                                                &ds->amount),
     714          330 :       TALER_TESTING_make_trait_deposit_fee_amount (0,
     715          330 :                                                    &ds->deposit_fee),
     716          330 :       TALER_TESTING_make_trait_timestamp (0,
     717          330 :                                           &ds->exchange_timestamp),
     718          330 :       TALER_TESTING_make_trait_wire_deadline (0,
     719          330 :                                               &ds->wire_deadline),
     720          330 :       TALER_TESTING_make_trait_refund_deadline (0,
     721          330 :                                                 &ds->refund_deadline),
     722          330 :       TALER_TESTING_trait_end ()
     723              :     };
     724              : 
     725          330 :     return TALER_TESTING_get_trait ((ds->deposit_succeeded)
     726              :                                     ? traits
     727              :                                     : &traits[2],
     728              :                                     ret,
     729              :                                     trait,
     730              :                                     index);
     731              :   }
     732              : }
     733              : 
     734              : 
     735              : struct TALER_TESTING_Command
     736           80 : TALER_TESTING_cmd_deposit (
     737              :   const char *label,
     738              :   const char *coin_reference,
     739              :   unsigned int coin_index,
     740              :   struct TALER_FullPayto target_account_payto,
     741              :   const char *contract_terms,
     742              :   struct GNUNET_TIME_Relative refund_deadline,
     743              :   const char *amount,
     744              :   unsigned int expected_response_code)
     745              : {
     746              :   struct DepositState *ds;
     747              : 
     748           80 :   ds = GNUNET_new (struct DepositState);
     749           80 :   ds->coin_reference = coin_reference;
     750           80 :   ds->coin_index = coin_index;
     751           80 :   ds->wire_details = TALER_TESTING_make_wire_details (target_account_payto);
     752           80 :   GNUNET_assert (NULL != ds->wire_details);
     753           80 :   ds->contract_terms = json_loads (contract_terms,
     754              :                                    JSON_REJECT_DUPLICATES,
     755              :                                    NULL);
     756           80 :   if (NULL == ds->contract_terms)
     757              :   {
     758            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     759              :                 "Failed to parse contract terms `%s' for CMD `%s'\n",
     760              :                 contract_terms,
     761              :                 label);
     762            0 :     GNUNET_assert (0);
     763              :   }
     764           80 :   ds->wallet_timestamp = GNUNET_TIME_timestamp_get ();
     765           80 :   GNUNET_assert (0 ==
     766              :                  json_object_set_new (ds->contract_terms,
     767              :                                       "timestamp",
     768              :                                       GNUNET_JSON_from_timestamp (
     769              :                                         ds->wallet_timestamp)));
     770           80 :   if (! GNUNET_TIME_relative_is_zero (refund_deadline))
     771              :   {
     772           10 :     ds->refund_deadline = GNUNET_TIME_relative_to_timestamp (refund_deadline);
     773           10 :     GNUNET_assert (0 ==
     774              :                    json_object_set_new (ds->contract_terms,
     775              :                                         "refund_deadline",
     776              :                                         GNUNET_JSON_from_timestamp (
     777              :                                           ds->refund_deadline)));
     778              :   }
     779           80 :   GNUNET_assert (GNUNET_OK ==
     780              :                  TALER_string_to_amount (amount,
     781              :                                          &ds->amount));
     782           80 :   ds->expected_response_code = expected_response_code;
     783           80 :   ds->command_initialized = true;
     784              :   {
     785           80 :     struct TALER_TESTING_Command cmd = {
     786              :       .cls = ds,
     787              :       .label = label,
     788              :       .run = &deposit_run,
     789              :       .cleanup = &deposit_cleanup,
     790              :       .traits = &deposit_traits
     791              :     };
     792              : 
     793           80 :     return cmd;
     794              :   }
     795              : }
     796              : 
     797              : 
     798              : struct TALER_TESTING_Command
     799            2 : TALER_TESTING_cmd_deposit_with_ref (
     800              :   const char *label,
     801              :   const char *coin_reference,
     802              :   unsigned int coin_index,
     803              :   struct TALER_FullPayto target_account_payto,
     804              :   const char *contract_terms,
     805              :   struct GNUNET_TIME_Relative refund_deadline,
     806              :   const char *amount,
     807              :   unsigned int expected_response_code,
     808              :   const char *merchant_priv_reference)
     809              : {
     810              :   struct DepositState *ds;
     811              : 
     812            2 :   ds = GNUNET_new (struct DepositState);
     813            2 :   ds->merchant_priv_reference = merchant_priv_reference;
     814            2 :   ds->coin_reference = coin_reference;
     815            2 :   ds->coin_index = coin_index;
     816            2 :   ds->wire_details = TALER_TESTING_make_wire_details (target_account_payto);
     817            2 :   GNUNET_assert (NULL != ds->wire_details);
     818            2 :   ds->contract_terms = json_loads (contract_terms,
     819              :                                    JSON_REJECT_DUPLICATES,
     820              :                                    NULL);
     821            2 :   if (NULL == ds->contract_terms)
     822              :   {
     823            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     824              :                 "Failed to parse contract terms `%s' for CMD `%s'\n",
     825              :                 contract_terms,
     826              :                 label);
     827            0 :     GNUNET_assert (0);
     828              :   }
     829            2 :   ds->wallet_timestamp = GNUNET_TIME_timestamp_get ();
     830            2 :   GNUNET_assert (0 ==
     831              :                  json_object_set_new (ds->contract_terms,
     832              :                                       "timestamp",
     833              :                                       GNUNET_JSON_from_timestamp (
     834              :                                         ds->wallet_timestamp)));
     835            2 :   if (0 != refund_deadline.rel_value_us)
     836              :   {
     837            0 :     ds->refund_deadline = GNUNET_TIME_relative_to_timestamp (refund_deadline);
     838            0 :     GNUNET_assert (0 ==
     839              :                    json_object_set_new (ds->contract_terms,
     840              :                                         "refund_deadline",
     841              :                                         GNUNET_JSON_from_timestamp (
     842              :                                           ds->refund_deadline)));
     843              :   }
     844            2 :   GNUNET_assert (GNUNET_OK ==
     845              :                  TALER_string_to_amount (amount,
     846              :                                          &ds->amount));
     847            2 :   ds->expected_response_code = expected_response_code;
     848            2 :   ds->command_initialized = true;
     849              :   {
     850            2 :     struct TALER_TESTING_Command cmd = {
     851              :       .cls = ds,
     852              :       .label = label,
     853              :       .run = &deposit_run,
     854              :       .cleanup = &deposit_cleanup,
     855              :       .traits = &deposit_traits
     856              :     };
     857              : 
     858            2 :     return cmd;
     859              :   }
     860              : }
     861              : 
     862              : 
     863              : struct TALER_TESTING_Command
     864           14 : TALER_TESTING_cmd_deposit_replay (
     865              :   const char *label,
     866              :   const char *deposit_reference,
     867              :   unsigned int expected_response_code)
     868              : {
     869              :   struct DepositState *ds;
     870              : 
     871           14 :   ds = GNUNET_new (struct DepositState);
     872           14 :   ds->deposit_reference = deposit_reference;
     873           14 :   ds->expected_response_code = expected_response_code;
     874              :   {
     875           14 :     struct TALER_TESTING_Command cmd = {
     876              :       .cls = ds,
     877              :       .label = label,
     878              :       .run = &deposit_run,
     879              :       .cleanup = &deposit_cleanup,
     880              :       .traits = &deposit_traits
     881              :     };
     882              : 
     883           14 :     return cmd;
     884              :   }
     885              : }
     886              : 
     887              : 
     888              : struct TALER_TESTING_Command
     889            0 : TALER_TESTING_cmd_deposit_with_retry (struct TALER_TESTING_Command cmd)
     890              : {
     891              :   struct DepositState *ds;
     892              : 
     893            0 :   GNUNET_assert (&deposit_run == cmd.run);
     894            0 :   ds = cmd.cls;
     895            0 :   ds->do_retry = NUM_RETRIES;
     896            0 :   return cmd;
     897              : }
     898              : 
     899              : 
     900              : /* end of testing_api_cmd_deposit.c */
        

Generated by: LCOV version 2.0-1