exchange

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

taler-exchange-httpd_post-melt.c (57002B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2025 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU Affero General Public License as published by the Free Software
      7   Foundation; either version 3, or (at your option) any later version.
      8 
      9   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
     10   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11   A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.
     12 
     13   You should have received a copy of the GNU Affero General Public License along with
     14   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
     15 */
     16 /**
     17  * @file taler-exchange-httpd_post-melt.c
     18  * @brief Handle /melt requests
     19  * @note This endpoint is active since vDOLDPLUS of the protocol API
     20  * @author Özgür Kesim
     21  */
     22 
     23 #include <gnunet/gnunet_util_lib.h>
     24 #include <jansson.h>
     25 #include "taler-exchange-httpd.h"
     26 #include "exchange-database/preflight.h"
     27 #include "taler/taler_json_lib.h"
     28 #include "taler/taler_mhd_lib.h"
     29 #include "taler-exchange-httpd_post-melt.h"
     30 #include "taler-exchange-httpd_responses.h"
     31 #include "taler-exchange-httpd_get-keys.h"
     32 #include "taler-exchange-httpd_secmod-helpers.h"
     33 #include "taler/taler_util.h"
     34 #include "exchange-database/do_refresh.h"
     35 #include "exchange-database/get_coin_denomination.h"
     36 #include "exchange-database/get_refresh.h"
     37 
     38 /**
     39  * The different type of errors that might occur, sorted by name.
     40  * Some of them require idempotency checks, which are marked
     41  * in @e idempotency_check_required below.
     42  */
     43 enum MeltError
     44 {
     45   MELT_ERROR_NONE = 0,
     46   MELT_ERROR_AGE_RESTRICTION_COMMITMENT_INVALID,
     47   MELT_ERROR_AGE_RESTRICTION_NOT_SUPPORTED_BY_DENOMINATION,
     48   MELT_ERROR_AMOUNT_OVERFLOW,
     49   MELT_ERROR_AMOUNT_PLUS_FEE_OVERFLOW,
     50   MELT_ERROR_AMOUNT_WITH_FEE_INCORRECT,
     51   MELT_ERROR_BLINDING_SEED_REQUIRED,
     52   MELT_ERROR_COIN_CIPHER_MISMATCH,
     53   MELT_COIN_CONFLICTING_DENOMINATION_KEY,
     54   MELT_ERROR_COIN_EXPIRED_NO_ZOMBIE,
     55   MELT_ERROR_COIN_SIGNATURE_INVALID,
     56   MELT_ERROR_COIN_UNKNOWN,
     57   MELT_ERROR_CONFIRMATION_SIGN,
     58   MELT_ERROR_CRYPTO_HELPER,
     59   MELT_ERROR_DB_FETCH_FAILED,
     60   MELT_ERROR_DB_INVARIANT_FAILURE,
     61   MELT_ERROR_DB_MAKE_COIN_KNOW_FAILURE,
     62   MELT_ERROR_DB_PREFLIGHT_FAILURE,
     63   MELT_ERROR_DENOMINATION_EXPIRED,
     64   MELT_ERROR_DENOMINATION_KEY_UNKNOWN,
     65   MELT_ERROR_DENOMINATION_REVOKED,
     66   MELT_ERROR_DENOMINATION_SIGN,
     67   MELT_ERROR_DENOMINATION_SIGNATURE_INVALID,
     68   MELT_ERROR_DENOMINATION_VALIDITY_IN_FUTURE,
     69   MELT_ERROR_DUPLICATE_PLANCHET,
     70   MELT_ERROR_DUPLICATE_TRANSFER_PUB,
     71   MELT_ERROR_INSUFFICIENT_FUNDS,
     72   MELT_ERROR_KEYS_MISSING,
     73   MELT_ERROR_FEES_EXCEED_CONTRIBUTION,
     74   MELT_ERROR_NONCE_RESUSE,
     75   MELT_ERROR_REQUEST_PARAMETER_MALFORMED,
     76 };
     77 
     78 /**
     79  * With the bits set in this value will be mark the errors
     80  * that require a check for idempotency before actually
     81  * returning an error.
     82  */
     83 static const uint64_t idempotency_check_required =
     84   0
     85   | (1 << MELT_ERROR_DENOMINATION_EXPIRED)
     86   | (1 << MELT_ERROR_DENOMINATION_KEY_UNKNOWN)
     87   | (1 << MELT_ERROR_DENOMINATION_REVOKED)
     88   | (1 << MELT_ERROR_INSUFFICIENT_FUNDS) /* TODO: is this still correct? Compare exchange_do_refresh.sql */
     89   | (1 << MELT_ERROR_KEYS_MISSING);
     90 
     91 #define IDEMPOTENCY_CHECK_REQUIRED(error) \
     92         (0 != (idempotency_check_required & (1 << (error))))
     93 
     94 /**
     95  * Context for a /melt request
     96  */
     97 struct MeltContext
     98 {
     99 
    100   /**
    101    * Processing phase we are in.
    102    * The ordering here partially matters, as we progress through
    103    * them by incrementing the phase in the happy path.
    104    */
    105   enum MeltPhase
    106   {
    107     MELT_PHASE_PARSE,
    108     MELT_PHASE_CHECK_MELT_VALID,
    109     MELT_PHASE_CHECK_KEYS,
    110     MELT_PHASE_CHECK_COIN_SIGNATURE,
    111     MELT_PHASE_PREPARE_TRANSACTION,
    112     MELT_PHASE_RUN_TRANSACTION,
    113     MELT_PHASE_GENERATE_REPLY_SUCCESS,
    114     MELT_PHASE_GENERATE_REPLY_ERROR,
    115     MELT_PHASE_RETURN_NO,
    116     MELT_PHASE_RETURN_YES,
    117   } phase;
    118 
    119 
    120   /**
    121    * Request context
    122    */
    123   const struct TEH_RequestContext *rc;
    124 
    125   /**
    126    * Current time for the DB transaction.
    127    */
    128   struct GNUNET_TIME_Timestamp now;
    129 
    130   /**
    131    * The current key state
    132    */
    133   struct TEH_KeyStateHandle *ksh;
    134 
    135   /**
    136    * The melted coin's denomination key
    137    */
    138   struct TEH_DenominationKey *melted_coin_denom;
    139 
    140   /**
    141    * Set to true if this coin's denomination was revoked and the operation
    142    * is thus only allowed for zombie coins where the transaction
    143    * history includes a #TALER_EXCHANGEDB_TT_OLD_COIN_RECOUP.
    144    *
    145    * TODO: find a better terminology.  The sentences in the comments containing
    146    * "zombie" make semantically _no sense_!
    147    */
    148   bool zombie_required;
    149 
    150   /**
    151    * We already checked and noticed that the coin is known. Hence we
    152    * can skip the "ensure_coin_known" step of the transaction.
    153    */
    154   bool coin_is_known;
    155 
    156   /**
    157    * UUID of the coin in the known_coins table.
    158    */
    159   uint64_t known_coin_id;
    160 
    161   /**
    162    * Captures all parameters provided in the JSON request
    163    */
    164   struct
    165   {
    166 
    167     /**
    168      * All fields (from the request or computed)
    169      * that we persist in the database.
    170      */
    171     struct TALER_EXCHANGEDB_Refresh_vDOLDPLUS refresh;
    172 
    173     /**
    174      * In some error cases we check for idempotency.
    175      * If we find an entry in the database, we mark this here.
    176      */
    177     bool is_idempotent;
    178 
    179     /**
    180      * In some error conditions the request is checked
    181      * for idempotency and the result from the database
    182      * is stored here.
    183      */
    184     struct TALER_EXCHANGEDB_Refresh_vDOLDPLUS refresh_idem;
    185 
    186     /**
    187      * True if @e blinding_seed is missing in the request
    188      */
    189     bool no_blinding_seed;
    190 
    191     /**
    192      * Array @e persis.num_coins of hashes of the public keys
    193      * of the denominations to refresh.
    194      */
    195     struct TALER_DenominationHashP *denoms_h;
    196 
    197     /**
    198      * Array of @e refresh.num_coins blinded coin planchets, arranged
    199      * in runs of @e refresh.num_coins coins, [0..num_coins)..[0..num_coins),
    200      * one for each kappa value.
    201      */
    202     struct TALER_BlindedPlanchet *planchets[TALER_CNC_KAPPA];
    203 
    204     /**
    205      * @since vDOLDPLUS
    206      * #TALER_CNC_KAPPA arrays of @e refresh.num_coins transfer public keys
    207      * in runs of @e num_coins coins, [0..num_coins)..[0..num_coins),
    208      * one for each kappa value.
    209      *
    210      * MAYBE null.  If the client has NOT provided the transfer_pubs in the request,
    211      * @e refresh.is_v27_refresh will be true.
    212      *
    213      * TODO: Once v27 clients are gone, this MUST NOT be nulls.
    214      */
    215     struct TALER_TransferPublicKeyP *transfer_pubs[TALER_CNC_KAPPA];
    216 
    217     /**
    218      * #TALER_CNC_KAPPA hashes of the batches of @e num_coins coins.
    219      */
    220     struct TALER_KappaHashBlindedPlanchetsP kappa_planchets_h;
    221 
    222     /**
    223      * Array @e withdraw.num_r_pubs of indices into @e denoms_h
    224      * of CS denominations.
    225      */
    226     uint32_t *cs_indices;
    227 
    228     /**
    229      * Total (over all coins) amount (excluding fee) committed for the refresh
    230      */
    231     struct TALER_Amount amount;
    232 
    233   } request;
    234 
    235   /**
    236    * Errors occurring during evaluation of the request are captured in this
    237    * struct.  In phase WITHDRAW_PHASE_GENERATE_REPLY_ERROR an appropriate error
    238    * message is prepared and sent to the client.
    239    */
    240   struct
    241   {
    242     /* The (internal) error code */
    243     enum MeltError code;
    244 
    245     /**
    246      * Some errors require details to be sent to the client.
    247      * These are captured in this union.
    248      * Each field is named according to the error that is using it, except
    249      * commented otherwise.
    250      */
    251     union
    252     {
    253       const char *request_parameter_malformed;
    254 
    255       /**
    256        * For all errors related to a particular denomination, i.e.
    257        *  #MELT_ERROR_DENOMINATION_KEY_UNKNOWN,
    258        *  #MELT_ERROR_DENOMINATION_EXPIRED,
    259        *  #MELT_ERROR_DENOMINATION_VALIDITY_IN_FUTURE,
    260        *  #MELT_ERROR_AGE_RESTRICTION_NOT_SUPPORTED_BY_DENOMINATION,
    261        * we use this one field.
    262        */
    263       struct TALER_DenominationHashP denom_h;
    264 
    265       const char *db_fetch_context;
    266 
    267       enum TALER_ErrorCode ec_confirmation_sign;
    268 
    269       enum TALER_ErrorCode ec_denomination_sign;
    270 
    271       /* remaining value of the coin */
    272       struct TALER_Amount insufficient_funds;
    273 
    274     } details;
    275   } error;
    276 };
    277 
    278 /**
    279  * The following macros set the given error code,
    280  * set the phase to Melt_PHASE_GENERATE_REPLY_ERROR,
    281  * and optionally set the given field (with an optionally given value).
    282  */
    283 #define SET_ERROR(mc, ec) \
    284         do \
    285         { GNUNET_static_assert (MELT_ERROR_NONE != ec); \
    286           (mc)->error.code = (ec);                      \
    287           (mc)->phase = MELT_PHASE_GENERATE_REPLY_ERROR; } while (0)
    288 
    289 #define SET_ERROR_WITH_FIELD(mc, ec, field) \
    290         do \
    291         { GNUNET_static_assert (MELT_ERROR_NONE != ec); \
    292           (mc)->error.code = (ec);                      \
    293           (mc)->error.details.field = (field);          \
    294           (mc)->phase = MELT_PHASE_GENERATE_REPLY_ERROR; } while (0)
    295 
    296 #define SET_ERROR_WITH_DETAIL(mc, ec, field, value) \
    297         do \
    298         { GNUNET_static_assert (MELT_ERROR_NONE != ec); \
    299           (mc)->error.code = (ec);                      \
    300           (mc)->error.details.field = (value);          \
    301           (mc)->phase = MELT_PHASE_GENERATE_REPLY_ERROR; } while (0)
    302 
    303 
    304 /**
    305  * Terminate the main loop by returning the final result.
    306  *
    307  * @param[in,out] mc context to update phase for
    308  * @param mres MHD status to return
    309  */
    310 static void
    311 finish_loop (struct MeltContext *mc,
    312              enum MHD_Result mres)
    313 {
    314   mc->phase = (MHD_YES == mres)
    315                          ? MELT_PHASE_RETURN_YES
    316                          : MELT_PHASE_RETURN_NO;
    317 }
    318 
    319 
    320 /**
    321  * Free information in @a re, but not @a re itself.
    322  *
    323  * @param[in] re refresh data to free
    324  */
    325 static void
    326 free_refresh (struct TALER_EXCHANGEDB_Refresh_vDOLDPLUS *re)
    327 {
    328   if (NULL != re->denom_sigs)
    329   {
    330     for (size_t i = 0; i<re->num_coins; i++)
    331       TALER_blinded_denom_sig_free (&re->denom_sigs[i]);
    332     GNUNET_free (re->denom_sigs);
    333   }
    334   GNUNET_free (re->cs_r_values);
    335   GNUNET_free (re->denom_serials);
    336   GNUNET_free (re->denom_pub_hashes);
    337   TALER_denom_sig_free (&re->coin.denom_sig);
    338 }
    339 
    340 
    341 /**
    342  * Cleanup routine for melt request.
    343  * The function is called upon completion of the request
    344  * that should clean up @a rh_ctx.
    345  *
    346  * @param rc request context to clean up
    347  */
    348 static void
    349 clean_melt_rc (struct TEH_RequestContext *rc)
    350 {
    351   struct MeltContext *mc = rc->rh_ctx;
    352 
    353   GNUNET_free (mc->request.denoms_h);
    354   for (uint8_t k = 0; k<TALER_CNC_KAPPA; k++)
    355   {
    356     if (NULL != mc->request.planchets[k])
    357     {
    358       /* num_coins is set long before planchets[k] is allocated,
    359          so freeing it needs the above guard */
    360       for (size_t i = 0; i<mc->request.refresh.num_coins; i++)
    361         TALER_blinded_planchet_free (&mc->request.planchets[k][i]);
    362       GNUNET_free (mc->request.planchets[k]);
    363     }
    364     if (! mc->request.refresh.is_v27_refresh)
    365       GNUNET_free (mc->request.transfer_pubs[k]);
    366   }
    367   free_refresh (&mc->request.refresh);
    368   if (mc->request.is_idempotent)
    369     free_refresh (&mc->request.refresh_idem);
    370   GNUNET_free (mc->request.cs_indices);
    371   GNUNET_free (mc);
    372 }
    373 
    374 
    375 /**
    376  * Creates a new context for the incoming melt request
    377  *
    378  * @param mc melt request context
    379  * @param root json body of the request
    380  */
    381 static void
    382 phase_parse_request (
    383   struct MeltContext *mc,
    384   const json_t *root)
    385 {
    386   const json_t *j_denoms_h;
    387   const json_t *j_coin_evs;
    388   const json_t *j_transfer_pubs;
    389   enum GNUNET_GenericReturnValue res;
    390   struct GNUNET_JSON_Specification spec[] = {
    391     GNUNET_JSON_spec_fixed_auto ("old_coin_pub",
    392                                  &mc->request.refresh.coin.coin_pub),
    393     GNUNET_JSON_spec_fixed_auto ("old_denom_pub_h",
    394                                  &mc->request.refresh.coin.denom_pub_hash),
    395     GNUNET_JSON_spec_mark_optional (
    396       GNUNET_JSON_spec_fixed_auto ("old_age_commitment_h",
    397                                    &mc->request.refresh.coin.h_age_commitment),
    398       &mc->request.refresh.coin.no_age_commitment),
    399     TALER_JSON_spec_denom_sig ("old_denom_sig",
    400                                &mc->request.refresh.coin.denom_sig),
    401     GNUNET_JSON_spec_fixed_auto ("refresh_seed",
    402                                  &mc->request.refresh.refresh_seed),
    403     GNUNET_JSON_spec_mark_optional (
    404       GNUNET_JSON_spec_fixed_auto ("blinding_seed",
    405                                    &mc->request.refresh.blinding_seed),
    406       &mc->request.refresh.no_blinding_seed),
    407     TALER_JSON_spec_amount ("value_with_fee",
    408                             TEH_currency,
    409                             &mc->request.refresh.amount_with_fee),
    410     GNUNET_JSON_spec_mark_optional (
    411       GNUNET_JSON_spec_array_const ("transfer_pubs",
    412                                     &j_transfer_pubs),
    413       &mc->request.refresh.is_v27_refresh),
    414     GNUNET_JSON_spec_array_const ("denoms_h",
    415                                   &j_denoms_h),
    416     GNUNET_JSON_spec_array_const ("coin_evs",
    417                                   &j_coin_evs),
    418     GNUNET_JSON_spec_fixed_auto ("confirm_sig",
    419                                  &mc->request.refresh.coin_sig),
    420     GNUNET_JSON_spec_end ()
    421   };
    422 
    423   /* validate array size */
    424   GNUNET_static_assert (
    425     TALER_MAX_COINS < INT_MAX / TALER_CNC_KAPPA);
    426   res = TALER_MHD_parse_json_data (mc->rc->connection,
    427                                    root,
    428                                    spec);
    429   if (GNUNET_OK != res)
    430   {
    431     GNUNET_break_op (0);
    432     mc->phase = (GNUNET_NO == res)
    433       ? MELT_PHASE_RETURN_YES
    434       : MELT_PHASE_RETURN_NO;
    435     return;
    436   }
    437 
    438   mc->request.refresh.num_coins = json_array_size (j_denoms_h);
    439   if (0 == mc->request.refresh.num_coins)
    440   {
    441     GNUNET_break_op (0);
    442     SET_ERROR_WITH_DETAIL (mc,
    443                            MELT_ERROR_REQUEST_PARAMETER_MALFORMED,
    444                            request_parameter_malformed,
    445                            "denoms_h must not be empty");
    446     return;
    447   }
    448   if (TALER_MAX_COINS < mc->request.refresh.num_coins)
    449   {
    450     /**
    451      * The wallet had committed to more than the maximum coins allowed, the
    452      * reserve has been charged, but now the user can not melt any money
    453      * from it.  Note that the user can't get their money back in this case!
    454      */
    455     GNUNET_break_op (0);
    456     SET_ERROR_WITH_DETAIL (mc,
    457                            MELT_ERROR_REQUEST_PARAMETER_MALFORMED,
    458                            request_parameter_malformed,
    459                            "maximum number of coins that can be refreshed has been exceeded");
    460     return;
    461   }
    462   if (TALER_CNC_KAPPA != json_array_size (j_coin_evs))
    463   {
    464     GNUNET_break_op (0);
    465     SET_ERROR_WITH_DETAIL (mc,
    466                            MELT_ERROR_REQUEST_PARAMETER_MALFORMED,
    467                            request_parameter_malformed,
    468                            "coin_evs must be an array of length "TALER_CNC_KAPPA_STR);
    469     return;
    470   }
    471   if (! mc->request.refresh.is_v27_refresh &&
    472       (TALER_CNC_KAPPA != json_array_size (j_transfer_pubs)))
    473   {
    474     GNUNET_break_op (0);
    475     SET_ERROR_WITH_DETAIL (mc,
    476                            MELT_ERROR_REQUEST_PARAMETER_MALFORMED,
    477                            request_parameter_malformed,
    478                            "transfer_pubs must be an array of length "TALER_CNC_KAPPA_STR);
    479     return;
    480   }
    481 
    482 
    483   /* Extract the denomination hashes */
    484   {
    485     size_t idx;
    486     json_t *value;
    487 
    488     mc->request.denoms_h
    489       = GNUNET_new_array (mc->request.refresh.num_coins,
    490                           struct TALER_DenominationHashP);
    491 
    492     json_array_foreach (j_denoms_h, idx, value) {
    493       struct GNUNET_JSON_Specification ispec[] = {
    494         GNUNET_JSON_spec_fixed_auto (NULL,
    495                                      &mc->request.denoms_h[idx]),
    496         GNUNET_JSON_spec_end ()
    497       };
    498 
    499       res = TALER_MHD_parse_json_data (mc->rc->connection,
    500                                        value,
    501                                        ispec);
    502       if (GNUNET_YES != res)
    503       {
    504         GNUNET_break_op (0);
    505         mc->phase = (GNUNET_NO == res)
    506           ? MELT_PHASE_RETURN_YES
    507           : MELT_PHASE_RETURN_NO;
    508         return;
    509       }
    510     }
    511   }
    512 
    513   /* Parse blinded envelopes. */
    514   {
    515     json_t *j_kappa_planchets;
    516     size_t kappa;
    517     struct GNUNET_HashContext *ctx;
    518 
    519     /* ctx to calculate the planchet_h */
    520     ctx = GNUNET_CRYPTO_hash_context_start ();
    521     GNUNET_assert (NULL != ctx);
    522 
    523     json_array_foreach (j_coin_evs, kappa, j_kappa_planchets)
    524     {
    525       json_t *j_cev;
    526       size_t idx;
    527 
    528       if (mc->request.refresh.num_coins != json_array_size (j_kappa_planchets))
    529       {
    530         GNUNET_break_op (0);
    531         SET_ERROR_WITH_DETAIL (mc,
    532                                MELT_ERROR_REQUEST_PARAMETER_MALFORMED,
    533                                request_parameter_malformed,
    534                                "coin_evs[i][] size");
    535         return;
    536       }
    537 
    538       mc->request.planchets[kappa] =
    539         GNUNET_new_array (mc->request.refresh.num_coins,
    540                           struct  TALER_BlindedPlanchet);
    541 
    542       json_array_foreach (j_kappa_planchets, idx, j_cev)
    543       {
    544         /* Now parse the individual envelopes and calculate the hash of
    545          * the commitment along the way. */
    546         struct GNUNET_JSON_Specification kspec[] = {
    547           TALER_JSON_spec_blinded_planchet (NULL,
    548                                             &mc->request.planchets[kappa][idx]),
    549           GNUNET_JSON_spec_end ()
    550         };
    551 
    552         res = TALER_MHD_parse_json_data (mc->rc->connection,
    553                                          j_cev,
    554                                          kspec);
    555         if (GNUNET_OK != res)
    556         {
    557           GNUNET_break_op (0);
    558           mc->phase = (GNUNET_NO == res)
    559             ? MELT_PHASE_RETURN_YES
    560             : MELT_PHASE_RETURN_NO;
    561           return;
    562         }
    563       }
    564       /* Save the hash of the batch of planchets for index kappa */
    565       TALER_wallet_blinded_planchets_hash (
    566         mc->request.refresh.num_coins,
    567         mc->request.planchets[kappa],
    568         mc->request.denoms_h,
    569         &mc->request.kappa_planchets_h.tuple[kappa]);
    570       GNUNET_CRYPTO_hash_context_read (
    571         ctx,
    572         &mc->request.kappa_planchets_h.tuple[kappa],
    573         sizeof(mc->request.kappa_planchets_h.tuple[kappa]));
    574     }
    575     /* Finally calculate the total hash over all planchets */
    576     GNUNET_CRYPTO_hash_context_finish (
    577       ctx,
    578       &mc->request.refresh.planchets_h.hash);
    579   }
    580   /* Check for duplicate planchets. Technically a bug on
    581    * the client side that is harmless for us, but still
    582    * not allowed per protocol
    583    */
    584   {
    585     size_t max_idx = TALER_CNC_KAPPA * mc->request.refresh.num_coins;
    586 
    587     for (size_t I = 0; I < max_idx - 1; I++)
    588     {
    589       size_t ki = I / mc->request.refresh.num_coins;
    590       size_t ni = I % mc->request.refresh.num_coins;
    591 
    592       for (size_t J = I + 1; J < max_idx; J++)
    593       {
    594         size_t kj = J / mc->request.refresh.num_coins;
    595         size_t nj = J % mc->request.refresh.num_coins;
    596 
    597         if (0 == TALER_blinded_planchet_cmp (
    598               &mc->request.planchets[ki][ni],
    599               &mc->request.planchets[kj][nj]))
    600         {
    601           GNUNET_break_op (0);
    602           SET_ERROR (mc,
    603                      MELT_ERROR_DUPLICATE_PLANCHET);
    604           return;
    605         }
    606       }
    607     }
    608   }
    609 
    610   /* Parse the transfer public keys, if applicable */
    611   if (! mc->request.refresh.is_v27_refresh)
    612   {
    613     json_t *j_ktp;
    614     size_t kappa;
    615     size_t max_idx;
    616 
    617     json_array_foreach (j_transfer_pubs, kappa, j_ktp)
    618     {
    619       if (mc->request.refresh.num_coins !=
    620           json_array_size (j_ktp))
    621       {
    622         GNUNET_break_op (0);
    623         SET_ERROR_WITH_DETAIL (mc,
    624                                MELT_ERROR_REQUEST_PARAMETER_MALFORMED,
    625                                request_parameter_malformed,
    626                                "transfer_pubs[i][] size");
    627         return;
    628       }
    629 
    630       mc->request.transfer_pubs[kappa] =
    631         GNUNET_new_array (mc->request.refresh.num_coins,
    632                           struct  TALER_TransferPublicKeyP);
    633 
    634       /* Parse the batch of @e num_coins transfer public keys
    635        * at index kappa  */
    636       {
    637         struct GNUNET_JSON_Specification ktp_spec[] = {
    638           TALER_JSON_spec_array_fixed (NULL,
    639                                        mc->request.refresh.num_coins,
    640                                        mc->request.transfer_pubs[kappa],
    641                                        sizeof(*mc->request.transfer_pubs[kappa])
    642                                        ),
    643           GNUNET_JSON_spec_end ()
    644         };
    645 
    646         res = TALER_MHD_parse_json_data (mc->rc->connection,
    647                                          j_ktp,
    648                                          ktp_spec);
    649         if (GNUNET_OK != res)
    650         {
    651           GNUNET_break_op (0);
    652           mc->phase = (GNUNET_NO == res)
    653             ? MELT_PHASE_RETURN_YES
    654             : MELT_PHASE_RETURN_NO;
    655           return;
    656         }
    657       }
    658     }
    659     /* Check for duplicate transfer public keys. Technically a bug on
    660      * the client side that is harmless for us, but still
    661      * not allowed per protocol
    662      */
    663     max_idx = TALER_CNC_KAPPA * mc->request.refresh.num_coins;
    664 
    665     for (size_t I = 0; I < max_idx - 1; I++)
    666     {
    667       size_t ki = I / mc->request.refresh.num_coins;
    668       size_t ni = I % mc->request.refresh.num_coins;
    669 
    670       for (size_t J = I + 1; J < max_idx; J++)
    671       {
    672         size_t kj = J / mc->request.refresh.num_coins;
    673         size_t nj = J % mc->request.refresh.num_coins;
    674 
    675         if (0 == GNUNET_memcmp (
    676               &mc->request.transfer_pubs[ki][ni],
    677               &mc->request.transfer_pubs[kj][nj]))
    678         {
    679           GNUNET_break_op (0);
    680           SET_ERROR (mc,
    681                      MELT_ERROR_DUPLICATE_TRANSFER_PUB);
    682           return;
    683         }
    684       }
    685     }
    686   }
    687 
    688   mc->ksh = TEH_keys_get_state ();
    689   if (NULL == mc->ksh)
    690   {
    691     GNUNET_break (0);
    692     SET_ERROR (mc,
    693                MELT_ERROR_KEYS_MISSING);
    694     return;
    695   }
    696   mc->phase = MELT_PHASE_CHECK_MELT_VALID;
    697 }
    698 
    699 
    700 /**
    701  * Check if the given denomination is still or already valid, has not been
    702  * revoked and potentically supports age restriction.
    703  *
    704  * @param[in,out] mc context for the melt operation
    705  * @param denom_h Hash of the denomination key to check
    706  * @param[out] pdk denomination key found, might be NULL
    707  * @return #GNUNET_OK when denomation was found and valid,
    708  *         #GNUNET_NO when denomination is not valid at this time
    709  *         #GNUNET_SYSERR otherwise (denomination invalid), with finish_loop called.
    710  */
    711 static enum GNUNET_GenericReturnValue
    712 find_denomination (
    713   struct MeltContext *mc,
    714   const struct TALER_DenominationHashP *denom_h,
    715   struct TEH_DenominationKey **pdk)
    716 {
    717   struct TEH_DenominationKey *dk;
    718 
    719   *pdk = NULL;
    720   GNUNET_assert (NULL != mc->ksh);
    721   dk = TEH_keys_denomination_by_hash_from_state (mc->ksh,
    722                                                  denom_h,
    723                                                  NULL,
    724                                                  NULL);
    725   if (NULL == dk)
    726   {
    727     SET_ERROR_WITH_DETAIL (mc,
    728                            MELT_ERROR_DENOMINATION_KEY_UNKNOWN,
    729                            denom_h,
    730                            *denom_h);
    731     return GNUNET_SYSERR;
    732   }
    733   *pdk = dk;
    734 
    735   if (GNUNET_TIME_absolute_is_past (
    736         dk->meta.expire_withdraw.abs_time))
    737   {
    738     SET_ERROR_WITH_DETAIL (mc,
    739                            MELT_ERROR_DENOMINATION_EXPIRED,
    740                            denom_h,
    741                            *denom_h);
    742     /**
    743      * Note that we return GNUNET_NO here.
    744      * This way phase_check_melt_valid can react
    745      * to it as a non-error case and do the zombie check.
    746      */
    747     return GNUNET_NO;
    748   }
    749 
    750   if (GNUNET_TIME_absolute_is_future (
    751         dk->meta.start.abs_time))
    752   {
    753     GNUNET_break_op (0);
    754     SET_ERROR_WITH_DETAIL (mc,
    755                            MELT_ERROR_DENOMINATION_VALIDITY_IN_FUTURE,
    756                            denom_h,
    757                            *denom_h);
    758     return GNUNET_SYSERR;
    759   }
    760 
    761   if (dk->recoup_possible)
    762   {
    763     SET_ERROR (mc,
    764                MELT_ERROR_DENOMINATION_REVOKED);
    765     return GNUNET_SYSERR;
    766   }
    767 
    768   /* In case of age melt, make sure that the denomination supports age restriction */
    769   if (! (mc->request.refresh.coin.no_age_commitment) &&
    770       (0 == dk->denom_pub.age_mask.bits))
    771   {
    772     GNUNET_break_op (0);
    773     SET_ERROR_WITH_DETAIL (mc,
    774                            MELT_ERROR_AGE_RESTRICTION_NOT_SUPPORTED_BY_DENOMINATION,
    775                            denom_h,
    776                            *denom_h);
    777     return GNUNET_SYSERR;
    778   }
    779   if ((mc->request.refresh.coin.no_age_commitment) &&
    780       (0 != dk->denom_pub.age_mask.bits))
    781   {
    782     GNUNET_break_op (0);
    783     SET_ERROR (mc,
    784                MELT_ERROR_AGE_RESTRICTION_COMMITMENT_INVALID);
    785     return GNUNET_SYSERR;
    786   }
    787 
    788   return GNUNET_OK;
    789 }
    790 
    791 
    792 /**
    793  * Check if the given array of hashes of denomination_keys
    794  * - belong to valid denominations
    795  * - calculate the total amount of the denominations including fees
    796  * for melt.
    797  *
    798  * @param mc context of the melt to check keys for
    799  */
    800 static void
    801 phase_check_keys (
    802   struct MeltContext *mc)
    803 {
    804   bool is_cs_denom[mc->request.refresh.num_coins];
    805 
    806   memset (is_cs_denom,
    807           0,
    808           sizeof(is_cs_denom));
    809 
    810   mc->request.refresh.denom_serials =
    811     GNUNET_new_array (mc->request.refresh.num_coins,
    812                       uint64_t);
    813   GNUNET_assert (GNUNET_OK ==
    814                  TALER_amount_set_zero (TEH_currency,
    815                                         &mc->request.amount));
    816 
    817   /* Calculate the total value and withdraw fees for the fresh coins */
    818   for (size_t i = 0; i < mc->request.refresh.num_coins; i++)
    819   {
    820     struct TEH_DenominationKey *dk;
    821 
    822     if (GNUNET_OK !=
    823         find_denomination (mc,
    824                            &mc->request.denoms_h[i],
    825                            &dk))
    826       return;
    827 
    828     if (GNUNET_CRYPTO_BSA_CS ==
    829         dk->denom_pub.bsign_pub_key->cipher)
    830     {
    831       if (mc->request.refresh.no_blinding_seed)
    832       {
    833         GNUNET_break_op (0);
    834         SET_ERROR (mc,
    835                    MELT_ERROR_BLINDING_SEED_REQUIRED);
    836         return;
    837       }
    838       mc->request.refresh.num_cs_r_values++;
    839       is_cs_denom[i] = true;
    840     }
    841     /* Ensure the ciphers from the planchets match the denominations'. */
    842     {
    843       for (uint8_t k = 0; k < TALER_CNC_KAPPA; k++)
    844       {
    845         if (dk->denom_pub.bsign_pub_key->cipher !=
    846             mc->request.planchets[k][i].blinded_message->cipher)
    847         {
    848           GNUNET_break_op (0);
    849           SET_ERROR (mc,
    850                      MELT_ERROR_COIN_CIPHER_MISMATCH);
    851           return;
    852         }
    853       }
    854     }
    855     /* Accumulate the values */
    856     if (0 > TALER_amount_add (&mc->request.amount,
    857                               &mc->request.amount,
    858                               &dk->meta.value))
    859     {
    860       GNUNET_break_op (0);
    861       SET_ERROR (mc,
    862                  MELT_ERROR_AMOUNT_OVERFLOW);
    863       return;
    864     }
    865     /* Accumulate the withdraw fees for the fresh coins */
    866     if (0 > TALER_amount_add (&mc->request.amount,
    867                               &mc->request.amount,
    868                               &dk->meta.fees.withdraw))
    869     {
    870       GNUNET_break_op (0);
    871       SET_ERROR (mc,
    872                  MELT_ERROR_AMOUNT_PLUS_FEE_OVERFLOW);
    873       return;
    874     }
    875     mc->request.refresh.denom_serials[i] = dk->meta.serial;
    876   }
    877 
    878   /**
    879    * Calculate the amount (with withdraw fee) plus refresh fee and
    880    * compare with the value provided by the client in the request.
    881    */
    882   {
    883     struct TALER_Amount amount_with_fee;
    884 
    885     if (0 > TALER_amount_add (&amount_with_fee,
    886                               &mc->request.amount,
    887                               &mc->melted_coin_denom->meta.fees.refresh))
    888     {
    889       GNUNET_break_op (0);
    890       SET_ERROR (mc,
    891                  MELT_ERROR_AMOUNT_PLUS_FEE_OVERFLOW);
    892       return;
    893     }
    894 
    895     if (0 != TALER_amount_cmp (&amount_with_fee,
    896                                &mc->request.refresh.amount_with_fee))
    897     {
    898       GNUNET_break_op (0);
    899       SET_ERROR (mc,
    900                  MELT_ERROR_AMOUNT_WITH_FEE_INCORRECT);
    901       return;
    902     }
    903   }
    904 
    905   /* Save the indices of CS denominations */
    906   if (0 < mc->request.refresh.num_cs_r_values)
    907   {
    908     size_t j = 0;
    909 
    910     mc->request.cs_indices = GNUNET_new_array (
    911       mc->request.refresh.num_cs_r_values,
    912       uint32_t);
    913 
    914     for (size_t i = 0; i < mc->request.refresh.num_coins; i++)
    915     {
    916       if (is_cs_denom[i])
    917         mc->request.cs_indices[j++] = i;
    918     }
    919   }
    920   mc->phase++;
    921 }
    922 
    923 
    924 /**
    925  * Check that the client signature authorizing the melt is valid.
    926  *
    927  * @param[in,out] mc request context to check
    928  */
    929 static void
    930 phase_check_coin_signature (
    931   struct MeltContext *mc)
    932 {
    933   /* We can now compute the commitment */
    934   {
    935     struct TALER_KappaHashBlindedPlanchetsP k_bps_h = {0};
    936     struct TALER_KappaTransferPublicKeys k_transfer_pubs = {0};
    937 
    938     for (uint8_t k = 0; k < TALER_CNC_KAPPA; k++)
    939       TALER_wallet_blinded_planchets_hash (
    940         mc->request.refresh.num_coins,
    941         mc->request.planchets[k],
    942         mc->request.denoms_h,
    943         &k_bps_h.tuple[k]);
    944 
    945     if (! mc->request.refresh.is_v27_refresh)
    946     {
    947       k_transfer_pubs.num_transfer_pubs = mc->request.refresh.num_coins;
    948       for (uint8_t k = 0; k < TALER_CNC_KAPPA; k++)
    949         k_transfer_pubs.batch[k] = mc->request.transfer_pubs[k];
    950     }
    951 
    952     TALER_refresh_get_commitment (
    953       &mc->request.refresh.rc,
    954       &mc->request.refresh.refresh_seed,
    955       mc->request.no_blinding_seed
    956       ? NULL
    957       : &mc->request.refresh.blinding_seed,
    958       mc->request.refresh.is_v27_refresh
    959       ? NULL
    960       : &k_transfer_pubs,
    961       &k_bps_h,
    962       &mc->request.refresh.coin.coin_pub,
    963       &mc->request.refresh.amount_with_fee);
    964   }
    965 
    966   TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++;
    967   if (GNUNET_OK !=
    968       TALER_wallet_melt_verify (
    969         &mc->request.refresh.amount_with_fee,
    970         &mc->melted_coin_denom->meta.fees.refresh,
    971         &mc->request.refresh.rc,
    972         &mc->request.refresh.coin.denom_pub_hash,
    973         &mc->request.refresh.coin.h_age_commitment,
    974         &mc->request.refresh.coin.coin_pub,
    975         &mc->request.refresh.coin_sig))
    976   {
    977     GNUNET_break_op (0);
    978     SET_ERROR (mc,
    979                MELT_ERROR_COIN_SIGNATURE_INVALID);
    980     return;
    981   }
    982 
    983   mc->phase++;
    984 }
    985 
    986 
    987 /**
    988  * Check for information about the melted coin's denomination,
    989  * extracting its validity status and fee structure.
    990  * Baseline: check if deposits/refreshes are generally
    991  * simply still allowed for this denomination.
    992  *
    993  * @param mc parsed request information
    994  */
    995 static void
    996 phase_check_melt_valid (struct MeltContext *mc)
    997 {
    998   enum MeltPhase current_phase = mc->phase;
    999   /**
   1000    * Find the old coin's denomination.
   1001    * Note that we return only on GNUNET_SYSERR,
   1002    * because GNUNET_NO for the expired denomination
   1003    * will be handled below, with the zombie-check.
   1004    */
   1005   if (GNUNET_SYSERR ==
   1006       find_denomination (mc,
   1007                          &mc->request.refresh.coin.denom_pub_hash,
   1008                          &mc->melted_coin_denom))
   1009     return;
   1010 
   1011   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1012               "Melted coin's denomination is worth %s\n",
   1013               TALER_amount2s (&mc->melted_coin_denom->meta.value));
   1014 
   1015   /* sanity-check that "total melt amount > melt fee" */
   1016   if (0 <
   1017       TALER_amount_cmp (&mc->melted_coin_denom->meta.fees.refresh,
   1018                         &mc->request.refresh.amount_with_fee))
   1019   {
   1020     GNUNET_break_op (0);
   1021     SET_ERROR (mc,
   1022                MELT_ERROR_FEES_EXCEED_CONTRIBUTION);
   1023     return;
   1024   }
   1025 
   1026   if (GNUNET_OK !=
   1027       TALER_test_coin_valid (&mc->request.refresh.coin,
   1028                              &mc->melted_coin_denom->denom_pub))
   1029   {
   1030     GNUNET_break_op (0);
   1031     SET_ERROR (mc,
   1032                MELT_ERROR_DENOMINATION_SIGNATURE_INVALID);
   1033     return;
   1034   }
   1035 
   1036   /**
   1037    * find_denomination might have set the phase to
   1038    * produce an error, but we are still investigating.
   1039    * We reset the phase.
   1040    */
   1041   mc->phase = current_phase;
   1042   mc->error.code = MELT_ERROR_NONE;
   1043 
   1044   if (GNUNET_TIME_absolute_is_past (
   1045         mc->melted_coin_denom->meta.expire_deposit.abs_time))
   1046   {
   1047     /**
   1048      * We are past deposit expiration time, but maybe this is a zombie?
   1049      */
   1050     struct TALER_DenominationHashP denom_hash;
   1051     enum GNUNET_DB_QueryStatus qs;
   1052 
   1053     /* Check that the coin is dirty (we have seen it before), as we will
   1054        not just allow melting of a *fresh* coin where the denomination was
   1055        revoked (those must be recouped) */
   1056     qs = TALER_EXCHANGEDB_get_coin_denomination (
   1057       TEH_pg,
   1058       &mc->request.refresh.coin.coin_pub,
   1059       &mc->known_coin_id,
   1060       &denom_hash);
   1061     if (0 > qs)
   1062     {
   1063       /* There is no good reason for a serialization failure here: */
   1064       GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
   1065       SET_ERROR (mc,
   1066                  MELT_ERROR_DB_FETCH_FAILED);
   1067       return;
   1068     }
   1069     if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
   1070     {
   1071       /* We never saw this coin before, so _this_ justification is not OK.
   1072        * Note that the error was already set in find_denominations. */
   1073       GNUNET_assert (MELT_ERROR_DENOMINATION_EXPIRED ==
   1074                      mc->error.code);
   1075       GNUNET_assert (MELT_PHASE_GENERATE_REPLY_ERROR ==
   1076                      mc->phase);
   1077       return;
   1078     }
   1079     /* sanity check */
   1080     if (0 !=
   1081         GNUNET_memcmp (&denom_hash,
   1082                        &mc->request.refresh.coin.denom_pub_hash))
   1083     {
   1084       GNUNET_break_op (0);
   1085       SET_ERROR_WITH_DETAIL (mc,
   1086                              MELT_COIN_CONFLICTING_DENOMINATION_KEY,
   1087                              denom_h,
   1088                              denom_hash);
   1089       return;
   1090     }
   1091     /* Minor optimization: no need to run the
   1092        "ensure_coin_known" part of the transaction */
   1093     mc->coin_is_known = true;
   1094     /* check later that zombie is satisfied */
   1095     mc->zombie_required = true;
   1096   }
   1097   mc->phase++;
   1098 }
   1099 
   1100 
   1101 /**
   1102  * The request for melt was parsed successfully.
   1103  * Sign and persist the chosen blinded coins for the reveal step.
   1104  *
   1105  * @param mc The context for the current melt request
   1106  */
   1107 static void
   1108 phase_prepare_transaction (
   1109   struct MeltContext *mc)
   1110 {
   1111   mc->request.refresh.denom_sigs
   1112     = GNUNET_new_array (
   1113         mc->request.refresh.num_coins,
   1114         struct TALER_BlindedDenominationSignature);
   1115   mc->request.refresh.noreveal_index =
   1116     GNUNET_CRYPTO_random_u32 (TALER_CNC_KAPPA);
   1117 
   1118   /* Choose and sign the coins */
   1119   {
   1120     struct TEH_SECMOD_CoinSignData csds[mc->request.refresh.num_coins];
   1121     enum TALER_ErrorCode ec_denomination_sign;
   1122     size_t noreveal_idx = mc->request.refresh.noreveal_index;
   1123 
   1124     memset (csds,
   1125             0,
   1126             sizeof(csds));
   1127 
   1128     /* Pick the chosen blinded coins */
   1129     for (size_t i = 0; i<mc->request.refresh.num_coins; i++)
   1130     {
   1131       csds[i].bp = &mc->request.planchets[noreveal_idx][i];
   1132       csds[i].h_denom_pub = &mc->request.denoms_h[i];
   1133     }
   1134 
   1135     ec_denomination_sign = TEH_SECMOD_denom_batch_sign (
   1136       mc->request.refresh.num_coins,
   1137       csds,
   1138       true, /* for melt */
   1139       mc->request.refresh.denom_sigs);
   1140     if (TALER_EC_NONE != ec_denomination_sign)
   1141     {
   1142       GNUNET_break (0);
   1143       SET_ERROR_WITH_FIELD (mc,
   1144                             MELT_ERROR_DENOMINATION_SIGN,
   1145                             ec_denomination_sign);
   1146       return;
   1147     }
   1148 
   1149     /* Save the hash of chosen planchets */
   1150     mc->request.refresh.selected_h =
   1151       mc->request.kappa_planchets_h.tuple[noreveal_idx];
   1152 
   1153     /* If applicable, save the chosen transfer public keys */
   1154     if (! mc->request.refresh.is_v27_refresh)
   1155       mc->request.refresh.transfer_pubs =
   1156         mc->request.transfer_pubs[noreveal_idx];
   1157 
   1158     /**
   1159      * For the denominations with cipher CS, calculate the R-values
   1160      * and save the choices we made now, as at a later point, the
   1161      * private keys for the denominations might now be available anymore
   1162      * to make the same choice again.
   1163      */
   1164     if (0 <  mc->request.refresh.num_cs_r_values)
   1165     {
   1166       size_t num_cs_r_values = mc->request.refresh.num_cs_r_values;
   1167       struct TEH_SECMOD_CsDeriveData cdds[num_cs_r_values];
   1168       struct GNUNET_CRYPTO_CsSessionNonce nonces[num_cs_r_values];
   1169 
   1170       memset (nonces,
   1171               0,
   1172               sizeof(nonces));
   1173       mc->request.refresh.cs_r_values =
   1174         GNUNET_new_array (num_cs_r_values,
   1175                           struct GNUNET_CRYPTO_CSPublicRPairP);
   1176       mc->request.refresh.cs_r_choices = 0;
   1177 
   1178       GNUNET_assert (! mc->request.refresh.no_blinding_seed);
   1179       TALER_cs_derive_nonces_from_seed (
   1180         &mc->request.refresh.blinding_seed,
   1181         true, /* for melt */
   1182         num_cs_r_values,
   1183         mc->request.cs_indices,
   1184         nonces);
   1185 
   1186       for (size_t i = 0; i < num_cs_r_values; i++)
   1187       {
   1188         size_t idx = mc->request.cs_indices[i];
   1189 
   1190         GNUNET_assert (idx < mc->request.refresh.num_coins);
   1191         cdds[i].h_denom_pub = &mc->request.denoms_h[idx];
   1192         cdds[i].nonce = &nonces[i];
   1193       }
   1194 
   1195       /**
   1196        * Let the crypto helper generate the R-values and
   1197        * make the choices
   1198        */
   1199       if (TALER_EC_NONE !=
   1200           TEH_SECMOD_denom_cs_batch_r_pub_simple (
   1201             mc->request.refresh.num_cs_r_values,
   1202             cdds,
   1203             true, /* for melt */
   1204             mc->request.refresh.cs_r_values))
   1205       {
   1206         GNUNET_break (0);
   1207         SET_ERROR (mc,
   1208                    MELT_ERROR_CRYPTO_HELPER);
   1209         return;
   1210       }
   1211 
   1212       /* Now save the choices for the selected bits */
   1213       GNUNET_assert (num_cs_r_values <= 64);
   1214       for (size_t i = 0; i < num_cs_r_values; i++)
   1215       {
   1216         size_t idx = mc->request.cs_indices[i];
   1217         struct TALER_BlindedDenominationSignature *sig =
   1218           &mc->request.refresh.denom_sigs[idx];
   1219         uint64_t bit = sig->blinded_sig->details.blinded_cs_answer.b;
   1220 
   1221         GNUNET_static_assert (
   1222           TALER_MAX_COINS <=
   1223           sizeof(mc->request.refresh.cs_r_choices) * 8);
   1224         mc->request.refresh.cs_r_choices |= bit << i;
   1225       }
   1226     }
   1227   }
   1228   mc->phase++;
   1229 }
   1230 
   1231 
   1232 /**
   1233  * Generates response for the melt request.
   1234  *
   1235  * @param mc melt operation context
   1236  */
   1237 static void
   1238 phase_generate_reply_success (struct MeltContext *mc)
   1239 {
   1240   struct TALER_EXCHANGEDB_Refresh_vDOLDPLUS *db_obj;
   1241   struct TALER_ExchangePublicKeyP pub;
   1242   struct TALER_ExchangeSignatureP sig;
   1243   enum TALER_ErrorCode ec_confirmation_sign;
   1244 
   1245   db_obj = mc->request.is_idempotent
   1246     ? &mc->request.refresh_idem
   1247     : &mc->request.refresh;
   1248   ec_confirmation_sign =
   1249     TALER_exchange_online_melt_confirmation_sign (
   1250       &TEH_keys_exchange_sign_,
   1251       &db_obj->rc,
   1252       db_obj->noreveal_index,
   1253       &pub,
   1254       &sig);
   1255   if (TALER_EC_NONE != ec_confirmation_sign)
   1256   {
   1257     SET_ERROR_WITH_FIELD (mc,
   1258                           MELT_ERROR_CONFIRMATION_SIGN,
   1259                           ec_confirmation_sign);
   1260     return;
   1261   }
   1262 
   1263   finish_loop (mc,
   1264                TALER_MHD_REPLY_JSON_PACK (
   1265                  mc->rc->connection,
   1266                  MHD_HTTP_OK,
   1267                  GNUNET_JSON_pack_uint64 ("noreveal_index",
   1268                                           db_obj->noreveal_index),
   1269                  GNUNET_JSON_pack_data_auto ("exchange_sig",
   1270                                              &sig),
   1271                  GNUNET_JSON_pack_data_auto ("exchange_pub",
   1272                                              &pub)));
   1273 }
   1274 
   1275 
   1276 /**
   1277  * Check if the melt request is replayed and we already have an answer.
   1278  * If so, replay the existing answer and return the HTTP response.
   1279  *
   1280  * @param[in,out] mc parsed request data
   1281  * @return true if the request is idempotent with an existing request
   1282  *    false if we did not find the request in the DB and did not set @a mret
   1283  */
   1284 static bool
   1285 melt_is_idempotent (
   1286   struct MeltContext *mc)
   1287 {
   1288   enum GNUNET_DB_QueryStatus qs;
   1289 
   1290   qs = TALER_EXCHANGEDB_get_refresh (
   1291     TEH_pg,
   1292     &mc->request.refresh.rc,
   1293     &mc->request.refresh_idem);
   1294   if (0 > qs)
   1295   {
   1296     GNUNET_break (0);
   1297     SET_ERROR_WITH_DETAIL (mc,
   1298                            MELT_ERROR_DB_FETCH_FAILED,
   1299                            db_fetch_context,
   1300                            "get_refresh");
   1301     return true; /* Well, kind-of. */
   1302   }
   1303   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
   1304     return false;
   1305 
   1306   mc->request.is_idempotent = true;
   1307   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   1308               "request is idempotent\n");
   1309 
   1310   /* Generate idempotent reply */
   1311   TEH_METRICS_num_requests[TEH_MT_REQUEST_IDEMPOTENT_MELT]++;
   1312   mc->phase = MELT_PHASE_GENERATE_REPLY_SUCCESS;
   1313   mc->error.code = MELT_ERROR_NONE;
   1314   return true;
   1315 }
   1316 
   1317 
   1318 /**
   1319  * Reports an error, potentially with details.
   1320  * That is, it puts a error-type specific response into the MHD queue.
   1321  * It will do a idempotency check first, if needed for the error type.
   1322  *
   1323  * @param mc melt context
   1324  */
   1325 static void
   1326 phase_generate_reply_error (
   1327   struct MeltContext *mc)
   1328 {
   1329   GNUNET_assert (MELT_PHASE_GENERATE_REPLY_ERROR == mc->phase);
   1330   GNUNET_assert (MELT_ERROR_NONE != mc->error.code);
   1331 
   1332   if (IDEMPOTENCY_CHECK_REQUIRED (mc->error.code) &&
   1333       melt_is_idempotent (mc))
   1334   {
   1335     return;
   1336   }
   1337 
   1338   switch (mc->error.code)
   1339   {
   1340   case MELT_ERROR_NONE:
   1341     break;
   1342   case MELT_ERROR_REQUEST_PARAMETER_MALFORMED:
   1343     finish_loop (mc,
   1344                  TALER_MHD_reply_with_error (
   1345                    mc->rc->connection,
   1346                    MHD_HTTP_BAD_REQUEST,
   1347                    TALER_EC_GENERIC_PARAMETER_MALFORMED,
   1348                    mc->error.details.request_parameter_malformed));
   1349     return;
   1350   case MELT_ERROR_KEYS_MISSING:
   1351     finish_loop (mc,
   1352                  TALER_MHD_reply_with_error (
   1353                    mc->rc->connection,
   1354                    MHD_HTTP_INTERNAL_SERVER_ERROR,
   1355                    TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
   1356                    NULL));
   1357     return;
   1358   case MELT_ERROR_DB_FETCH_FAILED:
   1359     finish_loop (mc,
   1360                  TALER_MHD_reply_with_error (
   1361                    mc->rc->connection,
   1362                    MHD_HTTP_INTERNAL_SERVER_ERROR,
   1363                    TALER_EC_GENERIC_DB_FETCH_FAILED,
   1364                    mc->error.details.db_fetch_context));
   1365     return;
   1366   case MELT_ERROR_DB_INVARIANT_FAILURE:
   1367     finish_loop (mc,
   1368                  TALER_MHD_reply_with_error (
   1369                    mc->rc->connection,
   1370                    MHD_HTTP_INTERNAL_SERVER_ERROR,
   1371                    TALER_EC_GENERIC_DB_INVARIANT_FAILURE,
   1372                    NULL));
   1373     return;
   1374   case MELT_ERROR_DB_PREFLIGHT_FAILURE:
   1375     finish_loop (mc,
   1376                  TALER_MHD_reply_with_error (
   1377                    mc->rc->connection,
   1378                    MHD_HTTP_INTERNAL_SERVER_ERROR,
   1379                    TALER_EC_GENERIC_DB_COMMIT_FAILED,
   1380                    "make_coin_known"));
   1381     return;
   1382   case MELT_ERROR_DB_MAKE_COIN_KNOW_FAILURE:
   1383     finish_loop (mc,
   1384                  TALER_MHD_reply_with_error (
   1385                    mc->rc->connection,
   1386                    MHD_HTTP_INTERNAL_SERVER_ERROR,
   1387                    TALER_EC_GENERIC_DB_START_FAILED,
   1388                    "preflight failure"));
   1389     return;
   1390   case MELT_ERROR_COIN_UNKNOWN:
   1391     finish_loop (mc,
   1392                  TALER_MHD_reply_with_ec (
   1393                    mc->rc->connection,
   1394                    TALER_EC_EXCHANGE_GENERIC_COIN_UNKNOWN,
   1395                    NULL));
   1396     return;
   1397   case MELT_COIN_CONFLICTING_DENOMINATION_KEY:
   1398     finish_loop (mc,
   1399                  TALER_MHD_reply_with_ec (
   1400                    mc->rc->connection,
   1401                    TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY,
   1402                    TALER_B2S (&mc->error.details.denom_h)));
   1403     return;
   1404   case MELT_ERROR_COIN_EXPIRED_NO_ZOMBIE:
   1405     finish_loop (mc,
   1406                  TALER_MHD_reply_with_error (
   1407                    mc->rc->connection,
   1408                    MHD_HTTP_BAD_REQUEST,
   1409                    TALER_EC_EXCHANGE_MELT_COIN_EXPIRED_NO_ZOMBIE,
   1410                    NULL));
   1411     return;
   1412   case MELT_ERROR_DENOMINATION_SIGN:
   1413     finish_loop (mc,
   1414                  TALER_MHD_reply_with_ec (
   1415                    mc->rc->connection,
   1416                    mc->error.details.ec_denomination_sign,
   1417                    NULL));
   1418     return;
   1419   case MELT_ERROR_DENOMINATION_SIGNATURE_INVALID:
   1420     finish_loop (mc,
   1421                  TALER_MHD_reply_with_error (mc->rc->connection,
   1422                                              MHD_HTTP_FORBIDDEN,
   1423                                              TALER_EC_EXCHANGE_DENOMINATION_SIGNATURE_INVALID,
   1424                                              NULL));
   1425     return;
   1426   case MELT_ERROR_DENOMINATION_KEY_UNKNOWN:
   1427     GNUNET_break_op (0);
   1428     finish_loop (mc,
   1429                  TEH_RESPONSE_reply_unknown_denom_pub_hash (
   1430                    mc->rc->connection,
   1431                    &mc->error.details.denom_h));
   1432     return;
   1433   case MELT_ERROR_DENOMINATION_EXPIRED:
   1434     GNUNET_break_op (0);
   1435     finish_loop (mc,
   1436                  TEH_RESPONSE_reply_expired_denom_pub_hash (
   1437                    mc->rc->connection,
   1438                    &mc->error.details.denom_h,
   1439                    TALER_EC_EXCHANGE_GENERIC_DENOMINATION_EXPIRED,
   1440                    "MELT"));
   1441     return;
   1442   case MELT_ERROR_DENOMINATION_VALIDITY_IN_FUTURE:
   1443     finish_loop (mc,
   1444                  TEH_RESPONSE_reply_expired_denom_pub_hash (
   1445                    mc->rc->connection,
   1446                    &mc->error.details.denom_h,
   1447                    TALER_EC_EXCHANGE_GENERIC_DENOMINATION_VALIDITY_IN_FUTURE,
   1448                    "MELT"));
   1449     return;
   1450   case MELT_ERROR_DENOMINATION_REVOKED:
   1451     GNUNET_break_op (0);
   1452     finish_loop (mc,
   1453                  TALER_MHD_reply_with_ec (
   1454                    mc->rc->connection,
   1455                    TALER_EC_EXCHANGE_GENERIC_DENOMINATION_REVOKED,
   1456                    NULL));
   1457     return;
   1458   case MELT_ERROR_COIN_CIPHER_MISMATCH:
   1459     finish_loop (mc,
   1460                  TALER_MHD_reply_with_ec (
   1461                    mc->rc->connection,
   1462                    TALER_EC_EXCHANGE_GENERIC_CIPHER_MISMATCH,
   1463                    NULL));
   1464     return;
   1465   case MELT_ERROR_BLINDING_SEED_REQUIRED:
   1466     finish_loop (mc,
   1467                  TALER_MHD_reply_with_ec (
   1468                    mc->rc->connection,
   1469                    TALER_EC_GENERIC_PARAMETER_MISSING,
   1470                    "blinding_seed"));
   1471     return;
   1472   case MELT_ERROR_CRYPTO_HELPER:
   1473     finish_loop (mc,
   1474                  TALER_MHD_reply_with_ec (
   1475                    mc->rc->connection,
   1476                    TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
   1477                    NULL));
   1478     return;
   1479   case MELT_ERROR_AGE_RESTRICTION_NOT_SUPPORTED_BY_DENOMINATION:
   1480     {
   1481       char msg[256];
   1482 
   1483       GNUNET_snprintf (msg,
   1484                        sizeof(msg),
   1485                        "denomination %s does not support age restriction",
   1486                        GNUNET_h2s (&mc->error.details.denom_h.hash));
   1487       finish_loop (mc,
   1488                    TALER_MHD_reply_with_ec (
   1489                      mc->rc->connection,
   1490                      TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN,
   1491                      msg));
   1492       return;
   1493     }
   1494   case  MELT_ERROR_AGE_RESTRICTION_COMMITMENT_INVALID:
   1495     finish_loop (mc,
   1496                  TALER_MHD_reply_with_ec (
   1497                    mc->rc->connection,
   1498                    TALER_EC_EXCHANGE_REFRESHES_REVEAL_AGE_RESTRICTION_COMMITMENT_INVALID,
   1499                    "old_age_commitment_h"));
   1500     return;
   1501   case MELT_ERROR_AMOUNT_OVERFLOW:
   1502     finish_loop (mc,
   1503                  TALER_MHD_reply_with_error (
   1504                    mc->rc->connection,
   1505                    MHD_HTTP_BAD_REQUEST,
   1506                    TALER_EC_EXCHANGE_REFRESHES_REVEAL_COST_CALCULATION_OVERFLOW,
   1507                    "amount"));
   1508     return;
   1509   case MELT_ERROR_AMOUNT_PLUS_FEE_OVERFLOW:
   1510     finish_loop (mc,
   1511                  TALER_MHD_reply_with_error (
   1512                    mc->rc->connection,
   1513                    MHD_HTTP_INTERNAL_SERVER_ERROR,
   1514                    TALER_EC_EXCHANGE_REFRESHES_REVEAL_COST_CALCULATION_OVERFLOW,
   1515                    "amount+fee"));
   1516     return;
   1517   case MELT_ERROR_FEES_EXCEED_CONTRIBUTION:
   1518     finish_loop (mc,
   1519                  TALER_MHD_reply_with_error (mc->rc->connection,
   1520                                              MHD_HTTP_BAD_REQUEST,
   1521                                              TALER_EC_EXCHANGE_MELT_FEES_EXCEED_CONTRIBUTION,
   1522                                              NULL));
   1523     return;
   1524   case MELT_ERROR_AMOUNT_WITH_FEE_INCORRECT:
   1525     finish_loop (mc,
   1526                  TALER_MHD_reply_with_error (
   1527                    mc->rc->connection,
   1528                    MHD_HTTP_BAD_REQUEST,
   1529                    TALER_EC_EXCHANGE_REFRESHES_REVEAL_COST_CALCULATION_OVERFLOW,
   1530                    "value_with_fee incorrect"));
   1531     return;
   1532   case MELT_ERROR_CONFIRMATION_SIGN:
   1533     finish_loop (mc,
   1534                  TALER_MHD_reply_with_ec (
   1535                    mc->rc->connection,
   1536                    mc->error.details.ec_confirmation_sign,
   1537                    NULL));
   1538     return;
   1539   case MELT_ERROR_INSUFFICIENT_FUNDS:
   1540     finish_loop (mc,
   1541                  TEH_RESPONSE_reply_coin_insufficient_funds (
   1542                    mc->rc->connection,
   1543                    TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS,
   1544                    &mc->request.refresh.coin.denom_pub_hash,
   1545                    &mc->request.refresh.coin.coin_pub));
   1546     return;
   1547   case MELT_ERROR_DUPLICATE_PLANCHET:
   1548     finish_loop (mc,
   1549                  TALER_MHD_reply_with_error (
   1550                    mc->rc->connection,
   1551                    MHD_HTTP_BAD_REQUEST,
   1552                    TALER_EC_GENERIC_PARAMETER_MALFORMED,
   1553                    "duplicate planchet"));
   1554     return;
   1555   case MELT_ERROR_DUPLICATE_TRANSFER_PUB:
   1556     finish_loop (mc,
   1557                  TALER_MHD_reply_with_error (
   1558                    mc->rc->connection,
   1559                    MHD_HTTP_BAD_REQUEST,
   1560                    TALER_EC_GENERIC_PARAMETER_MALFORMED,
   1561                    "duplicate transfer_pub"));
   1562     return;
   1563   case MELT_ERROR_NONCE_RESUSE:
   1564     finish_loop (mc,
   1565                  TALER_MHD_reply_with_error (
   1566                    mc->rc->connection,
   1567                    MHD_HTTP_BAD_REQUEST,
   1568                    TALER_EC_GENERIC_PARAMETER_MALFORMED,
   1569                    "nonce reuse"));
   1570     return;
   1571   case MELT_ERROR_COIN_SIGNATURE_INVALID:
   1572     finish_loop (mc,
   1573                  TALER_MHD_reply_with_ec (
   1574                    mc->rc->connection,
   1575                    TALER_EC_EXCHANGE_MELT_COIN_SIGNATURE_INVALID,
   1576                    NULL));
   1577     return;
   1578   }
   1579   GNUNET_break (0);
   1580   finish_loop (mc,
   1581                TALER_MHD_reply_with_error (
   1582                  mc->rc->connection,
   1583                  MHD_HTTP_INTERNAL_SERVER_ERROR,
   1584                  TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
   1585                  "error phase without error"));
   1586 }
   1587 
   1588 
   1589 /**
   1590  * Function implementing melt transaction.  Runs the
   1591  * transaction logic; IF it returns a non-error code, the transaction
   1592  * logic MUST NOT queue a MHD response.  IF it returns an hard error,
   1593  * the transaction logic MUST queue a MHD response and set @a mhd_ret.
   1594  * IF it returns the soft error code, the function MAY be called again
   1595  * to retry and MUST not queue a MHD response.
   1596  *
   1597  * @param cls a `struct MeltContext *`
   1598  * @param connection MHD request which triggered the transaction
   1599  * @param[out] mhd_ret set to MHD response status for @a connection,
   1600  *             if transaction failed (!)
   1601  * @return transaction status
   1602  */
   1603 static enum GNUNET_DB_QueryStatus
   1604 melt_transaction (
   1605   void *cls,
   1606   struct MHD_Connection *connection,
   1607   enum MHD_Result *mhd_ret)
   1608 {
   1609   struct MeltContext *mc = cls;
   1610   enum GNUNET_DB_QueryStatus qs;
   1611   bool balance_ok;
   1612   bool found;
   1613   bool nonce_reuse;
   1614   uint32_t noreveal_index;
   1615   struct TALER_Amount insufficient_funds;
   1616 
   1617   (void) connection;
   1618   (void) mhd_ret;
   1619 
   1620   qs = TALER_EXCHANGEDB_do_refresh (TEH_pg,
   1621                                     &mc->request.refresh,
   1622                                     &mc->now,
   1623                                     &found,
   1624                                     &noreveal_index,
   1625                                     &mc->zombie_required,
   1626                                     &nonce_reuse,
   1627                                     &balance_ok,
   1628                                     &insufficient_funds);
   1629   if (0 > qs)
   1630   {
   1631     if (GNUNET_DB_STATUS_HARD_ERROR == qs)
   1632       SET_ERROR_WITH_DETAIL (mc,
   1633                              MELT_ERROR_DB_FETCH_FAILED,
   1634                              db_fetch_context,
   1635                              "do_refresh");
   1636     return qs;
   1637   }
   1638   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
   1639   {
   1640     GNUNET_break_op (0);
   1641     SET_ERROR (mc,
   1642                MELT_ERROR_COIN_UNKNOWN);
   1643     return GNUNET_DB_STATUS_HARD_ERROR;
   1644   }
   1645   if (found)
   1646   {
   1647     /**
   1648      * This request is idempotent, set the nonreveal_index
   1649      * to the previous one and reply success.
   1650      */
   1651     mc->request.refresh.noreveal_index = noreveal_index;
   1652     mc->phase = MELT_PHASE_GENERATE_REPLY_SUCCESS;
   1653     mc->error.code = MELT_ERROR_NONE;
   1654     return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
   1655   }
   1656   if (nonce_reuse)
   1657   {
   1658     GNUNET_break_op (0);
   1659     SET_ERROR (mc,
   1660                MELT_ERROR_NONCE_RESUSE);
   1661     return GNUNET_DB_STATUS_HARD_ERROR;
   1662   }
   1663   if (! balance_ok)
   1664   {
   1665     GNUNET_break_op (0);
   1666     SET_ERROR_WITH_FIELD (mc,
   1667                           MELT_ERROR_INSUFFICIENT_FUNDS,
   1668                           insufficient_funds);
   1669     return GNUNET_DB_STATUS_HARD_ERROR;
   1670   }
   1671   if (mc->zombie_required)
   1672   {
   1673     GNUNET_break_op (0);
   1674     SET_ERROR (mc,
   1675                MELT_ERROR_COIN_EXPIRED_NO_ZOMBIE);
   1676     return GNUNET_DB_STATUS_HARD_ERROR;
   1677   }
   1678 
   1679   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
   1680     TEH_METRICS_num_success[TEH_MT_SUCCESS_MELT]++;
   1681   return qs;
   1682 }
   1683 
   1684 
   1685 /**
   1686  * The request was prepared successfully.
   1687  * Run the main DB transaction.
   1688  *
   1689  * @param mc The context for the current melt request
   1690  */
   1691 static void
   1692 phase_run_transaction (
   1693   struct MeltContext *mc)
   1694 {
   1695   if (GNUNET_SYSERR ==
   1696       TALER_EXCHANGEDB_preflight (TEH_pg))
   1697   {
   1698     GNUNET_break (0);
   1699     SET_ERROR (mc,
   1700                MELT_ERROR_DB_PREFLIGHT_FAILURE);
   1701     return;
   1702   }
   1703 
   1704   /* first, make sure coin is known */
   1705   if (! mc->coin_is_known)
   1706   {
   1707     enum MHD_Result mhd_ret = -1;
   1708     enum GNUNET_DB_QueryStatus qs;
   1709 
   1710     for (unsigned int tries = 0; tries<MAX_TRANSACTION_COMMIT_RETRIES; tries++)
   1711     {
   1712       qs = TEH_make_coin_known (&mc->request.refresh.coin,
   1713                                 mc->rc->connection,
   1714                                 &mc->known_coin_id,
   1715                                 &mhd_ret);
   1716       if (GNUNET_DB_STATUS_SOFT_ERROR != qs)
   1717         break;
   1718     }
   1719     if (0 > qs)
   1720     {
   1721       GNUNET_break (0);
   1722       /* Check if an answer has been queued */
   1723       switch (mhd_ret)
   1724       {
   1725       case MHD_NO:
   1726         mc->phase = MELT_PHASE_RETURN_NO;
   1727         return;
   1728       case MHD_YES:
   1729         mc->phase = MELT_PHASE_RETURN_YES;
   1730         return;
   1731       default: /* ignore */
   1732         ;
   1733       }
   1734       SET_ERROR (mc,
   1735                  MELT_ERROR_DB_MAKE_COIN_KNOW_FAILURE);
   1736       return;
   1737     }
   1738   }
   1739 
   1740   /* run main database transaction */
   1741   {
   1742     enum MHD_Result mhd_ret = -1;
   1743     enum GNUNET_GenericReturnValue ret;
   1744     enum MeltPhase current_phase = mc->phase;
   1745 
   1746     GNUNET_assert (MELT_PHASE_RUN_TRANSACTION ==
   1747                    current_phase);
   1748     ret = TEH_DB_run_transaction (mc->rc->connection,
   1749                                   "run melt",
   1750                                   TEH_MT_REQUEST_MELT,
   1751                                   &mhd_ret,
   1752                                   &melt_transaction,
   1753                                   mc);
   1754     if (GNUNET_OK != ret)
   1755     {
   1756       GNUNET_break (0);
   1757       /* Check if an answer has been queued */
   1758       switch (mhd_ret)
   1759       {
   1760       case MHD_NO:
   1761         mc->phase = MELT_PHASE_RETURN_NO;
   1762         return;
   1763       case MHD_YES:
   1764         mc->phase = MELT_PHASE_RETURN_YES;
   1765         return;
   1766       default: /* ignore */
   1767         ;
   1768       }
   1769       GNUNET_assert (MELT_ERROR_NONE != mc->error.code);
   1770       GNUNET_assert (MELT_PHASE_GENERATE_REPLY_ERROR == mc->phase);
   1771       return;
   1772     }
   1773     /**
   1774      * In case of idempotency (which is not an error condition),
   1775      * the phase has changed in melt_transaction.
   1776      * We simple return.
   1777      */
   1778     if (current_phase != mc->phase)
   1779       return;
   1780   }
   1781   mc->phase++;
   1782 }
   1783 
   1784 
   1785 enum MHD_Result
   1786 TEH_handler_melt (
   1787   struct TEH_RequestContext *rc,
   1788   const json_t *root,
   1789   const char *const args[0])
   1790 {
   1791   struct MeltContext *mc = rc->rh_ctx;
   1792 
   1793   (void) args;
   1794   if (NULL == mc)
   1795   {
   1796     mc = GNUNET_new (struct MeltContext);
   1797     rc->rh_ctx = mc;
   1798     rc->rh_cleaner = &clean_melt_rc;
   1799     mc->rc = rc;
   1800     mc->now = GNUNET_TIME_timestamp_get ();
   1801   }
   1802 
   1803   while (true)
   1804   {
   1805     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1806                 "melt processing in phase %d\n",
   1807                 mc->phase);
   1808     switch (mc->phase)
   1809     {
   1810     case MELT_PHASE_PARSE:
   1811       phase_parse_request (mc,
   1812                            root);
   1813       break;
   1814     case MELT_PHASE_CHECK_MELT_VALID:
   1815       phase_check_melt_valid (mc);
   1816       break;
   1817     case MELT_PHASE_CHECK_KEYS:
   1818       phase_check_keys (mc);
   1819       break;
   1820     case MELT_PHASE_CHECK_COIN_SIGNATURE:
   1821       phase_check_coin_signature (mc);
   1822       break;
   1823     case MELT_PHASE_PREPARE_TRANSACTION:
   1824       phase_prepare_transaction (mc);
   1825       break;
   1826     case MELT_PHASE_RUN_TRANSACTION:
   1827       phase_run_transaction (mc);
   1828       break;
   1829     case MELT_PHASE_GENERATE_REPLY_SUCCESS:
   1830       phase_generate_reply_success (mc);
   1831       break;
   1832     case MELT_PHASE_GENERATE_REPLY_ERROR:
   1833       phase_generate_reply_error (mc);
   1834       break;
   1835     case MELT_PHASE_RETURN_YES:
   1836       return MHD_YES;
   1837     case MELT_PHASE_RETURN_NO:
   1838       return MHD_NO;
   1839     }
   1840   }
   1841 }