exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

testing_api_cmd_refresh.c (37298B)


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