LCOV - code coverage report
Current view: top level - testing - testing_api_cmd_refresh.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 66.4 % 375 249
Test Date: 2026-03-07 14:54:45 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_PostMeltHandle *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_PostRevealMeltHandle *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_PostRevealMeltResponse *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_post_reveal_melt_create (
     581              :     TALER_TESTING_interpreter_get_context (is),
     582              :     TALER_TESTING_get_exchange_url (is),
     583           14 :     &ms->reveal_melt_input);
     584           14 :   if (NULL == rrs->rmh)
     585              :   {
     586            0 :     GNUNET_break (0);
     587            0 :     TALER_TESTING_interpreter_fail (is);
     588            0 :     return;
     589              :   }
     590           14 :   GNUNET_assert (TALER_EC_NONE ==
     591              :                  TALER_EXCHANGE_post_reveal_melt_start (rrs->rmh,
     592              :                                                         &reveal_cb,
     593              :                                                         rrs));
     594              : }
     595              : 
     596              : 
     597              : /**
     598              :  * Free the state from a "refresh reveal" CMD, and possibly
     599              :  * cancel a pending operation thereof.
     600              :  *
     601              :  * @param cls closure.
     602              :  * @param cmd the command which is being cleaned up.
     603              :  */
     604              : static void
     605           14 : melt_reveal_cleanup (void *cls,
     606              :                      const struct TALER_TESTING_Command *cmd)
     607              : {
     608           14 :   struct RevealMeltState *rrs = cls;
     609              : 
     610              :   (void) cmd;
     611           14 :   if (NULL != rrs->rmh)
     612              :   {
     613            0 :     TALER_TESTING_command_incomplete (rrs->is,
     614              :                                       cmd->label);
     615            0 :     TALER_EXCHANGE_post_reveal_melt_cancel (rrs->rmh);
     616            0 :     rrs->rmh = NULL;
     617              :   }
     618           14 :   if (NULL != rrs->retry_task)
     619              :   {
     620            0 :     GNUNET_SCHEDULER_cancel (rrs->retry_task);
     621            0 :     rrs->retry_task = NULL;
     622              :   }
     623              : 
     624           70 :   for (unsigned int j = 0; j < rrs->num_fresh_coins; j++)
     625              :   {
     626           56 :     TALER_denom_sig_free (&rrs->fresh_coins[j].sig);
     627           56 :     TALER_age_commitment_proof_free (rrs->fresh_coins[j].age_commitment_proof);
     628           56 :     GNUNET_free (rrs->fresh_coins[j].age_commitment_proof);
     629              :   }
     630           14 :   GNUNET_free (rrs->fresh_coins);
     631           14 :   GNUNET_free (rrs->psa);
     632           14 :   rrs->num_fresh_coins = 0;
     633           14 :   GNUNET_free (rrs);
     634           14 : }
     635              : 
     636              : 
     637              : /**
     638              :  * Task scheduled to re-try #melt_run.
     639              :  *
     640              :  * @param cls a `struct RefreshMeltState`
     641              :  */
     642              : static void
     643            0 : do_melt_retry (void *cls)
     644              : {
     645            0 :   struct MeltState *rms = cls;
     646              : 
     647            0 :   rms->retry_task = NULL;
     648            0 :   TALER_TESTING_touch_cmd (rms->is);
     649            0 :   melt_run (rms,
     650              :             NULL,
     651              :             rms->is);
     652            0 : }
     653              : 
     654              : 
     655              : /**
     656              :  * Callback for a " /melt" operation; checks if the HTTP
     657              :  * response code is okay and re-run the melt operation if the
     658              :  * CMD was set to do so.
     659              :  *
     660              :  * @param cls closure.
     661              :  * @param mr melt response details
     662              :  */
     663              : static void
     664           30 : melt_cb (void *cls,
     665              :          const struct TALER_EXCHANGE_PostMeltResponse *mr)
     666              : {
     667           30 :   struct MeltState *ms = cls;
     668           30 :   const struct TALER_EXCHANGE_HttpResponse *hr = &mr->hr;
     669              : 
     670           30 :   ms->mh = NULL;
     671           30 :   if (ms->expected_response_code != hr->http_status)
     672              :   {
     673            0 :     if (0 != ms->do_retry)
     674              :     {
     675            0 :       ms->do_retry--;
     676            0 :       if ( (0 == hr->http_status) ||
     677            0 :            (TALER_EC_GENERIC_DB_SOFT_FAILURE == hr->ec) ||
     678            0 :            (MHD_HTTP_INTERNAL_SERVER_ERROR == hr->http_status) )
     679              :       {
     680            0 :         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     681              :                     "Retrying refresh melt failed with %u/%d\n",
     682              :                     hr->http_status,
     683              :                     (int) hr->ec);
     684              :         /* on DB conflicts, do not use backoff */
     685            0 :         if (TALER_EC_GENERIC_DB_SOFT_FAILURE == hr->ec)
     686            0 :           ms->backoff = GNUNET_TIME_UNIT_ZERO;
     687              :         else
     688            0 :           ms->backoff = GNUNET_TIME_randomized_backoff (ms->backoff,
     689              :                                                         MAX_BACKOFF);
     690            0 :         ms->total_backoff = GNUNET_TIME_relative_add (ms->total_backoff,
     691              :                                                       ms->backoff);
     692            0 :         TALER_TESTING_inc_tries (ms->is);
     693            0 :         ms->retry_task = GNUNET_SCHEDULER_add_delayed (ms->backoff,
     694              :                                                        &do_melt_retry,
     695              :                                                        ms);
     696            0 :         return;
     697              :       }
     698              :     }
     699            0 :     TALER_TESTING_unexpected_status_with_body (ms->is,
     700              :                                                hr->http_status,
     701              :                                                ms->expected_response_code,
     702              :                                                hr->reply);
     703            0 :     return;
     704              :   }
     705           30 :   if (MHD_HTTP_OK == hr->http_status)
     706              :   {
     707           16 :     ms->noreveal_index = mr->details.ok.noreveal_index;
     708           16 :     if (mr->details.ok.num_melt_blinding_values != ms->num_fresh_coins)
     709              :     {
     710            0 :       GNUNET_break (0);
     711            0 :       TALER_TESTING_interpreter_fail (ms->is);
     712            0 :       return;
     713              :     }
     714           16 :     ms->no_blinding_seed = (NULL == mr->details.ok.blinding_seed);
     715           16 :     if (NULL != mr->details.ok.blinding_seed)
     716            8 :       ms->blinding_seed = *mr->details.ok.blinding_seed;
     717           16 :     ms->num_blinding_values = mr->details.ok.num_melt_blinding_values;
     718           16 :     if (NULL != ms->blinding_values)
     719              :     {
     720            8 :       GNUNET_break (0); /* can this this happen? Check! */
     721           40 :       for (unsigned int i = 0; i < ms->num_blinding_values; i++)
     722           32 :         TALER_denom_ewv_free (&ms->blinding_values[i]);
     723            8 :       GNUNET_free (ms->blinding_values);
     724              :     }
     725           16 :     ms->blinding_values = GNUNET_new_array (
     726              :       ms->num_blinding_values,
     727              :       struct TALER_ExchangeBlindingValues);
     728           80 :     for (unsigned int i = 0; i<ms->num_blinding_values; i++)
     729              :     {
     730           64 :       TALER_denom_ewv_copy (&ms->blinding_values[i],
     731           64 :                             &mr->details.ok.melt_blinding_values[i]);
     732              :     }
     733              :   }
     734           30 :   if (0 != ms->total_backoff.rel_value_us)
     735              :   {
     736            0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     737              :                 "Total melt backoff for %s was %s\n",
     738              :                 ms->cmd->label,
     739              :                 GNUNET_STRINGS_relative_time_to_string (ms->total_backoff,
     740              :                                                         true));
     741              :   }
     742           30 :   if (ms->double_melt)
     743              :   {
     744            8 :     TALER_LOG_DEBUG ("Doubling the melt (%s)\n",
     745              :                      ms->cmd->label);
     746            8 :     ms->mh = TALER_EXCHANGE_post_melt_create (
     747              :       TALER_TESTING_interpreter_get_context (ms->is),
     748              :       TALER_TESTING_get_exchange_url (ms->is),
     749              :       TALER_TESTING_get_keys (ms->is),
     750            8 :       &ms->rms,
     751            8 :       &ms->melt_input);
     752            8 :     GNUNET_assert (NULL != ms->mh);
     753            8 :     GNUNET_assert (TALER_EC_NONE ==
     754              :                    TALER_EXCHANGE_post_melt_start (ms->mh,
     755              :                                                    &melt_cb,
     756              :                                                    ms));
     757            8 :     ms->double_melt = false;
     758            8 :     return;
     759              :   }
     760           22 :   TALER_TESTING_interpreter_next (ms->is);
     761              : }
     762              : 
     763              : 
     764              : /**
     765              :  * Run the command.
     766              :  *
     767              :  * @param cls closure.
     768              :  * @param cmd the command to execute.
     769              :  * @param is the interpreter state.
     770              :  */
     771              : static void
     772           22 : melt_run (void *cls,
     773              :           const struct TALER_TESTING_Command *cmd,
     774              :           struct TALER_TESTING_Interpreter *is)
     775              : {
     776              :   static const char *default_melt_fresh_amounts[] = {
     777              :     "EUR:1", "EUR:1", "EUR:1", "EUR:0.1",
     778              :     NULL
     779              :   };
     780           22 :   struct MeltState *rms = cls;
     781              :   unsigned int num_fresh_coins;
     782              :   const char **melt_fresh_amounts;
     783              : 
     784           22 :   rms->cmd = cmd;
     785           22 :   if (NULL == (melt_fresh_amounts = rms->melt_fresh_amounts))
     786           22 :     melt_fresh_amounts = default_melt_fresh_amounts;
     787           22 :   rms->is = is;
     788           22 :   rms->noreveal_index = UINT16_MAX;
     789           22 :   TALER_refresh_master_setup_random (&rms->rms);
     790           22 :   for (num_fresh_coins = 0;
     791          110 :        NULL != melt_fresh_amounts[num_fresh_coins];
     792           88 :        num_fresh_coins++)
     793              :     ;
     794           22 :   rms->num_fresh_coins = num_fresh_coins;
     795              :   /* Free old data structure in case this is a retry! */
     796           22 :   if (NULL != rms->fresh_pks)
     797              :   {
     798            0 :     for (unsigned int i = 0; i < rms->num_fresh_coins; i++)
     799            0 :       TALER_denom_pub_free (&rms->fresh_pks[i].key);
     800            0 :     GNUNET_free (rms->fresh_pks);
     801              :   }
     802           22 :   rms->fresh_pks = GNUNET_new_array (
     803              :     num_fresh_coins,
     804              :     struct TALER_EXCHANGE_DenomPublicKey);
     805              :   {
     806              :     struct TALER_Amount melt_amount;
     807              :     struct TALER_Amount fresh_amount;
     808           22 :     const struct TALER_AgeCommitmentProof *age_commitment_proof = NULL;
     809           22 :     const struct TALER_AgeCommitmentHashP *h_age_commitment = NULL;
     810              :     const struct TALER_DenominationSignature *melt_sig;
     811              :     const struct TALER_EXCHANGE_DenomPublicKey *melt_denom_pub;
     812              :     const struct TALER_TESTING_Command *coin_command;
     813              :     bool age_restricted_denom;
     814              : 
     815           22 :     if (NULL == (coin_command
     816           22 :                    = TALER_TESTING_interpreter_lookup_command (
     817              :                        is,
     818              :                        rms->coin_reference)))
     819              :     {
     820            0 :       GNUNET_break (0);
     821            0 :       TALER_TESTING_interpreter_fail (rms->is);
     822            0 :       return;
     823              :     }
     824              : 
     825           22 :     if (GNUNET_OK !=
     826           22 :         TALER_TESTING_get_trait_coin_priv (coin_command,
     827              :                                            0,
     828              :                                            &rms->melt_priv))
     829              :     {
     830            0 :       GNUNET_break (0);
     831            0 :       TALER_TESTING_interpreter_fail (rms->is);
     832            0 :       return;
     833              :     }
     834           22 :     if (GNUNET_OK !=
     835           22 :         TALER_TESTING_get_trait_age_commitment_proof (coin_command,
     836              :                                                       0,
     837              :                                                       &age_commitment_proof))
     838              :     {
     839            0 :       GNUNET_break (0);
     840            0 :       TALER_TESTING_interpreter_fail (rms->is);
     841            0 :       return;
     842              :     }
     843              : 
     844           22 :     if (GNUNET_OK !=
     845           22 :         TALER_TESTING_get_trait_h_age_commitment (coin_command,
     846              :                                                   0,
     847              :                                                   &h_age_commitment))
     848              :     {
     849            0 :       GNUNET_break (0);
     850            0 :       TALER_TESTING_interpreter_fail (rms->is);
     851            0 :       return;
     852              :     }
     853           22 :     if (GNUNET_OK !=
     854           22 :         TALER_TESTING_get_trait_denom_sig (coin_command,
     855              :                                            0,
     856              :                                            &melt_sig))
     857              :     {
     858            0 :       GNUNET_break (0);
     859            0 :       TALER_TESTING_interpreter_fail (rms->is);
     860            0 :       return;
     861              :     }
     862           22 :     if (GNUNET_OK !=
     863           22 :         TALER_TESTING_get_trait_denom_pub (coin_command,
     864              :                                            0,
     865              :                                            &melt_denom_pub))
     866              :     {
     867            0 :       GNUNET_break (0);
     868            0 :       TALER_TESTING_interpreter_fail (rms->is);
     869            0 :       return;
     870              :     }
     871              : 
     872              :     /* Melt amount starts with the melt fee of the old coin; we'll add the
     873              :        values and withdraw fees of the fresh coins next */
     874           22 :     melt_amount = melt_denom_pub->fees.refresh;
     875           22 :     age_restricted_denom = melt_denom_pub->key.age_mask.bits != 0;
     876           22 :     GNUNET_assert (age_restricted_denom == (NULL != age_commitment_proof));
     877           22 :     GNUNET_assert ((NULL == age_commitment_proof) ||
     878              :                    (0 < age_commitment_proof->commitment.num));
     879          110 :     for (unsigned int i = 0; i<num_fresh_coins; i++)
     880              :     {
     881              :       const struct TALER_EXCHANGE_DenomPublicKey *fresh_pk;
     882              : 
     883           88 :       if (GNUNET_OK !=
     884           88 :           TALER_string_to_amount (melt_fresh_amounts[i],
     885              :                                   &fresh_amount))
     886              :       {
     887            0 :         GNUNET_break (0);
     888            0 :         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     889              :                     "Failed to parse amount `%s' at index %u\n",
     890              :                     melt_fresh_amounts[i],
     891              :                     i);
     892            0 :         TALER_TESTING_interpreter_fail (rms->is);
     893            0 :         return;
     894              :       }
     895           88 :       fresh_pk = TALER_TESTING_find_pk (TALER_TESTING_get_keys (rms->is),
     896              :                                         &fresh_amount,
     897              :                                         age_restricted_denom);
     898           88 :       if (NULL == fresh_pk)
     899              :       {
     900            0 :         GNUNET_break (0);
     901              :         /* Subroutine logs specific error */
     902            0 :         TALER_TESTING_interpreter_fail (rms->is);
     903            0 :         return;
     904              :       }
     905           88 :       GNUNET_assert (0 <=
     906              :                      TALER_amount_add (&melt_amount,
     907              :                                        &melt_amount,
     908              :                                        &fresh_amount));
     909           88 :       GNUNET_assert (0 <=
     910              :                      TALER_amount_add (&melt_amount,
     911              :                                        &melt_amount,
     912              :                                        &fresh_pk->fees.withdraw));
     913           88 :       rms->fresh_pks[i] = *fresh_pk;
     914              :       /* Make a deep copy of the RSA key */
     915           88 :       TALER_denom_pub_copy (&rms->fresh_pks[i].key,
     916              :                             &fresh_pk->key);
     917              :     } /* end for */
     918              : 
     919           22 :     rms->melt_input.melt_priv = *rms->melt_priv;
     920           22 :     GNUNET_CRYPTO_eddsa_key_get_public (&rms->melt_priv->eddsa_priv,
     921              :                                         &rms->melt_pub.eddsa_pub);
     922           22 :     rms->melt_input.melt_amount = melt_amount;
     923           22 :     rms->melt_input.melt_sig = *melt_sig;
     924           22 :     rms->melt_input.melt_pk = *melt_denom_pub;
     925              : 
     926           22 :     if (NULL != age_commitment_proof)
     927              :     {
     928           12 :       GNUNET_assert (NULL != h_age_commitment);
     929           12 :       rms->melt_input.melt_age_commitment_proof = age_commitment_proof;
     930           12 :       rms->melt_input.melt_h_age_commitment = h_age_commitment;
     931              :     }
     932           22 :     rms->melt_input.fresh_denom_pubs = rms->fresh_pks;
     933           22 :     rms->melt_input.num_fresh_denom_pubs = num_fresh_coins;
     934              : 
     935           22 :     GNUNET_assert (age_restricted_denom ==
     936              :                    (NULL != age_commitment_proof));
     937           22 :     GNUNET_assert ((NULL == age_commitment_proof) ||
     938              :                    (0 < age_commitment_proof->commitment.num));
     939              : 
     940           22 :     rms->che.type = TALER_EXCHANGE_CTT_MELT;
     941           22 :     rms->che.amount = melt_amount;
     942           22 :     if (NULL != age_commitment_proof)
     943           12 :       rms->che.details.melt.h_age_commitment = *h_age_commitment;
     944              :     else
     945           10 :       rms->che.details.melt.no_hac = true;
     946              : 
     947           22 :     rms->mh = TALER_EXCHANGE_post_melt_create (
     948              :       TALER_TESTING_interpreter_get_context (is),
     949              :       TALER_TESTING_get_exchange_url (is),
     950              :       TALER_TESTING_get_keys (is),
     951           22 :       &rms->rms,
     952           22 :       &rms->melt_input);
     953              : 
     954           22 :     if (NULL == rms->mh)
     955              :     {
     956            0 :       GNUNET_break (0);
     957            0 :       TALER_TESTING_interpreter_fail (rms->is);
     958            0 :       return;
     959              :     }
     960           22 :     GNUNET_assert (TALER_EC_NONE ==
     961              :                    TALER_EXCHANGE_post_melt_start (rms->mh,
     962              :                                                    &melt_cb,
     963              :                                                    rms));
     964              :   }
     965              : }
     966              : 
     967              : 
     968              : /**
     969              :  * Free the "refresh melt" CMD state, and possibly cancel a
     970              :  * pending operation thereof.
     971              :  *
     972              :  * @param cls closure, must be a `struct RefreshMeltState`.
     973              :  * @param cmd the command which is being cleaned up.
     974              :  */
     975              : static void
     976           22 : melt_cleanup (void *cls,
     977              :               const struct TALER_TESTING_Command *cmd)
     978              : {
     979           22 :   struct MeltState *rms = cls;
     980              : 
     981              :   (void) cmd;
     982           22 :   if (NULL != rms->mh)
     983              :   {
     984            0 :     TALER_TESTING_command_incomplete (rms->is,
     985              :                                       cmd->label);
     986            0 :     TALER_EXCHANGE_post_melt_cancel (rms->mh);
     987            0 :     rms->mh = NULL;
     988              :   }
     989           22 :   if (NULL != rms->retry_task)
     990              :   {
     991            0 :     GNUNET_SCHEDULER_cancel (rms->retry_task);
     992            0 :     rms->retry_task = NULL;
     993              :   }
     994           22 :   if (NULL != rms->fresh_pks)
     995              :   {
     996          110 :     for (unsigned int i = 0; i < rms->num_fresh_coins; i++)
     997           88 :       TALER_denom_pub_free (&rms->fresh_pks[i].key);
     998           22 :     GNUNET_free (rms->fresh_pks);
     999              :   }
    1000           22 :   if (NULL != rms->blinding_values)
    1001              :   {
    1002           40 :     for (unsigned int i = 0; i < rms->num_blinding_values; i++)
    1003           32 :       TALER_denom_ewv_free (&rms->blinding_values[i]);
    1004            8 :     GNUNET_free (rms->blinding_values);
    1005              :   }
    1006           22 :   GNUNET_free (rms->melt_fresh_amounts);
    1007           22 :   GNUNET_free (rms);
    1008           22 : }
    1009              : 
    1010              : 
    1011              : /**
    1012              :  * Offer internal data to the "refresh melt" CMD.
    1013              :  *
    1014              :  * @param cls closure.
    1015              :  * @param[out] ret result (could be anything).
    1016              :  * @param trait name of the trait.
    1017              :  * @param index index number of the object to offer.
    1018              :  * @return #GNUNET_OK on success.
    1019              :  */
    1020              : static enum GNUNET_GenericReturnValue
    1021           98 : melt_traits (void *cls,
    1022              :              const void **ret,
    1023              :              const char *trait,
    1024              :              unsigned int index)
    1025              : {
    1026           98 :   struct MeltState *rms = cls;
    1027              : 
    1028           98 :   if (index >= rms->num_fresh_coins)
    1029              :   {
    1030            0 :     GNUNET_break (0);
    1031            0 :     return GNUNET_SYSERR;
    1032              :   }
    1033              :   {
    1034              :     struct TALER_TESTING_Trait traits[] = {
    1035           98 :       TALER_TESTING_make_trait_denom_pub (index,
    1036           98 :                                           &rms->fresh_pks[index]),
    1037           98 :       TALER_TESTING_make_trait_coin_priv (0,
    1038              :                                           rms->melt_priv),
    1039           98 :       TALER_TESTING_make_trait_coin_pub (0,
    1040           98 :                                          &rms->melt_pub),
    1041           98 :       TALER_TESTING_make_trait_coin_history (0,
    1042           98 :                                              &rms->che),
    1043           98 :       TALER_TESTING_make_trait_age_commitment_proof (
    1044              :         index,
    1045              :         rms->melt_input.melt_age_commitment_proof),
    1046           98 :       TALER_TESTING_make_trait_h_age_commitment (
    1047              :         index,
    1048              :         rms->melt_input.melt_h_age_commitment),
    1049           98 :       TALER_TESTING_make_trait_refresh_seed (&rms->rms),
    1050           98 :       (NULL != rms->reveal_melt_input.blinding_values)
    1051           68 :       ? TALER_TESTING_make_trait_exchange_blinding_values (
    1052              :         index,
    1053           68 :         &rms->reveal_melt_input.blinding_values[index])
    1054           98 :       : TALER_TESTING_trait_end (),
    1055           98 :       TALER_TESTING_trait_end ()
    1056              :     };
    1057              : 
    1058           98 :     return TALER_TESTING_get_trait (traits,
    1059              :                                     ret,
    1060              :                                     trait,
    1061              :                                     index);
    1062              :   }
    1063              : }
    1064              : 
    1065              : 
    1066              : /**
    1067              :  * Parse list of amounts for melt operation.
    1068              :  *
    1069              :  * @param[in,out] rms where to store the list
    1070              :  * @param ap NULL-termianted list of amounts to be melted (one per fresh coin)
    1071              :  * @return #GNUNET_OK on success
    1072              :  */
    1073              : static enum GNUNET_GenericReturnValue
    1074           22 : parse_amounts (struct MeltState *rms,
    1075              :                va_list ap)
    1076              : {
    1077              :   unsigned int len;
    1078              :   unsigned int off;
    1079              :   const char *amount;
    1080              : 
    1081           22 :   len = 0;
    1082           22 :   off = 0;
    1083           44 :   while (NULL != (amount = va_arg (ap, const char *)))
    1084              :   {
    1085            0 :     if (len == off)
    1086              :     {
    1087              :       struct TALER_Amount a;
    1088              : 
    1089            0 :       GNUNET_array_grow (rms->melt_fresh_amounts,
    1090              :                          len,
    1091              :                          off + 16);
    1092            0 :       if (GNUNET_OK !=
    1093            0 :           TALER_string_to_amount (amount, &a))
    1094              :       {
    1095            0 :         GNUNET_break (0);
    1096            0 :         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1097              :                     "Failed to parse amount `%s' at index %u\n",
    1098              :                     amount, off);
    1099            0 :         GNUNET_free (rms->melt_fresh_amounts);
    1100            0 :         rms->melt_fresh_amounts = NULL;
    1101            0 :         return GNUNET_SYSERR;
    1102              :       }
    1103            0 :       rms->melt_fresh_amounts[off++] = amount;
    1104              :     }
    1105              :   }
    1106           22 :   if (0 == off)
    1107           22 :     return GNUNET_OK; /* no amounts given == use defaults! */
    1108              :   /* ensure NULL-termination */
    1109            0 :   GNUNET_array_grow (rms->melt_fresh_amounts,
    1110              :                      len,
    1111              :                      off + 1);
    1112            0 :   return GNUNET_OK;
    1113              : }
    1114              : 
    1115              : 
    1116              : struct TALER_TESTING_Command
    1117           14 : TALER_TESTING_cmd_melt (const char *label,
    1118              :                         const char *coin_reference,
    1119              :                         unsigned int expected_response_code,
    1120              :                         ...)
    1121              : {
    1122              :   struct MeltState *rms;
    1123              :   va_list ap;
    1124              : 
    1125           14 :   rms = GNUNET_new (struct MeltState);
    1126           14 :   rms->coin_reference = coin_reference;
    1127           14 :   rms->expected_response_code = expected_response_code;
    1128           14 :   va_start (ap,
    1129              :             expected_response_code);
    1130           14 :   GNUNET_assert (GNUNET_OK ==
    1131              :                  parse_amounts (rms, ap));
    1132           14 :   va_end (ap);
    1133              :   {
    1134           14 :     struct TALER_TESTING_Command cmd = {
    1135              :       .label = label,
    1136              :       .cls = rms,
    1137              :       .run = &melt_run,
    1138              :       .cleanup = &melt_cleanup,
    1139              :       .traits = &melt_traits
    1140              :     };
    1141              : 
    1142           14 :     return cmd;
    1143              :   }
    1144              : }
    1145              : 
    1146              : 
    1147              : struct TALER_TESTING_Command
    1148            8 : TALER_TESTING_cmd_melt_double (const char *label,
    1149              :                                const char *coin_reference,
    1150              :                                unsigned int expected_response_code,
    1151              :                                ...)
    1152              : {
    1153              :   struct MeltState *rms;
    1154              :   va_list ap;
    1155              : 
    1156            8 :   rms = GNUNET_new (struct MeltState);
    1157            8 :   rms->coin_reference = coin_reference;
    1158            8 :   rms->expected_response_code = expected_response_code;
    1159            8 :   rms->double_melt = true;
    1160            8 :   va_start (ap,
    1161              :             expected_response_code);
    1162            8 :   GNUNET_assert (GNUNET_OK ==
    1163              :                  parse_amounts (rms, ap));
    1164            8 :   va_end (ap);
    1165              :   {
    1166            8 :     struct TALER_TESTING_Command cmd = {
    1167              :       .label = label,
    1168              :       .cls = rms,
    1169              :       .run = &melt_run,
    1170              :       .cleanup = &melt_cleanup,
    1171              :       .traits = &melt_traits
    1172              :     };
    1173              : 
    1174            8 :     return cmd;
    1175              :   }
    1176              : }
    1177              : 
    1178              : 
    1179              : struct TALER_TESTING_Command
    1180            0 : TALER_TESTING_cmd_melt_with_retry (struct TALER_TESTING_Command cmd)
    1181              : {
    1182              :   struct MeltState *rms;
    1183              : 
    1184            0 :   GNUNET_assert (&melt_run == cmd.run);
    1185            0 :   rms = cmd.cls;
    1186            0 :   rms->do_retry = NUM_RETRIES;
    1187            0 :   return cmd;
    1188              : }
    1189              : 
    1190              : 
    1191              : /**
    1192              :  * Offer internal data from a "refresh reveal" CMD.
    1193              :  *
    1194              :  * @param cls closure.
    1195              :  * @param[out] ret result (could be anything).
    1196              :  * @param trait name of the trait.
    1197              :  * @param index index number of the object to offer.
    1198              :  * @return #GNUNET_OK on success.
    1199              :  */
    1200              : static enum GNUNET_GenericReturnValue
    1201          230 : melt_reveal_traits (void *cls,
    1202              :                     const void **ret,
    1203              :                     const char *trait,
    1204              :                     unsigned int index)
    1205              : {
    1206          230 :   struct RevealMeltState *rrs = cls;
    1207              : 
    1208          230 :   if (index >= rrs->num_fresh_coins)
    1209            8 :     return GNUNET_SYSERR;
    1210              : 
    1211              :   {
    1212              :     struct TALER_TESTING_Trait traits[] = {
    1213          222 :       TALER_TESTING_make_trait_coin_priv (
    1214              :         index,
    1215          222 :         &rrs->fresh_coins[index].coin_priv),
    1216          222 :       TALER_TESTING_make_trait_coin_pub (
    1217              :         index,
    1218          222 :         &rrs->fresh_coins[index].coin_pub),
    1219          222 :       TALER_TESTING_make_trait_age_commitment_proof (
    1220              :         index,
    1221          222 :         rrs->fresh_coins[index].age_commitment_proof),
    1222          222 :       TALER_TESTING_make_trait_h_age_commitment (
    1223              :         index,
    1224          222 :         &rrs->fresh_coins[index].h_age_commitment),
    1225          222 :       TALER_TESTING_make_trait_denom_pub (
    1226              :         index,
    1227          222 :         rrs->fresh_coins[index].pk),
    1228          222 :       TALER_TESTING_make_trait_denom_sig (
    1229              :         index,
    1230          222 :         &rrs->fresh_coins[index].sig),
    1231          222 :       TALER_TESTING_make_trait_blinding_key (
    1232              :         index,
    1233          222 :         &rrs->fresh_coins[index].blinding_key),
    1234          222 :       TALER_TESTING_make_trait_array_length (
    1235          222 :         &rrs->num_fresh_coins),
    1236          222 :       TALER_TESTING_make_trait_fresh_coins (
    1237          222 :         (const struct TALER_TESTING_FreshCoinData **) &rrs->fresh_coins),
    1238          222 :       TALER_TESTING_make_trait_planchet_secrets (index,
    1239          222 :                                                  &rrs->psa[index]),
    1240          222 :       TALER_TESTING_trait_end ()
    1241              :     };
    1242              : 
    1243          222 :     return TALER_TESTING_get_trait (traits,
    1244              :                                     ret,
    1245              :                                     trait,
    1246              :                                     index);
    1247              :   }
    1248              : }
    1249              : 
    1250              : 
    1251              : struct TALER_TESTING_Command
    1252           14 : TALER_TESTING_cmd_melt_reveal (const char *label,
    1253              :                                const char *melt_reference,
    1254              :                                unsigned int expected_response_code)
    1255              : {
    1256              :   struct RevealMeltState *rrs;
    1257              : 
    1258           14 :   rrs = GNUNET_new (struct RevealMeltState);
    1259           14 :   rrs->melt_reference = melt_reference;
    1260           14 :   rrs->expected_response_code = expected_response_code;
    1261              :   {
    1262           14 :     struct TALER_TESTING_Command cmd = {
    1263              :       .cls = rrs,
    1264              :       .label = label,
    1265              :       .run = &melt_reveal_run,
    1266              :       .cleanup = &melt_reveal_cleanup,
    1267              :       .traits = &melt_reveal_traits
    1268              :     };
    1269              : 
    1270           14 :     return cmd;
    1271              :   }
    1272              : }
    1273              : 
    1274              : 
    1275              : struct TALER_TESTING_Command
    1276            0 : TALER_TESTING_cmd_melt_reveal_with_retry (struct TALER_TESTING_Command cmd)
    1277              : {
    1278              :   struct RevealMeltState *rrs;
    1279              : 
    1280            0 :   GNUNET_assert (&melt_reveal_run == cmd.run);
    1281            0 :   rrs = cmd.cls;
    1282            0 :   rrs->do_retry = NUM_RETRIES;
    1283            0 :   return cmd;
    1284              : }
        

Generated by: LCOV version 2.0-1