LCOV - code coverage report
Current view: top level - testing - testing_api_cmd_deposit.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 197 282 69.9 %
Date: 2025-06-05 21:03:14 Functions: 7 9 77.8 %

          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 "platform.h"
      25             : #include "taler_json_lib.h"
      26             : #include <gnunet/gnunet_curl_lib.h>
      27             : #include "taler_testing_lib.h"
      28             : #include "taler_signatures.h"
      29             : #include "backoff.h"
      30             : 
      31             : 
      32             : /**
      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_AgeCommitmentHash *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             :   struct TALER_CoinSpendPublicKeyP coin_spent_pub;
     642         330 :   const struct TALER_AgeCommitmentProof *age_commitment_proof=NULL;
     643         330 :   const struct TALER_AgeCommitmentHash *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_age_commitment_proof (coin_cmd,
     667             :                                                       ds->coin_index,
     668         330 :                                                       &age_commitment_proof)) ||
     669             :        (GNUNET_OK !=
     670         330 :         TALER_TESTING_get_trait_h_age_commitment (coin_cmd,
     671             :                                                   ds->coin_index,
     672             :                                                   &h_age_commitment)) )
     673             :   {
     674           0 :     GNUNET_break (0);
     675           0 :     TALER_TESTING_interpreter_fail (ds->is);
     676           0 :     return GNUNET_NO;
     677             :   }
     678             : 
     679         330 :   GNUNET_CRYPTO_eddsa_key_get_public (&coin_spent_priv->eddsa_priv,
     680             :                                       &coin_spent_pub.eddsa_pub);
     681             : 
     682             :   {
     683             :     struct TALER_TESTING_Trait traits[] = {
     684             :       /* First two traits are only available if
     685             :          ds->traits is true */
     686         330 :       TALER_TESTING_make_trait_exchange_pub (0,
     687         330 :                                              &ds->exchange_pub),
     688         330 :       TALER_TESTING_make_trait_exchange_sig (0,
     689         330 :                                              &ds->exchange_sig),
     690             :       /* These traits are always available */
     691         330 :       TALER_TESTING_make_trait_coin_history (0,
     692         330 :                                              &ds->che),
     693         330 :       TALER_TESTING_make_trait_coin_priv (0,
     694             :                                           coin_spent_priv),
     695         330 :       TALER_TESTING_make_trait_coin_pub (0,
     696             :                                          &coin_spent_pub),
     697         330 :       TALER_TESTING_make_trait_denom_pub (0,
     698             :                                           ds->denom_pub),
     699         330 :       TALER_TESTING_make_trait_coin_sig (0,
     700         330 :                                          &ds->coin_sig),
     701         330 :       TALER_TESTING_make_trait_age_commitment_proof (0,
     702             :                                                      age_commitment_proof),
     703         330 :       TALER_TESTING_make_trait_h_age_commitment (0,
     704             :                                                  h_age_commitment),
     705         330 :       TALER_TESTING_make_trait_wire_details (ds->wire_details),
     706         330 :       TALER_TESTING_make_trait_contract_terms (ds->contract_terms),
     707         330 :       TALER_TESTING_make_trait_merchant_priv (&ds->account_priv.merchant_priv),
     708         330 :       TALER_TESTING_make_trait_merchant_pub (&ds->account_pub.merchant_pub),
     709         330 :       TALER_TESTING_make_trait_account_priv (&ds->account_priv),
     710         330 :       TALER_TESTING_make_trait_account_pub (&ds->account_pub),
     711         330 :       TALER_TESTING_make_trait_deposit_amount (0,
     712         330 :                                                &ds->amount),
     713         330 :       TALER_TESTING_make_trait_deposit_fee_amount (0,
     714         330 :                                                    &ds->deposit_fee),
     715         330 :       TALER_TESTING_make_trait_timestamp (0,
     716         330 :                                           &ds->exchange_timestamp),
     717         330 :       TALER_TESTING_make_trait_wire_deadline (0,
     718         330 :                                               &ds->wire_deadline),
     719         330 :       TALER_TESTING_make_trait_refund_deadline (0,
     720         330 :                                                 &ds->refund_deadline),
     721         330 :       TALER_TESTING_trait_end ()
     722             :     };
     723             : 
     724         330 :     return TALER_TESTING_get_trait ((ds->deposit_succeeded)
     725             :                                     ? traits
     726             :                                     : &traits[2],
     727             :                                     ret,
     728             :                                     trait,
     729             :                                     index);
     730             :   }
     731             : }
     732             : 
     733             : 
     734             : struct TALER_TESTING_Command
     735          80 : TALER_TESTING_cmd_deposit (
     736             :   const char *label,
     737             :   const char *coin_reference,
     738             :   unsigned int coin_index,
     739             :   struct TALER_FullPayto target_account_payto,
     740             :   const char *contract_terms,
     741             :   struct GNUNET_TIME_Relative refund_deadline,
     742             :   const char *amount,
     743             :   unsigned int expected_response_code)
     744             : {
     745             :   struct DepositState *ds;
     746             : 
     747          80 :   ds = GNUNET_new (struct DepositState);
     748          80 :   ds->coin_reference = coin_reference;
     749          80 :   ds->coin_index = coin_index;
     750          80 :   ds->wire_details = TALER_TESTING_make_wire_details (target_account_payto);
     751          80 :   GNUNET_assert (NULL != ds->wire_details);
     752          80 :   ds->contract_terms = json_loads (contract_terms,
     753             :                                    JSON_REJECT_DUPLICATES,
     754             :                                    NULL);
     755          80 :   if (NULL == ds->contract_terms)
     756             :   {
     757           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     758             :                 "Failed to parse contract terms `%s' for CMD `%s'\n",
     759             :                 contract_terms,
     760             :                 label);
     761           0 :     GNUNET_assert (0);
     762             :   }
     763          80 :   ds->wallet_timestamp = GNUNET_TIME_timestamp_get ();
     764          80 :   GNUNET_assert (0 ==
     765             :                  json_object_set_new (ds->contract_terms,
     766             :                                       "timestamp",
     767             :                                       GNUNET_JSON_from_timestamp (
     768             :                                         ds->wallet_timestamp)));
     769          80 :   if (! GNUNET_TIME_relative_is_zero (refund_deadline))
     770             :   {
     771          10 :     ds->refund_deadline = GNUNET_TIME_relative_to_timestamp (refund_deadline);
     772          10 :     GNUNET_assert (0 ==
     773             :                    json_object_set_new (ds->contract_terms,
     774             :                                         "refund_deadline",
     775             :                                         GNUNET_JSON_from_timestamp (
     776             :                                           ds->refund_deadline)));
     777             :   }
     778          80 :   GNUNET_assert (GNUNET_OK ==
     779             :                  TALER_string_to_amount (amount,
     780             :                                          &ds->amount));
     781          80 :   ds->expected_response_code = expected_response_code;
     782          80 :   ds->command_initialized = true;
     783             :   {
     784          80 :     struct TALER_TESTING_Command cmd = {
     785             :       .cls = ds,
     786             :       .label = label,
     787             :       .run = &deposit_run,
     788             :       .cleanup = &deposit_cleanup,
     789             :       .traits = &deposit_traits
     790             :     };
     791             : 
     792          80 :     return cmd;
     793             :   }
     794             : }
     795             : 
     796             : 
     797             : struct TALER_TESTING_Command
     798           2 : TALER_TESTING_cmd_deposit_with_ref (
     799             :   const char *label,
     800             :   const char *coin_reference,
     801             :   unsigned int coin_index,
     802             :   struct TALER_FullPayto target_account_payto,
     803             :   const char *contract_terms,
     804             :   struct GNUNET_TIME_Relative refund_deadline,
     805             :   const char *amount,
     806             :   unsigned int expected_response_code,
     807             :   const char *merchant_priv_reference)
     808             : {
     809             :   struct DepositState *ds;
     810             : 
     811           2 :   ds = GNUNET_new (struct DepositState);
     812           2 :   ds->merchant_priv_reference = merchant_priv_reference;
     813           2 :   ds->coin_reference = coin_reference;
     814           2 :   ds->coin_index = coin_index;
     815           2 :   ds->wire_details = TALER_TESTING_make_wire_details (target_account_payto);
     816           2 :   GNUNET_assert (NULL != ds->wire_details);
     817           2 :   ds->contract_terms = json_loads (contract_terms,
     818             :                                    JSON_REJECT_DUPLICATES,
     819             :                                    NULL);
     820           2 :   if (NULL == ds->contract_terms)
     821             :   {
     822           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     823             :                 "Failed to parse contract terms `%s' for CMD `%s'\n",
     824             :                 contract_terms,
     825             :                 label);
     826           0 :     GNUNET_assert (0);
     827             :   }
     828           2 :   ds->wallet_timestamp = GNUNET_TIME_timestamp_get ();
     829           2 :   GNUNET_assert (0 ==
     830             :                  json_object_set_new (ds->contract_terms,
     831             :                                       "timestamp",
     832             :                                       GNUNET_JSON_from_timestamp (
     833             :                                         ds->wallet_timestamp)));
     834           2 :   if (0 != refund_deadline.rel_value_us)
     835             :   {
     836           0 :     ds->refund_deadline = GNUNET_TIME_relative_to_timestamp (refund_deadline);
     837           0 :     GNUNET_assert (0 ==
     838             :                    json_object_set_new (ds->contract_terms,
     839             :                                         "refund_deadline",
     840             :                                         GNUNET_JSON_from_timestamp (
     841             :                                           ds->refund_deadline)));
     842             :   }
     843           2 :   GNUNET_assert (GNUNET_OK ==
     844             :                  TALER_string_to_amount (amount,
     845             :                                          &ds->amount));
     846           2 :   ds->expected_response_code = expected_response_code;
     847           2 :   ds->command_initialized = true;
     848             :   {
     849           2 :     struct TALER_TESTING_Command cmd = {
     850             :       .cls = ds,
     851             :       .label = label,
     852             :       .run = &deposit_run,
     853             :       .cleanup = &deposit_cleanup,
     854             :       .traits = &deposit_traits
     855             :     };
     856             : 
     857           2 :     return cmd;
     858             :   }
     859             : }
     860             : 
     861             : 
     862             : struct TALER_TESTING_Command
     863          14 : TALER_TESTING_cmd_deposit_replay (
     864             :   const char *label,
     865             :   const char *deposit_reference,
     866             :   unsigned int expected_response_code)
     867             : {
     868             :   struct DepositState *ds;
     869             : 
     870          14 :   ds = GNUNET_new (struct DepositState);
     871          14 :   ds->deposit_reference = deposit_reference;
     872          14 :   ds->expected_response_code = expected_response_code;
     873             :   {
     874          14 :     struct TALER_TESTING_Command cmd = {
     875             :       .cls = ds,
     876             :       .label = label,
     877             :       .run = &deposit_run,
     878             :       .cleanup = &deposit_cleanup,
     879             :       .traits = &deposit_traits
     880             :     };
     881             : 
     882          14 :     return cmd;
     883             :   }
     884             : }
     885             : 
     886             : 
     887             : struct TALER_TESTING_Command
     888           0 : TALER_TESTING_cmd_deposit_with_retry (struct TALER_TESTING_Command cmd)
     889             : {
     890             :   struct DepositState *ds;
     891             : 
     892           0 :   GNUNET_assert (&deposit_run == cmd.run);
     893           0 :   ds = cmd.cls;
     894           0 :   ds->do_retry = NUM_RETRIES;
     895           0 :   return cmd;
     896             : }
     897             : 
     898             : 
     899             : /* end of testing_api_cmd_deposit.c */

Generated by: LCOV version 1.16