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

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2018-2022 Taler Systems SA
       4             : 
       5             :   TALER is free software; you can redistribute it and/or modify it
       6             :   under the terms of the GNU General Public License as published by
       7             :   the Free Software Foundation; either version 3, or (at your
       8             :   option) any later version.
       9             : 
      10             :   TALER is distributed in the hope that it will be useful, but
      11             :   WITHOUT ANY WARRANTY; without even the implied warranty of
      12             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13             :   General Public License for more details.
      14             : 
      15             :   You should have received a copy of the GNU General Public
      16             :   License along with TALER; see the file COPYING.  If not, see
      17             :   <http://www.gnu.org/licenses/>
      18             : */
      19             : /**
      20             :  * @file testing/testing_api_cmd_batch_deposit.c
      21             :  * @brief command for testing /batch-deposit.
      22             :  * @author Marcello Stanisci
      23             :  * @author Christian Grothoff
      24             :  */
      25             : #include "platform.h"
      26             : #include "taler_json_lib.h"
      27             : #include <gnunet/gnunet_curl_lib.h>
      28             : #include "taler_testing_lib.h"
      29             : #include "taler_signatures.h"
      30             : #include "backoff.h"
      31             : 
      32             : 
      33             : /**
      34             :  * How often do we retry before giving up?
      35             :  */
      36             : #define NUM_RETRIES 5
      37             : 
      38             : /**
      39             :  * How long do we wait AT MOST when retrying?
      40             :  */
      41             : #define MAX_BACKOFF GNUNET_TIME_relative_multiply ( \
      42             :     GNUNET_TIME_UNIT_MILLISECONDS, 100)
      43             : 
      44             : 
      45             : /**
      46             :  * Information per coin in the batch.
      47             :  */
      48             : struct Coin
      49             : {
      50             : 
      51             :   /**
      52             :    * Amount to deposit.
      53             :    */
      54             :   struct TALER_Amount amount;
      55             : 
      56             :   /**
      57             :    * Deposit fee.
      58             :    */
      59             :   struct TALER_Amount deposit_fee;
      60             : 
      61             :   /**
      62             :    * Reference to any command that is able to provide a coin,
      63             :    * possibly using $LABEL#$INDEX notation.
      64             :    */
      65             :   char *coin_reference;
      66             : 
      67             :   /**
      68             :    * The command being referenced.
      69             :    */
      70             :   const struct TALER_TESTING_Command *coin_cmd;
      71             : 
      72             :   /**
      73             :    * Index of the coin at @e coin_cmd.
      74             :    */
      75             :   unsigned int coin_idx;
      76             : };
      77             : 
      78             : 
      79             : /**
      80             :  * State for a "batch deposit" CMD.
      81             :  */
      82             : struct BatchDepositState
      83             : {
      84             : 
      85             :   /**
      86             :    * Refund deadline. Zero for no refunds.
      87             :    */
      88             :   struct GNUNET_TIME_Timestamp refund_deadline;
      89             : 
      90             :   /**
      91             :    * Wire deadline.
      92             :    */
      93             :   struct GNUNET_TIME_Timestamp wire_deadline;
      94             : 
      95             :   /**
      96             :    * Timestamp of the /deposit operation in the wallet (contract signing time).
      97             :    */
      98             :   struct GNUNET_TIME_Timestamp wallet_timestamp;
      99             : 
     100             :   /**
     101             :    * How long do we wait until we retry?
     102             :    */
     103             :   struct GNUNET_TIME_Relative backoff;
     104             : 
     105             :   /**
     106             :    * When did the exchange receive the deposit?
     107             :    */
     108             :   struct GNUNET_TIME_Timestamp exchange_timestamp;
     109             : 
     110             :   /**
     111             :    * Signing key used by the exchange to sign the
     112             :    * deposit confirmation.
     113             :    */
     114             :   struct TALER_ExchangePublicKeyP exchange_pub;
     115             : 
     116             :   /**
     117             :    * Set (by the interpreter) to a fresh private key.  This
     118             :    * key will be used to sign the deposit request.
     119             :    */
     120             :   struct TALER_MerchantPrivateKeyP merchant_priv;
     121             : 
     122             :   /**
     123             :    * Deposit handle while operation is running.
     124             :    */
     125             :   struct TALER_EXCHANGE_BatchDepositHandle *dh;
     126             : 
     127             :   /**
     128             :    * Array of coins to batch-deposit.
     129             :    */
     130             :   struct Coin *coins;
     131             : 
     132             :   /**
     133             :    * Wire details of who is depositing -- this would be merchant
     134             :    * wire details in a normal scenario.
     135             :    */
     136             :   json_t *wire_details;
     137             : 
     138             :   /**
     139             :    * JSON string describing what a proposal is about.
     140             :    */
     141             :   json_t *contract_terms;
     142             : 
     143             :   /**
     144             :    * Interpreter state.
     145             :    */
     146             :   struct TALER_TESTING_Interpreter *is;
     147             : 
     148             :   /**
     149             :    * Task scheduled to try later.
     150             :    */
     151             :   struct GNUNET_SCHEDULER_Task *retry_task;
     152             : 
     153             :   /**
     154             :    * Array of @e num_coins signatures from the exchange on the
     155             :    * deposit confirmation.
     156             :    */
     157             :   struct TALER_ExchangeSignatureP *exchange_sigs;
     158             : 
     159             :   /**
     160             :    * Reference to previous deposit operation.
     161             :    * Only present if we're supposed to replay the previous deposit.
     162             :    */
     163             :   const char *deposit_reference;
     164             : 
     165             :   /**
     166             :    * If @e coin_reference refers to an operation that generated
     167             :    * an array of coins, this value determines which coin to pick.
     168             :    */
     169             :   unsigned int num_coins;
     170             : 
     171             :   /**
     172             :    * Expected HTTP response code.
     173             :    */
     174             :   unsigned int expected_response_code;
     175             : 
     176             :   /**
     177             :    * Set to true if the /deposit succeeded
     178             :    * and we now can provide the resulting traits.
     179             :    */
     180             :   bool deposit_succeeded;
     181             : 
     182             : };
     183             : 
     184             : 
     185             : /**
     186             :  * Callback to analyze the /batch-deposit response, just used to check if the
     187             :  * response code is acceptable.
     188             :  *
     189             :  * @param cls closure.
     190             :  * @param dr deposit response details
     191             :  */
     192             : static void
     193           0 : batch_deposit_cb (void *cls,
     194             :                   const struct TALER_EXCHANGE_BatchDepositResult *dr)
     195             : {
     196           0 :   struct BatchDepositState *ds = cls;
     197             : 
     198           0 :   ds->dh = NULL;
     199           0 :   if (ds->expected_response_code != dr->hr.http_status)
     200             :   {
     201           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     202             :                 "Unexpected response code %u to command %s in %s:%u\n",
     203             :                 dr->hr.http_status,
     204             :                 ds->is->commands[ds->is->ip].label,
     205             :                 __FILE__,
     206             :                 __LINE__);
     207           0 :     json_dumpf (dr->hr.reply,
     208             :                 stderr,
     209             :                 JSON_INDENT (2));
     210           0 :     TALER_TESTING_interpreter_fail (ds->is);
     211           0 :     return;
     212             :   }
     213           0 :   if (MHD_HTTP_OK == dr->hr.http_status)
     214             :   {
     215           0 :     if (ds->num_coins != dr->details.success.num_signatures)
     216             :     {
     217           0 :       GNUNET_break (0);
     218           0 :       TALER_TESTING_interpreter_fail (ds->is);
     219           0 :       return;
     220             :     }
     221           0 :     ds->deposit_succeeded = GNUNET_YES;
     222           0 :     ds->exchange_timestamp = dr->details.success.deposit_timestamp;
     223           0 :     ds->exchange_pub = *dr->details.success.exchange_pub;
     224           0 :     ds->exchange_sigs = GNUNET_memdup (dr->details.success.exchange_sigs,
     225             :                                        dr->details.success.num_signatures
     226             :                                        * sizeof (struct
     227             :                                                  TALER_ExchangeSignatureP));
     228             :   }
     229           0 :   TALER_TESTING_interpreter_next (ds->is);
     230             : }
     231             : 
     232             : 
     233             : /**
     234             :  * Run the command.
     235             :  *
     236             :  * @param cls closure.
     237             :  * @param cmd the command to execute.
     238             :  * @param is the interpreter state.
     239             :  */
     240             : static void
     241           0 : batch_deposit_run (void *cls,
     242             :                    const struct TALER_TESTING_Command *cmd,
     243             :                    struct TALER_TESTING_Interpreter *is)
     244           0 : {
     245           0 :   struct BatchDepositState *ds = cls;
     246             :   const struct TALER_EXCHANGE_DenomPublicKey *denom_pub;
     247             :   const struct TALER_DenominationSignature *denom_pub_sig;
     248             :   struct TALER_MerchantPublicKeyP merchant_pub;
     249             :   struct TALER_PrivateContractHashP h_contract_terms;
     250             :   enum TALER_ErrorCode ec;
     251             :   struct TALER_WireSaltP wire_salt;
     252             :   struct TALER_MerchantWireHashP h_wire;
     253             :   const char *payto_uri;
     254           0 :   struct TALER_EXCHANGE_CoinDepositDetail cdds[ds->num_coins];
     255             :   struct GNUNET_JSON_Specification spec[] = {
     256           0 :     GNUNET_JSON_spec_string ("payto_uri",
     257             :                              &payto_uri),
     258           0 :     GNUNET_JSON_spec_fixed_auto ("salt",
     259             :                                  &wire_salt),
     260           0 :     GNUNET_JSON_spec_end ()
     261             :   };
     262             : 
     263             :   (void) cmd;
     264           0 :   memset (cdds,
     265             :           0,
     266             :           sizeof (cdds));
     267           0 :   ds->is = is;
     268           0 :   GNUNET_assert (NULL != ds->wire_details);
     269           0 :   if (GNUNET_OK !=
     270           0 :       GNUNET_JSON_parse (ds->wire_details,
     271             :                          spec,
     272             :                          NULL, NULL))
     273             :   {
     274           0 :     json_dumpf (ds->wire_details,
     275             :                 stderr,
     276             :                 JSON_INDENT (2));
     277           0 :     GNUNET_break (0);
     278           0 :     TALER_TESTING_interpreter_fail (is);
     279           0 :     return;
     280             :   }
     281           0 :   if (GNUNET_OK !=
     282           0 :       TALER_JSON_contract_hash (ds->contract_terms,
     283             :                                 &h_contract_terms))
     284             :   {
     285           0 :     GNUNET_break (0);
     286           0 :     TALER_TESTING_interpreter_fail (is);
     287           0 :     return;
     288             :   }
     289           0 :   GNUNET_assert (GNUNET_OK ==
     290             :                  TALER_JSON_merchant_wire_signature_hash (ds->wire_details,
     291             :                                                           &h_wire));
     292           0 :   if (! GNUNET_TIME_absolute_is_zero (ds->refund_deadline.abs_time))
     293             :   {
     294             :     struct GNUNET_TIME_Relative refund_deadline;
     295             : 
     296             :     refund_deadline
     297           0 :       = GNUNET_TIME_absolute_get_remaining (ds->refund_deadline.abs_time);
     298             :     ds->wire_deadline
     299             :       =
     300           0 :         GNUNET_TIME_relative_to_timestamp (
     301             :           GNUNET_TIME_relative_multiply (refund_deadline,
     302             :                                          2));
     303             :   }
     304             :   else
     305             :   {
     306           0 :     ds->refund_deadline = ds->wallet_timestamp;
     307           0 :     ds->wire_deadline = GNUNET_TIME_timestamp_get ();
     308             :   }
     309           0 :   GNUNET_CRYPTO_eddsa_key_get_public (&ds->merchant_priv.eddsa_priv,
     310             :                                       &merchant_pub.eddsa_pub);
     311             : 
     312           0 :   for (unsigned int i = 0; i<ds->num_coins; i++)
     313             :   {
     314           0 :     struct Coin *coin = &ds->coins[i];
     315           0 :     struct TALER_EXCHANGE_CoinDepositDetail *cdd = &cdds[i];
     316             :     const struct TALER_CoinSpendPrivateKeyP *coin_priv;
     317           0 :     const struct TALER_AgeCommitmentProof *age_commitment_proof = NULL;
     318             : 
     319           0 :     GNUNET_assert (NULL != coin->coin_reference);
     320           0 :     cdd->amount = coin->amount;
     321           0 :     coin->coin_cmd = TALER_TESTING_interpreter_lookup_command (
     322             :       is,
     323           0 :       coin->coin_reference);
     324           0 :     if (NULL == coin->coin_cmd)
     325             :     {
     326           0 :       GNUNET_break (0);
     327           0 :       TALER_TESTING_interpreter_fail (is);
     328           0 :       return;
     329             :     }
     330             : 
     331           0 :     if ( (GNUNET_OK !=
     332           0 :           TALER_TESTING_get_trait_coin_priv (coin->coin_cmd,
     333             :                                              coin->coin_idx,
     334           0 :                                              &coin_priv)) ||
     335             :          (GNUNET_OK !=
     336           0 :           TALER_TESTING_get_trait_age_commitment_proof (coin->coin_cmd,
     337             :                                                         coin->coin_idx,
     338             :                                                         &age_commitment_proof))
     339           0 :          ||
     340             :          (GNUNET_OK !=
     341           0 :           TALER_TESTING_get_trait_denom_pub (coin->coin_cmd,
     342             :                                              coin->coin_idx,
     343           0 :                                              &denom_pub)) ||
     344             :          (GNUNET_OK !=
     345           0 :           TALER_TESTING_get_trait_denom_sig (coin->coin_cmd,
     346             :                                              coin->coin_idx,
     347             :                                              &denom_pub_sig)) )
     348             :     {
     349           0 :       GNUNET_break (0);
     350           0 :       TALER_TESTING_interpreter_fail (is);
     351           0 :       return;
     352             :     }
     353           0 :     if (NULL != age_commitment_proof)
     354             :     {
     355           0 :       TALER_age_commitment_hash (&age_commitment_proof->commitment,
     356             :                                  &cdd->h_age_commitment);
     357             :     }
     358           0 :     coin->deposit_fee = denom_pub->fees.deposit;
     359           0 :     GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
     360             :                                         &cdd->coin_pub.eddsa_pub);
     361           0 :     cdd->denom_sig = *denom_pub_sig;
     362           0 :     cdd->h_denom_pub = denom_pub->h_key;
     363           0 :     TALER_wallet_deposit_sign (&coin->amount,
     364           0 :                                &denom_pub->fees.deposit,
     365             :                                &h_wire,
     366             :                                &h_contract_terms,
     367           0 :                                &cdd->h_age_commitment,
     368             :                                NULL, /* FIXME #7270: add hash of extensions */
     369           0 :                                &denom_pub->h_key,
     370             :                                ds->wallet_timestamp,
     371             :                                &merchant_pub,
     372             :                                ds->refund_deadline,
     373             :                                coin_priv,
     374             :                                &cdd->coin_sig);
     375             :   }
     376             : 
     377           0 :   GNUNET_assert (NULL == ds->dh);
     378             :   {
     379           0 :     struct TALER_EXCHANGE_DepositContractDetail dcd = {
     380             :       .wire_deadline = ds->wire_deadline,
     381             :       .merchant_payto_uri = payto_uri,
     382             :       .wire_salt = wire_salt,
     383             :       .h_contract_terms = h_contract_terms,
     384             :       .extension_details = NULL /* FIXME #7270-OEC */,
     385             :       .timestamp = ds->wallet_timestamp,
     386             :       .merchant_pub = merchant_pub,
     387             :       .refund_deadline = ds->refund_deadline
     388             :     };
     389             : 
     390           0 :     ds->dh = TALER_EXCHANGE_batch_deposit (is->exchange,
     391             :                                            &dcd,
     392             :                                            ds->num_coins,
     393             :                                            cdds,
     394             :                                            &batch_deposit_cb,
     395             :                                            ds,
     396             :                                            &ec);
     397             :   }
     398           0 :   if (NULL == ds->dh)
     399             :   {
     400           0 :     GNUNET_break (0);
     401           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     402             :                 "Could not create deposit with EC %d\n",
     403             :                 (int) ec);
     404           0 :     TALER_TESTING_interpreter_fail (is);
     405           0 :     return;
     406             :   }
     407             : }
     408             : 
     409             : 
     410             : /**
     411             :  * Free the state of a "batch-deposit" CMD, and possibly cancel a
     412             :  * pending operation thereof.
     413             :  *
     414             :  * @param cls closure, must be a `struct BatchDepositState`.
     415             :  * @param cmd the command which is being cleaned up.
     416             :  */
     417             : static void
     418           0 : batch_deposit_cleanup (void *cls,
     419             :                        const struct TALER_TESTING_Command *cmd)
     420             : {
     421           0 :   struct BatchDepositState *ds = cls;
     422             : 
     423           0 :   if (NULL != ds->dh)
     424             :   {
     425           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     426             :                 "Command %u (%s) did not complete\n",
     427             :                 ds->is->ip,
     428             :                 cmd->label);
     429           0 :     TALER_EXCHANGE_batch_deposit_cancel (ds->dh);
     430           0 :     ds->dh = NULL;
     431             :   }
     432           0 :   if (NULL != ds->retry_task)
     433             :   {
     434           0 :     GNUNET_SCHEDULER_cancel (ds->retry_task);
     435           0 :     ds->retry_task = NULL;
     436             :   }
     437           0 :   for (unsigned int i = 0; i<ds->num_coins; i++)
     438           0 :     GNUNET_free (ds->coins[i].coin_reference);
     439           0 :   GNUNET_free (ds->coins);
     440           0 :   GNUNET_free (ds->exchange_sigs);
     441           0 :   json_decref (ds->wire_details);
     442           0 :   json_decref (ds->contract_terms);
     443           0 :   GNUNET_free (ds);
     444           0 : }
     445             : 
     446             : 
     447             : /**
     448             :  * Offer internal data from a "batch-deposit" CMD, to other commands.
     449             :  *
     450             :  * @param cls closure.
     451             :  * @param[out] ret result.
     452             :  * @param trait name of the trait.
     453             :  * @param index index number of the object to offer.
     454             :  * @return #GNUNET_OK on success.
     455             :  */
     456             : static enum GNUNET_GenericReturnValue
     457           0 : batch_deposit_traits (void *cls,
     458             :                       const void **ret,
     459             :                       const char *trait,
     460             :                       unsigned int index)
     461             : {
     462           0 :   struct BatchDepositState *ds = cls;
     463           0 :   struct Coin *coin = &ds->coins[index];
     464             :   /* Will point to coin cmd internals. */
     465             :   const struct TALER_CoinSpendPrivateKeyP *coin_spent_priv;
     466             :   const struct TALER_AgeCommitmentProof *age_commitment_proof;
     467             : 
     468           0 :   if (index >= ds->num_coins)
     469             :   {
     470           0 :     GNUNET_break (0);
     471           0 :     return GNUNET_NO;
     472             :   }
     473           0 :   if (NULL == coin->coin_cmd)
     474             :   {
     475           0 :     GNUNET_break (0);
     476           0 :     TALER_TESTING_interpreter_fail (ds->is);
     477           0 :     return GNUNET_NO;
     478             :   }
     479           0 :   if ( (GNUNET_OK !=
     480           0 :         TALER_TESTING_get_trait_coin_priv (coin->coin_cmd,
     481             :                                            coin->coin_idx,
     482           0 :                                            &coin_spent_priv)) ||
     483             :        (GNUNET_OK !=
     484           0 :         TALER_TESTING_get_trait_age_commitment_proof (coin->coin_cmd,
     485             :                                                       coin->coin_idx,
     486             :                                                       &age_commitment_proof)) )
     487             :   {
     488           0 :     GNUNET_break (0);
     489           0 :     TALER_TESTING_interpreter_fail (ds->is);
     490           0 :     return GNUNET_NO;
     491             :   }
     492             :   {
     493             :     struct TALER_TESTING_Trait traits[] = {
     494             :       /* First two traits are only available if
     495             :          ds->traits is #GNUNET_YES */
     496           0 :       TALER_TESTING_make_trait_exchange_pub (index,
     497           0 :                                              &ds->exchange_pub),
     498           0 :       TALER_TESTING_make_trait_exchange_sig (index,
     499           0 :                                              &ds->exchange_sigs[index]),
     500             :       /* These traits are always available */
     501           0 :       TALER_TESTING_make_trait_wire_details (ds->wire_details),
     502           0 :       TALER_TESTING_make_trait_contract_terms (ds->contract_terms),
     503           0 :       TALER_TESTING_make_trait_merchant_priv (&ds->merchant_priv),
     504           0 :       TALER_TESTING_make_trait_age_commitment_proof (index,
     505             :                                                      age_commitment_proof),
     506           0 :       TALER_TESTING_make_trait_coin_priv (index,
     507             :                                           coin_spent_priv),
     508           0 :       TALER_TESTING_make_trait_deposit_amount (index,
     509           0 :                                                &coin->amount),
     510           0 :       TALER_TESTING_make_trait_deposit_fee_amount (index,
     511           0 :                                                    &coin->deposit_fee),
     512             : 
     513           0 :       TALER_TESTING_make_trait_timestamp (index,
     514           0 :                                           &ds->exchange_timestamp),
     515           0 :       TALER_TESTING_make_trait_wire_deadline (index,
     516           0 :                                               &ds->wire_deadline),
     517           0 :       TALER_TESTING_make_trait_refund_deadline (index,
     518           0 :                                                 &ds->refund_deadline),
     519           0 :       TALER_TESTING_trait_end ()
     520             :     };
     521             : 
     522           0 :     return TALER_TESTING_get_trait ((ds->deposit_succeeded)
     523             :                                     ? traits
     524             :                                     : &traits[2],
     525             :                                     ret,
     526             :                                     trait,
     527             :                                     index);
     528             :   }
     529             : }
     530             : 
     531             : 
     532             : struct TALER_TESTING_Command
     533           0 : TALER_TESTING_cmd_batch_deposit (const char *label,
     534             :                                  const char *target_account_payto,
     535             :                                  const char *contract_terms,
     536             :                                  struct GNUNET_TIME_Relative refund_deadline,
     537             :                                  unsigned int expected_response_code,
     538             :                                  ...)
     539             : {
     540             :   struct BatchDepositState *ds;
     541             :   va_list ap;
     542           0 :   unsigned int num_coins = 0;
     543             :   const char *ref;
     544             : 
     545           0 :   va_start (ap,
     546             :             expected_response_code);
     547           0 :   while (NULL != (ref = va_arg (ap,
     548             :                                 const char *)))
     549             :   {
     550           0 :     GNUNET_assert (NULL != va_arg (ap,
     551             :                                    const char *));
     552           0 :     num_coins++;
     553             :   }
     554           0 :   va_end (ap);
     555             : 
     556           0 :   ds = GNUNET_new (struct BatchDepositState);
     557           0 :   ds->num_coins = num_coins;
     558           0 :   ds->coins = GNUNET_new_array (num_coins,
     559             :                                 struct Coin);
     560           0 :   num_coins = 0;
     561           0 :   va_start (ap,
     562             :             expected_response_code);
     563           0 :   while (NULL != (ref = va_arg (ap,
     564             :                                 const char *)))
     565             :   {
     566           0 :     struct Coin *coin = &ds->coins[num_coins++];
     567           0 :     const char *amount = va_arg (ap,
     568             :                                  const char *);
     569             : 
     570           0 :     GNUNET_assert (GNUNET_OK ==
     571             :                    TALER_TESTING_parse_coin_reference (ref,
     572             :                                                        &coin->coin_reference,
     573             :                                                        &coin->coin_idx));
     574           0 :     GNUNET_assert (GNUNET_OK ==
     575             :                    TALER_string_to_amount (amount,
     576             :                                            &coin->amount));
     577             :   }
     578           0 :   va_end (ap);
     579             : 
     580           0 :   ds->wire_details = TALER_TESTING_make_wire_details (target_account_payto);
     581           0 :   GNUNET_assert (NULL != ds->wire_details);
     582           0 :   ds->contract_terms = json_loads (contract_terms,
     583             :                                    JSON_REJECT_DUPLICATES,
     584             :                                    NULL);
     585           0 :   GNUNET_CRYPTO_eddsa_key_create (&ds->merchant_priv.eddsa_priv);
     586           0 :   if (NULL == ds->contract_terms)
     587             :   {
     588           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     589             :                 "Failed to parse contract terms `%s' for CMD `%s'\n",
     590             :                 contract_terms,
     591             :                 label);
     592           0 :     GNUNET_assert (0);
     593             :   }
     594           0 :   ds->wallet_timestamp = GNUNET_TIME_timestamp_get ();
     595           0 :   GNUNET_assert (0 ==
     596             :                  json_object_set_new (ds->contract_terms,
     597             :                                       "timestamp",
     598             :                                       GNUNET_JSON_from_timestamp (
     599             :                                         ds->wallet_timestamp)));
     600           0 :   if (! GNUNET_TIME_relative_is_zero (refund_deadline))
     601             :   {
     602           0 :     ds->refund_deadline = GNUNET_TIME_relative_to_timestamp (refund_deadline);
     603           0 :     GNUNET_assert (0 ==
     604             :                    json_object_set_new (ds->contract_terms,
     605             :                                         "refund_deadline",
     606             :                                         GNUNET_JSON_from_timestamp (
     607             :                                           ds->refund_deadline)));
     608             :   }
     609           0 :   ds->expected_response_code = expected_response_code;
     610             :   {
     611           0 :     struct TALER_TESTING_Command cmd = {
     612             :       .cls = ds,
     613             :       .label = label,
     614             :       .run = &batch_deposit_run,
     615             :       .cleanup = &batch_deposit_cleanup,
     616             :       .traits = &batch_deposit_traits
     617             :     };
     618             : 
     619           0 :     return cmd;
     620             :   }
     621             : }
     622             : 
     623             : 
     624             : /* end of testing_api_cmd_batch_deposit.c */

Generated by: LCOV version 1.14