LCOV - code coverage report
Current view: top level - testing - testing_api_cmd_deposit.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 70.1 % 284 199
Test Date: 2026-03-07 14:54:45 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_PostBatchDepositHandle *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_PostBatchDepositResponse *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_post_batch_deposit_create (
     569              :       TALER_TESTING_interpreter_get_context (is),
     570              :       exchange_url,
     571              :       TALER_TESTING_get_keys (is),
     572              :       &dcd,
     573              :       1,
     574              :       &cdd,
     575              :       &ec);
     576              :   }
     577           96 :   if (NULL == ds->dh)
     578              :   {
     579            0 :     GNUNET_break (0);
     580            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     581              :                 "Could not create deposit with EC %d\n",
     582              :                 (int) ec);
     583            0 :     TALER_TESTING_interpreter_fail (is);
     584            0 :     return;
     585              :   }
     586           96 :   TALER_EXCHANGE_post_batch_deposit_start (ds->dh,
     587              :                                            &deposit_cb,
     588              :                                            ds);
     589              : }
     590              : 
     591              : 
     592              : /**
     593              :  * Free the state of a "deposit" CMD, and possibly cancel a
     594              :  * pending operation thereof.
     595              :  *
     596              :  * @param cls closure, must be a `struct DepositState`.
     597              :  * @param cmd the command which is being cleaned up.
     598              :  */
     599              : static void
     600           96 : deposit_cleanup (void *cls,
     601              :                  const struct TALER_TESTING_Command *cmd)
     602              : {
     603           96 :   struct DepositState *ds = cls;
     604              : 
     605           96 :   if (NULL != ds->dh)
     606              :   {
     607            0 :     TALER_TESTING_command_incomplete (ds->is,
     608              :                                       cmd->label);
     609            0 :     TALER_EXCHANGE_post_batch_deposit_cancel (ds->dh);
     610            0 :     ds->dh = NULL;
     611              :   }
     612           96 :   if (NULL != ds->retry_task)
     613              :   {
     614            0 :     GNUNET_SCHEDULER_cancel (ds->retry_task);
     615            0 :     ds->retry_task = NULL;
     616              :   }
     617           96 :   json_decref (ds->wire_details);
     618           96 :   json_decref (ds->contract_terms);
     619           96 :   GNUNET_free (ds);
     620           96 : }
     621              : 
     622              : 
     623              : /**
     624              :  * Offer internal data from a "deposit" CMD, to other commands.
     625              :  *
     626              :  * @param cls closure.
     627              :  * @param[out] ret result.
     628              :  * @param trait name of the trait.
     629              :  * @param index index number of the object to offer.
     630              :  * @return #GNUNET_OK on success.
     631              :  */
     632              : static enum GNUNET_GenericReturnValue
     633          330 : deposit_traits (void *cls,
     634              :                 const void **ret,
     635              :                 const char *trait,
     636              :                 unsigned int index)
     637              : {
     638          330 :   struct DepositState *ds = cls;
     639              :   const struct TALER_TESTING_Command *coin_cmd;
     640              :   /* Will point to coin cmd internals. */
     641              :   const struct TALER_CoinSpendPrivateKeyP *coin_spent_priv;
     642              :   const struct TALER_CoinSpendPublicKeyP *coin_spent_pub;
     643          330 :   const struct TALER_AgeCommitmentProof *age_commitment_proof=NULL;
     644          330 :   const struct TALER_AgeCommitmentHashP *h_age_commitment=NULL;
     645              : 
     646          330 :   if (! ds->command_initialized)
     647              :   {
     648              :     /* No access to traits yet. */
     649            0 :     GNUNET_break (0);
     650            0 :     return GNUNET_NO;
     651              :   }
     652              : 
     653              :   coin_cmd
     654          330 :     = TALER_TESTING_interpreter_lookup_command (ds->is,
     655              :                                                 ds->coin_reference);
     656          330 :   if (NULL == coin_cmd)
     657              :   {
     658            0 :     GNUNET_break (0);
     659            0 :     TALER_TESTING_interpreter_fail (ds->is);
     660            0 :     return GNUNET_NO;
     661              :   }
     662          330 :   if ( (GNUNET_OK !=
     663          330 :         TALER_TESTING_get_trait_coin_priv (coin_cmd,
     664              :                                            ds->coin_index,
     665          330 :                                            &coin_spent_priv)) ||
     666              :        (GNUNET_OK !=
     667          330 :         TALER_TESTING_get_trait_coin_pub (coin_cmd,
     668              :                                           ds->coin_index,
     669          330 :                                           &coin_spent_pub)) ||
     670              :        (GNUNET_OK !=
     671          330 :         TALER_TESTING_get_trait_age_commitment_proof (coin_cmd,
     672              :                                                       ds->coin_index,
     673          330 :                                                       &age_commitment_proof)) ||
     674              :        (GNUNET_OK !=
     675          330 :         TALER_TESTING_get_trait_h_age_commitment (coin_cmd,
     676              :                                                   ds->coin_index,
     677              :                                                   &h_age_commitment)) )
     678              :   {
     679            0 :     GNUNET_break (0);
     680            0 :     TALER_TESTING_interpreter_fail (ds->is);
     681            0 :     return GNUNET_NO;
     682              :   }
     683              : 
     684              :   {
     685              :     struct TALER_TESTING_Trait traits[] = {
     686              :       /* First two traits are only available if
     687              :          ds->traits is true */
     688          330 :       TALER_TESTING_make_trait_exchange_pub (0,
     689          330 :                                              &ds->exchange_pub),
     690          330 :       TALER_TESTING_make_trait_exchange_sig (0,
     691          330 :                                              &ds->exchange_sig),
     692              :       /* These traits are always available */
     693          330 :       TALER_TESTING_make_trait_coin_history (0,
     694          330 :                                              &ds->che),
     695          330 :       TALER_TESTING_make_trait_coin_priv (0,
     696              :                                           coin_spent_priv),
     697          330 :       TALER_TESTING_make_trait_coin_pub (0,
     698              :                                          coin_spent_pub),
     699          330 :       TALER_TESTING_make_trait_denom_pub (0,
     700              :                                           ds->denom_pub),
     701          330 :       TALER_TESTING_make_trait_coin_sig (0,
     702          330 :                                          &ds->coin_sig),
     703          330 :       TALER_TESTING_make_trait_age_commitment_proof (0,
     704              :                                                      age_commitment_proof),
     705          330 :       TALER_TESTING_make_trait_h_age_commitment (0,
     706              :                                                  h_age_commitment),
     707          330 :       TALER_TESTING_make_trait_wire_details (ds->wire_details),
     708          330 :       TALER_TESTING_make_trait_contract_terms (ds->contract_terms),
     709          330 :       TALER_TESTING_make_trait_merchant_priv (&ds->account_priv.merchant_priv),
     710          330 :       TALER_TESTING_make_trait_merchant_pub (&ds->account_pub.merchant_pub),
     711          330 :       TALER_TESTING_make_trait_account_priv (&ds->account_priv),
     712          330 :       TALER_TESTING_make_trait_account_pub (&ds->account_pub),
     713          330 :       TALER_TESTING_make_trait_deposit_amount (0,
     714          330 :                                                &ds->amount),
     715          330 :       TALER_TESTING_make_trait_deposit_fee_amount (0,
     716          330 :                                                    &ds->deposit_fee),
     717          330 :       TALER_TESTING_make_trait_timestamp (0,
     718          330 :                                           &ds->exchange_timestamp),
     719          330 :       TALER_TESTING_make_trait_wire_deadline (0,
     720          330 :                                               &ds->wire_deadline),
     721          330 :       TALER_TESTING_make_trait_refund_deadline (0,
     722          330 :                                                 &ds->refund_deadline),
     723          330 :       TALER_TESTING_trait_end ()
     724              :     };
     725              : 
     726          330 :     return TALER_TESTING_get_trait ((ds->deposit_succeeded)
     727              :                                     ? traits
     728              :                                     : &traits[2],
     729              :                                     ret,
     730              :                                     trait,
     731              :                                     index);
     732              :   }
     733              : }
     734              : 
     735              : 
     736              : struct TALER_TESTING_Command
     737           80 : TALER_TESTING_cmd_deposit (
     738              :   const char *label,
     739              :   const char *coin_reference,
     740              :   unsigned int coin_index,
     741              :   struct TALER_FullPayto target_account_payto,
     742              :   const char *contract_terms,
     743              :   struct GNUNET_TIME_Relative refund_deadline,
     744              :   const char *amount,
     745              :   unsigned int expected_response_code)
     746              : {
     747              :   struct DepositState *ds;
     748              : 
     749           80 :   ds = GNUNET_new (struct DepositState);
     750           80 :   ds->coin_reference = coin_reference;
     751           80 :   ds->coin_index = coin_index;
     752           80 :   ds->wire_details = TALER_TESTING_make_wire_details (target_account_payto);
     753           80 :   GNUNET_assert (NULL != ds->wire_details);
     754           80 :   ds->contract_terms = json_loads (contract_terms,
     755              :                                    JSON_REJECT_DUPLICATES,
     756              :                                    NULL);
     757           80 :   if (NULL == ds->contract_terms)
     758              :   {
     759            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     760              :                 "Failed to parse contract terms `%s' for CMD `%s'\n",
     761              :                 contract_terms,
     762              :                 label);
     763            0 :     GNUNET_assert (0);
     764              :   }
     765           80 :   ds->wallet_timestamp = GNUNET_TIME_timestamp_get ();
     766           80 :   GNUNET_assert (0 ==
     767              :                  json_object_set_new (ds->contract_terms,
     768              :                                       "timestamp",
     769              :                                       GNUNET_JSON_from_timestamp (
     770              :                                         ds->wallet_timestamp)));
     771           80 :   if (! GNUNET_TIME_relative_is_zero (refund_deadline))
     772              :   {
     773           10 :     ds->refund_deadline = GNUNET_TIME_relative_to_timestamp (refund_deadline);
     774           10 :     GNUNET_assert (0 ==
     775              :                    json_object_set_new (ds->contract_terms,
     776              :                                         "refund_deadline",
     777              :                                         GNUNET_JSON_from_timestamp (
     778              :                                           ds->refund_deadline)));
     779              :   }
     780           80 :   GNUNET_assert (GNUNET_OK ==
     781              :                  TALER_string_to_amount (amount,
     782              :                                          &ds->amount));
     783           80 :   ds->expected_response_code = expected_response_code;
     784           80 :   ds->command_initialized = true;
     785              :   {
     786           80 :     struct TALER_TESTING_Command cmd = {
     787              :       .cls = ds,
     788              :       .label = label,
     789              :       .run = &deposit_run,
     790              :       .cleanup = &deposit_cleanup,
     791              :       .traits = &deposit_traits
     792              :     };
     793              : 
     794           80 :     return cmd;
     795              :   }
     796              : }
     797              : 
     798              : 
     799              : struct TALER_TESTING_Command
     800            2 : TALER_TESTING_cmd_deposit_with_ref (
     801              :   const char *label,
     802              :   const char *coin_reference,
     803              :   unsigned int coin_index,
     804              :   struct TALER_FullPayto target_account_payto,
     805              :   const char *contract_terms,
     806              :   struct GNUNET_TIME_Relative refund_deadline,
     807              :   const char *amount,
     808              :   unsigned int expected_response_code,
     809              :   const char *merchant_priv_reference)
     810              : {
     811              :   struct DepositState *ds;
     812              : 
     813            2 :   ds = GNUNET_new (struct DepositState);
     814            2 :   ds->merchant_priv_reference = merchant_priv_reference;
     815            2 :   ds->coin_reference = coin_reference;
     816            2 :   ds->coin_index = coin_index;
     817            2 :   ds->wire_details = TALER_TESTING_make_wire_details (target_account_payto);
     818            2 :   GNUNET_assert (NULL != ds->wire_details);
     819            2 :   ds->contract_terms = json_loads (contract_terms,
     820              :                                    JSON_REJECT_DUPLICATES,
     821              :                                    NULL);
     822            2 :   if (NULL == ds->contract_terms)
     823              :   {
     824            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     825              :                 "Failed to parse contract terms `%s' for CMD `%s'\n",
     826              :                 contract_terms,
     827              :                 label);
     828            0 :     GNUNET_assert (0);
     829              :   }
     830            2 :   ds->wallet_timestamp = GNUNET_TIME_timestamp_get ();
     831            2 :   GNUNET_assert (0 ==
     832              :                  json_object_set_new (ds->contract_terms,
     833              :                                       "timestamp",
     834              :                                       GNUNET_JSON_from_timestamp (
     835              :                                         ds->wallet_timestamp)));
     836            2 :   if (0 != refund_deadline.rel_value_us)
     837              :   {
     838            0 :     ds->refund_deadline = GNUNET_TIME_relative_to_timestamp (refund_deadline);
     839            0 :     GNUNET_assert (0 ==
     840              :                    json_object_set_new (ds->contract_terms,
     841              :                                         "refund_deadline",
     842              :                                         GNUNET_JSON_from_timestamp (
     843              :                                           ds->refund_deadline)));
     844              :   }
     845            2 :   GNUNET_assert (GNUNET_OK ==
     846              :                  TALER_string_to_amount (amount,
     847              :                                          &ds->amount));
     848            2 :   ds->expected_response_code = expected_response_code;
     849            2 :   ds->command_initialized = true;
     850              :   {
     851            2 :     struct TALER_TESTING_Command cmd = {
     852              :       .cls = ds,
     853              :       .label = label,
     854              :       .run = &deposit_run,
     855              :       .cleanup = &deposit_cleanup,
     856              :       .traits = &deposit_traits
     857              :     };
     858              : 
     859            2 :     return cmd;
     860              :   }
     861              : }
     862              : 
     863              : 
     864              : struct TALER_TESTING_Command
     865           14 : TALER_TESTING_cmd_deposit_replay (
     866              :   const char *label,
     867              :   const char *deposit_reference,
     868              :   unsigned int expected_response_code)
     869              : {
     870              :   struct DepositState *ds;
     871              : 
     872           14 :   ds = GNUNET_new (struct DepositState);
     873           14 :   ds->deposit_reference = deposit_reference;
     874           14 :   ds->expected_response_code = expected_response_code;
     875              :   {
     876           14 :     struct TALER_TESTING_Command cmd = {
     877              :       .cls = ds,
     878              :       .label = label,
     879              :       .run = &deposit_run,
     880              :       .cleanup = &deposit_cleanup,
     881              :       .traits = &deposit_traits
     882              :     };
     883              : 
     884           14 :     return cmd;
     885              :   }
     886              : }
     887              : 
     888              : 
     889              : struct TALER_TESTING_Command
     890            0 : TALER_TESTING_cmd_deposit_with_retry (struct TALER_TESTING_Command cmd)
     891              : {
     892              :   struct DepositState *ds;
     893              : 
     894            0 :   GNUNET_assert (&deposit_run == cmd.run);
     895            0 :   ds = cmd.cls;
     896            0 :   ds->do_retry = NUM_RETRIES;
     897            0 :   return cmd;
     898              : }
     899              : 
     900              : 
     901              : /* end of testing_api_cmd_deposit.c */
        

Generated by: LCOV version 2.0-1