LCOV - code coverage report
Current view: top level - testing - testing_api_cmd_refresh.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 241 368 65.5 %
Date: 2025-06-05 21:03:14 Functions: 12 16 75.0 %

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

Generated by: LCOV version 1.16