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

Generated by: LCOV version 2.0-1