LCOV - code coverage report
Current view: top level - testing - testing_api_cmd_refresh.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 66.0 % 371 245
Test Date: 2025-12-26 23:00:34 Functions: 75.0 % 16 12

            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_refresh.c
      21              :  * @brief commands for testing all "refresh" features.
      22              :  * @author Marcello Stanisci
      23              :  * @author Özgür Kesim
      24              :  */
      25              : #include "taler/platform.h"
      26              : #include "taler/taler_json_lib.h"
      27              : #include <gnunet/gnunet_curl_lib.h>
      28              : #include "taler/taler_testing_lib.h"
      29              : #include "taler/taler_signatures.h"
      30              : #include "taler/backoff.h"
      31              : 
      32              : /**
      33              :  * How long do we wait AT MOST when retrying?
      34              :  */
      35              : #define MAX_BACKOFF GNUNET_TIME_relative_multiply ( \
      36              :           GNUNET_TIME_UNIT_MILLISECONDS, 100)
      37              : 
      38              : /**
      39              :  * How often do we retry before giving up?
      40              :  */
      41              : #define NUM_RETRIES 5
      42              : 
      43              : /**
      44              :  * How long do we wait AT MOST when retrying?
      45              :  */
      46              : #define MAX_BACKOFF GNUNET_TIME_relative_multiply ( \
      47              :           GNUNET_TIME_UNIT_MILLISECONDS, 100)
      48              : 
      49              : /**
      50              :  * Information about a fresh coin generated by the refresh
      51              :  * operation.
      52              :  */
      53              : struct TALER_TESTING_FreshCoinData
      54              : {
      55              : 
      56              :   /**
      57              :    * If @e amount is NULL, this specifies the denomination key to
      58              :    * use.  Otherwise, this will be set (by the interpreter) to the
      59              :    * denomination PK matching @e amount.
      60              :    */
      61              :   const struct TALER_EXCHANGE_DenomPublicKey *pk;
      62              : 
      63              :   /**
      64              :    * Set (by the interpreter) to the exchange's signature over the
      65              :    * coin's public key.
      66              :    */
      67              :   struct TALER_DenominationSignature sig;
      68              : 
      69              :   /**
      70              :    * Set (by the interpreter) to the coin's private key.
      71              :    */
      72              :   struct TALER_CoinSpendPrivateKeyP coin_priv;
      73              : 
      74              :   /**
      75              :    * Set (by the interpreter) to the coin's public key.
      76              :    */
      77              :   struct TALER_CoinSpendPublicKeyP coin_pub;
      78              : 
      79              :   /**
      80              :    * Fresh age commitment for the coin with proof and its hash, NULL if not
      81              :    * applicable.
      82              :    */
      83              :   struct TALER_AgeCommitmentProof *age_commitment_proof;
      84              :   struct TALER_AgeCommitmentHashP h_age_commitment;
      85              : 
      86              :   /**
      87              :    * The blinding key (needed for recoup operations).
      88              :    */
      89              :   union GNUNET_CRYPTO_BlindingSecretP blinding_key;
      90              : 
      91              : };
      92              : 
      93              : 
      94              : /**
      95              :  * State for a "refresh melt" command.
      96              :  */
      97              : struct MeltState
      98              : {
      99              : 
     100              :   /**
     101              :    * Reference to reserve_withdraw operations for coin to
     102              :    * be used for the /refresh/melt operation.
     103              :    */
     104              :   const char *coin_reference;
     105              : 
     106              :   /**
     107              :    * Our command.
     108              :    */
     109              :   const struct TALER_TESTING_Command *cmd;
     110              : 
     111              :   /**
     112              :    * Reference to a previous melt command.
     113              :    */
     114              :   const char *melt_reference;
     115              : 
     116              :   /**
     117              :    * Melt handle while operation is running.
     118              :    */
     119              :   struct TALER_EXCHANGE_MeltHandle *mh;
     120              : 
     121              :   /**
     122              :    * Expected entry in the coin history created by this
     123              :    * operation.
     124              :    */
     125              :   struct TALER_EXCHANGE_CoinHistoryEntry che;
     126              : 
     127              :   /**
     128              :    * Interpreter state.
     129              :    */
     130              :   struct TALER_TESTING_Interpreter *is;
     131              : 
     132              :   /**
     133              :    * The input for the call to /melt
     134              :    */
     135              :   struct TALER_EXCHANGE_MeltInput melt_input;
     136              : 
     137              :   /**
     138              :    * Length of the @a blinding_values array with the exchange values
     139              :    * and blinding keys we are using.
     140              :    */
     141              :   unsigned int num_blinding_values;
     142              : 
     143              :   /**
     144              :    * Blinding values returned per coin.
     145              :    */
     146              :   struct TALER_ExchangeBlindingValues *blinding_values;
     147              : 
     148              :   /**
     149              :    * The input for the call to /reveal-melt
     150              :    */
     151              :   struct TALER_EXCHANGE_RevealMeltInput reveal_melt_input;
     152              : 
     153              :   /**
     154              :    * Array of the denomination public keys
     155              :    * corresponding to the @e num_fresh_coins;
     156              :    */
     157              :   struct TALER_EXCHANGE_DenomPublicKey *fresh_pks;
     158              : 
     159              :   /**
     160              :    * Private key of the dirty coin being melted.
     161              :    */
     162              :   const struct TALER_CoinSpendPrivateKeyP *melt_priv;
     163              : 
     164              :   /**
     165              :    * Public key of the dirty coin being melted.
     166              :    */
     167              :   struct TALER_CoinSpendPublicKeyP melt_pub;
     168              : 
     169              :   /**
     170              :    * Entropy seed for the refresh-melt operation.
     171              :    */
     172              :   struct TALER_PublicRefreshMasterSeedP rms;
     173              : 
     174              :   /**
     175              :    * If false, @e blinding_seed contains the seed for the
     176              :    * blinding values for CS signatures
     177              :    */
     178              :   bool no_blinding_seed;
     179              : 
     180              :   /**
     181              :    * If @e no_blinding_seed is false, contains the blinding
     182              :    * seed from which the nonces were derived for CS signatures
     183              :    */
     184              :   struct TALER_BlindingMasterSeedP blinding_seed;
     185              : 
     186              :   /**
     187              :    * The refresh commitment we calculated
     188              :    */
     189              :   struct TALER_RefreshCommitmentP rc;
     190              : 
     191              :   /**
     192              :    * The kappa refresh nonces for signing with the old coin.
     193              :    */
     194              :   struct TALER_KappaPublicRefreshNoncesP kappa_nonces;
     195              : 
     196              :   /**
     197              :    * Task scheduled to try later.
     198              :    */
     199              :   struct GNUNET_SCHEDULER_Task *retry_task;
     200              : 
     201              :   /**
     202              :    * How long do we wait until we retry?
     203              :    */
     204              :   struct GNUNET_TIME_Relative backoff;
     205              : 
     206              :   /**
     207              :    * How long did we wait in total for retries?
     208              :    */
     209              :   struct GNUNET_TIME_Relative total_backoff;
     210              : 
     211              :   /**
     212              :    * Amounts to be generated during melt.
     213              :    */
     214              :   const char **melt_fresh_amounts;
     215              : 
     216              :   /**
     217              :    * Number of fresh coins generated by the melt.
     218              :    */
     219              :   unsigned int num_fresh_coins;
     220              : 
     221              :   /**
     222              :    * Expected HTTP response code.
     223              :    */
     224              :   unsigned int expected_response_code;
     225              : 
     226              :   /**
     227              :    * if set to #GNUNET_YES, then two /refresh/melt operations
     228              :    * will be performed.  This is needed to trigger the logic
     229              :    * that manages those already-made requests.  Note: it
     230              :    * is not possible to just copy-and-paste a test refresh melt
     231              :    * CMD to have the same effect, because every data preparation
     232              :    * generates new planchets that (in turn) make the whole "hash"
     233              :    * different from any previous one, therefore NOT allowing the
     234              :    * exchange to pick any previous /rerfesh/melt operation from
     235              :    * the database.
     236              :    */
     237              :   bool double_melt;
     238              : 
     239              :   /**
     240              :    * How often should we retry on (transient) failures?
     241              :    */
     242              :   unsigned int do_retry;
     243              : 
     244              :   /**
     245              :    * Set by the melt callback as it comes from the exchange.
     246              :    */
     247              :   uint16_t noreveal_index;
     248              : 
     249              :   /**
     250              :    * The signatures over the nonces we need to reveal
     251              :    */
     252              :   struct TALER_RevealPrivateRefreshNonceSignaturesP revealed_signatures;
     253              : 
     254              : };
     255              : 
     256              : 
     257              : /**
     258              :  * State for a "refresh reveal" CMD.
     259              :  */
     260              : struct RevealMeltState
     261              : {
     262              :   /**
     263              :    * Link to a "refresh melt" command.
     264              :    */
     265              :   const char *melt_reference;
     266              : 
     267              :   /**
     268              :    * Reveal handle while operation is running.
     269              :    */
     270              :   struct TALER_EXCHANGE_RevealMeltHandle *rmh;
     271              : 
     272              :   /**
     273              :    * Our command.
     274              :    */
     275              :   const struct TALER_TESTING_Command *cmd;
     276              : 
     277              :   /**
     278              :    * Convenience struct to keep in one place all the
     279              :    * data related to one fresh coin, set by the reveal callback
     280              :    * as it comes from the exchange.
     281              :    */
     282              :   struct TALER_TESTING_FreshCoinData *fresh_coins;
     283              : 
     284              :   /**
     285              :    * Array of @e num_fresh_coins planchet secrets derived
     286              :    * from the transfer secret per fresh coin.
     287              :    */
     288              :   struct TALER_PlanchetMasterSecretP *psa;
     289              : 
     290              :   /**
     291              :    * Interpreter state.
     292              :    */
     293              :   struct TALER_TESTING_Interpreter *is;
     294              : 
     295              :   /**
     296              :    * Task scheduled to try later.
     297              :    */
     298              :   struct GNUNET_SCHEDULER_Task *retry_task;
     299              : 
     300              :   /**
     301              :    * How long do we wait until we retry?
     302              :    */
     303              :   struct GNUNET_TIME_Relative backoff;
     304              : 
     305              :   /**
     306              :    * How long did we wait in total for retries?
     307              :    */
     308              :   struct GNUNET_TIME_Relative total_backoff;
     309              : 
     310              :   /**
     311              :    * Number of fresh coins withdrawn, set by the
     312              :    * reveal callback as it comes from the exchange,
     313              :    * it is the length of the @e fresh_coins array.
     314              :    */
     315              :   unsigned int num_fresh_coins;
     316              : 
     317              :   /**
     318              :    * Expected HTTP response code.
     319              :    */
     320              :   unsigned int expected_response_code;
     321              : 
     322              :   /**
     323              :    * How often should we retry on (transient) failures?
     324              :    */
     325              :   unsigned int do_retry;
     326              : 
     327              : };
     328              : 
     329              : 
     330              : /**
     331              :  * State for a "refresh link" CMD.
     332              :  */
     333              : struct RefreshLinkState
     334              : {
     335              :   /**
     336              :    * Link to a "refresh reveal" command.
     337              :    */
     338              :   const char *reveal_reference;
     339              : 
     340              :   /**
     341              :    * Our command.
     342              :    */
     343              :   const struct TALER_TESTING_Command *cmd;
     344              : 
     345              :   /**
     346              :    * Handle to the ongoing operation.
     347              :    */
     348              :   struct TALER_EXCHANGE_LinkHandle *rlh;
     349              : 
     350              :   /**
     351              :    * Interpreter state.
     352              :    */
     353              :   struct TALER_TESTING_Interpreter *is;
     354              : 
     355              :   /**
     356              :    * Task scheduled to try later.
     357              :    */
     358              :   struct GNUNET_SCHEDULER_Task *retry_task;
     359              : 
     360              :   /**
     361              :    * How long do we wait until we retry?
     362              :    */
     363              :   struct GNUNET_TIME_Relative backoff;
     364              : 
     365              :   /**
     366              :    * How long did we wait in total for retries?
     367              :    */
     368              :   struct GNUNET_TIME_Relative total_backoff;
     369              : 
     370              :   /**
     371              :    * Expected HTTP response code.
     372              :    */
     373              :   unsigned int expected_response_code;
     374              : 
     375              :   /**
     376              :    * How often should we retry on (transient) failures?
     377              :    */
     378              :   unsigned int do_retry;
     379              : 
     380              : };
     381              : 
     382              : 
     383              : /**
     384              :  * Run the command.
     385              :  *
     386              :  * @param cls closure.
     387              :  * @param cmd the command to execute.
     388              :  * @param is the interpreter state.
     389              :  */
     390              : static void
     391              : melt_reveal_run (void *cls,
     392              :                  const struct TALER_TESTING_Command *cmd,
     393              :                  struct TALER_TESTING_Interpreter *is);
     394              : 
     395              : 
     396              : /**
     397              :  * Task scheduled to re-try #melt_reveal_run.
     398              :  *
     399              :  * @param cls a `struct RefreshRevealState`
     400              :  */
     401              : static void
     402            0 : do_reveal_retry (void *cls)
     403              : {
     404            0 :   struct RevealMeltState *rrs = cls;
     405              : 
     406            0 :   rrs->retry_task = NULL;
     407            0 :   TALER_TESTING_touch_cmd (rrs->is);
     408            0 :   melt_reveal_run (rrs,
     409              :                    NULL,
     410              :                    rrs->is);
     411            0 : }
     412              : 
     413              : 
     414              : /**
     415              :  * "refresh reveal" request callback; it checks that the response
     416              :  * code is expected and copies into its command's state the data
     417              :  * coming from the exchange, namely the fresh coins.
     418              :  *
     419              :  * @param cls closure, a `struct RevealMeltState`
     420              :  * @param rmr HTTP response details
     421              :  */
     422              : static void
     423           14 : reveal_cb (void *cls,
     424              :            const struct TALER_EXCHANGE_RevealMeltResponse *rmr)
     425              : {
     426           14 :   struct RevealMeltState *rrs = cls;
     427           14 :   const struct TALER_EXCHANGE_HttpResponse *hr = &rmr->hr;
     428              :   const struct TALER_TESTING_Command *melt_cmd;
     429              : 
     430           14 :   rrs->rmh = NULL;
     431           14 :   if (rrs->expected_response_code != hr->http_status)
     432              :   {
     433            0 :     if (0 != rrs->do_retry)
     434              :     {
     435            0 :       rrs->do_retry--;
     436            0 :       if ( (0 == hr->http_status) ||
     437            0 :            (TALER_EC_GENERIC_DB_SOFT_FAILURE == hr->ec) ||
     438            0 :            (MHD_HTTP_INTERNAL_SERVER_ERROR == hr->http_status) )
     439              :       {
     440            0 :         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     441              :                     "Retrying refresh reveal failed with %u/%d\n",
     442              :                     hr->http_status,
     443              :                     (int) hr->ec);
     444              :         /* on DB conflicts, do not use backoff */
     445            0 :         if (TALER_EC_GENERIC_DB_SOFT_FAILURE == hr->ec)
     446            0 :           rrs->backoff = GNUNET_TIME_UNIT_ZERO;
     447              :         else
     448            0 :           rrs->backoff = GNUNET_TIME_randomized_backoff (rrs->backoff,
     449              :                                                          MAX_BACKOFF);
     450            0 :         rrs->total_backoff = GNUNET_TIME_relative_add (rrs->total_backoff,
     451              :                                                        rrs->backoff);
     452            0 :         TALER_TESTING_inc_tries (rrs->is);
     453            0 :         rrs->retry_task = GNUNET_SCHEDULER_add_delayed (rrs->backoff,
     454              :                                                         &do_reveal_retry,
     455              :                                                         rrs);
     456            0 :         return;
     457              :       }
     458              :     }
     459            0 :     TALER_TESTING_unexpected_status_with_body (rrs->is,
     460              :                                                hr->http_status,
     461              :                                                rrs->expected_response_code,
     462              :                                                hr->reply);
     463            0 :     return;
     464              :   }
     465           14 :   melt_cmd = TALER_TESTING_interpreter_lookup_command (rrs->is,
     466              :                                                        rrs->melt_reference);
     467           14 :   if (NULL == melt_cmd)
     468              :   {
     469            0 :     GNUNET_break (0);
     470            0 :     TALER_TESTING_interpreter_fail (rrs->is);
     471            0 :     return;
     472              :   }
     473           14 :   switch (hr->http_status)
     474              :   {
     475           14 :   case MHD_HTTP_OK:
     476           14 :     rrs->num_fresh_coins = rmr->details.ok.num_coins;
     477           14 :     rrs->psa = GNUNET_new_array (rrs->num_fresh_coins,
     478              :                                  struct TALER_PlanchetMasterSecretP);
     479           14 :     rrs->fresh_coins = GNUNET_new_array (rrs->num_fresh_coins,
     480              :                                          struct TALER_TESTING_FreshCoinData);
     481           70 :     for (unsigned int i = 0; i<rrs->num_fresh_coins; i++)
     482              :     {
     483           56 :       const struct TALER_EXCHANGE_RevealedCoinInfo *coin
     484           56 :         = &rmr->details.ok.coins[i];
     485           56 :       struct TALER_TESTING_FreshCoinData *fc = &rrs->fresh_coins[i];
     486              : 
     487           56 :       rrs->psa[i] = coin->ps;
     488           56 :       fc->blinding_key = coin->bks;
     489           56 :       if (GNUNET_OK !=
     490           56 :           TALER_TESTING_get_trait_denom_pub (melt_cmd,
     491              :                                              i,
     492              :                                              &fc->pk))
     493              :       {
     494            0 :         GNUNET_break (0);
     495            0 :         TALER_TESTING_interpreter_fail (rrs->is);
     496            0 :         return;
     497              :       }
     498           56 :       fc->coin_priv = coin->coin_priv;
     499           56 :       GNUNET_CRYPTO_eddsa_key_get_public (&fc->coin_priv.eddsa_priv,
     500              :                                           &fc->coin_pub.eddsa_pub);
     501              : 
     502           56 :       if (NULL != coin->age_commitment_proof)
     503              :       {
     504           32 :         fc->age_commitment_proof =
     505           32 :           TALER_age_commitment_proof_duplicate (coin->age_commitment_proof);
     506           32 :         fc->h_age_commitment = coin->h_age_commitment;
     507              :       }
     508              : 
     509           56 :       TALER_denom_sig_copy (&fc->sig,
     510              :                             &coin->sig);
     511              :     }
     512           14 :     if (0 != rrs->total_backoff.rel_value_us)
     513              :     {
     514            0 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     515              :                   "Total reveal backoff for %s was %s\n",
     516              :                   rrs->cmd->label,
     517              :                   GNUNET_STRINGS_relative_time_to_string (rrs->total_backoff,
     518              :                                                           true));
     519              :     }
     520           14 :     break;
     521            0 :   default:
     522            0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     523              :                 "Unknown HTTP status %u/%d\n",
     524              :                 hr->http_status,
     525              :                 (int) hr->ec);
     526              :   }
     527           14 :   TALER_TESTING_interpreter_next (rrs->is);
     528              : }
     529              : 
     530              : 
     531              : /**
     532              :  * Run the command.
     533              :  *
     534              :  * @param cls closure.
     535              :  * @param cmd the command to execute.
     536              :  * @param is the interpreter state.
     537              :  */
     538              : static void
     539              : melt_run (void *cls,
     540              :           const struct TALER_TESTING_Command *cmd,
     541              :           struct TALER_TESTING_Interpreter *is);
     542              : 
     543              : 
     544              : /**
     545              :  * Run the command.
     546              :  *
     547              :  * @param cls closure.
     548              :  * @param cmd the command to execute.
     549              :  * @param is the interpreter state.
     550              :  */
     551              : static void
     552           14 : melt_reveal_run (void *cls,
     553              :                  const struct TALER_TESTING_Command *cmd,
     554              :                  struct TALER_TESTING_Interpreter *is)
     555              : {
     556           14 :   struct RevealMeltState *rrs = cls;
     557              :   struct MeltState *ms;
     558              :   const struct TALER_TESTING_Command *melt_cmd;
     559              : 
     560           14 :   rrs->cmd = cmd;
     561           14 :   rrs->is = is;
     562           14 :   melt_cmd = TALER_TESTING_interpreter_lookup_command (is,
     563              :                                                        rrs->melt_reference);
     564           14 :   if (NULL == melt_cmd)
     565              :   {
     566            0 :     GNUNET_break (0);
     567            0 :     TALER_TESTING_interpreter_fail (rrs->is);
     568            0 :     return;
     569              :   }
     570           14 :   GNUNET_assert (melt_cmd->run == &melt_run);
     571           14 :   ms = melt_cmd->cls;
     572           14 :   ms->reveal_melt_input.rms = &ms->rms;
     573           14 :   ms->reveal_melt_input.melt_input = &ms->melt_input;
     574           28 :   ms->reveal_melt_input.blinding_seed = ms->no_blinding_seed
     575              :     ? NULL
     576           14 :     : &ms->blinding_seed;
     577           14 :   ms->reveal_melt_input.num_blinding_values = ms->num_blinding_values;
     578           14 :   ms->reveal_melt_input.blinding_values = ms->blinding_values;
     579           14 :   ms->reveal_melt_input.noreveal_index = ms->noreveal_index;
     580           14 :   rrs->rmh = TALER_EXCHANGE_reveal_melt (
     581              :     TALER_TESTING_interpreter_get_context (is),
     582              :     TALER_TESTING_get_exchange_url (is),
     583           14 :     &ms->reveal_melt_input,
     584              :     &reveal_cb,
     585              :     rrs);
     586           14 :   if (NULL == rrs->rmh)
     587              :   {
     588            0 :     GNUNET_break (0);
     589            0 :     TALER_TESTING_interpreter_fail (is);
     590            0 :     return;
     591              :   }
     592              : }
     593              : 
     594              : 
     595              : /**
     596              :  * Free the state from a "refresh reveal" CMD, and possibly
     597              :  * cancel a pending operation thereof.
     598              :  *
     599              :  * @param cls closure.
     600              :  * @param cmd the command which is being cleaned up.
     601              :  */
     602              : static void
     603           14 : melt_reveal_cleanup (void *cls,
     604              :                      const struct TALER_TESTING_Command *cmd)
     605              : {
     606           14 :   struct RevealMeltState *rrs = cls;
     607              : 
     608              :   (void) cmd;
     609           14 :   if (NULL != rrs->rmh)
     610              :   {
     611            0 :     TALER_TESTING_command_incomplete (rrs->is,
     612              :                                       cmd->label);
     613            0 :     TALER_EXCHANGE_reveal_melt_cancel (rrs->rmh);
     614            0 :     rrs->rmh = NULL;
     615              :   }
     616           14 :   if (NULL != rrs->retry_task)
     617              :   {
     618            0 :     GNUNET_SCHEDULER_cancel (rrs->retry_task);
     619            0 :     rrs->retry_task = NULL;
     620              :   }
     621              : 
     622           70 :   for (unsigned int j = 0; j < rrs->num_fresh_coins; j++)
     623              :   {
     624           56 :     TALER_denom_sig_free (&rrs->fresh_coins[j].sig);
     625           56 :     TALER_age_commitment_proof_free (rrs->fresh_coins[j].age_commitment_proof);
     626           56 :     GNUNET_free (rrs->fresh_coins[j].age_commitment_proof);
     627              :   }
     628           14 :   GNUNET_free (rrs->fresh_coins);
     629           14 :   GNUNET_free (rrs->psa);
     630           14 :   rrs->num_fresh_coins = 0;
     631           14 :   GNUNET_free (rrs);
     632           14 : }
     633              : 
     634              : 
     635              : /**
     636              :  * Task scheduled to re-try #melt_run.
     637              :  *
     638              :  * @param cls a `struct RefreshMeltState`
     639              :  */
     640              : static void
     641            0 : do_melt_retry (void *cls)
     642              : {
     643            0 :   struct MeltState *rms = cls;
     644              : 
     645            0 :   rms->retry_task = NULL;
     646            0 :   TALER_TESTING_touch_cmd (rms->is);
     647            0 :   melt_run (rms,
     648              :             NULL,
     649              :             rms->is);
     650            0 : }
     651              : 
     652              : 
     653              : /**
     654              :  * Callback for a " /melt" operation; checks if the HTTP
     655              :  * response code is okay and re-run the melt operation if the
     656              :  * CMD was set to do so.
     657              :  *
     658              :  * @param cls closure.
     659              :  * @param mr melt response details
     660              :  */
     661              : static void
     662           30 : melt_cb (void *cls,
     663              :          const struct TALER_EXCHANGE_MeltResponse *mr)
     664              : {
     665           30 :   struct MeltState *ms = cls;
     666           30 :   const struct TALER_EXCHANGE_HttpResponse *hr = &mr->hr;
     667              : 
     668           30 :   ms->mh = NULL;
     669           30 :   if (ms->expected_response_code != hr->http_status)
     670              :   {
     671            0 :     if (0 != ms->do_retry)
     672              :     {
     673            0 :       ms->do_retry--;
     674            0 :       if ( (0 == hr->http_status) ||
     675            0 :            (TALER_EC_GENERIC_DB_SOFT_FAILURE == hr->ec) ||
     676            0 :            (MHD_HTTP_INTERNAL_SERVER_ERROR == hr->http_status) )
     677              :       {
     678            0 :         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     679              :                     "Retrying refresh melt failed with %u/%d\n",
     680              :                     hr->http_status,
     681              :                     (int) hr->ec);
     682              :         /* on DB conflicts, do not use backoff */
     683            0 :         if (TALER_EC_GENERIC_DB_SOFT_FAILURE == hr->ec)
     684            0 :           ms->backoff = GNUNET_TIME_UNIT_ZERO;
     685              :         else
     686            0 :           ms->backoff = GNUNET_TIME_randomized_backoff (ms->backoff,
     687              :                                                         MAX_BACKOFF);
     688            0 :         ms->total_backoff = GNUNET_TIME_relative_add (ms->total_backoff,
     689              :                                                       ms->backoff);
     690            0 :         TALER_TESTING_inc_tries (ms->is);
     691            0 :         ms->retry_task = GNUNET_SCHEDULER_add_delayed (ms->backoff,
     692              :                                                        &do_melt_retry,
     693              :                                                        ms);
     694            0 :         return;
     695              :       }
     696              :     }
     697            0 :     TALER_TESTING_unexpected_status_with_body (ms->is,
     698              :                                                hr->http_status,
     699              :                                                ms->expected_response_code,
     700              :                                                hr->reply);
     701            0 :     return;
     702              :   }
     703           30 :   if (MHD_HTTP_OK == hr->http_status)
     704              :   {
     705           16 :     ms->noreveal_index = mr->details.ok.noreveal_index;
     706           16 :     if (mr->details.ok.num_melt_blinding_values != ms->num_fresh_coins)
     707              :     {
     708            0 :       GNUNET_break (0);
     709            0 :       TALER_TESTING_interpreter_fail (ms->is);
     710            0 :       return;
     711              :     }
     712           16 :     ms->no_blinding_seed = (NULL == mr->details.ok.blinding_seed);
     713           16 :     if (NULL != mr->details.ok.blinding_seed)
     714            8 :       ms->blinding_seed = *mr->details.ok.blinding_seed;
     715           16 :     ms->num_blinding_values = mr->details.ok.num_melt_blinding_values;
     716           16 :     if (NULL != ms->blinding_values)
     717              :     {
     718            8 :       GNUNET_break (0); /* can this this happen? Check! */
     719           40 :       for (unsigned int i = 0; i < ms->num_blinding_values; i++)
     720           32 :         TALER_denom_ewv_free (&ms->blinding_values[i]);
     721            8 :       GNUNET_free (ms->blinding_values);
     722              :     }
     723           16 :     ms->blinding_values = GNUNET_new_array (
     724              :       ms->num_blinding_values,
     725              :       struct TALER_ExchangeBlindingValues);
     726           80 :     for (unsigned int i = 0; i<ms->num_blinding_values; i++)
     727              :     {
     728           64 :       TALER_denom_ewv_copy (&ms->blinding_values[i],
     729           64 :                             &mr->details.ok.melt_blinding_values[i]);
     730              :     }
     731              :   }
     732           30 :   if (0 != ms->total_backoff.rel_value_us)
     733              :   {
     734            0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     735              :                 "Total melt backoff for %s was %s\n",
     736              :                 ms->cmd->label,
     737              :                 GNUNET_STRINGS_relative_time_to_string (ms->total_backoff,
     738              :                                                         true));
     739              :   }
     740           30 :   if (ms->double_melt)
     741              :   {
     742            8 :     TALER_LOG_DEBUG ("Doubling the melt (%s)\n",
     743              :                      ms->cmd->label);
     744            8 :     ms->mh = TALER_EXCHANGE_melt (
     745              :       TALER_TESTING_interpreter_get_context (ms->is),
     746              :       TALER_TESTING_get_exchange_url (ms->is),
     747              :       TALER_TESTING_get_keys (ms->is),
     748            8 :       &ms->rms,
     749            8 :       &ms->melt_input,
     750              :       &melt_cb,
     751              :       ms);
     752            8 :     ms->double_melt = false;
     753            8 :     return;
     754              :   }
     755           22 :   TALER_TESTING_interpreter_next (ms->is);
     756              : }
     757              : 
     758              : 
     759              : /**
     760              :  * Run the command.
     761              :  *
     762              :  * @param cls closure.
     763              :  * @param cmd the command to execute.
     764              :  * @param is the interpreter state.
     765              :  */
     766              : static void
     767           22 : melt_run (void *cls,
     768              :           const struct TALER_TESTING_Command *cmd,
     769              :           struct TALER_TESTING_Interpreter *is)
     770              : {
     771              :   static const char *default_melt_fresh_amounts[] = {
     772              :     "EUR:1", "EUR:1", "EUR:1", "EUR:0.1",
     773              :     NULL
     774              :   };
     775           22 :   struct MeltState *rms = cls;
     776              :   unsigned int num_fresh_coins;
     777              :   const char **melt_fresh_amounts;
     778              : 
     779           22 :   rms->cmd = cmd;
     780           22 :   if (NULL == (melt_fresh_amounts = rms->melt_fresh_amounts))
     781           22 :     melt_fresh_amounts = default_melt_fresh_amounts;
     782           22 :   rms->is = is;
     783           22 :   rms->noreveal_index = UINT16_MAX;
     784           22 :   TALER_refresh_master_setup_random (&rms->rms);
     785           22 :   for (num_fresh_coins = 0;
     786          110 :        NULL != melt_fresh_amounts[num_fresh_coins];
     787           88 :        num_fresh_coins++)
     788              :     ;
     789           22 :   rms->num_fresh_coins = num_fresh_coins;
     790              :   /* Free old data structure in case this is a retry! */
     791           22 :   if (NULL != rms->fresh_pks)
     792              :   {
     793            0 :     for (unsigned int i = 0; i < rms->num_fresh_coins; i++)
     794            0 :       TALER_denom_pub_free (&rms->fresh_pks[i].key);
     795            0 :     GNUNET_free (rms->fresh_pks);
     796              :   }
     797           22 :   rms->fresh_pks = GNUNET_new_array (
     798              :     num_fresh_coins,
     799              :     struct TALER_EXCHANGE_DenomPublicKey);
     800              :   {
     801              :     struct TALER_Amount melt_amount;
     802              :     struct TALER_Amount fresh_amount;
     803           22 :     const struct TALER_AgeCommitmentProof *age_commitment_proof = NULL;
     804           22 :     const struct TALER_AgeCommitmentHashP *h_age_commitment = NULL;
     805              :     const struct TALER_DenominationSignature *melt_sig;
     806              :     const struct TALER_EXCHANGE_DenomPublicKey *melt_denom_pub;
     807              :     const struct TALER_TESTING_Command *coin_command;
     808              :     bool age_restricted_denom;
     809              : 
     810           22 :     if (NULL == (coin_command
     811           22 :                    = TALER_TESTING_interpreter_lookup_command (
     812              :                        is,
     813              :                        rms->coin_reference)))
     814              :     {
     815            0 :       GNUNET_break (0);
     816            0 :       TALER_TESTING_interpreter_fail (rms->is);
     817            0 :       return;
     818              :     }
     819              : 
     820           22 :     if (GNUNET_OK !=
     821           22 :         TALER_TESTING_get_trait_coin_priv (coin_command,
     822              :                                            0,
     823              :                                            &rms->melt_priv))
     824              :     {
     825            0 :       GNUNET_break (0);
     826            0 :       TALER_TESTING_interpreter_fail (rms->is);
     827            0 :       return;
     828              :     }
     829           22 :     if (GNUNET_OK !=
     830           22 :         TALER_TESTING_get_trait_age_commitment_proof (coin_command,
     831              :                                                       0,
     832              :                                                       &age_commitment_proof))
     833              :     {
     834            0 :       GNUNET_break (0);
     835            0 :       TALER_TESTING_interpreter_fail (rms->is);
     836            0 :       return;
     837              :     }
     838              : 
     839           22 :     if (GNUNET_OK !=
     840           22 :         TALER_TESTING_get_trait_h_age_commitment (coin_command,
     841              :                                                   0,
     842              :                                                   &h_age_commitment))
     843              :     {
     844            0 :       GNUNET_break (0);
     845            0 :       TALER_TESTING_interpreter_fail (rms->is);
     846            0 :       return;
     847              :     }
     848           22 :     if (GNUNET_OK !=
     849           22 :         TALER_TESTING_get_trait_denom_sig (coin_command,
     850              :                                            0,
     851              :                                            &melt_sig))
     852              :     {
     853            0 :       GNUNET_break (0);
     854            0 :       TALER_TESTING_interpreter_fail (rms->is);
     855            0 :       return;
     856              :     }
     857           22 :     if (GNUNET_OK !=
     858           22 :         TALER_TESTING_get_trait_denom_pub (coin_command,
     859              :                                            0,
     860              :                                            &melt_denom_pub))
     861              :     {
     862            0 :       GNUNET_break (0);
     863            0 :       TALER_TESTING_interpreter_fail (rms->is);
     864            0 :       return;
     865              :     }
     866              : 
     867              :     /* Melt amount starts with the melt fee of the old coin; we'll add the
     868              :        values and withdraw fees of the fresh coins next */
     869           22 :     melt_amount = melt_denom_pub->fees.refresh;
     870           22 :     age_restricted_denom = melt_denom_pub->key.age_mask.bits != 0;
     871           22 :     GNUNET_assert (age_restricted_denom == (NULL != age_commitment_proof));
     872           22 :     GNUNET_assert ((NULL == age_commitment_proof) ||
     873              :                    (0 < age_commitment_proof->commitment.num));
     874          110 :     for (unsigned int i = 0; i<num_fresh_coins; i++)
     875              :     {
     876              :       const struct TALER_EXCHANGE_DenomPublicKey *fresh_pk;
     877              : 
     878           88 :       if (GNUNET_OK !=
     879           88 :           TALER_string_to_amount (melt_fresh_amounts[i],
     880              :                                   &fresh_amount))
     881              :       {
     882            0 :         GNUNET_break (0);
     883            0 :         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     884              :                     "Failed to parse amount `%s' at index %u\n",
     885              :                     melt_fresh_amounts[i],
     886              :                     i);
     887            0 :         TALER_TESTING_interpreter_fail (rms->is);
     888            0 :         return;
     889              :       }
     890           88 :       fresh_pk = TALER_TESTING_find_pk (TALER_TESTING_get_keys (rms->is),
     891              :                                         &fresh_amount,
     892              :                                         age_restricted_denom);
     893           88 :       if (NULL == fresh_pk)
     894              :       {
     895            0 :         GNUNET_break (0);
     896              :         /* Subroutine logs specific error */
     897            0 :         TALER_TESTING_interpreter_fail (rms->is);
     898            0 :         return;
     899              :       }
     900           88 :       GNUNET_assert (0 <=
     901              :                      TALER_amount_add (&melt_amount,
     902              :                                        &melt_amount,
     903              :                                        &fresh_amount));
     904           88 :       GNUNET_assert (0 <=
     905              :                      TALER_amount_add (&melt_amount,
     906              :                                        &melt_amount,
     907              :                                        &fresh_pk->fees.withdraw));
     908           88 :       rms->fresh_pks[i] = *fresh_pk;
     909              :       /* Make a deep copy of the RSA key */
     910           88 :       TALER_denom_pub_copy (&rms->fresh_pks[i].key,
     911              :                             &fresh_pk->key);
     912              :     } /* end for */
     913              : 
     914           22 :     rms->melt_input.melt_priv = *rms->melt_priv;
     915           22 :     GNUNET_CRYPTO_eddsa_key_get_public (&rms->melt_priv->eddsa_priv,
     916              :                                         &rms->melt_pub.eddsa_pub);
     917           22 :     rms->melt_input.melt_amount = melt_amount;
     918           22 :     rms->melt_input.melt_sig = *melt_sig;
     919           22 :     rms->melt_input.melt_pk = *melt_denom_pub;
     920              : 
     921           22 :     if (NULL != age_commitment_proof)
     922              :     {
     923           12 :       GNUNET_assert (NULL != h_age_commitment);
     924           12 :       rms->melt_input.melt_age_commitment_proof = age_commitment_proof;
     925           12 :       rms->melt_input.melt_h_age_commitment = h_age_commitment;
     926              :     }
     927           22 :     rms->melt_input.fresh_denom_pubs = rms->fresh_pks;
     928           22 :     rms->melt_input.num_fresh_denom_pubs = num_fresh_coins;
     929              : 
     930           22 :     GNUNET_assert (age_restricted_denom ==
     931              :                    (NULL != age_commitment_proof));
     932           22 :     GNUNET_assert ((NULL == age_commitment_proof) ||
     933              :                    (0 < age_commitment_proof->commitment.num));
     934              : 
     935           22 :     rms->che.type = TALER_EXCHANGE_CTT_MELT;
     936           22 :     rms->che.amount = melt_amount;
     937           22 :     if (NULL != age_commitment_proof)
     938           12 :       rms->che.details.melt.h_age_commitment = *h_age_commitment;
     939              :     else
     940           10 :       rms->che.details.melt.no_hac = true;
     941              : 
     942           22 :     rms->mh = TALER_EXCHANGE_melt (
     943              :       TALER_TESTING_interpreter_get_context (is),
     944              :       TALER_TESTING_get_exchange_url (is),
     945              :       TALER_TESTING_get_keys (is),
     946           22 :       &rms->rms,
     947           22 :       &rms->melt_input,
     948              :       &melt_cb,
     949              :       rms);
     950              : 
     951           22 :     if (NULL == rms->mh)
     952              :     {
     953            0 :       GNUNET_break (0);
     954            0 :       TALER_TESTING_interpreter_fail (rms->is);
     955            0 :       return;
     956              :     }
     957              :   }
     958              : }
     959              : 
     960              : 
     961              : /**
     962              :  * Free the "refresh melt" CMD state, and possibly cancel a
     963              :  * pending operation thereof.
     964              :  *
     965              :  * @param cls closure, must be a `struct RefreshMeltState`.
     966              :  * @param cmd the command which is being cleaned up.
     967              :  */
     968              : static void
     969           22 : melt_cleanup (void *cls,
     970              :               const struct TALER_TESTING_Command *cmd)
     971              : {
     972           22 :   struct MeltState *rms = cls;
     973              : 
     974              :   (void) cmd;
     975           22 :   if (NULL != rms->mh)
     976              :   {
     977            0 :     TALER_TESTING_command_incomplete (rms->is,
     978              :                                       cmd->label);
     979            0 :     TALER_EXCHANGE_melt_cancel (rms->mh);
     980            0 :     rms->mh = NULL;
     981              :   }
     982           22 :   if (NULL != rms->retry_task)
     983              :   {
     984            0 :     GNUNET_SCHEDULER_cancel (rms->retry_task);
     985            0 :     rms->retry_task = NULL;
     986              :   }
     987           22 :   if (NULL != rms->fresh_pks)
     988              :   {
     989          110 :     for (unsigned int i = 0; i < rms->num_fresh_coins; i++)
     990           88 :       TALER_denom_pub_free (&rms->fresh_pks[i].key);
     991           22 :     GNUNET_free (rms->fresh_pks);
     992              :   }
     993           22 :   if (NULL != rms->blinding_values)
     994              :   {
     995           40 :     for (unsigned int i = 0; i < rms->num_blinding_values; i++)
     996           32 :       TALER_denom_ewv_free (&rms->blinding_values[i]);
     997            8 :     GNUNET_free (rms->blinding_values);
     998              :   }
     999           22 :   GNUNET_free (rms->melt_fresh_amounts);
    1000           22 :   GNUNET_free (rms);
    1001           22 : }
    1002              : 
    1003              : 
    1004              : /**
    1005              :  * Offer internal data to the "refresh melt" CMD.
    1006              :  *
    1007              :  * @param cls closure.
    1008              :  * @param[out] ret result (could be anything).
    1009              :  * @param trait name of the trait.
    1010              :  * @param index index number of the object to offer.
    1011              :  * @return #GNUNET_OK on success.
    1012              :  */
    1013              : static enum GNUNET_GenericReturnValue
    1014           98 : melt_traits (void *cls,
    1015              :              const void **ret,
    1016              :              const char *trait,
    1017              :              unsigned int index)
    1018              : {
    1019           98 :   struct MeltState *rms = cls;
    1020              : 
    1021           98 :   if (index >= rms->num_fresh_coins)
    1022              :   {
    1023            0 :     GNUNET_break (0);
    1024            0 :     return GNUNET_SYSERR;
    1025              :   }
    1026              :   {
    1027              :     struct TALER_TESTING_Trait traits[] = {
    1028           98 :       TALER_TESTING_make_trait_denom_pub (index,
    1029           98 :                                           &rms->fresh_pks[index]),
    1030           98 :       TALER_TESTING_make_trait_coin_priv (0,
    1031              :                                           rms->melt_priv),
    1032           98 :       TALER_TESTING_make_trait_coin_pub (0,
    1033           98 :                                          &rms->melt_pub),
    1034           98 :       TALER_TESTING_make_trait_coin_history (0,
    1035           98 :                                              &rms->che),
    1036           98 :       TALER_TESTING_make_trait_age_commitment_proof (
    1037              :         index,
    1038              :         rms->melt_input.melt_age_commitment_proof),
    1039           98 :       TALER_TESTING_make_trait_h_age_commitment (
    1040              :         index,
    1041              :         rms->melt_input.melt_h_age_commitment),
    1042           98 :       TALER_TESTING_make_trait_refresh_seed (&rms->rms),
    1043           98 :       (NULL != rms->reveal_melt_input.blinding_values)
    1044           68 :       ? TALER_TESTING_make_trait_exchange_blinding_values (
    1045              :         index,
    1046           68 :         &rms->reveal_melt_input.blinding_values[index])
    1047           98 :       : TALER_TESTING_trait_end (),
    1048           98 :       TALER_TESTING_trait_end ()
    1049              :     };
    1050              : 
    1051           98 :     return TALER_TESTING_get_trait (traits,
    1052              :                                     ret,
    1053              :                                     trait,
    1054              :                                     index);
    1055              :   }
    1056              : }
    1057              : 
    1058              : 
    1059              : /**
    1060              :  * Parse list of amounts for melt operation.
    1061              :  *
    1062              :  * @param[in,out] rms where to store the list
    1063              :  * @param ap NULL-termianted list of amounts to be melted (one per fresh coin)
    1064              :  * @return #GNUNET_OK on success
    1065              :  */
    1066              : static enum GNUNET_GenericReturnValue
    1067           22 : parse_amounts (struct MeltState *rms,
    1068              :                va_list ap)
    1069              : {
    1070              :   unsigned int len;
    1071              :   unsigned int off;
    1072              :   const char *amount;
    1073              : 
    1074           22 :   len = 0;
    1075           22 :   off = 0;
    1076           44 :   while (NULL != (amount = va_arg (ap, const char *)))
    1077              :   {
    1078            0 :     if (len == off)
    1079              :     {
    1080              :       struct TALER_Amount a;
    1081              : 
    1082            0 :       GNUNET_array_grow (rms->melt_fresh_amounts,
    1083              :                          len,
    1084              :                          off + 16);
    1085            0 :       if (GNUNET_OK !=
    1086            0 :           TALER_string_to_amount (amount, &a))
    1087              :       {
    1088            0 :         GNUNET_break (0);
    1089            0 :         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1090              :                     "Failed to parse amount `%s' at index %u\n",
    1091              :                     amount, off);
    1092            0 :         GNUNET_free (rms->melt_fresh_amounts);
    1093            0 :         rms->melt_fresh_amounts = NULL;
    1094            0 :         return GNUNET_SYSERR;
    1095              :       }
    1096            0 :       rms->melt_fresh_amounts[off++] = amount;
    1097              :     }
    1098              :   }
    1099           22 :   if (0 == off)
    1100           22 :     return GNUNET_OK; /* no amounts given == use defaults! */
    1101              :   /* ensure NULL-termination */
    1102            0 :   GNUNET_array_grow (rms->melt_fresh_amounts,
    1103              :                      len,
    1104              :                      off + 1);
    1105            0 :   return GNUNET_OK;
    1106              : }
    1107              : 
    1108              : 
    1109              : struct TALER_TESTING_Command
    1110           14 : TALER_TESTING_cmd_melt (const char *label,
    1111              :                         const char *coin_reference,
    1112              :                         unsigned int expected_response_code,
    1113              :                         ...)
    1114              : {
    1115              :   struct MeltState *rms;
    1116              :   va_list ap;
    1117              : 
    1118           14 :   rms = GNUNET_new (struct MeltState);
    1119           14 :   rms->coin_reference = coin_reference;
    1120           14 :   rms->expected_response_code = expected_response_code;
    1121           14 :   va_start (ap,
    1122              :             expected_response_code);
    1123           14 :   GNUNET_assert (GNUNET_OK ==
    1124              :                  parse_amounts (rms, ap));
    1125           14 :   va_end (ap);
    1126              :   {
    1127           14 :     struct TALER_TESTING_Command cmd = {
    1128              :       .label = label,
    1129              :       .cls = rms,
    1130              :       .run = &melt_run,
    1131              :       .cleanup = &melt_cleanup,
    1132              :       .traits = &melt_traits
    1133              :     };
    1134              : 
    1135           14 :     return cmd;
    1136              :   }
    1137              : }
    1138              : 
    1139              : 
    1140              : struct TALER_TESTING_Command
    1141            8 : TALER_TESTING_cmd_melt_double (const char *label,
    1142              :                                const char *coin_reference,
    1143              :                                unsigned int expected_response_code,
    1144              :                                ...)
    1145              : {
    1146              :   struct MeltState *rms;
    1147              :   va_list ap;
    1148              : 
    1149            8 :   rms = GNUNET_new (struct MeltState);
    1150            8 :   rms->coin_reference = coin_reference;
    1151            8 :   rms->expected_response_code = expected_response_code;
    1152            8 :   rms->double_melt = true;
    1153            8 :   va_start (ap,
    1154              :             expected_response_code);
    1155            8 :   GNUNET_assert (GNUNET_OK ==
    1156              :                  parse_amounts (rms, ap));
    1157            8 :   va_end (ap);
    1158              :   {
    1159            8 :     struct TALER_TESTING_Command cmd = {
    1160              :       .label = label,
    1161              :       .cls = rms,
    1162              :       .run = &melt_run,
    1163              :       .cleanup = &melt_cleanup,
    1164              :       .traits = &melt_traits
    1165              :     };
    1166              : 
    1167            8 :     return cmd;
    1168              :   }
    1169              : }
    1170              : 
    1171              : 
    1172              : struct TALER_TESTING_Command
    1173            0 : TALER_TESTING_cmd_melt_with_retry (struct TALER_TESTING_Command cmd)
    1174              : {
    1175              :   struct MeltState *rms;
    1176              : 
    1177            0 :   GNUNET_assert (&melt_run == cmd.run);
    1178            0 :   rms = cmd.cls;
    1179            0 :   rms->do_retry = NUM_RETRIES;
    1180            0 :   return cmd;
    1181              : }
    1182              : 
    1183              : 
    1184              : /**
    1185              :  * Offer internal data from a "refresh reveal" CMD.
    1186              :  *
    1187              :  * @param cls closure.
    1188              :  * @param[out] ret result (could be anything).
    1189              :  * @param trait name of the trait.
    1190              :  * @param index index number of the object to offer.
    1191              :  * @return #GNUNET_OK on success.
    1192              :  */
    1193              : static enum GNUNET_GenericReturnValue
    1194          230 : melt_reveal_traits (void *cls,
    1195              :                     const void **ret,
    1196              :                     const char *trait,
    1197              :                     unsigned int index)
    1198              : {
    1199          230 :   struct RevealMeltState *rrs = cls;
    1200              : 
    1201          230 :   if (index >= rrs->num_fresh_coins)
    1202            8 :     return GNUNET_SYSERR;
    1203              : 
    1204              :   {
    1205              :     struct TALER_TESTING_Trait traits[] = {
    1206          222 :       TALER_TESTING_make_trait_coin_priv (
    1207              :         index,
    1208          222 :         &rrs->fresh_coins[index].coin_priv),
    1209          222 :       TALER_TESTING_make_trait_coin_pub (
    1210              :         index,
    1211          222 :         &rrs->fresh_coins[index].coin_pub),
    1212          222 :       TALER_TESTING_make_trait_age_commitment_proof (
    1213              :         index,
    1214          222 :         rrs->fresh_coins[index].age_commitment_proof),
    1215          222 :       TALER_TESTING_make_trait_h_age_commitment (
    1216              :         index,
    1217          222 :         &rrs->fresh_coins[index].h_age_commitment),
    1218          222 :       TALER_TESTING_make_trait_denom_pub (
    1219              :         index,
    1220          222 :         rrs->fresh_coins[index].pk),
    1221          222 :       TALER_TESTING_make_trait_denom_sig (
    1222              :         index,
    1223          222 :         &rrs->fresh_coins[index].sig),
    1224          222 :       TALER_TESTING_make_trait_blinding_key (
    1225              :         index,
    1226          222 :         &rrs->fresh_coins[index].blinding_key),
    1227          222 :       TALER_TESTING_make_trait_array_length (
    1228          222 :         &rrs->num_fresh_coins),
    1229          222 :       TALER_TESTING_make_trait_fresh_coins (
    1230          222 :         (const struct TALER_TESTING_FreshCoinData **) &rrs->fresh_coins),
    1231          222 :       TALER_TESTING_make_trait_planchet_secrets (index,
    1232          222 :                                                  &rrs->psa[index]),
    1233          222 :       TALER_TESTING_trait_end ()
    1234              :     };
    1235              : 
    1236          222 :     return TALER_TESTING_get_trait (traits,
    1237              :                                     ret,
    1238              :                                     trait,
    1239              :                                     index);
    1240              :   }
    1241              : }
    1242              : 
    1243              : 
    1244              : struct TALER_TESTING_Command
    1245           14 : TALER_TESTING_cmd_melt_reveal (const char *label,
    1246              :                                const char *melt_reference,
    1247              :                                unsigned int expected_response_code)
    1248              : {
    1249              :   struct RevealMeltState *rrs;
    1250              : 
    1251           14 :   rrs = GNUNET_new (struct RevealMeltState);
    1252           14 :   rrs->melt_reference = melt_reference;
    1253           14 :   rrs->expected_response_code = expected_response_code;
    1254              :   {
    1255           14 :     struct TALER_TESTING_Command cmd = {
    1256              :       .cls = rrs,
    1257              :       .label = label,
    1258              :       .run = &melt_reveal_run,
    1259              :       .cleanup = &melt_reveal_cleanup,
    1260              :       .traits = &melt_reveal_traits
    1261              :     };
    1262              : 
    1263           14 :     return cmd;
    1264              :   }
    1265              : }
    1266              : 
    1267              : 
    1268              : struct TALER_TESTING_Command
    1269            0 : TALER_TESTING_cmd_melt_reveal_with_retry (struct TALER_TESTING_Command cmd)
    1270              : {
    1271              :   struct RevealMeltState *rrs;
    1272              : 
    1273            0 :   GNUNET_assert (&melt_reveal_run == cmd.run);
    1274            0 :   rrs = cmd.cls;
    1275            0 :   rrs->do_retry = NUM_RETRIES;
    1276            0 :   return cmd;
    1277              : }
        

Generated by: LCOV version 2.0-1