summaryrefslogtreecommitdiff
path: root/src/exchange/taler-exchange-httpd_melt.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/exchange/taler-exchange-httpd_melt.c')
-rw-r--r--src/exchange/taler-exchange-httpd_melt.c98
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;
{