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

Generated by: LCOV version 2.0-1