diff options
Diffstat (limited to 'src/exchange/taler-exchange-httpd_melt.c')
-rw-r--r-- | src/exchange/taler-exchange-httpd_melt.c | 98 |
1 files changed, 72 insertions, 26 deletions
diff --git a/src/exchange/taler-exchange-httpd_melt.c b/src/exchange/taler-exchange-httpd_melt.c index 54f1385d7..b31078f00 100644 --- a/src/exchange/taler-exchange-httpd_melt.c +++ b/src/exchange/taler-exchange-httpd_melt.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014-2021 Taler Systems SA + Copyright (C) 2014-2022 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software @@ -48,18 +48,15 @@ reply_melt_success (struct MHD_Connection *connection, { struct TALER_ExchangePublicKeyP pub; struct TALER_ExchangeSignatureP sig; - struct TALER_RefreshMeltConfirmationPS body = { - .purpose.size = htonl (sizeof (body)), - .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_MELT), - .rc = *rc, - .noreveal_index = htonl (noreveal_index) - }; enum TALER_ErrorCode ec; if (TALER_EC_NONE != - (ec = TEH_keys_exchange_sign (&body, - &pub, - &sig))) + (ec = TALER_exchange_online_melt_confirmation_sign ( + &TEH_keys_exchange_sign_, + rc, + noreveal_index, + &pub, + &sig))) { return TALER_MHD_reply_with_ec (connection, ec, @@ -105,6 +102,11 @@ struct MeltContext struct TALER_Amount coin_refresh_fee; /** + * Refresh master secret, if any of the fresh denominations use CS. + */ + struct TALER_RefreshMasterSecretP rms; + + /** * Set to true if this coin's denomination was revoked and the operation * is thus only allowed for zombie coins where the transaction * history includes a #TALER_EXCHANGEDB_TT_OLD_COIN_RECOUP. @@ -117,6 +119,10 @@ struct MeltContext */ bool coin_is_dirty; + /** + * True if @e rms is missing. + */ + bool no_rms; }; @@ -155,6 +161,9 @@ melt_transaction (void *cls, if (0 > (qs = TEH_plugin->do_melt (TEH_plugin->cls, + rmc->no_rms + ? NULL + : &rmc->rms, &rmc->refresh_session, rmc->known_coin_id, &rmc->zombie_required, @@ -174,7 +183,6 @@ melt_transaction (void *cls, if (rmc->zombie_required) { GNUNET_break_op (0); - TEH_plugin->rollback (TEH_plugin->cls); *mhd_ret = TALER_MHD_reply_with_error (connection, MHD_HTTP_BAD_REQUEST, TALER_EC_EXCHANGE_MELT_COIN_EXPIRED_NO_ZOMBIE, @@ -183,15 +191,17 @@ melt_transaction (void *cls, } if (! balance_ok) { - TEH_plugin->rollback (TEH_plugin->cls); + GNUNET_break_op (0); *mhd_ret = TEH_RESPONSE_reply_coin_insufficient_funds ( connection, TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS, + &rmc->refresh_session.coin.denom_pub_hash, &rmc->refresh_session.coin.coin_pub); return GNUNET_DB_STATUS_HARD_ERROR; } /* All good, commit, final response will be generated by caller */ + TEH_METRICS_num_success[TEH_MT_SUCCESS_MELT]++; return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; } @@ -224,12 +234,23 @@ database_melt (struct MHD_Connection *connection, MHD_RESULT mhd_ret = MHD_NO; enum GNUNET_DB_QueryStatus qs; - qs = TEH_make_coin_known (&rmc->refresh_session.coin, - connection, - &rmc->known_coin_id, - &mhd_ret); - /* no transaction => no serialization failures should be possible */ - GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs); + for (unsigned int tries = 0; tries<MAX_TRANSACTION_COMMIT_RETRIES; tries++) + { + qs = TEH_make_coin_known (&rmc->refresh_session.coin, + connection, + &rmc->known_coin_id, + &mhd_ret); + if (GNUNET_DB_STATUS_SOFT_ERROR != qs) + break; + } + if (GNUNET_DB_STATUS_SOFT_ERROR == qs) + { + GNUNET_break (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_COMMIT_FAILED, + "make_coin_known"); + } if (qs < 0) return mhd_ret; } @@ -241,7 +262,7 @@ database_melt (struct MHD_Connection *connection, if (GNUNET_OK != TEH_DB_run_transaction (connection, "run melt", - TEH_MT_MELT, + TEH_MT_REQUEST_MELT, &mhd_ret, &melt_transaction, rmc)) @@ -267,7 +288,7 @@ static MHD_RESULT check_melt_valid (struct MHD_Connection *connection, struct MeltContext *rmc) { - /* Baseline: check if deposits/refreshs are generally + /* Baseline: check if deposits/refreshes are generally simply still allowed for this denomination */ struct TEH_DenominationKey *dk; MHD_RESULT mret; @@ -278,6 +299,7 @@ check_melt_valid (struct MHD_Connection *connection, &mret); if (NULL == dk) return mret; + if (GNUNET_TIME_absolute_is_past (dk->meta.expire_legal.abs_time)) { /* Way too late now, even zombies have expired */ @@ -287,6 +309,7 @@ check_melt_valid (struct MHD_Connection *connection, TALER_EC_EXCHANGE_GENERIC_DENOMINATION_EXPIRED, "MELT"); } + if (GNUNET_TIME_absolute_is_future (dk->meta.start.abs_time)) { /* This denomination is not yet valid */ @@ -297,8 +320,13 @@ check_melt_valid (struct MHD_Connection *connection, "MELT"); } - rmc->coin_refresh_fee = dk->meta.fee_refresh; + rmc->coin_refresh_fee = dk->meta.fees.refresh; rmc->coin_value = dk->meta.value; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Melted coin's denomination is worth %s\n", + TALER_amount2s (&dk->meta.value)); + /* sanity-check that "total melt amount > melt fee" */ if (0 < TALER_amount_cmp (&rmc->coin_refresh_fee, @@ -310,7 +338,17 @@ check_melt_valid (struct MHD_Connection *connection, TALER_EC_EXCHANGE_MELT_FEES_EXCEED_CONTRIBUTION, NULL); } - + switch (dk->denom_pub.bsign_pub_key->cipher) + { + case GNUNET_CRYPTO_BSA_RSA: + TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_RSA]++; + break; + case GNUNET_CRYPTO_BSA_CS: + TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_CS]++; + break; + default: + break; + } if (GNUNET_OK != TALER_test_coin_valid (&rmc->refresh_session.coin, &dk->denom_pub)) @@ -323,11 +361,13 @@ check_melt_valid (struct MHD_Connection *connection, } /* verify signature of coin for melt operation */ + TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++; if (GNUNET_OK != TALER_wallet_melt_verify (&rmc->refresh_session.amount_with_fee, &rmc->coin_refresh_fee, &rmc->refresh_session.rc, &rmc->refresh_session.coin.denom_pub_hash, + &rmc->refresh_session.coin.h_age_commitment, &rmc->refresh_session.coin.coin_pub, &rmc->refresh_session.coin_sig)) { @@ -341,7 +381,7 @@ check_melt_valid (struct MHD_Connection *connection, if (GNUNET_TIME_absolute_is_past (dk->meta.expire_deposit.abs_time)) { /* We are past deposit expiration time, but maybe this is a zombie? */ - struct TALER_DenominationHash denom_hash; + struct TALER_DenominationHashP denom_hash; enum GNUNET_DB_QueryStatus qs; /* Check that the coin is dirty (we have seen it before), as we will @@ -403,6 +443,10 @@ TEH_handler_melt (struct MHD_Connection *connection, &rmc.refresh_session.coin.denom_sig), GNUNET_JSON_spec_fixed_auto ("denom_pub_hash", &rmc.refresh_session.coin.denom_pub_hash), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_fixed_auto ("age_commitment_hash", + &rmc.refresh_session.coin.h_age_commitment), + &rmc.refresh_session.coin.no_age_commitment), GNUNET_JSON_spec_fixed_auto ("confirm_sig", &rmc.refresh_session.coin_sig), TALER_JSON_spec_amount ("value_with_fee", @@ -410,12 +454,14 @@ TEH_handler_melt (struct MHD_Connection *connection, &rmc.refresh_session.amount_with_fee), GNUNET_JSON_spec_fixed_auto ("rc", &rmc.refresh_session.rc), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_fixed_auto ("rms", + &rmc.rms), + &rmc.no_rms), GNUNET_JSON_spec_end () }; - memset (&rmc, - 0, - sizeof (rmc)); + memset (&rmc, 0, sizeof (rmc)); rmc.refresh_session.coin.coin_pub = *coin_pub; { |